pg-workflows 0.3.0 → 0.4.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/README.md +36 -15
- package/dist/index.cjs +47 -18
- package/dist/index.d.cts +16 -6
- package/dist/index.d.ts +16 -6
- package/dist/index.js +47 -18
- package/dist/index.js.map +4 -4
- package/package.json +18 -8
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
[](https://www.postgresql.org/)
|
|
9
9
|
|
|
10
10
|
```bash
|
|
11
|
-
npm install pg-workflows
|
|
11
|
+
npm install pg-workflows pg
|
|
12
12
|
```
|
|
13
13
|
|
|
14
14
|
---
|
|
@@ -52,7 +52,7 @@ If you need enterprise-grade features like distributed tracing, complex DAG sche
|
|
|
52
52
|
- **Configurable Timeouts** - Set workflow-level and step-level timeouts to prevent runaway executions.
|
|
53
53
|
- **Progress Tracking** - Monitor workflow completion percentage, completed steps, and total steps in real-time.
|
|
54
54
|
- **Input Validation** - Define schemas with Zod for type-safe, validated workflow inputs.
|
|
55
|
-
- **Built on pg-boss** - Leverages the battle-tested [pg-boss](https://github.com/timgit/pg-boss) job queue for reliable task scheduling.
|
|
55
|
+
- **Built on pg-boss** - Leverages the battle-tested [pg-boss](https://github.com/timgit/pg-boss) job queue for reliable task scheduling. pg-boss is bundled as a dependency - no separate install or configuration needed.
|
|
56
56
|
|
|
57
57
|
---
|
|
58
58
|
|
|
@@ -76,18 +76,19 @@ All state lives in PostgreSQL. No Redis. No message broker. No external schedule
|
|
|
76
76
|
### 1. Install
|
|
77
77
|
|
|
78
78
|
```bash
|
|
79
|
-
npm install pg-workflows pg
|
|
79
|
+
npm install pg-workflows pg
|
|
80
80
|
# or
|
|
81
|
-
yarn add pg-workflows pg
|
|
81
|
+
yarn add pg-workflows pg
|
|
82
82
|
# or
|
|
83
|
-
bun add pg-workflows pg
|
|
83
|
+
bun add pg-workflows pg
|
|
84
84
|
```
|
|
85
85
|
|
|
86
|
+
> `pg` is a peer dependency - you bring your own PostgreSQL driver. `pg-boss` is bundled automatically.
|
|
87
|
+
|
|
86
88
|
### 2. Define a Workflow
|
|
87
89
|
|
|
88
90
|
```typescript
|
|
89
91
|
import { WorkflowEngine, workflow } from 'pg-workflows';
|
|
90
|
-
import PgBoss from 'pg-boss';
|
|
91
92
|
import { z } from 'zod';
|
|
92
93
|
|
|
93
94
|
// Define a durable workflow
|
|
@@ -125,12 +126,17 @@ const sendWelcomeEmail = workflow(
|
|
|
125
126
|
### 3. Start the Engine
|
|
126
127
|
|
|
127
128
|
```typescript
|
|
128
|
-
|
|
129
|
+
// Option A: Connection string (simplest - engine manages everything)
|
|
130
|
+
const engine = new WorkflowEngine({
|
|
129
131
|
connectionString: process.env.DATABASE_URL,
|
|
132
|
+
workflows: [sendWelcomeEmail],
|
|
130
133
|
});
|
|
131
134
|
|
|
135
|
+
// Option B: Bring your own pg.Pool
|
|
136
|
+
import pg from 'pg';
|
|
137
|
+
const pool = new pg.Pool({ connectionString: process.env.DATABASE_URL });
|
|
132
138
|
const engine = new WorkflowEngine({
|
|
133
|
-
|
|
139
|
+
pool,
|
|
134
140
|
workflows: [sendWelcomeEmail],
|
|
135
141
|
});
|
|
136
142
|
|
|
@@ -549,13 +555,27 @@ console.log({
|
|
|
549
555
|
#### Constructor
|
|
550
556
|
|
|
551
557
|
```typescript
|
|
558
|
+
// With connection string (engine creates and owns the pool)
|
|
559
|
+
const engine = new WorkflowEngine({
|
|
560
|
+
connectionString: string, // PostgreSQL connection string
|
|
561
|
+
workflows?: WorkflowDefinition[], // Optional: register workflows on init
|
|
562
|
+
logger?: WorkflowLogger, // Optional: custom logger
|
|
563
|
+
boss?: PgBoss, // Optional: bring your own pg-boss instance
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
// With existing pool (you manage the pool lifecycle)
|
|
552
567
|
const engine = new WorkflowEngine({
|
|
553
|
-
|
|
554
|
-
workflows
|
|
555
|
-
logger
|
|
568
|
+
pool: pg.Pool, // Your pg.Pool instance
|
|
569
|
+
workflows?: WorkflowDefinition[],
|
|
570
|
+
logger?: WorkflowLogger,
|
|
571
|
+
boss?: PgBoss,
|
|
556
572
|
});
|
|
557
573
|
```
|
|
558
574
|
|
|
575
|
+
Pass either `connectionString` or `pool` (exactly one). When `connectionString` is used, the engine creates the pool internally and closes it on `stop()`.
|
|
576
|
+
|
|
577
|
+
When `boss` is omitted, pg-boss is created automatically with an isolated schema (`pgboss_v12_pgworkflow`) to avoid conflicts with other pg-boss installations.
|
|
578
|
+
|
|
559
579
|
#### Methods
|
|
560
580
|
|
|
561
581
|
| Method | Description |
|
|
@@ -643,8 +663,8 @@ enum WorkflowStatus {
|
|
|
643
663
|
|
|
644
664
|
The engine automatically runs migrations on startup to create the required tables:
|
|
645
665
|
|
|
646
|
-
- `workflow_runs` - Stores workflow execution state, step results, and timeline. The optional `resource_id` column (indexed) associates each run with an external entity in your application. See [Resource ID](#resource-id).
|
|
647
|
-
- `
|
|
666
|
+
- `workflow_runs` - Stores workflow execution state, step results, and timeline in the `public` schema. The optional `resource_id` column (indexed) associates each run with an external entity in your application. See [Resource ID](#resource-id).
|
|
667
|
+
- `pgboss_v12_pgworkflow.*` - pg-boss job queue tables for reliable task scheduling (isolated schema to avoid conflicts)
|
|
648
668
|
|
|
649
669
|
---
|
|
650
670
|
|
|
@@ -660,7 +680,7 @@ As championed by [postgresforeverything.com](https://postgresforeverything.com/)
|
|
|
660
680
|
If you're already running Postgres (and you probably should be), adding durable workflows is as simple as:
|
|
661
681
|
|
|
662
682
|
```bash
|
|
663
|
-
npm install pg-workflows
|
|
683
|
+
npm install pg-workflows pg
|
|
664
684
|
```
|
|
665
685
|
|
|
666
686
|
---
|
|
@@ -669,7 +689,8 @@ npm install pg-workflows
|
|
|
669
689
|
|
|
670
690
|
- Node.js >= 18.0.0
|
|
671
691
|
- PostgreSQL >= 10
|
|
672
|
-
- pg
|
|
692
|
+
- `pg` >= 8.0.0 (peer dependency)
|
|
693
|
+
- `zod` >= 3.0.0 (optional peer dependency, needed only if using `inputSchema`)
|
|
673
694
|
|
|
674
695
|
## Acknowledgments
|
|
675
696
|
|
package/dist/index.cjs
CHANGED
|
@@ -144,6 +144,8 @@ function parseDuration(duration) {
|
|
|
144
144
|
}
|
|
145
145
|
// src/engine.ts
|
|
146
146
|
var import_es_toolkit = require("es-toolkit");
|
|
147
|
+
var import_pg = __toESM(require("pg"));
|
|
148
|
+
var import_pg_boss = require("pg-boss");
|
|
147
149
|
|
|
148
150
|
// src/ast-parser.ts
|
|
149
151
|
var ts = __toESM(require("typescript"));
|
|
@@ -508,15 +510,28 @@ async function getWorkflowRuns({
|
|
|
508
510
|
const prevCursor = hasPrev && items.length > 0 ? items[0]?.id ?? null : null;
|
|
509
511
|
return { items, nextCursor, prevCursor, hasMore, hasPrev };
|
|
510
512
|
}
|
|
511
|
-
async function withPostgresTransaction(db, callback) {
|
|
513
|
+
async function withPostgresTransaction(db, callback, pool) {
|
|
514
|
+
let txDb;
|
|
515
|
+
let release;
|
|
516
|
+
if (pool) {
|
|
517
|
+
const client = await pool.connect();
|
|
518
|
+
txDb = {
|
|
519
|
+
executeSql: (text, values) => client.query(text, values)
|
|
520
|
+
};
|
|
521
|
+
release = () => client.release();
|
|
522
|
+
} else {
|
|
523
|
+
txDb = db;
|
|
524
|
+
}
|
|
512
525
|
try {
|
|
513
|
-
await
|
|
514
|
-
const result = await callback(
|
|
515
|
-
await
|
|
526
|
+
await txDb.executeSql("BEGIN", []);
|
|
527
|
+
const result = await callback(txDb);
|
|
528
|
+
await txDb.executeSql("COMMIT", []);
|
|
516
529
|
return result;
|
|
517
530
|
} catch (error) {
|
|
518
|
-
await
|
|
531
|
+
await txDb.executeSql("ROLLBACK", []);
|
|
519
532
|
throw error;
|
|
533
|
+
} finally {
|
|
534
|
+
release?.();
|
|
520
535
|
}
|
|
521
536
|
}
|
|
522
537
|
|
|
@@ -524,6 +539,7 @@ async function withPostgresTransaction(db, callback) {
|
|
|
524
539
|
var PAUSE_EVENT_NAME = "__internal_pause";
|
|
525
540
|
var WORKFLOW_RUN_QUEUE_NAME = "workflow-run";
|
|
526
541
|
var LOG_PREFIX = "[WorkflowEngine]";
|
|
542
|
+
var DEFAULT_PGBOSS_SCHEMA = "pgboss_v12_pgworkflow";
|
|
527
543
|
var StepTypeToIcon = {
|
|
528
544
|
["run" /* RUN */]: "λ",
|
|
529
545
|
["waitFor" /* WAIT_FOR */]: "○",
|
|
@@ -541,24 +557,34 @@ var defaultExpireInSeconds = process.env.WORKFLOW_RUN_EXPIRE_IN_SECONDS ? Number
|
|
|
541
557
|
class WorkflowEngine {
|
|
542
558
|
boss;
|
|
543
559
|
db;
|
|
560
|
+
pool;
|
|
561
|
+
_ownsPool = false;
|
|
544
562
|
unregisteredWorkflows = new Map;
|
|
545
563
|
_started = false;
|
|
546
564
|
workflows = new Map;
|
|
547
565
|
logger;
|
|
548
|
-
constructor({
|
|
549
|
-
workflows,
|
|
550
|
-
logger,
|
|
551
|
-
boss
|
|
552
|
-
} = {}) {
|
|
566
|
+
constructor({ workflows, logger, boss, ...connectionOptions }) {
|
|
553
567
|
this.logger = this.buildLogger(logger ?? defaultLogger);
|
|
568
|
+
if ("pool" in connectionOptions && connectionOptions.pool) {
|
|
569
|
+
this.pool = connectionOptions.pool;
|
|
570
|
+
} else if ("connectionString" in connectionOptions && connectionOptions.connectionString) {
|
|
571
|
+
this.pool = new import_pg.default.Pool({ connectionString: connectionOptions.connectionString });
|
|
572
|
+
this._ownsPool = true;
|
|
573
|
+
} else {
|
|
574
|
+
throw new WorkflowEngineError("Either pool or connectionString must be provided");
|
|
575
|
+
}
|
|
554
576
|
if (workflows) {
|
|
555
577
|
this.unregisteredWorkflows = new Map(workflows.map((workflow2) => [workflow2.id, workflow2]));
|
|
556
578
|
}
|
|
557
|
-
|
|
558
|
-
|
|
579
|
+
const db = {
|
|
580
|
+
executeSql: (text, values) => this.pool.query(text, values)
|
|
581
|
+
};
|
|
582
|
+
if (boss) {
|
|
583
|
+
this.boss = boss;
|
|
584
|
+
} else {
|
|
585
|
+
this.boss = new import_pg_boss.PgBoss({ db, schema: DEFAULT_PGBOSS_SCHEMA });
|
|
559
586
|
}
|
|
560
|
-
this.
|
|
561
|
-
this.db = boss.getDb();
|
|
587
|
+
this.db = this.boss.getDb();
|
|
562
588
|
}
|
|
563
589
|
async start(asEngine = true, { batchSize } = { batchSize: 1 }) {
|
|
564
590
|
if (this._started) {
|
|
@@ -584,6 +610,9 @@ class WorkflowEngine {
|
|
|
584
610
|
}
|
|
585
611
|
async stop() {
|
|
586
612
|
await this.boss.stop();
|
|
613
|
+
if (this._ownsPool) {
|
|
614
|
+
await this.pool.end();
|
|
615
|
+
}
|
|
587
616
|
this._started = false;
|
|
588
617
|
this.logger.log("Workflow engine stopped");
|
|
589
618
|
}
|
|
@@ -652,7 +681,7 @@ class WorkflowEngine {
|
|
|
652
681
|
input,
|
|
653
682
|
maxRetries: options?.retries ?? workflow2.retries ?? 0,
|
|
654
683
|
timeoutAt
|
|
655
|
-
},
|
|
684
|
+
}, _db);
|
|
656
685
|
const job = {
|
|
657
686
|
runId: insertedRun.id,
|
|
658
687
|
resourceId,
|
|
@@ -664,7 +693,7 @@ class WorkflowEngine {
|
|
|
664
693
|
expireInSeconds: options?.expireInSeconds ?? defaultExpireInSeconds
|
|
665
694
|
});
|
|
666
695
|
return insertedRun;
|
|
667
|
-
});
|
|
696
|
+
}, this.pool);
|
|
668
697
|
this.logger.log("Started workflow run", {
|
|
669
698
|
runId: run.id,
|
|
670
699
|
workflowId
|
|
@@ -1061,7 +1090,7 @@ ${error.stack}` : String(error)
|
|
|
1061
1090
|
}, { db });
|
|
1062
1091
|
throw error;
|
|
1063
1092
|
}
|
|
1064
|
-
});
|
|
1093
|
+
}, this.pool);
|
|
1065
1094
|
}
|
|
1066
1095
|
async waitStep({
|
|
1067
1096
|
run,
|
|
@@ -1229,5 +1258,5 @@ ${error.stack}` : String(error)
|
|
|
1229
1258
|
}
|
|
1230
1259
|
}
|
|
1231
1260
|
|
|
1232
|
-
//# debugId=
|
|
1261
|
+
//# debugId=AA54057FBD64F69364756E2164756E21
|
|
1233
1262
|
//# sourceMappingURL=index.js.map
|
package/dist/index.d.cts
CHANGED
|
@@ -159,19 +159,29 @@ interface WorkflowInternalLogger {
|
|
|
159
159
|
error(message: string, error: Error, context?: WorkflowInternalLoggerContext): void;
|
|
160
160
|
}
|
|
161
161
|
declare const workflow: WorkflowFactory;
|
|
162
|
+
import pg from "pg";
|
|
162
163
|
import { Db, PgBoss } from "pg-boss";
|
|
164
|
+
type WorkflowEngineOptions = {
|
|
165
|
+
workflows?: WorkflowDefinition[];
|
|
166
|
+
logger?: WorkflowLogger;
|
|
167
|
+
boss?: PgBoss;
|
|
168
|
+
} & ({
|
|
169
|
+
pool: pg.Pool;
|
|
170
|
+
connectionString?: never;
|
|
171
|
+
} | {
|
|
172
|
+
connectionString: string;
|
|
173
|
+
pool?: never;
|
|
174
|
+
});
|
|
163
175
|
declare class WorkflowEngine {
|
|
164
176
|
private boss;
|
|
165
177
|
private db;
|
|
178
|
+
private pool;
|
|
179
|
+
private _ownsPool;
|
|
166
180
|
private unregisteredWorkflows;
|
|
167
181
|
private _started;
|
|
168
182
|
workflows: Map<string, WorkflowInternalDefinition>;
|
|
169
183
|
private logger;
|
|
170
|
-
constructor({ workflows, logger, boss }
|
|
171
|
-
workflows: WorkflowDefinition[];
|
|
172
|
-
logger: WorkflowLogger;
|
|
173
|
-
boss: PgBoss;
|
|
174
|
-
}>);
|
|
184
|
+
constructor({ workflows, logger, boss,...connectionOptions }: WorkflowEngineOptions);
|
|
175
185
|
start(asEngine?: boolean, { batchSize }?: {
|
|
176
186
|
batchSize?: number;
|
|
177
187
|
}): Promise<void>;
|
|
@@ -263,4 +273,4 @@ declare class WorkflowEngineError extends Error {
|
|
|
263
273
|
declare class WorkflowRunNotFoundError extends WorkflowEngineError {
|
|
264
274
|
constructor(runId?: string, workflowId?: string);
|
|
265
275
|
}
|
|
266
|
-
export { workflow, parseDuration, WorkflowStatus, WorkflowRunProgress, WorkflowRunNotFoundError, WorkflowPlugin, WorkflowOptions, WorkflowLogger, WorkflowInternalLoggerContext, WorkflowInternalLogger, WorkflowInternalDefinition, WorkflowFactory, WorkflowEngineError, WorkflowEngine, WorkflowDefinition, WorkflowContext, StepType, StepInternalDefinition, StepBaseContext, InputParameters, InferInputParameters, DurationObject, Duration };
|
|
276
|
+
export { workflow, parseDuration, WorkflowStatus, WorkflowRunProgress, WorkflowRunNotFoundError, WorkflowPlugin, WorkflowOptions, WorkflowLogger, WorkflowInternalLoggerContext, WorkflowInternalLogger, WorkflowInternalDefinition, WorkflowFactory, WorkflowEngineOptions, WorkflowEngineError, WorkflowEngine, WorkflowDefinition, WorkflowContext, StepType, StepInternalDefinition, StepBaseContext, InputParameters, InferInputParameters, DurationObject, Duration };
|
package/dist/index.d.ts
CHANGED
|
@@ -159,19 +159,29 @@ interface WorkflowInternalLogger {
|
|
|
159
159
|
error(message: string, error: Error, context?: WorkflowInternalLoggerContext): void;
|
|
160
160
|
}
|
|
161
161
|
declare const workflow: WorkflowFactory;
|
|
162
|
+
import pg from "pg";
|
|
162
163
|
import { Db, PgBoss } from "pg-boss";
|
|
164
|
+
type WorkflowEngineOptions = {
|
|
165
|
+
workflows?: WorkflowDefinition[];
|
|
166
|
+
logger?: WorkflowLogger;
|
|
167
|
+
boss?: PgBoss;
|
|
168
|
+
} & ({
|
|
169
|
+
pool: pg.Pool;
|
|
170
|
+
connectionString?: never;
|
|
171
|
+
} | {
|
|
172
|
+
connectionString: string;
|
|
173
|
+
pool?: never;
|
|
174
|
+
});
|
|
163
175
|
declare class WorkflowEngine {
|
|
164
176
|
private boss;
|
|
165
177
|
private db;
|
|
178
|
+
private pool;
|
|
179
|
+
private _ownsPool;
|
|
166
180
|
private unregisteredWorkflows;
|
|
167
181
|
private _started;
|
|
168
182
|
workflows: Map<string, WorkflowInternalDefinition>;
|
|
169
183
|
private logger;
|
|
170
|
-
constructor({ workflows, logger, boss }
|
|
171
|
-
workflows: WorkflowDefinition[];
|
|
172
|
-
logger: WorkflowLogger;
|
|
173
|
-
boss: PgBoss;
|
|
174
|
-
}>);
|
|
184
|
+
constructor({ workflows, logger, boss,...connectionOptions }: WorkflowEngineOptions);
|
|
175
185
|
start(asEngine?: boolean, { batchSize }?: {
|
|
176
186
|
batchSize?: number;
|
|
177
187
|
}): Promise<void>;
|
|
@@ -263,4 +273,4 @@ declare class WorkflowEngineError extends Error {
|
|
|
263
273
|
declare class WorkflowRunNotFoundError extends WorkflowEngineError {
|
|
264
274
|
constructor(runId?: string, workflowId?: string);
|
|
265
275
|
}
|
|
266
|
-
export { workflow, parseDuration, WorkflowStatus, WorkflowRunProgress, WorkflowRunNotFoundError, WorkflowPlugin, WorkflowOptions, WorkflowLogger, WorkflowInternalLoggerContext, WorkflowInternalLogger, WorkflowInternalDefinition, WorkflowFactory, WorkflowEngineError, WorkflowEngine, WorkflowDefinition, WorkflowContext, StepType, StepInternalDefinition, StepBaseContext, InputParameters, InferInputParameters, DurationObject, Duration };
|
|
276
|
+
export { workflow, parseDuration, WorkflowStatus, WorkflowRunProgress, WorkflowRunNotFoundError, WorkflowPlugin, WorkflowOptions, WorkflowLogger, WorkflowInternalLoggerContext, WorkflowInternalLogger, WorkflowInternalDefinition, WorkflowFactory, WorkflowEngineOptions, WorkflowEngineError, WorkflowEngine, WorkflowDefinition, WorkflowContext, StepType, StepInternalDefinition, StepBaseContext, InputParameters, InferInputParameters, DurationObject, Duration };
|
package/dist/index.js
CHANGED
|
@@ -68,6 +68,8 @@ function parseDuration(duration) {
|
|
|
68
68
|
}
|
|
69
69
|
// src/engine.ts
|
|
70
70
|
import { merge } from "es-toolkit";
|
|
71
|
+
import pg from "pg";
|
|
72
|
+
import { PgBoss } from "pg-boss";
|
|
71
73
|
|
|
72
74
|
// src/ast-parser.ts
|
|
73
75
|
import * as ts from "typescript";
|
|
@@ -432,15 +434,28 @@ async function getWorkflowRuns({
|
|
|
432
434
|
const prevCursor = hasPrev && items.length > 0 ? items[0]?.id ?? null : null;
|
|
433
435
|
return { items, nextCursor, prevCursor, hasMore, hasPrev };
|
|
434
436
|
}
|
|
435
|
-
async function withPostgresTransaction(db, callback) {
|
|
437
|
+
async function withPostgresTransaction(db, callback, pool) {
|
|
438
|
+
let txDb;
|
|
439
|
+
let release;
|
|
440
|
+
if (pool) {
|
|
441
|
+
const client = await pool.connect();
|
|
442
|
+
txDb = {
|
|
443
|
+
executeSql: (text, values) => client.query(text, values)
|
|
444
|
+
};
|
|
445
|
+
release = () => client.release();
|
|
446
|
+
} else {
|
|
447
|
+
txDb = db;
|
|
448
|
+
}
|
|
436
449
|
try {
|
|
437
|
-
await
|
|
438
|
-
const result = await callback(
|
|
439
|
-
await
|
|
450
|
+
await txDb.executeSql("BEGIN", []);
|
|
451
|
+
const result = await callback(txDb);
|
|
452
|
+
await txDb.executeSql("COMMIT", []);
|
|
440
453
|
return result;
|
|
441
454
|
} catch (error) {
|
|
442
|
-
await
|
|
455
|
+
await txDb.executeSql("ROLLBACK", []);
|
|
443
456
|
throw error;
|
|
457
|
+
} finally {
|
|
458
|
+
release?.();
|
|
444
459
|
}
|
|
445
460
|
}
|
|
446
461
|
|
|
@@ -448,6 +463,7 @@ async function withPostgresTransaction(db, callback) {
|
|
|
448
463
|
var PAUSE_EVENT_NAME = "__internal_pause";
|
|
449
464
|
var WORKFLOW_RUN_QUEUE_NAME = "workflow-run";
|
|
450
465
|
var LOG_PREFIX = "[WorkflowEngine]";
|
|
466
|
+
var DEFAULT_PGBOSS_SCHEMA = "pgboss_v12_pgworkflow";
|
|
451
467
|
var StepTypeToIcon = {
|
|
452
468
|
["run" /* RUN */]: "λ",
|
|
453
469
|
["waitFor" /* WAIT_FOR */]: "○",
|
|
@@ -465,24 +481,34 @@ var defaultExpireInSeconds = process.env.WORKFLOW_RUN_EXPIRE_IN_SECONDS ? Number
|
|
|
465
481
|
class WorkflowEngine {
|
|
466
482
|
boss;
|
|
467
483
|
db;
|
|
484
|
+
pool;
|
|
485
|
+
_ownsPool = false;
|
|
468
486
|
unregisteredWorkflows = new Map;
|
|
469
487
|
_started = false;
|
|
470
488
|
workflows = new Map;
|
|
471
489
|
logger;
|
|
472
|
-
constructor({
|
|
473
|
-
workflows,
|
|
474
|
-
logger,
|
|
475
|
-
boss
|
|
476
|
-
} = {}) {
|
|
490
|
+
constructor({ workflows, logger, boss, ...connectionOptions }) {
|
|
477
491
|
this.logger = this.buildLogger(logger ?? defaultLogger);
|
|
492
|
+
if ("pool" in connectionOptions && connectionOptions.pool) {
|
|
493
|
+
this.pool = connectionOptions.pool;
|
|
494
|
+
} else if ("connectionString" in connectionOptions && connectionOptions.connectionString) {
|
|
495
|
+
this.pool = new pg.Pool({ connectionString: connectionOptions.connectionString });
|
|
496
|
+
this._ownsPool = true;
|
|
497
|
+
} else {
|
|
498
|
+
throw new WorkflowEngineError("Either pool or connectionString must be provided");
|
|
499
|
+
}
|
|
478
500
|
if (workflows) {
|
|
479
501
|
this.unregisteredWorkflows = new Map(workflows.map((workflow2) => [workflow2.id, workflow2]));
|
|
480
502
|
}
|
|
481
|
-
|
|
482
|
-
|
|
503
|
+
const db = {
|
|
504
|
+
executeSql: (text, values) => this.pool.query(text, values)
|
|
505
|
+
};
|
|
506
|
+
if (boss) {
|
|
507
|
+
this.boss = boss;
|
|
508
|
+
} else {
|
|
509
|
+
this.boss = new PgBoss({ db, schema: DEFAULT_PGBOSS_SCHEMA });
|
|
483
510
|
}
|
|
484
|
-
this.
|
|
485
|
-
this.db = boss.getDb();
|
|
511
|
+
this.db = this.boss.getDb();
|
|
486
512
|
}
|
|
487
513
|
async start(asEngine = true, { batchSize } = { batchSize: 1 }) {
|
|
488
514
|
if (this._started) {
|
|
@@ -508,6 +534,9 @@ class WorkflowEngine {
|
|
|
508
534
|
}
|
|
509
535
|
async stop() {
|
|
510
536
|
await this.boss.stop();
|
|
537
|
+
if (this._ownsPool) {
|
|
538
|
+
await this.pool.end();
|
|
539
|
+
}
|
|
511
540
|
this._started = false;
|
|
512
541
|
this.logger.log("Workflow engine stopped");
|
|
513
542
|
}
|
|
@@ -576,7 +605,7 @@ class WorkflowEngine {
|
|
|
576
605
|
input,
|
|
577
606
|
maxRetries: options?.retries ?? workflow2.retries ?? 0,
|
|
578
607
|
timeoutAt
|
|
579
|
-
},
|
|
608
|
+
}, _db);
|
|
580
609
|
const job = {
|
|
581
610
|
runId: insertedRun.id,
|
|
582
611
|
resourceId,
|
|
@@ -588,7 +617,7 @@ class WorkflowEngine {
|
|
|
588
617
|
expireInSeconds: options?.expireInSeconds ?? defaultExpireInSeconds
|
|
589
618
|
});
|
|
590
619
|
return insertedRun;
|
|
591
|
-
});
|
|
620
|
+
}, this.pool);
|
|
592
621
|
this.logger.log("Started workflow run", {
|
|
593
622
|
runId: run.id,
|
|
594
623
|
workflowId
|
|
@@ -985,7 +1014,7 @@ ${error.stack}` : String(error)
|
|
|
985
1014
|
}, { db });
|
|
986
1015
|
throw error;
|
|
987
1016
|
}
|
|
988
|
-
});
|
|
1017
|
+
}, this.pool);
|
|
989
1018
|
}
|
|
990
1019
|
async waitStep({
|
|
991
1020
|
run,
|
|
@@ -1162,5 +1191,5 @@ export {
|
|
|
1162
1191
|
StepType
|
|
1163
1192
|
};
|
|
1164
1193
|
|
|
1165
|
-
//# debugId=
|
|
1194
|
+
//# debugId=CE7E5C5A6D5068D664756E2164756E21
|
|
1166
1195
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -5,13 +5,13 @@
|
|
|
5
5
|
"import type {\n InputParameters,\n StepBaseContext,\n WorkflowContext,\n WorkflowDefinition,\n WorkflowFactory,\n WorkflowOptions,\n WorkflowPlugin,\n} from './types';\n\nfunction createWorkflowFactory<TStepExt extends object = object>(\n plugins: Array<WorkflowPlugin<unknown, object>> = [],\n): WorkflowFactory<TStepExt> {\n const factory = (<I extends InputParameters>(\n id: string,\n handler: (context: WorkflowContext<I, StepBaseContext & TStepExt>) => Promise<unknown>,\n { inputSchema, timeout, retries }: WorkflowOptions<I> = {},\n ): WorkflowDefinition<I, StepBaseContext & TStepExt> => ({\n id,\n handler,\n inputSchema,\n timeout,\n retries,\n plugins: plugins.length > 0 ? (plugins as WorkflowPlugin[]) : undefined,\n })) as WorkflowFactory<TStepExt>;\n\n factory.use = <TNewExt>(\n plugin: WorkflowPlugin<StepBaseContext & TStepExt, TNewExt>,\n ): WorkflowFactory<TStepExt & TNewExt> =>\n createWorkflowFactory<TStepExt & TNewExt>([\n ...plugins,\n plugin as WorkflowPlugin<unknown, object>,\n ]);\n\n return factory;\n}\n\nexport const workflow: WorkflowFactory = createWorkflowFactory();\n",
|
|
6
6
|
"import parse from 'parse-duration';\nimport { WorkflowEngineError } from './error';\n\nexport type DurationObject = {\n weeks?: number;\n days?: number;\n hours?: number;\n minutes?: number;\n seconds?: number;\n};\n\nexport type Duration = string | DurationObject;\n\nconst MS_PER_SECOND = 1000;\nconst MS_PER_MINUTE = 60 * MS_PER_SECOND;\nconst MS_PER_HOUR = 60 * MS_PER_MINUTE;\nconst MS_PER_DAY = 24 * MS_PER_HOUR;\nconst MS_PER_WEEK = 7 * MS_PER_DAY;\n\nexport function parseDuration(duration: Duration): number {\n if (typeof duration === 'string') {\n if (duration.trim() === '') {\n throw new WorkflowEngineError('Invalid duration: empty string');\n }\n\n const ms = parse(duration);\n\n if (ms == null || ms <= 0) {\n throw new WorkflowEngineError(`Invalid duration: \"${duration}\"`);\n }\n\n return ms;\n }\n\n const { weeks = 0, days = 0, hours = 0, minutes = 0, seconds = 0 } = duration;\n\n const ms =\n weeks * MS_PER_WEEK +\n days * MS_PER_DAY +\n hours * MS_PER_HOUR +\n minutes * MS_PER_MINUTE +\n seconds * MS_PER_SECOND;\n\n if (ms <= 0) {\n throw new WorkflowEngineError('Invalid duration: must be a positive value');\n }\n\n return ms;\n}\n",
|
|
7
7
|
"export class WorkflowEngineError extends Error {\n constructor(\n message: string,\n public readonly workflowId?: string,\n public readonly runId?: string,\n public override readonly cause: Error | undefined = undefined,\n ) {\n super(message);\n this.name = 'WorkflowEngineError';\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, WorkflowEngineError);\n }\n }\n}\n\nexport class WorkflowRunNotFoundError extends WorkflowEngineError {\n constructor(runId?: string, workflowId?: string) {\n super('Workflow run not found', workflowId, runId);\n this.name = 'WorkflowRunNotFoundError';\n }\n}\n",
|
|
8
|
-
"import { merge } from 'es-toolkit';\nimport type { Db, Job, PgBoss } from 'pg-boss';\nimport type { z } from 'zod';\nimport { parseWorkflowHandler } from './ast-parser';\nimport { runMigrations } from './db/migration';\nimport {\n getWorkflowRun,\n getWorkflowRuns,\n insertWorkflowRun,\n updateWorkflowRun,\n withPostgresTransaction,\n} from './db/queries';\nimport type { WorkflowRun } from './db/types';\nimport type { Duration } from './duration';\nimport { parseDuration } from './duration';\nimport { WorkflowEngineError, WorkflowRunNotFoundError } from './error';\nimport {\n type InferInputParameters,\n type InputParameters,\n type StepBaseContext,\n StepType,\n type WorkflowContext,\n type WorkflowDefinition,\n type WorkflowInternalDefinition,\n type WorkflowInternalLogger,\n type WorkflowInternalLoggerContext,\n type WorkflowLogger,\n type WorkflowRunProgress,\n WorkflowStatus,\n} from './types';\n\nconst PAUSE_EVENT_NAME = '__internal_pause';\nconst WORKFLOW_RUN_QUEUE_NAME = 'workflow-run';\nconst LOG_PREFIX = '[WorkflowEngine]';\n\nconst StepTypeToIcon = {\n [StepType.RUN]: 'λ',\n [StepType.WAIT_FOR]: '○',\n [StepType.PAUSE]: '⏸',\n [StepType.WAIT_UNTIL]: '⏲',\n [StepType.DELAY]: '⏱',\n [StepType.POLL]: '↻',\n};\n\n// Timeline entry types\ntype TimelineStepEntry = {\n output?: unknown;\n timedOut?: true;\n timestamp: Date;\n};\n\ntype TimelineWaitForEntry = {\n waitFor: {\n eventName?: string;\n timeoutEvent?: string;\n skipOutput?: true;\n };\n timestamp: Date;\n};\n\ntype WorkflowRunJobParameters = {\n runId: string;\n resourceId?: string;\n workflowId: string;\n input: unknown;\n event?: {\n name: string;\n data?: Record<string, unknown>;\n };\n};\n\nconst defaultLogger: WorkflowLogger = {\n log: (_message: string) => console.warn(_message),\n error: (message: string, error: Error) => console.error(message, error),\n};\n\nconst defaultExpireInSeconds = process.env.WORKFLOW_RUN_EXPIRE_IN_SECONDS\n ? Number.parseInt(process.env.WORKFLOW_RUN_EXPIRE_IN_SECONDS, 10)\n : 5 * 60; // 5 minutes\n\nexport class WorkflowEngine {\n private boss: PgBoss;\n private db: Db;\n private unregisteredWorkflows = new Map<string, WorkflowDefinition>();\n private _started = false;\n\n public workflows: Map<string, WorkflowInternalDefinition> = new Map<\n string,\n WorkflowInternalDefinition\n >();\n private logger: WorkflowInternalLogger;\n\n constructor({\n workflows,\n logger,\n boss,\n }: Partial<{\n workflows: WorkflowDefinition[];\n logger: WorkflowLogger;\n boss: PgBoss;\n }> = {}) {\n this.logger = this.buildLogger(logger ?? defaultLogger);\n\n if (workflows) {\n this.unregisteredWorkflows = new Map(workflows.map((workflow) => [workflow.id, workflow]));\n }\n\n if (!boss) {\n throw new WorkflowEngineError('PgBoss instance is required in constructor');\n }\n this.boss = boss;\n this.db = boss.getDb();\n }\n\n async start(\n asEngine = true,\n { batchSize }: { batchSize?: number } = { batchSize: 1 },\n ): Promise<void> {\n if (this._started) {\n return;\n }\n\n // Start boss first to get the database connection\n await this.boss.start();\n\n await runMigrations(this.boss.getDb());\n\n if (this.unregisteredWorkflows.size > 0) {\n for (const workflow of this.unregisteredWorkflows.values()) {\n await this.registerWorkflow(workflow);\n }\n }\n\n await this.boss.createQueue(WORKFLOW_RUN_QUEUE_NAME);\n\n const numWorkers: number = +(process.env.WORKFLOW_RUN_WORKERS ?? 3);\n\n if (asEngine) {\n for (let i = 0; i < numWorkers; i++) {\n await this.boss.work<WorkflowRunJobParameters>(\n WORKFLOW_RUN_QUEUE_NAME,\n { pollingIntervalSeconds: 0.5, batchSize },\n (job) => this.handleWorkflowRun(job),\n );\n this.logger.log(\n `Worker ${i + 1}/${numWorkers} started for queue ${WORKFLOW_RUN_QUEUE_NAME}`,\n );\n }\n }\n\n this._started = true;\n\n this.logger.log('Workflow engine started!');\n }\n\n async stop(): Promise<void> {\n await this.boss.stop();\n\n this._started = false;\n\n this.logger.log('Workflow engine stopped');\n }\n\n async registerWorkflow<TStep extends StepBaseContext>(\n definition: WorkflowDefinition<InputParameters, TStep>,\n ): Promise<WorkflowEngine> {\n if (this.workflows.has(definition.id)) {\n throw new WorkflowEngineError(\n `Workflow ${definition.id} is already registered`,\n definition.id,\n );\n }\n\n const { steps } = parseWorkflowHandler(\n definition.handler as (context: WorkflowContext) => Promise<unknown>,\n );\n\n this.workflows.set(definition.id, {\n ...definition,\n steps,\n } as WorkflowInternalDefinition);\n\n this.logger.log(`Registered workflow \"${definition.id}\" with steps:`);\n for (const step of steps.values()) {\n const tags = [];\n if (step.conditional) tags.push('[conditional]');\n if (step.loop) tags.push('[loop]');\n if (step.isDynamic) tags.push('[dynamic]');\n this.logger.log(` └─ (${StepTypeToIcon[step.type]}) ${step.id} ${tags.join(' ')}`);\n }\n\n return this;\n }\n\n async unregisterWorkflow(workflowId: string): Promise<WorkflowEngine> {\n this.workflows.delete(workflowId);\n return this;\n }\n\n async unregisterAllWorkflows(): Promise<WorkflowEngine> {\n this.workflows.clear();\n return this;\n }\n\n async startWorkflow({\n resourceId,\n workflowId,\n input,\n options,\n }: {\n resourceId?: string;\n workflowId: string;\n input: unknown;\n options?: {\n timeout?: number;\n retries?: number;\n expireInSeconds?: number;\n batchSize?: number;\n };\n }): Promise<WorkflowRun> {\n if (!this._started) {\n await this.start(false, { batchSize: options?.batchSize ?? 1 });\n }\n\n const workflow = this.workflows.get(workflowId);\n if (!workflow) {\n throw new WorkflowEngineError(`Unknown workflow ${workflowId}`);\n }\n\n const hasSteps = workflow.steps.length > 0 && workflow.steps[0];\n const hasPlugins = (workflow.plugins?.length ?? 0) > 0;\n if (!hasSteps && !hasPlugins) {\n throw new WorkflowEngineError(`Workflow ${workflowId} has no steps`, workflowId);\n }\n if (workflow.inputSchema) {\n const result = workflow.inputSchema.safeParse(input);\n if (!result.success) {\n throw new WorkflowEngineError(result.error.message, workflowId);\n }\n }\n\n const initialStepId = workflow.steps[0]?.id ?? '__start__';\n\n const run = await withPostgresTransaction(this.boss.getDb(), async (_db) => {\n const timeoutAt = options?.timeout\n ? new Date(Date.now() + options.timeout)\n : workflow.timeout\n ? new Date(Date.now() + workflow.timeout)\n : null;\n\n const insertedRun = await insertWorkflowRun(\n {\n resourceId,\n workflowId,\n currentStepId: initialStepId,\n status: WorkflowStatus.RUNNING,\n input,\n maxRetries: options?.retries ?? workflow.retries ?? 0,\n timeoutAt,\n },\n this.boss.getDb(),\n );\n\n const job: WorkflowRunJobParameters = {\n runId: insertedRun.id,\n resourceId,\n workflowId,\n input,\n };\n\n await this.boss.send(WORKFLOW_RUN_QUEUE_NAME, job, {\n startAfter: new Date(),\n expireInSeconds: options?.expireInSeconds ?? defaultExpireInSeconds,\n });\n\n return insertedRun;\n });\n\n this.logger.log('Started workflow run', {\n runId: run.id,\n workflowId,\n });\n\n return run;\n }\n\n async pauseWorkflow({\n runId,\n resourceId,\n }: {\n runId: string;\n resourceId?: string;\n }): Promise<WorkflowRun> {\n await this.checkIfHasStarted();\n\n // TODO: Pause all running steps immediately\n const run = await this.updateRun({\n runId,\n resourceId,\n data: {\n status: WorkflowStatus.PAUSED,\n pausedAt: new Date(),\n },\n });\n\n this.logger.log('Paused workflow run', {\n runId,\n workflowId: run.workflowId,\n });\n\n return run;\n }\n\n async resumeWorkflow({\n runId,\n resourceId,\n options,\n }: {\n runId: string;\n resourceId?: string;\n options?: { expireInSeconds?: number };\n }): Promise<WorkflowRun> {\n await this.checkIfHasStarted();\n\n return this.triggerEvent({\n runId,\n resourceId,\n eventName: PAUSE_EVENT_NAME,\n data: {},\n options,\n });\n }\n\n async cancelWorkflow({\n runId,\n resourceId,\n }: {\n runId: string;\n resourceId?: string;\n }): Promise<WorkflowRun> {\n await this.checkIfHasStarted();\n\n const run = await this.updateRun({\n runId,\n resourceId,\n data: {\n status: WorkflowStatus.CANCELLED,\n },\n });\n\n this.logger.log(`cancelled workflow run with id ${runId}`);\n\n return run;\n }\n\n async triggerEvent({\n runId,\n resourceId,\n eventName,\n data,\n options,\n }: {\n runId: string;\n resourceId?: string;\n eventName: string;\n data?: Record<string, unknown>;\n options?: {\n expireInSeconds?: number;\n };\n }): Promise<WorkflowRun> {\n await this.checkIfHasStarted();\n\n const run = await this.getRun({ runId, resourceId });\n\n const job: WorkflowRunJobParameters = {\n runId: run.id,\n resourceId,\n workflowId: run.workflowId,\n input: run.input,\n event: {\n name: eventName,\n data,\n },\n };\n\n this.boss.send(WORKFLOW_RUN_QUEUE_NAME, job, {\n expireInSeconds: options?.expireInSeconds ?? defaultExpireInSeconds,\n });\n\n this.logger.log(`event ${eventName} sent for workflow run with id ${runId}`);\n return run;\n }\n\n async getRun(\n { runId, resourceId }: { runId: string; resourceId?: string },\n { exclusiveLock = false, db }: { exclusiveLock?: boolean; db?: Db } = {},\n ): Promise<WorkflowRun> {\n const run = await getWorkflowRun({ runId, resourceId }, { exclusiveLock, db: db ?? this.db });\n\n if (!run) {\n throw new WorkflowRunNotFoundError(runId);\n }\n\n return run;\n }\n\n async updateRun(\n {\n runId,\n resourceId,\n data,\n }: {\n runId: string;\n resourceId?: string;\n data: Partial<WorkflowRun>;\n },\n { db }: { db?: Db } = {},\n ): Promise<WorkflowRun> {\n const run = await updateWorkflowRun({ runId, resourceId, data }, db ?? this.db);\n\n if (!run) {\n throw new WorkflowRunNotFoundError(runId);\n }\n\n return run;\n }\n\n async checkProgress({\n runId,\n resourceId,\n }: {\n runId: string;\n resourceId?: string;\n }): Promise<WorkflowRunProgress> {\n const run = await this.getRun({ runId, resourceId });\n const workflow = this.workflows.get(run.workflowId);\n\n if (!workflow) {\n throw new WorkflowEngineError(`Workflow ${run.workflowId} not found`, run.workflowId, runId);\n }\n const steps = workflow?.steps ?? [];\n\n let completionPercentage = 0;\n let completedSteps = 0;\n\n if (steps.length > 0) {\n completedSteps = Object.values(run.timeline).filter(\n (step): step is TimelineStepEntry =>\n typeof step === 'object' &&\n step !== null &&\n 'output' in step &&\n step.output !== undefined,\n ).length;\n\n if (run.status === WorkflowStatus.COMPLETED) {\n completionPercentage = 100;\n } else if (run.status === WorkflowStatus.FAILED || run.status === WorkflowStatus.CANCELLED) {\n completionPercentage = Math.min((completedSteps / steps.length) * 100, 100);\n } else {\n const currentStepIndex = steps.findIndex((step) => step.id === run.currentStepId);\n if (currentStepIndex >= 0) {\n completionPercentage = (currentStepIndex / steps.length) * 100;\n } else {\n const completedSteps = Object.keys(run.timeline).length;\n\n completionPercentage = Math.min((completedSteps / steps.length) * 100, 100);\n }\n }\n }\n\n return {\n ...run,\n completedSteps,\n completionPercentage: Math.round(completionPercentage * 100) / 100, // Round to 2 decimal places\n totalSteps: steps.length,\n };\n }\n\n private async handleWorkflowRun([job]: Job<WorkflowRunJobParameters>[]) {\n const { runId, resourceId, workflowId, input, event } = job?.data ?? {};\n\n if (!runId) {\n throw new WorkflowEngineError('Invalid workflow run job, missing runId', workflowId);\n }\n\n if (!resourceId) {\n throw new WorkflowEngineError('Invalid workflow run job, missing resourceId', workflowId);\n }\n\n if (!workflowId) {\n throw new WorkflowEngineError(\n 'Invalid workflow run job, missing workflowId',\n undefined,\n runId,\n );\n }\n\n const workflow = this.workflows.get(workflowId);\n if (!workflow) {\n throw new WorkflowEngineError(`Workflow ${workflowId} not found`, workflowId, runId);\n }\n\n this.logger.log('Processing workflow run...', {\n runId,\n workflowId,\n });\n\n let run = await this.getRun({ runId, resourceId });\n\n try {\n if (run.status === WorkflowStatus.CANCELLED) {\n this.logger.log(`Workflow run ${runId} is cancelled, skipping`);\n return;\n }\n\n if (!run.currentStepId) {\n throw new WorkflowEngineError('Missing current step id', workflowId, runId);\n }\n\n if (run.status === WorkflowStatus.PAUSED) {\n const waitForStepEntry = run.timeline[`${run.currentStepId}-wait-for`];\n const waitForStep =\n waitForStepEntry && typeof waitForStepEntry === 'object' && 'waitFor' in waitForStepEntry\n ? (waitForStepEntry as TimelineWaitForEntry)\n : null;\n const currentStep = this.getCachedStepEntry(run.timeline, run.currentStepId);\n const waitFor = waitForStep?.waitFor;\n const hasCurrentStepOutput = currentStep?.output !== undefined;\n\n const eventMatches =\n waitFor &&\n event?.name &&\n (event.name === waitFor.eventName || event.name === waitFor.timeoutEvent) &&\n !hasCurrentStepOutput;\n\n if (eventMatches) {\n const isTimeout = event?.name === waitFor?.timeoutEvent;\n const skipOutput = waitFor?.skipOutput;\n run = await this.updateRun({\n runId,\n resourceId,\n data: {\n status: WorkflowStatus.RUNNING,\n pausedAt: null,\n resumedAt: new Date(),\n jobId: job?.id,\n ...(skipOutput\n ? {}\n : {\n timeline: merge(run.timeline, {\n [run.currentStepId]: {\n output: event?.data ?? {},\n ...(isTimeout ? { timedOut: true as const } : {}),\n timestamp: new Date(),\n },\n }),\n }),\n },\n });\n } else {\n run = await this.updateRun({\n runId,\n resourceId,\n data: {\n status: WorkflowStatus.RUNNING,\n pausedAt: null,\n resumedAt: new Date(),\n jobId: job?.id,\n },\n });\n }\n }\n\n const baseStep = {\n run: async <T>(stepId: string, handler: () => Promise<T>) => {\n if (!run) {\n throw new WorkflowEngineError('Missing workflow run', workflowId, runId);\n }\n return this.runStep({ stepId, run, handler }) as Promise<T>;\n },\n waitFor: async <T extends InputParameters>(\n stepId: string,\n { eventName, timeout }: { eventName: string; timeout?: number; schema?: T },\n ) => {\n if (!run) {\n throw new WorkflowEngineError('Missing workflow run', workflowId, runId);\n }\n const timeoutDate = timeout ? new Date(Date.now() + timeout) : undefined;\n return this.waitStep({ run, stepId, eventName, timeoutDate }) as Promise<\n InferInputParameters<T> | undefined\n >;\n },\n waitUntil: async (\n stepId: string,\n dateOrOptions: Date | string | { date: Date | string },\n ) => {\n if (!run) {\n throw new WorkflowEngineError('Missing workflow run', workflowId, runId);\n }\n const date =\n dateOrOptions instanceof Date\n ? dateOrOptions\n : typeof dateOrOptions === 'string'\n ? new Date(dateOrOptions)\n : dateOrOptions.date instanceof Date\n ? dateOrOptions.date\n : new Date(dateOrOptions.date);\n await this.waitStep({ run, stepId, timeoutDate: date });\n },\n pause: async (stepId: string) => {\n if (!run) {\n throw new WorkflowEngineError('Missing workflow run', workflowId, runId);\n }\n await this.waitStep({ run, stepId, eventName: PAUSE_EVENT_NAME });\n },\n delay: async (stepId: string, duration: Duration) => {\n if (!run) {\n throw new WorkflowEngineError('Missing workflow run', workflowId, runId);\n }\n await this.waitStep({\n run,\n stepId,\n timeoutDate: new Date(Date.now() + parseDuration(duration)),\n });\n },\n get sleep() {\n return this.delay;\n },\n poll: async <T>(\n stepId: string,\n conditionFn: () => Promise<T | false>,\n options?: { interval?: Duration; timeout?: Duration },\n ) => {\n if (!run) {\n throw new WorkflowEngineError('Missing workflow run', workflowId, runId);\n }\n const intervalMs = parseDuration(options?.interval ?? '30s');\n if (intervalMs < 30_000) {\n throw new WorkflowEngineError(\n `step.poll interval must be at least 30s (got ${intervalMs}ms)`,\n workflowId,\n runId,\n );\n }\n const timeoutMs = options?.timeout ? parseDuration(options.timeout) : undefined;\n return this.pollStep({ run, stepId, conditionFn, intervalMs, timeoutMs }) as Promise<\n { timedOut: false; data: T } | { timedOut: true }\n >;\n },\n };\n\n let step = { ...baseStep };\n const plugins = workflow.plugins ?? [];\n for (const plugin of plugins) {\n const extra = plugin.methods(step);\n step = { ...step, ...extra };\n }\n\n const context: WorkflowContext = {\n input: run.input as z.ZodTypeAny,\n workflowId: run.workflowId,\n runId: run.id,\n timeline: run.timeline,\n logger: this.logger,\n step,\n };\n\n const result = await workflow.handler(context);\n\n run = await this.getRun({ runId, resourceId });\n\n const isLastParsedStep = run.currentStepId === workflow.steps[workflow.steps.length - 1]?.id;\n const hasPluginSteps = (workflow.plugins?.length ?? 0) > 0;\n const noParsedSteps = workflow.steps.length === 0;\n const shouldComplete =\n run.status === WorkflowStatus.RUNNING &&\n (noParsedSteps || isLastParsedStep || (hasPluginSteps && result !== undefined));\n if (shouldComplete) {\n const normalizedResult = result === undefined ? {} : result;\n await this.updateRun({\n runId,\n resourceId,\n data: {\n status: WorkflowStatus.COMPLETED,\n output: normalizedResult,\n completedAt: new Date(),\n jobId: job?.id,\n },\n });\n\n this.logger.log('Workflow run completed.', {\n runId,\n workflowId,\n });\n }\n } catch (error) {\n if (run.retryCount < run.maxRetries) {\n await this.updateRun({\n runId,\n resourceId,\n data: {\n retryCount: run.retryCount + 1,\n jobId: job?.id,\n },\n });\n\n const retryDelay = 2 ** run.retryCount * 1000;\n\n // NOTE: Do not use pg-boss retryLimit and retryBackoff so that we can fully control the retry logic from the WorkflowEngine and not PGBoss.\n const pgBossJob: WorkflowRunJobParameters = {\n runId,\n resourceId,\n workflowId,\n input,\n };\n await this.boss?.send('workflow-run', pgBossJob, {\n startAfter: new Date(Date.now() + retryDelay),\n expireInSeconds: defaultExpireInSeconds,\n });\n\n return;\n }\n\n // TODO: Ensure that this code always runs, even if worker is stopped unexpectedly.\n await this.updateRun({\n runId,\n resourceId,\n data: {\n status: WorkflowStatus.FAILED,\n error: error instanceof Error ? error.message : String(error),\n jobId: job?.id,\n },\n });\n\n throw error;\n }\n }\n\n private getCachedStepEntry(\n timeline: Record<string, unknown>,\n stepId: string,\n ): TimelineStepEntry | null {\n const stepEntry = timeline[stepId];\n return stepEntry && typeof stepEntry === 'object' && 'output' in stepEntry\n ? (stepEntry as TimelineStepEntry)\n : null;\n }\n\n private async runStep({\n stepId,\n run,\n handler,\n }: {\n stepId: string;\n run: WorkflowRun;\n handler: () => Promise<unknown>;\n }) {\n return withPostgresTransaction(this.db, async (db) => {\n const persistedRun = await this.getRun(\n { runId: run.id, resourceId: run.resourceId ?? undefined },\n {\n exclusiveLock: true,\n db,\n },\n );\n\n if (\n persistedRun.status === WorkflowStatus.CANCELLED ||\n persistedRun.status === WorkflowStatus.PAUSED ||\n persistedRun.status === WorkflowStatus.FAILED\n ) {\n this.logger.log(`Step ${stepId} skipped, workflow run is ${persistedRun.status}`, {\n runId: run.id,\n workflowId: run.workflowId,\n });\n\n return;\n }\n\n try {\n const cached = this.getCachedStepEntry(persistedRun.timeline, stepId);\n if (cached?.output !== undefined) {\n return cached.output;\n }\n\n await this.updateRun(\n {\n runId: run.id,\n resourceId: run.resourceId ?? undefined,\n data: {\n currentStepId: stepId,\n },\n },\n { db },\n );\n\n this.logger.log(`Running step ${stepId}...`, {\n runId: run.id,\n workflowId: run.workflowId,\n });\n\n let output = await handler();\n\n if (output === undefined) {\n output = {};\n }\n\n run = await this.updateRun(\n {\n runId: run.id,\n resourceId: run.resourceId ?? undefined,\n data: {\n timeline: merge(run.timeline, {\n [stepId]: {\n output,\n timestamp: new Date(),\n },\n }),\n },\n },\n { db },\n );\n\n return output;\n } catch (error) {\n this.logger.error(`Step ${stepId} failed:`, error as Error, {\n runId: run.id,\n workflowId: run.workflowId,\n });\n\n await this.updateRun(\n {\n runId: run.id,\n resourceId: run.resourceId ?? undefined,\n data: {\n status: WorkflowStatus.FAILED,\n error: error instanceof Error ? `${error.message}\\n${error.stack}` : String(error),\n },\n },\n { db },\n );\n\n throw error;\n }\n });\n }\n\n private async waitStep({\n run,\n stepId,\n eventName,\n timeoutDate,\n }: {\n run: WorkflowRun;\n stepId: string;\n eventName?: string;\n timeoutDate?: Date;\n }): Promise<unknown> {\n const persistedRun = await this.getRun({\n runId: run.id,\n resourceId: run.resourceId ?? undefined,\n });\n\n if (\n persistedRun.status === WorkflowStatus.CANCELLED ||\n persistedRun.status === WorkflowStatus.PAUSED ||\n persistedRun.status === WorkflowStatus.FAILED\n ) {\n return;\n }\n\n const cached = this.getCachedStepEntry(persistedRun.timeline, stepId);\n if (cached?.output !== undefined) {\n return cached.timedOut ? undefined : cached.output;\n }\n\n const timeoutEvent = timeoutDate ? `__timeout_${stepId}` : undefined;\n\n await this.updateRun({\n runId: run.id,\n resourceId: run.resourceId ?? undefined,\n data: {\n status: WorkflowStatus.PAUSED,\n currentStepId: stepId,\n pausedAt: new Date(),\n timeline: merge(run.timeline, {\n [`${stepId}-wait-for`]: {\n waitFor: { eventName, timeoutEvent },\n timestamp: new Date(),\n },\n }),\n },\n });\n\n if (timeoutDate && timeoutEvent) {\n const job: WorkflowRunJobParameters = {\n runId: run.id,\n resourceId: run.resourceId ?? undefined,\n workflowId: run.workflowId,\n input: run.input,\n event: { name: timeoutEvent, data: { date: timeoutDate.toISOString() } },\n };\n await this.boss.send(WORKFLOW_RUN_QUEUE_NAME, job, {\n startAfter: timeoutDate.getTime() <= Date.now() ? new Date() : timeoutDate,\n expireInSeconds: defaultExpireInSeconds,\n });\n }\n\n this.logger.log(\n `Step ${stepId} waiting${eventName ? ` for event \"${eventName}\"` : ''}${timeoutDate ? ` until ${timeoutDate.toISOString()}` : ''}`,\n { runId: run.id, workflowId: run.workflowId },\n );\n }\n\n private async pollStep<T>({\n run,\n stepId,\n conditionFn,\n intervalMs,\n timeoutMs,\n }: {\n run: WorkflowRun;\n stepId: string;\n conditionFn: () => Promise<T | false>;\n intervalMs: number;\n timeoutMs?: number;\n }): Promise<{ timedOut: false; data: T } | { timedOut: true } | undefined> {\n const persistedRun = await this.getRun({\n runId: run.id,\n resourceId: run.resourceId ?? undefined,\n });\n\n if (\n persistedRun.status === WorkflowStatus.CANCELLED ||\n persistedRun.status === WorkflowStatus.PAUSED ||\n persistedRun.status === WorkflowStatus.FAILED\n ) {\n return { timedOut: true };\n }\n\n const cached = this.getCachedStepEntry(persistedRun.timeline, stepId);\n if (cached?.output !== undefined) {\n return cached.timedOut ? { timedOut: true } : { timedOut: false, data: cached.output as T };\n }\n\n const pollStateEntry = persistedRun.timeline[`${stepId}-poll`];\n const startedAt =\n pollStateEntry && typeof pollStateEntry === 'object' && 'startedAt' in pollStateEntry\n ? new Date((pollStateEntry as { startedAt: string }).startedAt)\n : new Date();\n\n if (timeoutMs !== undefined && Date.now() >= startedAt.getTime() + timeoutMs) {\n await this.updateRun({\n runId: run.id,\n resourceId: run.resourceId ?? undefined,\n data: {\n currentStepId: stepId,\n timeline: merge(persistedRun.timeline, {\n [stepId]: { output: {}, timedOut: true as const, timestamp: new Date() },\n }),\n },\n });\n return { timedOut: true };\n }\n\n const result = await conditionFn();\n\n if (result !== false) {\n await this.updateRun({\n runId: run.id,\n resourceId: run.resourceId ?? undefined,\n data: {\n currentStepId: stepId,\n timeline: merge(persistedRun.timeline, {\n [stepId]: { output: result, timestamp: new Date() },\n }),\n },\n });\n return { timedOut: false, data: result };\n }\n\n const pollEvent = `__poll_${stepId}`;\n await this.updateRun({\n runId: run.id,\n resourceId: run.resourceId ?? undefined,\n data: {\n status: WorkflowStatus.PAUSED,\n currentStepId: stepId,\n pausedAt: new Date(),\n timeline: merge(persistedRun.timeline, {\n [`${stepId}-poll`]: { startedAt: startedAt.toISOString() },\n [`${stepId}-wait-for`]: {\n waitFor: { timeoutEvent: pollEvent, skipOutput: true },\n timestamp: new Date(),\n },\n }),\n },\n });\n\n await this.boss.send(\n WORKFLOW_RUN_QUEUE_NAME,\n {\n runId: run.id,\n resourceId: run.resourceId ?? undefined,\n workflowId: run.workflowId,\n input: run.input,\n event: { name: pollEvent, data: {} },\n },\n {\n startAfter: new Date(Date.now() + intervalMs),\n expireInSeconds: defaultExpireInSeconds,\n },\n );\n\n this.logger.log(`Step ${stepId} polling every ${intervalMs}ms...`, {\n runId: run.id,\n workflowId: run.workflowId,\n });\n\n return { timedOut: false, data: undefined as T };\n }\n\n private async checkIfHasStarted(): Promise<void> {\n if (!this._started) {\n throw new WorkflowEngineError('Workflow engine not started');\n }\n }\n\n private buildLogger(logger: WorkflowLogger): WorkflowInternalLogger {\n return {\n log: (message: string, context?: WorkflowInternalLoggerContext) => {\n const { runId, workflowId } = context ?? {};\n const parts = [LOG_PREFIX, workflowId, runId].filter(Boolean).join(' ');\n logger.log(`${parts}: ${message}`);\n },\n error: (message: string, error: Error, context?: WorkflowInternalLoggerContext) => {\n const { runId, workflowId } = context ?? {};\n const parts = [LOG_PREFIX, workflowId, runId].filter(Boolean).join(' ');\n logger.error(`${parts}: ${message}`, error);\n },\n };\n }\n\n async getRuns({\n resourceId,\n startingAfter,\n endingBefore,\n limit = 20,\n statuses,\n workflowId,\n }: {\n resourceId?: string;\n startingAfter?: string | null;\n endingBefore?: string | null;\n limit?: number;\n statuses?: WorkflowStatus[];\n workflowId?: string;\n }): Promise<{\n items: WorkflowRun[];\n nextCursor: string | null;\n prevCursor: string | null;\n hasMore: boolean;\n hasPrev: boolean;\n }> {\n return getWorkflowRuns(\n {\n resourceId,\n startingAfter,\n endingBefore,\n limit,\n statuses,\n workflowId,\n },\n this.db,\n );\n }\n}\n",
|
|
8
|
+
"import { merge } from 'es-toolkit';\nimport pg from 'pg';\nimport { type Db, type Job, PgBoss } from 'pg-boss';\nimport type { z } from 'zod';\nimport { parseWorkflowHandler } from './ast-parser';\nimport { runMigrations } from './db/migration';\nimport {\n getWorkflowRun,\n getWorkflowRuns,\n insertWorkflowRun,\n updateWorkflowRun,\n withPostgresTransaction,\n} from './db/queries';\nimport type { WorkflowRun } from './db/types';\nimport type { Duration } from './duration';\nimport { parseDuration } from './duration';\nimport { WorkflowEngineError, WorkflowRunNotFoundError } from './error';\nimport {\n type InferInputParameters,\n type InputParameters,\n type StepBaseContext,\n StepType,\n type WorkflowContext,\n type WorkflowDefinition,\n type WorkflowInternalDefinition,\n type WorkflowInternalLogger,\n type WorkflowInternalLoggerContext,\n type WorkflowLogger,\n type WorkflowRunProgress,\n WorkflowStatus,\n} from './types';\n\nconst PAUSE_EVENT_NAME = '__internal_pause';\nconst WORKFLOW_RUN_QUEUE_NAME = 'workflow-run';\nconst LOG_PREFIX = '[WorkflowEngine]';\nconst DEFAULT_PGBOSS_SCHEMA = 'pgboss_v12_pgworkflow';\n\nexport type WorkflowEngineOptions = {\n workflows?: WorkflowDefinition[];\n logger?: WorkflowLogger;\n boss?: PgBoss;\n} & ({ pool: pg.Pool; connectionString?: never } | { connectionString: string; pool?: never });\n\nconst StepTypeToIcon = {\n [StepType.RUN]: 'λ',\n [StepType.WAIT_FOR]: '○',\n [StepType.PAUSE]: '⏸',\n [StepType.WAIT_UNTIL]: '⏲',\n [StepType.DELAY]: '⏱',\n [StepType.POLL]: '↻',\n};\n\n// Timeline entry types\ntype TimelineStepEntry = {\n output?: unknown;\n timedOut?: true;\n timestamp: Date;\n};\n\ntype TimelineWaitForEntry = {\n waitFor: {\n eventName?: string;\n timeoutEvent?: string;\n skipOutput?: true;\n };\n timestamp: Date;\n};\n\ntype WorkflowRunJobParameters = {\n runId: string;\n resourceId?: string;\n workflowId: string;\n input: unknown;\n event?: {\n name: string;\n data?: Record<string, unknown>;\n };\n};\n\nconst defaultLogger: WorkflowLogger = {\n log: (_message: string) => console.warn(_message),\n error: (message: string, error: Error) => console.error(message, error),\n};\n\nconst defaultExpireInSeconds = process.env.WORKFLOW_RUN_EXPIRE_IN_SECONDS\n ? Number.parseInt(process.env.WORKFLOW_RUN_EXPIRE_IN_SECONDS, 10)\n : 5 * 60; // 5 minutes\n\nexport class WorkflowEngine {\n private boss: PgBoss;\n private db: Db;\n private pool: pg.Pool;\n private _ownsPool = false;\n private unregisteredWorkflows = new Map<string, WorkflowDefinition>();\n private _started = false;\n\n public workflows: Map<string, WorkflowInternalDefinition> = new Map<\n string,\n WorkflowInternalDefinition\n >();\n private logger: WorkflowInternalLogger;\n\n constructor({ workflows, logger, boss, ...connectionOptions }: WorkflowEngineOptions) {\n this.logger = this.buildLogger(logger ?? defaultLogger);\n\n if ('pool' in connectionOptions && connectionOptions.pool) {\n this.pool = connectionOptions.pool;\n } else if ('connectionString' in connectionOptions && connectionOptions.connectionString) {\n this.pool = new pg.Pool({ connectionString: connectionOptions.connectionString });\n this._ownsPool = true;\n } else {\n throw new WorkflowEngineError('Either pool or connectionString must be provided');\n }\n\n if (workflows) {\n this.unregisteredWorkflows = new Map(workflows.map((workflow) => [workflow.id, workflow]));\n }\n\n const db: Db = {\n executeSql: (text: string, values?: unknown[]) =>\n this.pool.query(text, values) as Promise<{ rows: unknown[] }>,\n };\n\n if (boss) {\n this.boss = boss;\n } else {\n this.boss = new PgBoss({ db, schema: DEFAULT_PGBOSS_SCHEMA });\n }\n this.db = this.boss.getDb();\n }\n\n async start(\n asEngine = true,\n { batchSize }: { batchSize?: number } = { batchSize: 1 },\n ): Promise<void> {\n if (this._started) {\n return;\n }\n\n // Start boss first to get the database connection\n await this.boss.start();\n\n await runMigrations(this.boss.getDb());\n\n if (this.unregisteredWorkflows.size > 0) {\n for (const workflow of this.unregisteredWorkflows.values()) {\n await this.registerWorkflow(workflow);\n }\n }\n\n await this.boss.createQueue(WORKFLOW_RUN_QUEUE_NAME);\n\n const numWorkers: number = +(process.env.WORKFLOW_RUN_WORKERS ?? 3);\n\n if (asEngine) {\n for (let i = 0; i < numWorkers; i++) {\n await this.boss.work<WorkflowRunJobParameters>(\n WORKFLOW_RUN_QUEUE_NAME,\n { pollingIntervalSeconds: 0.5, batchSize },\n (job) => this.handleWorkflowRun(job),\n );\n this.logger.log(\n `Worker ${i + 1}/${numWorkers} started for queue ${WORKFLOW_RUN_QUEUE_NAME}`,\n );\n }\n }\n\n this._started = true;\n\n this.logger.log('Workflow engine started!');\n }\n\n async stop(): Promise<void> {\n await this.boss.stop();\n\n if (this._ownsPool) {\n await this.pool.end();\n }\n\n this._started = false;\n\n this.logger.log('Workflow engine stopped');\n }\n\n async registerWorkflow<TStep extends StepBaseContext>(\n definition: WorkflowDefinition<InputParameters, TStep>,\n ): Promise<WorkflowEngine> {\n if (this.workflows.has(definition.id)) {\n throw new WorkflowEngineError(\n `Workflow ${definition.id} is already registered`,\n definition.id,\n );\n }\n\n const { steps } = parseWorkflowHandler(\n definition.handler as (context: WorkflowContext) => Promise<unknown>,\n );\n\n this.workflows.set(definition.id, {\n ...definition,\n steps,\n } as WorkflowInternalDefinition);\n\n this.logger.log(`Registered workflow \"${definition.id}\" with steps:`);\n for (const step of steps.values()) {\n const tags = [];\n if (step.conditional) tags.push('[conditional]');\n if (step.loop) tags.push('[loop]');\n if (step.isDynamic) tags.push('[dynamic]');\n this.logger.log(` └─ (${StepTypeToIcon[step.type]}) ${step.id} ${tags.join(' ')}`);\n }\n\n return this;\n }\n\n async unregisterWorkflow(workflowId: string): Promise<WorkflowEngine> {\n this.workflows.delete(workflowId);\n return this;\n }\n\n async unregisterAllWorkflows(): Promise<WorkflowEngine> {\n this.workflows.clear();\n return this;\n }\n\n async startWorkflow({\n resourceId,\n workflowId,\n input,\n options,\n }: {\n resourceId?: string;\n workflowId: string;\n input: unknown;\n options?: {\n timeout?: number;\n retries?: number;\n expireInSeconds?: number;\n batchSize?: number;\n };\n }): Promise<WorkflowRun> {\n if (!this._started) {\n await this.start(false, { batchSize: options?.batchSize ?? 1 });\n }\n\n const workflow = this.workflows.get(workflowId);\n if (!workflow) {\n throw new WorkflowEngineError(`Unknown workflow ${workflowId}`);\n }\n\n const hasSteps = workflow.steps.length > 0 && workflow.steps[0];\n const hasPlugins = (workflow.plugins?.length ?? 0) > 0;\n if (!hasSteps && !hasPlugins) {\n throw new WorkflowEngineError(`Workflow ${workflowId} has no steps`, workflowId);\n }\n if (workflow.inputSchema) {\n const result = workflow.inputSchema.safeParse(input);\n if (!result.success) {\n throw new WorkflowEngineError(result.error.message, workflowId);\n }\n }\n\n const initialStepId = workflow.steps[0]?.id ?? '__start__';\n\n const run = await withPostgresTransaction(\n this.boss.getDb(),\n async (_db) => {\n const timeoutAt = options?.timeout\n ? new Date(Date.now() + options.timeout)\n : workflow.timeout\n ? new Date(Date.now() + workflow.timeout)\n : null;\n\n const insertedRun = await insertWorkflowRun(\n {\n resourceId,\n workflowId,\n currentStepId: initialStepId,\n status: WorkflowStatus.RUNNING,\n input,\n maxRetries: options?.retries ?? workflow.retries ?? 0,\n timeoutAt,\n },\n _db,\n );\n\n const job: WorkflowRunJobParameters = {\n runId: insertedRun.id,\n resourceId,\n workflowId,\n input,\n };\n\n await this.boss.send(WORKFLOW_RUN_QUEUE_NAME, job, {\n startAfter: new Date(),\n expireInSeconds: options?.expireInSeconds ?? defaultExpireInSeconds,\n });\n\n return insertedRun;\n },\n this.pool,\n );\n\n this.logger.log('Started workflow run', {\n runId: run.id,\n workflowId,\n });\n\n return run;\n }\n\n async pauseWorkflow({\n runId,\n resourceId,\n }: {\n runId: string;\n resourceId?: string;\n }): Promise<WorkflowRun> {\n await this.checkIfHasStarted();\n\n // TODO: Pause all running steps immediately\n const run = await this.updateRun({\n runId,\n resourceId,\n data: {\n status: WorkflowStatus.PAUSED,\n pausedAt: new Date(),\n },\n });\n\n this.logger.log('Paused workflow run', {\n runId,\n workflowId: run.workflowId,\n });\n\n return run;\n }\n\n async resumeWorkflow({\n runId,\n resourceId,\n options,\n }: {\n runId: string;\n resourceId?: string;\n options?: { expireInSeconds?: number };\n }): Promise<WorkflowRun> {\n await this.checkIfHasStarted();\n\n return this.triggerEvent({\n runId,\n resourceId,\n eventName: PAUSE_EVENT_NAME,\n data: {},\n options,\n });\n }\n\n async cancelWorkflow({\n runId,\n resourceId,\n }: {\n runId: string;\n resourceId?: string;\n }): Promise<WorkflowRun> {\n await this.checkIfHasStarted();\n\n const run = await this.updateRun({\n runId,\n resourceId,\n data: {\n status: WorkflowStatus.CANCELLED,\n },\n });\n\n this.logger.log(`cancelled workflow run with id ${runId}`);\n\n return run;\n }\n\n async triggerEvent({\n runId,\n resourceId,\n eventName,\n data,\n options,\n }: {\n runId: string;\n resourceId?: string;\n eventName: string;\n data?: Record<string, unknown>;\n options?: {\n expireInSeconds?: number;\n };\n }): Promise<WorkflowRun> {\n await this.checkIfHasStarted();\n\n const run = await this.getRun({ runId, resourceId });\n\n const job: WorkflowRunJobParameters = {\n runId: run.id,\n resourceId,\n workflowId: run.workflowId,\n input: run.input,\n event: {\n name: eventName,\n data,\n },\n };\n\n this.boss.send(WORKFLOW_RUN_QUEUE_NAME, job, {\n expireInSeconds: options?.expireInSeconds ?? defaultExpireInSeconds,\n });\n\n this.logger.log(`event ${eventName} sent for workflow run with id ${runId}`);\n return run;\n }\n\n async getRun(\n { runId, resourceId }: { runId: string; resourceId?: string },\n { exclusiveLock = false, db }: { exclusiveLock?: boolean; db?: Db } = {},\n ): Promise<WorkflowRun> {\n const run = await getWorkflowRun({ runId, resourceId }, { exclusiveLock, db: db ?? this.db });\n\n if (!run) {\n throw new WorkflowRunNotFoundError(runId);\n }\n\n return run;\n }\n\n async updateRun(\n {\n runId,\n resourceId,\n data,\n }: {\n runId: string;\n resourceId?: string;\n data: Partial<WorkflowRun>;\n },\n { db }: { db?: Db } = {},\n ): Promise<WorkflowRun> {\n const run = await updateWorkflowRun({ runId, resourceId, data }, db ?? this.db);\n\n if (!run) {\n throw new WorkflowRunNotFoundError(runId);\n }\n\n return run;\n }\n\n async checkProgress({\n runId,\n resourceId,\n }: {\n runId: string;\n resourceId?: string;\n }): Promise<WorkflowRunProgress> {\n const run = await this.getRun({ runId, resourceId });\n const workflow = this.workflows.get(run.workflowId);\n\n if (!workflow) {\n throw new WorkflowEngineError(`Workflow ${run.workflowId} not found`, run.workflowId, runId);\n }\n const steps = workflow?.steps ?? [];\n\n let completionPercentage = 0;\n let completedSteps = 0;\n\n if (steps.length > 0) {\n completedSteps = Object.values(run.timeline).filter(\n (step): step is TimelineStepEntry =>\n typeof step === 'object' &&\n step !== null &&\n 'output' in step &&\n step.output !== undefined,\n ).length;\n\n if (run.status === WorkflowStatus.COMPLETED) {\n completionPercentage = 100;\n } else if (run.status === WorkflowStatus.FAILED || run.status === WorkflowStatus.CANCELLED) {\n completionPercentage = Math.min((completedSteps / steps.length) * 100, 100);\n } else {\n const currentStepIndex = steps.findIndex((step) => step.id === run.currentStepId);\n if (currentStepIndex >= 0) {\n completionPercentage = (currentStepIndex / steps.length) * 100;\n } else {\n const completedSteps = Object.keys(run.timeline).length;\n\n completionPercentage = Math.min((completedSteps / steps.length) * 100, 100);\n }\n }\n }\n\n return {\n ...run,\n completedSteps,\n completionPercentage: Math.round(completionPercentage * 100) / 100, // Round to 2 decimal places\n totalSteps: steps.length,\n };\n }\n\n private async handleWorkflowRun([job]: Job<WorkflowRunJobParameters>[]) {\n const { runId, resourceId, workflowId, input, event } = job?.data ?? {};\n\n if (!runId) {\n throw new WorkflowEngineError('Invalid workflow run job, missing runId', workflowId);\n }\n\n if (!resourceId) {\n throw new WorkflowEngineError('Invalid workflow run job, missing resourceId', workflowId);\n }\n\n if (!workflowId) {\n throw new WorkflowEngineError(\n 'Invalid workflow run job, missing workflowId',\n undefined,\n runId,\n );\n }\n\n const workflow = this.workflows.get(workflowId);\n if (!workflow) {\n throw new WorkflowEngineError(`Workflow ${workflowId} not found`, workflowId, runId);\n }\n\n this.logger.log('Processing workflow run...', {\n runId,\n workflowId,\n });\n\n let run = await this.getRun({ runId, resourceId });\n\n try {\n if (run.status === WorkflowStatus.CANCELLED) {\n this.logger.log(`Workflow run ${runId} is cancelled, skipping`);\n return;\n }\n\n if (!run.currentStepId) {\n throw new WorkflowEngineError('Missing current step id', workflowId, runId);\n }\n\n if (run.status === WorkflowStatus.PAUSED) {\n const waitForStepEntry = run.timeline[`${run.currentStepId}-wait-for`];\n const waitForStep =\n waitForStepEntry && typeof waitForStepEntry === 'object' && 'waitFor' in waitForStepEntry\n ? (waitForStepEntry as TimelineWaitForEntry)\n : null;\n const currentStep = this.getCachedStepEntry(run.timeline, run.currentStepId);\n const waitFor = waitForStep?.waitFor;\n const hasCurrentStepOutput = currentStep?.output !== undefined;\n\n const eventMatches =\n waitFor &&\n event?.name &&\n (event.name === waitFor.eventName || event.name === waitFor.timeoutEvent) &&\n !hasCurrentStepOutput;\n\n if (eventMatches) {\n const isTimeout = event?.name === waitFor?.timeoutEvent;\n const skipOutput = waitFor?.skipOutput;\n run = await this.updateRun({\n runId,\n resourceId,\n data: {\n status: WorkflowStatus.RUNNING,\n pausedAt: null,\n resumedAt: new Date(),\n jobId: job?.id,\n ...(skipOutput\n ? {}\n : {\n timeline: merge(run.timeline, {\n [run.currentStepId]: {\n output: event?.data ?? {},\n ...(isTimeout ? { timedOut: true as const } : {}),\n timestamp: new Date(),\n },\n }),\n }),\n },\n });\n } else {\n run = await this.updateRun({\n runId,\n resourceId,\n data: {\n status: WorkflowStatus.RUNNING,\n pausedAt: null,\n resumedAt: new Date(),\n jobId: job?.id,\n },\n });\n }\n }\n\n const baseStep = {\n run: async <T>(stepId: string, handler: () => Promise<T>) => {\n if (!run) {\n throw new WorkflowEngineError('Missing workflow run', workflowId, runId);\n }\n return this.runStep({ stepId, run, handler }) as Promise<T>;\n },\n waitFor: async <T extends InputParameters>(\n stepId: string,\n { eventName, timeout }: { eventName: string; timeout?: number; schema?: T },\n ) => {\n if (!run) {\n throw new WorkflowEngineError('Missing workflow run', workflowId, runId);\n }\n const timeoutDate = timeout ? new Date(Date.now() + timeout) : undefined;\n return this.waitStep({ run, stepId, eventName, timeoutDate }) as Promise<\n InferInputParameters<T> | undefined\n >;\n },\n waitUntil: async (\n stepId: string,\n dateOrOptions: Date | string | { date: Date | string },\n ) => {\n if (!run) {\n throw new WorkflowEngineError('Missing workflow run', workflowId, runId);\n }\n const date =\n dateOrOptions instanceof Date\n ? dateOrOptions\n : typeof dateOrOptions === 'string'\n ? new Date(dateOrOptions)\n : dateOrOptions.date instanceof Date\n ? dateOrOptions.date\n : new Date(dateOrOptions.date);\n await this.waitStep({ run, stepId, timeoutDate: date });\n },\n pause: async (stepId: string) => {\n if (!run) {\n throw new WorkflowEngineError('Missing workflow run', workflowId, runId);\n }\n await this.waitStep({ run, stepId, eventName: PAUSE_EVENT_NAME });\n },\n delay: async (stepId: string, duration: Duration) => {\n if (!run) {\n throw new WorkflowEngineError('Missing workflow run', workflowId, runId);\n }\n await this.waitStep({\n run,\n stepId,\n timeoutDate: new Date(Date.now() + parseDuration(duration)),\n });\n },\n get sleep() {\n return this.delay;\n },\n poll: async <T>(\n stepId: string,\n conditionFn: () => Promise<T | false>,\n options?: { interval?: Duration; timeout?: Duration },\n ) => {\n if (!run) {\n throw new WorkflowEngineError('Missing workflow run', workflowId, runId);\n }\n const intervalMs = parseDuration(options?.interval ?? '30s');\n if (intervalMs < 30_000) {\n throw new WorkflowEngineError(\n `step.poll interval must be at least 30s (got ${intervalMs}ms)`,\n workflowId,\n runId,\n );\n }\n const timeoutMs = options?.timeout ? parseDuration(options.timeout) : undefined;\n return this.pollStep({ run, stepId, conditionFn, intervalMs, timeoutMs }) as Promise<\n { timedOut: false; data: T } | { timedOut: true }\n >;\n },\n };\n\n let step = { ...baseStep };\n const plugins = workflow.plugins ?? [];\n for (const plugin of plugins) {\n const extra = plugin.methods(step);\n step = { ...step, ...extra };\n }\n\n const context: WorkflowContext = {\n input: run.input as z.ZodTypeAny,\n workflowId: run.workflowId,\n runId: run.id,\n timeline: run.timeline,\n logger: this.logger,\n step,\n };\n\n const result = await workflow.handler(context);\n\n run = await this.getRun({ runId, resourceId });\n\n const isLastParsedStep = run.currentStepId === workflow.steps[workflow.steps.length - 1]?.id;\n const hasPluginSteps = (workflow.plugins?.length ?? 0) > 0;\n const noParsedSteps = workflow.steps.length === 0;\n const shouldComplete =\n run.status === WorkflowStatus.RUNNING &&\n (noParsedSteps || isLastParsedStep || (hasPluginSteps && result !== undefined));\n if (shouldComplete) {\n const normalizedResult = result === undefined ? {} : result;\n await this.updateRun({\n runId,\n resourceId,\n data: {\n status: WorkflowStatus.COMPLETED,\n output: normalizedResult,\n completedAt: new Date(),\n jobId: job?.id,\n },\n });\n\n this.logger.log('Workflow run completed.', {\n runId,\n workflowId,\n });\n }\n } catch (error) {\n if (run.retryCount < run.maxRetries) {\n await this.updateRun({\n runId,\n resourceId,\n data: {\n retryCount: run.retryCount + 1,\n jobId: job?.id,\n },\n });\n\n const retryDelay = 2 ** run.retryCount * 1000;\n\n // NOTE: Do not use pg-boss retryLimit and retryBackoff so that we can fully control the retry logic from the WorkflowEngine and not PGBoss.\n const pgBossJob: WorkflowRunJobParameters = {\n runId,\n resourceId,\n workflowId,\n input,\n };\n await this.boss?.send('workflow-run', pgBossJob, {\n startAfter: new Date(Date.now() + retryDelay),\n expireInSeconds: defaultExpireInSeconds,\n });\n\n return;\n }\n\n // TODO: Ensure that this code always runs, even if worker is stopped unexpectedly.\n await this.updateRun({\n runId,\n resourceId,\n data: {\n status: WorkflowStatus.FAILED,\n error: error instanceof Error ? error.message : String(error),\n jobId: job?.id,\n },\n });\n\n throw error;\n }\n }\n\n private getCachedStepEntry(\n timeline: Record<string, unknown>,\n stepId: string,\n ): TimelineStepEntry | null {\n const stepEntry = timeline[stepId];\n return stepEntry && typeof stepEntry === 'object' && 'output' in stepEntry\n ? (stepEntry as TimelineStepEntry)\n : null;\n }\n\n private async runStep({\n stepId,\n run,\n handler,\n }: {\n stepId: string;\n run: WorkflowRun;\n handler: () => Promise<unknown>;\n }) {\n return withPostgresTransaction(\n this.db,\n async (db) => {\n const persistedRun = await this.getRun(\n { runId: run.id, resourceId: run.resourceId ?? undefined },\n {\n exclusiveLock: true,\n db,\n },\n );\n\n if (\n persistedRun.status === WorkflowStatus.CANCELLED ||\n persistedRun.status === WorkflowStatus.PAUSED ||\n persistedRun.status === WorkflowStatus.FAILED\n ) {\n this.logger.log(`Step ${stepId} skipped, workflow run is ${persistedRun.status}`, {\n runId: run.id,\n workflowId: run.workflowId,\n });\n\n return;\n }\n\n try {\n const cached = this.getCachedStepEntry(persistedRun.timeline, stepId);\n if (cached?.output !== undefined) {\n return cached.output;\n }\n\n await this.updateRun(\n {\n runId: run.id,\n resourceId: run.resourceId ?? undefined,\n data: {\n currentStepId: stepId,\n },\n },\n { db },\n );\n\n this.logger.log(`Running step ${stepId}...`, {\n runId: run.id,\n workflowId: run.workflowId,\n });\n\n let output = await handler();\n\n if (output === undefined) {\n output = {};\n }\n\n run = await this.updateRun(\n {\n runId: run.id,\n resourceId: run.resourceId ?? undefined,\n data: {\n timeline: merge(run.timeline, {\n [stepId]: {\n output,\n timestamp: new Date(),\n },\n }),\n },\n },\n { db },\n );\n\n return output;\n } catch (error) {\n this.logger.error(`Step ${stepId} failed:`, error as Error, {\n runId: run.id,\n workflowId: run.workflowId,\n });\n\n await this.updateRun(\n {\n runId: run.id,\n resourceId: run.resourceId ?? undefined,\n data: {\n status: WorkflowStatus.FAILED,\n error: error instanceof Error ? `${error.message}\\n${error.stack}` : String(error),\n },\n },\n { db },\n );\n\n throw error;\n }\n },\n this.pool,\n );\n }\n\n private async waitStep({\n run,\n stepId,\n eventName,\n timeoutDate,\n }: {\n run: WorkflowRun;\n stepId: string;\n eventName?: string;\n timeoutDate?: Date;\n }): Promise<unknown> {\n const persistedRun = await this.getRun({\n runId: run.id,\n resourceId: run.resourceId ?? undefined,\n });\n\n if (\n persistedRun.status === WorkflowStatus.CANCELLED ||\n persistedRun.status === WorkflowStatus.PAUSED ||\n persistedRun.status === WorkflowStatus.FAILED\n ) {\n return;\n }\n\n const cached = this.getCachedStepEntry(persistedRun.timeline, stepId);\n if (cached?.output !== undefined) {\n return cached.timedOut ? undefined : cached.output;\n }\n\n const timeoutEvent = timeoutDate ? `__timeout_${stepId}` : undefined;\n\n await this.updateRun({\n runId: run.id,\n resourceId: run.resourceId ?? undefined,\n data: {\n status: WorkflowStatus.PAUSED,\n currentStepId: stepId,\n pausedAt: new Date(),\n timeline: merge(run.timeline, {\n [`${stepId}-wait-for`]: {\n waitFor: { eventName, timeoutEvent },\n timestamp: new Date(),\n },\n }),\n },\n });\n\n if (timeoutDate && timeoutEvent) {\n const job: WorkflowRunJobParameters = {\n runId: run.id,\n resourceId: run.resourceId ?? undefined,\n workflowId: run.workflowId,\n input: run.input,\n event: { name: timeoutEvent, data: { date: timeoutDate.toISOString() } },\n };\n await this.boss.send(WORKFLOW_RUN_QUEUE_NAME, job, {\n startAfter: timeoutDate.getTime() <= Date.now() ? new Date() : timeoutDate,\n expireInSeconds: defaultExpireInSeconds,\n });\n }\n\n this.logger.log(\n `Step ${stepId} waiting${eventName ? ` for event \"${eventName}\"` : ''}${timeoutDate ? ` until ${timeoutDate.toISOString()}` : ''}`,\n { runId: run.id, workflowId: run.workflowId },\n );\n }\n\n private async pollStep<T>({\n run,\n stepId,\n conditionFn,\n intervalMs,\n timeoutMs,\n }: {\n run: WorkflowRun;\n stepId: string;\n conditionFn: () => Promise<T | false>;\n intervalMs: number;\n timeoutMs?: number;\n }): Promise<{ timedOut: false; data: T } | { timedOut: true } | undefined> {\n const persistedRun = await this.getRun({\n runId: run.id,\n resourceId: run.resourceId ?? undefined,\n });\n\n if (\n persistedRun.status === WorkflowStatus.CANCELLED ||\n persistedRun.status === WorkflowStatus.PAUSED ||\n persistedRun.status === WorkflowStatus.FAILED\n ) {\n return { timedOut: true };\n }\n\n const cached = this.getCachedStepEntry(persistedRun.timeline, stepId);\n if (cached?.output !== undefined) {\n return cached.timedOut ? { timedOut: true } : { timedOut: false, data: cached.output as T };\n }\n\n const pollStateEntry = persistedRun.timeline[`${stepId}-poll`];\n const startedAt =\n pollStateEntry && typeof pollStateEntry === 'object' && 'startedAt' in pollStateEntry\n ? new Date((pollStateEntry as { startedAt: string }).startedAt)\n : new Date();\n\n if (timeoutMs !== undefined && Date.now() >= startedAt.getTime() + timeoutMs) {\n await this.updateRun({\n runId: run.id,\n resourceId: run.resourceId ?? undefined,\n data: {\n currentStepId: stepId,\n timeline: merge(persistedRun.timeline, {\n [stepId]: { output: {}, timedOut: true as const, timestamp: new Date() },\n }),\n },\n });\n return { timedOut: true };\n }\n\n const result = await conditionFn();\n\n if (result !== false) {\n await this.updateRun({\n runId: run.id,\n resourceId: run.resourceId ?? undefined,\n data: {\n currentStepId: stepId,\n timeline: merge(persistedRun.timeline, {\n [stepId]: { output: result, timestamp: new Date() },\n }),\n },\n });\n return { timedOut: false, data: result };\n }\n\n const pollEvent = `__poll_${stepId}`;\n await this.updateRun({\n runId: run.id,\n resourceId: run.resourceId ?? undefined,\n data: {\n status: WorkflowStatus.PAUSED,\n currentStepId: stepId,\n pausedAt: new Date(),\n timeline: merge(persistedRun.timeline, {\n [`${stepId}-poll`]: { startedAt: startedAt.toISOString() },\n [`${stepId}-wait-for`]: {\n waitFor: { timeoutEvent: pollEvent, skipOutput: true },\n timestamp: new Date(),\n },\n }),\n },\n });\n\n await this.boss.send(\n WORKFLOW_RUN_QUEUE_NAME,\n {\n runId: run.id,\n resourceId: run.resourceId ?? undefined,\n workflowId: run.workflowId,\n input: run.input,\n event: { name: pollEvent, data: {} },\n },\n {\n startAfter: new Date(Date.now() + intervalMs),\n expireInSeconds: defaultExpireInSeconds,\n },\n );\n\n this.logger.log(`Step ${stepId} polling every ${intervalMs}ms...`, {\n runId: run.id,\n workflowId: run.workflowId,\n });\n\n return { timedOut: false, data: undefined as T };\n }\n\n private async checkIfHasStarted(): Promise<void> {\n if (!this._started) {\n throw new WorkflowEngineError('Workflow engine not started');\n }\n }\n\n private buildLogger(logger: WorkflowLogger): WorkflowInternalLogger {\n return {\n log: (message: string, context?: WorkflowInternalLoggerContext) => {\n const { runId, workflowId } = context ?? {};\n const parts = [LOG_PREFIX, workflowId, runId].filter(Boolean).join(' ');\n logger.log(`${parts}: ${message}`);\n },\n error: (message: string, error: Error, context?: WorkflowInternalLoggerContext) => {\n const { runId, workflowId } = context ?? {};\n const parts = [LOG_PREFIX, workflowId, runId].filter(Boolean).join(' ');\n logger.error(`${parts}: ${message}`, error);\n },\n };\n }\n\n async getRuns({\n resourceId,\n startingAfter,\n endingBefore,\n limit = 20,\n statuses,\n workflowId,\n }: {\n resourceId?: string;\n startingAfter?: string | null;\n endingBefore?: string | null;\n limit?: number;\n statuses?: WorkflowStatus[];\n workflowId?: string;\n }): Promise<{\n items: WorkflowRun[];\n nextCursor: string | null;\n prevCursor: string | null;\n hasMore: boolean;\n hasPrev: boolean;\n }> {\n return getWorkflowRuns(\n {\n resourceId,\n startingAfter,\n endingBefore,\n limit,\n statuses,\n workflowId,\n },\n this.db,\n );\n }\n}\n",
|
|
9
9
|
"import * as ts from 'typescript';\nimport type { StepInternalDefinition, WorkflowContext } from './types';\nimport { StepType } from './types';\n\ntype ParseWorkflowHandlerReturnType = {\n steps: StepInternalDefinition[];\n};\n\nexport function parseWorkflowHandler(\n handler: (context: WorkflowContext) => Promise<unknown>,\n): ParseWorkflowHandlerReturnType {\n const handlerSource = handler.toString();\n const sourceFile = ts.createSourceFile('handler.ts', handlerSource, ts.ScriptTarget.Latest, true);\n\n const steps: Map<string, StepInternalDefinition> = new Map();\n\n function isInConditional(node: ts.Node): boolean {\n let current = node.parent;\n while (current) {\n if (\n ts.isIfStatement(current) ||\n ts.isConditionalExpression(current) ||\n ts.isSwitchStatement(current) ||\n ts.isCaseClause(current)\n ) {\n return true;\n }\n current = current.parent;\n }\n return false;\n }\n\n function isInLoop(node: ts.Node): boolean {\n let current = node.parent;\n while (current) {\n if (\n ts.isForStatement(current) ||\n ts.isForInStatement(current) ||\n ts.isForOfStatement(current) ||\n ts.isWhileStatement(current) ||\n ts.isDoStatement(current)\n ) {\n return true;\n }\n current = current.parent;\n }\n return false;\n }\n\n function extractStepId(arg: ts.Expression): {\n id: string;\n isDynamic: boolean;\n } {\n if (ts.isStringLiteral(arg) || ts.isNoSubstitutionTemplateLiteral(arg)) {\n return { id: arg.text, isDynamic: false };\n }\n\n if (ts.isTemplateExpression(arg)) {\n let templateStr = arg.head.text;\n for (const span of arg.templateSpans) {\n templateStr += `\\${...}`;\n templateStr += span.literal.text;\n }\n return { id: templateStr, isDynamic: true };\n }\n\n return { id: arg.getText(sourceFile), isDynamic: true };\n }\n\n function visit(node: ts.Node) {\n if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression)) {\n const propertyAccess = node.expression;\n const objectName = propertyAccess.expression.getText(sourceFile);\n const methodName = propertyAccess.name.text;\n\n if (\n objectName === 'step' &&\n (methodName === 'run' ||\n methodName === 'waitFor' ||\n methodName === 'pause' ||\n methodName === 'waitUntil' ||\n methodName === 'delay' ||\n methodName === 'sleep' ||\n methodName === 'poll')\n ) {\n const firstArg = node.arguments[0];\n if (firstArg) {\n const { id, isDynamic } = extractStepId(firstArg);\n const stepType = methodName === 'sleep' ? StepType.DELAY : (methodName as StepType);\n\n const stepDefinition: StepInternalDefinition = {\n id,\n type: stepType,\n conditional: isInConditional(node),\n loop: isInLoop(node),\n isDynamic,\n };\n\n if (steps.has(id)) {\n throw new Error(\n `Duplicate step ID detected: '${id}'. Step IDs must be unique within a workflow.`,\n );\n }\n\n steps.set(id, stepDefinition);\n }\n }\n }\n\n ts.forEachChild(node, visit);\n }\n\n visit(sourceFile);\n\n return { steps: Array.from(steps.values()) };\n}\n",
|
|
10
10
|
"import type { z } from 'zod';\nimport type { WorkflowRun } from './db/types';\nimport type { Duration } from './duration';\n\nexport enum WorkflowStatus {\n PENDING = 'pending',\n RUNNING = 'running',\n PAUSED = 'paused',\n COMPLETED = 'completed',\n FAILED = 'failed',\n CANCELLED = 'cancelled',\n}\n\nexport enum StepType {\n PAUSE = 'pause',\n RUN = 'run',\n WAIT_FOR = 'waitFor',\n WAIT_UNTIL = 'waitUntil',\n DELAY = 'delay',\n POLL = 'poll',\n}\n\nexport type InputParameters = z.ZodTypeAny;\nexport type InferInputParameters<P extends InputParameters> = P extends z.ZodTypeAny\n ? z.infer<P>\n : never;\n\nexport type WorkflowOptions<I extends InputParameters> = {\n timeout?: number;\n retries?: number;\n inputSchema?: I;\n};\n\nexport type StepBaseContext = {\n run: <T>(stepId: string, handler: () => Promise<T>) => Promise<T>;\n waitFor: {\n <T extends InputParameters>(\n stepId: string,\n options: { eventName: string; schema?: T },\n ): Promise<InferInputParameters<T>>;\n <T extends InputParameters>(\n stepId: string,\n options: { eventName: string; timeout: number; schema?: T },\n ): Promise<InferInputParameters<T> | undefined>;\n };\n waitUntil: {\n (stepId: string, date: Date): Promise<void>;\n (stepId: string, dateString: string): Promise<void>;\n (stepId: string, options: { date: Date | string }): Promise<void>;\n };\n /** Delay execution for a duration (sugar over waitUntil). Alias: sleep. */\n delay: (stepId: string, duration: Duration) => Promise<void>;\n /** Alias for delay. */\n sleep: (stepId: string, duration: Duration) => Promise<void>;\n pause: (stepId: string) => Promise<void>;\n poll: <T>(\n stepId: string,\n conditionFn: () => Promise<T | false>,\n options?: { interval?: Duration; timeout?: Duration },\n ) => Promise<{ timedOut: false; data: T } | { timedOut: true }>;\n};\n\n/**\n * Plugin that extends the workflow step API with extra methods.\n * @template TStepBase - The step type this plugin receives (base + previous plugins).\n * @template TStepExt - The extra methods this plugin adds to step.\n */\nexport interface WorkflowPlugin<TStepBase = StepBaseContext, TStepExt = object> {\n name: string;\n methods: (step: TStepBase) => TStepExt;\n}\n\nexport type WorkflowContext<\n TInput extends InputParameters = InputParameters,\n TStep extends StepBaseContext = StepBaseContext,\n> = {\n input: InferInputParameters<TInput>;\n step: TStep;\n workflowId: string;\n runId: string;\n timeline: Record<string, unknown>;\n logger: WorkflowLogger;\n};\n\nexport type WorkflowDefinition<\n TInput extends InputParameters = InputParameters,\n TStep extends StepBaseContext = StepBaseContext,\n> = {\n id: string;\n handler: (context: WorkflowContext<TInput, TStep>) => Promise<unknown>;\n inputSchema?: TInput;\n timeout?: number; // milliseconds\n retries?: number;\n plugins?: WorkflowPlugin[];\n};\n\nexport type StepInternalDefinition = {\n id: string;\n type: StepType;\n conditional: boolean;\n loop: boolean;\n isDynamic: boolean;\n};\n\nexport type WorkflowInternalDefinition<\n TInput extends InputParameters = InputParameters,\n TStep extends StepBaseContext = StepBaseContext,\n> = WorkflowDefinition<TInput, TStep> & {\n steps: StepInternalDefinition[];\n};\n\n/**\n * Chainable workflow factory: call as (id, handler, options) and/or use .use(plugin).\n * TStepExt is the accumulated step extension from all plugins (step = StepContext & TStepExt).\n */\nexport interface WorkflowFactory<TStepExt = object> {\n (\n id: string,\n handler: (\n context: WorkflowContext<InputParameters, StepBaseContext & TStepExt>,\n ) => Promise<unknown>,\n options?: WorkflowOptions<InputParameters>,\n ): WorkflowDefinition<InputParameters, StepBaseContext & TStepExt>;\n use<TNewExt>(\n plugin: WorkflowPlugin<StepBaseContext & TStepExt, TNewExt>,\n ): WorkflowFactory<TStepExt & TNewExt>;\n}\n\nexport type WorkflowRunProgress = WorkflowRun & {\n completionPercentage: number;\n totalSteps: number;\n completedSteps: number;\n};\n\nexport interface WorkflowLogger {\n log(message: string): void;\n error(message: string, ...args: unknown[]): void;\n}\n\nexport type WorkflowInternalLoggerContext = {\n runId?: string;\n workflowId?: string;\n};\nexport interface WorkflowInternalLogger {\n log(message: string, context?: WorkflowInternalLoggerContext): void;\n error(message: string, error: Error, context?: WorkflowInternalLoggerContext): void;\n}\n",
|
|
11
11
|
"import type { Db } from 'pg-boss';\n\nexport async function runMigrations(db: Db): Promise<void> {\n const tableExistsResult = await db.executeSql(\n `\n SELECT EXISTS (\n SELECT FROM information_schema.tables \n WHERE table_schema = 'public' \n AND table_name = 'workflow_runs'\n );\n `,\n [],\n );\n\n if (!tableExistsResult.rows[0]?.exists) {\n await db.executeSql(\n `\n CREATE TABLE workflow_runs (\n id varchar(32) PRIMARY KEY NOT NULL,\n created_at timestamp with time zone DEFAULT now() NOT NULL,\n updated_at timestamp with time zone DEFAULT now() NOT NULL,\n resource_id varchar(32),\n workflow_id varchar(32) NOT NULL,\n status text DEFAULT 'pending' NOT NULL,\n input jsonb NOT NULL,\n output jsonb,\n error text,\n current_step_id varchar(256) NOT NULL,\n timeline jsonb DEFAULT '{}'::jsonb NOT NULL,\n paused_at timestamp with time zone,\n resumed_at timestamp with time zone,\n completed_at timestamp with time zone,\n timeout_at timestamp with time zone,\n retry_count integer DEFAULT 0 NOT NULL,\n max_retries integer DEFAULT 0 NOT NULL,\n job_id varchar(256)\n );\n `,\n [],\n );\n\n await db.executeSql(\n `\n CREATE INDEX workflow_runs_workflow_id_idx ON workflow_runs USING btree (workflow_id);\n `,\n [],\n );\n\n await db.executeSql(\n `\n CREATE INDEX workflow_runs_created_at_idx ON workflow_runs USING btree (created_at);\n `,\n [],\n );\n\n await db.executeSql(\n `\n CREATE INDEX workflow_runs_resource_id_idx ON workflow_runs USING btree (resource_id);\n `,\n [],\n );\n }\n}\n",
|
|
12
|
-
"import ksuid from 'ksuid';\nimport type { Db } from 'pg-boss';\nimport type { WorkflowRun } from './types';\n\nexport function generateKSUID(prefix?: string): string {\n return `${prefix ? `${prefix}_` : ''}${ksuid.randomSync().string}`;\n}\n\ntype WorkflowRunRow = {\n id: string;\n created_at: string | Date;\n updated_at: string | Date;\n resource_id: string | null;\n workflow_id: string;\n status: 'pending' | 'running' | 'paused' | 'completed' | 'failed' | 'cancelled';\n input: string | unknown;\n output: string | unknown | null;\n error: string | null;\n current_step_id: string;\n timeline: string | Record<string, unknown>;\n paused_at: string | Date | null;\n resumed_at: string | Date | null;\n completed_at: string | Date | null;\n timeout_at: string | Date | null;\n retry_count: number;\n max_retries: number;\n job_id: string | null;\n};\n\nfunction mapRowToWorkflowRun(row: WorkflowRunRow): WorkflowRun {\n return {\n id: row.id,\n createdAt: new Date(row.created_at),\n updatedAt: new Date(row.updated_at),\n resourceId: row.resource_id,\n workflowId: row.workflow_id,\n status: row.status,\n input: typeof row.input === 'string' ? JSON.parse(row.input) : row.input,\n output:\n typeof row.output === 'string'\n ? row.output.trim().startsWith('{') || row.output.trim().startsWith('[')\n ? JSON.parse(row.output)\n : row.output\n : (row.output ?? null),\n error: row.error,\n currentStepId: row.current_step_id,\n timeline: typeof row.timeline === 'string' ? JSON.parse(row.timeline) : row.timeline,\n pausedAt: row.paused_at ? new Date(row.paused_at) : null,\n resumedAt: row.resumed_at ? new Date(row.resumed_at) : null,\n completedAt: row.completed_at ? new Date(row.completed_at) : null,\n timeoutAt: row.timeout_at ? new Date(row.timeout_at) : null,\n retryCount: row.retry_count,\n maxRetries: row.max_retries,\n jobId: row.job_id,\n };\n}\n\nexport async function insertWorkflowRun(\n {\n resourceId,\n workflowId,\n currentStepId,\n status,\n input,\n maxRetries,\n timeoutAt,\n }: {\n resourceId?: string;\n workflowId: string;\n currentStepId: string;\n status: string;\n input: unknown;\n maxRetries: number;\n timeoutAt: Date | null;\n },\n db: Db,\n): Promise<WorkflowRun> {\n const runId = generateKSUID('run');\n const now = new Date();\n\n const result = await db.executeSql(\n `INSERT INTO workflow_runs (\n id, \n resource_id, \n workflow_id, \n current_step_id, \n status, \n input, \n max_retries, \n timeout_at,\n created_at,\n updated_at,\n timeline,\n retry_count\n )\n VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)\n RETURNING *`,\n [\n runId,\n resourceId ?? null,\n workflowId,\n currentStepId,\n status,\n JSON.stringify(input),\n maxRetries,\n timeoutAt,\n now,\n now,\n '{}',\n 0,\n ],\n );\n\n const insertedRun = result.rows[0];\n\n if (!insertedRun) {\n throw new Error('Failed to insert workflow run');\n }\n\n return mapRowToWorkflowRun(insertedRun);\n}\n\nexport async function getWorkflowRun(\n {\n runId,\n resourceId,\n }: {\n runId: string;\n resourceId?: string;\n },\n { exclusiveLock = false, db }: { exclusiveLock?: boolean; db: Db },\n): Promise<WorkflowRun | null> {\n const lockSuffix = exclusiveLock ? 'FOR UPDATE' : '';\n\n const result = resourceId\n ? await db.executeSql(\n `SELECT * FROM workflow_runs \n WHERE id = $1 AND resource_id = $2\n ${lockSuffix}`,\n [runId, resourceId],\n )\n : await db.executeSql(\n `SELECT * FROM workflow_runs \n WHERE id = $1\n ${lockSuffix}`,\n [runId],\n );\n\n const run = result.rows[0];\n\n if (!run) {\n return null;\n }\n\n return mapRowToWorkflowRun(run);\n}\n\nexport async function updateWorkflowRun(\n {\n runId,\n resourceId,\n data,\n }: {\n runId: string;\n resourceId?: string;\n data: Partial<WorkflowRun>;\n },\n db: Db,\n): Promise<WorkflowRun | null> {\n const now = new Date();\n\n const updates: string[] = ['updated_at = $1'];\n const values: (string | number | Date | null)[] = [now];\n let paramIndex = 2;\n\n if (data.status !== undefined) {\n updates.push(`status = $${paramIndex}`);\n values.push(data.status);\n paramIndex++;\n }\n if (data.currentStepId !== undefined) {\n updates.push(`current_step_id = $${paramIndex}`);\n values.push(data.currentStepId);\n paramIndex++;\n }\n if (data.timeline !== undefined) {\n updates.push(`timeline = $${paramIndex}`);\n values.push(JSON.stringify(data.timeline));\n paramIndex++;\n }\n if (data.pausedAt !== undefined) {\n updates.push(`paused_at = $${paramIndex}`);\n values.push(data.pausedAt);\n paramIndex++;\n }\n if (data.resumedAt !== undefined) {\n updates.push(`resumed_at = $${paramIndex}`);\n values.push(data.resumedAt);\n paramIndex++;\n }\n if (data.completedAt !== undefined) {\n updates.push(`completed_at = $${paramIndex}`);\n values.push(data.completedAt);\n paramIndex++;\n }\n if (data.output !== undefined) {\n updates.push(`output = $${paramIndex}`);\n values.push(JSON.stringify(data.output));\n paramIndex++;\n }\n if (data.error !== undefined) {\n updates.push(`error = $${paramIndex}`);\n values.push(data.error);\n paramIndex++;\n }\n if (data.retryCount !== undefined) {\n updates.push(`retry_count = $${paramIndex}`);\n values.push(data.retryCount);\n paramIndex++;\n }\n if (data.jobId !== undefined) {\n updates.push(`job_id = $${paramIndex}`);\n values.push(data.jobId);\n paramIndex++;\n }\n\n const whereClause = resourceId\n ? `WHERE id = $${paramIndex} AND resource_id = $${paramIndex + 1}`\n : `WHERE id = $${paramIndex}`;\n\n values.push(runId);\n if (resourceId) {\n values.push(resourceId);\n }\n\n const query = `\n UPDATE workflow_runs \n SET ${updates.join(', ')}\n ${whereClause}\n RETURNING *\n `;\n\n const result = await db.executeSql(query, values);\n const run = result.rows[0];\n\n if (!run) {\n return null;\n }\n\n return mapRowToWorkflowRun(run);\n}\n\nexport async function getWorkflowRuns(\n {\n resourceId,\n startingAfter,\n endingBefore,\n limit = 20,\n statuses,\n workflowId,\n }: {\n resourceId?: string;\n startingAfter?: string | null;\n endingBefore?: string | null;\n limit?: number;\n statuses?: string[];\n workflowId?: string;\n },\n db: Db,\n): Promise<{\n items: WorkflowRun[];\n nextCursor: string | null;\n prevCursor: string | null;\n hasMore: boolean;\n hasPrev: boolean;\n}> {\n const conditions: string[] = [];\n const values: (string | number | string[] | Date)[] = [];\n let paramIndex = 1;\n\n if (resourceId) {\n conditions.push(`resource_id = $${paramIndex}`);\n values.push(resourceId);\n paramIndex++;\n }\n\n if (statuses && statuses.length > 0) {\n conditions.push(`status = ANY($${paramIndex})`);\n values.push(statuses);\n paramIndex++;\n }\n\n if (workflowId) {\n conditions.push(`workflow_id = $${paramIndex}`);\n values.push(workflowId);\n paramIndex++;\n }\n\n if (startingAfter) {\n const cursorResult = await db.executeSql(\n 'SELECT created_at FROM workflow_runs WHERE id = $1 LIMIT 1',\n [startingAfter],\n );\n if (cursorResult.rows[0]?.created_at) {\n conditions.push(`created_at < $${paramIndex}`);\n values.push(\n typeof cursorResult.rows[0].created_at === 'string'\n ? new Date(cursorResult.rows[0].created_at)\n : cursorResult.rows[0].created_at,\n );\n paramIndex++;\n }\n }\n\n if (endingBefore) {\n const cursorResult = await db.executeSql(\n 'SELECT created_at FROM workflow_runs WHERE id = $1 LIMIT 1',\n [endingBefore],\n );\n if (cursorResult.rows[0]?.created_at) {\n conditions.push(`created_at > $${paramIndex}`);\n values.push(\n typeof cursorResult.rows[0].created_at === 'string'\n ? new Date(cursorResult.rows[0].created_at)\n : cursorResult.rows[0].created_at,\n );\n paramIndex++;\n }\n }\n\n const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';\n const actualLimit = Math.min(Math.max(limit, 1), 100) + 1;\n\n const query = `\n SELECT * FROM workflow_runs\n ${whereClause}\n ORDER BY created_at DESC\n LIMIT $${paramIndex}\n `;\n values.push(actualLimit);\n\n const result = await db.executeSql(query, values);\n const rows = result.rows;\n\n const hasMore = rows.length > (limit ?? 20);\n const rawItems = hasMore ? rows.slice(0, limit) : rows;\n const items = rawItems.map((row) => mapRowToWorkflowRun(row));\n const hasPrev = !!endingBefore;\n const nextCursor = hasMore && items.length > 0 ? (items[items.length - 1]?.id ?? null) : null;\n const prevCursor = hasPrev && items.length > 0 ? (items[0]?.id ?? null) : null;\n\n return { items, nextCursor, prevCursor, hasMore, hasPrev };\n}\n\nexport async function withPostgresTransaction<T>(\n db: Db,\n callback: (db: Db) => Promise<T>,\n): Promise<T> {\n try {\n await db.executeSql('BEGIN', []);\n const result = await callback(db);\n await db.executeSql('COMMIT', []);\n return result;\n } catch (error) {\n await db.executeSql('ROLLBACK', []);\n throw error;\n }\n}\n"
|
|
12
|
+
"import ksuid from 'ksuid';\nimport type { Db } from 'pg-boss';\nimport type { WorkflowRun } from './types';\n\nexport function generateKSUID(prefix?: string): string {\n return `${prefix ? `${prefix}_` : ''}${ksuid.randomSync().string}`;\n}\n\ntype WorkflowRunRow = {\n id: string;\n created_at: string | Date;\n updated_at: string | Date;\n resource_id: string | null;\n workflow_id: string;\n status: 'pending' | 'running' | 'paused' | 'completed' | 'failed' | 'cancelled';\n input: string | unknown;\n output: string | unknown | null;\n error: string | null;\n current_step_id: string;\n timeline: string | Record<string, unknown>;\n paused_at: string | Date | null;\n resumed_at: string | Date | null;\n completed_at: string | Date | null;\n timeout_at: string | Date | null;\n retry_count: number;\n max_retries: number;\n job_id: string | null;\n};\n\nfunction mapRowToWorkflowRun(row: WorkflowRunRow): WorkflowRun {\n return {\n id: row.id,\n createdAt: new Date(row.created_at),\n updatedAt: new Date(row.updated_at),\n resourceId: row.resource_id,\n workflowId: row.workflow_id,\n status: row.status,\n input: typeof row.input === 'string' ? JSON.parse(row.input) : row.input,\n output:\n typeof row.output === 'string'\n ? row.output.trim().startsWith('{') || row.output.trim().startsWith('[')\n ? JSON.parse(row.output)\n : row.output\n : (row.output ?? null),\n error: row.error,\n currentStepId: row.current_step_id,\n timeline: typeof row.timeline === 'string' ? JSON.parse(row.timeline) : row.timeline,\n pausedAt: row.paused_at ? new Date(row.paused_at) : null,\n resumedAt: row.resumed_at ? new Date(row.resumed_at) : null,\n completedAt: row.completed_at ? new Date(row.completed_at) : null,\n timeoutAt: row.timeout_at ? new Date(row.timeout_at) : null,\n retryCount: row.retry_count,\n maxRetries: row.max_retries,\n jobId: row.job_id,\n };\n}\n\nexport async function insertWorkflowRun(\n {\n resourceId,\n workflowId,\n currentStepId,\n status,\n input,\n maxRetries,\n timeoutAt,\n }: {\n resourceId?: string;\n workflowId: string;\n currentStepId: string;\n status: string;\n input: unknown;\n maxRetries: number;\n timeoutAt: Date | null;\n },\n db: Db,\n): Promise<WorkflowRun> {\n const runId = generateKSUID('run');\n const now = new Date();\n\n const result = await db.executeSql(\n `INSERT INTO workflow_runs (\n id, \n resource_id, \n workflow_id, \n current_step_id, \n status, \n input, \n max_retries, \n timeout_at,\n created_at,\n updated_at,\n timeline,\n retry_count\n )\n VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)\n RETURNING *`,\n [\n runId,\n resourceId ?? null,\n workflowId,\n currentStepId,\n status,\n JSON.stringify(input),\n maxRetries,\n timeoutAt,\n now,\n now,\n '{}',\n 0,\n ],\n );\n\n const insertedRun = result.rows[0];\n\n if (!insertedRun) {\n throw new Error('Failed to insert workflow run');\n }\n\n return mapRowToWorkflowRun(insertedRun);\n}\n\nexport async function getWorkflowRun(\n {\n runId,\n resourceId,\n }: {\n runId: string;\n resourceId?: string;\n },\n { exclusiveLock = false, db }: { exclusiveLock?: boolean; db: Db },\n): Promise<WorkflowRun | null> {\n const lockSuffix = exclusiveLock ? 'FOR UPDATE' : '';\n\n const result = resourceId\n ? await db.executeSql(\n `SELECT * FROM workflow_runs \n WHERE id = $1 AND resource_id = $2\n ${lockSuffix}`,\n [runId, resourceId],\n )\n : await db.executeSql(\n `SELECT * FROM workflow_runs \n WHERE id = $1\n ${lockSuffix}`,\n [runId],\n );\n\n const run = result.rows[0];\n\n if (!run) {\n return null;\n }\n\n return mapRowToWorkflowRun(run);\n}\n\nexport async function updateWorkflowRun(\n {\n runId,\n resourceId,\n data,\n }: {\n runId: string;\n resourceId?: string;\n data: Partial<WorkflowRun>;\n },\n db: Db,\n): Promise<WorkflowRun | null> {\n const now = new Date();\n\n const updates: string[] = ['updated_at = $1'];\n const values: (string | number | Date | null)[] = [now];\n let paramIndex = 2;\n\n if (data.status !== undefined) {\n updates.push(`status = $${paramIndex}`);\n values.push(data.status);\n paramIndex++;\n }\n if (data.currentStepId !== undefined) {\n updates.push(`current_step_id = $${paramIndex}`);\n values.push(data.currentStepId);\n paramIndex++;\n }\n if (data.timeline !== undefined) {\n updates.push(`timeline = $${paramIndex}`);\n values.push(JSON.stringify(data.timeline));\n paramIndex++;\n }\n if (data.pausedAt !== undefined) {\n updates.push(`paused_at = $${paramIndex}`);\n values.push(data.pausedAt);\n paramIndex++;\n }\n if (data.resumedAt !== undefined) {\n updates.push(`resumed_at = $${paramIndex}`);\n values.push(data.resumedAt);\n paramIndex++;\n }\n if (data.completedAt !== undefined) {\n updates.push(`completed_at = $${paramIndex}`);\n values.push(data.completedAt);\n paramIndex++;\n }\n if (data.output !== undefined) {\n updates.push(`output = $${paramIndex}`);\n values.push(JSON.stringify(data.output));\n paramIndex++;\n }\n if (data.error !== undefined) {\n updates.push(`error = $${paramIndex}`);\n values.push(data.error);\n paramIndex++;\n }\n if (data.retryCount !== undefined) {\n updates.push(`retry_count = $${paramIndex}`);\n values.push(data.retryCount);\n paramIndex++;\n }\n if (data.jobId !== undefined) {\n updates.push(`job_id = $${paramIndex}`);\n values.push(data.jobId);\n paramIndex++;\n }\n\n const whereClause = resourceId\n ? `WHERE id = $${paramIndex} AND resource_id = $${paramIndex + 1}`\n : `WHERE id = $${paramIndex}`;\n\n values.push(runId);\n if (resourceId) {\n values.push(resourceId);\n }\n\n const query = `\n UPDATE workflow_runs \n SET ${updates.join(', ')}\n ${whereClause}\n RETURNING *\n `;\n\n const result = await db.executeSql(query, values);\n const run = result.rows[0];\n\n if (!run) {\n return null;\n }\n\n return mapRowToWorkflowRun(run);\n}\n\nexport async function getWorkflowRuns(\n {\n resourceId,\n startingAfter,\n endingBefore,\n limit = 20,\n statuses,\n workflowId,\n }: {\n resourceId?: string;\n startingAfter?: string | null;\n endingBefore?: string | null;\n limit?: number;\n statuses?: string[];\n workflowId?: string;\n },\n db: Db,\n): Promise<{\n items: WorkflowRun[];\n nextCursor: string | null;\n prevCursor: string | null;\n hasMore: boolean;\n hasPrev: boolean;\n}> {\n const conditions: string[] = [];\n const values: (string | number | string[] | Date)[] = [];\n let paramIndex = 1;\n\n if (resourceId) {\n conditions.push(`resource_id = $${paramIndex}`);\n values.push(resourceId);\n paramIndex++;\n }\n\n if (statuses && statuses.length > 0) {\n conditions.push(`status = ANY($${paramIndex})`);\n values.push(statuses);\n paramIndex++;\n }\n\n if (workflowId) {\n conditions.push(`workflow_id = $${paramIndex}`);\n values.push(workflowId);\n paramIndex++;\n }\n\n if (startingAfter) {\n const cursorResult = await db.executeSql(\n 'SELECT created_at FROM workflow_runs WHERE id = $1 LIMIT 1',\n [startingAfter],\n );\n if (cursorResult.rows[0]?.created_at) {\n conditions.push(`created_at < $${paramIndex}`);\n values.push(\n typeof cursorResult.rows[0].created_at === 'string'\n ? new Date(cursorResult.rows[0].created_at)\n : cursorResult.rows[0].created_at,\n );\n paramIndex++;\n }\n }\n\n if (endingBefore) {\n const cursorResult = await db.executeSql(\n 'SELECT created_at FROM workflow_runs WHERE id = $1 LIMIT 1',\n [endingBefore],\n );\n if (cursorResult.rows[0]?.created_at) {\n conditions.push(`created_at > $${paramIndex}`);\n values.push(\n typeof cursorResult.rows[0].created_at === 'string'\n ? new Date(cursorResult.rows[0].created_at)\n : cursorResult.rows[0].created_at,\n );\n paramIndex++;\n }\n }\n\n const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';\n const actualLimit = Math.min(Math.max(limit, 1), 100) + 1;\n\n const query = `\n SELECT * FROM workflow_runs\n ${whereClause}\n ORDER BY created_at DESC\n LIMIT $${paramIndex}\n `;\n values.push(actualLimit);\n\n const result = await db.executeSql(query, values);\n const rows = result.rows;\n\n const hasMore = rows.length > (limit ?? 20);\n const rawItems = hasMore ? rows.slice(0, limit) : rows;\n const items = rawItems.map((row) => mapRowToWorkflowRun(row));\n const hasPrev = !!endingBefore;\n const nextCursor = hasMore && items.length > 0 ? (items[items.length - 1]?.id ?? null) : null;\n const prevCursor = hasPrev && items.length > 0 ? (items[0]?.id ?? null) : null;\n\n return { items, nextCursor, prevCursor, hasMore, hasPrev };\n}\n\n/**\n * Run a callback inside a PostgreSQL transaction using a dedicated client.\n *\n * When a `pool` is provided, a dedicated client is checked out so that\n * BEGIN / COMMIT / ROLLBACK all execute on the **same** connection.\n * This is critical for `SELECT … FOR UPDATE` locks and any work that\n * yields to the event-loop inside the transaction (e.g. async step handlers).\n *\n * Falls back to the pg-boss `Db` adapter when no pool is given (unit-test path).\n */\nexport async function withPostgresTransaction<T>(\n db: Db,\n callback: (db: Db) => Promise<T>,\n pool?: {\n connect: () => Promise<{\n query: (text: string, values?: unknown[]) => Promise<unknown>;\n release: () => void;\n }>;\n },\n): Promise<T> {\n let txDb: Db;\n let release: (() => void) | undefined;\n\n if (pool) {\n const client = await pool.connect();\n txDb = {\n executeSql: (text: string, values?: unknown[]) =>\n client.query(text, values) as Promise<{ rows: unknown[] }>,\n };\n release = () => client.release();\n } else {\n txDb = db;\n }\n\n try {\n await txDb.executeSql('BEGIN', []);\n const result = await callback(txDb);\n await txDb.executeSql('COMMIT', []);\n return result;\n } catch (error) {\n await txDb.executeSql('ROLLBACK', []);\n throw error;\n } finally {\n release?.();\n }\n}\n"
|
|
13
13
|
],
|
|
14
|
-
"mappings": "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",
|
|
15
|
-
"debugId": "
|
|
14
|
+
"mappings": "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",
|
|
15
|
+
"debugId": "AA54057FBD64F69364756E2164756E21",
|
|
16
16
|
"names": []
|
|
17
17
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pg-workflows",
|
|
3
3
|
"description": "The simplest Postgres workflow engine for TypeScript - durable execution, event-driven orchestration, and automatic retries powered entirely by PostgreSQL",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.4.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
7
7
|
"dist"
|
|
@@ -25,9 +25,10 @@
|
|
|
25
25
|
"scripts": {
|
|
26
26
|
"build": "bunup",
|
|
27
27
|
"dev": "bunup --watch",
|
|
28
|
-
"test": "
|
|
29
|
-
"test:
|
|
30
|
-
"test:
|
|
28
|
+
"test": "bun run test:unit && bun run test:integration",
|
|
29
|
+
"test:unit": "vitest run --config src/vitest.unit.config.ts",
|
|
30
|
+
"test:integration": "vitest run --config src/vitest.integration.config.ts",
|
|
31
|
+
"test:watch": "vitest watch --config src/vitest.unit.config.ts",
|
|
31
32
|
"lint": "biome check .",
|
|
32
33
|
"lint:fix": "biome check --write .",
|
|
33
34
|
"format": "biome format --write .",
|
|
@@ -69,12 +70,21 @@
|
|
|
69
70
|
"es-toolkit": "^1.44.0",
|
|
70
71
|
"ksuid": "^3.0.0",
|
|
71
72
|
"parse-duration": "^2.1.5",
|
|
72
|
-
"pg": "^
|
|
73
|
-
"
|
|
74
|
-
|
|
75
|
-
|
|
73
|
+
"pg-boss": "^12.14.0",
|
|
74
|
+
"typescript": "^5.9.3"
|
|
75
|
+
},
|
|
76
|
+
"peerDependencies": {
|
|
77
|
+
"pg": "^8.0.0",
|
|
78
|
+
"zod": "^3.0.0"
|
|
79
|
+
},
|
|
80
|
+
"peerDependenciesMeta": {
|
|
81
|
+
"zod": {
|
|
82
|
+
"optional": true
|
|
83
|
+
}
|
|
76
84
|
},
|
|
77
85
|
"devDependencies": {
|
|
86
|
+
"pg": "^8.20.0",
|
|
87
|
+
"zod": "^3.24.0",
|
|
78
88
|
"@biomejs/biome": "^2.3.10",
|
|
79
89
|
"@electric-sql/pglite": "^0.3.14",
|
|
80
90
|
"@types/node": "^22.10.2",
|