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

  • Events — event 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 — event grouping with encrypted names
  • Settings — system configuration (currency, email, payment keys)
  • Holidays — date exclusions for daily events
  • Activity Log — admin audit trail
  • Processed Payments — idempotency tracking
  • Login Attempts — rate limiting and lockout

Functions

f
activateUser

Activate a user by wrapping the data key with their KEK

f
addQueryLogEntry

Record a query (no-op when logging is disabled)

f
assignEventsToGroup

Assign events to a group by updating their group_id.

f
buildInputKeyMap

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

f
checkBatchAvailability

Wrapper for test mocking - delegates to attendeesApi at runtime

f
clearLoginAttempts

Clear login attempts for an IP (on successful login)

f
clearPaymentProvider

Clear the active payment provider (disables payments)

f
clearSetupCompleteCache

Clear setup complete cache (for testing)

f
completeSetup

Complete initial setup by storing all configuration Generates the encryption key hierarchy:

f
computeGroupSlugIndex

Compute slug index from slug for blind index lookup

f
computeSlugIndex

Compute slug index from slug for blind index lookup

f
createAttendeeAtomic

Wrapper for test mocking - delegates to attendeesApi at runtime

f
createInvitedUser

Create an invited user (no password yet, has invite code)

f
createSession

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

f
createUser

Create a new user with encrypted fields

f
decryptAdminLevel

Decrypt a user's admin level

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
decryptAttendeesForTable

Decrypt attendees for table display, skipping contact fields not configured on the event and payment fields for free events. For a free event that only collects email, this skips up to 6 RSA decryptions per attendee (phone, address, special_instructions, payment_id, refunded, plus 1 symmetric for price_paid).

f
decryptUsername

Decrypt a user's username

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 and older than STALE_RESERVATION_MS). Called from admin event views to clean up abandoned checkouts.

f
deleteAttendee

Delete an attendee and its processed payments in a single database round-trip. Uses write batch to cascade: processed_payments → attendee. Reduces 2 sequential HTTP round-trips to 1.

f
deleteEvent

Delete an event and all its attendees in a single database round-trip. Uses write batch to cascade: processed_payments → attendees → event. Reduces 3 sequential HTTP round-trips to 1.

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
deleteStaleReservation

Delete a stale reservation to allow retry

f
deleteUser

Delete a user and all their sessions

f
enableQueryLog

Enable query logging and clear previous entries

f
encryptedNameSchema

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

f
executeBatch

Execute multiple write statements in a single round-trip using Turso batch API. Statements are executed in order within a single transaction, making this ideal for cascading deletes and multi-step writes. Reduces N sequential HTTP round-trips to 1.

f
executeByField

Execute delete by field

f
finalizeSession

Finalize a reserved session with the created attendee ID (second phase)

f
getActiveEventsByGroupId

Get active events in a group with attendee counts.

f
getActiveEventStats

Get aggregated statistics for active events. Filters active events from the provided list, computes attendees (sum of quantities) from cached EventWithCount data, and queries ticket count (rows) and income (sum of decrypted price_paid).

f
getActiveHolidays

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

f
getAllActivityLog

Get all activity log entries (most recent first)

f
getAllDailyEvents

Get all daily events with attendee counts (from cache).

f
getAllEvents

Get all events with attendee counts (from cache)

f
getAllGroups

Get all groups, decrypted, ordered by id (from cache)

f
getAllHolidays

Get all holidays, decrypted, ordered by start_date (from cache)

f
getAllSessions

Get all sessions ordered by expiration (newest first)

f
getAllStandardEvents

Get all standard events with attendee counts (from cache). Used by the calendar view to include one-time events on their scheduled date.

f
getAllUsers

Get all users (for admin user management page, from cache)

f
getAppleWalletConfig

Get Apple Wallet config for pass generation. DB settings take priority, falls back to env vars.

f
getAppleWalletDbConfig

Get Apple Wallet config from DB (decrypted). Returns null if incomplete.

f
getAttendee

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

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, event_id, quantity are plaintext)

f
getAttendeesByEventIds

Get raw attendees for a set of event IDs. Used by the calendar to load attendees for standard events whose decrypted date matches the selected calendar date.

f
getAttendeesByTokens

Get attendees by ticket tokens (plaintext tokens, looked up via HMAC index) Returns attendees in the same order as the input tokens.

f
getAttendeesRaw

Get attendees for an event without decrypting PII Used for tests and operations that don't need decrypted data

f
getCurrencyCodeFromDb

Get currency code from database

