Database client, ORM abstractions, and entity tables.

The database layer uses libsql with a type-safe table abstraction that handles column definitions, field transformers (encrypt/decrypt), and generic CRUD operations.

Entity Tables

  • Listings — listing CRUD with cached encrypted slugs/names
  • Attendees — hybrid RSA+AES encryption for PII
  • Users — password hashing, admin levels, wrapped keys
  • Sessions — token hashing with TTL caching
  • Groups — listing grouping with encrypted names
  • Settings — system configuration (currency, email, payment keys)
  • Holidays — date exclusions for daily listings
  • Activity Log — admin audit trail
  • Processed Payments — idempotency tracking
  • Login Attempts — rate limiting and lockout

Classes

c
DatabaseBusyError

Raised when a write can't get through because the database stays locked after the retries below — too busy. The request layer turns this into a friendly auto-reloading page rather than a generic error.

c
SetupAlreadyCompleteError
No documentation available

Functions

f
acceptInvite
No documentation available
f
activateKeylessUser

A keyless invite leaves wrapped_data_key NULL. An editor holds no DATA_KEY, so unlike acceptInvite there is no handoff to unwrap or re-wrap. The password only authenticates, and protects no key.

f
adjustListingIncome

Correct projected listing income to the requested amount.

f
advanceSessionFailure

Advance a stored terminal outcome from its conservative shape to its final one, once the follow-up money work has finished. Reads the row fresh, so ANY later process — not just the one that stored it — can finish the move. The write is fenced on the exact bytes just read; a racing advance makes this one converge instead of clobbering. A missing or re-reserved row means the idempotency record was pruned mid-move: the durable money records are already correct, so there is nothing left to advance.

f
advanceStoredOutcomeOnce

One fenced attempt to move a session's stored outcome to to: the write lands only while the row still holds the exact fence bytes. When the fence misses, the row must have converged to to (a racing advance won) or vanished (pruned) — anything else is a real conflict and throws. Exported for that race arm: a test can hand it a stale fence deterministically, where a live race cannot be scripted.

f
aggregateRepairs

Both repairs for one table's aggregate columns, given the SQL that recounts each one. Every aggregate family declares its table and its per-column recount here rather than writing the same two wrappers again.

f
anyHiddenPackageGroup

Whether any of the given group ids names a HIDDEN package group (hide_package_listings). A hidden package collapses its members to the package name on every buyer surface, so a member there can never gate its own add-on children — the selector would name them.

f
anyListingInPackageGroup

Whether any of the given listings is a member of a package group. Empty input → false (no query). Used to keep a package member from being turned into another listing's required child (a package page can't render child edges).

f
attendeeRemovalStatements

Remove or detach every dependent row for one or many attendee ids.

f
buildAttendeeInsert
No documentation available
f
buildCapacityCheckedInsert

Build an INSERT into listing_attendees, capacity-checked by default. A zero-quantity booking carries no capacity or active condition: it demands no places, so it can land on a full or inactive listing too — but by default it still names a listing that must exist, because listing_attendees has no foreign key. An overbook caller (the payment ghost store) explicitly asks for the row whatever the listing state. An order-level extra condition still applies.

f
buildInputKeyMap

Build input key mapping from DB columns snake_case DB column → camelCase input key

f
buildPiiBlob

Build a PII blob JSON from contact fields. An unpinned latitude/longitude ("") is left out of the JSON so blobs without a pin stay as small as before.

f
bumpSettingsVersion
No documentation available
f
cachedEntityTable

A write to the table, or to a dependsOn table whose triggers feed it, clears the cache automatically at the db-client layer.

f
cachedTable

A write to the table, or to a dependsOn table whose triggers feed it, clears the cache at the db-client layer, so no write path calls it.

f
checkBatchAvailabilityImpl

Check a whole booking batch in one preflight query.

f
checkGroupCapAfterDurationChange

After a duration change on a grouped listing, check whether any day in any existing booking's new range now exceeds the group cap. Returns the earliest over-capacity day, or null if everything fits. Call AFTER recomputeListingBookingRanges so end_at is already updated.

f
checkLinesCapacity

Check several capacity conditions in one query.

f
checkListingAvailability

Check one listing's availability, including its group limits.

f
checkoutStageDeleteStatements

Clear the one booking-stage relationship a merge must replace early.

f
clearAllCaches

Clear every module-level in-process cache.

f
clearLoginAttempts

Clear login attempts for an IP on successful login. Clearing is login-only: successful API-key, booking, and address requests must retain their counters.

f
clearSessionTokens

Clear stored ticket tokens for a session (after redirect has consumed them)

f
cloneGroupMembershipStatement

One group_listings row for a DUPLICATED group, resolving both the new group and the cloned listing by the slug_index each was just inserted with, so the whole clone (group + listings + memberships) runs as one batch — one round-trip, atomic, and clear of the interactive-transaction round-trip guard. Carries the source member's per-package quantity; the flat price override lives in listing_prices and is copied separately (keyed to the new group).

f
columnFrom
No documentation available
f
columnMapByIds
No documentation available
f
contactFields

Extract ContactInfo fields from an object

f
copyPackageMemberOverridesTx

Copy the source's package overrides onto the duplicate's membership rows in the SAME transaction that inserted them (the create write's afterWrite), so a failure rolls the whole duplicate back rather than leaving a live member at the default price. The flat group and per-day group_day price rows are copied only for package groups the NEW listing actually joined (the duplicate form may untick some of the source's groups) — scoping each source row's encoded group to the clone's group_listings, exactly as the quantity copy does. Otherwise a copied override for a non-joined group would lurk invisibly and resurrect the source's price if the clone were later added to that package.

f
countDatabaseRoundTrip

enforceBudget: false exempts the call from the budget allowance only — the reserve/allowance cap the migration runner sets below the real limit. The hard round-trip limit below always applies: it mirrors Bunny's platform cap, which no call, cleanup included, can exceed. So a rollback is let past our own stricter reserve to run, but is still blocked if it would be a genuine over-the-platform-limit subrequest — exactly as Bunny would reject it.

f
countRows

Count all rows in a table. table must be a trusted constant, not input.

f
createInvitedUser

