@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.
package/h3.js CHANGED
@@ -339,7 +339,95 @@ var H3Headers = globalThis.Headers;
339
339
  var H3Response = globalThis.Response;
340
340
 
341
341
  // src/client/utils.ts
342
+ var import_qstash2 = require("@upstash/qstash");
343
+
344
+ // src/error.ts
342
345
  var import_qstash = require("@upstash/qstash");
346
+ var WorkflowError = class extends import_qstash.QstashError {
347
+ constructor(message) {
348
+ super(message);
349
+ this.name = "WorkflowError";
350
+ }
351
+ };
352
+ var WorkflowAbort = class extends Error {
353
+ stepInfo;
354
+ stepName;
355
+ /**
356
+ * whether workflow is to be canceled on abort
357
+ */
358
+ cancelWorkflow;
359
+ /**
360
+ *
361
+ * @param stepName name of the aborting step
362
+ * @param stepInfo step information
363
+ * @param cancelWorkflow
364
+ */
365
+ constructor(stepName, stepInfo, cancelWorkflow = false) {
366
+ super(
367
+ `This is an Upstash Workflow error thrown after a step executes. It is expected to be raised. Make sure that you await for each step. Also, if you are using try/catch blocks, you should not wrap context.run/sleep/sleepUntil/call methods with try/catch. Aborting workflow after executing step '${stepName}'.`
368
+ );
369
+ this.name = "WorkflowAbort";
370
+ this.stepName = stepName;
371
+ this.stepInfo = stepInfo;
372
+ this.cancelWorkflow = cancelWorkflow;
373
+ }
374
+ };
375
+ var WorkflowNonRetryableError = class extends WorkflowAbort {
376
+ /**
377
+ * @param message error message to be displayed
378
+ */
379
+ constructor(message) {
380
+ super("fail", void 0, false);
381
+ this.name = "WorkflowNonRetryableError";
382
+ if (message) this.message = message;
383
+ }
384
+ };
385
+ var WorkflowRetryAfterError = class extends WorkflowAbort {
386
+ retryAfter;
387
+ /**
388
+ * @param retryAfter time in seconds after which the workflow should be retried
389
+ * @param message error message to be displayed
390
+ */
391
+ constructor(message, retryAfter) {
392
+ super("retry", void 0, false);
393
+ this.name = "WorkflowRetryAfterError";
394
+ this.retryAfter = retryAfter;
395
+ if (message) this.message = message;
396
+ }
397
+ };
398
+ var formatWorkflowError = (error) => {
399
+ return error instanceof Error ? {
400
+ error: error.name,
401
+ message: error.message,
402
+ stack: error.stack
403
+ } : {
404
+ error: "Error",
405
+ message: `An error occured while executing workflow: '${typeof error === "string" ? error : JSON.stringify(error)}'`
406
+ };
407
+ };
408
+ function getConstructorName(obj) {
409
+ if (obj === null || obj === void 0) {
410
+ return null;
411
+ }
412
+ const ctor = obj.constructor;
413
+ if (!ctor || ctor.name === "Object") {
414
+ return null;
415
+ }
416
+ return ctor.name;
417
+ }
418
+ function getConstructorNames(obj) {
419
+ const proto = Object.getPrototypeOf(obj);
420
+ const name = getConstructorName(proto);
421
+ if (name === null) {
422
+ return [];
423
+ }
424
+ return [name, ...getConstructorNames(proto)];
425
+ }
426
+ function isInstanceOf(v, ctor) {
427
+ return getConstructorNames(v).includes(ctor.name);
428
+ }
429
+
430
+ // src/client/utils.ts
343
431
  var makeNotifyRequest = async (requester, eventId, eventData) => {
344
432
  const result = await requester.request({
345
433
  path: ["v2", "notify", eventId],
@@ -379,7 +467,7 @@ var getSteps = async (requester, workflowRunId, messageId, debug) => {
379
467
  return { steps: filteredSteps, workflowRunEnded: false };
380
468
  }
381
469
  } catch (error) {
382
- if (error instanceof import_qstash.QstashError && error.status === 404) {
470
+ if (isInstanceOf(error, import_qstash2.QstashError) && error.status === 404) {
383
471
  await debug?.log("WARN", "ENDPOINT_START", {
384
472
  message: "Couldn't fetch workflow run steps. This can happen if the workflow run succesfully ends before some callback is executed.",
385
473
  error
@@ -404,65 +492,13 @@ var WORKFLOW_PROTOCOL_VERSION_HEADER = "Upstash-Workflow-Sdk-Version";
404
492
  var DEFAULT_CONTENT_TYPE = "application/json";
405
493
  var NO_CONCURRENCY = 1;
406
494
  var DEFAULT_RETRIES = 3;
407
- var VERSION = "v0.2.21";
495
+ var VERSION = "v0.2.22";
408
496
  var SDK_TELEMETRY = `@upstash/workflow@${VERSION}`;
409
497
  var TELEMETRY_HEADER_SDK = "Upstash-Telemetry-Sdk";
410
498
  var TELEMETRY_HEADER_FRAMEWORK = "Upstash-Telemetry-Framework";
411
499
  var TELEMETRY_HEADER_RUNTIME = "Upstash-Telemetry-Runtime";
412
500
  var TELEMETRY_HEADER_AGENT = "Upstash-Telemetry-Agent";
413
501
 
414
- // src/error.ts
415
- var import_qstash2 = require("@upstash/qstash");
416
- var WorkflowError = class extends import_qstash2.QstashError {
417
- constructor(message) {
418
- super(message);
419
- this.name = "WorkflowError";
420
- }
421
- };
422
- var WorkflowAbort = class extends Error {
423
- stepInfo;
424
- stepName;
425
- /**
426
- * whether workflow is to be canceled on abort
427
- */
428
- cancelWorkflow;
429
- /**
430
- *
431
- * @param stepName name of the aborting step
432
- * @param stepInfo step information
433
- * @param cancelWorkflow
434
- */
435
- constructor(stepName, stepInfo, cancelWorkflow = false) {
436
- super(
437
- `This is an Upstash Workflow error thrown after a step executes. It is expected to be raised. Make sure that you await for each step. Also, if you are using try/catch blocks, you should not wrap context.run/sleep/sleepUntil/call methods with try/catch. Aborting workflow after executing step '${stepName}'.`
438
- );
439
- this.name = "WorkflowAbort";
440
- this.stepName = stepName;
441
- this.stepInfo = stepInfo;
442
- this.cancelWorkflow = cancelWorkflow;
443
- }
444
- };
445
- var WorkflowNonRetryableError = class extends WorkflowAbort {
446
- /**
447
- * @param message error message to be displayed
448
- */
449
- constructor(message) {
450
- super("fail", void 0, false);
451
- this.name = "WorkflowNonRetryableError";
452
- if (message) this.message = message;
453
- }
454
- };
455
- var formatWorkflowError = (error) => {
456
- return error instanceof Error ? {
457
- error: error.name,
458
- message: error.message,
459
- stack: error.stack
460
- } : {
461
- error: "Error",
462
- message: `An error occured while executing workflow: '${typeof error === "string" ? error : JSON.stringify(error)}'`
463
- };
464
- };
465
-
466
502
  // src/context/auto-executor.ts
467
503
  var import_qstash5 = require("@upstash/qstash");
468
504
 
@@ -475,8 +511,8 @@ var NANOID_LENGTH = 21;
475
511
  function getRandomInt() {
476
512
  return Math.floor(Math.random() * NANOID_CHARS.length);
477
513
  }
478
- function nanoid() {
479
- return Array.from({ length: NANOID_LENGTH }).map(() => NANOID_CHARS[getRandomInt()]).join("");
514
+ function nanoid(length = NANOID_LENGTH) {
515
+ return Array.from({ length }).map(() => NANOID_CHARS[getRandomInt()]).join("");
480
516
  }
481
517
  function getWorkflowRunId(id) {
482
518
  return `wfr_${id ?? nanoid()}`;
@@ -493,6 +529,37 @@ function decodeBase64(base64) {
493
529
  return binString;
494
530
  }
495
531
  }
532
+ function getUserIdFromToken(qstashClient) {
533
+ try {
534
+ const token = qstashClient.token;
535
+ const decodedToken = decodeBase64(token);
536
+ const tokenPayload = JSON.parse(decodedToken);
537
+ const userId = tokenPayload.UserID;
538
+ if (!userId) {
539
+ throw new WorkflowError("QStash token payload does not contain userId");
540
+ }
541
+ return userId;
542
+ } catch (error) {
543
+ throw new WorkflowError(
544
+ `Failed to decode QStash token while running create webhook step: ${error.message}`
545
+ );
546
+ }
547
+ }
548
+ function getQStashUrl(qstashClient) {
549
+ try {
550
+ const requester = qstashClient.http;
551
+ const baseUrl = requester.baseUrl;
552
+ if (!baseUrl) {
553
+ throw new WorkflowError("QStash client does not have a baseUrl");
554
+ }
555
+ return baseUrl;
556
+ } catch (error) {
557
+ throw new WorkflowError(`Failed to get QStash URL from client: ${error.message}`);
558
+ }
559
+ }
560
+ function getEventId() {
561
+ return `evt_${nanoid(15)}`;
562
+ }
496
563
 
497
564
  // node_modules/neverthrow/dist/index.es.js
498
565
  var defaultErrorConfig = {
@@ -918,7 +985,9 @@ var StepTypes = [
918
985
  "Call",
919
986
  "Wait",
920
987
  "Notify",
921
- "Invoke"
988
+ "Invoke",
989
+ "CreateWebhook",
990
+ "WaitForWebhook"
922
991
  ];
923
992
 
924
993
  // src/workflow-requests.ts
@@ -1022,17 +1091,17 @@ var triggerRouteFunction = async ({
1022
1091
  return ok("workflow-finished");
1023
1092
  } catch (error) {
1024
1093
  const error_ = error;
1025
- if (error instanceof import_qstash3.QstashError && error.status === 400) {
1094
+ if (isInstanceOf(error, import_qstash3.QstashError) && error.status === 400) {
1026
1095
  await debug?.log("WARN", "RESPONSE_WORKFLOW", {
1027
1096
  message: `tried to append to a cancelled workflow. exiting without publishing.`,
1028
1097
  name: error.name,
1029
1098
  errorMessage: error.message
1030
1099
  });
1031
1100
  return ok("workflow-was-finished");
1032
- } else if (!(error_ instanceof WorkflowAbort)) {
1033
- return err(error_);
1034
- } else if (error_ instanceof WorkflowNonRetryableError) {
1101
+ } else if (isInstanceOf(error_, WorkflowNonRetryableError) || isInstanceOf(error_, WorkflowRetryAfterError)) {
1035
1102
  return ok(error_);
1103
+ } else if (!isInstanceOf(error_, WorkflowAbort)) {
1104
+ return err(error_);
1036
1105
  } else if (error_.cancelWorkflow) {
1037
1106
  await onCancel();
1038
1107
  return ok("workflow-finished");
@@ -1230,7 +1299,9 @@ If you want to disable QStash Verification, you should clear env variables QSTAS
1230
1299
  // src/context/steps.ts
1231
1300
  var BaseLazyStep = class _BaseLazyStep {
1232
1301
  stepName;
1233
- constructor(stepName) {
1302
+ context;
1303
+ constructor(context, stepName) {
1304
+ this.context = context;
1234
1305
  if (!stepName) {
1235
1306
  throw new WorkflowError(
1236
1307
  "A workflow step name cannot be undefined or an empty string. Please provide a name for your workflow step."
@@ -1248,13 +1319,14 @@ var BaseLazyStep = class _BaseLazyStep {
1248
1319
  *
1249
1320
  * will be called when returning the steps to the context from auto executor
1250
1321
  *
1251
- * @param out field of the step
1322
+ * @param step step
1252
1323
  * @returns parsed out field
1253
1324
  */
1254
- parseOut(out) {
1325
+ parseOut(step) {
1326
+ const out = step.out;
1255
1327
  if (out === void 0) {
1256
1328
  if (this.allowUndefinedOut) {
1257
- return void 0;
1329
+ return this.handleUndefinedOut(step);
1258
1330
  } else {
1259
1331
  throw new WorkflowError(
1260
1332
  `Error while parsing output of ${this.stepType} step. Expected a string, but got: undefined`
@@ -1262,27 +1334,26 @@ var BaseLazyStep = class _BaseLazyStep {
1262
1334
  }
1263
1335
  }
1264
1336
  if (typeof out === "object") {
1265
- if (this.stepType !== "Wait") {
1266
- console.warn(
1267
- `Error while parsing ${this.stepType} step output. Expected a string, but got object. Please reach out to Upstash Support.`
1268
- );
1269
- return out;
1270
- }
1271
- return {
1272
- ...out,
1273
- eventData: _BaseLazyStep.tryParsing(out.eventData)
1274
- };
1337
+ console.warn(
1338
+ `Error while parsing ${this.stepType} step output. Expected a string, but got object. Please reach out to Upstash Support.`
1339
+ );
1340
+ return out;
1275
1341
  }
1276
1342
  if (typeof out !== "string") {
1277
1343
  throw new WorkflowError(
1278
1344
  `Error while parsing output of ${this.stepType} step. Expected a string or undefined, but got: ${typeof out}`
1279
1345
  );
1280
1346
  }
1281
- return this.safeParseOut(out);
1347
+ return this.safeParseOut(out, step);
1282
1348
  }
1283
- safeParseOut(out) {
1349
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1350
+ safeParseOut(out, step) {
1284
1351
  return _BaseLazyStep.tryParsing(out);
1285
1352
  }
1353
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1354
+ handleUndefinedOut(step) {
1355
+ return void 0;
1356
+ }
1286
1357
  static tryParsing(stepOut) {
1287
1358
  try {
1288
1359
  return JSON.parse(stepOut);
@@ -1333,8 +1404,8 @@ var LazyFunctionStep = class extends BaseLazyStep {
1333
1404
  stepFunction;
1334
1405
  stepType = "Run";
1335
1406
  allowUndefinedOut = true;
1336
- constructor(stepName, stepFunction) {
1337
- super(stepName);
1407
+ constructor(context, stepName, stepFunction) {
1408
+ super(context, stepName);
1338
1409
  this.stepFunction = stepFunction;
1339
1410
  }
1340
1411
  getPlanStep(concurrent, targetStep) {
@@ -1364,8 +1435,8 @@ var LazySleepStep = class extends BaseLazyStep {
1364
1435
  sleep;
1365
1436
  stepType = "SleepFor";
1366
1437
  allowUndefinedOut = true;
1367
- constructor(stepName, sleep) {
1368
- super(stepName);
1438
+ constructor(context, stepName, sleep) {
1439
+ super(context, stepName);
1369
1440
  this.sleep = sleep;
1370
1441
  }
1371
1442
  getPlanStep(concurrent, targetStep) {
@@ -1406,8 +1477,8 @@ var LazySleepUntilStep = class extends BaseLazyStep {
1406
1477
  sleepUntil;
1407
1478
  stepType = "SleepUntil";
1408
1479
  allowUndefinedOut = true;
1409
- constructor(stepName, sleepUntil) {
1410
- super(stepName);
1480
+ constructor(context, stepName, sleepUntil) {
1481
+ super(context, stepName);
1411
1482
  this.sleepUntil = sleepUntil;
1412
1483
  }
1413
1484
  getPlanStep(concurrent, targetStep) {
@@ -1459,8 +1530,8 @@ var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
1459
1530
  stringifyBody;
1460
1531
  stepType = "Call";
1461
1532
  allowUndefinedOut = false;
1462
- constructor(stepName, url, method, body, headers, retries, retryDelay, timeout, flowControl, stringifyBody) {
1463
- super(stepName);
1533
+ constructor(context, stepName, url, method, body, headers, retries, retryDelay, timeout, flowControl, stringifyBody) {
1534
+ super(context, stepName);
1464
1535
  this.url = url;
1465
1536
  this.method = method;
1466
1537
  this.body = body;
@@ -1604,13 +1675,12 @@ var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
1604
1675
  ]);
1605
1676
  }
1606
1677
  };
1607
- var LazyWaitForEventStep = class extends BaseLazyStep {
1678
+ var LazyWaitEventStep = class extends BaseLazyStep {
1608
1679
  eventId;
1609
1680
  timeout;
1610
- stepType = "Wait";
1611
1681
  allowUndefinedOut = false;
1612
- constructor(stepName, eventId, timeout) {
1613
- super(stepName);
1682
+ constructor(context, stepName, eventId, timeout) {
1683
+ super(context, stepName);
1614
1684
  this.eventId = eventId;
1615
1685
  this.timeout = timeout;
1616
1686
  }
@@ -1635,13 +1705,6 @@ var LazyWaitForEventStep = class extends BaseLazyStep {
1635
1705
  concurrent
1636
1706
  });
1637
1707
  }
1638
- safeParseOut(out) {
1639
- const result = JSON.parse(out);
1640
- return {
1641
- ...result,
1642
- eventData: BaseLazyStep.tryParsing(result.eventData)
1643
- };
1644
- }
1645
1708
  getHeaders({ context, telemetry: telemetry2, invokeCount, step }) {
1646
1709
  const headers = super.getHeaders({ context, telemetry: telemetry2, invokeCount, step });
1647
1710
  headers.headers["Upstash-Workflow-CallType"] = "step";
@@ -1675,7 +1738,7 @@ var LazyWaitForEventStep = class extends BaseLazyStep {
1675
1738
  timeoutHeaders,
1676
1739
  step: {
1677
1740
  stepId: step.stepId,
1678
- stepType: "Wait",
1741
+ stepType: this.stepType,
1679
1742
  stepName: step.stepName,
1680
1743
  concurrent: step.concurrent,
1681
1744
  targetStep: step.targetStep
@@ -1696,8 +1759,8 @@ var LazyWaitForEventStep = class extends BaseLazyStep {
1696
1759
  };
1697
1760
  var LazyNotifyStep = class extends LazyFunctionStep {
1698
1761
  stepType = "Notify";
1699
- constructor(stepName, eventId, eventData, requester) {
1700
- super(stepName, async () => {
1762
+ constructor(context, stepName, eventId, eventData, requester) {
1763
+ super(context, stepName, async () => {
1701
1764
  const notifyResponse = await makeNotifyRequest(requester, eventId, eventData);
1702
1765
  return {
1703
1766
  eventId,
@@ -1722,7 +1785,7 @@ var LazyInvokeStep = class extends BaseLazyStep {
1722
1785
  * workflow id of the invoked workflow
1723
1786
  */
1724
1787
  workflowId;
1725
- constructor(stepName, {
1788
+ constructor(context, stepName, {
1726
1789
  workflow,
1727
1790
  body,
1728
1791
  headers = {},
@@ -1732,7 +1795,7 @@ var LazyInvokeStep = class extends BaseLazyStep {
1732
1795
  flowControl,
1733
1796
  stringifyBody = true
1734
1797
  }) {
1735
- super(stepName);
1798
+ super(context, stepName);
1736
1799
  this.params = {
1737
1800
  workflow,
1738
1801
  body,
@@ -1793,6 +1856,9 @@ var LazyInvokeStep = class extends BaseLazyStep {
1793
1856
  userHeaders: context.headers,
1794
1857
  invokeCount
1795
1858
  });
1859
+ context.qstashClient.http.headers?.forEach((value, key) => {
1860
+ invokerHeaders[key] = value;
1861
+ });
1796
1862
  invokerHeaders["Upstash-Workflow-Runid"] = context.workflowRunId;
1797
1863
  let invokeBody;
1798
1864
  if (this.params.stringifyBody) {
@@ -1864,6 +1930,91 @@ var LazyInvokeStep = class extends BaseLazyStep {
1864
1930
  return [result];
1865
1931
  }
1866
1932
  };
1933
+ var LazyCreateWebhookStep = class extends BaseLazyStep {
1934
+ stepType = "CreateWebhook";
1935
+ allowUndefinedOut = false;
1936
+ getPlanStep(concurrent, targetStep) {
1937
+ return {
1938
+ stepId: 0,
1939
+ stepName: this.stepName,
1940
+ stepType: this.stepType,
1941
+ concurrent,
1942
+ targetStep
1943
+ };
1944
+ }
1945
+ async getResultStep(concurrent, stepId) {
1946
+ return {
1947
+ stepId,
1948
+ stepName: this.stepName,
1949
+ stepType: this.stepType,
1950
+ out: void 0,
1951
+ concurrent
1952
+ };
1953
+ }
1954
+ getBody({ step, context }) {
1955
+ const userId = getUserIdFromToken(context.qstashClient);
1956
+ const out = [userId, context.workflowRunId, getEventId()].join("/");
1957
+ return JSON.stringify({
1958
+ ...step,
1959
+ out
1960
+ });
1961
+ }
1962
+ safeParseOut(out) {
1963
+ const [userId, workflowRunId, eventId] = out.split("/");
1964
+ const qstashUrl = getQStashUrl(this.context.qstashClient);
1965
+ return {
1966
+ webhookUrl: `${qstashUrl}/v2/workflows/hooks/${userId}/${workflowRunId}/${eventId}`,
1967
+ eventId
1968
+ };
1969
+ }
1970
+ };
1971
+ var LazyWaitForWebhookStep = class extends LazyWaitEventStep {
1972
+ stepType = "WaitForWebhook";
1973
+ allowUndefinedOut = true;
1974
+ constructor(context, stepName, webhook, timeout) {
1975
+ super(context, stepName, webhook.eventId, timeout);
1976
+ }
1977
+ safeParseOut(out) {
1978
+ const eventData = decodeBase64(out);
1979
+ const parsedEventData = BaseLazyStep.tryParsing(eventData);
1980
+ const body = parsedEventData.body;
1981
+ const parsedBody = typeof body === "string" ? decodeBase64(body) : void 0;
1982
+ const request = new Request(
1983
+ `${parsedEventData.proto}://${parsedEventData.host}${parsedEventData.url}`,
1984
+ {
1985
+ method: parsedEventData.method,
1986
+ headers: parsedEventData.header,
1987
+ body: parsedBody
1988
+ }
1989
+ );
1990
+ return {
1991
+ request,
1992
+ timeout: false
1993
+ };
1994
+ }
1995
+ handleUndefinedOut() {
1996
+ return {
1997
+ timeout: true,
1998
+ request: void 0
1999
+ };
2000
+ }
2001
+ };
2002
+ var LazyWaitForEventStep = class extends LazyWaitEventStep {
2003
+ stepType = "Wait";
2004
+ allowUndefinedOut = true;
2005
+ parseWaitForEventOut(out, waitTimeout) {
2006
+ return {
2007
+ eventData: out ? BaseLazyStep.tryParsing(decodeBase64(out)) : void 0,
2008
+ timeout: waitTimeout ?? false
2009
+ };
2010
+ }
2011
+ safeParseOut(out, step) {
2012
+ return this.parseWaitForEventOut(out, step.waitTimeout);
2013
+ }
2014
+ handleUndefinedOut(step) {
2015
+ return this.parseWaitForEventOut(void 0, step.waitTimeout);
2016
+ }
2017
+ };
1867
2018
 
1868
2019
  // src/agents/constants.ts
1869
2020
  var AGENT_NAME_HEADER = "upstash-agent-name";
@@ -2268,7 +2419,7 @@ var AutoExecutor = class _AutoExecutor {
2268
2419
  step,
2269
2420
  stepCount: this.stepCount
2270
2421
  });
2271
- return lazyStep.parseOut(step.out);
2422
+ return lazyStep.parseOut(step);
2272
2423
  }
2273
2424
  const resultStep = await submitSingleStep({
2274
2425
  context: this.context,
@@ -2339,7 +2490,7 @@ var AutoExecutor = class _AutoExecutor {
2339
2490
  });
2340
2491
  throw new WorkflowAbort(parallelStep.stepName, resultStep);
2341
2492
  } catch (error) {
2342
- if (error instanceof WorkflowAbort || error instanceof import_qstash5.QstashError && error.status === 400) {
2493
+ if (isInstanceOf(error, WorkflowAbort) || isInstanceOf(error, import_qstash5.QstashError) && error.status === 400) {
2343
2494
  throw error;
2344
2495
  }
2345
2496
  throw new WorkflowError(
@@ -2355,7 +2506,7 @@ var AutoExecutor = class _AutoExecutor {
2355
2506
  const parallelResultSteps = sortedSteps.filter((step) => step.stepId >= initialStepCount).slice(0, parallelSteps.length);
2356
2507
  validateParallelSteps(parallelSteps, parallelResultSteps);
2357
2508
  return parallelResultSteps.map(
2358
- (step, index) => parallelSteps[index].parseOut(step.out)
2509
+ (step, index) => parallelSteps[index].parseOut(step)
2359
2510
  );
2360
2511
  }
2361
2512
  }
@@ -2411,7 +2562,6 @@ var AutoExecutor = class _AutoExecutor {
2411
2562
  * @param index index of the current step
2412
2563
  * @returns result[index] if lazyStepList > 1, otherwise result
2413
2564
  */
2414
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters
2415
2565
  static getResult(lazyStepList, result, index) {
2416
2566
  if (lazyStepList.length === 1) {
2417
2567
  return result;
@@ -2446,7 +2596,7 @@ var validateParallelSteps = (lazySteps, stepsFromRequest) => {
2446
2596
  validateStep(lazySteps[index], stepFromRequest);
2447
2597
  }
2448
2598
  } catch (error) {
2449
- if (error instanceof WorkflowError) {
2599
+ if (isInstanceOf(error, WorkflowError)) {
2450
2600
  const lazyStepNames = lazySteps.map((lazyStep) => lazyStep.stepName);
2451
2601
  const lazyStepTypes = lazySteps.map((lazyStep) => lazyStep.stepType);
2452
2602
  const requestStepNames = stepsFromRequest.map((step) => step.stepName);
@@ -2627,7 +2777,7 @@ var fetchWithContextCall = async (context, agentCallParams, ...params) => {
2627
2777
  headers: responseHeaders
2628
2778
  });
2629
2779
  } catch (error) {
2630
- if (error instanceof Error && error.name === "WorkflowAbort") {
2780
+ if (error instanceof Error && isInstanceOf(error, WorkflowAbort)) {
2631
2781
  throw error;
2632
2782
  } else {
2633
2783
  console.error("Error in fetch implementation:", error);
@@ -2729,10 +2879,10 @@ var Agent = class {
2729
2879
  });
2730
2880
  return { text: result.text };
2731
2881
  } catch (error) {
2732
- if (error instanceof import_ai2.ToolExecutionError) {
2733
- if (error.cause instanceof Error && error.cause.name === "WorkflowAbort") {
2882
+ if (isInstanceOf(error, import_ai2.ToolExecutionError)) {
2883
+ if (error.cause instanceof Error && isInstanceOf(error.cause, WorkflowAbort)) {
2734
2884
  throw error.cause;
2735
- } else if (error.cause instanceof import_ai2.ToolExecutionError && error.cause.cause instanceof Error && error.cause.cause.name === "WorkflowAbort") {
2885
+ } else if (isInstanceOf(error.cause, import_ai2.ToolExecutionError) && isInstanceOf(error.cause.cause, WorkflowAbort)) {
2736
2886
  throw error.cause.cause;
2737
2887
  } else {
2738
2888
  throw error;
@@ -3203,7 +3353,7 @@ var WorkflowContext = class {
3203
3353
  */
3204
3354
  async run(stepName, stepFunction) {
3205
3355
  const wrappedStepFunction = () => this.executor.wrapStep(stepName, stepFunction);
3206
- return await this.addStep(new LazyFunctionStep(stepName, wrappedStepFunction));
3356
+ return await this.addStep(new LazyFunctionStep(this, stepName, wrappedStepFunction));
3207
3357
  }
3208
3358
  /**
3209
3359
  * Stops the execution for the duration provided.
@@ -3217,7 +3367,7 @@ var WorkflowContext = class {
3217
3367
  * @returns undefined
3218
3368
  */
3219
3369
  async sleep(stepName, duration) {
3220
- await this.addStep(new LazySleepStep(stepName, duration));
3370
+ await this.addStep(new LazySleepStep(this, stepName, duration));
3221
3371
  }
3222
3372
  /**
3223
3373
  * Stops the execution until the date time provided.
@@ -3239,13 +3389,14 @@ var WorkflowContext = class {
3239
3389
  datetime = typeof datetime === "string" ? new Date(datetime) : datetime;
3240
3390
  time = Math.round(datetime.getTime() / 1e3);
3241
3391
  }
3242
- await this.addStep(new LazySleepUntilStep(stepName, time));
3392
+ await this.addStep(new LazySleepUntilStep(this, stepName, time));
3243
3393
  }
3244
3394
  async call(stepName, settings) {
3245
3395
  let callStep;
3246
3396
  if ("workflow" in settings) {
3247
3397
  const url = getNewUrlFromWorkflowId(this.url, settings.workflow.workflowId);
3248
3398
  callStep = new LazyCallStep(
3399
+ this,
3249
3400
  stepName,
3250
3401
  url,
3251
3402
  "POST",
@@ -3270,6 +3421,7 @@ var WorkflowContext = class {
3270
3421
  stringifyBody = true
3271
3422
  } = settings;
3272
3423
  callStep = new LazyCallStep(
3424
+ this,
3273
3425
  stepName,
3274
3426
  url,
3275
3427
  method,
@@ -3321,7 +3473,9 @@ var WorkflowContext = class {
3321
3473
  async waitForEvent(stepName, eventId, options = {}) {
3322
3474
  const { timeout = "7d" } = options;
3323
3475
  const timeoutStr = typeof timeout === "string" ? timeout : `${timeout}s`;
3324
- return await this.addStep(new LazyWaitForEventStep(stepName, eventId, timeoutStr));
3476
+ return await this.addStep(
3477
+ new LazyWaitForEventStep(this, stepName, eventId, timeoutStr)
3478
+ );
3325
3479
  }
3326
3480
  /**
3327
3481
  * Notify workflow runs waiting for an event
@@ -3346,11 +3500,19 @@ var WorkflowContext = class {
3346
3500
  */
3347
3501
  async notify(stepName, eventId, eventData) {
3348
3502
  return await this.addStep(
3349
- new LazyNotifyStep(stepName, eventId, eventData, this.qstashClient.http)
3503
+ new LazyNotifyStep(this, stepName, eventId, eventData, this.qstashClient.http)
3350
3504
  );
3351
3505
  }
3352
3506
  async invoke(stepName, settings) {
3353
- return await this.addStep(new LazyInvokeStep(stepName, settings));
3507
+ return await this.addStep(
3508
+ new LazyInvokeStep(this, stepName, settings)
3509
+ );
3510
+ }
3511
+ async createWebhook(stepName) {
3512
+ return await this.addStep(new LazyCreateWebhookStep(this, stepName));
3513
+ }
3514
+ async waitForWebhook(stepName, webhook, timeout) {
3515
+ return await this.addStep(new LazyWaitForWebhookStep(this, stepName, webhook, timeout));
3354
3516
  }
3355
3517
  /**
3356
3518
  * Cancel the current workflow run
@@ -3481,7 +3643,7 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
3481
3643
  try {
3482
3644
  await routeFunction(disabledContext);
3483
3645
  } catch (error) {
3484
- if (error instanceof WorkflowAbort && error.stepName === this.disabledMessage || error instanceof WorkflowNonRetryableError) {
3646
+ if (isInstanceOf(error, WorkflowAbort) && error.stepName === this.disabledMessage || isInstanceOf(error, WorkflowNonRetryableError) || isInstanceOf(error, WorkflowRetryAfterError)) {
3485
3647
  return ok("step-found");
3486
3648
  }
3487
3649
  console.warn(
@@ -3514,13 +3676,6 @@ var processRawSteps = (rawSteps) => {
3514
3676
  const stepsToDecode = encodedSteps.filter((step) => step.callType === "step");
3515
3677
  const otherSteps = stepsToDecode.map((rawStep) => {
3516
3678
  const step = JSON.parse(decodeBase64(rawStep.body));
3517
- if (step.waitEventId) {
3518
- const newOut = {
3519
- eventData: step.out ? decodeBase64(step.out) : void 0,
3520
- timeout: step.waitTimeout ?? false
3521
- };
3522
- step.out = newOut;
3523
- }
3524
3679
  return step;
3525
3680
  });
3526
3681
  const steps = [initialStep, ...otherSteps];
@@ -3734,13 +3889,24 @@ var processOptions = (options) => {
3734
3889
  },
3735
3890
  status: 489
3736
3891
  });
3737
- } else if (detailedFinishCondition?.condition === "failure-callback") {
3738
- return new Response(detailedFinishCondition.result ?? void 0, {
3739
- status: 200,
3892
+ } else if (detailedFinishCondition?.condition === "retry-after-error") {
3893
+ return new Response(JSON.stringify(formatWorkflowError(detailedFinishCondition.result)), {
3740
3894
  headers: {
3895
+ "Retry-After": detailedFinishCondition.result.retryAfter.toString(),
3741
3896
  [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION
3742
- }
3897
+ },
3898
+ status: 429
3743
3899
  });
3900
+ } else if (detailedFinishCondition?.condition === "failure-callback") {
3901
+ return new Response(
3902
+ JSON.stringify({ result: detailedFinishCondition.result ?? void 0 }),
3903
+ {
3904
+ status: 200,
3905
+ headers: {
3906
+ [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION
3907
+ }
3908
+ }
3909
+ );
3744
3910
  }
3745
3911
  return new Response(JSON.stringify({ workflowRunId }), {
3746
3912
  status: 200,
@@ -3950,12 +4116,18 @@ var serveBase = (routeFunction, telemetry2, options) => {
3950
4116
  },
3951
4117
  debug
3952
4118
  });
3953
- if (result.isOk() && result.value instanceof WorkflowNonRetryableError) {
4119
+ if (result.isOk() && isInstanceOf(result.value, WorkflowNonRetryableError)) {
3954
4120
  return onStepFinish(workflowRunId, result.value, {
3955
4121
  condition: "non-retryable-error",
3956
4122
  result: result.value
3957
4123
  });
3958
4124
  }
4125
+ if (result.isOk() && isInstanceOf(result.value, WorkflowRetryAfterError)) {
4126
+ return onStepFinish(workflowRunId, result.value, {
4127
+ condition: "retry-after-error",
4128
+ result: result.value
4129
+ });
4130
+ }
3959
4131
  if (result.isErr()) {
3960
4132
  await debug?.log("ERROR", "ERROR", { error: result.error.message });
3961
4133
  throw result.error;
@@ -3986,7 +4158,7 @@ var serveBase = (routeFunction, telemetry2, options) => {
3986
4158
  const errorMessage = `Error while running onError callback: '${formattedOnErrorError.message}'.
3987
4159
  Original error: '${formattedError.message}'`;
3988
4160
  console.error(errorMessage);
3989
- return new Response(errorMessage, {
4161
+ return new Response(JSON.stringify({ error: errorMessage }), {
3990
4162
  status: 500,
3991
4163
  headers: {
3992
4164
  [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION