import { type DeleteRangeOptions } from './delete-range.ts'; import { type BatchOperation, type ConditionalBatchCondition, type ScanOptions, type Storage, type StorageCapabilities } from './interface.ts'; import { type NeonQueryResult } from './neon-value-mapping.ts'; /** * A connection that can run a single interactive transaction. Obtained from * {@link PostgresPool.connect}; `release()` returns it to the pool. Both * `batch()` and `conditionalBatch()` drive `BEGIN`/`COMMIT`/`ROLLBACK` over one * of these so every statement in a transaction lands on the same connection — * `pool.query()` alone may scatter statements across pooled connections, which * would make a multi-statement batch non-atomic. */ export type PostgresPoolClient = { query(sql: string, parameters?: unknown[]): Promise; release(): void; }; /** * Minimal structural view of a node-postgres `Pool`. Both the `pg` `Pool` and * the Neon serverless `Pool` satisfy this; the PGlite test backend is wrapped to * satisfy it too. `query()` runs a single statement on a pooled connection (used * for the single-statement hot paths); `connect()` pins a connection for an * interactive transaction; `end()` tears the pool down. */ export type PostgresPool = { query(sql: string, parameters?: unknown[]): Promise; connect(): Promise; end(): Promise; }; /** * Configuration shared by every Postgres-wire storage adapter (the native `pg` * {@link PostgresPool}-backed adapter and the Neon serverless one). */ export type PostgresKeyValueStorageOptions = { /** * Postgres connection string. Required only when no `pool` is supplied — the * adapter builds its own pool from this via the subclass's `poolFactory`. When * `pool` is given, `url` is ignored and may be omitted entirely. */ url?: string; /** * Optional pre-built pool. Pass this to reuse a pool you manage (for example a * test backend such as PGlite, or a shared application pool), instead of having * the adapter construct its own from `url`. When supplied, `url` is ignored and * **ownership stays with the caller**: disposing the adapter does NOT close an * injected pool, so it can be shared across adapters and the caller remains * responsible for ending it. A pool the adapter constructs itself (from `url`) * IS closed on disposal. */ pool?: PostgresPool; /** * Postgres schema to contain the kv table. Default: unqualified — the table * resolves through `search_path` (in practice `public`). When set, the adapter * creates the schema if absent (`CREATE SCHEMA IF NOT EXISTS`) and qualifies * every statement as `"schema"."table"`. Lets Weft live in its own schema * alongside the application's tables in one database — one PITR line, no Drizzle * drift/drop risk. Validated as a strict Postgres identifier at construction. */ schema?: string; /** * Table name. Default: `'kv'`. Validated as a strict Postgres identifier at * construction. With neither `schema` nor `table` set, the adapter emits * byte-identical SQL against the unqualified `kv` table (existing deployments * are unaffected). */ table?: string; }; /** * Driver-agnostic base for Weft's Postgres-wire storage adapters. Implements the * full `Storage` interface over a single `kv(key TEXT COLLATE "C", value BYTEA)` * table using the structural {@link PostgresPool} seam, so switching between the * native `pg` driver and the Neon serverless driver is a subclass choice, not a * behavior change. Everything driver-specific — the driver import and the default * connection-pool construction — lives in the concrete subclass, which passes a * `poolFactory` to this constructor; the base itself carries no driver dependency. * * **Endpoint assumption.** `capabilities()` reports `readAfterWrite: * 'linearizable'`, which holds for the **primary** endpoint. A read-replica * connection string would violate that guarantee — point this adapter at the * primary. * * @see {@link PostgresStorage} for the native `pg` adapter and {@link NeonStorage} * for the Neon serverless adapter. */ export declare class PostgresKeyValueStorage implements Storage { #private; /** * @param options Connection configuration ({@link PostgresKeyValueStorageOptions}). * @param poolFactory Constructs the owned pool from `url`. Required — the * concrete subclass injects its driver's pool constructor here (lazily loaded) * so the base module never imports a driver. Used only when no `pool` is * supplied; an injected `pool` stays caller-owned. Throws if neither `pool` * nor `url` is provided. */ constructor(options: PostgresKeyValueStorageOptions, poolFactory: (url: string) => PostgresPool); capabilities(): StorageCapabilities; get(key: string): Promise; put(key: string, value: Uint8Array): Promise; delete(key: string): Promise; has(key: string): Promise; deletePrefix(prefix: string): Promise; deleteRange(prefix: string, options: DeleteRangeOptions): Promise; scan(prefix: string, options?: ScanOptions): AsyncIterable<[string, Uint8Array]>; keys(prefix: string, options?: ScanOptions): AsyncIterable; count(prefix: string): Promise; scoped(prefix: string): Storage; batch(operations: BatchOperation[]): Promise; conditionalBatch(conditions: ConditionalBatchCondition[], operations: BatchOperation[]): Promise; query(sql: string, parameters?: unknown[]): Promise; [Symbol.dispose](): void; [Symbol.asyncDispose](): Promise; }