/** * Shared RPC Types for postgres.do * * These types define the capnweb RPC contract between: * - Client: postgres.do (this package) * - Server: @dotdo/postgres Worker * * IMPORTANT: This file is the single source of truth for RPC types. * Both client and server MUST use these types to ensure type safety. * * @see packages/postgres/src/worker/rpc.ts - Server-side RPC implementation * @see packages/postgres.do/src/transport/rpc.ts - Client-side RPC transport */ // ============================================================================ // Base Types // ============================================================================ /** * Generic row type for query results * Used as a constraint for typed query results */ export type RpcRow = Record /** * Field metadata from query results * Maps to PostgreSQL's column metadata */ export interface RpcField { /** 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?: string } // ============================================================================ // Query Types // ============================================================================ /** * RPC query result * * Returned from all query operations (query, queryOne, execute, etc.) */ export interface RpcQueryResult { /** Query result rows */ rows: T[] /** Field metadata */ fields: RpcField[] /** Number of affected rows (for INSERT/UPDATE/DELETE) or returned rows */ rowCount: number /** Query execution time in milliseconds */ durationMs: number } /** * RPC batch query item * * Single query within a batch operation */ export interface RpcBatchQuery { /** SQL query string */ sql: string /** Query parameters (positional: $1, $2, etc.) */ params?: unknown[] } /** * RPC batch result * * Returned from batch and batchTransaction operations */ export interface RpcBatchResult { /** Results for each query in order */ results: RpcQueryResult[] /** Total execution time in milliseconds */ durationMs: number } // ============================================================================ // Transaction Types // ============================================================================ /** * Transaction isolation levels * * Follows PostgreSQL's isolation level semantics */ export type RpcIsolationLevel = | 'READ UNCOMMITTED' | 'READ COMMITTED' | 'REPEATABLE READ' | 'SERIALIZABLE' /** * Transaction options * * Passed to transaction() and batchTransaction() operations */ export interface RpcTransactionOptions { /** Isolation level for the transaction */ isolationLevel?: RpcIsolationLevel /** Read-only transaction hint (enables optimizations) */ readOnly?: boolean /** Deferrable (only valid with SERIALIZABLE + READ ONLY) */ deferrable?: boolean } /** * Transaction state */ export type RpcTransactionState = 'active' | 'committed' | 'rolled_back' // ============================================================================ // Error Types // ============================================================================ /** * RPC error response structure * * Follows PostgreSQL error format with additional fields */ export interface RpcError { /** Error message */ message: string /** PostgreSQL error code (e.g., '23505' for unique violation) */ code?: string /** Error severity (ERROR, WARNING, etc.) */ severity?: string /** Detailed error message */ detail?: string /** Hint for fixing the error */ hint?: string /** Position in query where error occurred */ position?: number /** Schema name if relevant */ schema?: string /** Table name if relevant */ table?: string /** Column name if relevant */ column?: string /** Constraint name if relevant */ constraint?: string } // ============================================================================ // RPC Message Types (Wire Protocol) // ============================================================================ /** * RPC message types for the WebSocket protocol * * These define the request/response types used over the wire */ export enum RpcMessageType { // === Requests === /** Single query request */ Query = 'query', /** Batch query request */ Batch = 'batch', /** Batch transaction request */ BatchTransaction = 'batch_tx', /** Start transaction request */ Transaction = 'transaction', /** Query within transaction */ TransactionQuery = 'tx_query', /** Commit transaction */ TransactionCommit = 'tx_commit', /** Rollback transaction */ TransactionRollback = 'tx_rollback', /** Ping for keepalive */ Ping = 'ping', /** Authentication request */ Auth = 'auth', // === Responses === /** Query result response */ QueryResult = 'query_result', /** Batch result response */ BatchResult = 'batch_result', /** Transaction result response */ TransactionResult = 'tx_result', /** Error response */ Error = 'error', /** Pong response */ Pong = 'pong', /** Auth result response */ AuthResult = 'auth_result', } // ============================================================================ // RPC Request Messages // ============================================================================ /** * Base RPC message */ interface RpcMessageBase { /** Message type */ type: RpcMessageType /** Request ID for correlation */ id: number } /** * Query request message */ export interface RpcQueryRequest extends RpcMessageBase { type: RpcMessageType.Query /** SQL query string */ sql: string /** Query parameters */ params?: unknown[] } /** * Batch query request message */ export interface RpcBatchRequest extends RpcMessageBase { type: RpcMessageType.Batch /** Queries to execute */ queries: RpcBatchQuery[] } /** * Batch transaction request message */ export interface RpcBatchTransactionRequest extends RpcMessageBase { type: RpcMessageType.BatchTransaction /** Queries to execute */ queries: RpcBatchQuery[] /** Transaction options */ options?: RpcTransactionOptions } /** * Authentication request message */ export interface RpcAuthRequest extends RpcMessageBase { type: RpcMessageType.Auth /** API key for authentication */ apiKey?: string } /** * Ping request message */ export interface RpcPingRequest extends RpcMessageBase { type: RpcMessageType.Ping } // ============================================================================ // RPC Response Messages // ============================================================================ /** * Query result response message */ export interface RpcQueryResultMessage extends RpcMessageBase { type: RpcMessageType.QueryResult /** Result rows */ rows: T[] /** Field metadata */ fields: RpcField[] /** Number of affected/returned rows */ rowCount: number /** Query execution time */ durationMs: number /** Command type (SELECT, INSERT, etc.) */ command?: string } /** * Batch result response message */ export interface RpcBatchResultMessage extends RpcMessageBase { type: RpcMessageType.BatchResult /** Results for each query */ results: RpcQueryResult[] /** Total execution time */ durationMs: number } /** * Error response message */ export interface RpcErrorMessage extends RpcMessageBase { type: RpcMessageType.Error /** Error details */ error: RpcError } /** * Auth result response message */ export interface RpcAuthResultMessage extends RpcMessageBase { type: RpcMessageType.AuthResult /** Whether authentication succeeded */ success: boolean /** Error message if failed */ error?: string } /** * Pong response message */ export interface RpcPongMessage extends RpcMessageBase { type: RpcMessageType.Pong } // ============================================================================ // Union Types // ============================================================================ /** * All possible RPC request message types */ export type RpcRequestMessage = | RpcQueryRequest | RpcBatchRequest | RpcBatchTransactionRequest | RpcAuthRequest | RpcPingRequest /** * All possible RPC response message types */ export type RpcResponseMessage = | RpcQueryResultMessage | RpcBatchResultMessage | RpcErrorMessage | RpcAuthResultMessage | RpcPongMessage /** * All RPC message types */ export type RpcMessage = RpcRequestMessage | RpcResponseMessage // ============================================================================ // Server API Interface // ============================================================================ /** * PostgresRpcApi interface * * This interface defines the RPC API that the server exposes. * Clients use this interface (via capnweb RPC stubs) to call server methods. * * @example Server-side implementation in @dotdo/postgres: * ```typescript * import type { IPostgresRpcApi } from 'postgres.do/rpc' * * export class PostgresRpcApi extends RpcTarget implements IPostgresRpcApi { * async query(sql: string, params?: unknown[]): Promise> { * // ...implementation * } * } * ``` * * @example Client-side usage: * ```typescript * import { createClient } from 'postgres.do/rpc' * * const db = createClient('postgres.do/my-database') * const result = await db.query('SELECT * FROM users') * ``` */ export interface IPostgresRpcApi { /** * Execute a SQL query */ query( sql: string, params?: unknown[] ): Promise> /** * Execute a query and return only the first row */ queryOne( sql: string, params?: unknown[] ): Promise /** * Execute a query and return the scalar value (first column of first row) */ queryScalar( sql: string, params?: unknown[] ): Promise /** * Execute a SQL statement that doesn't return rows */ execute( sql: string, params?: unknown[] ): Promise<{ rowCount: number; durationMs: number }> /** * Execute a batch of queries */ batch(queries: RpcBatchQuery[]): Promise /** * Execute a batch of queries within a transaction */ batchTransaction( queries: RpcBatchQuery[], options?: RpcTransactionOptions ): Promise /** * Health check */ ping(): Promise<{ ok: true; durationMs: number }> /** * Get database version */ version(): Promise /** * List all tables in the public schema */ listTables(): Promise /** * Get table schema information */ describeTable(tableName: string): Promise> /** * Get database name */ getDatabase(): string } /** * Transaction RPC API interface */ export interface ITransactionRpcApi { /** * Execute a query within this transaction */ query( sql: string, params?: unknown[] ): Promise> /** * Commit the transaction */ commit(): Promise<{ success: true; durationMs: number }> /** * Rollback the transaction */ rollback(): Promise<{ success: true; durationMs: number }> /** * Get transaction state */ getState(): RpcTransactionState /** * Get number of queries executed in this transaction */ getQueryCount(): number }