pg-workflows 0.1.3 → 0.3.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.js CHANGED
@@ -1,18 +1,98 @@
1
1
  // src/definition.ts
2
- function workflow(id, handler, { inputSchema, timeout, retries } = {}) {
3
- return {
2
+ function createWorkflowFactory(plugins = []) {
3
+ const factory = (id, handler, { inputSchema, timeout, retries } = {}) => ({
4
4
  id,
5
5
  handler,
6
6
  inputSchema,
7
7
  timeout,
8
- retries
9
- };
8
+ retries,
9
+ plugins: plugins.length > 0 ? plugins : undefined
10
+ });
11
+ factory.use = (plugin) => createWorkflowFactory([
12
+ ...plugins,
13
+ plugin
14
+ ]);
15
+ return factory;
16
+ }
17
+ var workflow = createWorkflowFactory();
18
+ // src/duration.ts
19
+ import parse from "parse-duration";
20
+
21
+ // src/error.ts
22
+ class WorkflowEngineError extends Error {
23
+ workflowId;
24
+ runId;
25
+ cause;
26
+ constructor(message, workflowId, runId, cause = undefined) {
27
+ super(message);
28
+ this.workflowId = workflowId;
29
+ this.runId = runId;
30
+ this.cause = cause;
31
+ this.name = "WorkflowEngineError";
32
+ if (Error.captureStackTrace) {
33
+ Error.captureStackTrace(this, WorkflowEngineError);
34
+ }
35
+ }
36
+ }
37
+
38
+ class WorkflowRunNotFoundError extends WorkflowEngineError {
39
+ constructor(runId, workflowId) {
40
+ super("Workflow run not found", workflowId, runId);
41
+ this.name = "WorkflowRunNotFoundError";
42
+ }
43
+ }
44
+
45
+ // src/duration.ts
46
+ var MS_PER_SECOND = 1000;
47
+ var MS_PER_MINUTE = 60 * MS_PER_SECOND;
48
+ var MS_PER_HOUR = 60 * MS_PER_MINUTE;
49
+ var MS_PER_DAY = 24 * MS_PER_HOUR;
50
+ var MS_PER_WEEK = 7 * MS_PER_DAY;
51
+ function parseDuration(duration) {
52
+ if (typeof duration === "string") {
53
+ if (duration.trim() === "") {
54
+ throw new WorkflowEngineError("Invalid duration: empty string");
55
+ }
56
+ const ms2 = parse(duration);
57
+ if (ms2 == null || ms2 <= 0) {
58
+ throw new WorkflowEngineError(`Invalid duration: "${duration}"`);
59
+ }
60
+ return ms2;
61
+ }
62
+ const { weeks = 0, days = 0, hours = 0, minutes = 0, seconds = 0 } = duration;
63
+ const ms = weeks * MS_PER_WEEK + days * MS_PER_DAY + hours * MS_PER_HOUR + minutes * MS_PER_MINUTE + seconds * MS_PER_SECOND;
64
+ if (ms <= 0) {
65
+ throw new WorkflowEngineError("Invalid duration: must be a positive value");
66
+ }
67
+ return ms;
10
68
  }
11
69
  // src/engine.ts
12
70
  import { merge } from "es-toolkit";
13
71
 
14
72
  // src/ast-parser.ts
15
73
  import * as ts from "typescript";
74
+
75
+ // src/types.ts
76
+ var WorkflowStatus;
77
+ ((WorkflowStatus2) => {
78
+ WorkflowStatus2["PENDING"] = "pending";
79
+ WorkflowStatus2["RUNNING"] = "running";
80
+ WorkflowStatus2["PAUSED"] = "paused";
81
+ WorkflowStatus2["COMPLETED"] = "completed";
82
+ WorkflowStatus2["FAILED"] = "failed";
83
+ WorkflowStatus2["CANCELLED"] = "cancelled";
84
+ })(WorkflowStatus ||= {});
85
+ var StepType;
86
+ ((StepType2) => {
87
+ StepType2["PAUSE"] = "pause";
88
+ StepType2["RUN"] = "run";
89
+ StepType2["WAIT_FOR"] = "waitFor";
90
+ StepType2["WAIT_UNTIL"] = "waitUntil";
91
+ StepType2["DELAY"] = "delay";
92
+ StepType2["POLL"] = "poll";
93
+ })(StepType ||= {});
94
+
95
+ // src/ast-parser.ts
16
96
  function parseWorkflowHandler(handler) {
17
97
  const handlerSource = handler.toString();
18
98
  const sourceFile = ts.createSourceFile("handler.ts", handlerSource, ts.ScriptTarget.Latest, true);
@@ -56,13 +136,14 @@ function parseWorkflowHandler(handler) {
56
136
  const propertyAccess = node.expression;
57
137
  const objectName = propertyAccess.expression.getText(sourceFile);
58
138
  const methodName = propertyAccess.name.text;
59
- if (objectName === "step" && (methodName === "run" || methodName === "waitFor" || methodName === "pause")) {
139
+ if (objectName === "step" && (methodName === "run" || methodName === "waitFor" || methodName === "pause" || methodName === "waitUntil" || methodName === "delay" || methodName === "sleep" || methodName === "poll")) {
60
140
  const firstArg = node.arguments[0];
61
141
  if (firstArg) {
62
142
  const { id, isDynamic } = extractStepId(firstArg);
143
+ const stepType = methodName === "sleep" ? "delay" /* DELAY */ : methodName;
63
144
  const stepDefinition = {
64
145
  id,
65
- type: methodName,
146
+ type: stepType,
66
147
  conditional: isInConditional(node),
67
148
  loop: isInLoop(node),
68
149
  isDynamic
@@ -363,48 +444,6 @@ async function withPostgresTransaction(db, callback) {
363
444
  }
364
445
  }
365
446
 
366
- // src/error.ts
367
- class WorkflowEngineError extends Error {
368
- workflowId;
369
- runId;
370
- cause;
371
- constructor(message, workflowId, runId, cause = undefined) {
372
- super(message);
373
- this.workflowId = workflowId;
374
- this.runId = runId;
375
- this.cause = cause;
376
- this.name = "WorkflowEngineError";
377
- if (Error.captureStackTrace) {
378
- Error.captureStackTrace(this, WorkflowEngineError);
379
- }
380
- }
381
- }
382
-
383
- class WorkflowRunNotFoundError extends WorkflowEngineError {
384
- constructor(runId, workflowId) {
385
- super("Workflow run not found", workflowId, runId);
386
- this.name = "WorkflowRunNotFoundError";
387
- }
388
- }
389
-
390
- // src/types.ts
391
- var WorkflowStatus;
392
- ((WorkflowStatus2) => {
393
- WorkflowStatus2["PENDING"] = "pending";
394
- WorkflowStatus2["RUNNING"] = "running";
395
- WorkflowStatus2["PAUSED"] = "paused";
396
- WorkflowStatus2["COMPLETED"] = "completed";
397
- WorkflowStatus2["FAILED"] = "failed";
398
- WorkflowStatus2["CANCELLED"] = "cancelled";
399
- })(WorkflowStatus ||= {});
400
- var StepType;
401
- ((StepType2) => {
402
- StepType2["PAUSE"] = "pause";
403
- StepType2["RUN"] = "run";
404
- StepType2["WAIT_FOR"] = "waitFor";
405
- StepType2["WAIT_UNTIL"] = "waitUntil";
406
- })(StepType ||= {});
407
-
408
447
  // src/engine.ts
409
448
  var PAUSE_EVENT_NAME = "__internal_pause";
410
449
  var WORKFLOW_RUN_QUEUE_NAME = "workflow-run";
@@ -413,7 +452,9 @@ var StepTypeToIcon = {
413
452
  ["run" /* RUN */]: "λ",
414
453
  ["waitFor" /* WAIT_FOR */]: "○",
415
454
  ["pause" /* PAUSE */]: "⏸",
416
- ["waitUntil" /* WAIT_UNTIL */]: "⏲"
455
+ ["waitUntil" /* WAIT_UNTIL */]: "⏲",
456
+ ["delay" /* DELAY */]: "⏱",
457
+ ["poll" /* POLL */]: "↻"
417
458
  };
418
459
  var defaultLogger = {
419
460
  log: (_message) => console.warn(_message),
@@ -513,7 +554,9 @@ class WorkflowEngine {
513
554
  if (!workflow2) {
514
555
  throw new WorkflowEngineError(`Unknown workflow ${workflowId}`);
515
556
  }
516
- if (workflow2.steps.length === 0 || !workflow2.steps[0]) {
557
+ const hasSteps = workflow2.steps.length > 0 && workflow2.steps[0];
558
+ const hasPlugins = (workflow2.plugins?.length ?? 0) > 0;
559
+ if (!hasSteps && !hasPlugins) {
517
560
  throw new WorkflowEngineError(`Workflow ${workflowId} has no steps`, workflowId);
518
561
  }
519
562
  if (workflow2.inputSchema) {
@@ -522,7 +565,7 @@ class WorkflowEngine {
522
565
  throw new WorkflowEngineError(result.error.message, workflowId);
523
566
  }
524
567
  }
525
- const initialStepId = workflow2.steps[0]?.id;
568
+ const initialStepId = workflow2.steps[0]?.id ?? "__start__";
526
569
  const run = await withPostgresTransaction(this.boss.getDb(), async (_db) => {
527
570
  const timeoutAt = options?.timeout ? new Date(Date.now() + options.timeout) : workflow2.timeout ? new Date(Date.now() + workflow2.timeout) : null;
528
571
  const insertedRun = await insertWorkflowRun({
@@ -709,11 +752,13 @@ class WorkflowEngine {
709
752
  if (run.status === "paused" /* PAUSED */) {
710
753
  const waitForStepEntry = run.timeline[`${run.currentStepId}-wait-for`];
711
754
  const waitForStep = waitForStepEntry && typeof waitForStepEntry === "object" && "waitFor" in waitForStepEntry ? waitForStepEntry : null;
712
- const currentStepEntry = run.timeline[run.currentStepId];
713
- const currentStep = currentStepEntry && typeof currentStepEntry === "object" && "output" in currentStepEntry ? currentStepEntry : null;
755
+ const currentStep = this.getCachedStepEntry(run.timeline, run.currentStepId);
714
756
  const waitFor = waitForStep?.waitFor;
715
757
  const hasCurrentStepOutput = currentStep?.output !== undefined;
716
- if (waitFor && waitFor.eventName === event?.name && !hasCurrentStepOutput) {
758
+ const eventMatches = waitFor && event?.name && (event.name === waitFor.eventName || event.name === waitFor.timeoutEvent) && !hasCurrentStepOutput;
759
+ if (eventMatches) {
760
+ const isTimeout = event?.name === waitFor?.timeoutEvent;
761
+ const skipOutput = waitFor?.skipOutput;
717
762
  run = await this.updateRun({
718
763
  runId,
719
764
  resourceId,
@@ -721,13 +766,16 @@ class WorkflowEngine {
721
766
  status: "running" /* RUNNING */,
722
767
  pausedAt: null,
723
768
  resumedAt: new Date,
724
- timeline: merge(run.timeline, {
725
- [run.currentStepId]: {
726
- output: event?.data ?? {},
727
- timestamp: new Date
728
- }
729
- }),
730
- jobId: job?.id
769
+ jobId: job?.id,
770
+ ...skipOutput ? {} : {
771
+ timeline: merge(run.timeline, {
772
+ [run.currentStepId]: {
773
+ output: event?.data ?? {},
774
+ ...isTimeout ? { timedOut: true } : {},
775
+ timestamp: new Date
776
+ }
777
+ })
778
+ }
731
779
  }
732
780
  });
733
781
  } else {
@@ -743,51 +791,79 @@ class WorkflowEngine {
743
791
  });
744
792
  }
745
793
  }
794
+ const baseStep = {
795
+ run: async (stepId, handler) => {
796
+ if (!run) {
797
+ throw new WorkflowEngineError("Missing workflow run", workflowId, runId);
798
+ }
799
+ return this.runStep({ stepId, run, handler });
800
+ },
801
+ waitFor: async (stepId, { eventName, timeout }) => {
802
+ if (!run) {
803
+ throw new WorkflowEngineError("Missing workflow run", workflowId, runId);
804
+ }
805
+ const timeoutDate = timeout ? new Date(Date.now() + timeout) : undefined;
806
+ return this.waitStep({ run, stepId, eventName, timeoutDate });
807
+ },
808
+ waitUntil: async (stepId, dateOrOptions) => {
809
+ if (!run) {
810
+ throw new WorkflowEngineError("Missing workflow run", workflowId, runId);
811
+ }
812
+ const date = dateOrOptions instanceof Date ? dateOrOptions : typeof dateOrOptions === "string" ? new Date(dateOrOptions) : dateOrOptions.date instanceof Date ? dateOrOptions.date : new Date(dateOrOptions.date);
813
+ await this.waitStep({ run, stepId, timeoutDate: date });
814
+ },
815
+ pause: async (stepId) => {
816
+ if (!run) {
817
+ throw new WorkflowEngineError("Missing workflow run", workflowId, runId);
818
+ }
819
+ await this.waitStep({ run, stepId, eventName: PAUSE_EVENT_NAME });
820
+ },
821
+ delay: async (stepId, duration) => {
822
+ if (!run) {
823
+ throw new WorkflowEngineError("Missing workflow run", workflowId, runId);
824
+ }
825
+ await this.waitStep({
826
+ run,
827
+ stepId,
828
+ timeoutDate: new Date(Date.now() + parseDuration(duration))
829
+ });
830
+ },
831
+ get sleep() {
832
+ return this.delay;
833
+ },
834
+ poll: async (stepId, conditionFn, options) => {
835
+ if (!run) {
836
+ throw new WorkflowEngineError("Missing workflow run", workflowId, runId);
837
+ }
838
+ const intervalMs = parseDuration(options?.interval ?? "30s");
839
+ if (intervalMs < 30000) {
840
+ throw new WorkflowEngineError(`step.poll interval must be at least 30s (got ${intervalMs}ms)`, workflowId, runId);
841
+ }
842
+ const timeoutMs = options?.timeout ? parseDuration(options.timeout) : undefined;
843
+ return this.pollStep({ run, stepId, conditionFn, intervalMs, timeoutMs });
844
+ }
845
+ };
846
+ let step = { ...baseStep };
847
+ const plugins = workflow2.plugins ?? [];
848
+ for (const plugin of plugins) {
849
+ const extra = plugin.methods(step);
850
+ step = { ...step, ...extra };
851
+ }
746
852
  const context = {
747
853
  input: run.input,
748
854
  workflowId: run.workflowId,
749
855
  runId: run.id,
750
856
  timeline: run.timeline,
751
857
  logger: this.logger,
752
- step: {
753
- run: async (stepId, handler) => {
754
- if (!run) {
755
- throw new WorkflowEngineError("Missing workflow run", workflowId, runId);
756
- }
757
- return this.runStep({
758
- stepId,
759
- run,
760
- handler
761
- });
762
- },
763
- waitFor: async (stepId, { eventName, timeout }) => {
764
- if (!run) {
765
- throw new WorkflowEngineError("Missing workflow run", workflowId, runId);
766
- }
767
- return this.waitForEvent({
768
- run,
769
- stepId,
770
- eventName,
771
- timeout
772
- });
773
- },
774
- waitUntil: async ({ date }) => {
775
- return this.waitUntil(runId, date);
776
- },
777
- pause: async (stepId) => {
778
- if (!run) {
779
- throw new WorkflowEngineError("Missing workflow run", workflowId, runId);
780
- }
781
- return this.pauseStep({
782
- stepId,
783
- run
784
- });
785
- }
786
- }
858
+ step
787
859
  };
788
860
  const result = await workflow2.handler(context);
789
861
  run = await this.getRun({ runId, resourceId });
790
- if (run.status === "running" /* RUNNING */ && run.currentStepId === workflow2.steps[workflow2.steps.length - 1]?.id) {
862
+ const isLastParsedStep = run.currentStepId === workflow2.steps[workflow2.steps.length - 1]?.id;
863
+ const hasPluginSteps = (workflow2.plugins?.length ?? 0) > 0;
864
+ const noParsedSteps = workflow2.steps.length === 0;
865
+ const shouldComplete = run.status === "running" /* RUNNING */ && (noParsedSteps || isLastParsedStep || hasPluginSteps && result !== undefined);
866
+ if (shouldComplete) {
791
867
  const normalizedResult = result === undefined ? {} : result;
792
868
  await this.updateRun({
793
869
  runId,
@@ -839,6 +915,10 @@ class WorkflowEngine {
839
915
  throw error;
840
916
  }
841
917
  }
918
+ getCachedStepEntry(timeline, stepId) {
919
+ const stepEntry = timeline[stepId];
920
+ return stepEntry && typeof stepEntry === "object" && "output" in stepEntry ? stepEntry : null;
921
+ }
842
922
  async runStep({
843
923
  stepId,
844
924
  run,
@@ -857,39 +937,38 @@ class WorkflowEngine {
857
937
  return;
858
938
  }
859
939
  try {
860
- let result;
861
- const timelineStepEntry = persistedRun.timeline[stepId];
862
- const timelineStep = timelineStepEntry && typeof timelineStepEntry === "object" && "output" in timelineStepEntry ? timelineStepEntry : null;
863
- if (timelineStep?.output !== undefined) {
864
- result = timelineStep.output;
865
- } else {
866
- await this.updateRun({
867
- runId: run.id,
868
- resourceId: run.resourceId ?? undefined,
869
- data: {
870
- currentStepId: stepId
871
- }
872
- }, { db });
873
- this.logger.log(`Running step ${stepId}...`, {
874
- runId: run.id,
875
- workflowId: run.workflowId
876
- });
877
- result = await handler();
878
- run = await this.updateRun({
879
- runId: run.id,
880
- resourceId: run.resourceId ?? undefined,
881
- data: {
882
- timeline: merge(run.timeline, {
883
- [stepId]: {
884
- output: result === undefined ? {} : result,
885
- timestamp: new Date
886
- }
887
- })
888
- }
889
- }, { db });
940
+ const cached = this.getCachedStepEntry(persistedRun.timeline, stepId);
941
+ if (cached?.output !== undefined) {
942
+ return cached.output;
943
+ }
944
+ await this.updateRun({
945
+ runId: run.id,
946
+ resourceId: run.resourceId ?? undefined,
947
+ data: {
948
+ currentStepId: stepId
949
+ }
950
+ }, { db });
951
+ this.logger.log(`Running step ${stepId}...`, {
952
+ runId: run.id,
953
+ workflowId: run.workflowId
954
+ });
955
+ let output = await handler();
956
+ if (output === undefined) {
957
+ output = {};
890
958
  }
891
- const finalResult = result === undefined ? {} : result;
892
- return finalResult;
959
+ run = await this.updateRun({
960
+ runId: run.id,
961
+ resourceId: run.resourceId ?? undefined,
962
+ data: {
963
+ timeline: merge(run.timeline, {
964
+ [stepId]: {
965
+ output,
966
+ timestamp: new Date
967
+ }
968
+ })
969
+ }
970
+ }, { db });
971
+ return output;
893
972
  } catch (error) {
894
973
  this.logger.error(`Step ${stepId} failed:`, error, {
895
974
  runId: run.id,
@@ -908,60 +987,133 @@ ${error.stack}` : String(error)
908
987
  }
909
988
  });
910
989
  }
911
- async waitForEvent({
990
+ async waitStep({
912
991
  run,
913
992
  stepId,
914
993
  eventName,
915
- timeout
994
+ timeoutDate
916
995
  }) {
917
996
  const persistedRun = await this.getRun({
918
997
  runId: run.id,
919
998
  resourceId: run.resourceId ?? undefined
920
999
  });
921
1000
  if (persistedRun.status === "cancelled" /* CANCELLED */ || persistedRun.status === "paused" /* PAUSED */ || persistedRun.status === "failed" /* FAILED */) {
922
- this.logger.log(`Step ${stepId} skipped, workflow run is ${persistedRun.status}`, {
923
- runId: run.id,
924
- workflowId: run.workflowId
925
- });
926
1001
  return;
927
1002
  }
928
- const timelineStepCheckEntry = persistedRun.timeline[stepId];
929
- const timelineStepCheck = timelineStepCheckEntry && typeof timelineStepCheckEntry === "object" && "output" in timelineStepCheckEntry ? timelineStepCheckEntry : null;
930
- if (timelineStepCheck?.output !== undefined) {
931
- return timelineStepCheck.output;
1003
+ const cached = this.getCachedStepEntry(persistedRun.timeline, stepId);
1004
+ if (cached?.output !== undefined) {
1005
+ return cached.timedOut ? undefined : cached.output;
932
1006
  }
1007
+ const timeoutEvent = timeoutDate ? `__timeout_${stepId}` : undefined;
933
1008
  await this.updateRun({
934
1009
  runId: run.id,
935
1010
  resourceId: run.resourceId ?? undefined,
936
1011
  data: {
937
1012
  status: "paused" /* PAUSED */,
938
1013
  currentStepId: stepId,
1014
+ pausedAt: new Date,
939
1015
  timeline: merge(run.timeline, {
940
1016
  [`${stepId}-wait-for`]: {
941
- waitFor: {
942
- eventName,
943
- timeout
944
- },
1017
+ waitFor: { eventName, timeoutEvent },
945
1018
  timestamp: new Date
946
1019
  }
947
- }),
948
- pausedAt: new Date
1020
+ })
1021
+ }
1022
+ });
1023
+ if (timeoutDate && timeoutEvent) {
1024
+ const job = {
1025
+ runId: run.id,
1026
+ resourceId: run.resourceId ?? undefined,
1027
+ workflowId: run.workflowId,
1028
+ input: run.input,
1029
+ event: { name: timeoutEvent, data: { date: timeoutDate.toISOString() } }
1030
+ };
1031
+ await this.boss.send(WORKFLOW_RUN_QUEUE_NAME, job, {
1032
+ startAfter: timeoutDate.getTime() <= Date.now() ? new Date : timeoutDate,
1033
+ expireInSeconds: defaultExpireInSeconds
1034
+ });
1035
+ }
1036
+ this.logger.log(`Step ${stepId} waiting${eventName ? ` for event "${eventName}"` : ""}${timeoutDate ? ` until ${timeoutDate.toISOString()}` : ""}`, { runId: run.id, workflowId: run.workflowId });
1037
+ }
1038
+ async pollStep({
1039
+ run,
1040
+ stepId,
1041
+ conditionFn,
1042
+ intervalMs,
1043
+ timeoutMs
1044
+ }) {
1045
+ const persistedRun = await this.getRun({
1046
+ runId: run.id,
1047
+ resourceId: run.resourceId ?? undefined
1048
+ });
1049
+ if (persistedRun.status === "cancelled" /* CANCELLED */ || persistedRun.status === "paused" /* PAUSED */ || persistedRun.status === "failed" /* FAILED */) {
1050
+ return { timedOut: true };
1051
+ }
1052
+ const cached = this.getCachedStepEntry(persistedRun.timeline, stepId);
1053
+ if (cached?.output !== undefined) {
1054
+ return cached.timedOut ? { timedOut: true } : { timedOut: false, data: cached.output };
1055
+ }
1056
+ const pollStateEntry = persistedRun.timeline[`${stepId}-poll`];
1057
+ const startedAt = pollStateEntry && typeof pollStateEntry === "object" && "startedAt" in pollStateEntry ? new Date(pollStateEntry.startedAt) : new Date;
1058
+ if (timeoutMs !== undefined && Date.now() >= startedAt.getTime() + timeoutMs) {
1059
+ await this.updateRun({
1060
+ runId: run.id,
1061
+ resourceId: run.resourceId ?? undefined,
1062
+ data: {
1063
+ currentStepId: stepId,
1064
+ timeline: merge(persistedRun.timeline, {
1065
+ [stepId]: { output: {}, timedOut: true, timestamp: new Date }
1066
+ })
1067
+ }
1068
+ });
1069
+ return { timedOut: true };
1070
+ }
1071
+ const result = await conditionFn();
1072
+ if (result !== false) {
1073
+ await this.updateRun({
1074
+ runId: run.id,
1075
+ resourceId: run.resourceId ?? undefined,
1076
+ data: {
1077
+ currentStepId: stepId,
1078
+ timeline: merge(persistedRun.timeline, {
1079
+ [stepId]: { output: result, timestamp: new Date }
1080
+ })
1081
+ }
1082
+ });
1083
+ return { timedOut: false, data: result };
1084
+ }
1085
+ const pollEvent = `__poll_${stepId}`;
1086
+ await this.updateRun({
1087
+ runId: run.id,
1088
+ resourceId: run.resourceId ?? undefined,
1089
+ data: {
1090
+ status: "paused" /* PAUSED */,
1091
+ currentStepId: stepId,
1092
+ pausedAt: new Date,
1093
+ timeline: merge(persistedRun.timeline, {
1094
+ [`${stepId}-poll`]: { startedAt: startedAt.toISOString() },
1095
+ [`${stepId}-wait-for`]: {
1096
+ waitFor: { timeoutEvent: pollEvent, skipOutput: true },
1097
+ timestamp: new Date
1098
+ }
1099
+ })
949
1100
  }
950
1101
  });
951
- this.logger.log(`Running step ${stepId}, waiting for event ${eventName}...`, {
1102
+ await this.boss.send(WORKFLOW_RUN_QUEUE_NAME, {
952
1103
  runId: run.id,
953
- workflowId: run.workflowId
1104
+ resourceId: run.resourceId ?? undefined,
1105
+ workflowId: run.workflowId,
1106
+ input: run.input,
1107
+ event: { name: pollEvent, data: {} }
1108
+ }, {
1109
+ startAfter: new Date(Date.now() + intervalMs),
1110
+ expireInSeconds: defaultExpireInSeconds
954
1111
  });
955
- }
956
- async pauseStep({ stepId, run }) {
957
- await this.waitForEvent({
958
- run,
959
- stepId,
960
- eventName: PAUSE_EVENT_NAME
1112
+ this.logger.log(`Step ${stepId} polling every ${intervalMs}ms...`, {
1113
+ runId: run.id,
1114
+ workflowId: run.workflowId
961
1115
  });
962
- }
963
- async waitUntil(runId, _date) {
964
- throw new WorkflowEngineError("Not implemented yet", undefined, runId);
1116
+ return { timedOut: false, data: undefined };
965
1117
  }
966
1118
  async checkIfHasStarted() {
967
1119
  if (!this._started) {
@@ -1002,6 +1154,7 @@ ${error.stack}` : String(error)
1002
1154
  }
1003
1155
  export {
1004
1156
  workflow,
1157
+ parseDuration,
1005
1158
  WorkflowStatus,
1006
1159
  WorkflowRunNotFoundError,
1007
1160
  WorkflowEngineError,
@@ -1009,5 +1162,5 @@ export {
1009
1162
  StepType
1010
1163
  };
1011
1164
 
1012
- //# debugId=CEF6DB946A8B69A164756E2164756E21
1165
+ //# debugId=4ADA0797255A878364756E2164756E21
1013
1166
  //# sourceMappingURL=index.js.map