octaflow 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,10 @@
1
+ //#region src/core/logger.d.ts
2
+ type LogAttributes = Record<string, unknown>;
3
+ interface Logger {
4
+ info(message: string, attributes?: LogAttributes): void;
5
+ warn(message: string, attributes?: LogAttributes): void;
6
+ error(message: string, error?: Error, attributes?: LogAttributes): void;
7
+ }
8
+ declare const noopLogger: Logger;
9
+ //#endregion
10
+ export { Logger as n, noopLogger as r, LogAttributes as t };
@@ -0,0 +1,249 @@
1
+ import { F as StepId, G as WorkflowWithSteps, I as StepRecord, U as WorkflowRecord, V as WorkflowId, W as WorkflowStatus } from "./index-D_fOYfmf.js";
2
+ //#region src/core/store.d.ts
3
+ interface CreateWorkflowStep {
4
+ key: string;
5
+ type: string;
6
+ dependencies: string[];
7
+ input: Record<string, unknown> | null;
8
+ }
9
+ /** A map child step to insert at runtime. */
10
+ interface AddChildStep {
11
+ /** Synthetic key, e.g. `${parentKey}#${index}`. */
12
+ key: string;
13
+ type: string;
14
+ input: Record<string, unknown> | null;
15
+ }
16
+ interface CreateWorkflowParams {
17
+ type: string;
18
+ input: Record<string, unknown>;
19
+ entityRef?: string;
20
+ metadata?: Record<string, unknown>;
21
+ /** Dedup key (per partition); a collision returns the existing workflow. */
22
+ idempotencyKey?: string;
23
+ /** Sub-workflow linkage: the parent workflow + step that started this child. */
24
+ parentWorkflowId?: WorkflowId;
25
+ parentStepId?: StepId;
26
+ startedAt: string;
27
+ steps: CreateWorkflowStep[];
28
+ }
29
+ interface CreatedWorkflow {
30
+ workflowId: WorkflowId;
31
+ /** The step rows (new on insert, existing on an idempotency hit) — used to enqueue roots. */
32
+ steps: StepRecord[];
33
+ /**
34
+ * True when `idempotencyKey` matched an existing workflow and nothing new was created.
35
+ * The engine then returns the existing workflow without re-enqueuing roots.
36
+ */
37
+ alreadyExisted: boolean;
38
+ }
39
+ interface CompleteStepParams {
40
+ workflowId: WorkflowId;
41
+ stepId: StepId;
42
+ output: Record<string, unknown>;
43
+ completedAt: string;
44
+ }
45
+ interface FailStepParams {
46
+ workflowId: WorkflowId;
47
+ stepId: StepId;
48
+ error: string;
49
+ completedAt: string;
50
+ }
51
+ interface FinishWorkflowParams {
52
+ workflowId: WorkflowId;
53
+ status: Extract<WorkflowStatus, 'completed' | 'failed' | 'cancelled'>;
54
+ output?: Record<string, unknown>;
55
+ error?: string;
56
+ completedAt: string;
57
+ }
58
+ interface ListWorkflowsFilters {
59
+ status?: WorkflowStatus;
60
+ type?: string;
61
+ entityRef?: string;
62
+ limit?: number;
63
+ }
64
+ /**
65
+ * Persistence boundary for the engine. Implementations are **partition-scoped at
66
+ * construction** (e.g. bound to one tenant) — exactly like the engine — so methods
67
+ * never take a partition key. The default adapter is Postgres/Drizzle.
68
+ *
69
+ * Counter ownership: `completeStep` MUST atomically increment the workflow's
70
+ * `completedSteps`; `failStep` MUST atomically increment `failedSteps`. The engine
71
+ * relies on these counters only for progress reporting — readiness and termination
72
+ * are computed from `listSteps`.
73
+ */
74
+ interface WorkflowStore {
75
+ /** Create the workflow + all step rows atomically (transactional). */
76
+ createWorkflow(params: CreateWorkflowParams): Promise<CreatedWorkflow>;
77
+ getWorkflow(workflowId: WorkflowId): Promise<WorkflowRecord | null>;
78
+ getStep(stepId: StepId): Promise<StepRecord | null>;
79
+ listSteps(workflowId: WorkflowId): Promise<StepRecord[]>;
80
+ /**
81
+ * **Atomically claim** a step: flip it to `running`, set `startedAt` and increment
82
+ * `attempts` — but **only if it is still `pending`**. Returns `true` if this caller
83
+ * won the claim, `false` if the step had already left `pending` (another worker
84
+ * claimed it, or it was cancelled/skipped meanwhile).
85
+ *
86
+ * Implementations MUST make the status check and the write a single atomic
87
+ * operation (e.g. `UPDATE … WHERE id = $1 AND status = 'pending'` and report
88
+ * whether a row matched). A read-then-write would let two workers handed the
89
+ * same job by an at-least-once dispatcher both run the handler.
90
+ */
91
+ markStepRunning(stepId: StepId, startedAt: string): Promise<boolean>;
92
+ /** Reset a step to `pending` for a scheduled retry (leaves `attempts` as-is). */
93
+ markStepPending(stepId: StepId): Promise<void>;
94
+ /** Flip a ready step to `waiting` — it suspends until `resumeStep` (waitForEvent). */
95
+ markStepWaiting(stepId: StepId): Promise<void>;
96
+ /** Flip a map parent to `mapping` — it suspends until all spawned children finish. */
97
+ markStepMapping(stepId: StepId): Promise<void>;
98
+ /** Flip a completed step to `compensating` while its rollback handler runs. */
99
+ markStepCompensating(stepId: StepId): Promise<void>;
100
+ /** Flip a step to `compensated`; optionally record a compensation error for surfacing. */
101
+ markStepCompensated(stepId: StepId, error?: string): Promise<void>;
102
+ /** Insert map child step rows at runtime and return them with ids. */
103
+ addChildSteps(workflowId: WorkflowId, parentStepId: StepId, children: AddChildStep[]): Promise<StepRecord[]>;
104
+ /** List the child steps of a map parent, ordered by creation (item order). */
105
+ listChildSteps(parentStepId: StepId): Promise<StepRecord[]>;
106
+ /** Flip a step to `completed`, persist output, and increment `completedSteps`. */
107
+ completeStep(params: CompleteStepParams): Promise<void>;
108
+ /** Flip a step to `failed`, persist error, and increment `failedSteps`. */
109
+ failStep(params: FailStepParams): Promise<void>;
110
+ /** Flip a single pending/ready step to `skipped`. */
111
+ skipStep(stepId: StepId, reason: string): Promise<void>;
112
+ /** Flip every still-pending or `waiting` step of a workflow to `skipped` (used on cancel). */
113
+ skipPendingSteps(workflowId: WorkflowId, reason: string): Promise<void>;
114
+ /** Transition the workflow to a terminal state. */
115
+ finishWorkflow(params: FinishWorkflowParams): Promise<void>;
116
+ /** List workflows (with their steps) for status/dashboard reads. */
117
+ listWorkflows(filters: ListWorkflowsFilters): Promise<WorkflowWithSteps[]>;
118
+ /** All workflows currently in `running` state (for the stuck-step sweeper). */
119
+ listRunningWorkflows(): Promise<WorkflowRecord[]>;
120
+ /** Steps stuck in `running` with `startedAt` older than `cutoff` (ISO string). */
121
+ findStuckSteps(workflowId: WorkflowId, cutoff: string): Promise<StepRecord[]>;
122
+ }
123
+ //#endregion
124
+ //#region src/core/gate.d.ts
125
+ interface StepGateRequest {
126
+ partitionKey: string;
127
+ workflowId: WorkflowId;
128
+ stepId: StepId;
129
+ stepKey: string;
130
+ stepType: string;
131
+ }
132
+ type StepGateDecision = {
133
+ admitted: true;
134
+ release(): void | Promise<void>;
135
+ } | {
136
+ admitted: false;
137
+ retryAfterSeconds: number;
138
+ };
139
+ /**
140
+ * Admission control consulted by the engine **before** a step runs. Return
141
+ * `{ admitted: false, retryAfterSeconds }` to defer the step — it is re-enqueued with
142
+ * that delay and **no attempt is consumed** — or `{ admitted: true, release }` with a
143
+ * `release` the engine calls when the step finishes (success, terminal failure, or
144
+ * retry-reschedule).
145
+ *
146
+ * The shipped {@link createInMemoryStepGate} is **per-process** — correct for a single
147
+ * worker and for tests. For a multi-worker concurrency cap, implement this against a
148
+ * shared store (e.g. a leases table); the contract is identical.
149
+ */
150
+ interface StepGate {
151
+ acquire(req: StepGateRequest): Promise<StepGateDecision>;
152
+ }
153
+ /** Max concurrently-running steps of a given type (per process). */
154
+ interface ConcurrencyRule {
155
+ maxConcurrent: number;
156
+ }
157
+ /** Token-bucket throughput limit for a given step type. */
158
+ interface RateRule {
159
+ /** Sustained rate, tokens per second. */
160
+ perSecond: number;
161
+ /** Bucket capacity (max burst). Defaults to `max(1, ceil(perSecond))`. */
162
+ burst?: number;
163
+ }
164
+ interface InMemoryStepGateConfig {
165
+ /** Per-stepType concurrency caps. */
166
+ concurrency?: Record<string, ConcurrencyRule>;
167
+ /** Per-stepType token-bucket rate limits. */
168
+ rateLimit?: Record<string, RateRule>;
169
+ /** Retry delay (seconds) returned when a concurrency cap is hit. Default 1. */
170
+ concurrencyRetrySeconds?: number;
171
+ /** Clock injection for tests (ms epoch). Defaults to `Date.now`. */
172
+ now?: () => number;
173
+ }
174
+ /**
175
+ * A per-process {@link StepGate}: per-stepType concurrency caps (held slots) plus
176
+ * per-stepType token-bucket rate limits (throughput). Both are optional and checked
177
+ * per step type; a step type with no rule is always admitted.
178
+ *
179
+ * Concurrency is reserved first, then the rate token — so a rate denial does not waste
180
+ * a concurrency slot. Good for single-worker deployments; swap in a shared-store gate
181
+ * for multi-worker concurrency control.
182
+ */
183
+ declare function createInMemoryStepGate(config?: InMemoryStepGateConfig): StepGate;
184
+ //#endregion
185
+ //#region src/core/observability.d.ts
186
+ /** Lifecycle event types the engine emits at every workflow/step transition. */
187
+ type FlowEventType = 'workflow.started' | 'workflow.completed' | 'workflow.failed' | 'workflow.cancelled' | 'step.started' | 'step.completed' | 'step.failed' | 'step.retrying' | 'step.skipped' | 'step.waiting' | 'step.resumed' | 'step.mapping' | 'step.compensating' | 'step.compensated';
188
+ /**
189
+ * An append-only run-history record. The engine emits one per transition; an observer can
190
+ * persist it (a timeline), turn it into OpenTelemetry metrics (counters/histograms), or both.
191
+ */
192
+ interface FlowEvent {
193
+ type: FlowEventType;
194
+ /** ISO timestamp of the transition. */
195
+ at: string;
196
+ partitionKey: string;
197
+ workflowId: WorkflowId;
198
+ workflowType?: string;
199
+ stepId?: StepId;
200
+ stepKey?: string;
201
+ stepType?: string;
202
+ /** Execution attempt number (for step events). */
203
+ attempt?: number;
204
+ /** Wall-clock duration of the step run in ms (for step.completed / step.failed). */
205
+ durationMs?: number;
206
+ error?: string;
207
+ }
208
+ /**
209
+ * Sink for run-history / metrics. Implementations **must not throw** and should be cheap
210
+ * (fire-and-forget) — the engine guards calls but never awaits them. Wire a Postgres event
211
+ * sink for history, or an OTel-meter adapter for metrics. Defaults to a no-op.
212
+ */
213
+ interface FlowObserver {
214
+ record(event: FlowEvent): void;
215
+ }
216
+ declare const noopObserver: FlowObserver;
217
+ /** In-memory observer that accumulates events — for tests and introspection. */
218
+ interface RecordingObserver extends FlowObserver {
219
+ readonly events: FlowEvent[];
220
+ clear(): void;
221
+ }
222
+ declare function createRecordingObserver(): RecordingObserver;
223
+ /** A minimal span handle. Maps 1:1 onto an OpenTelemetry span in an adapter. */
224
+ interface FlowSpan {
225
+ setAttribute(key: string, value: string | number | boolean): void;
226
+ recordError(error: Error): void;
227
+ end(): void;
228
+ }
229
+ /**
230
+ * A minimal tracer. The engine wraps each `executeStep` in a span. Provide an OTel-backed
231
+ * adapter (`startSpan` → `tracer.startSpan`) to get distributed traces; defaults to a no-op.
232
+ */
233
+ interface FlowTracer {
234
+ startSpan(name: string, attributes?: Record<string, string | number | boolean>): FlowSpan;
235
+ }
236
+ declare const noopTracer: FlowTracer;
237
+ /** A span captured in memory — for tests. */
238
+ interface RecordedSpan {
239
+ name: string;
240
+ attributes: Record<string, string | number | boolean>;
241
+ error?: string;
242
+ ended: boolean;
243
+ }
244
+ interface RecordingTracer extends FlowTracer {
245
+ readonly spans: RecordedSpan[];
246
+ }
247
+ declare function createRecordingTracer(): RecordingTracer;
248
+ //#endregion
249
+ export { CreateWorkflowStep as C, ListWorkflowsFilters as D, FinishWorkflowParams as E, WorkflowStore as O, CreateWorkflowParams as S, FailStepParams as T, StepGateDecision as _, FlowTracer as a, AddChildStep as b, RecordingTracer as c, noopObserver as d, noopTracer as f, StepGate as g, RateRule as h, FlowSpan as i, createRecordingObserver as l, InMemoryStepGateConfig as m, FlowEventType as n, RecordedSpan as o, ConcurrencyRule as p, FlowObserver as r, RecordingObserver as s, FlowEvent as t, createRecordingTracer as u, StepGateRequest as v, CreatedWorkflow as w, CompleteStepParams as x, createInMemoryStepGate as y };
@@ -0,0 +1,195 @@
1
+ import { V as WorkflowId } from "../index-D_fOYfmf.js";
2
+ import { O as WorkflowStore, g as StepGate, h as RateRule, p as ConcurrencyRule, r as FlowObserver, t as FlowEvent } from "../observability-BsrvbhDr.js";
3
+ import { Pool } from "pg";
4
+ //#region src/store-pg/ddl.d.ts
5
+ /**
6
+ * Schema for the Postgres WorkflowStore adapter. Two tables mirror flow-core's
7
+ * record shapes. Apply once at deploy time (or call `applySchema`).
8
+ *
9
+ * `partition_key` is the generic multi-tenancy column (the engine/store are bound
10
+ * to one partition). Add Row Level Security on top if you need hard isolation.
11
+ */
12
+ declare function flowStoreDdl(schema?: string): string;
13
+ /** Default-schema DDL string. */
14
+ declare const FLOW_STORE_DDL: string;
15
+ /** `CREATE SCHEMA IF NOT EXISTS` line for non-default schemas; empty for 'public'. */
16
+ declare function createSchemaDdl(schema: string): string;
17
+ //#endregion
18
+ //#region src/store-pg/executor.d.ts
19
+ /** Minimal query result shape the adapters consume (a structural subset of `pg`'s `QueryResult`). */
20
+ interface SqlResult<R> {
21
+ rows: R[];
22
+ rowCount: number | null;
23
+ }
24
+ /**
25
+ * A Postgres adapter's only contact with the database. Adapters issue raw
26
+ * parameterized SQL through this seam and never open their own connections, so
27
+ * the *host* decides how queries run: a plain pool ({@link poolExecutor}), or a
28
+ * connection that first sets transaction-local GUCs for Row Level Security.
29
+ *
30
+ * `transaction(fn)` MUST run every `fn` query on a single connection inside one
31
+ * DB transaction; the passed executor is that same-connection handle. Adapters
32
+ * never nest transactions.
33
+ */
34
+ interface SqlExecutor {
35
+ query<R = Record<string, unknown>>(sql: string, params?: unknown[]): Promise<SqlResult<R>>;
36
+ transaction<T>(fn: (tx: SqlExecutor) => Promise<T>): Promise<T>;
37
+ }
38
+ /**
39
+ * Build a {@link SqlExecutor} over a `pg` {@link Pool}: top-level queries run on
40
+ * the pool (autocommit); `transaction` checks out a client and wraps `fn` in
41
+ * `BEGIN`/`COMMIT` (rolling back and always releasing on error). This is the
42
+ * batteries-included executor used by the `createPg*` adapters.
43
+ */
44
+ declare function poolExecutor(pool: Pool): SqlExecutor;
45
+ /**
46
+ * Normalize a `Pool | SqlExecutor` argument to a {@link SqlExecutor}. Lets the
47
+ * read helpers accept either the batteries-included pool or a host's RLS-scoped
48
+ * executor without a breaking signature change. `SqlExecutor` is discriminated by
49
+ * its `transaction` method (a `pg` `Pool` has none).
50
+ */
51
+ declare function toExecutor(db: Pool | SqlExecutor): SqlExecutor;
52
+ //#endregion
53
+ //#region src/store-pg/store.d.ts
54
+ interface PgWorkflowStoreDeps {
55
+ pool: Pool;
56
+ /** Partition this store instance is bound to (e.g. a tenant id). */
57
+ partitionKey: string;
58
+ /** Schema the flow tables live in. Default 'public'. */
59
+ schema?: string;
60
+ }
61
+ interface WorkflowStoreDeps {
62
+ /** How the store talks to Postgres (pool-backed, RLS-scoped, …). */
63
+ exec: SqlExecutor;
64
+ /** Partition this store instance is bound to (e.g. a tenant id). */
65
+ partitionKey: string;
66
+ /** Schema the flow tables live in. Default 'public'. */
67
+ schema?: string;
68
+ }
69
+ /**
70
+ * A `WorkflowStore` over Postgres, addressing raw parameterized SQL through an
71
+ * injected {@link SqlExecutor}. Partition-scoped at construction; every query is
72
+ * additionally filtered by `partition_key` as defense-in-depth. Requires the two
73
+ * tables from `flowStoreDdl()`.
74
+ *
75
+ * The executor decides *how* queries run: {@link createPgWorkflowStore} wires a
76
+ * plain pool; a host that wants Row Level Security injects an executor whose
77
+ * `transaction` sets the tenant GUC, so the store's own transactions run scoped.
78
+ */
79
+ declare function createWorkflowStore(deps: WorkflowStoreDeps): WorkflowStore;
80
+ /**
81
+ * A `WorkflowStore` backed by a `pg` {@link Pool} — the batteries-included
82
+ * adapter that owns its own connections/transactions (via {@link poolExecutor})
83
+ * and requires the tables from `flowStoreDdl()`. Unchanged public surface: hosts
84
+ * that need Row Level Security or their own migrations should instead build an
85
+ * executor and call {@link createWorkflowStore}.
86
+ */
87
+ declare function createPgWorkflowStore(deps: PgWorkflowStoreDeps): WorkflowStore;
88
+ /** Convenience: apply the flow-store schema to a database. */
89
+ declare function applySchema(pool: Pool, ddl: string): Promise<void>;
90
+ //#endregion
91
+ //#region src/store-pg/gate.d.ts
92
+ /** DDL for the gate's two tables. Apply once at deploy time (or via `applySchema`). */
93
+ declare function flowGateDdl(opts?: {
94
+ schema?: string;
95
+ rateBucketTable?: string;
96
+ leaseTable?: string;
97
+ }): string;
98
+ /** Default-schema gate DDL string. */
99
+ declare const FLOW_GATE_DDL: string;
100
+ interface PgStepGateConfig {
101
+ pool: Pool;
102
+ /** Partition this gate is bound to (matches the engine/store partition). */
103
+ partitionKey: string;
104
+ /** Schema the gate tables live in. Default 'public'. */
105
+ schema?: string;
106
+ /** Per-stepType concurrency caps (held leases). */
107
+ concurrency?: Record<string, ConcurrencyRule>;
108
+ /** Per-stepType token-bucket rate limits. */
109
+ rateLimit?: Record<string, RateRule>;
110
+ /** Lease TTL in seconds — crash-safety for held concurrency slots. Default 600. */
111
+ leaseTtlSeconds?: number;
112
+ /** Retry delay (seconds) returned when a concurrency cap is hit. Default 1. */
113
+ concurrencyRetrySeconds?: number;
114
+ /** Table name overrides. */
115
+ tables?: {
116
+ rateBucket?: string;
117
+ lease?: string;
118
+ };
119
+ }
120
+ interface StepGateConfig extends Omit<PgStepGateConfig, 'pool'> {
121
+ /** How the gate talks to Postgres (pool-backed, RLS-scoped, …). */
122
+ exec: SqlExecutor;
123
+ }
124
+ /**
125
+ * A Postgres-backed {@link StepGate} addressing all SQL through an injected
126
+ * {@link SqlExecutor}, so a host can run the concurrency/rate SQL under Row Level
127
+ * Security (inject an executor that sets the tenant GUC) instead of a plain pool.
128
+ * Global concurrency caps + rate limits shared across all workers; drop-in for
129
+ * the in-memory gate via `WorkflowEngineDeps.gate`.
130
+ */
131
+ declare function createStepGate(config: StepGateConfig): StepGate;
132
+ /**
133
+ * A Postgres-backed {@link StepGate} over a `pg` {@link Pool} — the
134
+ * batteries-included adapter (via {@link poolExecutor}). Hosts that need Row
135
+ * Level Security should build an executor and call {@link createStepGate}.
136
+ */
137
+ declare function createPgStepGate(config: PgStepGateConfig): StepGate;
138
+ //#endregion
139
+ //#region src/store-pg/event-sink.d.ts
140
+ /**
141
+ * DDL for the append-only run-history table. Apply once at deploy time (alongside
142
+ * `flowStoreDdl`), or call `applySchema(pool, flowEventDdl())`.
143
+ */
144
+ declare function flowEventDdl(schema?: string): string;
145
+ /** Default-schema event-table DDL string. */
146
+ declare const FLOW_EVENT_DDL: string;
147
+ interface PgEventSinkDeps {
148
+ pool: Pool;
149
+ /** Partition this sink is bound to (e.g. a tenant id). */
150
+ partitionKey: string;
151
+ /** Schema the flow tables live in. Default 'public'. */
152
+ schema?: string;
153
+ }
154
+ interface EventSinkDeps {
155
+ /** How the sink talks to Postgres (pool-backed, RLS-scoped, …). */
156
+ exec: SqlExecutor;
157
+ /** Partition this sink is bound to (e.g. a tenant id). */
158
+ partitionKey: string;
159
+ /** Schema the flow tables live in. Default 'public'. */
160
+ schema?: string;
161
+ }
162
+ /**
163
+ * A `FlowObserver` that appends every engine event to `flow_step_event`. `record` is
164
+ * fire-and-forget (it never throws and never blocks the engine); call `flush()` to await the
165
+ * in-flight inserts — useful in tests and before shutdown.
166
+ */
167
+ interface PgEventSink extends FlowObserver {
168
+ flush(): Promise<void>;
169
+ }
170
+ /**
171
+ * A `FlowObserver` that appends engine events to `flow_step_event` through an
172
+ * injected {@link SqlExecutor}, so a host can run the write under Row Level
173
+ * Security (inject an executor that sets the tenant GUC) instead of a plain pool.
174
+ * `record` is fire-and-forget (never throws, never blocks the engine); `flush()`
175
+ * awaits the in-flight inserts.
176
+ */
177
+ declare function createEventSink(deps: EventSinkDeps): PgEventSink;
178
+ /**
179
+ * A `FlowObserver` backed by a `pg` {@link Pool} — the batteries-included sink
180
+ * (via {@link poolExecutor}). Hosts that need Row Level Security should build an
181
+ * executor and call {@link createEventSink} instead.
182
+ */
183
+ declare function createPgEventSink(deps: PgEventSinkDeps): PgEventSink;
184
+ /**
185
+ * Read a workflow's run history, ordered oldest-first. Accepts either a
186
+ * `pg` {@link Pool} (batteries-included) or a host's {@link SqlExecutor} (e.g.
187
+ * RLS-scoped) — both route through the same seam.
188
+ */
189
+ declare function readFlowEvents(db: Pool | SqlExecutor, params: {
190
+ workflowId: WorkflowId;
191
+ partitionKey: string;
192
+ schema?: string;
193
+ }): Promise<FlowEvent[]>;
194
+ //#endregion
195
+ export { EventSinkDeps, FLOW_EVENT_DDL, FLOW_GATE_DDL, FLOW_STORE_DDL, PgEventSink, PgEventSinkDeps, PgStepGateConfig, PgWorkflowStoreDeps, SqlExecutor, SqlResult, StepGateConfig, WorkflowStoreDeps, applySchema, createEventSink, createPgEventSink, createPgStepGate, createPgWorkflowStore, createSchemaDdl, createStepGate, createWorkflowStore, flowEventDdl, flowGateDdl, flowStoreDdl, poolExecutor, readFlowEvents, toExecutor };