/** * Structural subset of `pg`'s `PoolClient`/`Client` this module needs — * defined locally so nothing here requires `@types/pg` to typecheck (the * dependency stays optional/lazy at both the type and runtime level). */ export interface PgQueryable { query(text: string, values?: unknown[]): Promise<{ rows: any[]; }>; } /** Structural subset of `pg`'s `Pool`/`Client` needed to BEGIN/COMMIT/ROLLBACK a transaction. */ export interface PgTransactionalClient extends PgQueryable { release?(): void; } /** * What `Worker` learns once at startup (see `Worker.run()`) via * `GetSqlContract` and hands to every activity's `ActivityContext`. * `storeKind !== 'postgres'` or a missing/empty `postgresTargetFingerprint` * means the server itself isn't running the Postgres tier — `ctx.transaction()` * must refuse outright regardless of `sameDatabase`/`degrade` config, per the * "Postgres tier only" requirement (Design Law 3 honesty: lite/non-Postgres get * the same loud error, never a silent fallback). */ export interface ServerSqlContractHandshake { storeKind: string; contractVersion: number; postgresTargetFingerprint: string; } /** Thrown by `ctx.transaction()` whenever it must refuse rather than fake a guarantee. */ export declare class TransactionalStepUnsupportedError extends Error { constructor(message: string); } /** * sha256 hex of `host:port/dbname`, matching * `crates/server/src/grpc/worker_service.rs::fingerprint_postgres_target` * byte-for-byte (same normalization: drop userinfo/credentials and query * string, default port 5432). Two connection strings that resolve to the * same physical database (possibly with different credentials) fingerprint * identically; anything else does not — this is the ENTIRE trust boundary * for "is the user database the memoflow store," so it must stay in lockstep * with the Rust implementation. */ export declare function fingerprintPostgresTarget(connectionString: string): string; export interface TransactionStepIdentity { namespace: string; workflowId: string; runId: string; stepSeq: number; stepKey: string; stepName: string; } /** * Runs `fn` inside a Postgres transaction opened against `connectionString` * (the user's own database), and — IF `handshake` proves that database is * the same physical Postgres instance/database as the memoflow store — * writes this step's COMPLETED checkpoint with the SAME transaction, using * the versioned SQL contract. `fn`'s return value becomes the step's * checkpointed result (JSON-serialized the same way a plain activity return * value would be, via the caller-supplied `serializeOutput`). * * Behavior when the databases differ (or the server isn't Postgres at all): * - `degrade === 'refuse'` (the default): throws `TransactionalStepUnsupportedError` * before running `fn` at all — never a fake guarantee. * - `degrade === 'at-least-once'`: runs `fn` inside a transaction against the * user's database as requested (still gets real DB transactionality for * the user's OWN writes), commits/rolls back normally, but does NOT write * the checkpoint here — the caller falls back to the ordinary * at-least-once CompleteActivity path. A prominent one-time warning is * logged so this is never silent. */ export declare function runTransactionalStep(args: { connectionString: string; sameDatabase?: boolean; degrade: 'refuse' | 'at-least-once'; handshake: ServerSqlContractHandshake | undefined; identity: TransactionStepIdentity; serializeOutput: (value: T) => Buffer; fn: (tx: PgQueryable) => Promise; }): Promise<{ result: T; checkpointedInTx: boolean; }>; /** Never used by production code — exists so tests can reset the module-level pool cache. */ export declare function __resetPoolForTests(): void;