Create an invited user (no password yet, has invite code). When the inviter passes a wrapped DATA_KEY handoff, the invitee self-activates at /join under the v2 scheme; otherwise an admin activates them later (legacy v1 path). kek_version is a placeholder here — there is no wrapped_data_key until activation, which sets the real version.

f
createKeyedCache
No documentation available
f
createSession

Create a new session with CSRF token, wrapped data key, and user ID Token is hashed before storage for security

f
dateToStartEnd

Convert a nullable date to the stored half-open range.

f
daySpan

Half-open span covering a non-empty set of YYYY-MM-DD days.

f
decryptAdminLevel

Decrypt a user's admin level

f
decryptAttendeeFields

Decrypt attendee fields from the PII blob. Requires migration to be complete (admin is gated behind migration). When paidListing is false, payment_id and refunded are skipped.

f
decryptAttendeeOrNull

Decrypt a single raw attendee, handling null input. Used when attendee is fetched via batch query.

f
decryptAttendees

Decrypt a list of raw attendees (all fields). Used when attendees are fetched via batch query.

f
decryptListingWithCount

Convert a projected DB row and overlay the effective listing defaults.

f
decryptPiiBlob

Decrypt a PII blob and extract all contact fields

f
decryptSessionTokens

Decrypt the ticket_tokens field from a processed payment record. Returns the plaintext token string (e.g. "tok1+tok2") or empty string.

f
decryptUsername

Decrypt a user's username

f
defineCachedListTable

Define a cached "list" table in one call: build the table with defineTable, then wrap it in cachedTable whose fetchAll selects and decrypts every row in orderBy sequence. Returns the cached table plus its getAll/invalidate.

f
defineIdTable

Helper for tables whose primary key column is id.

f
defineTable

Define a table with CRUD operations

f
deleteAllSessions

Delete all sessions (used when password is changed)

f
deleteAllStaleReservations

Delete all stale reservations (unfinalized, outcome-less, and older than STALE_RESERVATION_MS). Called from admin listing views to clean up abandoned checkouts. Rows carrying a recorded terminal failure are kept so a late redirect/webhook replays the handled outcome rather than re-refunding.

f
deleteAttendee

Delete an attendee and all its listing links, payments, and answers.

f
deleteByField

Delete rows matching a field value

f
deleteByFieldBatch

Delete rows from multiple tables in a single batch transaction

f
deleteByFieldStatement

Build the DELETE statement for one DeleteByFieldTarget — for batches that mix these deletes with other statements.

f
deleteListing

Delete one listing and its listing-owned relationships in one batch.

f
deleteOtherSessions

Delete all sessions except the current one Token is hashed before database comparison

f
deleteSession

Delete a session by token Token is hashed before database lookup

f
deleteUser

Delete a user and all their sessions and API keys

f
deleteWithChildren

Delete one row and the rows that point at it, children first, in one batch. Each child names the column that holds the parent's id.

f
enableFooterDebug

Allow the admin debug footer to render the captured queries (staff-only).

f
enableQueryLog

Enable query logging and clear previous entries

f
encryptAttendeeFields

Encrypt attendee fields into a PII blob.

f
encryptedNameSchema

Shared encrypted name column for tables that store a display name.

f
encryptedSeoContentSchema

Shared encrypted SEO/content columns for operator-authored pages (site pages, news posts): the markdown body plus the meta pair.

f
encryptedSlugSchema

Encrypted slug + its plaintext blind-index slug_index (the permalink pair shared by pages and news posts).

f
encryptPiiBlob

Encrypt a PII blob JSON string with the public key

f
encryptTicketTokens

Encrypt ticket tokens for the atomic payment finalize.

f
enforceTransactionRoundTripGuard

Count a statement within one interactive transaction and fire once, exactly when the running count crosses the threshold. Only enforced inside a request scope — startup migrations rebuild tables in one big transaction outside any request, so they are never counted. count is the running per-transaction statement count.

f
envNameSource

A table's env-key-encrypted name column as an id → name source. The env decrypt and the name column are the common case, so per-table wrappers bind just the table and its singular-word alias, then take .byIds (narrow id lookups) or .all() (every name, for pickers/labels).

f
executeBatch

Execute multiple write statements, discarding results.

f
executeBatchWithoutCacheInvalidation

Write without firing cache invalidation. Reserved for plaintext bookkeeping rows (script-version markers) no cache ever holds — written concurrently with requests, the normal path would wipe the settings snapshot the request just loaded.

f
executeReturningRow

Run a write that ends in RETURNING and read back the row it wrote. A write that returns no row means nothing was written — fail there, loudly.

f
executeUpdate

Build the update statement and run it in one call — the executing form for the single-statement call sites (batch and transactional callers use update itself).

f
executeWithoutCacheInvalidation

A single statement with no table-scoped invalidation, for a caller keeping its own cache state through a write. Query tracking still happens. Every other write wants execute.

f
expandDailyRange

Expand a daily-listing range into individual day strings.

f
extractUpdateColumns

The lower-cased column names an UPDATE's SET clause assigns, or null when none can be read. Commas inside parentheses are skipped, so a coalesce(x, 0) does not split one assignment into two. Null means the caller invalidates unconditionally — safe over stale.

f
finalizeSessionIfUnresolved

Heals a reservation ONLY while it is unresolved, so it never overwrites the attendee_id or blanks the ticket_tokens a racing delivery just finalized. The guard is UNRESOLVED_RESERVATION, so the first outcome wins.

f
generateUniqueGroupSlug

Generate a unique group slug, retrying on collision.

f
getActiveHolidays

Get active holidays (end_date >= today) for date computation (from cache). "today" is computed in the configured timezone.

f
getActiveListingStats

Get aggregated statistics for active listings. All three values are summed from the precomputed aggregate columns on ListingWithCount (trigger-maintained), which are already in memory from the caller's getAllListings() fetch — no additional DB query needed.

f
getAllActivityLog

Get all activity log entries (most recent first)

f
getAllAttendeePiiBlobs

Get every attendee's encrypted PII blob (one row per attendee). Used to resolve bulk-email recipient lists, where only the email inside each blob is needed. De-duplication of addresses happens after decryption.

