@upstash/workflow 0.2.22 → 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/index.js CHANGED
@@ -213,8 +213,8 @@ var NANOID_LENGTH = 21;
213
213
  function getRandomInt() {
214
214
  return Math.floor(Math.random() * NANOID_CHARS.length);
215
215
  }
216
- function nanoid() {
217
- return Array.from({ length: NANOID_LENGTH }).map(() => NANOID_CHARS[getRandomInt()]).join("");
216
+ function nanoid(length = NANOID_LENGTH) {
217
+ return Array.from({ length }).map(() => NANOID_CHARS[getRandomInt()]).join("");
218
218
  }
219
219
  function getWorkflowRunId(id) {
220
220
  return `wfr_${id ?? nanoid()}`;
@@ -231,6 +231,37 @@ function decodeBase64(base64) {
231
231
  return binString;
232
232
  }
233
233
  }
234
+ function getUserIdFromToken(qstashClient) {
235
+ try {
236
+ const token = qstashClient.token;
237
+ const decodedToken = decodeBase64(token);
238
+ const tokenPayload = JSON.parse(decodedToken);
239
+ const userId = tokenPayload.UserID;
240
+ if (!userId) {
241
+ throw new WorkflowError("QStash token payload does not contain userId");
242
+ }
243
+ return userId;
244
+ } catch (error) {
245
+ throw new WorkflowError(
246
+ `Failed to decode QStash token while running create webhook step: ${error.message}`
247
+ );
248
+ }
249
+ }
250
+ function getQStashUrl(qstashClient) {
251
+ try {
252
+ const requester = qstashClient.http;
253
+ const baseUrl = requester.baseUrl;
254
+ if (!baseUrl) {
255
+ throw new WorkflowError("QStash client does not have a baseUrl");
256
+ }
257
+ return baseUrl;
258
+ } catch (error) {
259
+ throw new WorkflowError(`Failed to get QStash URL from client: ${error.message}`);
260
+ }
261
+ }
262
+ function getEventId() {
263
+ return `evt_${nanoid(15)}`;
264
+ }
234
265
 
235
266
  // node_modules/neverthrow/dist/index.es.js
236
267
  var defaultErrorConfig = {
@@ -656,7 +687,9 @@ var StepTypes = [
656
687
  "Call",
657
688
  "Wait",
658
689
  "Notify",
659
- "Invoke"
690
+ "Invoke",
691
+ "CreateWebhook",
692
+ "WaitForWebhook"
660
693
  ];
661
694
 
662
695
  // src/workflow-requests.ts
@@ -968,7 +1001,9 @@ If you want to disable QStash Verification, you should clear env variables QSTAS
968
1001
  // src/context/steps.ts
969
1002
  var BaseLazyStep = class _BaseLazyStep {
970
1003
  stepName;
971
- constructor(stepName) {
1004
+ context;
1005
+ constructor(context, stepName) {
1006
+ this.context = context;
972
1007
  if (!stepName) {
973
1008
  throw new WorkflowError(
974
1009
  "A workflow step name cannot be undefined or an empty string. Please provide a name for your workflow step."
@@ -986,13 +1021,14 @@ var BaseLazyStep = class _BaseLazyStep {
986
1021
  *
987
1022
  * will be called when returning the steps to the context from auto executor
988
1023
  *
989
- * @param out field of the step
1024
+ * @param step step
990
1025
  * @returns parsed out field
991
1026
  */
992
- parseOut(out) {
1027
+ parseOut(step) {
1028
+ const out = step.out;
993
1029
  if (out === void 0) {
994
1030
  if (this.allowUndefinedOut) {
995
- return void 0;
1031
+ return this.handleUndefinedOut(step);
996
1032
  } else {
997
1033
  throw new WorkflowError(
998
1034
  `Error while parsing output of ${this.stepType} step. Expected a string, but got: undefined`
@@ -1000,27 +1036,26 @@ var BaseLazyStep = class _BaseLazyStep {
1000
1036
  }
1001
1037
  }
1002
1038
  if (typeof out === "object") {
1003
- if (this.stepType !== "Wait") {
1004
- console.warn(
1005
- `Error while parsing ${this.stepType} step output. Expected a string, but got object. Please reach out to Upstash Support.`
1006
- );
1007
- return out;
1008
- }
1009
- return {
1010
- ...out,
1011
- eventData: _BaseLazyStep.tryParsing(out.eventData)
1012
- };
1039
+ console.warn(
1040
+ `Error while parsing ${this.stepType} step output. Expected a string, but got object. Please reach out to Upstash Support.`
1041
+ );
1042
+ return out;
1013
1043
  }
1014
1044
  if (typeof out !== "string") {
1015
1045
  throw new WorkflowError(
1016
1046
  `Error while parsing output of ${this.stepType} step. Expected a string or undefined, but got: ${typeof out}`
1017
1047
  );
1018
1048
  }
1019
- return this.safeParseOut(out);
1049
+ return this.safeParseOut(out, step);
1020
1050
  }
1021
- safeParseOut(out) {
1051
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1052
+ safeParseOut(out, step) {
1022
1053
  return _BaseLazyStep.tryParsing(out);
1023
1054
  }
1055
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1056
+ handleUndefinedOut(step) {
1057
+ return void 0;
1058
+ }
1024
1059
  static tryParsing(stepOut) {
1025
1060
  try {
1026
1061
  return JSON.parse(stepOut);
@@ -1071,8 +1106,8 @@ var LazyFunctionStep = class extends BaseLazyStep {
1071
1106
  stepFunction;
1072
1107
  stepType = "Run";
1073
1108
  allowUndefinedOut = true;
1074
- constructor(stepName, stepFunction) {
1075
- super(stepName);
1109
+ constructor(context, stepName, stepFunction) {
1110
+ super(context, stepName);
1076
1111
  this.stepFunction = stepFunction;
1077
1112
  }
1078
1113
  getPlanStep(concurrent, targetStep) {
@@ -1102,8 +1137,8 @@ var LazySleepStep = class extends BaseLazyStep {
1102
1137
  sleep;
1103
1138
  stepType = "SleepFor";
1104
1139
  allowUndefinedOut = true;
1105
- constructor(stepName, sleep) {
1106
- super(stepName);
1140
+ constructor(context, stepName, sleep) {
1141
+ super(context, stepName);
1107
1142
  this.sleep = sleep;
1108
1143
  }
1109
1144
  getPlanStep(concurrent, targetStep) {
@@ -1144,8 +1179,8 @@ var LazySleepUntilStep = class extends BaseLazyStep {
1144
1179
  sleepUntil;
1145
1180
  stepType = "SleepUntil";
1146
1181
  allowUndefinedOut = true;
1147
- constructor(stepName, sleepUntil) {
1148
- super(stepName);
1182
+ constructor(context, stepName, sleepUntil) {
1183
+ super(context, stepName);
1149
1184
  this.sleepUntil = sleepUntil;
1150
1185
  }
1151
1186
  getPlanStep(concurrent, targetStep) {
@@ -1197,8 +1232,8 @@ var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
1197
1232
  stringifyBody;
1198
1233
  stepType = "Call";
1199
1234
  allowUndefinedOut = false;
1200
- constructor(stepName, url, method, body, headers, retries, retryDelay, timeout, flowControl, stringifyBody) {
1201
- super(stepName);
1235
+ constructor(context, stepName, url, method, body, headers, retries, retryDelay, timeout, flowControl, stringifyBody) {
1236
+ super(context, stepName);
1202
1237
  this.url = url;
1203
1238
  this.method = method;
1204
1239
  this.body = body;
@@ -1342,13 +1377,12 @@ var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
1342
1377
  ]);
1343
1378
  }
1344
1379
  };
1345
- var LazyWaitForEventStep = class extends BaseLazyStep {
1380
+ var LazyWaitEventStep = class extends BaseLazyStep {
1346
1381
  eventId;
1347
1382
  timeout;
1348
- stepType = "Wait";
1349
1383
  allowUndefinedOut = false;
1350
- constructor(stepName, eventId, timeout) {
1351
- super(stepName);
1384
+ constructor(context, stepName, eventId, timeout) {
1385
+ super(context, stepName);
1352
1386
  this.eventId = eventId;
1353
1387
  this.timeout = timeout;
1354
1388
  }
@@ -1373,13 +1407,6 @@ var LazyWaitForEventStep = class extends BaseLazyStep {
1373
1407
  concurrent
1374
1408
  });
1375
1409
  }
1376
- safeParseOut(out) {
1377
- const result = JSON.parse(out);
1378
- return {
1379
- ...result,
1380
- eventData: BaseLazyStep.tryParsing(result.eventData)
1381
- };
1382
- }
1383
1410
  getHeaders({ context, telemetry, invokeCount, step }) {
1384
1411
  const headers = super.getHeaders({ context, telemetry, invokeCount, step });
1385
1412
  headers.headers["Upstash-Workflow-CallType"] = "step";
@@ -1413,7 +1440,7 @@ var LazyWaitForEventStep = class extends BaseLazyStep {
1413
1440
  timeoutHeaders,
1414
1441
  step: {
1415
1442
  stepId: step.stepId,
1416
- stepType: "Wait",
1443
+ stepType: this.stepType,
1417
1444
  stepName: step.stepName,
1418
1445
  concurrent: step.concurrent,
1419
1446
  targetStep: step.targetStep
@@ -1434,8 +1461,8 @@ var LazyWaitForEventStep = class extends BaseLazyStep {
1434
1461
  };
1435
1462
  var LazyNotifyStep = class extends LazyFunctionStep {
1436
1463
  stepType = "Notify";
1437
- constructor(stepName, eventId, eventData, requester) {
1438
- super(stepName, async () => {
1464
+ constructor(context, stepName, eventId, eventData, requester) {
1465
+ super(context, stepName, async () => {
1439
1466
  const notifyResponse = await makeNotifyRequest(requester, eventId, eventData);
1440
1467
  return {
1441
1468
  eventId,
@@ -1460,7 +1487,7 @@ var LazyInvokeStep = class extends BaseLazyStep {
1460
1487
  * workflow id of the invoked workflow
1461
1488
  */
1462
1489
  workflowId;
1463
- constructor(stepName, {
1490
+ constructor(context, stepName, {
1464
1491
  workflow,
1465
1492
  body,
1466
1493
  headers = {},
@@ -1470,7 +1497,7 @@ var LazyInvokeStep = class extends BaseLazyStep {
1470
1497
  flowControl,
1471
1498
  stringifyBody = true
1472
1499
  }) {
1473
- super(stepName);
1500
+ super(context, stepName);
1474
1501
  this.params = {
1475
1502
  workflow,
1476
1503
  body,
@@ -1531,6 +1558,9 @@ var LazyInvokeStep = class extends BaseLazyStep {
1531
1558
  userHeaders: context.headers,
1532
1559
  invokeCount
1533
1560
  });
1561
+ context.qstashClient.http.headers?.forEach((value, key) => {
1562
+ invokerHeaders[key] = value;
1563
+ });
1534
1564
  invokerHeaders["Upstash-Workflow-Runid"] = context.workflowRunId;
1535
1565
  let invokeBody;
1536
1566
  if (this.params.stringifyBody) {
@@ -1602,6 +1632,91 @@ var LazyInvokeStep = class extends BaseLazyStep {
1602
1632
  return [result];
1603
1633
  }
1604
1634
  };
1635
+ var LazyCreateWebhookStep = class extends BaseLazyStep {
1636
+ stepType = "CreateWebhook";
1637
+ allowUndefinedOut = false;
1638
+ getPlanStep(concurrent, targetStep) {
1639
+ return {
1640
+ stepId: 0,
1641
+ stepName: this.stepName,
1642
+ stepType: this.stepType,
1643
+ concurrent,
1644
+ targetStep
1645
+ };
1646
+ }
1647
+ async getResultStep(concurrent, stepId) {
1648
+ return {
1649
+ stepId,
1650
+ stepName: this.stepName,
1651
+ stepType: this.stepType,
1652
+ out: void 0,
1653
+ concurrent
1654
+ };
1655
+ }
1656
+ getBody({ step, context }) {
1657
+ const userId = getUserIdFromToken(context.qstashClient);
1658
+ const out = [userId, context.workflowRunId, getEventId()].join("/");
1659
+ return JSON.stringify({
1660
+ ...step,
1661
+ out
1662
+ });
1663
+ }
1664
+ safeParseOut(out) {
1665
+ const [userId, workflowRunId, eventId] = out.split("/");
1666
+ const qstashUrl = getQStashUrl(this.context.qstashClient);
1667
+ return {
1668
+ webhookUrl: `${qstashUrl}/v2/workflows/hooks/${userId}/${workflowRunId}/${eventId}`,
1669
+ eventId
1670
+ };
1671
+ }
1672
+ };
1673
+ var LazyWaitForWebhookStep = class extends LazyWaitEventStep {
1674
+ stepType = "WaitForWebhook";
1675
+ allowUndefinedOut = true;
1676
+ constructor(context, stepName, webhook, timeout) {
1677
+ super(context, stepName, webhook.eventId, timeout);
1678
+ }
1679
+ safeParseOut(out) {
1680
+ const eventData = decodeBase64(out);
1681
+ const parsedEventData = BaseLazyStep.tryParsing(eventData);
1682
+ const body = parsedEventData.body;
1683
+ const parsedBody = typeof body === "string" ? decodeBase64(body) : void 0;
1684
+ const request = new Request(
1685
+ `${parsedEventData.proto}://${parsedEventData.host}${parsedEventData.url}`,
1686
+ {
1687
+ method: parsedEventData.method,
1688
+ headers: parsedEventData.header,
1689
+ body: parsedBody
1690
+ }
1691
+ );
1692
+ return {
1693
+ request,
1694
+ timeout: false
1695
+ };
1696
+ }
1697
+ handleUndefinedOut() {
1698
+ return {
1699
+ timeout: true,
1700
+ request: void 0
1701
+ };
1702
+ }
1703
+ };
1704
+ var LazyWaitForEventStep = class extends LazyWaitEventStep {
1705
+ stepType = "Wait";
1706
+ allowUndefinedOut = true;
1707
+ parseWaitForEventOut(out, waitTimeout) {
1708
+ return {
1709
+ eventData: out ? BaseLazyStep.tryParsing(decodeBase64(out)) : void 0,
1710
+ timeout: waitTimeout ?? false
1711
+ };
1712
+ }
1713
+ safeParseOut(out, step) {
1714
+ return this.parseWaitForEventOut(out, step.waitTimeout);
1715
+ }
1716
+ handleUndefinedOut(step) {
1717
+ return this.parseWaitForEventOut(void 0, step.waitTimeout);
1718
+ }
1719
+ };
1605
1720
 
1606
1721
  // src/agents/constants.ts
1607
1722
  var AGENT_NAME_HEADER = "upstash-agent-name";
@@ -2006,7 +2121,7 @@ var AutoExecutor = class _AutoExecutor {
2006
2121
  step,
2007
2122
  stepCount: this.stepCount
2008
2123
  });
2009
- return lazyStep.parseOut(step.out);
2124
+ return lazyStep.parseOut(step);
2010
2125
  }
2011
2126
  const resultStep = await submitSingleStep({
2012
2127
  context: this.context,
@@ -2093,7 +2208,7 @@ var AutoExecutor = class _AutoExecutor {
2093
2208
  const parallelResultSteps = sortedSteps.filter((step) => step.stepId >= initialStepCount).slice(0, parallelSteps.length);
2094
2209
  validateParallelSteps(parallelSteps, parallelResultSteps);
2095
2210
  return parallelResultSteps.map(
2096
- (step, index) => parallelSteps[index].parseOut(step.out)
2211
+ (step, index) => parallelSteps[index].parseOut(step)
2097
2212
  );
2098
2213
  }
2099
2214
  }
@@ -2149,7 +2264,6 @@ var AutoExecutor = class _AutoExecutor {
2149
2264
  * @param index index of the current step
2150
2265
  * @returns result[index] if lazyStepList > 1, otherwise result
2151
2266
  */
2152
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters
2153
2267
  static getResult(lazyStepList, result, index) {
2154
2268
  if (lazyStepList.length === 1) {
2155
2269
  return result;
@@ -2905,7 +3019,7 @@ var WorkflowContext = class {
2905
3019
  */
2906
3020
  async run(stepName, stepFunction) {
2907
3021
  const wrappedStepFunction = () => this.executor.wrapStep(stepName, stepFunction);
2908
- return await this.addStep(new LazyFunctionStep(stepName, wrappedStepFunction));
3022
+ return await this.addStep(new LazyFunctionStep(this, stepName, wrappedStepFunction));
2909
3023
  }
2910
3024
  /**
2911
3025
  * Stops the execution for the duration provided.
@@ -2919,7 +3033,7 @@ var WorkflowContext = class {
2919
3033
  * @returns undefined
2920
3034
  */
2921
3035
  async sleep(stepName, duration) {
2922
- await this.addStep(new LazySleepStep(stepName, duration));
3036
+ await this.addStep(new LazySleepStep(this, stepName, duration));
2923
3037
  }
2924
3038
  /**
2925
3039
  * Stops the execution until the date time provided.
@@ -2941,13 +3055,14 @@ var WorkflowContext = class {
2941
3055
  datetime = typeof datetime === "string" ? new Date(datetime) : datetime;
2942
3056
  time = Math.round(datetime.getTime() / 1e3);
2943
3057
  }
2944
- await this.addStep(new LazySleepUntilStep(stepName, time));
3058
+ await this.addStep(new LazySleepUntilStep(this, stepName, time));
2945
3059
  }
2946
3060
  async call(stepName, settings) {
2947
3061
  let callStep;
2948
3062
  if ("workflow" in settings) {
2949
3063
  const url = getNewUrlFromWorkflowId(this.url, settings.workflow.workflowId);
2950
3064
  callStep = new LazyCallStep(
3065
+ this,
2951
3066
  stepName,
2952
3067
  url,
2953
3068
  "POST",
@@ -2972,6 +3087,7 @@ var WorkflowContext = class {
2972
3087
  stringifyBody = true
2973
3088
  } = settings;
2974
3089
  callStep = new LazyCallStep(
3090
+ this,
2975
3091
  stepName,
2976
3092
  url,
2977
3093
  method,
@@ -3023,7 +3139,9 @@ var WorkflowContext = class {
3023
3139
  async waitForEvent(stepName, eventId, options = {}) {
3024
3140
  const { timeout = "7d" } = options;
3025
3141
  const timeoutStr = typeof timeout === "string" ? timeout : `${timeout}s`;
3026
- return await this.addStep(new LazyWaitForEventStep(stepName, eventId, timeoutStr));
3142
+ return await this.addStep(
3143
+ new LazyWaitForEventStep(this, stepName, eventId, timeoutStr)
3144
+ );
3027
3145
  }
3028
3146
  /**
3029
3147
  * Notify workflow runs waiting for an event
@@ -3048,11 +3166,19 @@ var WorkflowContext = class {
3048
3166
  */
3049
3167
  async notify(stepName, eventId, eventData) {
3050
3168
  return await this.addStep(
3051
- new LazyNotifyStep(stepName, eventId, eventData, this.qstashClient.http)
3169
+ new LazyNotifyStep(this, stepName, eventId, eventData, this.qstashClient.http)
3052
3170
  );
3053
3171
  }
3054
3172
  async invoke(stepName, settings) {
3055
- return await this.addStep(new LazyInvokeStep(stepName, settings));
3173
+ return await this.addStep(
3174
+ new LazyInvokeStep(this, stepName, settings)
3175
+ );
3176
+ }
3177
+ async createWebhook(stepName) {
3178
+ return await this.addStep(new LazyCreateWebhookStep(this, stepName));
3179
+ }
3180
+ async waitForWebhook(stepName, webhook, timeout) {
3181
+ return await this.addStep(new LazyWaitForWebhookStep(this, stepName, webhook, timeout));
3056
3182
  }
3057
3183
  /**
3058
3184
  * Cancel the current workflow run
@@ -3216,13 +3342,6 @@ var processRawSteps = (rawSteps) => {
3216
3342
  const stepsToDecode = encodedSteps.filter((step) => step.callType === "step");
3217
3343
  const otherSteps = stepsToDecode.map((rawStep) => {
3218
3344
  const step = JSON.parse(decodeBase64(rawStep.body));
3219
- if (step.waitEventId) {
3220
- const newOut = {
3221
- eventData: step.out ? decodeBase64(step.out) : void 0,
3222
- timeout: step.waitTimeout ?? false
3223
- };
3224
- step.out = newOut;
3225
- }
3226
3345
  return step;
3227
3346
  });
3228
3347
  const steps = [initialStep, ...otherSteps];
package/index.mjs CHANGED
@@ -15,7 +15,7 @@ import {
15
15
  prepareFlowControl,
16
16
  serve,
17
17
  triggerFirstInvocation
18
- } from "./chunk-BON2RKOR.mjs";
18
+ } from "./chunk-KAGTWBLF.mjs";
19
19
 
20
20
  // src/client/index.ts
21
21
  import { Client as QStashClient } from "@upstash/qstash";
package/nextjs.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { NextApiHandler, NextApiRequest, NextApiResponse } from 'next';
2
- import { R as RouteFunction, o as PublicServeOptions, z as InvokableWorkflow } from './types-9nCq6bRP.mjs';
3
- import { s as serveManyBase } from './serve-many-CctdYIfB.mjs';
2
+ import { R as RouteFunction, o as PublicServeOptions, z as InvokableWorkflow } from './types-BD06btU6.mjs';
3
+ import { s as serveManyBase } from './serve-many-B5Vbacm6.mjs';
4
4
  import '@upstash/qstash';
5
5
  import 'zod';
6
6
  import 'ai';
package/nextjs.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { NextApiHandler, NextApiRequest, NextApiResponse } from 'next';
2
- import { R as RouteFunction, o as PublicServeOptions, z as InvokableWorkflow } from './types-9nCq6bRP.js';
3
- import { s as serveManyBase } from './serve-many-BXDr30rl.js';
2
+ import { R as RouteFunction, o as PublicServeOptions, z as InvokableWorkflow } from './types-BD06btU6.js';
3
+ import { s as serveManyBase } from './serve-many-BCV7INWe.js';
4
4
  import '@upstash/qstash';
5
5
  import 'zod';
6
6
  import 'ai';