@upstash/workflow 0.2.22-rc → 0.2.23-rc

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.
@@ -1,23 +1,3 @@
1
- // src/constants.ts
2
- var WORKFLOW_ID_HEADER = "Upstash-Workflow-RunId";
3
- var WORKFLOW_INIT_HEADER = "Upstash-Workflow-Init";
4
- var WORKFLOW_URL_HEADER = "Upstash-Workflow-Url";
5
- var WORKFLOW_FAILURE_HEADER = "Upstash-Workflow-Is-Failure";
6
- var WORKFLOW_FEATURE_HEADER = "Upstash-Feature-Set";
7
- var WORKFLOW_INVOKE_COUNT_HEADER = "Upstash-Workflow-Invoke-Count";
8
- var WORKFLOW_LABEL_HEADER = "Upstash-Label";
9
- var WORKFLOW_PROTOCOL_VERSION = "1";
10
- var WORKFLOW_PROTOCOL_VERSION_HEADER = "Upstash-Workflow-Sdk-Version";
11
- var DEFAULT_CONTENT_TYPE = "application/json";
12
- var NO_CONCURRENCY = 1;
13
- var DEFAULT_RETRIES = 3;
14
- var VERSION = "v0.2.21";
15
- var SDK_TELEMETRY = `@upstash/workflow@${VERSION}`;
16
- var TELEMETRY_HEADER_SDK = "Upstash-Telemetry-Sdk";
17
- var TELEMETRY_HEADER_FRAMEWORK = "Upstash-Telemetry-Framework";
18
- var TELEMETRY_HEADER_RUNTIME = "Upstash-Telemetry-Runtime";
19
- var TELEMETRY_HEADER_AGENT = "Upstash-Telemetry-Agent";
20
-
21
1
  // src/error.ts
22
2
  import { QstashError } from "@upstash/qstash";
23
3
  var WorkflowError = class extends QstashError {
@@ -59,6 +39,19 @@ var WorkflowNonRetryableError = class extends WorkflowAbort {
59
39
  if (message) this.message = message;
60
40
  }
61
41
  };
