pg-workflows 0.7.1 → 0.8.1

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/dist/index.cjs CHANGED
@@ -66,180 +66,25 @@ var exports_src = {};
66
66
  __export(exports_src, {
67
67
  workflow: () => workflow,
68
68
  parseDuration: () => parseDuration,
69
+ createWorkflowRef: () => createWorkflowRef,
69
70
  WorkflowStatus: () => WorkflowStatus,
70
71
  WorkflowRunNotFoundError: () => WorkflowRunNotFoundError,
71
72
  WorkflowEngineError: () => WorkflowEngineError,
72
73
  WorkflowEngine: () => WorkflowEngine,
74
+ WorkflowClient: () => WorkflowClient,
73
75
  StepType: () => StepType
74
76
  });
75
77
  module.exports = __toCommonJS(exports_src);
76
78
 
77
- // src/definition.ts
78
- function createWorkflowFactory(plugins = []) {
79
- const factory = (id, handler, { inputSchema, timeout, retries } = {}) => ({
80
- id,
81
- handler,
82
- inputSchema,
83
- timeout,
84
- retries,
85
- plugins: plugins.length > 0 ? plugins : undefined
86
- });
87
- factory.use = (plugin) => createWorkflowFactory([
88
- ...plugins,
89
- plugin
90
- ]);
91
- return factory;
92
- }
93
- var workflow = createWorkflowFactory();
94
- // src/duration.ts
95
- var import_parse_duration = __toESM(require("parse-duration"));
96
-
97
- // src/error.ts
98
- class WorkflowEngineError extends Error {
99
- workflowId;
100
- runId;
101
- cause;
102
- issues;
103
- constructor(message, workflowId, runId, cause = undefined, issues) {
104
- super(message);
105
- this.workflowId = workflowId;
106
- this.runId = runId;
107
- this.cause = cause;
108
- this.issues = issues;
109
- this.name = "WorkflowEngineError";
110
- if (Error.captureStackTrace) {
111
- Error.captureStackTrace(this, WorkflowEngineError);
112
- }
113
- }
114
- }
115
-
116
- class WorkflowRunNotFoundError extends WorkflowEngineError {
117
- constructor(runId, workflowId) {
118
- super("Workflow run not found", workflowId, runId);
119
- this.name = "WorkflowRunNotFoundError";
120
- }
121
- }
122
-
123
- // src/duration.ts
124
- var MS_PER_SECOND = 1000;
125
- var MS_PER_MINUTE = 60 * MS_PER_SECOND;
126
- var MS_PER_HOUR = 60 * MS_PER_MINUTE;
127
- var MS_PER_DAY = 24 * MS_PER_HOUR;
128
- var MS_PER_WEEK = 7 * MS_PER_DAY;
129
- function parseDuration(duration) {
130
- if (typeof duration === "string") {
131
- if (duration.trim() === "") {
132
- throw new WorkflowEngineError("Invalid duration: empty string");
133
- }
134
- const ms2 = import_parse_duration.default(duration);
135
- if (ms2 == null || ms2 <= 0) {
136
- throw new WorkflowEngineError(`Invalid duration: "${duration}"`);
137
- }
138
- return ms2;
139
- }
140
- const { weeks = 0, days = 0, hours = 0, minutes = 0, seconds = 0 } = duration;
141
- const ms = weeks * MS_PER_WEEK + days * MS_PER_DAY + hours * MS_PER_HOUR + minutes * MS_PER_MINUTE + seconds * MS_PER_SECOND;
142
- if (ms <= 0) {
143
- throw new WorkflowEngineError("Invalid duration: must be a positive value");
144
- }
145
- return ms;
146
- }
147
- // src/engine.ts
79
+ // src/client.ts
148
80
  var import_es_toolkit = require("es-toolkit");
149
81
  var import_pg = __toESM(require("pg"));
150
82
  var import_pg_boss = require("pg-boss");
151
83
 
152
- // src/ast-parser.ts
153
- var ts = __toESM(require("typescript"));
154
-
155
- // src/types.ts
156
- var WorkflowStatus;
157
- ((WorkflowStatus2) => {
158
- WorkflowStatus2["PENDING"] = "pending";
159
- WorkflowStatus2["RUNNING"] = "running";
160
- WorkflowStatus2["PAUSED"] = "paused";
161
- WorkflowStatus2["COMPLETED"] = "completed";
162
- WorkflowStatus2["FAILED"] = "failed";
163
- WorkflowStatus2["CANCELLED"] = "cancelled";
164
- })(WorkflowStatus ||= {});
165
- var StepType;
166
- ((StepType2) => {
167
- StepType2["PAUSE"] = "pause";
168
- StepType2["RUN"] = "run";
169
- StepType2["WAIT_FOR"] = "waitFor";
170
- StepType2["WAIT_UNTIL"] = "waitUntil";
171
- StepType2["DELAY"] = "delay";
172
- StepType2["POLL"] = "poll";
173
- })(StepType ||= {});
174
-
175
- // src/ast-parser.ts
176
- function parseWorkflowHandler(handler) {
177
- const handlerSource = handler.toString();
178
- const sourceFile = ts.createSourceFile("handler.ts", handlerSource, ts.ScriptTarget.Latest, true);
179
- const steps = new Map;
180
- function isInConditional(node) {
181
- let current = node.parent;
182
- while (current) {
183
- if (ts.isIfStatement(current) || ts.isConditionalExpression(current) || ts.isSwitchStatement(current) || ts.isCaseClause(current)) {
184
- return true;
185
- }
186
- current = current.parent;
187
- }
188
- return false;
189
- }
190
- function isInLoop(node) {
191
- let current = node.parent;
192
- while (current) {
193
- if (ts.isForStatement(current) || ts.isForInStatement(current) || ts.isForOfStatement(current) || ts.isWhileStatement(current) || ts.isDoStatement(current)) {
194
- return true;
195
- }
196
- current = current.parent;
197
- }
198
- return false;
199
- }
200
- function extractStepId(arg) {
201
- if (ts.isStringLiteral(arg) || ts.isNoSubstitutionTemplateLiteral(arg)) {
202
- return { id: arg.text, isDynamic: false };
203
- }
204
- if (ts.isTemplateExpression(arg)) {
205
- let templateStr = arg.head.text;
206
- for (const span of arg.templateSpans) {
207
- templateStr += `\${...}`;
208
- templateStr += span.literal.text;
209
- }
210
- return { id: templateStr, isDynamic: true };
211
- }
212
- return { id: arg.getText(sourceFile), isDynamic: true };
213
- }
214
- function visit(node) {
215
- if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression)) {
216
- const propertyAccess = node.expression;
217
- const objectName = propertyAccess.expression.getText(sourceFile);
218
- const methodName = propertyAccess.name.text;
219
- if (objectName === "step" && (methodName === "run" || methodName === "waitFor" || methodName === "pause" || methodName === "waitUntil" || methodName === "delay" || methodName === "sleep" || methodName === "poll")) {
220
- const firstArg = node.arguments[0];
221
- if (firstArg) {
222
- const { id, isDynamic } = extractStepId(firstArg);
223
- const stepType = methodName === "sleep" ? "delay" /* DELAY */ : methodName;
224
- const stepDefinition = {
225
- id,
226
- type: stepType,
227
- conditional: isInConditional(node),
228
- loop: isInLoop(node),
229
- isDynamic
230
- };
231
- if (steps.has(id)) {
232
- throw new Error(`Duplicate step ID detected: '${id}'. Step IDs must be unique within a workflow.`);
233
- }
234
- steps.set(id, stepDefinition);
235
- }
236
- }
237
- }
238
- ts.forEachChild(node, visit);
239
- }
240
- visit(sourceFile);
241
- return { steps: Array.from(steps.values()) };
242
- }
84
+ // src/constants.ts
85
+ var PAUSE_EVENT_NAME = "__internal_pause";
86
+ var WORKFLOW_RUN_QUEUE_NAME = "workflow-run";
87
+ var DEFAULT_PGBOSS_SCHEMA = "pgboss_v12_pgworkflow";
243
88
 