f
getAllGroupNames

Narrow id → name map for every group (selects + decrypts only the name), for pickers/labels that must not load the whole groups cache.

f
getAllListingOptions

Read the narrow listing option projection used by item pickers.

f
getAllListings

Read every listing with effective defaults and aggregate projections.

f
getAllSessions

Get all sessions ordered by expiration (newest first)

f
getAllUsers
No documentation available
f
getAttendeeActivityLog

Get activity log entries for a specific attendee (most recent first), decrypting messages.

f
getAttendeeBookingRowsByTokens

Look up attendees by plaintext tokens for the Previous bookings table.

f
getAttendeeKindsByIds

Bounded id → kind lookup for attendee-linked admin surfaces. Empty ids ⇒ empty map. Unknown/deleted ids are omitted.

f
getAttendeeNamesByIds

Bounded id → name lookup for the given attendees, decrypting only the name from each PII blob with the owner private key (no booking join, one row per attendee). Empty ids ⇒ empty map. Used for link labels in the activity log; a deleted attendee's id simply has no entry.

f
getAttendeeOrNull

Get an attendee by ID (decrypted) Requires private key for decryption - only available to authenticated sessions

f
getAttendeePackageRowsRaw

One attendee's raw booking rows within one package group (real lines only — quantity > 0). Lets a listing-scoped action rehydrate the WHOLE package the selected line belongs to, so a per-member notification resend doesn't treat a single member row as the complete package.

f
getAttendeePiiBlobForToken

Get the encrypted PII blob for the attendee identified by a plaintext ticket token. Used to resolve a single-attendee bulk-email recipient. Ticket tokens are unique, so this matches at most one attendee; returns null when the token matches none, so a stale or unknown token resolves to no recipient rather than erroring.

f
getAttendeePiiBlobsForListingDay

Get the encrypted PII blobs for attendees whose booking on one listing covers a given day. A booking spanning several days covers each of them, so a stay from Friday to Sunday answers to Saturday as well as to its own first day. Uses the same half-open overlap predicate as the capacity checks, so the people a day's message reaches are the people that day counts.

f
getAttendeePiiBlobsForListings

Get the encrypted PII blobs for attendees booked onto any of the given listings (one row per attendee, even if booked onto several of them). Returns an empty array when no listing IDs are supplied.

f
getAttendeeRaw

Get an attendee by ID without decrypting PII Used for payment callbacks and webhooks where decryption is not needed Returns the attendee with encrypted fields (id, listing_id, quantity are plaintext)

f
getAttendeesByIds

Get attendees by ID without decrypting PII, one row per (attendee, booking). Used by the agent run sheet, which already knows the attendee ids it needs and only reads each attendee's contact fields. Returns an empty array for no ids. Decrypt with decryptAttendees before display.

f
getAttendeesByListingIds

Read raw attendees attached to any requested listing.

f
getAttendeesByTokens

Look up attendees by plaintext tokens, returning full booking data. Two queries: attendees by token index, then all listing_attendees for those attendees. Returns results in the same order as input tokens. Bookings sorted by start_at then listing_id for deterministic ordering.

f
getAttendeesPage

Pagination counts ATTENDEES, not booking lines, so a grouped attendee row carries their complete listings list and never splits across a page boundary. listingIds decides WHICH attendees match, and the returned rows still cover all of a matched attendee's listings.

f
getAttendeesRaw
No documentation available
f
getCatalogListings

Read only active, effectively visible listings for the public catalog.

f
getCurrentSettingsVersion

Read the current settings_version counter straight from the DB (bypassing the snapshot and the read audit — it is cache machinery, not an app setting). The row is an integer once any write has created it; before the first write (a fresh database) it is absent, which reads as version 0.

f
getDailyListingAttendeeDates

Read every occupied date across daily listing bookings.

f
getDailyListingAttendeesByDate

Read daily-listing attendees whose booking overlaps one date.

f
getDatelessGroupRemaining

Date-less remaining for capped groups reached from cumulative listings.

f
getDb

Get or create database client

f
getFirstBooking

The first real booking, or a no-quantity placeholder when no real one remains. The returned row itself proves whether the action has a live booking; callers do not need a second existence query.

f
getGroupById

One stored group, through the shared many-group read. Null when no group has that id.

f
getGroupBySlugIndex

Get a single group by slug_index (from cache)

f
getGroupPackagePrices

Every membership row for a group, carrying its package_price override and per-package quantity. A null package_price means "no override — use the listing's own price", 0 means explicitly free in this package, and a positive value overrides the price; quantity defaults to 1. The override is read from the group dimension of listing_prices; quantity from the membership row.

f
getGroupPackagePricesByGroupIds

The membership rows for several groups in one query, keyed by group id, so a list endpoint can hydrate every group's package members without a per-group round-trip. Groups with no membership rows are absent from the map.

f
getGroupRemainingForListing

Remaining group capacity for one listing, or undefined when no cap applies or the listing does not exist.

f
getGroupsById

Every group keyed by id, from the request-cached set — the batched alternative to one read per id when resolving or validating many groups without tripping the N+1 read guard.

f
getGroupsByIds

Groups by id in one query, read straight from the table: a group about to be shown, edited or acted on must be the stored row, not a cached copy that another edge may already have changed. An id with no row is simply absent from the map.

f
getGroupStaticCapByGroupId

Static maximum capacity for each capped group.

f
getListingActivityLog

Get activity log entries for an listing (most recent first)

f
getListingAggregateRecalculation

Compare stored listing aggregates with the values rebuilt from bookings.

f
getListingOfferFlags

Read the flags that decide whether one listing may be offered.

f
getListingPickerNames

Read names and offer flags for the admin site-page picker.

f
getListingRemainingForRange

Remaining bookable units for each listing over a date range.

f
getListingRows

The one reader every listing-record surface uses: declare the filter and the order, and it returns raw rows. Encrypted columns are still encrypted — decrypt with the readers in records.ts before display.

f
getListingsByGroupIds