f
getCustomDomainLastValidatedFromDb

Get the custom domain last validated timestamp. Returns null if never validated.

f
getDailyEventAttendeeDates

Get distinct attendee dates for daily events. Used for the calendar date picker (lightweight, no attendee data).

f
getDailyEventAttendeesByDate

Get raw attendees for daily events on a specific date. Bounded query: only returns attendees matching the given date.

f
getDateAttendeeCount

Get the total attendee quantity for a specific event + date

f
getDb

Get or create database client

f
getEmailTemplate

Get a custom email template (decrypted). Returns null if not customised (use default).

f
getEmailTemplateSet

Get all 3 parts of a custom email template (subject, html, text). Nulls mean "use default".

f
getEmbedHostsFromDb

Get allowed embed hosts from database (decrypted) Returns null if not configured (embedding allowed from anywhere)

f
getEvent

Get a single event by ID (from cache)

f
getEventActivityLog

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

f
getEventsByGroupId

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

f
getEventsBySlugsBatch

Get multiple events by slugs (from cache). Returns events in the same order as the input slugs. Missing or inactive events are returned as null.

f
getEventWithActivityLog

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

f
getEventWithAttendeeRaw

Get event and a single attendee in a single database round-trip. Used for attendee management pages where we need both the event context and the specific attendee data.

f
getEventWithAttendeesRaw

Get event and all attendees in a single database round-trip. Uses batch API to execute both queries together, reducing latency for remote databases like Turso from 2 RTTs to 1. Computes attendee_count from the attendees array.

f
getEventWithCount

Get event with attendee count (from cache)

f
getEventWithCountBySlug

Get event with attendee count by slug (from cache)

f
getGroupBySlugIndex

Get a single group by slug_index (from cache)

f
getHostAppleWalletConfig

Read Apple Wallet config from environment variables. Returns null if not fully configured.

f
getNewestAttendeesRaw

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

f
getPaymentProviderFromDb

Get the configured payment provider type Returns null if no provider is configured

f
getPhonePrefixFromDb

Get the configured phone prefix from database. Returns the country calling code, defaulting to "44" (UK).

f
getProcessedAttendeeId

Get the attendee ID for an already-processed session Used to return success for idempotent webhook retries

f
getPublicKey