244
89
  // src/db/migration.ts
245
90
  var MIGRATION_LOCK_ID = 738291645;
@@ -508,123 +353,582 @@ async function updateWorkflowRun({
508
353
  if (expectedStatuses && expectedStatuses.length > 0) {
509
354
  whereClause += ` AND status = ANY($${paramIndex - 1})`;
510
355
  }
511
- const query = `
512
- UPDATE workflow_runs
513
- SET ${updates.join(", ")}
514
- ${whereClause}
515
- RETURNING *
516
- `;
517
- const result = await db.executeSql(query, values);
518
- const run = result.rows[0];
519
- if (!run) {
520
- return null;
356
+ const query = `
357
+ UPDATE workflow_runs
358
+ SET ${updates.join(", ")}
359
+ ${whereClause}
360
+ RETURNING *
361
+ `;
362
+ const result = await db.executeSql(query, values);
363
+ const run = result.rows[0];
364
+ if (!run) {
365
+ return null;
366
+ }
367
+ return mapRowToWorkflowRun(run);
368
+ }
369
+ async function getWorkflowRuns({
370
+ resourceId,
371
+ startingAfter,
372
+ endingBefore,
373
+ limit = 20,
374
+ statuses,
375
+ workflowId
376
+ }, db) {
377
+ const conditions = [];
378
+ const values = [];
379
+ let paramIndex = 1;
380
+ if (resourceId) {
381
+ conditions.push(`resource_id = $${paramIndex}`);
382
+ values.push(resourceId);
383
+ paramIndex++;
384
+ }
385
+ if (statuses && statuses.length > 0) {
386
+ conditions.push(`status = ANY($${paramIndex})`);
387
+ values.push(statuses);
388
+ paramIndex++;
389
+ }
390
+ if (workflowId) {
391
+ conditions.push(`workflow_id = $${paramIndex}`);
392
+ values.push(workflowId);
393
+ paramIndex++;
394
+ }
395
+ const cursorIds = [startingAfter, endingBefore].filter(Boolean);
396
+ if (cursorIds.length > 0) {
397
+ const cursorResult = await db.executeSql("SELECT id, created_at FROM workflow_runs WHERE id = ANY($1)", [cursorIds]);
398
+ const cursorMap = new Map;
399
+ for (const row of cursorResult.rows) {
400
+ cursorMap.set(row.id, typeof row.created_at === "string" ? new Date(row.created_at) : row.created_at);
401
+ }
402
+ if (startingAfter) {
403
+ const cursor = cursorMap.get(startingAfter);
404
+ if (cursor) {
405
+ conditions.push(`created_at < $${paramIndex}`);
406
+ values.push(cursor);
407
+ paramIndex++;
408
+ }
409
+ }
410
+ if (endingBefore) {
411
+ const cursor = cursorMap.get(endingBefore);
412
+ if (cursor) {
413
+ conditions.push(`created_at > $${paramIndex}`);
414
+ values.push(cursor);
415
+ paramIndex++;
416
+ }
417
+ }
418
+ }
419
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
420
+ const actualLimit = Math.min(Math.max(limit, 1), 100) + 1;
421
+ const isBackward = !!endingBefore && !startingAfter;
422
+ const query = `
423
+ SELECT * FROM workflow_runs
424
+ ${whereClause}
425
+ ORDER BY created_at ${isBackward ? "ASC" : "DESC"}
426
+ LIMIT $${paramIndex}
427
+ `;
428
+ values.push(actualLimit);
429
+ const result = await db.executeSql(query, values);
430
+ const rows = result.rows;
431
+ const hasExtraRow = rows.length > (limit ?? 20);
432
+ const rawItems = hasExtraRow ? rows.slice(0, limit) : rows;
433
+ if (isBackward) {
434
+ rawItems.reverse();
435
+ }
436
+ const items = rawItems.map((row) => mapRowToWorkflowRun(row));
437
+ const hasMore = isBackward ? items.length > 0 : hasExtraRow;
438
+ const hasPrev = isBackward ? hasExtraRow : !!startingAfter && items.length > 0;
439
+ const nextCursor = hasMore && items.length > 0 ? items[items.length - 1]?.id ?? null : null;
440
+ const prevCursor = hasPrev && items.length > 0 ? items[0]?.id ?? null : null;
441
+ return { items, nextCursor, prevCursor, hasMore, hasPrev };
442
+ }
443
+ async function withPostgresTransaction(db, callback, pool) {
444
+ let txDb;
445
+ let release;
446
+ if (pool) {
447
+ const client = await pool.connect();
448
+ txDb = {
449
+ executeSql: (text, values) => client.query(text, values)
450
+ };
451
+ release = () => client.release();
452
+ } else {
453
+ txDb = db;
454
+ }
455
+ try {
456
+ await txDb.executeSql("BEGIN", []);
457
+ const result = await callback(txDb);
458
+ await txDb.executeSql("COMMIT", []);
459
+ return result;
460
+ } catch (error) {
461
+ await txDb.executeSql("ROLLBACK", []);
462
+ throw error;
463
+ } finally {
464
+ release?.();
465
+ }
466
+ }
467
+
468
+ // src/error.ts
469
+ class WorkflowEngineError extends Error {
470
+ workflowId;
471
+ runId;
472
+ cause;
473
+ issues;
474
+ constructor(message, workflowId, runId, cause = undefined, issues) {
475
+ super(message);
476
+ this.workflowId = workflowId;
477
+ this.runId = runId;
478
+ this.cause = cause;
479
+ this.issues = issues;
480
+ this.name = "WorkflowEngineError";
481
+ if (Error.captureStackTrace) {
482
+ Error.captureStackTrace(this, WorkflowEngineError);
483
+ }
484
+ }
485
+ }
486
+
487
+ class WorkflowRunNotFoundError extends WorkflowEngineError {
488
+ constructor(runId, workflowId) {
489
+ super("Workflow run not found", workflowId, runId);
490
+ this.name = "WorkflowRunNotFoundError";
491
+ }
492
+ }
493
+
494
+ // src/types.ts
495
+ var WorkflowStatus;
496
+ ((WorkflowStatus2) => {
497
+ WorkflowStatus2["PENDING"] = "pending";
498
+ WorkflowStatus2["RUNNING"] = "running";
499
+ WorkflowStatus2["PAUSED"] = "paused";
500
+ WorkflowStatus2["COMPLETED"] = "completed";
501
+ WorkflowStatus2["FAILED"] = "failed";
502
+ WorkflowStatus2["CANCELLED"] = "cancelled";
503
+ })(WorkflowStatus ||= {});
504
+ var StepType;
505
+ ((StepType2) => {
506
+ StepType2["PAUSE"] = "pause";
507
+ StepType2["RUN"] = "run";
508
+ StepType2["WAIT_FOR"] = "waitFor";
509
+ StepType2["WAIT_UNTIL"] = "waitUntil";
510
+ StepType2["DELAY"] = "delay";
511
+ StepType2["POLL"] = "poll";
512
+ })(StepType ||= {});
513
+
514
+ // src/client.ts
515
+ var LOG_PREFIX = "[WorkflowClient]";
516
+ var defaultLogger = {
517
+ log: (_message) => console.warn(_message),
518
+ error: (message, error) => console.error(message, error)
519
+ };
520
+ var defaultExpireInSeconds = process.env.WORKFLOW_RUN_EXPIRE_IN_SECONDS ? Number.parseInt(process.env.WORKFLOW_RUN_EXPIRE_IN_SECONDS, 10) : 5 * 60;
521
+
522
+ class WorkflowClient {
523
+ boss;
524
+ db;
525
+ pool;
526
+ _ownsPool = false;
527
+ _started = false;
528
+ logger;
529
+ constructor({ logger, ...connectionOptions }) {
530
+ this.logger = logger ?? defaultLogger;
531
+ if ("pool" in connectionOptions && connectionOptions.pool) {
532
+ this.pool = connectionOptions.pool;
533
+ } else if ("connectionString" in connectionOptions && connectionOptions.connectionString) {
534
+ this.pool = new import_pg.default.Pool({ connectionString: connectionOptions.connectionString });
535
+ this._ownsPool = true;
536
+ } else {
537
+ throw new WorkflowEngineError("Either pool or connectionString must be provided");
538
+ }
539
+ const db = {
540
+ executeSql: (text, values) => this.pool.query(text, values)
541
+ };
542
+ this.boss = new import_pg_boss.PgBoss({ db, schema: DEFAULT_PGBOSS_SCHEMA });
543
+ this.db = db;
544
+ }
545
+ async start() {
546
+ if (this._started) {
547
+ return;
548
+ }
549
+ await this.boss.start();
550
+ this.db = this.boss.getDb();
551
+ await runMigrations(this.db);
552
+ await this.boss.createQueue(WORKFLOW_RUN_QUEUE_NAME);
553
+ this._started = true;
554
+ this.logger.log(`${LOG_PREFIX} Client started`);
555
+ }
556
+ async stop() {
557
+ await this.boss.stop();
558
+ if (this._ownsPool) {
559
+ await this.pool.end();
560
+ }
561
+ this._started = false;
562
+ this.logger.log(`${LOG_PREFIX} Client stopped`);
563
+ }
564
+ async startWorkflow(refOrParams, inputArg, optionsArg) {
565
+ await this.ensureStarted();
566
+ let workflowId;
567
+ let input;
568
+ let resourceId;
569
+ let idempotencyKey;
570
+ let options;
571
+ if (typeof refOrParams === "function" && "id" in refOrParams) {
572
+ const ref = refOrParams;
573
+ workflowId = ref.id;
574
+ input = inputArg;
575
+ options = optionsArg;
576
+ resourceId = optionsArg?.resourceId;
577
+ idempotencyKey = optionsArg?.idempotencyKey;
578
+ if (ref.inputSchema) {
579
+ const result = await ref.inputSchema["~standard"].validate(input);
580
+ if (result.issues) {
581
+ throw new WorkflowEngineError(JSON.stringify(result.issues), workflowId, undefined, undefined, result.issues);
582
+ }
583
+ }
584
+ } else {
585
+ const params = refOrParams;
586
+ workflowId = params.workflowId;
587
+ input = params.input;
588
+ resourceId = params.resourceId;
589
+ idempotencyKey = params.idempotencyKey;
590
+ options = params.options;
591
+ }
592
+ const run = await withPostgresTransaction(this.db, async (_db) => {
593
+ const timeoutAt = options?.timeout ? new Date(Date.now() + options.timeout) : null;
594
+ const { run: insertedRun, created } = await insertWorkflowRun({
595
+ resourceId,
596
+ workflowId,
597
+ currentStepId: "__start__",
598
+ status: "running" /* RUNNING */,
599
+ input,
600
+ maxRetries: options?.retries ?? 0,
601
+ timeoutAt,
602
+ idempotencyKey
603
+ }, _db);
604
+ if (created) {
605
+ const job = {
606
+ runId: insertedRun.id,
607
+ resourceId,
608
+ workflowId,
609
+ input
610
+ };
611
+ await this.boss.send(WORKFLOW_RUN_QUEUE_NAME, job, {
612
+ startAfter: new Date,
613
+ expireInSeconds: options?.expireInSeconds ?? defaultExpireInSeconds
614
+ });
615
+ }
616
+ return insertedRun;
617
+ }, this.pool);
618
+ this.logger.log(`${LOG_PREFIX} Started workflow run ${run.id} for ${workflowId}`);
619
+ return run;
620
+ }
621
+ async triggerEvent({
622
+ runId,
623
+ resourceId,
624
+ eventName,
625
+ data,
626
+ options
627
+ }) {
628
+ await this.ensureStarted();
629
+ const run = await this.getRun({ runId, resourceId });
630
+ const job = {
631
+ runId: run.id,
632
+ resourceId: resourceId ?? run.resourceId ?? undefined,
633
+ workflowId: run.workflowId,
634
+ input: run.input,
635
+ event: {
636
+ name: eventName,
637
+ data
638
+ }
639
+ };
640
+ await this.boss.send(WORKFLOW_RUN_QUEUE_NAME, job, {
641
+ expireInSeconds: options?.expireInSeconds ?? defaultExpireInSeconds
642
+ });
643
+ this.logger.log(`${LOG_PREFIX} Event ${eventName} sent for workflow run ${runId}`);
644
+ return run;
645
+ }
646
+ async pauseWorkflow({
647
+ runId,
648
+ resourceId
649
+ }) {
650
+ await this.ensureStarted();
651
+ const run = await updateWorkflowRun({
652
+ runId,
653
+ resourceId,
654
+ data: {
655
+ status: "paused" /* PAUSED */,
656
+ pausedAt: new Date
657
+ },
658
+ expectedStatuses: ["running" /* RUNNING */, "pending" /* PENDING */]
659
+ }, this.db);
660
+ if (!run) {
661
+ throw new WorkflowRunNotFoundError(runId);
662
+ }
663
+ this.logger.log(`${LOG_PREFIX} Paused workflow run ${runId}`);
664
+ return run;
665
+ }
666
+ async resumeWorkflow({
667
+ runId,
668
+ resourceId,
669
+ options
670
+ }) {
671
+ await this.ensureStarted();
672
+ const current = await this.getRun({ runId, resourceId });
673
+ if (current.status !== "paused" /* PAUSED */) {
674
+ throw new WorkflowEngineError(`Cannot resume workflow run in '${current.status}' status, must be 'paused'`, current.workflowId, runId);
675
+ }
676
+ return this.triggerEvent({
677
+ runId,
678
+ resourceId,
679
+ eventName: PAUSE_EVENT_NAME,
680
+ data: {},
681
+ options
682
+ });
683
+ }
684
+ async fastForwardWorkflow({
685
+ runId,
686
+ resourceId,
687
+ data
688
+ }) {
689
+ await this.ensureStarted();
690
+ const run = await this.getRun({ runId, resourceId });
691
+ if (run.status !== "paused" /* PAUSED */) {
692
+ return run;
693
+ }
694
+ const stepId = run.currentStepId;
695
+ const waitForEntry = run.timeline[`${stepId}-wait-for`];
696
+ if (!waitForEntry || typeof waitForEntry !== "object" || !("waitFor" in waitForEntry)) {
697
+ return run;
698
+ }
699
+ const { eventName, timeoutEvent, skipOutput } = waitForEntry.waitFor;
700
+ if (eventName === PAUSE_EVENT_NAME) {
701
+ return this.resumeWorkflow({ runId, resourceId });
702
+ }
703
+ if (skipOutput && timeoutEvent) {
704
+ await withPostgresTransaction(this.db, async (db) => {
705
+ const freshRun = await getWorkflowRun({ runId, resourceId }, { exclusiveLock: true, db });
706
+ if (!freshRun)
707
+ throw new WorkflowRunNotFoundError(runId);
708
+ return updateWorkflowRun({
709
+ runId,
710
+ resourceId,
711
+ data: {
712
+ timeline: import_es_toolkit.merge(freshRun.timeline, {
713
+ [stepId]: {
714
+ output: data ?? {},
715
+ timestamp: new Date
716
+ }
717
+ })
718
+ }
719
+ }, db);
720
+ }, this.pool);
721
+ return this.triggerEvent({ runId, resourceId, eventName: timeoutEvent });
722
+ }
723
+ if (eventName) {
724
+ return this.triggerEvent({ runId, resourceId, eventName, data: data ?? {} });
725
+ }
726
+ if (timeoutEvent) {
727
+ return this.triggerEvent({ runId, resourceId, eventName: timeoutEvent, data: data ?? {} });
728
+ }
729
+ return run;
730
+ }
731
+ async cancelWorkflow({
732
+ runId,
733
+ resourceId
734
+ }) {
735
+ await this.ensureStarted();
736
+ const run = await updateWorkflowRun({
737
+ runId,
738
+ resourceId,
739
+ data: {
740
+ status: "cancelled" /* CANCELLED */
741
+ },
742
+ expectedStatuses: ["pending" /* PENDING */, "running" /* RUNNING */, "paused" /* PAUSED */]
743
+ }, this.db);
744
+ if (!run) {
745
+ throw new WorkflowRunNotFoundError(runId);
746
+ }
747
+ this.logger.log(`${LOG_PREFIX} Cancelled workflow run ${runId}`);
748
+ return run;
749
+ }
750
+ async getRun({
751
+ runId,
752
+ resourceId
753
+ }) {
754
+ await this.ensureStarted();
755
+ const run = await getWorkflowRun({ runId, resourceId }, { db: this.db });
756
+ if (!run) {
757
+ throw new WorkflowRunNotFoundError(runId);
758
+ }
759
+ return run;
760
+ }
761
+ async checkProgress({
762
+ runId,
763
+ resourceId
764
+ }) {
765
+ const run = await this.getRun({ runId, resourceId });
766
+ const completedSteps = Object.values(run.timeline).filter((entry) => typeof entry === "object" && entry !== null && ("output" in entry) && entry.output !== undefined).length;
767
+ const totalSteps = run.status === "completed" /* COMPLETED */ ? completedSteps : 0;
768
+ const completionPercentage = run.status === "completed" /* COMPLETED */ ? 100 : run.status === "failed" /* FAILED */ || run.status === "cancelled" /* CANCELLED */ ? 0 : 0;
769
+ return {
770
+ ...run,
771
+ completedSteps,
772
+ completionPercentage,
773
+ totalSteps
774
+ };
775
+ }
776
+ async getRuns({
777
+ resourceId,
778
+ startingAfter,
779
+ endingBefore,
780
+ limit = 20,
781
+ statuses,
782
+ workflowId
783
+ }) {
784
+ await this.ensureStarted();
785
+ return getWorkflowRuns({
786
+ resourceId,
787
+ startingAfter,
788
+ endingBefore,
789
+ limit,
790
+ statuses,
791
+ workflowId
792
+ }, this.db);
793
+ }
794
+ async ensureStarted() {
795
+ if (!this._started) {
796
+ await this.start();
797
+ }
521
798
  }
522
- return mapRowToWorkflowRun(run);
523
799
  }
524
- async function getWorkflowRuns({
525
- resourceId,
526
- startingAfter,
527
- endingBefore,
528
- limit = 20,
529
- statuses,
530
- workflowId
531
- }, db) {
532
- const conditions = [];
533
- const values = [];
534
- let paramIndex = 1;
535
- if (resourceId) {
536
- conditions.push(`resource_id = $${paramIndex}`);
537
- values.push(resourceId);
538
- paramIndex++;
539
- }
540
- if (statuses && statuses.length > 0) {
541
- conditions.push(`status = ANY($${paramIndex})`);
542
- values.push(statuses);
543
- paramIndex++;
800
+ // src/definition.ts
801
+ function createWorkflowRef(id, options) {
802
+ const ref = (handler, defineOptions) => ({
803
+ id,
804
+ handler,
805
+ inputSchema: options?.inputSchema,
806
+ timeout: defineOptions?.timeout,
807
+ retries: defineOptions?.retries
808
+ });
809
+ Object.defineProperty(ref, "id", { value: id, enumerable: true });
810
+ Object.defineProperty(ref, "inputSchema", { value: options?.inputSchema, enumerable: true });
811
+ return ref;
812
+ }
813
+ function createWorkflowFactory(plugins = []) {
814
+ const factory = (id, handler, { inputSchema, timeout, retries } = {}) => ({
815
+ id,
816
+ handler,
817
+ inputSchema,
818
+ timeout,
819
+ retries,
820
+ plugins: plugins.length > 0 ? plugins : undefined
821
+ });
822
+ factory.use = (plugin) => createWorkflowFactory([
823
+ ...plugins,
824
+ plugin
825
+ ]);
826
+ factory.ref = createWorkflowRef;
827
+ return factory;
828
+ }
829
+ var workflow = createWorkflowFactory();
830
+ // src/duration.ts
831
+ var import_parse_duration = __toESM(require("parse-duration"));
832
+ var MS_PER_SECOND = 1000;
833
+ var MS_PER_MINUTE = 60 * MS_PER_SECOND;
834
+ var MS_PER_HOUR = 60 * MS_PER_MINUTE;
835
+ var MS_PER_DAY = 24 * MS_PER_HOUR;
836
+ var MS_PER_WEEK = 7 * MS_PER_DAY;
837
+ function parseDuration(duration) {
838
+ if (typeof duration === "string") {
839
+ if (duration.trim() === "") {
840
+ throw new WorkflowEngineError("Invalid duration: empty string");
841
+ }
842
+ const ms2 = import_parse_duration.default(duration);
843
+ if (ms2 == null || ms2 <= 0) {
844
+ throw new WorkflowEngineError(`Invalid duration: "${duration}"`);
845
+ }
846
+ return ms2;
544
847
  }
545
- if (workflowId) {
546
- conditions.push(`workflow_id = $${paramIndex}`);
547
- values.push(workflowId);
548
- paramIndex++;
848
+ const { weeks = 0, days = 0, hours = 0, minutes = 0, seconds = 0 } = duration;
849
+ const ms = weeks * MS_PER_WEEK + days * MS_PER_DAY + hours * MS_PER_HOUR + minutes * MS_PER_MINUTE + seconds * MS_PER_SECOND;
850
+ if (ms <= 0) {
851
+ throw new WorkflowEngineError("Invalid duration: must be a positive value");
549
852
  }
550
- const cursorIds = [startingAfter, endingBefore].filter(Boolean);
551
- if (cursorIds.length > 0) {
552
- const cursorResult = await db.executeSql("SELECT id, created_at FROM workflow_runs WHERE id = ANY($1)", [cursorIds]);
553
- const cursorMap = new Map;
554
- for (const row of cursorResult.rows) {
555
- cursorMap.set(row.id, typeof row.created_at === "string" ? new Date(row.created_at) : row.created_at);
556
- }
557
- if (startingAfter) {
558
- const cursor = cursorMap.get(startingAfter);
559
- if (cursor) {
560
- conditions.push(`created_at < $${paramIndex}`);
561
- values.push(cursor);
562
- paramIndex++;
853
+ return ms;
854
+ }
855
+ // src/engine.ts
856
+ var import_es_toolkit2 = require("es-toolkit");
857
+ var import_pg2 = __toESM(require("pg"));
858
+ var import_pg_boss2 = require("pg-boss");
859
+
860
+ // src/ast-parser.ts
861
+ var ts = __toESM(require("typescript"));
862
+ function parseWorkflowHandler(handler) {
863
+ const handlerSource = handler.toString();
864
+ const sourceFile = ts.createSourceFile("handler.ts", handlerSource, ts.ScriptTarget.Latest, true);
865
+ const steps = new Map;
866
+ function isInConditional(node) {
867
+ let current = node.parent;
868
+ while (current) {
869
+ if (ts.isIfStatement(current) || ts.isConditionalExpression(current) || ts.isSwitchStatement(current) || ts.isCaseClause(current)) {
870
+ return true;
563
871
  }
872
+ current = current.parent;
564
873
  }
565
- if (endingBefore) {
566
- const cursor = cursorMap.get(endingBefore);
567
- if (cursor) {
568
- conditions.push(`created_at > $${paramIndex}`);
569
- values.push(cursor);
570
- paramIndex++;
874
+ return false;
875
+ }
876
+ function isInLoop(node) {
877
+ let current = node.parent;
878
+ while (current) {
879
+ if (ts.isForStatement(current) || ts.isForInStatement(current) || ts.isForOfStatement(current) || ts.isWhileStatement(current) || ts.isDoStatement(current)) {
880
+ return true;
571
881
  }
882
+ current = current.parent;
572
883
  }
884
+ return false;
573
885
  }
574
- const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
575
- const actualLimit = Math.min(Math.max(limit, 1), 100) + 1;
576
- const isBackward = !!endingBefore && !startingAfter;
577
- const query = `
578
- SELECT * FROM workflow_runs
579
- ${whereClause}
580
- ORDER BY created_at ${isBackward ? "ASC" : "DESC"}
581
- LIMIT $${paramIndex}
582
- `;
583
- values.push(actualLimit);
584
- const result = await db.executeSql(query, values);
585
- const rows = result.rows;
586
- const hasExtraRow = rows.length > (limit ?? 20);
587
- const rawItems = hasExtraRow ? rows.slice(0, limit) : rows;
588
- if (isBackward) {
589
- rawItems.reverse();
590
- }
591
- const items = rawItems.map((row) => mapRowToWorkflowRun(row));
592
- const hasMore = isBackward ? items.length > 0 : hasExtraRow;
593
- const hasPrev = isBackward ? hasExtraRow : !!startingAfter && items.length > 0;
594
- const nextCursor = hasMore && items.length > 0 ? items[items.length - 1]?.id ?? null : null;
595
- const prevCursor = hasPrev && items.length > 0 ? items[0]?.id ?? null : null;
596
- return { items, nextCursor, prevCursor, hasMore, hasPrev };
597
- }
598
- async function withPostgresTransaction(db, callback, pool) {
599
- let txDb;
600
- let release;
601
- if (pool) {
602
- const client = await pool.connect();
603
- txDb = {
604
- executeSql: (text, values) => client.query(text, values)
605
- };
606
- release = () => client.release();
607
- } else {
608
- txDb = db;
886
+ function extractStepId(arg) {
887
+ if (ts.isStringLiteral(arg) || ts.isNoSubstitutionTemplateLiteral(arg)) {
888
+ return { id: arg.text, isDynamic: false };
889
+ }
890
+ if (ts.isTemplateExpression(arg)) {
891
+ let templateStr = arg.head.text;
892
+ for (const span of arg.templateSpans) {
893
+ templateStr += `\${...}`;
894
+ templateStr += span.literal.text;
895
+ }
896
+ return { id: templateStr, isDynamic: true };
897
+ }
898
+ return { id: arg.getText(sourceFile), isDynamic: true };
609
899
  }
610
- try {
611
- await txDb.executeSql("BEGIN", []);
612
- const result = await callback(txDb);
613
- await txDb.executeSql("COMMIT", []);
614
- return result;
615
- } catch (error) {
616
- await txDb.executeSql("ROLLBACK", []);
617
- throw error;
618
- } finally {
619
- release?.();
900
+ function visit(node) {
901
+ if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression)) {
902
+ const propertyAccess = node.expression;
903
+ const objectName = propertyAccess.expression.getText(sourceFile);
904
+ const methodName = propertyAccess.name.text;
905
+ if (objectName === "step" && (methodName === "run" || methodName === "waitFor" || methodName === "pause" || methodName === "waitUntil" || methodName === "delay" || methodName === "sleep" || methodName === "poll")) {
906
+ const firstArg = node.arguments[0];
907
+ if (firstArg) {
908
+ const { id, isDynamic } = extractStepId(firstArg);
909
+ const stepType = methodName === "sleep" ? "delay" /* DELAY */ : methodName;
910
+ const stepDefinition = {
911
+ id,
912
+ type: stepType,
913
+ conditional: isInConditional(node),
914
+ loop: isInLoop(node),
915
+ isDynamic
916
+ };
917
+ if (steps.has(id)) {
918
+ throw new Error(`Duplicate step ID detected: '${id}'. Step IDs must be unique within a workflow.`);
919
+ }
920
+ steps.set(id, stepDefinition);
921
+ }
922
+ }
923
+ }
924
+ ts.forEachChild(node, visit);
620
925
  }
926
+ visit(sourceFile);
927
+ return { steps: Array.from(steps.values()) };
621
928
  }
622
929
 
623
930
  // src/engine.ts
624
- var PAUSE_EVENT_NAME = "__internal_pause";
625
- var WORKFLOW_RUN_QUEUE_NAME = "workflow-run";
626
- var LOG_PREFIX = "[WorkflowEngine]";
627
- var DEFAULT_PGBOSS_SCHEMA = "pgboss_v12_pgworkflow";
931
+ var LOG_PREFIX2 = "[WorkflowEngine]";
628
932
  var StepTypeToIcon = {
629
933
  ["run" /* RUN */]: "λ",
630
934
  ["waitFor" /* WAIT_FOR */]: "○",
@@ -633,11 +937,11 @@ var StepTypeToIcon = {
633
937
  ["delay" /* DELAY */]: "⏱",
634
938
  ["poll" /* POLL */]: "↻"
635
939
  };
636
- var defaultLogger = {
940
+ var defaultLogger2 = {
637
941
  log: (_message) => console.warn(_message),
638
942
  error: (message, error) => console.error(message, error)
639
943
  };
640
- var defaultExpireInSeconds = process.env.WORKFLOW_RUN_EXPIRE_IN_SECONDS ? Number.parseInt(process.env.WORKFLOW_RUN_EXPIRE_IN_SECONDS, 10) : 5 * 60;
944
+ var defaultExpireInSeconds2 = process.env.WORKFLOW_RUN_EXPIRE_IN_SECONDS ? Number.parseInt(process.env.WORKFLOW_RUN_EXPIRE_IN_SECONDS, 10) : 5 * 60;
641
945
 
642
946
  class WorkflowEngine {
643
947
  boss;
@@ -649,11 +953,11 @@ class WorkflowEngine {
649
953
  workflows = new Map;
650
954
  logger;
651
955
  constructor({ workflows, logger, boss, ...connectionOptions }) {
652
- this.logger = this.buildLogger(logger ?? defaultLogger);
956
+ this.logger = this.buildLogger(logger ?? defaultLogger2);
653
957
  if ("pool" in connectionOptions && connectionOptions.pool) {
654
958
  this.pool = connectionOptions.pool;
655
959
  } else if ("connectionString" in connectionOptions && connectionOptions.connectionString) {
656
- this.pool = new import_pg.default.Pool({ connectionString: connectionOptions.connectionString });
960
+ this.pool = new import_pg2.default.Pool({ connectionString: connectionOptions.connectionString });
657
961
  this._ownsPool = true;
658
962
  } else {
659
963
  throw new WorkflowEngineError("Either pool or connectionString must be provided");
@@ -667,7 +971,7 @@ class WorkflowEngine {
667
971
  if (boss) {
668
972
  this.boss = boss;
669
973
  } else {
670
- this.boss = new import_pg_boss.PgBoss({ db, schema: DEFAULT_PGBOSS_SCHEMA });
974
+ this.boss = new import_pg_boss2.PgBoss({ db, schema: DEFAULT_PGBOSS_SCHEMA });
671
975
  }
672
976
  this.db = this.boss.getDb();
673
977
  }
@@ -731,13 +1035,26 @@ class WorkflowEngine {
731
1035
  this.workflows.clear();
732
1036
  return this;
733
1037
  }
734
- async startWorkflow({
735
- resourceId,
736
- workflowId,
737
- input,
738
- idempotencyKey,
739
- options
740
- }) {
1038
+ async startWorkflow(refOrParams, inputArg, optionsArg) {
1039
+ let workflowId;
1040
+ let input;
1041
+ let resourceId;
1042
+ let idempotencyKey;
1043
+ let options;
1044
+ if (typeof refOrParams === "function" && "id" in refOrParams) {
1045
+ workflowId = refOrParams.id;
1046
+ input = inputArg;
1047
+ options = optionsArg;
1048
+ resourceId = optionsArg?.resourceId;
1049
+ idempotencyKey = optionsArg?.idempotencyKey;
1050
+ } else {
1051
+ const params = refOrParams;
1052
+ workflowId = params.workflowId;
1053
+ input = params.input;
1054
+ resourceId = params.resourceId;
1055
+ idempotencyKey = params.idempotencyKey;
1056
+ options = params.options;
1057
+ }
741
1058
  if (!this._started) {
742
1059
  await this.start(false, { batchSize: options?.batchSize ?? 1 });
743
1060
  }
@@ -778,7 +1095,7 @@ class WorkflowEngine {
778
1095
  };
779
1096
  await this.boss.send(WORKFLOW_RUN_QUEUE_NAME, job, {
780
1097
  startAfter: new Date,
781
- expireInSeconds: options?.expireInSeconds ?? defaultExpireInSeconds
1098
+ expireInSeconds: options?.expireInSeconds ?? defaultExpireInSeconds2
782
1099
  });
783
1100
  }
784
1101
  return insertedRun;
@@ -853,7 +1170,7 @@ class WorkflowEngine {
853
1170
  runId,
854
1171
  resourceId,
855
1172
  data: {
856
- timeline: import_es_toolkit.merge(freshRun.timeline, {
1173
+ timeline: import_es_toolkit2.merge(freshRun.timeline, {
857
1174
  [stepId]: {
858
1175
  output: data ?? {},
859
1176
  timestamp: new Date
@@ -909,7 +1226,7 @@ class WorkflowEngine {
909
1226
  }
910
1227
  };
911
1228
  await this.boss.send(WORKFLOW_RUN_QUEUE_NAME, job, {
912
- expireInSeconds: options?.expireInSeconds ?? defaultExpireInSeconds
1229
+ expireInSeconds: options?.expireInSeconds ?? defaultExpireInSeconds2
913
1230
  });
914
1231
  this.logger.log(`event ${eventName} sent for workflow run with id ${runId}`);
915
1232
  return run;
@@ -988,27 +1305,29 @@ class WorkflowEngine {
988
1305
  return run.resourceId ?? undefined;
989
1306
  }
990
1307
  async handleWorkflowRun([job]) {
991
- const { runId, resourceId, workflowId, input, event } = job?.data ?? {};
992
- if (!runId) {
993
- throw new WorkflowEngineError("Invalid workflow run job, missing runId", workflowId);
994
- }
995
- if (!workflowId) {
996
- throw new WorkflowEngineError("Invalid workflow run job, missing workflowId", undefined, runId);
997
- }
998
- const workflow2 = this.workflows.get(workflowId);
999
- if (!workflow2) {
1000
- throw new WorkflowEngineError(`Workflow ${workflowId} not found`, workflowId, runId);
1001
- }
1002
- this.logger.log("Processing workflow run...", {
1003
- runId,
1004
- workflowId
1005
- });
1006
- let run = await this.getRun({ runId });
1007
- if (run.workflowId !== workflowId) {
1008
- throw new WorkflowEngineError(`Workflow run ${runId} does not match job workflowId ${workflowId}`, workflowId, runId);
1009
- }
1010
- const scopedResourceId = this.resolveScopedResourceId(resourceId, run);
1308
+ const { runId = "", resourceId, workflowId = "", input, event } = job?.data ?? {};
1309
+ let run;
1310
+ let scopedResourceId;
1011
1311
  try {
1312
+ if (!runId) {
1313
+ throw new WorkflowEngineError("Invalid workflow run job, missing runId", workflowId);
1314
+ }
1315
+ if (!workflowId) {
1316
+ throw new WorkflowEngineError("Invalid workflow run job, missing workflowId", undefined, runId);
1317
+ }
1318
+ const workflow2 = this.workflows.get(workflowId);
1319
+ if (!workflow2) {
1320
+ throw new WorkflowEngineError(`Workflow ${workflowId} not found`, workflowId, runId);
1321
+ }
1322
+ this.logger.log("Processing workflow run...", {
1323
+ runId,
1324
+ workflowId
1325
+ });
1326
+ run = await this.getRun({ runId });
1327
+ if (run.workflowId !== workflowId) {
1328
+ throw new WorkflowEngineError(`Workflow run ${runId} does not match job workflowId ${workflowId}`, workflowId, runId);
1329
+ }
1330
+ scopedResourceId = this.resolveScopedResourceId(resourceId, run);
1012
1331
  if (run.status === "cancelled" /* CANCELLED */) {
1013
1332
  this.logger.log(`Workflow run ${runId} is cancelled, skipping`);
1014
1333
  return;
@@ -1039,7 +1358,7 @@ class WorkflowEngine {
1039
1358
  resumedAt: new Date,
1040
1359
  jobId: job?.id,
1041
1360
  ...skipOutput ? {} : {
1042
- timeline: import_es_toolkit.merge(lockedRun.timeline, {
1361
+ timeline: import_es_toolkit2.merge(lockedRun.timeline, {
1043
1362
  [lockedRun.currentStepId]: {
1044
1363
  output: event?.data ?? {},
1045
1364
  ...isTimeout ? { timedOut: true } : {},
@@ -1152,7 +1471,7 @@ class WorkflowEngine {
1152
1471
  });
1153
1472
  }
1154
1473
  } catch (error) {
1155
- if (run.retryCount < run.maxRetries) {
1474
+ if (run && run.retryCount < run.maxRetries) {
1156
1475
  await this.updateRun({
1157
1476
  runId,
1158
1477
  resourceId: scopedResourceId,
@@ -1170,19 +1489,21 @@ class WorkflowEngine {
1170
1489
  };
1171
1490
  await this.boss?.send("workflow-run", pgBossJob, {
1172
1491
  startAfter: new Date(Date.now() + retryDelay),
1173
- expireInSeconds: defaultExpireInSeconds
1492
+ expireInSeconds: defaultExpireInSeconds2
1174
1493
  });
1175
1494
  return;
1176
1495
  }
1177
- await this.updateRun({
1178
- runId,
1179
- resourceId: scopedResourceId,
1180
- data: {
1181
- status: "failed" /* FAILED */,
1182
- error: error instanceof Error ? error.message : String(error),
1183
- jobId: job?.id
1184
- }
1185
- });
1496
+ if (runId) {
1497
+ await this.updateRun({
1498
+ runId,
1499
+ resourceId: scopedResourceId,
1500
+ data: {
1501
+ status: "failed" /* FAILED */,
1502
+ error: error instanceof Error ? error.message : String(error),
1503
+ jobId: job?.id
1504
+ }
1505
+ });
1506
+ }
1186
1507
  throw error;
1187
1508
  }
1188
1509
  }
@@ -1235,7 +1556,7 @@ class WorkflowEngine {
1235
1556
  runId: run.id,
1236
1557
  resourceId: run.resourceId ?? undefined,
1237
1558
  data: {
1238
- timeline: import_es_toolkit.merge(persistedRun.timeline, {
1559
+ timeline: import_es_toolkit2.merge(persistedRun.timeline, {
1239
1560
  [stepId]: {
1240
1561
  output,
1241
1562
  timestamp: new Date
@@ -1289,7 +1610,7 @@ ${error.stack}` : String(error)
1289
1610
  status: "paused" /* PAUSED */,
1290
1611
  currentStepId: stepId,
1291
1612
  pausedAt: new Date,
1292
- timeline: import_es_toolkit.merge(freshRun.timeline, {
1613
+ timeline: import_es_toolkit2.merge(freshRun.timeline, {
1293
1614
  [`${stepId}-wait-for`]: {
1294
1615
  waitFor: { eventName, timeoutEvent },
1295
1616
  timestamp: new Date
@@ -1309,7 +1630,7 @@ ${error.stack}` : String(error)
1309
1630
  };
1310
1631
  await this.boss.send(WORKFLOW_RUN_QUEUE_NAME, job, {
1311
1632
  startAfter: timeoutDate.getTime() <= Date.now() ? new Date : timeoutDate,
1312
- expireInSeconds: defaultExpireInSeconds
1633
+ expireInSeconds: defaultExpireInSeconds2
1313
1634
  });
1314
1635
  } catch (error) {
1315
1636
  await this.updateRun({
@@ -1350,7 +1671,7 @@ ${error.stack}` : String(error)
1350
1671
  resourceId: run.resourceId ?? undefined,
1351
1672
  data: {
1352
1673
  currentStepId: stepId,
1353
- timeline: import_es_toolkit.merge(freshRun.timeline, {
1674
+ timeline: import_es_toolkit2.merge(freshRun.timeline, {
1354
1675
  [stepId]: { output: {}, timedOut: true, timestamp: new Date }
1355
1676
  })
1356
1677
  }
@@ -1371,7 +1692,7 @@ ${error.stack}` : String(error)
1371
1692
  resourceId: run.resourceId ?? undefined,
1372
1693
  data: {
1373
1694
  currentStepId: stepId,
1374
- timeline: import_es_toolkit.merge(freshRun.timeline, {
1695
+ timeline: import_es_toolkit2.merge(freshRun.timeline, {
1375
1696
  [stepId]: { output: {}, timedOut: true, timestamp: new Date }
1376
1697
  })
1377
1698
  }
@@ -1389,7 +1710,7 @@ ${error.stack}` : String(error)
1389
1710
  resourceId: run.resourceId ?? undefined,
1390
1711
  data: {
1391
1712
  currentStepId: stepId,
1392
- timeline: import_es_toolkit.merge(freshRun.timeline, {
1713
+ timeline: import_es_toolkit2.merge(freshRun.timeline, {
1393
1714
  [stepId]: { output: result, timestamp: new Date }
1394
1715
  })
1395
1716
  }
@@ -1407,7 +1728,7 @@ ${error.stack}` : String(error)
1407
1728
  status: "paused" /* PAUSED */,
1408
1729
  currentStepId: stepId,
1409
1730
  pausedAt: new Date,
1410
- timeline: import_es_toolkit.merge(freshRun.timeline, {
1731
+ timeline: import_es_toolkit2.merge(freshRun.timeline, {
1411
1732
  [`${stepId}-poll`]: { startedAt: startedAt.toISOString() },
1412
1733
  [`${stepId}-wait-for`]: {
1413
1734
  waitFor: { timeoutEvent: pollEvent, skipOutput: true },
@@ -1426,7 +1747,7 @@ ${error.stack}` : String(error)
1426
1747
  event: { name: pollEvent, data: {} }
1427
1748
  }, {
1428
1749
  startAfter: new Date(Date.now() + intervalMs),
1429
- expireInSeconds: defaultExpireInSeconds
1750
+ expireInSeconds: defaultExpireInSeconds2
1430
1751
  });
1431
1752
  } catch (error) {
1432
1753
  await this.updateRun({
@@ -1451,12 +1772,12 @@ ${error.stack}` : String(error)
1451
1772
  return {
1452
1773
  log: (message, context) => {
1453
1774
  const { runId, workflowId } = context ?? {};
1454
- const parts = [LOG_PREFIX, workflowId, runId].filter(Boolean).join(" ");
1775
+ const parts = [LOG_PREFIX2, workflowId, runId].filter(Boolean).join(" ");
1455
1776
  logger.log(`${parts}: ${message}`);
1456
1777
  },
1457
1778
  error: (message, error, context) => {
1458
1779
  const { runId, workflowId } = context ?? {};
1459
- const parts = [LOG_PREFIX, workflowId, runId].filter(Boolean).join(" ");
1780
+ const parts = [LOG_PREFIX2, workflowId, runId].filter(Boolean).join(" ");
1460
1781
  logger.error(`${parts}: ${message}`, error);
1461
1782
  }
1462
1783
  };
@@ -1480,5 +1801,5 @@ ${error.stack}` : String(error)
1480
1801
  }
1481
1802
  }
1482
1803
 
1483
- //# debugId=644364C840A9480364756E2164756E21
1804
+ //# debugId=8707EFFDC2423EEE64756E2164756E21
1484
1805
  //# sourceMappingURL=index.js.map