pg-workflows 0.7.1 → 0.8.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/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,578 @@ 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 options;
570
+ if (typeof refOrParams === "function" && "id" in refOrParams) {
571
+ const ref = refOrParams;
572
+ workflowId = ref.id;
573
+ input = inputArg;
574
+ options = optionsArg;
575
+ resourceId = optionsArg?.resourceId;
576
+ if (ref.inputSchema) {
577
+ const result = await ref.inputSchema["~standard"].validate(input);
578
+ if (result.issues) {
579
+ throw new WorkflowEngineError(JSON.stringify(result.issues), workflowId, undefined, undefined, result.issues);
580
+ }
581
+ }
582
+ } else {
583
+ const params = refOrParams;
584
+ workflowId = params.workflowId;
585
+ input = params.input;
586
+ resourceId = params.resourceId;
587
+ options = params.options;
588
+ }
589
+ const run = await withPostgresTransaction(this.db, async (_db) => {
590
+ const timeoutAt = options?.timeout ? new Date(Date.now() + options.timeout) : null;
591
+ const { run: insertedRun, created } = await insertWorkflowRun({
592
+ resourceId,
593
+ workflowId,
594
+ currentStepId: "__start__",
595
+ status: "running" /* RUNNING */,
596
+ input,
597
+ maxRetries: options?.retries ?? 0,
598
+ timeoutAt
599
+ }, _db);
600
+ if (created) {
601
+ const job = {
602
+ runId: insertedRun.id,
603
+ resourceId,
604
+ workflowId,
605
+ input
606
+ };
607
+ await this.boss.send(WORKFLOW_RUN_QUEUE_NAME, job, {
608
+ startAfter: new Date,
609
+ expireInSeconds: options?.expireInSeconds ?? defaultExpireInSeconds
610
+ });
611
+ }
612
+ return insertedRun;
613
+ }, this.pool);
614
+ this.logger.log(`${LOG_PREFIX} Started workflow run ${run.id} for ${workflowId}`);
615
+ return run;
616
+ }
617
+ async triggerEvent({
618
+ runId,
619
+ resourceId,
620
+ eventName,
621
+ data,
622
+ options
623
+ }) {
624
+ await this.ensureStarted();
625
+ const run = await this.getRun({ runId, resourceId });
626
+ const job = {
627
+ runId: run.id,
628
+ resourceId: resourceId ?? run.resourceId ?? undefined,
629
+ workflowId: run.workflowId,
630
+ input: run.input,
631
+ event: {
632
+ name: eventName,
633
+ data
634
+ }
635
+ };
636
+ await this.boss.send(WORKFLOW_RUN_QUEUE_NAME, job, {
637
+ expireInSeconds: options?.expireInSeconds ?? defaultExpireInSeconds
638
+ });
639
+ this.logger.log(`${LOG_PREFIX} Event ${eventName} sent for workflow run ${runId}`);
640
+ return run;
641
+ }
642
+ async pauseWorkflow({
643
+ runId,
644
+ resourceId
645
+ }) {
646
+ await this.ensureStarted();
647
+ const run = await updateWorkflowRun({
648
+ runId,
649
+ resourceId,
650
+ data: {
651
+ status: "paused" /* PAUSED */,
652
+ pausedAt: new Date
653
+ },
654
+ expectedStatuses: ["running" /* RUNNING */, "pending" /* PENDING */]
655
+ }, this.db);
656
+ if (!run) {
657
+ throw new WorkflowRunNotFoundError(runId);
658
+ }
659
+ this.logger.log(`${LOG_PREFIX} Paused workflow run ${runId}`);
660
+ return run;
661
+ }
662
+ async resumeWorkflow({
663
+ runId,
664
+ resourceId,
665
+ options
666
+ }) {
667
+ await this.ensureStarted();
668
+ const current = await this.getRun({ runId, resourceId });
669
+ if (current.status !== "paused" /* PAUSED */) {
670
+ throw new WorkflowEngineError(`Cannot resume workflow run in '${current.status}' status, must be 'paused'`, current.workflowId, runId);
671
+ }
672
+ return this.triggerEvent({
673
+ runId,
674
+ resourceId,
675
+ eventName: PAUSE_EVENT_NAME,
676
+ data: {},
677
+ options
678
+ });
679
+ }
680
+ async fastForwardWorkflow({
681
+ runId,
682
+ resourceId,
683
+ data
684
+ }) {
685
+ await this.ensureStarted();
686
+ const run = await this.getRun({ runId, resourceId });
687
+ if (run.status !== "paused" /* PAUSED */) {
688
+ return run;
689
+ }
690
+ const stepId = run.currentStepId;
691
+ const waitForEntry = run.timeline[`${stepId}-wait-for`];
692
+ if (!waitForEntry || typeof waitForEntry !== "object" || !("waitFor" in waitForEntry)) {
693
+ return run;
694
+ }
695
+ const { eventName, timeoutEvent, skipOutput } = waitForEntry.waitFor;
696
+ if (eventName === PAUSE_EVENT_NAME) {
697
+ return this.resumeWorkflow({ runId, resourceId });
698
+ }
699
+ if (skipOutput && timeoutEvent) {
700
+ await withPostgresTransaction(this.db, async (db) => {
701
+ const freshRun = await getWorkflowRun({ runId, resourceId }, { exclusiveLock: true, db });
702
+ if (!freshRun)
703
+ throw new WorkflowRunNotFoundError(runId);
704
+ return updateWorkflowRun({
705
+ runId,
706
+ resourceId,
707
+ data: {
708
+ timeline: import_es_toolkit.merge(freshRun.timeline, {
709
+ [stepId]: {
710
+ output: data ?? {},
711
+ timestamp: new Date
712
+ }
713
+ })
714
+ }
715
+ }, db);
716
+ }, this.pool);
717
+ return this.triggerEvent({ runId, resourceId, eventName: timeoutEvent });
718
+ }
719
+ if (eventName) {
720
+ return this.triggerEvent({ runId, resourceId, eventName, data: data ?? {} });
721
+ }
722
+ if (timeoutEvent) {
723
+ return this.triggerEvent({ runId, resourceId, eventName: timeoutEvent, data: data ?? {} });
724
+ }
725
+ return run;
726
+ }
727
+ async cancelWorkflow({
728
+ runId,
729
+ resourceId
730
+ }) {
731
+ await this.ensureStarted();
732
+ const run = await updateWorkflowRun({
733
+ runId,
734
+ resourceId,
735
+ data: {
736
+ status: "cancelled" /* CANCELLED */
737
+ },
738
+ expectedStatuses: ["pending" /* PENDING */, "running" /* RUNNING */, "paused" /* PAUSED */]
739
+ }, this.db);
740
+ if (!run) {
741
+ throw new WorkflowRunNotFoundError(runId);
742
+ }
743
+ this.logger.log(`${LOG_PREFIX} Cancelled workflow run ${runId}`);
744
+ return run;
745
+ }
746
+ async getRun({
747
+ runId,
748
+ resourceId
749
+ }) {
750
+ await this.ensureStarted();
751
+ const run = await getWorkflowRun({ runId, resourceId }, { db: this.db });
752
+ if (!run) {
753
+ throw new WorkflowRunNotFoundError(runId);
754
+ }
755
+ return run;
756
+ }
757
+ async checkProgress({
758
+ runId,
759
+ resourceId
760
+ }) {
761
+ const run = await this.getRun({ runId, resourceId });
762
+ const completedSteps = Object.values(run.timeline).filter((entry) => typeof entry === "object" && entry !== null && ("output" in entry) && entry.output !== undefined).length;
763
+ const totalSteps = run.status === "completed" /* COMPLETED */ ? completedSteps : 0;
764
+ const completionPercentage = run.status === "completed" /* COMPLETED */ ? 100 : run.status === "failed" /* FAILED */ || run.status === "cancelled" /* CANCELLED */ ? 0 : 0;
765
+ return {
766
+ ...run,
767
+ completedSteps,
768
+ completionPercentage,
769
+ totalSteps
770
+ };
771
+ }
772
+ async getRuns({
773
+ resourceId,
774
+ startingAfter,
775
+ endingBefore,
776
+ limit = 20,
777
+ statuses,
778
+ workflowId
779
+ }) {
780
+ await this.ensureStarted();
781
+ return getWorkflowRuns({
782
+ resourceId,
783
+ startingAfter,
784
+ endingBefore,
785
+ limit,
786
+ statuses,
787
+ workflowId
788
+ }, this.db);
789
+ }
790
+ async ensureStarted() {
791
+ if (!this._started) {
792
+ await this.start();
793
+ }
521
794
  }