42
+ var WorkflowRetryAfterError = class extends WorkflowAbort {
43
+ retryAfter;
44
+ /**
45
+ * @param retryAfter time in seconds after which the workflow should be retried
46
+ * @param message error message to be displayed
47
+ */
48
+ constructor(message, retryAfter) {
49
+ super("retry", void 0, false);
50
+ this.name = "WorkflowRetryAfterError";
51
+ this.retryAfter = retryAfter;
52
+ if (message) this.message = message;
53
+ }
54
+ };
62
55
  var formatWorkflowError = (error) => {
63
56
  return error instanceof Error ? {
64
57
  error: error.name,
@@ -69,6 +62,47 @@ var formatWorkflowError = (error) => {
69
62
  message: `An error occured while executing workflow: '${typeof error === "string" ? error : JSON.stringify(error)}'`
70
63
  };
71
64
  };
65
+ function getConstructorName(obj) {
66
+ if (obj === null || obj === void 0) {
67
+ return null;
68
+ }
69
+ const ctor = obj.constructor;
70
+ if (!ctor || ctor.name === "Object") {
71
+ return null;
72
+ }
73
+ return ctor.name;
74
+ }
75
+ function getConstructorNames(obj) {
76
+ const proto = Object.getPrototypeOf(obj);
77
+ const name = getConstructorName(proto);
78
+ if (name === null) {
79
+ return [];
80
+ }
81
+ return [name, ...getConstructorNames(proto)];
82
+ }
83
+ function isInstanceOf(v, ctor) {
84
+ return getConstructorNames(v).includes(ctor.name);
85
+ }
86
+
87
+ // src/constants.ts
88
+ var WORKFLOW_ID_HEADER = "Upstash-Workflow-RunId";
89
+ var WORKFLOW_INIT_HEADER = "Upstash-Workflow-Init";
90
+ var WORKFLOW_URL_HEADER = "Upstash-Workflow-Url";
91
+ var WORKFLOW_FAILURE_HEADER = "Upstash-Workflow-Is-Failure";
92
+ var WORKFLOW_FEATURE_HEADER = "Upstash-Feature-Set";
93
+ var WORKFLOW_INVOKE_COUNT_HEADER = "Upstash-Workflow-Invoke-Count";
94
+ var WORKFLOW_LABEL_HEADER = "Upstash-Label";
95
+ var WORKFLOW_PROTOCOL_VERSION = "1";
96
+ var WORKFLOW_PROTOCOL_VERSION_HEADER = "Upstash-Workflow-Sdk-Version";
97
+ var DEFAULT_CONTENT_TYPE = "application/json";
98
+ var NO_CONCURRENCY = 1;
99
+ var DEFAULT_RETRIES = 3;
100
+ var VERSION = "v0.2.22";
101
+ var SDK_TELEMETRY = `@upstash/workflow@${VERSION}`;
102
+ var TELEMETRY_HEADER_SDK = "Upstash-Telemetry-Sdk";
103
+ var TELEMETRY_HEADER_FRAMEWORK = "Upstash-Telemetry-Framework";
104
+ var TELEMETRY_HEADER_RUNTIME = "Upstash-Telemetry-Runtime";
105
+ var TELEMETRY_HEADER_AGENT = "Upstash-Telemetry-Agent";
72
106
 
73
107
  // src/types.ts
74
108
  var StepTypes = [
@@ -79,7 +113,9 @@ var StepTypes = [
79
113
  "Call",
80
114
  "Wait",
81
115
  "Notify",
82
- "Invoke"
116
+ "Invoke",
117
+ "CreateWebhook",
118
+ "WaitForWebhook"
83
119
  ];
84
120
 
85
121
  // src/agents/adapters.ts
@@ -131,7 +167,7 @@ var fetchWithContextCall = async (context, agentCallParams, ...params) => {
131
167
  headers: responseHeaders
132
168
  });
133
169
  } catch (error) {
134
- if (error instanceof Error && error.name === "WorkflowAbort") {
170
+ if (error instanceof Error && isInstanceOf(error, WorkflowAbort)) {
135
171
  throw error;
136
172
  } else {
137
173
  console.error("Error in fetch implementation:", error);
@@ -342,7 +378,7 @@ var getSteps = async (requester, workflowRunId, messageId, debug) => {
342
378
  return { steps: filteredSteps, workflowRunEnded: false };
343
379
  }
344
380
  } catch (error) {
345
- if (error instanceof QstashError2 && error.status === 404) {
381
+ if (isInstanceOf(error, QstashError2) && error.status === 404) {
346
382
  await debug?.log("WARN", "ENDPOINT_START", {
347
383
  message: "Couldn't fetch workflow run steps. This can happen if the workflow run succesfully ends before some callback is executed.",
348
384
  error
@@ -360,8 +396,8 @@ var NANOID_LENGTH = 21;
360
396
  function getRandomInt() {
361
397
  return Math.floor(Math.random() * NANOID_CHARS.length);
362
398
  }
363
- function nanoid() {
364
- return Array.from({ length: NANOID_LENGTH }).map(() => NANOID_CHARS[getRandomInt()]).join("");
399
+ function nanoid(length = NANOID_LENGTH) {
400
+ return Array.from({ length }).map(() => NANOID_CHARS[getRandomInt()]).join("");
365
401
  }
366
402
  function getWorkflowRunId(id) {
367
403
  return `wfr_${id ?? nanoid()}`;
@@ -378,6 +414,37 @@ function decodeBase64(base64) {
378
414
  return binString;
379
415
  }
380
416
  }
417
+ function getUserIdFromToken(qstashClient) {
418
+ try {
419
+ const token = qstashClient.token;
420
+ const decodedToken = decodeBase64(token);
421
+ const tokenPayload = JSON.parse(decodedToken);
422
+ const userId = tokenPayload.UserID;
423
+ if (!userId) {
424
+ throw new WorkflowError("QStash token payload does not contain userId");
425
+ }
426
+ return userId;
427
+ } catch (error) {
428
+ throw new WorkflowError(
429
+ `Failed to decode QStash token while running create webhook step: ${error.message}`
430
+ );
431
+ }
432
+ }
433
+ function getQStashUrl(qstashClient) {
434
+ try {
435
+ const requester = qstashClient.http;
436
+ const baseUrl = requester.baseUrl;
437
+ if (!baseUrl) {
438
+ throw new WorkflowError("QStash client does not have a baseUrl");
439
+ }
440
+ return baseUrl;
441
+ } catch (error) {
442
+ throw new WorkflowError(`Failed to get QStash URL from client: ${error.message}`);
443
+ }
444
+ }
445
+ function getEventId() {
446
+ return `evt_${nanoid(15)}`;
447
+ }
381
448
 
382
449
  // node_modules/neverthrow/dist/index.es.js
383
450
  var defaultErrorConfig = {
@@ -895,17 +962,17 @@ var triggerRouteFunction = async ({
895
962
  return ok("workflow-finished");
896
963
  } catch (error) {
897
964
  const error_ = error;
898
- if (error instanceof QstashError3 && error.status === 400) {
965
+ if (isInstanceOf(error, QstashError3) && error.status === 400) {
899
966
  await debug?.log("WARN", "RESPONSE_WORKFLOW", {
900
967
  message: `tried to append to a cancelled workflow. exiting without publishing.`,
901
968
  name: error.name,
902
969
  errorMessage: error.message
903
970
  });
904
971
  return ok("workflow-was-finished");
905
- } else if (!(error_ instanceof WorkflowAbort)) {
906
- return err(error_);
907
- } else if (error_ instanceof WorkflowNonRetryableError) {
972
+ } else if (isInstanceOf(error_, WorkflowNonRetryableError) || isInstanceOf(error_, WorkflowRetryAfterError)) {
908
973
  return ok(error_);
974
+ } else if (!isInstanceOf(error_, WorkflowAbort)) {
975
+ return err(error_);
909
976
  } else if (error_.cancelWorkflow) {
910
977
  await onCancel();
911
978
  return ok("workflow-finished");
@@ -1103,7 +1170,9 @@ If you want to disable QStash Verification, you should clear env variables QSTAS
1103
1170
  // src/context/steps.ts
1104
1171
  var BaseLazyStep = class _BaseLazyStep {
1105
1172
  stepName;
1106
- constructor(stepName) {
1173
+ context;
1174
+ constructor(context, stepName) {
1175
+ this.context = context;
1107
1176
  if (!stepName) {
1108
1177
  throw new WorkflowError(
1109
1178
  "A workflow step name cannot be undefined or an empty string. Please provide a name for your workflow step."
@@ -1121,13 +1190,14 @@ var BaseLazyStep = class _BaseLazyStep {
1121
1190
  *
1122
1191
  * will be called when returning the steps to the context from auto executor
1123
1192
  *
1124
- * @param out field of the step
1193
+ * @param step step
1125
1194
  * @returns parsed out field
1126
1195
  */
1127
- parseOut(out) {
1196
+ parseOut(step) {
1197
+ const out = step.out;
1128
1198
  if (out === void 0) {
1129
1199
  if (this.allowUndefinedOut) {
1130
- return void 0;
1200
+ return this.handleUndefinedOut(step);
1131
1201
  } else {
1132
1202
  throw new WorkflowError(
1133
1203
  `Error while parsing output of ${this.stepType} step. Expected a string, but got: undefined`
@@ -1135,27 +1205,26 @@ var BaseLazyStep = class _BaseLazyStep {
1135
1205
  }
1136
1206
  }
1137
1207
  if (typeof out === "object") {
1138
- if (this.stepType !== "Wait") {
1139
- console.warn(
1140
- `Error while parsing ${this.stepType} step output. Expected a string, but got object. Please reach out to Upstash Support.`
1141
- );
1142
- return out;
1143
- }
1144
- return {
1145
- ...out,
1146
- eventData: _BaseLazyStep.tryParsing(out.eventData)
1147
- };
1208
+ console.warn(
1209
+ `Error while parsing ${this.stepType} step output. Expected a string, but got object. Please reach out to Upstash Support.`
1210
+ );
1211
+ return out;
1148
1212
  }
1149
1213
  if (typeof out !== "string") {
1150
1214
  throw new WorkflowError(
1151
1215
  `Error while parsing output of ${this.stepType} step. Expected a string or undefined, but got: ${typeof out}`
1152
1216
  );
1153
1217
  }
1154
- return this.safeParseOut(out);
1218
+ return this.safeParseOut(out, step);
1155
1219
  }
1156
- safeParseOut(out) {
1220
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1221
+ safeParseOut(out, step) {
1157
1222
  return _BaseLazyStep.tryParsing(out);
1158
1223
  }
1224
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1225
+ handleUndefinedOut(step) {
1226
+ return void 0;
1227
+ }
1159
1228
  static tryParsing(stepOut) {
1160
1229
  try {
1161
1230
  return JSON.parse(stepOut);
@@ -1206,8 +1275,8 @@ var LazyFunctionStep = class extends BaseLazyStep {
1206
1275
  stepFunction;
1207
1276
  stepType = "Run";
1208
1277
  allowUndefinedOut = true;
1209
- constructor(stepName, stepFunction) {
1210
- super(stepName);
1278
+ constructor(context, stepName, stepFunction) {
1279
+ super(context, stepName);
1211
1280
  this.stepFunction = stepFunction;
1212
1281
  }
1213
1282
  getPlanStep(concurrent, targetStep) {
@@ -1237,8 +1306,8 @@ var LazySleepStep = class extends BaseLazyStep {
1237
1306
  sleep;
1238
1307
  stepType = "SleepFor";
1239
1308
  allowUndefinedOut = true;
1240
- constructor(stepName, sleep) {
1241
- super(stepName);
1309
+ constructor(context, stepName, sleep) {
1310
+ super(context, stepName);
1242
1311
  this.sleep = sleep;
1243
1312
  }
1244
1313
  getPlanStep(concurrent, targetStep) {
@@ -1279,8 +1348,8 @@ var LazySleepUntilStep = class extends BaseLazyStep {
1279
1348
  sleepUntil;
1280
1349
  stepType = "SleepUntil";
1281
1350
  allowUndefinedOut = true;
1282
- constructor(stepName, sleepUntil) {
1283
- super(stepName);
1351
+ constructor(context, stepName, sleepUntil) {
1352
+ super(context, stepName);
1284
1353
  this.sleepUntil = sleepUntil;
1285
1354
  }
1286
1355
  getPlanStep(concurrent, targetStep) {
@@ -1332,8 +1401,8 @@ var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
1332
1401
  stringifyBody;
1333
1402
  stepType = "Call";
1334
1403
  allowUndefinedOut = false;
1335
- constructor(stepName, url, method, body, headers, retries, retryDelay, timeout, flowControl, stringifyBody) {
1336
- super(stepName);
1404
+ constructor(context, stepName, url, method, body, headers, retries, retryDelay, timeout, flowControl, stringifyBody) {
1405
+ super(context, stepName);
1337
1406
  this.url = url;
1338
1407
  this.method = method;
1339
1408
  this.body = body;
@@ -1477,13 +1546,12 @@ var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
1477
1546
  ]);
1478
1547
  }
1479
1548
  };
1480
- var LazyWaitForEventStep = class extends BaseLazyStep {
1549
+ var LazyWaitEventStep = class extends BaseLazyStep {
1481
1550
  eventId;
1482
1551
  timeout;
1483
- stepType = "Wait";
1484
1552
  allowUndefinedOut = false;
1485
- constructor(stepName, eventId, timeout) {
1486
- super(stepName);
1553
+ constructor(context, stepName, eventId, timeout) {
1554
+ super(context, stepName);
1487
1555
  this.eventId = eventId;
1488
1556
  this.timeout = timeout;
1489
1557
  }
@@ -1508,13 +1576,6 @@ var LazyWaitForEventStep = class extends BaseLazyStep {
1508
1576
  concurrent
1509
1577
  });
1510
1578
  }
1511
- safeParseOut(out) {
1512
- const result = JSON.parse(out);
1513
- return {
1514
- ...result,
1515
- eventData: BaseLazyStep.tryParsing(result.eventData)
1516
- };
1517
- }
1518
1579
  getHeaders({ context, telemetry, invokeCount, step }) {
1519
1580
  const headers = super.getHeaders({ context, telemetry, invokeCount, step });
1520
1581
  headers.headers["Upstash-Workflow-CallType"] = "step";
@@ -1548,7 +1609,7 @@ var LazyWaitForEventStep = class extends BaseLazyStep {
1548
1609
  timeoutHeaders,
1549
1610
  step: {
1550
1611
  stepId: step.stepId,
1551
- stepType: "Wait",
1612
+ stepType: this.stepType,
1552
1613
  stepName: step.stepName,
1553
1614
  concurrent: step.concurrent,
1554
1615
  targetStep: step.targetStep
@@ -1569,8 +1630,8 @@ var LazyWaitForEventStep = class extends BaseLazyStep {
1569
1630
  };
1570
1631
  var LazyNotifyStep = class extends LazyFunctionStep {
1571
1632
  stepType = "Notify";
1572
- constructor(stepName, eventId, eventData, requester) {
1573
- super(stepName, async () => {
1633
+ constructor(context, stepName, eventId, eventData, requester) {
1634
+ super(context, stepName, async () => {
1574
1635
  const notifyResponse = await makeNotifyRequest(requester, eventId, eventData);
1575
1636
  return {
1576
1637
  eventId,
@@ -1595,7 +1656,7 @@ var LazyInvokeStep = class extends BaseLazyStep {
1595
1656
  * workflow id of the invoked workflow
1596
1657
  */
1597
1658
  workflowId;
1598
- constructor(stepName, {
1659
+ constructor(context, stepName, {
1599
1660
  workflow,
1600
1661
  body,
1601
1662
  headers = {},
@@ -1605,7 +1666,7 @@ var LazyInvokeStep = class extends BaseLazyStep {
1605
1666
  flowControl,
1606
1667
  stringifyBody = true
1607
1668
  }) {
1608
- super(stepName);
1669
+ super(context, stepName);
1609
1670
  this.params = {
1610
1671
  workflow,
1611
1672
  body,
@@ -1666,6 +1727,9 @@ var LazyInvokeStep = class extends BaseLazyStep {
1666
1727
  userHeaders: context.headers,
1667
1728
  invokeCount
1668
1729
  });
1730
+ context.qstashClient.http.headers?.forEach((value, key) => {
1731
+ invokerHeaders[key] = value;
1732
+ });
1669
1733
  invokerHeaders["Upstash-Workflow-Runid"] = context.workflowRunId;
1670
1734
  let invokeBody;
1671
1735
  if (this.params.stringifyBody) {
@@ -1737,6 +1801,91 @@ var LazyInvokeStep = class extends BaseLazyStep {
1737
1801
  return [result];
1738
1802
  }
1739
1803
  };
1804
+ var LazyCreateWebhookStep = class extends BaseLazyStep {
1805
+ stepType = "CreateWebhook";
1806
+ allowUndefinedOut = false;
1807
+ getPlanStep(concurrent, targetStep) {
1808
+ return {
1809
+ stepId: 0,
1810
+ stepName: this.stepName,
1811
+ stepType: this.stepType,
1812
+ concurrent,
1813
+ targetStep
1814
+ };
1815
+ }
1816
+ async getResultStep(concurrent, stepId) {
1817
+ return {
1818
+ stepId,
1819
+ stepName: this.stepName,
1820
+ stepType: this.stepType,
1821
+ out: void 0,
1822
+ concurrent
1823
+ };
1824
+ }
1825
+ getBody({ step, context }) {
1826
+ const userId = getUserIdFromToken(context.qstashClient);
1827
+ const out = [userId, context.workflowRunId, getEventId()].join("/");
1828
+ return JSON.stringify({
1829
+ ...step,
1830
+ out
1831
+ });
1832
+ }
1833
+ safeParseOut(out) {
1834
+ const [userId, workflowRunId, eventId] = out.split("/");
1835
+ const qstashUrl = getQStashUrl(this.context.qstashClient);
1836
+ return {
1837
+ webhookUrl: `${qstashUrl}/v2/workflows/hooks/${userId}/${workflowRunId}/${eventId}`,
1838
+ eventId
1839
+ };
1840
+ }
1841
+ };
1842
+ var LazyWaitForWebhookStep = class extends LazyWaitEventStep {
1843
+ stepType = "WaitForWebhook";
1844
+ allowUndefinedOut = true;
1845
+ constructor(context, stepName, webhook, timeout) {
1846
+ super(context, stepName, webhook.eventId, timeout);
1847
+ }
1848
+ safeParseOut(out) {
1849
+ const eventData = decodeBase64(out);
1850
+ const parsedEventData = BaseLazyStep.tryParsing(eventData);
1851
+ const body = parsedEventData.body;
1852
+ const parsedBody = typeof body === "string" ? decodeBase64(body) : void 0;
1853
+ const request = new Request(
1854
+ `${parsedEventData.proto}://${parsedEventData.host}${parsedEventData.url}`,
1855
+ {
1856
+ method: parsedEventData.method,
1857
+ headers: parsedEventData.header,
1858
+ body: parsedBody
1859
+ }
1860
+ );
1861
+ return {
1862
+ request,
1863
+ timeout: false
1864
+ };
1865
+ }
1866
+ handleUndefinedOut() {
1867
+ return {
1868
+ timeout: true,
1869
+ request: void 0
1870
+ };
1871
+ }
1872
+ };
1873
+ var LazyWaitForEventStep = class extends LazyWaitEventStep {
1874
+ stepType = "Wait";
1875
+ allowUndefinedOut = true;
1876
+ parseWaitForEventOut(out, waitTimeout) {
1877
+ return {
1878
+ eventData: out ? BaseLazyStep.tryParsing(decodeBase64(out)) : void 0,
1879
+ timeout: waitTimeout ?? false
1880
+ };
1881
+ }
1882
+ safeParseOut(out, step) {
1883
+ return this.parseWaitForEventOut(out, step.waitTimeout);
1884
+ }
1885
+ handleUndefinedOut(step) {
1886
+ return this.parseWaitForEventOut(void 0, step.waitTimeout);
1887
+ }
1888
+ };
1740
1889
 
1741
1890
  // src/qstash/headers.ts
1742
1891
  var WorkflowHeaders = class {
@@ -2127,7 +2276,7 @@ var AutoExecutor = class _AutoExecutor {
2127
2276
  step,
2128
2277
  stepCount: this.stepCount
2129
2278
  });
2130
- return lazyStep.parseOut(step.out);
2279
+ return lazyStep.parseOut(step);
2131
2280
  }
2132
2281
  const resultStep = await submitSingleStep({
2133
2282
  context: this.context,
@@ -2198,7 +2347,7 @@ var AutoExecutor = class _AutoExecutor {
2198
2347
  });
2199
2348
  throw new WorkflowAbort(parallelStep.stepName, resultStep);
2200
2349
  } catch (error) {
2201
- if (error instanceof WorkflowAbort || error instanceof QstashError5 && error.status === 400) {
2350
+ if (isInstanceOf(error, WorkflowAbort) || isInstanceOf(error, QstashError5) && error.status === 400) {
2202
2351
  throw error;
2203
2352
  }
2204
2353
  throw new WorkflowError(
@@ -2214,7 +2363,7 @@ var AutoExecutor = class _AutoExecutor {
2214
2363
  const parallelResultSteps = sortedSteps.filter((step) => step.stepId >= initialStepCount).slice(0, parallelSteps.length);
2215
2364
  validateParallelSteps(parallelSteps, parallelResultSteps);
2216
2365
  return parallelResultSteps.map(
2217
- (step, index) => parallelSteps[index].parseOut(step.out)
2366
+ (step, index) => parallelSteps[index].parseOut(step)
2218
2367
  );
2219
2368
  }
2220
2369
  }
@@ -2270,7 +2419,6 @@ var AutoExecutor = class _AutoExecutor {
2270
2419
  * @param index index of the current step
2271
2420
  * @returns result[index] if lazyStepList > 1, otherwise result
2272
2421
  */
2273
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters
2274
2422
  static getResult(lazyStepList, result, index) {
2275
2423
  if (lazyStepList.length === 1) {
2276
2424
  return result;
@@ -2305,7 +2453,7 @@ var validateParallelSteps = (lazySteps, stepsFromRequest) => {
2305
2453
  validateStep(lazySteps[index], stepFromRequest);
2306
2454
  }
2307
2455
  } catch (error) {
2308
- if (error instanceof WorkflowError) {
2456
+ if (isInstanceOf(error, WorkflowError)) {
2309
2457
  const lazyStepNames = lazySteps.map((lazyStep) => lazyStep.stepName);
2310
2458
  const lazyStepTypes = lazySteps.map((lazyStep) => lazyStep.stepType);
2311
2459
  const requestStepNames = stepsFromRequest.map((step) => step.stepName);
@@ -2504,10 +2652,10 @@ var Agent = class {
2504
2652
  });
2505
2653
  return { text: result.text };
2506
2654
  } catch (error) {
2507
- if (error instanceof ToolExecutionError) {
2508
- if (error.cause instanceof Error && error.cause.name === "WorkflowAbort") {
2655
+ if (isInstanceOf(error, ToolExecutionError)) {
2656
+ if (error.cause instanceof Error && isInstanceOf(error.cause, WorkflowAbort)) {
2509
2657
  throw error.cause;
2510
- } else if (error.cause instanceof ToolExecutionError && error.cause.cause instanceof Error && error.cause.cause.name === "WorkflowAbort") {
2658
+ } else if (isInstanceOf(error.cause, ToolExecutionError) && isInstanceOf(error.cause.cause, WorkflowAbort)) {
2511
2659
  throw error.cause.cause;
2512
2660
  } else {
2513
2661
  throw error;
@@ -2903,7 +3051,7 @@ var WorkflowContext = class {
2903
3051
  */
2904
3052
  async run(stepName, stepFunction) {
2905
3053
  const wrappedStepFunction = () => this.executor.wrapStep(stepName, stepFunction);
2906
- return await this.addStep(new LazyFunctionStep(stepName, wrappedStepFunction));
3054
+ return await this.addStep(new LazyFunctionStep(this, stepName, wrappedStepFunction));
2907
3055
  }
2908
3056
  /**
2909
3057
  * Stops the execution for the duration provided.
@@ -2917,7 +3065,7 @@ var WorkflowContext = class {
2917
3065
  * @returns undefined
2918
3066
  */
2919
3067
  async sleep(stepName, duration) {
2920
- await this.addStep(new LazySleepStep(stepName, duration));
3068
+ await this.addStep(new LazySleepStep(this, stepName, duration));
2921
3069
  }
2922
3070
  /**
2923
3071
  * Stops the execution until the date time provided.
@@ -2939,13 +3087,14 @@ var WorkflowContext = class {
2939
3087
  datetime = typeof datetime === "string" ? new Date(datetime) : datetime;
2940
3088
  time = Math.round(datetime.getTime() / 1e3);
2941
3089
  }
2942
- await this.addStep(new LazySleepUntilStep(stepName, time));
3090
+ await this.addStep(new LazySleepUntilStep(this, stepName, time));
2943
3091
  }
2944
3092
  async call(stepName, settings) {
2945
3093
  let callStep;
2946
3094
  if ("workflow" in settings) {
2947
3095
  const url = getNewUrlFromWorkflowId(this.url, settings.workflow.workflowId);
2948
3096
  callStep = new LazyCallStep(
3097
+ this,
2949
3098
  stepName,
2950
3099
  url,
2951
3100
  "POST",
@@ -2970,6 +3119,7 @@ var WorkflowContext = class {
2970
3119
  stringifyBody = true
2971
3120
  } = settings;
2972
3121
  callStep = new LazyCallStep(
3122
+ this,
2973
3123
  stepName,
2974
3124
  url,
2975
3125
  method,
@@ -3021,7 +3171,9 @@ var WorkflowContext = class {
3021
3171
  async waitForEvent(stepName, eventId, options = {}) {
3022
3172
  const { timeout = "7d" } = options;
3023
3173
  const timeoutStr = typeof timeout === "string" ? timeout : `${timeout}s`;
3024
- return await this.addStep(new LazyWaitForEventStep(stepName, eventId, timeoutStr));
3174
+ return await this.addStep(
3175
+ new LazyWaitForEventStep(this, stepName, eventId, timeoutStr)
3176
+ );
3025
3177
  }
3026
3178
  /**
3027
3179
  * Notify workflow runs waiting for an event
@@ -3046,11 +3198,19 @@ var WorkflowContext = class {
3046
3198
  */
3047
3199
  async notify(stepName, eventId, eventData) {
3048
3200
  return await this.addStep(
3049
- new LazyNotifyStep(stepName, eventId, eventData, this.qstashClient.http)
3201
+ new LazyNotifyStep(this, stepName, eventId, eventData, this.qstashClient.http)
3050
3202
  );
3051
3203
  }
3052
3204
  async invoke(stepName, settings) {
3053
- return await this.addStep(new LazyInvokeStep(stepName, settings));
3205
+ return await this.addStep(
3206
+ new LazyInvokeStep(this, stepName, settings)
3207
+ );
3208
+ }
3209
+ async createWebhook(stepName) {
3210
+ return await this.addStep(new LazyCreateWebhookStep(this, stepName));
3211
+ }
3212
+ async waitForWebhook(stepName, webhook, timeout) {
3213
+ return await this.addStep(new LazyWaitForWebhookStep(this, stepName, webhook, timeout));
3054
3214
  }
3055
3215
  /**
3056
3216
  * Cancel the current workflow run
@@ -3181,7 +3341,7 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
3181
3341
  try {
3182
3342
  await routeFunction(disabledContext);
3183
3343
  } catch (error) {
3184
- if (error instanceof WorkflowAbort && error.stepName === this.disabledMessage || error instanceof WorkflowNonRetryableError) {
3344
+ if (isInstanceOf(error, WorkflowAbort) && error.stepName === this.disabledMessage || isInstanceOf(error, WorkflowNonRetryableError) || isInstanceOf(error, WorkflowRetryAfterError)) {
3185
3345
  return ok("step-found");
3186
3346
  }
3187
3347
  console.warn(
@@ -3214,13 +3374,6 @@ var processRawSteps = (rawSteps) => {
3214
3374
  const stepsToDecode = encodedSteps.filter((step) => step.callType === "step");
3215
3375
  const otherSteps = stepsToDecode.map((rawStep) => {
3216
3376
  const step = JSON.parse(decodeBase64(rawStep.body));
3217
- if (step.waitEventId) {
3218
- const newOut = {
3219
- eventData: step.out ? decodeBase64(step.out) : void 0,
3220
- timeout: step.waitTimeout ?? false
3221
- };
3222
- step.out = newOut;
3223
- }
3224
3377
  return step;
3225
3378
  });
3226
3379
  const steps = [initialStep, ...otherSteps];
@@ -3434,13 +3587,24 @@ var processOptions = (options) => {
3434
3587
  },
3435
3588
  status: 489
3436
3589
  });
3437
- } else if (detailedFinishCondition?.condition === "failure-callback") {
3438
- return new Response(detailedFinishCondition.result ?? void 0, {
3439
- status: 200,
3590
+ } else if (detailedFinishCondition?.condition === "retry-after-error") {
3591
+ return new Response(JSON.stringify(formatWorkflowError(detailedFinishCondition.result)), {
3440
3592
  headers: {
3593
+ "Retry-After": detailedFinishCondition.result.retryAfter.toString(),
3441
3594
  [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION
3442
- }
3595
+ },
3596
+ status: 429
3443
3597
  });
3598
+ } else if (detailedFinishCondition?.condition === "failure-callback") {
3599
+ return new Response(
3600
+ JSON.stringify({ result: detailedFinishCondition.result ?? void 0 }),
3601
+ {
3602
+ status: 200,
3603
+ headers: {
3604
+ [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION
3605
+ }
3606
+ }
3607
+ );
3444
3608
  }
3445
3609
  return new Response(JSON.stringify({ workflowRunId }), {
3446
3610
  status: 200,
@@ -3650,12 +3814,18 @@ var serveBase = (routeFunction, telemetry, options) => {
3650
3814
  },
3651
3815
  debug
3652
3816
  });
3653
- if (result.isOk() && result.value instanceof WorkflowNonRetryableError) {
3817
+ if (result.isOk() && isInstanceOf(result.value, WorkflowNonRetryableError)) {
3654
3818
  return onStepFinish(workflowRunId, result.value, {
3655
3819
  condition: "non-retryable-error",
3656
3820
  result: result.value
3657
3821
  });
3658
3822
  }
3823
+ if (result.isOk() && isInstanceOf(result.value, WorkflowRetryAfterError)) {
3824
+ return onStepFinish(workflowRunId, result.value, {
3825
+ condition: "retry-after-error",
3826
+ result: result.value
3827
+ });
3828
+ }
3659
3829
  if (result.isErr()) {
3660
3830
  await debug?.log("ERROR", "ERROR", { error: result.error.message });
3661
3831
  throw result.error;
@@ -3686,7 +3856,7 @@ var serveBase = (routeFunction, telemetry, options) => {
3686
3856
  const errorMessage = `Error while running onError callback: '${formattedOnErrorError.message}'.
3687
3857
  Original error: '${formattedError.message}'`;
3688
3858
  console.error(errorMessage);
3689
- return new Response(errorMessage, {
3859
+ return new Response(JSON.stringify({ error: errorMessage }), {
3690
3860
  status: 500,
3691
3861
  headers: {
3692
3862
  [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION
@@ -3715,13 +3885,14 @@ var serve = (routeFunction, options) => {
3715
3885
  };
3716
3886
 
3717
3887
  export {
3888
+ WorkflowError,
3889
+ WorkflowAbort,
3890
+ WorkflowNonRetryableError,
3891
+ WorkflowRetryAfterError,
3718
3892
  makeNotifyRequest,
3719
3893
  makeGetWaitersRequest,
3720
3894
  WORKFLOW_LABEL_HEADER,
3721
3895
  SDK_TELEMETRY,
3722
- WorkflowError,
3723
- WorkflowAbort,
3724
- WorkflowNonRetryableError,
3725
3896
  getWorkflowRunId,
3726
3897
  StepTypes,
3727
3898
  triggerFirstInvocation,