@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.
@@ -113,7 +113,9 @@ var StepTypes = [
113
113
  "Call",
114
114
  "Wait",
115
115
  "Notify",
116
- "Invoke"
116
+ "Invoke",
117
+ "CreateWebhook",
118
+ "WaitForWebhook"
117
119
  ];
118
120
 
119
121
  // src/agents/adapters.ts
@@ -394,8 +396,8 @@ var NANOID_LENGTH = 21;
394
396
  function getRandomInt() {
395
397
  return Math.floor(Math.random() * NANOID_CHARS.length);
396
398
  }
397
- function nanoid() {
398
- 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("");
399
401
  }
400
402
  function getWorkflowRunId(id) {
401
403
  return `wfr_${id ?? nanoid()}`;
@@ -412,6 +414,37 @@ function decodeBase64(base64) {
412
414
  return binString;
413
415
  }
414
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
+ }
415
448
 
416
449
  // node_modules/neverthrow/dist/index.es.js
417
450
  var defaultErrorConfig = {
@@ -1137,7 +1170,9 @@ If you want to disable QStash Verification, you should clear env variables QSTAS
1137
1170
  // src/context/steps.ts
1138
1171
  var BaseLazyStep = class _BaseLazyStep {
1139
1172
  stepName;
1140
- constructor(stepName) {
1173
+ context;
1174
+ constructor(context, stepName) {
1175
+ this.context = context;
1141
1176
  if (!stepName) {
1142
1177
  throw new WorkflowError(
1143
1178
  "A workflow step name cannot be undefined or an empty string. Please provide a name for your workflow step."
@@ -1155,13 +1190,14 @@ var BaseLazyStep = class _BaseLazyStep {
1155
1190
  *
1156
1191
  * will be called when returning the steps to the context from auto executor
1157
1192
  *
1158
- * @param out field of the step
1193
+ * @param step step
1159
1194
  * @returns parsed out field
1160
1195
  */
1161
- parseOut(out) {
1196
+ parseOut(step) {
1197
+ const out = step.out;
1162
1198
  if (out === void 0) {
1163
1199
  if (this.allowUndefinedOut) {
1164
- return void 0;
1200
+ return this.handleUndefinedOut(step);
1165
1201
  } else {
1166
1202
  throw new WorkflowError(
1167
1203
  `Error while parsing output of ${this.stepType} step. Expected a string, but got: undefined`
@@ -1169,27 +1205,26 @@ var BaseLazyStep = class _BaseLazyStep {
1169
1205
  }
1170
1206
  }
1171
1207
  if (typeof out === "object") {
1172
- if (this.stepType !== "Wait") {
1173
- console.warn(
1174
- `Error while parsing ${this.stepType} step output. Expected a string, but got object. Please reach out to Upstash Support.`
1175
- );
1176
- return out;
1177
- }
1178
- return {
1179
- ...out,
1180
- eventData: _BaseLazyStep.tryParsing(out.eventData)
1181
- };
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;
1182
1212
  }
1183
1213
  if (typeof out !== "string") {
1184
1214
  throw new WorkflowError(
1185
1215
  `Error while parsing output of ${this.stepType} step. Expected a string or undefined, but got: ${typeof out}`
1186
1216
  );
1187
1217
  }
1188
- return this.safeParseOut(out);
1218
+ return this.safeParseOut(out, step);
1189
1219
  }
1190
- safeParseOut(out) {
1220
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1221
+ safeParseOut(out, step) {
1191
1222
  return _BaseLazyStep.tryParsing(out);
1192
1223
  }
1224
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1225
+ handleUndefinedOut(step) {
1226
+ return void 0;
1227
+ }
1193
1228
  static tryParsing(stepOut) {
1194
1229
  try {
1195
1230
  return JSON.parse(stepOut);
@@ -1240,8 +1275,8 @@ var LazyFunctionStep = class extends BaseLazyStep {
1240
1275
  stepFunction;
1241
1276
  stepType = "Run";
1242
1277
  allowUndefinedOut = true;
1243
- constructor(stepName, stepFunction) {
1244
- super(stepName);
1278
+ constructor(context, stepName, stepFunction) {
1279
+ super(context, stepName);
1245
1280
  this.stepFunction = stepFunction;
1246
1281
  }
1247
1282
  getPlanStep(concurrent, targetStep) {
@@ -1271,8 +1306,8 @@ var LazySleepStep = class extends BaseLazyStep {
1271
1306
  sleep;
1272
1307
  stepType = "SleepFor";
1273
1308
  allowUndefinedOut = true;
1274
- constructor(stepName, sleep) {
1275
- super(stepName);
1309
+ constructor(context, stepName, sleep) {
1310
+ super(context, stepName);
1276
1311
  this.sleep = sleep;
1277
1312
  }
1278
1313
  getPlanStep(concurrent, targetStep) {
@@ -1313,8 +1348,8 @@ var LazySleepUntilStep = class extends BaseLazyStep {
1313
1348
  sleepUntil;
1314
1349
  stepType = "SleepUntil";
1315
1350
  allowUndefinedOut = true;
1316
- constructor(stepName, sleepUntil) {
1317
- super(stepName);
1351
+ constructor(context, stepName, sleepUntil) {
1352
+ super(context, stepName);
1318
1353
  this.sleepUntil = sleepUntil;
1319
1354
  }
1320
1355
  getPlanStep(concurrent, targetStep) {
@@ -1366,8 +1401,8 @@ var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
1366
1401
  stringifyBody;
1367
1402
  stepType = "Call";
1368
1403
  allowUndefinedOut = false;
1369
- constructor(stepName, url, method, body, headers, retries, retryDelay, timeout, flowControl, stringifyBody) {
1370
- super(stepName);
1404
+ constructor(context, stepName, url, method, body, headers, retries, retryDelay, timeout, flowControl, stringifyBody) {
1405
+ super(context, stepName);
1371
1406
  this.url = url;
1372
1407
  this.method = method;
1373
1408
  this.body = body;
@@ -1511,13 +1546,12 @@ var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
1511
1546
  ]);
1512
1547
  }
1513
1548
  };
1514
- var LazyWaitForEventStep = class extends BaseLazyStep {
1549
+ var LazyWaitEventStep = class extends BaseLazyStep {
1515
1550
  eventId;
1516
1551
  timeout;
1517
- stepType = "Wait";
1518
1552
  allowUndefinedOut = false;
1519
- constructor(stepName, eventId, timeout) {
1520
- super(stepName);
1553
+ constructor(context, stepName, eventId, timeout) {
1554
+ super(context, stepName);
1521
1555
  this.eventId = eventId;
1522
1556
  this.timeout = timeout;
1523
1557
  }
@@ -1542,13 +1576,6 @@ var LazyWaitForEventStep = class extends BaseLazyStep {
1542
1576
  concurrent
1543
1577
  });
1544
1578
  }
1545
- safeParseOut(out) {
1546
- const result = JSON.parse(out);
1547
- return {
1548
- ...result,
1549
- eventData: BaseLazyStep.tryParsing(result.eventData)
1550
- };
1551
- }
1552
1579
  getHeaders({ context, telemetry, invokeCount, step }) {
1553
1580
  const headers = super.getHeaders({ context, telemetry, invokeCount, step });
1554
1581
  headers.headers["Upstash-Workflow-CallType"] = "step";
@@ -1582,7 +1609,7 @@ var LazyWaitForEventStep = class extends BaseLazyStep {
1582
1609
  timeoutHeaders,
1583
1610
  step: {
1584
1611
  stepId: step.stepId,
1585
- stepType: "Wait",
1612
+ stepType: this.stepType,
1586
1613
  stepName: step.stepName,
1587
1614
  concurrent: step.concurrent,
1588
1615
  targetStep: step.targetStep
@@ -1603,8 +1630,8 @@ var LazyWaitForEventStep = class extends BaseLazyStep {
1603
1630
  };
1604
1631
  var LazyNotifyStep = class extends LazyFunctionStep {
1605
1632
  stepType = "Notify";
1606
- constructor(stepName, eventId, eventData, requester) {
1607
- super(stepName, async () => {
1633
+ constructor(context, stepName, eventId, eventData, requester) {
1634
+ super(context, stepName, async () => {
1608
1635
  const notifyResponse = await makeNotifyRequest(requester, eventId, eventData);
1609
1636
  return {
1610
1637
  eventId,
@@ -1629,7 +1656,7 @@ var LazyInvokeStep = class extends BaseLazyStep {
1629
1656
  * workflow id of the invoked workflow
1630
1657
  */
1631
1658
  workflowId;
1632
- constructor(stepName, {
1659
+ constructor(context, stepName, {
1633
1660
  workflow,
1634
1661
  body,
1635
1662
  headers = {},
@@ -1639,7 +1666,7 @@ var LazyInvokeStep = class extends BaseLazyStep {
1639
1666
  flowControl,
1640
1667
  stringifyBody = true
1641
1668
  }) {
1642
- super(stepName);
1669
+ super(context, stepName);
1643
1670
  this.params = {
1644
1671
  workflow,
1645
1672
  body,
@@ -1700,6 +1727,9 @@ var LazyInvokeStep = class extends BaseLazyStep {
1700
1727
  userHeaders: context.headers,
1701
1728
  invokeCount
1702
1729
  });
1730
+ context.qstashClient.http.headers?.forEach((value, key) => {
1731
+ invokerHeaders[key] = value;
1732
+ });
1703
1733
  invokerHeaders["Upstash-Workflow-Runid"] = context.workflowRunId;
1704
1734
  let invokeBody;
1705
1735
  if (this.params.stringifyBody) {
@@ -1771,6 +1801,91 @@ var LazyInvokeStep = class extends BaseLazyStep {
1771
1801
  return [result];
1772
1802
  }
1773
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
+ };
1774
1889
 
1775
1890
  // src/qstash/headers.ts
1776
1891
  var WorkflowHeaders = class {
@@ -2161,7 +2276,7 @@ var AutoExecutor = class _AutoExecutor {
2161
2276
  step,
2162
2277
  stepCount: this.stepCount
2163
2278
  });
2164
- return lazyStep.parseOut(step.out);
2279
+ return lazyStep.parseOut(step);
2165
2280
  }
2166
2281
  const resultStep = await submitSingleStep({
2167
2282
  context: this.context,
@@ -2248,7 +2363,7 @@ var AutoExecutor = class _AutoExecutor {
2248
2363
  const parallelResultSteps = sortedSteps.filter((step) => step.stepId >= initialStepCount).slice(0, parallelSteps.length);
2249
2364
  validateParallelSteps(parallelSteps, parallelResultSteps);
2250
2365
  return parallelResultSteps.map(
2251
- (step, index) => parallelSteps[index].parseOut(step.out)
2366
+ (step, index) => parallelSteps[index].parseOut(step)
2252
2367
  );
2253
2368
  }
2254
2369
  }
@@ -2304,7 +2419,6 @@ var AutoExecutor = class _AutoExecutor {
2304
2419
  * @param index index of the current step
2305
2420
  * @returns result[index] if lazyStepList > 1, otherwise result
2306
2421
  */
2307
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters
2308
2422
  static getResult(lazyStepList, result, index) {
2309
2423
  if (lazyStepList.length === 1) {
2310
2424
  return result;
@@ -2937,7 +3051,7 @@ var WorkflowContext = class {
2937
3051
  */
2938
3052
  async run(stepName, stepFunction) {
2939
3053
  const wrappedStepFunction = () => this.executor.wrapStep(stepName, stepFunction);
2940
- return await this.addStep(new LazyFunctionStep(stepName, wrappedStepFunction));
3054
+ return await this.addStep(new LazyFunctionStep(this, stepName, wrappedStepFunction));
2941
3055
  }
2942
3056
  /**
2943
3057
  * Stops the execution for the duration provided.
@@ -2951,7 +3065,7 @@ var WorkflowContext = class {
2951
3065
  * @returns undefined
2952
3066
  */
2953
3067
  async sleep(stepName, duration) {
2954
- await this.addStep(new LazySleepStep(stepName, duration));
3068
+ await this.addStep(new LazySleepStep(this, stepName, duration));
2955
3069
  }
2956
3070
  /**
2957
3071
  * Stops the execution until the date time provided.
@@ -2973,13 +3087,14 @@ var WorkflowContext = class {
2973
3087
  datetime = typeof datetime === "string" ? new Date(datetime) : datetime;
2974
3088
  time = Math.round(datetime.getTime() / 1e3);
2975
3089
  }
2976
- await this.addStep(new LazySleepUntilStep(stepName, time));
3090
+ await this.addStep(new LazySleepUntilStep(this, stepName, time));
2977
3091
  }
2978
3092
  async call(stepName, settings) {
2979
3093
  let callStep;
2980
3094
  if ("workflow" in settings) {
2981
3095
  const url = getNewUrlFromWorkflowId(this.url, settings.workflow.workflowId);
2982
3096
  callStep = new LazyCallStep(
3097
+ this,
2983
3098
  stepName,
2984
3099
  url,
2985
3100
  "POST",
@@ -3004,6 +3119,7 @@ var WorkflowContext = class {
3004
3119
  stringifyBody = true
3005
3120
  } = settings;
3006
3121
  callStep = new LazyCallStep(
3122
+ this,
3007
3123
  stepName,
3008
3124
  url,
3009
3125
  method,
@@ -3055,7 +3171,9 @@ var WorkflowContext = class {
3055
3171
  async waitForEvent(stepName, eventId, options = {}) {
3056
3172
  const { timeout = "7d" } = options;
3057
3173
  const timeoutStr = typeof timeout === "string" ? timeout : `${timeout}s`;
3058
- return await this.addStep(new LazyWaitForEventStep(stepName, eventId, timeoutStr));
3174
+ return await this.addStep(
3175
+ new LazyWaitForEventStep(this, stepName, eventId, timeoutStr)
3176
+ );
3059
3177
  }
3060
3178
  /**
3061
3179
  * Notify workflow runs waiting for an event
@@ -3080,11 +3198,19 @@ var WorkflowContext = class {
3080
3198
  */
3081
3199
  async notify(stepName, eventId, eventData) {
3082
3200
  return await this.addStep(
3083
- new LazyNotifyStep(stepName, eventId, eventData, this.qstashClient.http)
3201
+ new LazyNotifyStep(this, stepName, eventId, eventData, this.qstashClient.http)
3084
3202
  );
3085
3203
  }
3086
3204
  async invoke(stepName, settings) {
3087
- 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));
3088
3214
  }
3089
3215
  /**
3090
3216
  * Cancel the current workflow run
@@ -3248,13 +3374,6 @@ var processRawSteps = (rawSteps) => {
3248
3374
  const stepsToDecode = encodedSteps.filter((step) => step.callType === "step");
3249
3375
  const otherSteps = stepsToDecode.map((rawStep) => {
3250
3376
  const step = JSON.parse(decodeBase64(rawStep.body));
3251
- if (step.waitEventId) {
3252
- const newOut = {
3253
- eventData: step.out ? decodeBase64(step.out) : void 0,
3254
- timeout: step.waitTimeout ?? false
3255
- };
3256
- step.out = newOut;
3257
- }
3258
3377
  return step;
3259
3378
  });
3260
3379
  const steps = [initialStep, ...otherSteps];
package/cloudflare.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { R as RouteFunction, o as PublicServeOptions, z as InvokableWorkflow } from './types-9nCq6bRP.mjs';
2
- import { s as serveManyBase } from './serve-many-CctdYIfB.mjs';
1
+ import { R as RouteFunction, o as PublicServeOptions, z as InvokableWorkflow } from './types-BD06btU6.mjs';
2
+ import { s as serveManyBase } from './serve-many-B5Vbacm6.mjs';
3
3
  import '@upstash/qstash';
4
4
  import 'zod';
5
5
  import 'ai';
package/cloudflare.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { R as RouteFunction, o as PublicServeOptions, z as InvokableWorkflow } from './types-9nCq6bRP.js';
2
- import { s as serveManyBase } from './serve-many-BXDr30rl.js';
1
+ import { R as RouteFunction, o as PublicServeOptions, z as InvokableWorkflow } from './types-BD06btU6.js';
2
+ import { s as serveManyBase } from './serve-many-BCV7INWe.js';
3
3
  import '@upstash/qstash';
4
4
  import 'zod';
5
5
  import 'ai';