import { PostgresError as PostgresError$1, ConnectionError as ConnectionError$1, ConnectionTimeoutError } from '@dotdo/postgres-shared/errors'; /** * PostgreSQL client types for postgres.do * Compatible with Drizzle ORM and direct usage */ /** A single row returned from a query */ type Row = Record; /** Result of a query execution */ interface QueryResult { /** Rows returned by the query */ rows: T[]; /** Number of rows affected (for INSERT/UPDATE/DELETE) */ rowCount: number; /** Column metadata */ fields: FieldInfo[]; /** Command type (SELECT, INSERT, etc.) */ command: string; } /** Column/field metadata */ interface FieldInfo { /** Column name */ name: string; /** PostgreSQL OID for the column type */ dataTypeID: number; /** Table OID (0 if not from a table) */ tableID: number; /** Column position in table */ columnID: number; /** Data type size in bytes (-1 for variable) */ dataTypeSize: number; /** Type modifier */ dataTypeModifier: number; /** Format code (0 = text, 1 = binary) */ format: number; } /** Type parser function */ type TypeParser = (value: string) => unknown; /** Configuration options for the postgres client */ interface PostgresConfig { /** Database connection URL (postgres://...) */ url?: string; /** API key for postgres.do authentication */ apiKey?: string; /** Transport type: 'http' (default) or 'ws' */ transport?: 'http' | 'ws'; /** Custom type parsers by OID */ parsers?: Record; /** Connection timeout in milliseconds */ connectTimeout?: number; /** Query timeout in milliseconds */ queryTimeout?: number; /** Maximum number of retry attempts */ maxRetries?: number; /** Whether to use SSL/TLS */ ssl?: boolean | 'require' | 'prefer' | 'allow' | 'disable'; /** Custom fetch implementation (for Cloudflare Workers) */ fetch?: typeof fetch; /** Custom WebSocket implementation */ WebSocket?: typeof WebSocket; /** Enable debug logging */ debug?: boolean; /** Transform column names (e.g., snake_case to camelCase) */ transform?: { column?: (name: string) => string; value?: (value: unknown, column: string) => unknown; }; /** * Default transaction retry configuration. * These settings are used as defaults for all transactions initiated with begin(). * Transaction-level options can override these defaults. */ transactionRetry?: { /** Automatically retry on serialization failure (error code 40001) */ retryOnSerializationFailure?: boolean; /** Automatically retry on deadlock (error code 40P01) */ retryOnDeadlock?: boolean; /** Maximum retry attempts (default: 3) */ maxRetries?: number; /** Base delay in milliseconds for exponential backoff (default: 10) */ backoffMs?: number; }; } /** Pending query that can be executed */ interface PendingQuery extends Promise { /** Execute the query and return rows */ execute(): Promise; /** Get the parameterized SQL string */ toString(): string; /** Get query values/parameters */ values: unknown[]; /** Get the SQL template string */ strings: TemplateStringsArray; } /** Transaction isolation levels */ type IsolationLevel = 'read uncommitted' | 'read committed' | 'repeatable read' | 'serializable'; /** Lock mode types */ type LockMode = 'access share' | 'row share' | 'row exclusive' | 'share update exclusive' | 'share' | 'share row exclusive' | 'exclusive' | 'access exclusive'; /** Transaction options */ interface TransactionOptions { /** Isolation level */ isolationLevel?: IsolationLevel; /** Read only transaction */ readOnly?: boolean; /** Deferrable (only with serializable + read only) */ deferrable?: boolean; /** Named transaction (for debugging/logging) */ name?: string; /** * Transaction timeout in milliseconds. * This is the total timeout across all retry attempts. * When retries are enabled, the timeout counts from the start of the first attempt. */ timeout?: number; /** * Per-retry timeout in milliseconds. * When set, each retry attempt gets a fresh timeout of this duration. * This is useful when you want to allow each attempt to take up to N ms, * but the total time can exceed that due to retries. * If both `timeout` and `perRetryTimeout` are set, `timeout` takes precedence * (the total timeout will be enforced). */ perRetryTimeout?: number; /** Lock mode for explicit table locking */ lockMode?: LockMode; /** Automatically retry on serialization failure (error code 40001) */ retryOnSerializationFailure?: boolean; /** Automatically retry on deadlock (error code 40P01) */ retryOnDeadlock?: boolean; /** Maximum retry attempts (default: 3) */ maxRetries?: number; /** Base delay in milliseconds for exponential backoff (default: 10) */ backoffMs?: number; /** Callback called before each retry attempt */ onRetry?: (attempt: number, error: Error) => void | Promise; } /** * Options for streaming queries */ interface StreamOptions { /** Batch size for fetching rows (default: 100) */ batchSize?: number; /** Custom cursor name (auto-generated if not provided) */ cursorName?: string; /** Transaction isolation level for the cursor */ isolationLevel?: IsolationLevel; /** Whether the cursor should be read-only (default: true) */ readOnly?: boolean; } /** * Result of a cursor fetch operation */ interface CursorFetchResult { /** Rows fetched in this batch */ rows: T[]; /** Whether there are more rows to fetch */ hasMore: boolean; /** Total number of rows fetched so far */ totalFetched: number; } /** * Cursor interface for manual control over streaming */ interface Cursor extends AsyncIterable { /** Whether the cursor is still open */ readonly isOpen: boolean; /** Total number of rows fetched so far */ readonly totalFetched: number; /** Column metadata from the query */ readonly fields: FieldInfo[]; /** * Fetch the next batch of rows * @param count - Number of rows to fetch (default: batch size) * @returns Array of rows (empty array if no more rows) */ fetch(count?: number): Promise; /** * Fetch the next batch of rows with additional metadata * @param count - Number of rows to fetch (default: batch size) * @returns Result object with rows, hasMore flag, and total fetched count */ fetchWithInfo(count?: number): Promise>; /** * Close the cursor and release resources * Always call this when done, or use for-await-of which closes automatically */ close(): Promise; } /** * Stream result interface for fluent streaming API */ interface StreamResult extends AsyncIterable { /** The SQL query being streamed */ readonly sql: string; /** The query parameters */ readonly params: unknown[]; /** * Stream rows in batches * @param size - Number of rows per batch * @returns AsyncIterable of row arrays * @example * for await (const batch of sql.stream`SELECT * FROM users`.batch(1000)) { * processBatch(batch) * } */ batch(size: number): AsyncIterable; /** * Get a cursor for manual control * @returns A cursor that can be used to fetch rows manually * @example * const cursor = await sql.stream`SELECT * FROM users`.cursor() * while (const rows = await cursor.fetch(100)) { * process(rows) * } * await cursor.close() */ cursor(): Promise>; } /** * Query middleware function signature (forward declaration for types) * Full implementation is in middleware.ts */ type QueryMiddlewareFn = (request: { sql: string; params: unknown[]; timestamp: number; queryId: string; context?: Record; }, next: () => Promise<{ result: QueryResult; durationMs: number; success: boolean; error?: Error; metadata?: Record; }>) => Promise<{ result: QueryResult; durationMs: number; success: boolean; error?: Error; metadata?: Record; }>; /** * Main SQL client interface * Compatible with Drizzle ORM integration */ interface Sql { /** * Execute a SQL query using tagged template literal * @example * const users = await sql`SELECT * FROM users WHERE id = ${userId}` */ (strings: TemplateStringsArray, ...values: unknown[]): PendingQuery; /** * Execute raw SQL (use with caution - no parameterization) * This is used by Drizzle ORM for generated queries * @param query - Raw SQL query string * @param params - Optional query parameters */ unsafe(query: string, params?: unknown[]): Promise; /** * Begin a transaction * Compatible with Drizzle ORM transaction interface * @param fn - Transaction callback function * @param options - Transaction options */ begin(fn: (sql: TransactionSql) => Promise, options?: TransactionOptions): Promise; /** * Create a savepoint within a transaction * For nested transaction support * @param fn - Savepoint callback function */ savepoint(fn: (sql: TransactionSql) => Promise): Promise; /** * End the connection/session */ end(): Promise; /** * Stream large result sets using PostgreSQL cursors * Keeps memory usage constant regardless of result size * @example * // Stream rows one at a time * for await (const row of sql.stream`SELECT * FROM huge_table`) { * process(row) * } * * // Stream in batches * for await (const batch of sql.stream`SELECT * FROM huge_table`.batch(1000)) { * processBatch(batch) * } * * // Manual cursor control * const cursor = await sql.stream`SELECT * FROM huge_table`.cursor() * while (const rows = await cursor.fetch(100)) { * process(rows) * } * await cursor.close() */ stream(strings: TemplateStringsArray, ...values: unknown[]): StreamResult; /** * Add a query middleware to the chain * Middlewares are executed in the order they are added * @param middleware - The middleware function to add * @returns The same Sql instance for chaining * @example * const sql = postgres() * .use(loggingMiddleware({ level: 'info' })) * .use(metricsMiddleware({ onMetric: console.log })) */ use(middleware: QueryMiddlewareFn): this; /** * Client configuration options * Includes type parsers and serializers for Drizzle compatibility */ options: { parsers: Record; serializers: Record string>; [key: string]: unknown; }; /** * Reserve a connection from the pool * Returns a client with exclusive connection */ reserve(): Promise; /** * Commit a prepared transaction (two-phase commit) * @param transactionId - The ID returned from prepare() */ commitPrepared(transactionId: string): Promise; /** * Rollback a prepared transaction (two-phase commit) * @param transactionId - The ID returned from prepare() */ rollbackPrepared(transactionId: string): Promise; /** * Subscribe to changes on a table * @param table - Table name (optionally with schema: "schema.table") * @param options - Subscription options * @returns A subscription that can be iterated over or used with callbacks * @example * // Using async iteration * const sub = await sql.subscribe('users') * for await (const event of sub) { * console.log(event.operation, event.newRow) * } * * // Using callbacks * const sub = await sql.subscribe('users', { * onInsert: (row) => console.log('New user:', row), * onUpdate: (newRow, oldRow) => console.log('Updated:', newRow), * onDelete: (oldRow) => console.log('Deleted:', oldRow) * }) */ subscribe(table: string, options?: CDCClientSubscribeOptions): Promise>; /** * Unsubscribe from a subscription by ID * @param subscriptionId - The subscription ID to unsubscribe from */ unsubscribe(subscriptionId: string): Promise; /** * Get all active subscriptions * @returns Array of active subscriptions */ subscriptions(): CDCClientSubscriptionInfo[]; } /** Transaction-specific SQL interface */ interface TransactionSql extends Omit { /** * Create a savepoint within the transaction */ savepoint(fn: (sql: TransactionSql) => Promise): Promise; /** * Acquire an exclusive advisory lock that is released when the transaction ends (blocking). * @param lockId - Lock identifier (number or bigint for single-key) * @example await tx.advisoryLock(12345) */ advisoryLock(lockId: number | bigint): Promise; /** * Acquire an exclusive advisory lock with namespace (blocking). * @param classId - Lock class/namespace identifier (int4) * @param objId - Object identifier within the namespace (int4) * @example await tx.advisoryLock(1, 42) // namespace 1, object 42 */ advisoryLock(classId: number, objId: number): Promise; /** * Try to acquire an exclusive advisory lock without blocking. * @param lockId - Lock identifier (number or bigint for single-key) * @returns true if lock was acquired, false otherwise * @example const acquired = await tx.tryAdvisoryLock(12345) */ tryAdvisoryLock(lockId: number | bigint): Promise; /** * Try to acquire an exclusive advisory lock with namespace without blocking. * @param classId - Lock class/namespace identifier (int4) * @param objId - Object identifier within the namespace (int4) * @returns true if lock was acquired, false otherwise * @example const acquired = await tx.tryAdvisoryLock(1, 42) */ tryAdvisoryLock(classId: number, objId: number): Promise; /** * Acquire a shared advisory lock that is released when the transaction ends (blocking). * Multiple sessions can hold a shared lock simultaneously; blocks only if exclusive lock is held. * @param lockId - Lock identifier (number or bigint for single-key) * @example await tx.advisoryLockShared(12345) */ advisoryLockShared(lockId: number | bigint): Promise; /** * Acquire a shared advisory lock with namespace (blocking). * @param classId - Lock class/namespace identifier (int4) * @param objId - Object identifier within the namespace (int4) * @example await tx.advisoryLockShared(1, 42) */ advisoryLockShared(classId: number, objId: number): Promise; /** * Try to acquire a shared advisory lock without blocking. * @param lockId - Lock identifier (number or bigint for single-key) * @returns true if lock was acquired, false if exclusive lock is held * @example const acquired = await tx.tryAdvisoryLockShared(12345) */ tryAdvisoryLockShared(lockId: number | bigint): Promise; /** * Try to acquire a shared advisory lock with namespace without blocking. * @param classId - Lock class/namespace identifier (int4) * @param objId - Object identifier within the namespace (int4) * @returns true if lock was acquired, false if exclusive lock is held * @example const acquired = await tx.tryAdvisoryLockShared(1, 42) */ tryAdvisoryLockShared(classId: number, objId: number): Promise; /** * Prepare transaction for two-phase commit * After calling this, the transaction must be committed with commitPrepared() * @param transactionId - Unique identifier for the prepared transaction * @returns The transaction ID */ prepare(transactionId: string): Promise; /** * Register a callback to run after transaction commits * @param fn - Callback function */ onCommit(fn: () => void | Promise): void; /** * Register a callback to run after transaction rolls back * @param fn - Callback function */ onRollback(fn: () => void | Promise): void; /** * Current transaction ID (xid) * Lazily fetched from the database */ readonly txid: string | undefined; /** * Transaction name (if provided in options) */ readonly name: string | undefined; /** * Current retry attempt number (0 for first attempt, 1 for first retry, etc.) * Only set when retryOnSerializationFailure or retryOnDeadlock is enabled. */ readonly retryCount: number; } /** Reserved connection SQL interface */ interface ReservedSql extends Sql { /** * Release the reserved connection back to the pool */ release(): Promise; } /** Transport interface for sending queries */ interface Transport { /** Send a query and receive results */ query(sql: string, params?: unknown[]): Promise>; /** Execute multiple queries in a transaction */ transaction(queries: Array<{ sql: string; params?: unknown[]; }>, options?: TransactionOptions): Promise; /** Close the transport connection */ close(): Promise; /** Check if transport is connected */ isConnected(): boolean; } /** HTTP transport configuration */ interface HttpTransportConfig { /** Base URL for the postgres.do API */ baseUrl: string; /** API key for authentication */ apiKey?: string | undefined; /** Custom fetch implementation */ fetch?: typeof fetch | undefined; /** Request timeout in milliseconds */ timeout?: number | undefined; /** Custom headers */ headers?: Record | undefined; } /** WebSocket transport configuration */ interface WsTransportConfig { /** WebSocket URL for postgres.do */ url: string; /** API key for authentication */ apiKey?: string | undefined; /** Custom WebSocket implementation */ WebSocket?: typeof WebSocket | undefined; /** Connection timeout in milliseconds */ connectTimeout?: number | undefined; /** Ping interval in milliseconds */ pingInterval?: number | undefined; } /** * CDC operation types for PostgreSQL change notifications */ type CDCOperation = 'INSERT' | 'UPDATE' | 'DELETE' | 'TRUNCATE'; /** * CDC change event representing a single database change */ interface CDCChangeEvent { /** Unique event ID (typically LSN-based) */ id: string; /** PostgreSQL Log Sequence Number for this change */ lsn: string; /** Type of operation that caused this change */ operation: CDCOperation; /** Table name where the change occurred */ table: string; /** Schema name */ schema: string; /** Timestamp when the change occurred */ timestamp: Date; /** New row data (for INSERT and UPDATE) */ newRow?: Row | undefined; /** Old row data (for UPDATE and DELETE) */ oldRow?: Row | undefined; /** Columns that were changed (for UPDATE) */ changedColumns?: string[] | undefined; /** Transaction ID */ xid: number; /** Whether this is the last change in the transaction */ isLastInTransaction: boolean; } /** * Options for CDC subscriptions */ interface CDCSubscriptionOptions { /** Event types to subscribe to (default: all) */ events?: CDCOperation[] | undefined; /** SQL filter expression for row-level filtering */ filter?: string | undefined; /** Resume from this LSN (for exactly-once delivery) */ resumeFrom?: string | undefined; /** Include old row data for UPDATE/DELETE events */ includeOldRow?: boolean | undefined; /** Track which columns changed for UPDATE events */ trackChangedColumns?: boolean | undefined; /** Batch size for event delivery */ batchSize?: number | undefined; /** Heartbeat interval in milliseconds */ heartbeatInterval?: number | undefined; } /** * CDC Transport interface for streaming database changes */ interface CDCTransport { /** Connect to the CDC stream */ connect(): Promise; /** Disconnect from the CDC stream */ disconnect(): Promise; /** Check if connected */ isConnected(): boolean; /** Get the last event ID received */ getLastEventId(): string | null; /** Subscribe to a table */ subscribe(subscriptionId: string, table: string, schema: string, options: CDCSubscriptionOptions): Promise; /** Unsubscribe from a subscription */ unsubscribe(subscriptionId: string): Promise; /** Set the event handler */ onEvent(handler: (subscriptionId: string, event: CDCChangeEvent) => void): void; /** Set the error handler */ onError(handler: (subscriptionId: string, error: Error) => void): void; /** Set the reconnect handler */ onReconnect(handler: (attempt: number, lastLsn: string | undefined) => void): void; /** Set the close handler */ onClose(handler: () => void): void; } /** * CDC WebSocket transport configuration */ interface CDCWsTransportConfig { /** WebSocket URL for the CDC endpoint */ url: string; /** API key for authentication */ apiKey?: string | undefined; /** Custom WebSocket implementation */ WebSocket?: typeof WebSocket | undefined; /** Connection timeout in milliseconds */ connectTimeout?: number | undefined; /** Ping interval for keepalive in milliseconds */ pingInterval?: number | undefined; } /** * CDC SSE (Server-Sent Events) transport configuration */ interface CDCSseTransportConfig { /** URL for the CDC SSE endpoint */ url: string; /** API key for authentication */ apiKey?: string; /** Resume from this event ID (Last-Event-ID) */ resumeFrom?: string; /** Reconnection delay in milliseconds */ retryMs?: number; /** Custom fetch implementation */ fetch?: typeof fetch; /** Custom headers */ headers?: Record; } /** PostgreSQL error fields specific to postgres.do */ interface PostgresErrorFields { /** PostgreSQL error code (e.g., '23505' for unique violation) */ code?: string | undefined; /** Error severity */ severity?: string | undefined; /** Detailed error message */ detail?: string | undefined; /** Hint for fixing the error */ hint?: string | undefined; /** Position in query where error occurred */ position?: number | undefined; /** Schema name if relevant */ schema?: string | undefined; /** Table name if relevant */ table?: string | undefined; /** Column name if relevant */ column?: string | undefined; /** Constraint name if relevant */ constraint?: string | undefined; } /** * Error thrown by postgres.do client. * Extends the shared PostgresError with postgres.do-specific properties. */ declare class PostgresError extends PostgresError$1 { /** Error severity */ readonly severity: string; /** Detailed error message */ readonly detail: string | undefined; /** Hint for fixing the error */ readonly hint: string | undefined; /** Position in query where error occurred */ readonly position: number | undefined; /** PostgreSQL error code (e.g., '23505' for unique violation) */ readonly pgCode: string; constructor(message: string, fields?: PostgresErrorFields); /** Schema name if relevant */ get schema(): string | undefined; /** Table name if relevant */ get table(): string | undefined; /** Column name if relevant */ get column(): string | undefined; /** Constraint name if relevant */ get constraint(): string | undefined; } /** * Connection error. * Extends the shared ConnectionError. */ declare class ConnectionError extends ConnectionError$1 { constructor(message: string); } /** * Query timeout error. * Extends the shared ConnectionTimeoutError. */ declare class TimeoutError extends ConnectionTimeoutError { constructor(message?: string); } /** * Options for CDC client subscription */ interface CDCClientSubscribeOptions extends CDCSubscriptionOptions { /** Called for every change event */ onChange?: (event: CDCChangeEvent & { newRow?: T; oldRow?: T; }) => void | Promise; /** Called for INSERT events */ onInsert?: (row: T) => void | Promise; /** Called for UPDATE events */ onUpdate?: (newRow: T, oldRow?: T) => void | Promise; /** Called for DELETE events */ onDelete?: (oldRow: T) => void | Promise; /** Called when an error occurs */ onError?: (error: Error) => void; } /** * Client subscription interface for CDC streaming */ interface CDCClientSubscription extends AsyncIterable { /** Unique subscription ID */ readonly id: string; /** Table name */ readonly table: string; /** Schema name */ readonly schema: string; /** Whether the subscription is currently active */ readonly isActive: boolean; /** Last processed LSN for resumption */ readonly lastLsn: string | null; /** Unsubscribe and stop receiving events */ unsubscribe(): Promise; /** Register a handler for all change events */ onChange(handler: (event: CDCChangeEvent & { newRow?: T; oldRow?: T; }) => void | Promise): this; /** Register a handler for INSERT events */ onInsert(handler: (row: T) => void | Promise): this; /** Register a handler for UPDATE events */ onUpdate(handler: (newRow: T, oldRow?: T) => void | Promise): this; /** Register a handler for DELETE events */ onDelete(handler: (oldRow: T) => void | Promise): this; } /** * Information about an active subscription */ interface CDCClientSubscriptionInfo { /** Unique subscription ID */ id: string; /** Table name */ table: string; /** Schema name */ schema: string; /** Whether the subscription is currently active */ isActive: boolean; } export { type CDCTransport as C, type FieldInfo as F, type HttpTransportConfig as H, type IsolationLevel as I, type PostgresConfig as P, type QueryResult as Q, type Row as R, type Sql as S, type Transport as T, type WsTransportConfig as W, type TransactionOptions as a, type CDCWsTransportConfig as b, type CDCSubscriptionOptions as c, type CDCChangeEvent as d, type CDCSseTransportConfig as e, type TypeParser as f, type StreamOptions as g, type StreamResult as h, type Cursor as i, type TransactionSql as j, type ReservedSql as k, type PendingQuery as l, type CDCOperation as m, type CDCClientSubscription as n, type CDCClientSubscribeOptions as o, type CDCClientSubscriptionInfo as p, PostgresError as q, ConnectionError as r, TimeoutError as s, type PostgresErrorFields as t, type CursorFetchResult as u };