@multiplier-labs/stepflow 0.3.3 → 0.3.6
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/README.md +9 -0
- package/dist/{chunk-GYPNJBDP.js → chunk-D5HW7VEG.js} +269 -48
- package/dist/chunk-D5HW7VEG.js.map +1 -0
- package/dist/{chunk-KHTUWLVZ.js → chunk-FMPJBK2N.js} +55 -10
- package/dist/chunk-FMPJBK2N.js.map +1 -0
- package/dist/{chunk-ML35PIHX.js → chunk-JPXPB7U5.js} +52 -2
- package/dist/chunk-JPXPB7U5.js.map +1 -0
- package/dist/{chunk-4VOKMGP6.js → chunk-JUPZEBR3.js} +519 -522
- package/dist/chunk-JUPZEBR3.js.map +1 -0
- package/dist/events/index.d.ts +58 -3
- package/dist/events/index.js +1 -1
- package/dist/{index-Dzr437iW.d.ts → index-Cd0IZ40L.d.ts} +50 -11
- package/dist/index.d.ts +2 -12
- package/dist/index.js +764 -485
- package/dist/index.js.map +1 -1
- package/dist/scheduler/index.d.ts +1 -1
- package/dist/scheduler/index.js +2 -2
- package/dist/storage/index.d.ts +313 -47
- package/dist/storage/index.js +4 -2
- package/package.json +27 -13
- package/.codekin/reports/comments/2026-04-04_comment-assessment.md +0 -179
- package/.codekin/reports/complexity/2026-04-03_complexity-report.md +0 -152
- package/.codekin/reports/dependencies/2026-04-04_dependency-health.md +0 -94
- package/.codekin/reports/docs-audit/2026-04-04_docs-audit.md +0 -10
- package/.codekin/reports/security/2026-04-03_security-audit.md +0 -208
- package/.github/CODEOWNERS +0 -15
- package/.github/dependabot.yml +0 -23
- package/.github/workflows/ci.yml +0 -38
- package/.github/workflows/publish.yml +0 -36
- package/.github/workflows/security.yml +0 -29
- package/CHANGELOG.md +0 -34
- package/SECURITY.md +0 -40
- package/dist/chunk-4VOKMGP6.js.map +0 -1
- package/dist/chunk-GYPNJBDP.js.map +0 -1
- package/dist/chunk-KHTUWLVZ.js.map +0 -1
- package/dist/chunk-ML35PIHX.js.map +0 -1
- package/docs/github-packages-setup.md +0 -97
- package/docs/stepflow-api-reference.md +0 -1661
- package/src/core/engine.test.ts +0 -1365
- package/src/core/engine.ts +0 -692
- package/src/core/index.ts +0 -7
- package/src/core/orchestrator.ts +0 -571
- package/src/core/types.ts +0 -220
- package/src/events/index.ts +0 -8
- package/src/events/memory.test.ts +0 -107
- package/src/events/memory.ts +0 -92
- package/src/events/socketio.test.ts +0 -378
- package/src/events/socketio.ts +0 -262
- package/src/events/types.ts +0 -118
- package/src/events/webhook.test.ts +0 -657
- package/src/events/webhook.ts +0 -564
- package/src/index.ts +0 -270
- package/src/planning/index.ts +0 -55
- package/src/planning/planner.ts +0 -576
- package/src/planning/planning.test.ts +0 -727
- package/src/planning/registry.test.ts +0 -398
- package/src/planning/registry.ts +0 -365
- package/src/planning/types.ts +0 -566
- package/src/scheduler/cron.test.ts +0 -471
- package/src/scheduler/cron.ts +0 -414
- package/src/scheduler/index.ts +0 -8
- package/src/scheduler/postgres-persistence.ts +0 -518
- package/src/scheduler/sqlite-persistence.test.ts +0 -235
- package/src/scheduler/sqlite-persistence.ts +0 -261
- package/src/scheduler/types.ts +0 -73
- package/src/storage/index.ts +0 -27
- package/src/storage/memory.test.ts +0 -349
- package/src/storage/memory.ts +0 -227
- package/src/storage/postgres.ts +0 -1354
- package/src/storage/sqlite.test.ts +0 -466
- package/src/storage/sqlite.ts +0 -627
- package/src/storage/types.ts +0 -343
- package/src/utils/errors.test.ts +0 -150
- package/src/utils/errors.ts +0 -161
- package/src/utils/id.ts +0 -21
- package/src/utils/index.ts +0 -8
- package/src/utils/logger.test.ts +0 -121
- package/src/utils/logger.ts +0 -96
- package/src/utils/postgres-deps.ts +0 -63
- package/src/utils/retry.test.ts +0 -177
- package/src/utils/retry.ts +0 -121
- package/tsconfig.json +0 -21
- package/tsup.config.ts +0 -14
- package/vitest.config.ts +0 -9
package/dist/scheduler/index.js
CHANGED
|
@@ -2,8 +2,8 @@ import {
|
|
|
2
2
|
CronScheduler,
|
|
3
3
|
PostgresSchedulePersistence,
|
|
4
4
|
SQLiteSchedulePersistence
|
|
5
|
-
} from "../chunk-
|
|
6
|
-
import "../chunk-
|
|
5
|
+
} from "../chunk-FMPJBK2N.js";
|
|
6
|
+
import "../chunk-JPXPB7U5.js";
|
|
7
7
|
export {
|
|
8
8
|
CronScheduler,
|
|
9
9
|
PostgresSchedulePersistence,
|
package/dist/storage/index.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { i as StorageAdapter, j as WorkflowRunRecord, d as ListRunsOptions, P as PaginatedResult, k as WorkflowRunStepRecord, W as WorkflowEventRecord, L as ListEventsOptions, C as CreateRunInput, U as UpdateRunInput, e as StepResult } from '../types-DSEjiLMj.js';
|
|
2
2
|
export { E as ExtendedListRunsOptions, a as ExtendedRunStatus, b as ExtendedStepStatus, c as ExtendedWorkflowRunRecord, S as StepRecord, f as StepflowDatabase, g as StepflowRunsTable, h as StepflowStepResultsTable, l as WorkflowStorage } from '../types-DSEjiLMj.js';
|
|
3
3
|
import Database from 'better-sqlite3';
|
|
4
|
+
import { L as Logger } from '../types-K5Gjk3H_.js';
|
|
5
|
+
import { Kysely } from 'kysely';
|
|
4
6
|
import { Pool, PoolConfig } from 'pg';
|
|
5
|
-
import '../types-K5Gjk3H_.js';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* In-memory storage adapter for development and testing.
|
|
@@ -69,6 +70,21 @@ declare class MemoryStorageAdapter implements StorageAdapter {
|
|
|
69
70
|
* SQLite storage adapter using better-sqlite3.
|
|
70
71
|
*
|
|
71
72
|
* Provides durable persistence for workflow runs, steps, and events.
|
|
73
|
+
*
|
|
74
|
+
* ## Module layout
|
|
75
|
+
*
|
|
76
|
+
* - `SQLiteStorageAdapter` (this file) owns the better-sqlite3 connection,
|
|
77
|
+
* the prepared-statement cache, and every method on `StorageAdapter`. It
|
|
78
|
+
* is the only adapter class — unlike the Postgres adapter there is no
|
|
79
|
+
* transaction-scoped twin, so no abstract CRUD base class is required.
|
|
80
|
+
*
|
|
81
|
+
* - `sqlite-core.ts` holds the pure row-type interfaces and row mappers
|
|
82
|
+
* (`mapRunRow`, `mapStepRow`, `mapEventRow`). The mappers route every
|
|
83
|
+
* JSON-column parse through `safeParseField` / `safeParseOptionalField`
|
|
84
|
+
* in `src/utils/safe-json.ts`, sharing the corruption-counter +
|
|
85
|
+
* structured-warn behavior with the Postgres core (audit M2 / L3,
|
|
86
|
+
* PR #52). The split mirrors `postgres-core.ts` so both adapters
|
|
87
|
+
* expose mappers in the same shape.
|
|
72
88
|
*/
|
|
73
89
|
|
|
74
90
|
/**
|
|
@@ -90,6 +106,12 @@ interface SQLiteStorageConfig {
|
|
|
90
106
|
* Table names are always prefixed with 'workflow_'.
|
|
91
107
|
*/
|
|
92
108
|
tablePrefix?: string;
|
|
109
|
+
/**
|
|
110
|
+
* Optional structured logger used to surface JSON corruption events.
|
|
111
|
+
* Without one, parse failures still increment the corruption counter
|
|
112
|
+
* exposed via `getJsonParseCorruptionCount()` but produce no log output.
|
|
113
|
+
*/
|
|
114
|
+
logger?: Logger;
|
|
93
115
|
}
|
|
94
116
|
/**
|
|
95
117
|
* SQLite implementation of StorageAdapter using better-sqlite3.
|
|
@@ -114,12 +136,31 @@ interface SQLiteStorageConfig {
|
|
|
114
136
|
declare class SQLiteStorageAdapter implements StorageAdapter {
|
|
115
137
|
private db;
|
|
116
138
|
private prefix;
|
|
139
|
+
private logger;
|
|
117
140
|
private stmts;
|
|
118
141
|
constructor(config: SQLiteStorageConfig);
|
|
119
142
|
/**
|
|
120
143
|
* Create the workflow tables if they don't exist.
|
|
121
144
|
*/
|
|
122
145
|
private createTables;
|
|
146
|
+
/**
|
|
147
|
+
* Apply additive schema migrations to existing tables.
|
|
148
|
+
*
|
|
149
|
+
* `CREATE TABLE IF NOT EXISTS` is a no-op when the table already exists, so
|
|
150
|
+
* any column added to {@link CREATE_TABLES_SQL} after the initial schema is
|
|
151
|
+
* silently absent on databases created by older versions of this adapter.
|
|
152
|
+
* Without this step, the first INSERT/SELECT crashes with
|
|
153
|
+
* `SqliteError: table X has no column named Y`. This mirrors the
|
|
154
|
+
* `ALTER TABLE ADD COLUMN IF NOT EXISTS` block in `postgres.ts`'s
|
|
155
|
+
* `createTables()`.
|
|
156
|
+
*
|
|
157
|
+
* For each entry in {@link SCHEMA_MIGRATIONS}: if the table exists and the
|
|
158
|
+
* column does not, run `ALTER TABLE ADD COLUMN`. The ALTER is wrapped in a
|
|
159
|
+
* try/catch that tolerates `duplicate column` errors so concurrent startups
|
|
160
|
+
* (or any race between the existence check and the ALTER) do not crash.
|
|
161
|
+
* Other SQLite errors propagate.
|
|
162
|
+
*/
|
|
163
|
+
private runMigrations;
|
|
123
164
|
/**
|
|
124
165
|
* Prepare all SQL statements for better performance.
|
|
125
166
|
*/
|
|
@@ -137,10 +178,17 @@ declare class SQLiteStorageAdapter implements StorageAdapter {
|
|
|
137
178
|
/**
|
|
138
179
|
* Execute a function within a database transaction (async interface).
|
|
139
180
|
*
|
|
140
|
-
* @deprecated Use
|
|
141
|
-
*
|
|
142
|
-
* If the callback awaits real async I/O (network,
|
|
143
|
-
*
|
|
181
|
+
* @deprecated Use {@link transactionSync} instead. better-sqlite3 transactions
|
|
182
|
+
* are synchronous: COMMIT happens the moment the callback returns control to
|
|
183
|
+
* `db.transaction(fn)()`. If the callback awaits real async I/O (network,
|
|
184
|
+
* timers, etc.), the COMMIT has already happened by the time the awaited work
|
|
185
|
+
* runs, so its operations are **not** transactional.
|
|
186
|
+
*
|
|
187
|
+
* To make the footgun visible the adapter installs a runtime guard: when the
|
|
188
|
+
* callback's promise has not settled by the time the COMMIT returns, the
|
|
189
|
+
* deprecated method emits a `console.warn` so that the misuse surfaces in
|
|
190
|
+
* production logs. The promise is still returned so existing callers keep
|
|
191
|
+
* working — switch to `transactionSync` to silence the warning.
|
|
144
192
|
*/
|
|
145
193
|
transaction<T>(fn: (tx: StorageAdapter) => Promise<T>): Promise<T>;
|
|
146
194
|
/**
|
|
@@ -172,9 +220,8 @@ declare class SQLiteStorageAdapter implements StorageAdapter {
|
|
|
172
220
|
* Useful for resuming from a checkpoint.
|
|
173
221
|
*/
|
|
174
222
|
getLastCompletedStep(runId: string): Promise<WorkflowRunStepRecord | null>;
|
|
175
|
-
|
|
176
|
-
private
|
|
177
|
-
private mapEventRow;
|
|
223
|
+
/** Mapper context paired with the adapter's component label + optional logger. */
|
|
224
|
+
private get mapperCtx();
|
|
178
225
|
/**
|
|
179
226
|
* Close the database connection.
|
|
180
227
|
*/
|
|
@@ -189,13 +236,215 @@ declare class SQLiteStorageAdapter implements StorageAdapter {
|
|
|
189
236
|
};
|
|
190
237
|
}
|
|
191
238
|
|
|
239
|
+
/**
|
|
240
|
+
* Safe JSON-parse helpers shared by storage and scheduler adapters.
|
|
241
|
+
*
|
|
242
|
+
* When a stored JSON column is corrupted, we want to surface the problem
|
|
243
|
+
* operationally — structured log + counter — instead of silently degrading.
|
|
244
|
+
* The logger payload is restricted to safe metadata (component, row id,
|
|
245
|
+
* column, payload length, payload type, parser error message). The raw
|
|
246
|
+
* value is intentionally never logged because it may contain user-provided
|
|
247
|
+
* run / step input.
|
|
248
|
+
*
|
|
249
|
+
* Audit: 2026-04-27 findings L3 (corruption visibility) and M2 (do not
|
|
250
|
+
* bypass the configured `Logger` or leak the raw value via `console`).
|
|
251
|
+
*/
|
|
252
|
+
|
|
253
|
+
interface SafeJsonParseContext {
|
|
254
|
+
/** Component label, e.g. `SQLiteStorageAdapter`. */
|
|
255
|
+
component: string;
|
|
256
|
+
/** Optional database row id, surfaced in the warning so operators can locate the bad row. */
|
|
257
|
+
rowId?: string;
|
|
258
|
+
/** Optional column name for additional context. */
|
|
259
|
+
column?: string;
|
|
260
|
+
/** Optional structured logger; without one, only the counter is bumped. */
|
|
261
|
+
logger?: Logger;
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Storage-adapter-level slice of `SafeJsonParseContext` — the part each
|
|
265
|
+
* adapter binds once (its component label + optional logger). Row mappers
|
|
266
|
+
* extend this with `rowId` and `column` per field, so corruption logs always
|
|
267
|
+
* identify the bad row.
|
|
268
|
+
*
|
|
269
|
+
* Shared between `src/storage/postgres-core.ts` and
|
|
270
|
+
* `src/storage/sqlite-core.ts` so all storage adapters use one mapper-context
|
|
271
|
+
* shape regardless of backend.
|
|
272
|
+
*/
|
|
273
|
+
type MapperContext = Pick<SafeJsonParseContext, 'component' | 'logger'>;
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Shared core for the PostgreSQL storage adapters.
|
|
277
|
+
*
|
|
278
|
+
* `PostgresStorageAdapter` (the public, pool-owning adapter) and
|
|
279
|
+
* `PostgresTransactionAdapter` (the in-transaction wrapper used by
|
|
280
|
+
* `PostgresStorageAdapter.transaction()`) both implement the same CRUD subset
|
|
281
|
+
* of `StorageAdapter`. Before this refactor they each carried their own copy
|
|
282
|
+
* of every CRUD method, every row mapper, and every JSON-parse helper. The
|
|
283
|
+
* only meaningful difference between them is which Kysely query builder they
|
|
284
|
+
* target — an instance-bound one (`db.withSchema(schema)`) versus a
|
|
285
|
+
* transaction-bound one (`trx.withSchema(schema)`).
|
|
286
|
+
*
|
|
287
|
+
* This module collapses that duplication:
|
|
288
|
+
*
|
|
289
|
+
* - Pure helpers (`safeJsonParse`, `safeParseField`, `safeParseOptionalField`,
|
|
290
|
+
* row mappers, `applyRunsFilters`) live as standalone functions so callers
|
|
291
|
+
* can use them directly without inheritance.
|
|
292
|
+
*
|
|
293
|
+
* - `PostgresStorageCore` is an abstract base class that implements the
|
|
294
|
+
* CRUD subset of `StorageAdapter` against an abstract `qb` accessor and
|
|
295
|
+
* an `ensureReady()` hook. Subclasses supply the schema-scoped query
|
|
296
|
+
* builder (and an optional pre-call guard, e.g.
|
|
297
|
+
* `PostgresStorageAdapter.ensureInitialized()`).
|
|
298
|
+
*
|
|
299
|
+
* No behavior change: every query and every JSON-parse path matches the
|
|
300
|
+
* previous in-line implementations. The C2 transaction-pagination fix
|
|
301
|
+
* (same-connection COUNT(*)) is preserved by the shared `listRuns`
|
|
302
|
+
* implementation. The C1 migration error-propagation fix lives on
|
|
303
|
+
* `PostgresStorageAdapter` and is unaffected by this module.
|
|
304
|
+
*/
|
|
305
|
+
|
|
306
|
+
/** Kysely row type for the workflow_runs table. */
|
|
307
|
+
interface WorkflowRunsTable {
|
|
308
|
+
id: string;
|
|
309
|
+
kind: string;
|
|
310
|
+
status: string;
|
|
311
|
+
parent_run_id: string | null;
|
|
312
|
+
input_json: string;
|
|
313
|
+
metadata_json: string;
|
|
314
|
+
context_json: string;
|
|
315
|
+
output_json: string | null;
|
|
316
|
+
error_json: string | null;
|
|
317
|
+
priority: number;
|
|
318
|
+
timeout_ms: number | null;
|
|
319
|
+
created_at: Date;
|
|
320
|
+
started_at: Date | null;
|
|
321
|
+
finished_at: Date | null;
|
|
322
|
+
}
|
|
323
|
+
/** Kysely row type for the workflow_run_steps table. */
|
|
324
|
+
interface WorkflowRunStepsTable {
|
|
325
|
+
id: string;
|
|
326
|
+
run_id: string;
|
|
327
|
+
step_key: string;
|
|
328
|
+
step_name: string;
|
|
329
|
+
status: string;
|
|
330
|
+
attempt: number;
|
|
331
|
+
result_json: string | null;
|
|
332
|
+
error_json: string | null;
|
|
333
|
+
started_at: Date | null;
|
|
334
|
+
finished_at: Date | null;
|
|
335
|
+
}
|
|
336
|
+
/** Kysely row type for the workflow_events table. */
|
|
337
|
+
interface WorkflowEventsTable {
|
|
338
|
+
id: string;
|
|
339
|
+
run_id: string;
|
|
340
|
+
step_key: string | null;
|
|
341
|
+
event_type: string;
|
|
342
|
+
level: string;
|
|
343
|
+
payload_json: string | null;
|
|
344
|
+
timestamp: Date;
|
|
345
|
+
}
|
|
346
|
+
/** Combined Kysely schema covering the tables touched by the shared core. */
|
|
347
|
+
interface PostgresCoreDatabase {
|
|
348
|
+
runs: WorkflowRunsTable;
|
|
349
|
+
workflow_run_steps: WorkflowRunStepsTable;
|
|
350
|
+
workflow_events: WorkflowEventsTable;
|
|
351
|
+
}
|
|
352
|
+
/** Schema-scoped query builder produced by `db.withSchema(schemaName)`. */
|
|
353
|
+
type SchemaQueryBuilder<DB extends PostgresCoreDatabase = PostgresCoreDatabase> = ReturnType<Kysely<DB>['withSchema']>;
|
|
354
|
+
/** Concrete core-only schema query builder used inside the shared base class. */
|
|
355
|
+
type CoreSchemaQueryBuilder = SchemaQueryBuilder<PostgresCoreDatabase>;
|
|
356
|
+
/**
|
|
357
|
+
* Abstract base implementing the CRUD subset of `StorageAdapter` against a
|
|
358
|
+
* schema-scoped Kysely query builder. Subclasses must provide the query
|
|
359
|
+
* builder via `qb` and may override `ensureReady()` to gate calls (the
|
|
360
|
+
* pool-owning adapter uses this to enforce `initialize()` having run).
|
|
361
|
+
*
|
|
362
|
+
* The base class deliberately does **not** own the connection pool, schema
|
|
363
|
+
* migrations, or transaction control — those stay with `PostgresStorageAdapter`.
|
|
364
|
+
*
|
|
365
|
+
* The base class targets `PostgresCoreDatabase` (the three core tables) so
|
|
366
|
+
* Kysely's row-type machinery can fully resolve column types on every query.
|
|
367
|
+
* Subclasses with a wider schema (e.g. `PostgresStorageAdapter` with
|
|
368
|
+
* `stepflow_step_results`) keep their own typed handle for the extra tables
|
|
369
|
+
* and return a core-typed view here.
|
|
370
|
+
*/
|
|
371
|
+
declare abstract class PostgresStorageCore implements StorageAdapter {
|
|
372
|
+
protected readonly schema: string;
|
|
373
|
+
protected readonly logger?: Logger | undefined;
|
|
374
|
+
protected constructor(schema: string, logger?: Logger | undefined);
|
|
375
|
+
/** Schema-scoped query builder. Subclasses return the bound builder. */
|
|
376
|
+
protected abstract get qb(): CoreSchemaQueryBuilder;
|
|
377
|
+
/** Component label used in corruption warnings; defines the JSON-parse `MapperContext`. */
|
|
378
|
+
protected abstract get warnLabel(): string;
|
|
379
|
+
/** Mapper context handed to row mappers — pairs the component label with the optional logger. */
|
|
380
|
+
protected get mapperCtx(): MapperContext;
|
|
381
|
+
/**
|
|
382
|
+
* Hook called at the start of every CRUD method. The pool-owning adapter
|
|
383
|
+
* overrides this to throw before `initialize()` has run; the transaction
|
|
384
|
+
* wrapper leaves it as a no-op.
|
|
385
|
+
*/
|
|
386
|
+
protected ensureReady(): void;
|
|
387
|
+
createRun(run: CreateRunInput | Omit<WorkflowRunRecord, 'id' | 'createdAt'>): Promise<WorkflowRunRecord>;
|
|
388
|
+
getRun(runId: string): Promise<WorkflowRunRecord | null>;
|
|
389
|
+
updateRun(runId: string, updates: UpdateRunInput | Partial<WorkflowRunRecord>): Promise<void>;
|
|
390
|
+
listRuns(options?: ListRunsOptions): Promise<PaginatedResult<WorkflowRunRecord>>;
|
|
391
|
+
createStep(step: Omit<WorkflowRunStepRecord, 'id'>): Promise<WorkflowRunStepRecord>;
|
|
392
|
+
getStep(stepId: string): Promise<WorkflowRunStepRecord | null>;
|
|
393
|
+
updateStep(stepId: string, updates: Partial<WorkflowRunStepRecord>): Promise<void>;
|
|
394
|
+
getStepsForRun(runId: string): Promise<WorkflowRunStepRecord[]>;
|
|
395
|
+
saveEvent(event: Omit<WorkflowEventRecord, 'id'>): Promise<void>;
|
|
396
|
+
getEventsForRun(runId: string, options?: ListEventsOptions): Promise<WorkflowEventRecord[]>;
|
|
397
|
+
}
|
|
398
|
+
|
|
192
399
|
/**
|
|
193
400
|
* PostgreSQL storage adapter using Kysely.
|
|
194
401
|
*
|
|
195
|
-
* Provides durable persistence for workflow runs, steps, and events
|
|
196
|
-
*
|
|
402
|
+
* Provides durable persistence for workflow runs, steps, and events with
|
|
403
|
+
* support for distributed deployments and connection pooling.
|
|
404
|
+
*
|
|
405
|
+
* ## Module layout
|
|
406
|
+
*
|
|
407
|
+
* - `PostgresStorageAdapter` (this file) owns the `pg.Pool` / Kysely
|
|
408
|
+
* instance, runs schema migrations on `initialize()`, and implements all
|
|
409
|
+
* non-CRUD methods: connection lifecycle (`close`, `transaction`),
|
|
410
|
+
* workflow-level operations (`dequeueRun`, `cleanupStaleRuns`,
|
|
411
|
+
* `markRunsAsFailed`, `getStats`, `deleteRun`, `deleteOldRuns`,
|
|
412
|
+
* `getInterruptedRuns`, `getLastCompletedStep`), and the
|
|
413
|
+
* `stepflow_step_results` accessors.
|
|
414
|
+
*
|
|
415
|
+
* - `PostgresTransactionAdapter` (this file) is a thin shell used by
|
|
416
|
+
* `PostgresStorageAdapter.transaction()`. It binds a transaction-scoped
|
|
417
|
+
* Kysely query builder; everything else comes from the shared core.
|
|
418
|
+
* Exported only for regression tests.
|
|
419
|
+
*
|
|
420
|
+
* - `PostgresStorageCore` (./postgres-core.ts) holds the shared CRUD
|
|
421
|
+
* methods (`createRun`, `getRun`, `updateRun`, `listRuns`, `createStep`,
|
|
422
|
+
* `getStep`, `updateStep`, `getStepsForRun`, `saveEvent`,
|
|
423
|
+
* `getEventsForRun`), the row mappers, and the JSON-parse helpers. Both
|
|
424
|
+
* classes here extend it.
|
|
197
425
|
*/
|
|
198
426
|
|
|
427
|
+
/** Kysely row type for the stepflow_step_results table (extended storage). */
|
|
428
|
+
interface StepflowStepResultsTable {
|
|
429
|
+
id: string;
|
|
430
|
+
/** Foreign key to runs.id. */
|
|
431
|
+
run_id: string;
|
|
432
|
+
/** Step name identifier. */
|
|
433
|
+
step_name: string;
|
|
434
|
+
/** Current step status (maps to ExtendedStepStatus). */
|
|
435
|
+
status: string;
|
|
436
|
+
/** JSON-serialized step output, null until step completes. */
|
|
437
|
+
output_json: string | null;
|
|
438
|
+
/** JSON-serialized error object, null unless step failed. */
|
|
439
|
+
error_json: string | null;
|
|
440
|
+
/** Current retry attempt number (1-based). */
|
|
441
|
+
attempt: number;
|
|
442
|
+
started_at: Date | null;
|
|
443
|
+
completed_at: Date | null;
|
|
444
|
+
}
|
|
445
|
+
interface StepflowDatabase extends PostgresCoreDatabase {
|
|
446
|
+
stepflow_step_results: StepflowStepResultsTable;
|
|
447
|
+
}
|
|
199
448
|
/**
|
|
200
449
|
* Configuration options for the PostgreSQL storage adapter.
|
|
201
450
|
*/
|
|
@@ -224,6 +473,12 @@ interface PostgresStorageConfig {
|
|
|
224
473
|
* @default true
|
|
225
474
|
*/
|
|
226
475
|
autoMigrate?: boolean;
|
|
476
|
+
/**
|
|
477
|
+
* Optional structured logger used to surface JSON corruption events.
|
|
478
|
+
* Without one, parse failures still increment the corruption counter
|
|
479
|
+
* exposed via `getJsonParseCorruptionCount()` but produce no log output.
|
|
480
|
+
*/
|
|
481
|
+
logger?: Logger;
|
|
227
482
|
}
|
|
228
483
|
/**
|
|
229
484
|
* PostgreSQL implementation of StorageAdapter using Kysely.
|
|
@@ -263,20 +518,30 @@ interface PostgresStorageConfig {
|
|
|
263
518
|
* const storage = new PostgresStorageAdapter({ pool });
|
|
264
519
|
* ```
|
|
265
520
|
*/
|
|
266
|
-
declare class PostgresStorageAdapter
|
|
521
|
+
declare class PostgresStorageAdapter extends PostgresStorageCore {
|
|
267
522
|
private db;
|
|
268
523
|
private pool;
|
|
269
524
|
private ownsPool;
|
|
270
|
-
private schema;
|
|
271
525
|
private autoMigrate;
|
|
272
526
|
private initialized;
|
|
273
527
|
private config;
|
|
274
528
|
constructor(config: PostgresStorageConfig);
|
|
275
529
|
/**
|
|
276
|
-
*
|
|
277
|
-
*
|
|
530
|
+
* Core-tables query builder consumed by `PostgresStorageCore`. Returns the
|
|
531
|
+
* schema-scoped Kysely view typed against the three core tables, which is
|
|
532
|
+
* what the shared CRUD methods need.
|
|
533
|
+
*/
|
|
534
|
+
protected get qb(): CoreSchemaQueryBuilder;
|
|
535
|
+
/**
|
|
536
|
+
* Extended query builder for adapter-only tables (currently
|
|
537
|
+
* `stepflow_step_results`). Kept separate from `qb` so the base class stays
|
|
538
|
+
* typed against the core schema.
|
|
278
539
|
*/
|
|
279
|
-
private get
|
|
540
|
+
private get extQb();
|
|
541
|
+
/** Tag used by shared row mappers in `console.warn` messages. */
|
|
542
|
+
protected get warnLabel(): string;
|
|
543
|
+
/** Override of `PostgresStorageCore.ensureReady()` — enforces `initialize()`. */
|
|
544
|
+
protected ensureReady(): void;
|
|
280
545
|
private ensureInitialized;
|
|
281
546
|
/**
|
|
282
547
|
* Initialize the storage adapter.
|
|
@@ -289,35 +554,28 @@ declare class PostgresStorageAdapter implements StorageAdapter {
|
|
|
289
554
|
*/
|
|
290
555
|
close(): Promise<void>;
|
|
291
556
|
/**
|
|
292
|
-
*
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
* Create a new workflow run.
|
|
297
|
-
* Supports both legacy and new CreateRunInput interfaces.
|
|
298
|
-
*/
|
|
299
|
-
createRun(run: CreateRunInput | Omit<WorkflowRunRecord, 'id' | 'createdAt'>): Promise<WorkflowRunRecord>;
|
|
300
|
-
getRun(runId: string): Promise<WorkflowRunRecord | null>;
|
|
301
|
-
/**
|
|
302
|
-
* Update a workflow run.
|
|
303
|
-
* Supports both legacy Partial<WorkflowRunRecord> and new UpdateRunInput interfaces.
|
|
557
|
+
* Run a single migration step. Tolerates only known-benign Postgres errors
|
|
558
|
+
* (duplicate object codes that map to "already applied"), and rethrows
|
|
559
|
+
* everything else with a clear message so partial-state upgrades are not
|
|
560
|
+
* silently swallowed.
|
|
304
561
|
*/
|
|
305
|
-
|
|
562
|
+
protected runMigration(label: string, fn: () => Promise<unknown>): Promise<void>;
|
|
306
563
|
/**
|
|
307
|
-
*
|
|
564
|
+
* Postgres SQLSTATE codes that indicate a migration step has already been
|
|
565
|
+
* applied (object already exists). These are safe to ignore on idempotent
|
|
566
|
+
* re-runs; everything else must propagate.
|
|
567
|
+
*
|
|
568
|
+
* - 42701: duplicate_column
|
|
569
|
+
* - 42P07: duplicate_table
|
|
570
|
+
* - 42P06: duplicate_schema
|
|
571
|
+
* - 42710: duplicate_object (e.g., index, constraint)
|
|
308
572
|
*/
|
|
573
|
+
private static readonly BENIGN_MIGRATION_CODES;
|
|
574
|
+
private static isBenignMigrationError;
|
|
309
575
|
/**
|
|
310
|
-
*
|
|
311
|
-
* Used by both the data query and count query in listRuns to avoid duplication.
|
|
576
|
+
* Create the workflow tables if they don't exist.
|
|
312
577
|
*/
|
|
313
|
-
private
|
|
314
|
-
listRuns(options?: ListRunsOptions): Promise<PaginatedResult<WorkflowRunRecord>>;
|
|
315
|
-
createStep(step: Omit<WorkflowRunStepRecord, 'id'>): Promise<WorkflowRunStepRecord>;
|
|
316
|
-
getStep(stepId: string): Promise<WorkflowRunStepRecord | null>;
|
|
317
|
-
updateStep(stepId: string, updates: Partial<WorkflowRunStepRecord>): Promise<void>;
|
|
318
|
-
getStepsForRun(runId: string): Promise<WorkflowRunStepRecord[]>;
|
|
319
|
-
saveEvent(event: Omit<WorkflowEventRecord, 'id'>): Promise<void>;
|
|
320
|
-
getEventsForRun(runId: string, options?: ListEventsOptions): Promise<WorkflowEventRecord[]>;
|
|
578
|
+
private createTables;
|
|
321
579
|
/**
|
|
322
580
|
* Execute a function within a database transaction.
|
|
323
581
|
*/
|
|
@@ -345,14 +603,7 @@ declare class PostgresStorageAdapter implements StorageAdapter {
|
|
|
345
603
|
* @returns The dequeued run, or null if no runs are available
|
|
346
604
|
*/
|
|
347
605
|
dequeueRun(workflowKinds?: string[]): Promise<WorkflowRunRecord | null>;
|
|
348
|
-
private mapRunRow;
|
|
349
|
-
/**
|
|
350
|
-
* Map a database row to an extended workflow run record.
|
|
351
|
-
*/
|
|
352
|
-
private mapExtendedRunRow;
|
|
353
606
|
private mapStepResultRow;
|
|
354
|
-
private mapStepRow;
|
|
355
|
-
private mapEventRow;
|
|
356
607
|
/**
|
|
357
608
|
* Delete a workflow run by ID.
|
|
358
609
|
* Also deletes associated steps and events (via CASCADE).
|
|
@@ -398,5 +649,20 @@ declare class PostgresStorageAdapter implements StorageAdapter {
|
|
|
398
649
|
events: number;
|
|
399
650
|
}>;
|
|
400
651
|
}
|
|
652
|
+
/**
|
|
653
|
+
* A StorageAdapter wrapper for use within transactions.
|
|
654
|
+
*
|
|
655
|
+
* Used internally by `PostgresStorageAdapter.transaction()`. All CRUD methods
|
|
656
|
+
* are inherited from `PostgresStorageCore`; this class only binds the
|
|
657
|
+
* transaction-scoped query builder.
|
|
658
|
+
*
|
|
659
|
+
* Exported for regression testing; not part of the public API.
|
|
660
|
+
*/
|
|
661
|
+
declare class PostgresTransactionAdapter extends PostgresStorageCore {
|
|
662
|
+
private readonly _qb;
|
|
663
|
+
constructor(trx: Kysely<StepflowDatabase>, schema: string, logger?: Logger);
|
|
664
|
+
protected get qb(): CoreSchemaQueryBuilder;
|
|
665
|
+
protected get warnLabel(): string;
|
|
666
|
+
}
|
|
401
667
|
|
|
402
|
-
export { CreateRunInput, ListEventsOptions, ListRunsOptions, MemoryStorageAdapter, PaginatedResult, PostgresStorageAdapter as PostgresStorage, PostgresStorageAdapter, type PostgresStorageConfig, type PostgresStorageConfig as PostgresStorageOptions, SQLiteStorageAdapter, type SQLiteStorageConfig, StepResult, StorageAdapter, UpdateRunInput, WorkflowEventRecord, WorkflowRunRecord, WorkflowRunStepRecord };
|
|
668
|
+
export { CreateRunInput, ListEventsOptions, ListRunsOptions, MemoryStorageAdapter, PaginatedResult, PostgresStorageAdapter as PostgresStorage, PostgresStorageAdapter, type PostgresStorageConfig, type PostgresStorageConfig as PostgresStorageOptions, PostgresTransactionAdapter, SQLiteStorageAdapter, type SQLiteStorageConfig, StepResult, StorageAdapter, UpdateRunInput, WorkflowEventRecord, WorkflowRunRecord, WorkflowRunStepRecord };
|
package/dist/storage/index.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
MemoryStorageAdapter,
|
|
3
3
|
PostgresStorageAdapter,
|
|
4
|
+
PostgresTransactionAdapter,
|
|
4
5
|
SQLiteStorageAdapter
|
|
5
|
-
} from "../chunk-
|
|
6
|
-
import "../chunk-
|
|
6
|
+
} from "../chunk-JUPZEBR3.js";
|
|
7
|
+
import "../chunk-JPXPB7U5.js";
|
|
7
8
|
export {
|
|
8
9
|
MemoryStorageAdapter,
|
|
9
10
|
PostgresStorageAdapter as PostgresStorage,
|
|
10
11
|
PostgresStorageAdapter,
|
|
12
|
+
PostgresTransactionAdapter,
|
|
11
13
|
SQLiteStorageAdapter
|
|
12
14
|
};
|
|
13
15
|
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@multiplier-labs/stepflow",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.6",
|
|
4
4
|
"description": "A durable, type-safe workflow orchestration engine for Node.js with SQLite persistence, scheduling, and real-time events",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -43,6 +43,9 @@
|
|
|
43
43
|
"import": "./dist/scheduler/index.js"
|
|
44
44
|
}
|
|
45
45
|
},
|
|
46
|
+
"engines": {
|
|
47
|
+
"node": "^22.22.2 || ^24.15.0 || >=26.0.0"
|
|
48
|
+
},
|
|
46
49
|
"scripts": {
|
|
47
50
|
"build": "tsup",
|
|
48
51
|
"dev": "tsup --watch",
|
|
@@ -52,12 +55,12 @@
|
|
|
52
55
|
"test:coverage": "vitest run --coverage"
|
|
53
56
|
},
|
|
54
57
|
"dependencies": {
|
|
55
|
-
"cron-parser": "^5.
|
|
56
|
-
"re2": "^1.
|
|
58
|
+
"cron-parser": "^5.10.1",
|
|
59
|
+
"re2": "^1.27.0"
|
|
57
60
|
},
|
|
58
61
|
"peerDependencies": {
|
|
59
62
|
"better-sqlite3": ">=11.0.0",
|
|
60
|
-
"kysely": ">=0.28.
|
|
63
|
+
"kysely": ">=0.28.16",
|
|
61
64
|
"pg": ">=8.13.0"
|
|
62
65
|
},
|
|
63
66
|
"peerDependenciesMeta": {
|
|
@@ -73,14 +76,25 @@
|
|
|
73
76
|
},
|
|
74
77
|
"devDependencies": {
|
|
75
78
|
"@types/better-sqlite3": "^7.6.11",
|
|
76
|
-
"@types/node": "^
|
|
79
|
+
"@types/node": "^25.6.0",
|
|
77
80
|
"@types/pg": "^8.18.0",
|
|
78
|
-
"@vitest/coverage-v8": "^4.1.
|
|
79
|
-
"better-sqlite3": "^12.
|
|
80
|
-
"kysely": "^0.
|
|
81
|
-
"pg": "^8.
|
|
82
|
-
"tsup": "^8.
|
|
83
|
-
"typescript": "^
|
|
84
|
-
"vitest": "^4.1.
|
|
85
|
-
}
|
|
81
|
+
"@vitest/coverage-v8": "^4.1.11",
|
|
82
|
+
"better-sqlite3": "^12.11.1",
|
|
83
|
+
"kysely": "^0.29.4",
|
|
84
|
+
"pg": "^8.23.0",
|
|
85
|
+
"tsup": "^8.5.1",
|
|
86
|
+
"typescript": "^6.0.3",
|
|
87
|
+
"vitest": "^4.1.11"
|
|
88
|
+
},
|
|
89
|
+
"overrides": {
|
|
90
|
+
"postcss": ">=8.5.18",
|
|
91
|
+
"brace-expansion": ">=5.0.8",
|
|
92
|
+
"esbuild": ">=0.28.1",
|
|
93
|
+
"tar": ">=7.5.21",
|
|
94
|
+
"vite": ">=8.0.16",
|
|
95
|
+
"nanoid": "^3.3.17"
|
|
96
|
+
},
|
|
97
|
+
"files": [
|
|
98
|
+
"dist"
|
|
99
|
+
]
|
|
86
100
|
}
|