@upstash/workflow 0.2.10 → 0.2.11

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
@@ -163,22 +163,21 @@ function getWorkflowRunId(id) {
163
163
  return `wfr_${id ?? nanoid()}`;
164
164
  }
165
165
  function decodeBase64(base64) {
166
+ const binString = atob(base64);
166
167
  try {
167
- const binString = atob(base64);
168
168
  const intArray = Uint8Array.from(binString, (m) => m.codePointAt(0));
169
169
  return new TextDecoder().decode(intArray);
170
170
  } catch (error) {
171
171
  console.warn(
172
172
  `Upstash Qstash: Failed while decoding base64 "${base64}". Decoding with atob and returning it instead. ${error}`
173
173
  );
174
- return atob(base64);
174
+ return binString;
175
175
  }
176
176
  }
177
177
 
178
178
  // src/context/steps.ts
179
- var BaseLazyStep = class {
179
+ var BaseLazyStep = class _BaseLazyStep {
180
180
  stepName;
181
- // will be set in the subclasses
182
181
  constructor(stepName) {
183
182
  if (!stepName) {
184
183
  throw new WorkflowError(
@@ -187,10 +186,58 @@ var BaseLazyStep = class {
187
186
  }
188
187
  this.stepName = stepName;
189
188
  }
189
+ /**
190
+ * parse the out field of a step result.
191
+ *
192
+ * will be called when returning the steps to the context from auto executor
193
+ *
194
+ * @param out field of the step
195
+ * @returns parsed out field
196
+ */
197
+ parseOut(out) {
198
+ if (out === void 0) {
199
+ if (this.allowUndefinedOut) {
200
+ return void 0;
201
+ } else {
202
+ throw new WorkflowError(
203
+ `Error while parsing output of ${this.stepType} step. Expected a string, but got: undefined`
204
+ );
205
+ }
206
+ }
207
+ if (typeof out === "object") {
208
+ if (this.stepType !== "Wait") {
209
+ console.warn(
210
+ `Error while parsing ${this.stepType} step output. Expected a string, but got object. Please reach out to Upstash Support.`
211
+ );
212
+ return out;
213
+ }
214
+ return {
215
+ ...out,
216
+ eventData: _BaseLazyStep.tryParsing(out.eventData)
217
+ };
218
+ }
219
+ if (typeof out !== "string") {
220
+ throw new WorkflowError(
221
+ `Error while parsing output of ${this.stepType} step. Expected a string or undefined, but got: ${typeof out}`
222
+ );
223
+ }
224
+ return this.safeParseOut(out);
225
+ }
226
+ safeParseOut(out) {
227
+ return _BaseLazyStep.tryParsing(out);
228
+ }
229
+ static tryParsing(stepOut) {
230
+ try {
231
+ return JSON.parse(stepOut);
232
+ } catch {
233
+ return stepOut;
234
+ }
235
+ }
190
236
  };
191
237
  var LazyFunctionStep = class extends BaseLazyStep {
192
238
  stepFunction;
193
239
  stepType = "Run";
240
+ allowUndefinedOut = true;
194
241
  constructor(stepName, stepFunction) {
195
242
  super(stepName);
196
243
  this.stepFunction = stepFunction;
@@ -221,6 +268,7 @@ var LazyFunctionStep = class extends BaseLazyStep {
221
268
  var LazySleepStep = class extends BaseLazyStep {
222
269
  sleep;
223
270
  stepType = "SleepFor";
271
+ allowUndefinedOut = true;
224
272
  constructor(stepName, sleep) {
225
273
  super(stepName);
226
274
  this.sleep = sleep;
@@ -248,6 +296,7 @@ var LazySleepStep = class extends BaseLazyStep {
248
296
  var LazySleepUntilStep = class extends BaseLazyStep {
249
297
  sleepUntil;
250
298
  stepType = "SleepUntil";
299
+ allowUndefinedOut = true;
251
300
  constructor(stepName, sleepUntil) {
252
301
  super(stepName);
253
302
  this.sleepUntil = sleepUntil;
@@ -271,8 +320,11 @@ var LazySleepUntilStep = class extends BaseLazyStep {
271
320
  concurrent
272
321
  });
273
322
  }
323
+ safeParseOut() {
324
+ return void 0;
325
+ }
274
326
  };
275
- var LazyCallStep = class extends BaseLazyStep {
327
+ var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
276
328
  url;
277
329
  method;
278
330
  body;
@@ -281,6 +333,7 @@ var LazyCallStep = class extends BaseLazyStep {
281
333
  timeout;
282
334
  flowControl;
283
335
  stepType = "Call";
336
+ allowUndefinedOut = false;
284
337
  constructor(stepName, url, method, body, headers, retries, timeout, flowControl) {
285
338
  super(stepName);
286
339
  this.url = url;
@@ -312,11 +365,53 @@ var LazyCallStep = class extends BaseLazyStep {
312
365
  callHeaders: this.headers
313
366
  });
314
367
  }
368
+ safeParseOut(out) {
369
+ const { header, status, body } = JSON.parse(out);
370
+ const responseHeaders = new Headers(header);
371
+ if (_LazyCallStep.isText(responseHeaders.get("content-type"))) {
372
+ const bytes = new Uint8Array(out.length);
373
+ for (let i = 0; i < out.length; i++) {
374
+ bytes[i] = out.charCodeAt(i);
375
+ }
376
+ const processedResult = new TextDecoder().decode(bytes);
377
+ const newBody = JSON.parse(processedResult).body;
378
+ return {
379
+ status,
380
+ header,
381
+ body: BaseLazyStep.tryParsing(newBody)
382
+ };
383
+ } else {
384
+ return { header, status, body };
385
+ }
386
+ }
387
+ static applicationHeaders = /* @__PURE__ */ new Set([
388
+ "application/json",
389
+ "application/xml",
390
+ "application/javascript",
391
+ "application/x-www-form-urlencoded",
392
+ "application/xhtml+xml",
393
+ "application/ld+json",
394
+ "application/rss+xml",
395
+ "application/atom+xml"
396
+ ]);
397
+ static isText = (contentTypeHeader) => {
398
+ if (!contentTypeHeader) {
399
+ return false;
400
+ }
401
+ if (_LazyCallStep.applicationHeaders.has(contentTypeHeader)) {
402
+ return true;
403
+ }
404
+ if (contentTypeHeader.startsWith("text/")) {
405
+ return true;
406
+ }
407
+ return false;
408
+ };
315
409
  };
316
410
  var LazyWaitForEventStep = class extends BaseLazyStep {
317
411
  eventId;
318
412
  timeout;
319
413
  stepType = "Wait";
414
+ allowUndefinedOut = false;
320
415
  constructor(stepName, eventId, timeout) {
321
416
  super(stepName);
322
417
  this.eventId = eventId;
@@ -343,6 +438,13 @@ var LazyWaitForEventStep = class extends BaseLazyStep {
343
438
  concurrent
344
439
  });
345
440
  }
441
+ safeParseOut(out) {
442
+ const result = JSON.parse(out);
443
+ return {
444
+ ...result,
445
+ eventData: BaseLazyStep.tryParsing(result.eventData)
446
+ };
447
+ }
346
448
  };
347
449
  var LazyNotifyStep = class extends LazyFunctionStep {
348
450
  stepType = "Notify";
@@ -356,10 +458,18 @@ var LazyNotifyStep = class extends LazyFunctionStep {
356
458
  };
357
459
  });
358
460
  }
461
+ safeParseOut(out) {
462
+ const result = JSON.parse(out);
463
+ return {
464
+ ...result,
465
+ eventData: BaseLazyStep.tryParsing(result.eventData)
466
+ };
467
+ }
359
468
  };
360
469
  var LazyInvokeStep = class extends BaseLazyStep {
361
470
  stepType = "Invoke";
362
471
  params;
472
+ allowUndefinedOut = false;
363
473
  constructor(stepName, {
364
474
  workflow,
365
475
  body,
@@ -399,6 +509,13 @@ var LazyInvokeStep = class extends BaseLazyStep {
399
509
  concurrent
400
510
  });
401
511
  }
512
+ safeParseOut(out) {
513
+ const result = JSON.parse(out);
514
+ return {
515
+ ...result,
516
+ body: BaseLazyStep.tryParsing(result.body)
517
+ };
518
+ }
402
519
  };
403
520
 
404
521
  // node_modules/neverthrow/dist/index.es.js
@@ -1084,7 +1201,8 @@ var getHeaders = ({
1084
1201
  flowControl,
1085
1202
  callFlowControl
1086
1203
  }) => {
1087
- const contentType = (userHeaders ? userHeaders.get("Content-Type") : void 0) ?? DEFAULT_CONTENT_TYPE;
1204
+ const callHeaders = new Headers(step?.callHeaders);
1205
+ const contentType = (callHeaders.get("content-type") ? callHeaders.get("content-type") : userHeaders?.get("Content-Type") ? userHeaders.get("Content-Type") : void 0) ?? DEFAULT_CONTENT_TYPE;
1088
1206
  const baseHeaders = {
1089
1207
  [WORKFLOW_INIT_HEADER]: initHeaderValue,
1090
1208
  [WORKFLOW_ID_HEADER]: workflowRunId,
@@ -1434,7 +1552,7 @@ var AutoExecutor = class _AutoExecutor {
1434
1552
  step,
1435
1553
  stepCount: this.stepCount
1436
1554
  });
1437
- return step.out;
1555
+ return lazyStep.parseOut(step.out);
1438
1556
  }
1439
1557
  const resultStep = await lazyStep.getResultStep(NO_CONCURRENCY, this.stepCount);
1440
1558
  await this.debug?.log("INFO", "RUN_SINGLE", {
@@ -1509,7 +1627,9 @@ var AutoExecutor = class _AutoExecutor {
1509
1627
  case "last": {
1510
1628
  const parallelResultSteps = sortedSteps.filter((step) => step.stepId >= initialStepCount).slice(0, parallelSteps.length);
1511
1629
  validateParallelSteps(parallelSteps, parallelResultSteps);
1512
- return parallelResultSteps.map((step) => step.out);
1630
+ return parallelResultSteps.map(
1631
+ (step, index) => parallelSteps[index].parseOut(step.out)
1632
+ );
1513
1633
  }
1514
1634
  }
1515
1635
  const fillValue = void 0;
@@ -1612,7 +1732,7 @@ var AutoExecutor = class _AutoExecutor {
1612
1732
  });
1613
1733
  throw new WorkflowAbort(invokeStep.stepName, invokeStep);
1614
1734
  }
1615
- const result = await this.context.qstashClient.batchJSON(
1735
+ const result = await this.context.qstashClient.batch(
1616
1736
  steps.map((singleStep, index) => {
1617
1737
  const lazyStep = lazySteps[index];
1618
1738
  const { headers } = getHeaders({
@@ -1642,7 +1762,7 @@ var AutoExecutor = class _AutoExecutor {
1642
1762
  {
1643
1763
  headers,
1644
1764
  method: singleStep.callMethod,
1645
- body: singleStep.callBody,
1765
+ body: JSON.stringify(singleStep.callBody),
1646
1766
  url: singleStep.callUrl
1647
1767
  }
1648
1768
  ) : (
@@ -1652,7 +1772,7 @@ var AutoExecutor = class _AutoExecutor {
1652
1772
  {
1653
1773
  headers,
1654
1774
  method: "POST",
1655
- body: singleStep,
1775
+ body: JSON.stringify(singleStep),
1656
1776
  url: this.context.url,
1657
1777
  notBefore: willWait ? singleStep.sleepUntil : void 0,
1658
1778
  delay: willWait ? singleStep.sleepFor : void 0
@@ -1660,8 +1780,9 @@ var AutoExecutor = class _AutoExecutor {
1660
1780
  );
1661
1781
  })
1662
1782
  );
1783
+ const _result = result;
1663
1784
  await this.debug?.log("INFO", "SUBMIT_STEP", {
1664
- messageIds: result.map((message) => {
1785
+ messageIds: _result.map((message) => {
1665
1786
  return {
1666
1787
  message: message.messageId
1667
1788
  };
@@ -2381,7 +2502,7 @@ var WorkflowContext = class {
2381
2502
  */
2382
2503
  async run(stepName, stepFunction) {
2383
2504
  const wrappedStepFunction = () => this.executor.wrapStep(stepName, stepFunction);
2384
- return this.addStep(new LazyFunctionStep(stepName, wrappedStepFunction));
2505
+ return await this.addStep(new LazyFunctionStep(stepName, wrappedStepFunction));
2385
2506
  }
2386
2507
  /**
2387
2508
  * Stops the execution for the duration provided.
@@ -2452,43 +2573,27 @@ var WorkflowContext = class {
2452
2573
  * }
2453
2574
  */
2454
2575
  async call(stepName, settings) {
2455
- const { url, method = "GET", body, headers = {}, retries = 0, timeout, flowControl } = settings;
2456
- const result = await this.addStep(
2576
+ const {
2577
+ url,
2578
+ method = "GET",
2579
+ body: requestBody,
2580
+ headers = {},
2581
+ retries = 0,
2582
+ timeout,
2583
+ flowControl
2584
+ } = settings;
2585
+ return await this.addStep(
2457
2586
  new LazyCallStep(
2458
2587
  stepName,
2459
2588
  url,
2460
2589
  method,
2461
- body,
2590
+ requestBody,
2462
2591
  headers,
2463
2592
  retries,
2464
2593
  timeout,
2465
2594
  flowControl
2466
2595
  )
2467
2596
  );
2468
- if (typeof result === "string") {
2469
- try {
2470
- const body2 = JSON.parse(result);
2471
- return {
2472
- status: 200,
2473
- header: {},
2474
- body: body2
2475
- };
2476
- } catch {
2477
- return {
2478
- status: 200,
2479
- header: {},
2480
- body: result
2481
- };
2482
- }
2483
- }
2484
- try {
2485
- return {
2486
- ...result,
2487
- body: JSON.parse(result.body)
2488
- };
2489
- } catch {
2490
- return result;
2491
- }
2492
2597
  }
2493
2598
  /**
2494
2599
  * Pauses workflow execution until a specific event occurs or a timeout is reached.
@@ -2527,15 +2632,7 @@ var WorkflowContext = class {
2527
2632
  async waitForEvent(stepName, eventId, options = {}) {
2528
2633
  const { timeout = "7d" } = options;
2529
2634
  const timeoutStr = typeof timeout === "string" ? timeout : `${timeout}s`;
2530
- const result = await this.addStep(new LazyWaitForEventStep(stepName, eventId, timeoutStr));
2531
- try {
2532
- return {
2533
- ...result,
2534
- eventData: JSON.parse(result.eventData)
2535
- };
2536
- } catch {
2537
- return result;
2538
- }
2635
+ return await this.addStep(new LazyWaitForEventStep(stepName, eventId, timeoutStr));
2539
2636
  }
2540
2637
  /**
2541
2638
  * Notify workflow runs waiting for an event
@@ -2559,24 +2656,12 @@ var WorkflowContext = class {
2559
2656
  * @returns notify response which has event id, event data and list of waiters which were notified
2560
2657
  */
2561
2658
  async notify(stepName, eventId, eventData) {
2562
- const result = await this.addStep(
2659
+ return await this.addStep(
2563
2660
  new LazyNotifyStep(stepName, eventId, eventData, this.qstashClient.http)
2564
2661
  );
2565
- try {
2566
- return {
2567
- ...result,
2568
- eventData: JSON.parse(result.eventData)
2569
- };
2570
- } catch {
2571
- return result;
2572
- }
2573
2662
  }
2574
2663
  async invoke(stepName, settings) {
2575
- const result = await this.addStep(new LazyInvokeStep(stepName, settings));
2576
- return {
2577
- ...result,
2578
- body: result.body ? JSON.parse(result.body) : void 0
2579
- };
2664
+ return await this.addStep(new LazyInvokeStep(stepName, settings));
2580
2665
  }
2581
2666
  /**
2582
2667
  * Cancel the current workflow run
@@ -2735,10 +2820,6 @@ var processRawSteps = (rawSteps) => {
2735
2820
  const stepsToDecode = encodedSteps.filter((step) => step.callType === "step");
2736
2821
  const otherSteps = stepsToDecode.map((rawStep) => {
2737
2822
  const step = JSON.parse(decodeBase64(rawStep.body));
2738
- try {
2739
- step.out = JSON.parse(step.out);
2740
- } catch {
2741
- }
2742
2823
  if (step.waitEventId) {
2743
2824
  const newOut = {
2744
2825
  eventData: step.out ? decodeBase64(step.out) : void 0,
package/index.mjs CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  makeNotifyRequest,
11
11
  serve,
12
12
  triggerFirstInvocation
13
- } from "./chunk-GFNR743S.mjs";
13
+ } from "./chunk-WQAJ2RSZ.mjs";
14
14
 
15
15
  // src/client/index.ts
16
16
  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, k as PublicServeOptions, t as InvokableWorkflow } from './types-CYhDXnf8.mjs';
3
- import { s as serveManyBase } from './serve-many-BVDpPsF-.mjs';
2
+ import { R as RouteFunction, k as PublicServeOptions, t as InvokableWorkflow } from './types-DS9q8FyV.mjs';
3
+ import { s as serveManyBase } from './serve-many-Fuovl7gl.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, k as PublicServeOptions, t as InvokableWorkflow } from './types-CYhDXnf8.js';
3
- import { s as serveManyBase } from './serve-many-e4zufyXN.js';
2
+ import { R as RouteFunction, k as PublicServeOptions, t as InvokableWorkflow } from './types-DS9q8FyV.js';
3
+ import { s as serveManyBase } from './serve-many-DNnLsDIp.js';
4
4
  import '@upstash/qstash';
5
5
  import 'zod';
6
6
  import 'ai';