@upstash/workflow 0.2.22 → 0.2.23

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,88 @@ 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 workflowRunId = context.workflowRunId;
1659
+ const eventId = getEventId();
1660
+ const qstashUrl = getQStashUrl(this.context.qstashClient);
1661
+ return JSON.stringify({
1662
+ ...step,
1663
+ out: JSON.stringify({
1664
+ webhookUrl: `${qstashUrl}/v2/workflows/hooks/${userId}/${workflowRunId}/${eventId}`,
1665
+ eventId
1666
+ })
1667
+ });
1668
+ }
1669
+ };
1670
+ var LazyWaitForWebhookStep = class extends LazyWaitEventStep {
1671
+ stepType = "WaitForWebhook";
1672
+ allowUndefinedOut = true;
1673
+ constructor(context, stepName, webhook, timeout) {
1674
+ super(context, stepName, webhook.eventId, timeout);
1675
+ }
1676
+ safeParseOut(out) {
1677
+ const eventData = decodeBase64(out);
1678
+ const parsedEventData = BaseLazyStep.tryParsing(eventData);
1679
+ const body = parsedEventData.body;
1680
+ const parsedBody = typeof body === "string" ? decodeBase64(body) : void 0;
1681
+ const request = new Request(
1682
+ `${parsedEventData.proto}://${parsedEventData.host}${parsedEventData.url}`,
1683
+ {
1684
+ method: parsedEventData.method,
1685
+ headers: parsedEventData.header,
1686
+ body: parsedBody
1687
+ }
1688
+ );
1689
+ return {
1690
+ request,
1691
+ timeout: false
1692
+ };
1693
+ }
1694
+ handleUndefinedOut() {
1695
+ return {
1696
+ timeout: true,
1697
+ request: void 0
1698
+ };
1699
+ }
1700
+ };
1701
+ var LazyWaitForEventStep = class extends LazyWaitEventStep {
1702
+ stepType = "Wait";
1703
+ allowUndefinedOut = true;
1704
+ parseWaitForEventOut(out, waitTimeout) {
1705
+ return {
1706
+ eventData: out ? BaseLazyStep.tryParsing(decodeBase64(out)) : void 0,
1707
+ timeout: waitTimeout ?? false
1708
+ };
1709
+ }
1710
+ safeParseOut(out, step) {
1711
+ return this.parseWaitForEventOut(out, step.waitTimeout);
1712
+ }
1713
+ handleUndefinedOut(step) {
1714
+ return this.parseWaitForEventOut(void 0, step.waitTimeout);
1715
+ }
1716
+ };
1605
1717
 
1606
1718
  // src/agents/constants.ts
1607
1719
  var AGENT_NAME_HEADER = "upstash-agent-name";
@@ -2006,7 +2118,7 @@ var AutoExecutor = class _AutoExecutor {
2006
2118
  step,
2007
2119
  stepCount: this.stepCount
2008
2120
  });
2009
- return lazyStep.parseOut(step.out);
2121
+ return lazyStep.parseOut(step);
2010
2122
  }