Members of SEVERAL groups at once, keyed by group id — the batched form of the single-group loaders for a multi-group surface. A page with many group leaves would otherwise run one member query per group; this loads the join once and the member listings once, then assembles each group's list in memory. Every requested group id maps to an entry (empty when it has no matching member). activeOnly keeps just active members (the site-page nav's liveness gate); the default includes inactive members (the validators' group-compatibility read for a listing that joins many groups, kept batched to stay under the N+1 guard).

f
getListingsById

Read every listing keyed by id.

f
getListingsBySlugs

Read listings by slug in input order, retaining nulls for missing rows.

f
getListingsWithCountsByIds

Read listings in input order, retaining nulls for expected missing rows.

f
getListingWithActivityLogOrNull

Get listing and its activity log in a single database round-trip. Uses batch API to reduce latency for remote databases.

f
getListingWithAttendeeRaw

Read one listing and one attendee in one round-trip.

f
getListingWithAttendeesRaw

Read one listing and all its attendee rows in one round-trip.

f
getListingWithCount

Read one listing when absence is expected.

f
getListingWithCountBySlug

Read one listing by its plaintext slug when absence is expected.

f
getListingWithCountPrimary

Read a just-written listing from the primary, or null if it was deleted.

f
getNewestAttendeesRaw

Get the newest attendees across all listings without decrypting PII. Used for the admin dashboard to show recent registrations.

f
getPackageDisplaysByIds

The package displays for a set of (possibly repeated or zero) package_group_ids — only ids naming a live package appear in the map. Lets the ticket view collapse each token's package rows into one card per package, so an attendee holding both a package booking and a standalone one (e.g. after an attendee merge) doesn't fall back to per-row cards that leak a hidden member. Groups are resolved together from their shared cache.

f
getQueryLog

Return a snapshot of all logged queries

f
getQueryLogStartTime

Return the start time recorded by enableQueryLog()

f
getSession

Get a session by token (with 10s TTL cache) Token is hashed for database lookup

f
getSessionWithUser

Read a session and the user it belongs to together.

f
getSharedGroupCapacities

Group remaining, static caps, and membership for date-less package checks.

f
getStoredListingsWithCountsByIds

Read requested listings' stored values without overlaying inherited defaults.

f
getStoredListingWithCount

Read one listing's stored values without overlaying inherited defaults.

f
getUserAuthFieldsById

Get the minimal encrypted user fields needed to authenticate a session.

f
getUserById

Get a user by ID (from cache)

f
getUserByInviteCode

Find a user by invite code hash Scans all users, decrypts invite_code_hash, and compares

f
getUserByUsername

Look up a user by username (using blind index, from cache)

f
getUserDisplayFields

Get the minimal encrypted user fields needed to show assignable users.

f
groupExists

Does a group row exist? The add-item revalidation's single-row check — no name decryption, never the whole table.

f
hasActiveBookingLine

True when the attendee has a real (quantity > 0) booking on the exact listing. Authorizes per-(attendee, listing) actions — e.g. the signed attachment download — against the EXACT row, not getAttendeeRaw's arbitrary left-joined sibling row (which for a mixed attendee could pass on a ghost/other-listing row, or wrongly reject a valid real-line download). A no-quantity sentinel line is excluded, so a line later marked no-quantity stops authorizing.

f
hashInviteCode

Hash an invite code using SHA-256

f
hasPackageBookings

Whether any booking row is stamped with this package's group id — sold tickets whose display (and hidden-member concealment) resolves through the live package row. Refund placeholders (quantity 0) don't count.

f
hasPackageBookingsTx

Transaction-local recheck: whether any sold booking still holds this group's package id. Used inside the group write transaction so a checkout that commits between a request-level sold-hidden check and the write rolls the un-packaging back rather than revealing concealed member names.

f
idAndCreatedSchema

Shared generated id + plaintext created stamp columns. created stays unencrypted so SQL can order and prune by time without decrypting.

f
incrementAttachmentDownloads
No documentation available
f
initDb

Initialize database tables for an existing database. Fresh database creation requires allowMissingSettings. Uses an advisory lock to prevent concurrent migrations.

f
inPlaceholders

Build SQL placeholders for an IN clause, e.g. "?, ?, ?"

f
insert

Build an INSERT statement from a table name and column-to-value record. A rawSql value goes into the SQL as written rather than as a bound placeholder, which is how a column takes an expression such as last_insert_rowid().

f
insertedRowId

The key of the row an INSERT … RETURNING wrote, read from the row itself rather than from the driver's optional lastInsertRowid. Every generated key is a positive integer, so anything else means nothing downstream can be keyed on this row and the write must fail here.

f
invalidateInitDbCache

Forget the per-isolate "database is ready" cache.

f
invalidateListingsCache

Clear the listing entity cache.

f
invalidateUsersCache

Invalidate the users cache (for testing or after writes).

f
isFooterDebugEnabled

Whether the admin debug footer may render the captured queries.

f
isGroupSlugTaken

Check if a group slug is already in use. Checks both listings and groups for cross-table uniqueness.

f
isInviteExpired

Check if a user's invite has expired. Callers should skip this for users who have already set a password.

f
isInviteValid

Check if a user's invite is still valid (not expired, has invite code)

f
isSlugTaken

Check whether a slug is already used, optionally excluding one listing.

f
isUsernameTaken

Check if a username is already taken

f
lineKeyFromBooking

Build the canonical line key from a stored booking row (matches the ${listingId}|${startAt}|${parentListingId}|${packageGroupId} identity carried by the form's hidden key field). parent_listing_id distinguishes the two rows produced when the same child is booked under two different parents; package_group_id the rows produced when the same listing is booked through two packages (or a package plus its own standalone row) in one order.

f
listingAttendeeRowColumnsFrom

Columns for a ListingAttendeeRow read straight from one listing_attendees source. The source name feeds correlated ledger subqueries, so a caller can pass either the table name or a query alias without the sibling subquery shadowing bare column names.

f
loadAttendeeRows

Load attendee rows carrying the standard ATTENDEE_FIELDS set (PII still encrypted — decrypt before display). Callers vary only in join, order, and where, so the field set is declared in exactly one place.

f
loadExistingLines

Read all current listing_attendees rows for an attendee, with line keys.

f
loadPackageMemberPricingByGroupIds

The full pricing state of SEVERAL package groups, keyed by group id, in two reads however many groups are asked for — an order that books many packages would otherwise spend two round-trips per package and eat the request's subrequest budget. Every requested group is present; one with no membership rows reads as empty maps.

f
logActivities

Log several activities as ONE write. A booking with many lines records a line apiece, and one insert per line would eat the edge request's subrequest budget; a batch costs the same single round-trip however many there are, and either they all land or none does. Returns the stored rows in the same order, with their plaintext messages. A caller may pass its open write transaction so the log and the action it records commit together.

f
logActivity

Log one activity, through the shared many-activity write. Optionally associate it with a listing and/or attendee so admin views can filter the log by either.

f
logCompletedSql

Mirror the debug footer to the system logs: emit each SQL statement as it completes, with its bound values omitted. The statement is parameterised, so the string carries only ? placeholders — never PII or secrets — exactly the value-free view the admin footer renders. Whitespace is collapsed so a multi-line statement logs on one line. Routed through logDebug (category "SQL") so it honours the same debug-log suppression as other debug output; the dynamic import avoids the static cycle (query-log is imported by the db client, which the logger transitively depends on), mirroring notifyN1Violation.

f
makeIpRateLimiter

Build a namespaced per-IP limiter: isLimited checks the lockout, record counts one attempt (locking out at maxAttempts for lockoutMs and returning true once locked). Each caller picks its own prefix so counters never collide across features.

f
mapByIds

Run an integer-keyed lookup query and turn each row into a [key, value] pair via toEntry, returning the id-keyed map (empty when ids is empty).

f
markSessionFailed

Record a handled terminal failure on a still-unresolved session. A later redirect/webhook for the same session reads this back via parseSessionFailure and returns the same outcome, so refunds and validation never run twice. Guarded on UNRESOLVED_RESERVATION, so it never clobbers a finalized success and never overwrites an already-recorded failure (the first outcome wins); a no-op if the row was pruned away.

f
migrateUserToV2Kek

Re-wrap a user's DATA_KEY under the password-bound (v2) KEK. Called at login — the one place both the raw password and the freshly-unwrapped DATA_KEY are in hand — for users still on the legacy v1 wrap, replacing the DB-recoverable wrap in place without touching any encrypted data.

f
nameSource

A table's id → name projection, bound to its columns once. byIds returns the map for the requested ids (empty ids ⇒ empty map); all returns it for every row, ordered by id. Only the name column is decrypted, via the decryption-agnostic decryptName; table/alias/nameColumn (alias qualifies the selected columns, repo SQL convention) are internal constants.

f
onUsersInvalidated

Register a callback to run whenever the users cache is invalidated.

f
orIgnore

Rewrite a built INSERT as INSERT OR IGNORE, dropping a row whose unique key is already stored instead of raising a constraint error. This is the once-only latch resumable flows lean on: a replayed write re-derives the same key and lands nowhere. It silences every conflict on the statement, so use it only where the unique key IS the idempotency rule.

f
overlapsDay

Whether a stored booking overlaps one day. String comparison mirrors the SQLite overlap check byte-for-byte.

f
packageDisplaysForRows

The package displays behind a set of booked rows — each row's attendee names its persisted package_group_id (0 on a plain row, matching no package). Shared by the ticket view, the wallet lookup, and the email renderer, which all carry { attendee, listing } row shapes.

f
packageMemberMaps

A package group's member rows projected into the two maps every consumer needs (the booking flow, the webhook revalidation, the bookability gate, and the test harness): prices keeps only members with a real override — a positive price OR an explicit free 0, dropping a null "no override" — while quantities covers every member (default 1). Owning both here keeps the "what counts as an override" rule in one place; callers destructure what they use.

f
packageMembersError

The member-naming package error for the first listing in listings that can't be a package member (pay-what-you-want, an add-on of another listing, or — on a hidden package — a member gating its own children), or null when every listing is a valid member. Judged against ONE batched edge load (two queries for the whole member list, never one per member); the rules and their messages live in the shared packageMemberError. The one place every package save (group form, add-listings, listing form/API, catalog import) turns an unpackageable member into its user-facing message.

f
parsePiiBlob

Parse a PII blob JSON back into contact fields (defaults v to 1 for pre-versioned blobs)

f
parseSessionFailure

Parse a stored terminal failure, or null when the row carries none. A non-empty value is an app-written durable outcome, so decryption or schema failure is corruption and must surface here instead of being mistaken for a handled booking result.

f
perDayLoads

Per-day quantity sums from rows fetched for the whole span.

f
prepareSessionFailure
No documentation available
f
queryAll

Query all rows as a typed array. A read whose cache refill requires read-your-writes goes to the primary instead.

f
queryAllPrimary

queryAll for a caller that must read its own writes. The same rows, pinned to the primary, because a replica can lag behind the write and miss them. See queryBatchPrimary. It takes the statement whole, which is the shape a batch runs, so a caller that holds one hands it over as it is.

f
queryAndMap

Execute a SQL query and map result rows through an async transformer.

f
queryColumnSet

Run a single-column SELECT and collect that column's values into a Set of strings — the shared shape of the "which hashes/names already exist" reads (e.g. the live table names, the unsubscribed contact hashes).

f
queryIdColumn

Run a query whose single selected column is aliased id and return the ids.

f
queryOne

Query one row, or null when the query returns none.

f
queryOnePrimary

Query an optional row on the primary — the singular of queryAllPrimary, as queryOne is of queryAll. args is required here: every read-back keys on the row the write just made.

f
rawSql

Embed a raw SQL expression (e.g. last_insert_rowid())

f
readGroupMembersWith

Read several groups' members together with one more thing about the SAME groups — their prices, their full membership, whatever the caller needs — in one round of reads. A page hydrating many packages would otherwise pay a pair of reads per package and eat the request's subrequest budget. activeOnly has the meaning getListingsByGroupIds gives it, and is spelled out at every call site — whether inactive members count is the caller's decision, never a default.

f
rebuildWipedSchema

Rebuild the full schema after resetDatabase(), WITHOUT reading the database to decide what to create.

f
recomputeListingBookingRanges

Recompute end_at on all existing listing_attendees rows for an listing based on a new duration_days value. Leaves NULL-start rows alone. The .000Z suffix matches the format fresh inserts produce via toISOString() so raw-row dumps stay consistent.

f
registerTableInvalidation

Register invalidate to run whenever any of tables is written.

f
releaseReservation

Release an in-progress reservation so the very next delivery can re-claim it. Deletes only a still-unresolved row, so it never clobbers a finalized success or a recorded terminal failure that a racing delivery may have written.

f
remainingByListingOverGroups

Tightest capped-group value for each listing.

f
repointAttendeeDependents

Move live attendee assignments while keeping their records.

f
requireListingsWithCountsByIds

Read required listings in input order through the shared cache path.

f
requireListingWithCount

Read one required listing through the shared many-listing path.

f
requireOne

Query one required row and name the failed query when none exists.

f
requireOnePrimary

Query one required row from the primary.

f
reserveSession

Reserve a payment session for processing (first phase of two-phase lock). Missing and stale unresolved rows are claimed atomically. Existing fresh, finalized, and failed rows are returned without changing them.

f
resetAggregates

Reset selected aggregate columns from trusted SQL expressions. Each expression must use the entity id as its only placeholder.

f
resetDatabase

Reset the database by dropping all tables (reverse order for FK safety)

f
resetGroupListings

Remove every listing from a group (used when the group is deleted), along with the group's package price overrides — its flat group and per-day group_day price rows key on the group id, so they'd otherwise outlive the deletion.

f
resultRows

Cast libsql ResultSet rows to a typed array (single centralized assertion)

f
rowExists

True when the query returns a row. sql should be an existence probe such as SELECT 1 ... LIMIT 1; which columns it selects is ignored.

f
rowExistsForIdList

Build an existence check for "one leading id, matched against a list of ids". The checker binds leadingId to the first ? and expands ids into the IN (...) that buildSql embeds through the placeholder string it is handed. Empty ids runs an empty IN (), which matches nothing.

f
rowsByIds

Run an id-keyed SELECT, short-circuiting to [] (no query) when ids is empty. buildSql receives the bound ?-placeholder list for ids, so ids are the only query args. The base skeleton for the id-map helpers below and for any read that loads rows for a caller-supplied id list.

f
runWithQueryLogContext
No documentation available
f
setDb

Set database client (for testing)

f
setGroupListingsActive

Set the active flag on every listing in a group. Returns the number of listings affected.

f
setGroupPackageMembers

Set a group's package member overrides — the flat group price rows in listing_prices plus the per-package quantity on the membership rows. Pass tx to run inside an existing write transaction (the admin API update path, so the overrides commit atomically with the group row write); omit it to run as the function's own statements. See applyPackageMembers for the partial-update rules.

f
setListingGroupsTx

Replace a listing's group memberships inside an existing write transaction, so the change commits atomically with the listing row write (the admin API create/update path). Mirrors setListingGroups but reads the current set and runs each statement on the caller's tx.

f
setN1GuardNotifyOnly

Switch the N+1 guard between throw (default) and notify-only (production).

f
sqlWallClockMs

Wall-clock milliseconds during which at least one query was in flight: the combined length of the query intervals with overlaps merged.

f
stringColumnSet

Collapse a result's rows to the set of one column's values, as strings — the shared tail of the "which names/ids already exist" reads (applied migrations, live table columns, index and trigger names).

f
toCamelCase

Convert snake_case to camelCase (e.g. max_attendeesmaxAttendees).

f
toSnakeCase

Convert camelCase to snake_case (the inverse of toCamelCase).

f
trackSql

Run an async DB operation, enforcing the N+1 read guard and logging it when footer tracking is active.

f
unfitListingIds

The listings whose lines do not fit right now, in one query. The attendee-edit preflight names its culprit with this.

f
update

Build an UPDATE statement, the WHERE record ANDed as equality checks. SET values may be rawSql expressions, such as a counter increment. A write needing a richer guard — IS NULL, an inequality, a subquery — keeps its own SQL rather than bending this one.

f
updateAttendeePII
No documentation available
f
updateAttendeeStatus

Set an attendee's status from the admin edit form (a plain column write, outside the encrypted pii_blob). The outstanding balance is NOT set from the form — it projects from the transfers ledger, and an operator adjusts it through the ledger's manual write-off entries.

f
updateCheckedIn

Set a line's check-in flag, refusing a no-quantity (quantity 0) line — it isn't a real ticket, mirroring the refunded-ticket guard in checkin.ts. The quantity > 0 predicate scopes the write so a ghost row is a no-op (it can never have been checked in, so scoping the check-OUT case too is harmless).

f
useTransaction

Run work on the caller's open transaction, or open one when there is no caller transaction. Transaction-aware table methods use this so direct calls and larger atomic operations share the same write path.

f
verifyUserPassword

Verify a user's password (decrypt stored hash, then verify) Returns the decrypted password hash if valid (needed for KEK derivation)

f
withTransaction

Use this rather than a plain batch only when a multi-step write needs logic between steps, such as create → check capacity → finalize, where a zero-row guard must abort and undo everything.

f
writeRowInTransaction

Write one row statement in a fresh write transaction and run persist (the coupled join-table writes) on the same tx, so the row and its side writes commit or roll back together. On update, an optional readState runs before the statement and its result reaches persist; creates skip it. Returns the row id — existingId on update, or the key the INSERT returned on create.

f
writeTableRow

Execute one table-built INSERT/UPDATE on an open transaction and return the affected row. A conditional write returns null when its condition is false.

Interfaces

I
ActivityLogEntry

Activity log entry as callers see it: the message decrypted to plaintext.

I
CrudTable

A table built by defineTable: the transactional statement builders and the primary-pinned read are always present. They stay optional on Table only for hand-written façade tables that never take the transactional path.

I
IntervalRow

A booking row's stored range and quantity.

I
ListingCapacityRow

A listing's identity, capacity, and current booked quantity.

I
NamedSortOrderInput

Input shared by ordered tables whose only required value is a name.

I
PackageMemberPricing

A package group's full pricing state: what it charges, plus the membership rows those charges were read from (which listings are in the bundle).

I
PackagePrices

What a package charges for its members: the flat override + quantity maps (packageMemberMaps) and each customisable member's per-day overrides. The shape the booking page, the webhook payload, and the payment revalidation all price from.

I
PreparedSessionFailure

One terminal-failure transition that can join an existing transaction. statement establishes the conservative outcome; once follow-up money work finishes, advanceSessionFailure moves it to its final shape.

Type Aliases

T
ActiveListingStats

Aggregated statistics for active listings

T
ActivityLogInput

Activity log input for create

T
ActivityToLog

One thing to record in the log: what happened, and which listing/attendee it happened to.

T
AggregateRecalculation

Per-column comparison of each aggregate F's stored value against its rebuilt-from-source value — what the "recalculate aggregates" tools return.

T
AggregateRepairs

The two owner-facing repairs every trigger-maintained aggregate column set needs: write the numbers the operator typed, and rebuild chosen columns from the rows they count.

T
AggregateValues

Stored values of the trigger-maintained aggregate columns F, keyed by column.

T
AtomicDesiredLine

A desired final-state line for the atomic update path. Re-exported from the shared types module so callers can keep importing it from here.

T
AttendeeBookingRows

PII-free booking rows for a token-resolved attendee.

T
AttendeeInput

Input for creating an attendee atomically (one or more listings)

T
AttendeesPage

One page of attendee booking rows, plus whether a further page exists. Carries the full field set because the same page query feeds both the browsing table (which shows no money) and the CSV export (which sums price_paid); the table simply ignores the columns it doesn't render.

T
T
BatchAvailabilityItem

Item for batch availability check

T
BatchExecutor

Runs several statements as one batch and answers each in turn: the shape queryBatch and executeBatchWithResults have, and the one TxScope's batch fits. A caller that reads either from the client or through an open transaction takes one of these instead of naming both.

T
BookingBatchPlan
No documentation available
T
BrowsingAttendee

A browsing-table attendee row — every core column plus refunded, but none of the expensive money projections.

T
ColumnDef

Column definition for a table

T
CreateAttendeeResult

Result of atomic attendee creation. A failure carries the listings whose lines did not fit when the refusal was checked — empty when the failure was not one listing's capacity shortfall (a duplicate slot, a replayed ledger event, or a race that freed the room again before the check).

T
DecryptedAttendeeRow

A decrypted attendee row: the raw row with its PII overlaid and its booleans/price coerced, keeping exactly whichever optional money fields the read selected. DecryptedAttendeeRow<Attendee> is the full Attendee.

T
DeleteByFieldTarget

One delete-rows-matching-a-field target: which table, matched on which field, for which value.

T
ExistingLine

A pre-fetched existing booking row plus its line key.

T
FirstBooking
No documentation available
T
GetListingsQuery

Everything a caller declares to read listing records: which rows to keep and in what order.

T
HolidayInput

Holiday input fields for create/update (camelCase)

T
ListingAggregateField
No documentation available
T
ListingAggregateRecalculation
No documentation available
T
ListingAggregateValues
No documentation available
T
ListingBooking

A single listing booking within a multi-listing attendee creation

T
ListingOfferFlags
No documentation available
T
ListingOption
No documentation available
T
ListingOrder

How the rows come back. A named order so callers can't hand-roll a stray ORDER BY. Exported because a narrow listing read — one that selects its own columns rather than the whole record — still wants to come back in the same order as the full reads.

T
ListingRecordRow

The raw shape a listing read returns: the stored columns plus the worked-out values, before decryption and before any inherited defaults are overlaid.

T
ListingWhere

A declarative filter for a listing read. Each present field adds one WHERE clause (absent fields don't constrain), so a caller says WHICH listings it wants rather than hand-writing SQL. An empty filter reads every listing.

T
ListingWithActivityLog

Result type for listing + activity log batch query

T
ListingWithAttendeeRaw
No documentation available
T
ListingWithAttendees
No documentation available
T
ListsByIds

A batch loader: takes a list of ids and returns, for each id, the list of related numbers found for it. Ids with no matches are absent from the map.

T
Migration
No documentation available
T
PackageDisplay

Package-group display info for grouping a booking's lines under the package name on tickets/emails.

T
T
RawAttendeeRow

The raw attendee columns the decrypt step reads and coerces. price_paid and refunded are optional because a field-selected read may leave them out (see file://./select.ts); the decrypt then leaves them out too rather than coercing an absent column into "undefined" / false.

T
ReadColumn

Run one column's declared read transform (e.g. decrypt) on a stored value — identity when the column declares none or the value is null. For reading a single column back without building a whole row. rowId (when known) lets the transform name the record in error reports.

T
ReserveSessionResult

Result of session reservation attempt

T
SchemaRequirement

The schema objects a single migration is responsible for. Drives that migration's verify() so failures name exactly what the migration was meant to add or remove.

T
SessionWithUser

A session and the user it belongs to. user is null when the session outlived its user, which the caller reports and clears — never mistake it for a token nobody ever had.

T
SettingsData

Full settings snapshot type.

T
SqlStatement

A single SQL statement plus its bound arguments — the object form libsql's batch API accepts. This is the one shared shape for a { sql, args } pair; callers that build statements to hand to executeBatch and friends import this rather than re-declaring the same object type locally.

T
StoredLogMessage

A stored log message: owner-key ciphertext for rows written since the keypair existed, env-key ciphertext for legacy rows the backfill hasn't re-encrypted yet. The format prefix routes decryption at runtime.

T
TableDefinition

The shape that defines a table: its name, primary key, and column schema.

T
TableSchema

Table schema definition Keys are DB column names (snake_case), values are column definitions

T
TransactionStateReader

Reads narrow pre-update state through an open write transaction.

T
TxScope

The slice of an open write transaction handed to a withTransaction callback: run statements singly or as one batch; commit/rollback are managed for you.

T
UpdateAttendeeAtomicResult

Result of an atomic attendee update. Every failure carries listingIds — the SPECIFIC listings that failed the capacity preflight — so a caller can tell the operator what was actually sold out instead of a bare reason string. Empty when no particular listing is to blame: a duplicate booking slot (see applyAttendeeAtomicEdit's duplicate-slot guard) or a no_lines rejection.

T
UpdateAttendeePIIInput

Input for updating attendee PII (shared across listings)

T
UserAuthFields
No documentation available
T
UserDisplayFields
No documentation available

Variables

v
activityLogTable

Activity log table definition.

v
ALL_SETTINGS_KEYS

All keys that populate the snapshot plus the setup-complete flag. Equivalent to the former loadAll SELECT * in terms of what affects request behaviour. Use in tests and in pre-load bundles that need every setting.

v
ATTENDEE_LISTING_CONTRIBUTIONS_SQL

Per-listing aggregate contributions of an attendee's lines, summed so the hold-delete restore can add them back after deleting. tickets_count counts only quantity > 0 rows (mirroring the delete trigger, which now subtracts 0 for a no-quantity line — see ticketCountSumExpr); booked_quantity sums over all rows. Exported for the shared-predicate guard test.

v
ATTENDEES_PAGE_SIZE

Attendees per page in the admin attendees browser. Fixed here so the page size is never derived from the request — callers choose only the page.

v
buildCreateUserStatement

Build the INSERT that createUser would run, without executing it, so a caller can include the user creation in a batch/transaction with other writes (e.g. initial setup creates the owner atomically alongside its config keys).

v
CONFIG_KEYS
No documentation available
v
createUser

Create a new (already-activated) user with encrypted fields. Activated users are created at the password-bound KEK scheme (v2); the caller computes the matching wrapped_data_key via wrapDataKeyForPassword.

v
DATABASE_MAX_ATTEMPTS

Most physical database attempts made for one retryable operation on the remote database — the number the edge subrequest budgets are sized from. A file database retries longer, where no subrequest budget binds.

v
EMAIL_BODY_KEYS
No documentation available
v
execute

Run a single statement: track it for the query log / N+1 guard, then fire any table-scoped cache invalidation. Every single-statement read and write goes through here (queryOne/queryAll wrap it), so cache invalidation is driven by the write itself rather than by each call site remembering to invalidate.

v
executeBatchWithResults

Write statements in order in one transaction, returning every ResultSet — suited to cascading deletes and multi-step writes.

v
getActiveListingsByGroupId
No documentation available
v
getGroupPerDayRemaining

Per-day remaining for several capped groups, loaded in two queries.

v
getGroupRemainingByGroupId

Remaining capacity for each capped group.

v
getGroupRemainingByListingId

Tightest remaining capped-group capacity for each listing.

v
getListingsByGroupId

Get all listings in a group with attendee counts (including inactive).

v
groupListings

The listing ids in a group, and the reverse listing-to-groups side.

v
groups

Execute a query and decrypt the resulting group rows

v
hasPaidLine

True when any of the listings has a paid line for this attendee — a gross sale leg in the row's ledger_event_group (a sale leg's amount is always > 0, so its existence is exactly a non-zero projected price_paid; a refund keeps the gross leg, so a refunded line still reads as paid). One query over all the IDs, read from the live ledger rather than the edit form's submitted key (a stale/missing key can leave it null), so a recorded payment is never dropped onto a fresh quantity-0 row. Callers pass a non-empty list.

v
holidays

Cached holidays table — name is encrypted, dates are plaintext; writes auto-invalidate the cache.

v
idAndEncryptedNameSchema

Shared columns for tables with a generated id plus an encrypted name.

v
idAndEncryptedSlugSchema

Shared columns for tables with a generated id plus the encrypted slug pair.

v
LATEST_UPDATE

Schema version label and the migrations bookkeeping table name.

v
LISTING_AGGREGATE_FIELDS
No documentation available
v
LISTING_ATTENDEE_ROW_COLS
No documentation available
v
LISTING_ORDER_SQL
No documentation available
v
listingAggregates

Write the operator's typed listing aggregates, or rebuild chosen ones from the booking rows they count.

v
listingGroups
No documentation available
v
listingNames

Read and decrypt listing names without loading full records.

v
listingOptionColumns

The shared narrow listing shape used by listing and attribute pickers.

v
listingReader

The listing reader. Reading by group starts from the membership rows and folds a listing's several memberships back into one row, naming which groups it matched; every other read starts from the listings themselves.

v
listingsTable

Listing CRUD with cache invalidation and listing-price synchronization.

v
loginLimiter
No documentation available
v
N_PLUS_ONE_THRESHOLD

Max times one parameterized read may run as a separate round-trip within a single request before the N+1 guard fires. Set above the worst legitimate repeat in the suite; lower it to catch smaller N+1s.

v
PII_BLOB_VERSION

Current PII blob schema version

v
queryBatch

Execute multiple read queries in a single round-trip using Turso batch API.

v
queryBatchPrimary

HTTP primary reads use a separate BEGIN and COMMIT in one pipeline. A complete SELECT-only batch can run on a replica despite its write mode.

v
rawListingsTable

Raw listings table. Records adds cache-aware CRUD and price syncing.

v
registerCache

Register a cache stat provider (called at module load time)

v
SCHEMA_HASH
No documentation available
v
SCHEMA_TABLE_NAMES

Ordered table names — matches FK dependency order (parents before children)

v
setListingGroups
No documentation available
v
settings
No documentation available
v
SNAPSHOT_KEYS

Every config key that maps to a snapshot field, in load order.

v
STALE_RESERVATION_MS

Threshold for abandoned payment reservations in ms (default: 300000 = 5 min)

v
TRANSACTION_ROUNDTRIP_THRESHOLD

Every statement inside a withTransaction holds the single primary write connection open for another edge→primary round-trip. A chatty interactive transaction is what the primary aborts as "Transaction timed-out".

v
UNRESOLVED_RESERVATION

A processed_payments row is in exactly one of three lifecycle states, encoded across two columns: reserved (in-progress: attendee_id NULL, no failure_data), finalized (success: attendee_id set), failed (terminal handled failure: attendee_id NULL, failure_data set). This predicate is the single source of truth for the unresolved shape, so the encoding can't drift between call sites.

v
withReadSnapshot

Run read-only work against one database snapshot.

Usage

import * as mod from "docs/database.ts";