import { DatabaseSync } from "node:sqlite"; import type { WorkflowRunDatabase, WorkflowRunTransaction } from "../storage/api.js"; import { type DurableEvent, type DurableStream, type JournalProvenance } from "@executablemd/durable-streams"; import type { Operation } from "effection"; import { Database as CloudflareDatabase } from "../../vendor/cloudflare-computer-dofs/generated/storage.js"; import { WorkspaceFilesystem } from "../../vendor/cloudflare-computer-dofs/generated/fs/filesystem.js"; import { type ConnectionLock } from "./lock.js"; import { type SavepointManager, type SavepointObserver, type SavepointTransaction } from "./savepoints.js"; /** * The connections one host owns, for as long as it owns them. * * One authoritative connection per database is a storage invariant rather than a * convenience: the DOFS layer caches against it, and Workspace effect * transactions run serially on it. Storage and lifecycle write to the same * databases, so the host creates this once and hands the same registry to both * rather than letting either open a second writer. * * Passed explicitly. It carries operations, so it is not context data, and * "whichever installs first creates it" would have made one installer's * savepoint observation and hooks depend on installation order. * * It is coordination and nothing more: what may advance a run is the executor * lease, which every mutating transaction validates for itself. */ export declare function useWorkflowRunConnections(observeSavepoint?: SavepointObserver, hooks?: WorkflowRunConnectionHooks): Operation; export declare class ConnectionGeneration { #private; } export declare class TransactionIdentity { #private; } export declare class WorkflowRunTransactionToken { #private; } export interface RunConnectionLease { readonly connection: RunConnection; readonly generation: ConnectionGeneration; readonly path: string; readonly database: WorkflowRunDatabase; journalProvenance: JournalProvenance | undefined; open: boolean; } export interface RunTransaction extends SavepointTransaction { readonly path: string; readonly generation: ConnectionGeneration; readonly identity: TransactionIdentity; readonly lease: RunConnectionLease | undefined; /** * The opaque id of every event appended through this transaction, in order. * * A `DurableStream` carries events and not their identities, so an append * answers with nothing. A caller that has to name the event it just appended * — to retain something against it in this same transaction — reads its id * from here rather than asking the journal what is last, which would be * position standing in for identity. * * Uncommitted, like everything else on a transaction. A rollback takes the * rows and this list with it. */ readonly appended: string[]; handle: WorkflowRunTransaction | undefined; open: boolean; failure: unknown | undefined; } export interface RunConnection { readonly path: string; readonly generation: ConnectionGeneration; readonly database: DatabaseSync; readonly dofs: CloudflareDatabase; readonly filesystem: WorkspaceFilesystem; readonly lock: ConnectionLock; readonly savepoints: SavepointManager; invalidateDofsCaches(): void; beginTransaction(lease?: RunConnectionLease): RunTransaction; bindTransaction(transaction: RunTransaction, handle: WorkflowRunTransaction): void; validateTransaction(transaction: RunTransaction): void; finishTransaction(transaction: RunTransaction): void; currentTransaction(): RunTransaction; setClock(now: () => number): void; close(): void; } export interface WorkflowRunConnections { at(path: string): Operation; registerLease(database: WorkflowRunDatabase, connection: RunConnection): RunConnectionLease; registerJournal(database: WorkflowRunDatabase, journal: DurableStream): void; closeLease(lease: RunConnectionLease): void; validateLease(database: WorkflowRunDatabase): RunConnectionLease; validateJournalProvenance(database: WorkflowRunDatabase, provenance: JournalProvenance | undefined): void; afterRoutedJournalAppend(database: WorkflowRunDatabase, event: DurableEvent): Operation; beforeCommit(database: WorkflowRunDatabase): Operation; authorizeTransaction(database: WorkflowRunDatabase, transaction: WorkflowRunTransaction): RunTransaction; issueToken(database: WorkflowRunDatabase, transaction: WorkflowRunTransaction): WorkflowRunTransactionToken; validateToken(database: WorkflowRunDatabase, token: WorkflowRunTransactionToken): RunTransaction; /** Close and forget one run's connection, so its file can be removed. */ close(path?: string): void; } export declare class WorkflowConnectionStateError extends Error { name: string; } export interface WorkflowRunConnectionHooks { afterRoutedJournalAppend?(database: WorkflowRunDatabase, event: DurableEvent): Operation; beforeCommit?(database: WorkflowRunDatabase): Operation; } export declare function createWorkflowRunConnections(observeSavepoint?: SavepointObserver, hooks?: WorkflowRunConnectionHooks): WorkflowRunConnections;