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.
- package/LICENSE +21 -0
- package/README.md +288 -0
- package/dist/ai/index.d.ts +397 -0
- package/dist/ai/index.js +466 -0
- package/dist/core-ERYGlYsS.js +574 -0
- package/dist/dispatcher-BydjyrgU.d.ts +26 -0
- package/dist/dispatcher-pgboss/index.d.ts +170 -0
- package/dist/dispatcher-pgboss/index.js +301 -0
- package/dist/hooks-CDRFQZbT.d.ts +56 -0
- package/dist/index-D_fOYfmf.d.ts +580 -0
- package/dist/index.d.ts +137 -0
- package/dist/index.js +1426 -0
- package/dist/logger-BCus3AOa.d.ts +10 -0
- package/dist/observability-BsrvbhDr.d.ts +249 -0
- package/dist/store-pg/index.d.ts +195 -0
- package/dist/store-pg/index.js +671 -0
- package/package.json +116 -0
|
@@ -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 };
|