import { Dialect, Kysely } from "kysely"; //#region src/db/hyperdrive.d.ts /** * Hyperdrive configuration (runtime type — matches the config-time type in * index.ts). */ interface HyperdriveConfig { binding: string; max?: number; /** * Optional binding for a cache-enabled Hyperdrive config over the same * database. When set, anonymous read requests route through it; all * authenticated requests and all writes stay on `binding`. */ cachedBinding?: string; } /** * Create a PostgreSQL dialect backed by a Hyperdrive binding. * * Used for the per-isolate singleton Kysely, which serves cold-start migrations * only. The request path reads through `createRequestScopedDb`, and the * background/plugin paths resolve an event-scoped connection from ALS, so * neither reuses this singleton's request-bound socket across events. */ declare function createDialect(config: HyperdriveConfig): Dialect; /** * A cookie interface minimally compatible with Astro's AstroCookies. Declared * here (not imported from astro) so this module stays free of astro types. */ interface CookieJar { get(name: string): { value: string; } | undefined; set(name: string, value: string, options: Record): void; } interface RequestScopedDbOpts { config: HyperdriveConfig; isAuthenticated: boolean; isWrite: boolean; cookies: CookieJar; url: URL; } interface RequestScopedDb { /** Per-request Kysely instance backed by a fresh pg Pool. */ db: Kysely; /** * No per-request state to persist (Hyperdrive routes and caches itself, so * there are no bookmark cookies). Kept to satisfy the adapter contract. */ commit: () => void; /** * Close the per-request pool. The middleware calls this once the response * body has fully streamed — not before — because Astro streams HTML and the * Live loader issues queries while the body streams; tearing the pool down * any earlier yields "driver has already been destroyed". Draining is handed * to `waitUntil` so it never blocks, while the socket stays valid for the * whole request it was opened in. */ close: () => void; } /** * Create a fresh, request-scoped Kysely backed by its own pg Pool. EmDash * middleware calls this once per request, stashes `db` in ALS for the duration * of next(), then closes it once the response body has streamed. * * Hyperdrive itself routes reads/writes and handles caching, so this adapter * does not need bookmark cookies or read-replica constraints — every request * gets an equivalent connection. */ declare function createRequestScopedDb(opts: RequestScopedDbOpts): RequestScopedDb | null; /** * Decide which binding a given request should use. * * The cache-enabled binding (when configured) is used only for **anonymous * reads of public-site paths** — the one class of request that tolerates a * short staleness window. Everything else uses the primary uncached binding to * preserve read-after-write consistency: * * - authenticated requests (editors/authors) → primary; * - writes (`POST`/`PUT`/`DELETE`) → primary; * - **any request under `/_emdash`** (admin, setup, auth, internal APIs), * even an anonymous GET → primary. The setup-status and login-state reads * are anonymous GETs that must see writes made moments earlier; routing them * to the cache would loop the setup wizard and show stale auth state. * * Pure (no I/O) so the routing rule can be unit-tested directly. */ declare function selectBindingName(config: HyperdriveConfig, opts: { isAuthenticated: boolean; isWrite: boolean; url: URL; }): string; //#endregion export { RequestScopedDb, RequestScopedDbOpts, createDialect, createRequestScopedDb, selectBindingName };