2011
2123
  const resultStep = await submitSingleStep({
2012
2124
  context: this.context,
@@ -2093,7 +2205,7 @@ var AutoExecutor = class _AutoExecutor {
2093
2205
  const parallelResultSteps = sortedSteps.filter((step) => step.stepId >= initialStepCount).slice(0, parallelSteps.length);
2094
2206
  validateParallelSteps(parallelSteps, parallelResultSteps);
2095
2207
  return parallelResultSteps.map(
2096
- (step, index) => parallelSteps[index].parseOut(step.out)
2208
+ (step, index) => parallelSteps[index].parseOut(step)
2097
2209
  );
2098
2210
  }
2099
2211
  }
@@ -2149,7 +2261,6 @@ var AutoExecutor = class _AutoExecutor {
2149
2261
  * @param index index of the current step
2150
2262
  * @returns result[index] if lazyStepList > 1, otherwise result
2151
2263
  */
2152
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters
2153
2264
  static getResult(lazyStepList, result, index) {
2154
2265
  if (lazyStepList.length === 1) {
2155
2266
  return result;
@@ -2905,7 +3016,7 @@ var WorkflowContext = class {
2905
3016
  */
2906
3017
  async run(stepName, stepFunction) {
2907
3018
  const wrappedStepFunction = () => this.executor.wrapStep(stepName, stepFunction);
2908
- return await this.addStep(new LazyFunctionStep(stepName, wrappedStepFunction));
3019
+ return await this.addStep(new LazyFunctionStep(this, stepName, wrappedStepFunction));
2909
3020
  }
2910
3021
  /**
2911
3022
  * Stops the execution for the duration provided.
@@ -2919,7 +3030,7 @@ var WorkflowContext = class {
2919
3030
  * @returns undefined
2920
3031
  */
2921
3032
  async sleep(stepName, duration) {
2922
- await this.addStep(new LazySleepStep(stepName, duration));
3033
+ await this.addStep(new LazySleepStep(this, stepName, duration));
2923
3034
  }
2924
3035
  /**
2925
3036
  * Stops the execution until the date time provided.
@@ -2941,13 +3052,14 @@ var WorkflowContext = class {
2941
3052
  datetime = typeof datetime === "string" ? new Date(datetime) : datetime;
2942
3053
  time = Math.round(datetime.getTime() / 1e3);
2943
3054
  }
2944
- await this.addStep(new LazySleepUntilStep(stepName, time));
3055
+ await this.addStep(new LazySleepUntilStep(this, stepName, time));
2945
3056
  }
2946
3057
  async call(stepName, settings) {
2947
3058
  let callStep;
2948
3059
  if ("workflow" in settings) {
2949
3060
  const url = getNewUrlFromWorkflowId(this.url, settings.workflow.workflowId);
2950
3061
  callStep = new LazyCallStep(
3062
+ this,
2951
3063
  stepName,
2952
3064
  url,
2953
3065
  "POST",
@@ -2972,6 +3084,7 @@ var WorkflowContext = class {
2972
3084
  stringifyBody = true
2973
3085
  } = settings;
2974
3086
  callStep = new LazyCallStep(
3087
+ this,
2975
3088
  stepName,
2976
3089
  url,
2977
3090
  method,
@@ -3023,7 +3136,9 @@ var WorkflowContext = class {
3023
3136
  async waitForEvent(stepName, eventId, options = {}) {
3024
3137
  const { timeout = "7d" } = options;
3025
3138
  const timeoutStr = typeof timeout === "string" ? timeout : `${timeout}s`;
3026
- return await this.addStep(new LazyWaitForEventStep(stepName, eventId, timeoutStr));
3139
+ return await this.addStep(
3140
+ new LazyWaitForEventStep(this, stepName, eventId, timeoutStr)
3141
+ );
3027
3142
  }
3028
3143
  /**
3029
3144
  * Notify workflow runs waiting for an event
@@ -3048,11 +3163,19 @@ var WorkflowContext = class {
3048
3163
  */
3049
3164
  async notify(stepName, eventId, eventData) {
3050
3165
  return await this.addStep(
3051
- new LazyNotifyStep(stepName, eventId, eventData, this.qstashClient.http)
3166
+ new LazyNotifyStep(this, stepName, eventId, eventData, this.qstashClient.http)
3052
3167
  );
3053
3168
  }
3054
3169
  async invoke(stepName, settings) {
3055
- return await this.addStep(new LazyInvokeStep(stepName, settings));
3170
+ return await this.addStep(
3171
+ new LazyInvokeStep(this, stepName, settings)
3172
+ );
3173
+ }
3174
+ async createWebhook(stepName) {
3175
+ return await this.addStep(new LazyCreateWebhookStep(this, stepName));
3176
+ }
3177
+ async waitForWebhook(stepName, webhook, timeout) {
3178
+ return await this.addStep(new LazyWaitForWebhookStep(this, stepName, webhook, timeout));
3056
3179
  }
3057
3180
  /**
3058
3181
  * Cancel the current workflow run
@@ -3216,13 +3339,6 @@ var processRawSteps = (rawSteps) => {
3216
3339
  const stepsToDecode = encodedSteps.filter((step) => step.callType === "step");
3217
3340
  const otherSteps = stepsToDecode.map((rawStep) => {
3218
3341
  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
3342
  return step;
3227
3343
  });
3228
3344
  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-GZRDB6Z5.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';