Get the public key for encrypting attendee PII Always available (it's meant to be public)

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
getSetting

Get a setting value. Reads from the in-memory cache, loading all settings in one query on first access or after TTL expiry.

f
getShowPublicSiteCached

Get the "show public site" setting synchronously from cache. Returns false if the cache is not populated or the setting is not "true". Safe to call from synchronous template code after the settings cache is warmed.

f
getSquareLocationIdFromDb

Get Square location ID from database Returns null if not configured

f
getStripeWebhookEndpointId

Get Stripe webhook endpoint ID from database Returns null if not configured

f
getTermsAndConditionsFromDb

Get terms and conditions text from database (30m cached). Returns null if not configured.

f
getThemeFromDb

Get the configured theme from database. Returns "light" or "dark", defaulting to "light".

f
getTimezoneCached

Get the configured timezone synchronously. Reads from the permanent cache, falling back to the TTL settings cache, then to the default timezone. Safe to call from synchronous template code because the middleware populates the settings cache on every request.

f
getTimezoneFromDb

Get the configured timezone from database. Returns the IANA timezone identifier, defaulting to Europe/London. Also populates the permanent timezone cache for sync access via getTimezoneCached().

f
getUngroupedEvents

Get ungrouped events (group_id = 0) with attendee counts.

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
getWrappedPrivateKey

Get the wrapped private key (needs DATA_KEY to decrypt)

f
hasAppleWalletConfig

Check if Apple Wallet is configured (DB settings or env vars).

f
hasAppleWalletDbConfig

Check if Apple Wallet DB settings are fully configured (all 5 settings present).

f
hasAvailableSpots

Wrapper for test mocking - delegates to attendeesApi at runtime

f
hasEmailApiKey

Check if an email API key has been configured in the database

f
hashInviteCode

Hash an invite code using SHA-256

f
hasPassword

Check if a user has set their password (password_hash is non-empty encrypted value)

f
hasSquareToken

Check if a Square access token has been configured in the database

f
hasStripeKey

Check if a Stripe key has been configured in the database

f
idAndEncryptedSlugSchema

Shared columns for tables with encrypted slug + blind-index slug_index.

f
initDb

Initialize database tables

f
inPlaceholders

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

f
invalidateEventsCache

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

f
invalidateGroupsCache

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

f
invalidateHolidaysCache

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

f
invalidatePageCache

Clear the entire page content cache (for testing or after bulk changes).

f
invalidateSettingsCache

Invalidate the settings cache (for testing or after writes). Also clears the permanent timezone cache since it derives from settings, and the page content cache since it derives from encrypted settings.

f
invalidateUsersCache

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

f
isGroupSlugTaken

Check if a group slug is already in use. Checks both events 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
isLoginRateLimited

Check if IP is rate limited for login

f
isMaskSentinel

Check whether a submitted form value is the mask sentinel (i.e. unchanged)

f
isQueryLogEnabled

Whether query logging is currently active

f
isReservationStale

Check if a reservation is stale (abandoned by a crashed process)

f
isSessionProcessed

Check if a payment session has already been processed

f
isSetupComplete

Check if initial setup has been completed Result is cached in memory - once true, we never query again.

f
isSlugTaken

Check if a slug is already in use (optionally excluding a specific event ID) Uses slug_index for lookup (blind index)

f
isUsernameTaken

Check if a username is already taken

f
loadAllSettings

Load every setting row into the in-memory cache with a single query.

f
logActivity

Log an activity

f
markRefunded

Mark an attendee as refunded (set refunded to encrypted "true"). Keeps payment_id intact so payment details can still be viewed.

f
queryAll

Query all rows, returning a typed array

f
queryAndMap

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

f
queryBatch

Execute multiple read queries in a single round-trip using Turso batch API. Significantly reduces latency for remote databases.

f
queryOne

Query single row, returning null if not found

f
recordFailedLogin

Record a failed login attempt Returns true if the account is now locked

f
registerCache

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

f
reserveSession

Reserve a payment session for processing (first phase of two-phase lock) Inserts with NULL attendee_id to claim the session. Returns { reserved: true } if we claimed it, or { reserved: false, existing } if already claimed.

f
resetDatabase

Reset the database by dropping all tables

f
resetGroupEvents

Reset group assignment on all events in a group.

f
resetSessionCache

Clear session cache (exported for testing)

f
resultRows

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

f
runWithQueryLogContext
No documentation available
f
setDb

Set database client (for testing)

f
setPaymentProvider

Set the active payment provider type

f
setSetting

Set a setting value. Invalidates the cache so the next read will pick up the new value.

f
setStripeWebhookConfig

Store Stripe webhook configuration (secret encrypted, endpoint ID plaintext)

f
setUserPassword

Set a user's password (for invite flow)

f
toCamelCase

Convert snake_case to camelCase

f
toSnakeCase

Convert camelCase to snake_case

f
trackQuery

Run an async DB operation and log it when tracking is active

f
updateAttendee

Update an attendee's information (encrypted fields) Caller must be authenticated admin (public key always exists after setup)

f
updateCheckedIn

Update an attendee's checked_in status (encrypted) Caller must be authenticated admin (public key always exists after setup)

f
updateCustomDomainLastValidated

Update the custom domain last validated timestamp to now (UTC ISO 8601).

f
updateEmailTemplate

Update a custom email template (encrypted at rest). Pass empty string to clear (revert to default).

f
updateEmbedHosts

Update allowed embed hosts (encrypted at rest) Pass empty string to clear the restriction

f
updatePhonePrefix

Update the configured phone prefix.

f
updateSquareLocationId

Store Square location ID (plaintext - not sensitive)

f
updateTermsAndConditions

Update terms and conditions text Pass empty string to clear

f
updateTheme

Update the configured theme.

f
updateTimezone

Update the configured timezone.

f
updateUserPassword

Update a user's password and re-wrap DATA_KEY with new KEK Requires the user's old password hash (decrypted) and their user row

f
verifyUserPassword

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

f
writeClosesAt

Encrypt closes_at for DB storage (null/empty → encrypted empty)

f
writeEventDate

Encrypt event date for DB storage

Interfaces

Type Aliases

T
ActiveEventStats

Aggregated statistics for active events

T
ActivityLogInput

Activity log input for create

T
AttendeeInput

Input for creating an attendee atomically

T
BatchAvailabilityItem

Item for batch availability check

T
ColumnDef

Column definition for a table

T
CreateAttendeeResult

Result of atomic attendee creation

T
EmailTemplateFormat

Valid email template formats

T
EmailTemplateType

Valid email template types

T
EventWithActivityLog

Result type for event + activity log batch query

T
EventWithAttendeeRaw

Result type for event + single attendee query

T
EventWithAttendees

Result type for combined event + attendees query

T
GroupInput

Group input fields for create/update (camelCase)

T
HolidayInput

Holiday input fields for create/update (camelCase)

T
InputFor

Derive Input type from Row type and Schema

T
QueryLogEntry

A single logged query

T
ReserveSessionResult

Result of session reservation attempt

T
TableSchema

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

Variables

v
activityLogTable

Activity log table definition message is encrypted - decrypted only for admin view

v
v
DEFAULT_BOOKABLE_DAYS

Default bookable days (all days of the week)

v
EVENTS_CACHE_TTL_MS

In-memory events cache. Loads all events with attendee counts in a single query and serves subsequent reads from memory until the TTL expires or a write invalidates the cache.

v
eventsTable
No documentation available
v
getAppleWalletPassTypeIdFromDb
No documentation available
v
getAppleWalletSigningCertFromDb
No documentation available
v
getAppleWalletSigningKeyFromDb
No documentation available
v
getAppleWalletTeamIdFromDb
No documentation available
v
getAppleWalletWwdrCertFromDb
No documentation available
v
getContactPageTextFromDb
No documentation available
v
getCustomDomainFromDb
No documentation available
v
getEmailApiKeyFromDb
No documentation available
v
getEmailFromAddressFromDb
No documentation available
v
getEmailProviderFromDb
No documentation available
v
getHeaderImageUrlFromDb
No documentation available
v
getHomepageTextFromDb
No documentation available
v
getShowPublicApiFromDb
No documentation available
v
getShowPublicSiteFromDb
No documentation available
v
getSquareAccessTokenFromDb
No documentation available
v
getSquareSandboxFromDb
No documentation available
v
getSquareWebhookSignatureKeyFromDb
No documentation available
v
getStripeSecretKeyFromDb
No documentation available
v
getStripeWebhookSecretFromDb
No documentation available
v
getWebsiteTitleFromDb
No documentation available
v
GROUPS_CACHE_TTL_MS

In-memory groups cache. Loads all groups in a single query and serves subsequent reads from memory until the TTL expires or a write invalidates the cache.

v
groupsTable

Groups table with CRUD operations — writes auto-invalidate the cache

v
HOLIDAYS_CACHE_TTL_MS

In-memory holidays cache. Loads all holidays in a single query and serves subsequent reads from memory until the TTL expires or a write invalidates the cache.

v
holidaysTable

Holidays table with CRUD operations — writes auto-invalidate the cache

v
LATEST_UPDATE

The latest database update identifier - update this when changing schema

v
MASK_SENTINEL

Sentinel value rendered in password fields for configured secrets. The actual secret is never sent to the browser — only this placeholder. On form submission, if the value equals the sentinel, the update is skipped.

v
MAX_EMAIL_TEMPLATE_LENGTH

Max length for email templates

v
MAX_PAGE_TEXT_LENGTH

Max length for page text content

v
MAX_TERMS_LENGTH

Max length for terms and conditions text

v
MAX_WEBSITE_TITLE_LENGTH

Max length for website title

v
SETTINGS_CACHE_TTL_MS

In-memory settings cache. Loads all rows in a single query and serves subsequent reads from memory until the TTL expires or a write invalidates the cache.

v
settingsApi

Stubbable API for testing - allows mocking in ES modules Use spyOn(settingsApi, "method") instead of spyOn(settingsModule, "method")

v
STALE_RESERVATION_MS

Threshold for considering an unfinalized reservation abandoned (5 minutes)

v
updateAppleWalletPassTypeId
No documentation available
v
updateAppleWalletSigningCert
No documentation available
v
updateAppleWalletSigningKey
No documentation available
v
updateAppleWalletTeamId
No documentation available
v
updateAppleWalletWwdrCert
No documentation available
v
updateContactPageText
No documentation available
v
updateCustomDomain
No documentation available
v
updateEmailApiKey
No documentation available
v
updateEmailFromAddress
No documentation available
v
updateEmailProvider
No documentation available
v
updateHeaderImageUrl
No documentation available
v
updateHomepageText
No documentation available
v
updateShowPublicApi
No documentation available
v
updateShowPublicSite
No documentation available
v
updateSquareAccessToken
No documentation available
v
updateSquareSandbox
No documentation available
v
updateSquareWebhookSignatureKey
No documentation available
v
updateStripeKey
No documentation available
v
updateWebsiteTitle
No documentation available
v
USERS_CACHE_TTL_MS

In-memory users cache. Loads all rows in a single query and serves subsequent reads from memory until the TTL expires or a write invalidates the cache.

Usage

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