522
- return mapRowToWorkflowRun(run);
523
795
  }
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++;
796
+ // src/definition.ts
797
+ function createWorkflowRef(id, options) {
798
+ const ref = (handler, defineOptions) => ({
799
+ id,
800
+ handler,
801
+ inputSchema: options?.inputSchema,
802
+ timeout: defineOptions?.timeout,
803
+ retries: defineOptions?.retries
804
+ });
805
+ Object.defineProperty(ref, "id", { value: id, enumerable: true });
806
+ Object.defineProperty(ref, "inputSchema", { value: options?.inputSchema, enumerable: true });
807
+ return ref;
808
+ }
809
+ function createWorkflowFactory(plugins = []) {
810
+ const factory = (id, handler, { inputSchema, timeout, retries } = {}) => ({
811
+ id,
812
+ handler,
813
+ inputSchema,
814
+ timeout,
815
+ retries,
816
+ plugins: plugins.length > 0 ? plugins : undefined
817
+ });
818
+ factory.use = (plugin) => createWorkflowFactory([
819
+ ...plugins,
820
+ plugin
821
+ ]);
822
+ factory.ref = createWorkflowRef;
823
+ return factory;
824
+ }
825
+ var workflow = createWorkflowFactory();
826
+ // src/duration.ts
827
+ var import_parse_duration = __toESM(require("parse-duration"));
828
+ var MS_PER_SECOND = 1000;
829
+ var MS_PER_MINUTE = 60 * MS_PER_SECOND;
830
+ var MS_PER_HOUR = 60 * MS_PER_MINUTE;
831
+ var MS_PER_DAY = 24 * MS_PER_HOUR;
832
+ var MS_PER_WEEK = 7 * MS_PER_DAY;
833
+ function parseDuration(duration) {
834
+ if (typeof duration === "string") {
835
+ if (duration.trim() === "") {
836
+ throw new WorkflowEngineError("Invalid duration: empty string");
837
+ }
838
+ const ms2 = import_parse_duration.default(duration);
839
+ if (ms2 == null || ms2 <= 0) {
840
+ throw new WorkflowEngineError(`Invalid duration: "${duration}"`);
841
+ }
842
+ return ms2;
544
843
  }
545
- if (workflowId) {
546
- conditions.push(`workflow_id = $${paramIndex}`);
547
- values.push(workflowId);
548
- paramIndex++;
844
+ const { weeks = 0, days = 0, hours = 0, minutes = 0, seconds = 0 } = duration;
845
+ const ms = weeks * MS_PER_WEEK + days * MS_PER_DAY + hours * MS_PER_HOUR + minutes * MS_PER_MINUTE + seconds * MS_PER_SECOND;
846
+ if (ms <= 0) {
847
+ throw new WorkflowEngineError("Invalid duration: must be a positive value");
549
848
  }
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++;
849
+ return ms;
850
+ }
851
+ // src/engine.ts
852
+ var import_es_toolkit2 = require("es-toolkit");
853
+ var import_pg2 = __toESM(require("pg"));
854
+ var import_pg_boss2 = require("pg-boss");
855
+
856
+ // src/ast-parser.ts
857
+ var ts = __toESM(require("typescript"));
858
+ function parseWorkflowHandler(handler) {
859
+ const handlerSource = handler.toString();
860
+ const sourceFile = ts.createSourceFile("handler.ts", handlerSource, ts.ScriptTarget.Latest, true);
861
+ const steps = new Map;
862
+ function isInConditional(node) {
863
+ let current = node.parent;
864
+ while (current) {
865
+ if (ts.isIfStatement(current) || ts.isConditionalExpression(current) || ts.isSwitchStatement(current) || ts.isCaseClause(current)) {
866
+ return true;
563
867
  }
868
+ current = current.parent;
564
869
  }
565
- if (endingBefore) {
566
- const cursor = cursorMap.get(endingBefore);
567
- if (cursor) {
568
- conditions.push(`created_at > $${paramIndex}`);
569
- values.push(cursor);
570
- paramIndex++;
870
+ return false;
871
+ }
872
+ function isInLoop(node) {
873
+ let current = node.parent;
874
+ while (current) {
875
+ if (ts.isForStatement(current) || ts.isForInStatement(current) || ts.isForOfStatement(current) || ts.isWhileStatement(current) || ts.isDoStatement(current)) {
876
+ return true;
571
877
  }
878
+ current = current.parent;
572
879
  }
880
+ return false;
573
881
  }
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;
882
+ function extractStepId(arg) {
883
+ if (ts.isStringLiteral(arg) || ts.isNoSubstitutionTemplateLiteral(arg)) {
884
+ return { id: arg.text, isDynamic: false };
885
+ }
886
+ if (ts.isTemplateExpression(arg)) {
887
+ let templateStr = arg.head.text;
888
+ for (const span of arg.templateSpans) {
889
+ templateStr += `\${...}`;
890
+ templateStr += span.literal.text;
891
+ }
892
+ return { id: templateStr, isDynamic: true };
893
+ }
894
+ return { id: arg.getText(sourceFile), isDynamic: true };
609
895
  }
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?.();
896
+ function visit(node) {
897
+ if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression)) {
898
+ const propertyAccess = node.expression;
899
+ const objectName = propertyAccess.expression.getText(sourceFile);
900
+ const methodName = propertyAccess.name.text;
901
+ if (objectName === "step" && (methodName === "run" || methodName === "waitFor" || methodName === "pause" || methodName === "waitUntil" || methodName === "delay" || methodName === "sleep" || methodName === "poll")) {
902
+ const firstArg = node.arguments[0];
903
+ if (firstArg) {
904
+ const { id, isDynamic } = extractStepId(firstArg);
905
+ const stepType = methodName === "sleep" ? "delay" /* DELAY */ : methodName;
906
+ const stepDefinition = {
907
+ id,
908
+ type: stepType,
909
+ conditional: isInConditional(node),
910
+ loop: isInLoop(node),
911
+ isDynamic
912
+ };
913
+ if (steps.has(id)) {
914
+ throw new Error(`Duplicate step ID detected: '${id}'. Step IDs must be unique within a workflow.`);
915
+ }
916
+ steps.set(id, stepDefinition);
917
+ }
918
+ }
919
+ }
920
+ ts.forEachChild(node, visit);
620
921
  }
922
+ visit(sourceFile);
923
+ return { steps: Array.from(steps.values()) };
621
924
  }
622
925
 
623
926
  // 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";
927
+ var LOG_PREFIX2 = "[WorkflowEngine]";
628
928
  var StepTypeToIcon = {
629
929
  ["run" /* RUN */]: "λ",
630
930
  ["waitFor" /* WAIT_FOR */]: "○",
@@ -633,11 +933,11 @@ var StepTypeToIcon = {
633
933
  ["delay" /* DELAY */]: "⏱",
634
934
  ["poll" /* POLL */]: "↻"
635
935
  };
636
- var defaultLogger = {
936
+ var defaultLogger2 = {
637
937
  log: (_message) => console.warn(_message),
638
938
  error: (message, error) => console.error(message, error)
639
939
  };
640
- var defaultExpireInSeconds = process.env.WORKFLOW_RUN_EXPIRE_IN_SECONDS ? Number.parseInt(process.env.WORKFLOW_RUN_EXPIRE_IN_SECONDS, 10) : 5 * 60;
940
+ var defaultExpireInSeconds2 = process.env.WORKFLOW_RUN_EXPIRE_IN_SECONDS ? Number.parseInt(process.env.WORKFLOW_RUN_EXPIRE_IN_SECONDS, 10) : 5 * 60;
641
941
 
642
942
  class WorkflowEngine {
643
943
  boss;
@@ -649,11 +949,11 @@ class WorkflowEngine {
649
949
  workflows = new Map;
650
950
  logger;
651
951
  constructor({ workflows, logger, boss, ...connectionOptions }) {
652
- this.logger = this.buildLogger(logger ?? defaultLogger);
952
+ this.logger = this.buildLogger(logger ?? defaultLogger2);
653
953
  if ("pool" in connectionOptions && connectionOptions.pool) {
654
954
  this.pool = connectionOptions.pool;
655
955
  } else if ("connectionString" in connectionOptions && connectionOptions.connectionString) {
656
- this.pool = new import_pg.default.Pool({ connectionString: connectionOptions.connectionString });
956
+ this.pool = new import_pg2.default.Pool({ connectionString: connectionOptions.connectionString });
657
957
  this._ownsPool = true;
658
958
  } else {
659
959
  throw new WorkflowEngineError("Either pool or connectionString must be provided");
@@ -667,7 +967,7 @@ class WorkflowEngine {
667
967
  if (boss) {
668
968
  this.boss = boss;
669
969
  } else {
670
- this.boss = new import_pg_boss.PgBoss({ db, schema: DEFAULT_PGBOSS_SCHEMA });
970
+ this.boss = new import_pg_boss2.PgBoss({ db, schema: DEFAULT_PGBOSS_SCHEMA });
671
971
  }
672
972
  this.db = this.boss.getDb();
673
973
  }
@@ -731,13 +1031,26 @@ class WorkflowEngine {
731
1031
  this.workflows.clear();
732
1032
  return this;
733
1033
  }
734
- async startWorkflow({
735
- resourceId,
736
- workflowId,
737
- input,
738
- idempotencyKey,
739
- options
740
- }) {
1034
+ async startWorkflow(refOrParams, inputArg, optionsArg) {
1035
+ let workflowId;
1036
+ let input;
1037
+ let resourceId;
1038
+ let idempotencyKey;
1039
+ let options;
1040
+ if (typeof refOrParams === "function" && "id" in refOrParams) {
1041
+ workflowId = refOrParams.id;
1042
+ input = inputArg;
1043
+ options = optionsArg;
1044
+ resourceId = optionsArg?.resourceId;
1045
+ idempotencyKey = optionsArg?.idempotencyKey;
1046
+ } else {
1047
+ const params = refOrParams;
1048
+ workflowId = params.workflowId;
1049
+ input = params.input;
1050
+ resourceId = params.resourceId;
1051
+ idempotencyKey = params.idempotencyKey;
1052
+ options = params.options;
1053
+ }
741
1054
  if (!this._started) {
742
1055
  await this.start(false, { batchSize: options?.batchSize ?? 1 });
743
1056
  }
@@ -778,7 +1091,7 @@ class WorkflowEngine {
778
1091
  };
779
1092
  await this.boss.send(WORKFLOW_RUN_QUEUE_NAME, job, {
780
1093
  startAfter: new Date,
781
- expireInSeconds: options?.expireInSeconds ?? defaultExpireInSeconds
1094
+ expireInSeconds: options?.expireInSeconds ?? defaultExpireInSeconds2
782
1095
  });
783
1096
  }
784
1097
  return insertedRun;
@@ -853,7 +1166,7 @@ class WorkflowEngine {
853
1166
  runId,
854
1167
  resourceId,
855
1168
  data: {
856
- timeline: import_es_toolkit.merge(freshRun.timeline, {
1169
+ timeline: import_es_toolkit2.merge(freshRun.timeline, {
857
1170
  [stepId]: {
858
1171
  output: data ?? {},
859
1172
  timestamp: new Date
@@ -909,7 +1222,7 @@ class WorkflowEngine {
909
1222
  }
910
1223
  };
911
1224
  await this.boss.send(WORKFLOW_RUN_QUEUE_NAME, job, {
912
- expireInSeconds: options?.expireInSeconds ?? defaultExpireInSeconds
1225
+ expireInSeconds: options?.expireInSeconds ?? defaultExpireInSeconds2
913
1226
  });
914
1227
  this.logger.log(`event ${eventName} sent for workflow run with id ${runId}`);
915
1228
  return run;
@@ -988,27 +1301,29 @@ class WorkflowEngine {
988
1301
  return run.resourceId ?? undefined;
989
1302
  }
990
1303
  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);
1304
+ const { runId = "", resourceId, workflowId = "", input, event } = job?.data ?? {};
1305
+ let run;
1306
+ let scopedResourceId;
1011
1307
  try {
1308
+ if (!runId) {
1309
+ throw new WorkflowEngineError("Invalid workflow run job, missing runId", workflowId);
1310
+ }
1311
+ if (!workflowId) {
1312
+ throw new WorkflowEngineError("Invalid workflow run job, missing workflowId", undefined, runId);
1313
+ }
1314
+ const workflow2 = this.workflows.get(workflowId);
1315
+ if (!workflow2) {
1316
+ throw new WorkflowEngineError(`Workflow ${workflowId} not found`, workflowId, runId);
1317
+ }
1318
+ this.logger.log("Processing workflow run...", {
1319
+ runId,
1320
+ workflowId
1321
+ });
1322
+ run = await this.getRun({ runId });
1323
+ if (run.workflowId !== workflowId) {
1324
+ throw new WorkflowEngineError(`Workflow run ${runId} does not match job workflowId ${workflowId}`, workflowId, runId);
1325
+ }
1326
+ scopedResourceId = this.resolveScopedResourceId(resourceId, run);
1012
1327
  if (run.status === "cancelled" /* CANCELLED */) {
1013
1328
  this.logger.log(`Workflow run ${runId} is cancelled, skipping`);
1014
1329
  return;
@@ -1039,7 +1354,7 @@ class WorkflowEngine {
1039
1354
  resumedAt: new Date,
1040
1355
  jobId: job?.id,
1041
1356
  ...skipOutput ? {} : {
1042
- timeline: import_es_toolkit.merge(lockedRun.timeline, {
1357
+ timeline: import_es_toolkit2.merge(lockedRun.timeline, {
1043
1358
  [lockedRun.currentStepId]: {
1044
1359
  output: event?.data ?? {},
1045
1360
  ...isTimeout ? { timedOut: true } : {},
@@ -1152,7 +1467,7 @@ class WorkflowEngine {
1152
1467
  });
1153
1468
  }
1154
1469
  } catch (error) {
1155
- if (run.retryCount < run.maxRetries) {
1470
+ if (run && run.retryCount < run.maxRetries) {
1156
1471
  await this.updateRun({
1157
1472
  runId,
1158
1473
  resourceId: scopedResourceId,
@@ -1170,19 +1485,21 @@ class WorkflowEngine {
1170
1485
  };
1171
1486
  await this.boss?.send("workflow-run", pgBossJob, {
1172
1487
  startAfter: new Date(Date.now() + retryDelay),
1173
- expireInSeconds: defaultExpireInSeconds
1488
+ expireInSeconds: defaultExpireInSeconds2
1174
1489
  });
1175
1490
  return;
1176
1491
  }
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
- });
1492
+ if (runId) {
1493
+ await this.updateRun({
1494
+ runId,
1495
+ resourceId: scopedResourceId,
1496
+ data: {
1497
+ status: "failed" /* FAILED */,
1498
+ error: error instanceof Error ? error.message : String(error),
1499
+ jobId: job?.id
1500
+ }
1501
+ });
1502
+ }
1186
1503
  throw error;
1187
1504
  }
1188
1505
  }
@@ -1235,7 +1552,7 @@ class WorkflowEngine {
1235
1552
  runId: run.id,
1236
1553
  resourceId: run.resourceId ?? undefined,
1237
1554
  data: {
1238
- timeline: import_es_toolkit.merge(persistedRun.timeline, {
1555
+ timeline: import_es_toolkit2.merge(persistedRun.timeline, {
1239
1556
  [stepId]: {
1240
1557
  output,
1241
1558
  timestamp: new Date
@@ -1289,7 +1606,7 @@ ${error.stack}` : String(error)
1289
1606
  status: "paused" /* PAUSED */,
1290
1607
  currentStepId: stepId,
1291
1608
  pausedAt: new Date,
1292
- timeline: import_es_toolkit.merge(freshRun.timeline, {
1609
+ timeline: import_es_toolkit2.merge(freshRun.timeline, {
1293
1610
  [`${stepId}-wait-for`]: {
1294
1611
  waitFor: { eventName, timeoutEvent },
1295
1612
  timestamp: new Date
@@ -1309,7 +1626,7 @@ ${error.stack}` : String(error)
1309
1626
  };
1310
1627
  await this.boss.send(WORKFLOW_RUN_QUEUE_NAME, job, {
1311
1628
  startAfter: timeoutDate.getTime() <= Date.now() ? new Date : timeoutDate,
1312
- expireInSeconds: defaultExpireInSeconds
1629
+ expireInSeconds: defaultExpireInSeconds2
1313
1630
  });
1314
1631
  } catch (error) {
1315
1632
  await this.updateRun({
@@ -1350,7 +1667,7 @@ ${error.stack}` : String(error)
1350
1667
  resourceId: run.resourceId ?? undefined,
1351
1668
  data: {
1352
1669
  currentStepId: stepId,
1353
- timeline: import_es_toolkit.merge(freshRun.timeline, {
1670
+ timeline: import_es_toolkit2.merge(freshRun.timeline, {
1354
1671
  [stepId]: { output: {}, timedOut: true, timestamp: new Date }
1355
1672
  })
1356
1673
  }
@@ -1371,7 +1688,7 @@ ${error.stack}` : String(error)
1371
1688
  resourceId: run.resourceId ?? undefined,
1372
1689
  data: {
1373
1690
  currentStepId: stepId,
1374
- timeline: import_es_toolkit.merge(freshRun.timeline, {
1691
+ timeline: import_es_toolkit2.merge(freshRun.timeline, {
1375
1692
  [stepId]: { output: {}, timedOut: true, timestamp: new Date }
1376
1693
  })
1377
1694
  }
@@ -1389,7 +1706,7 @@ ${error.stack}` : String(error)
1389
1706
  resourceId: run.resourceId ?? undefined,
1390
1707
  data: {
1391
1708
  currentStepId: stepId,
1392
- timeline: import_es_toolkit.merge(freshRun.timeline, {
1709
+ timeline: import_es_toolkit2.merge(freshRun.timeline, {
1393
1710
  [stepId]: { output: result, timestamp: new Date }
1394
1711
  })
1395
1712
  }
@@ -1407,7 +1724,7 @@ ${error.stack}` : String(error)
1407
1724
  status: "paused" /* PAUSED */,
1408
1725
  currentStepId: stepId,
1409
1726
  pausedAt: new Date,
1410
- timeline: import_es_toolkit.merge(freshRun.timeline, {
1727
+ timeline: import_es_toolkit2.merge(freshRun.timeline, {
1411
1728
  [`${stepId}-poll`]: { startedAt: startedAt.toISOString() },
1412
1729
  [`${stepId}-wait-for`]: {
1413
1730
  waitFor: { timeoutEvent: pollEvent, skipOutput: true },
@@ -1426,7 +1743,7 @@ ${error.stack}` : String(error)
1426
1743
  event: { name: pollEvent, data: {} }
1427
1744
  }, {
1428
1745
  startAfter: new Date(Date.now() + intervalMs),
1429
- expireInSeconds: defaultExpireInSeconds
1746
+ expireInSeconds: defaultExpireInSeconds2
1430
1747
  });
1431
1748
  } catch (error) {
1432
1749
  await this.updateRun({
@@ -1451,12 +1768,12 @@ ${error.stack}` : String(error)
1451
1768
  return {
1452
1769
  log: (message, context) => {
1453
1770
  const { runId, workflowId } = context ?? {};
1454
- const parts = [LOG_PREFIX, workflowId, runId].filter(Boolean).join(" ");
1771
+ const parts = [LOG_PREFIX2, workflowId, runId].filter(Boolean).join(" ");
1455
1772
  logger.log(`${parts}: ${message}`);
1456
1773
  },
1457
1774
  error: (message, error, context) => {
1458
1775
  const { runId, workflowId } = context ?? {};
1459
- const parts = [LOG_PREFIX, workflowId, runId].filter(Boolean).join(" ");
1776
+ const parts = [LOG_PREFIX2, workflowId, runId].filter(Boolean).join(" ");
1460
1777
  logger.error(`${parts}: ${message}`, error);
1461
1778
  }
1462
1779
  };
@@ -1480,5 +1797,5 @@ ${error.stack}` : String(error)
1480
1797
  }
1481
1798
  }
1482
1799
 
1483
- //# debugId=644364C840A9480364756E2164756E21
1800
+ //# debugId=BE8A12714B5354A264756E2164756E21
1484
1801
  //# sourceMappingURL=index.js.map