@upstash/workflow 0.2.13 → 0.2.15

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
@@ -26,6 +26,7 @@ __export(src_exports, {
26
26
  WorkflowContext: () => WorkflowContext,
27
27
  WorkflowError: () => WorkflowError,
28
28
  WorkflowLogger: () => WorkflowLogger,
29
+ WorkflowNonRetryableError: () => WorkflowNonRetryableError,
29
30
  WorkflowTool: () => WorkflowTool,
30
31
  serve: () => serve
31
32
  });
@@ -103,7 +104,7 @@ var WORKFLOW_PROTOCOL_VERSION_HEADER = "Upstash-Workflow-Sdk-Version";
103
104
  var DEFAULT_CONTENT_TYPE = "application/json";
104
105
  var NO_CONCURRENCY = 1;
105
106
  var DEFAULT_RETRIES = 3;
106
- var VERSION = "v0.2.13";
107
+ var VERSION = "v0.2.15";
107
108
  var SDK_TELEMETRY = `@upstash/workflow@${VERSION}`;
108
109
  var TELEMETRY_HEADER_SDK = "Upstash-Telemetry-Sdk";
109
110
  var TELEMETRY_HEADER_FRAMEWORK = "Upstash-Telemetry-Framework";
@@ -141,6 +142,16 @@ var WorkflowAbort = class extends Error {
141
142
  this.cancelWorkflow = cancelWorkflow;
142
143
  }
143
144
  };
145
+ var WorkflowNonRetryableError = class extends WorkflowAbort {
146
+ /**
147
+ * @param message error message to be displayed
148
+ */
149
+ constructor(message) {
150
+ super("fail", void 0, false);
151
+ this.name = "WorkflowNonRetryableError";
152
+ if (message) this.message = message;
153
+ }
154
+ };
144
155
  var formatWorkflowError = (error) => {
145
156
  return error instanceof Error ? {
146
157
  error: error.name,
@@ -611,59 +622,72 @@ var StepTypes = [
611
622
 
612
623
  // src/workflow-requests.ts
613
624
  var import_qstash3 = require("@upstash/qstash");
614
- var triggerFirstInvocation = async ({
615
- workflowContext,
616
- useJSONContent,
617
- telemetry,
618
- debug,
619
- invokeCount,
620
- delay
621
- }) => {
622
- const { headers } = getHeaders({
623
- initHeaderValue: "true",
624
- workflowConfig: {
625
- workflowRunId: workflowContext.workflowRunId,
626
- workflowUrl: workflowContext.url,
627
- failureUrl: workflowContext.failureUrl,
628
- retries: workflowContext.retries,
629
- telemetry,
630
- flowControl: workflowContext.flowControl,
631
- useJSONContent: useJSONContent ?? false
632
- },
633
- invokeCount: invokeCount ?? 0,
634
- userHeaders: workflowContext.headers
635
- });
636
- if (workflowContext.headers.get("content-type")) {
637
- headers["content-type"] = workflowContext.headers.get("content-type");
638
- }
639
- if (useJSONContent) {
640
- headers["content-type"] = "application/json";
641
- }
642
- try {
643
- const body = typeof workflowContext.requestPayload === "string" ? workflowContext.requestPayload : JSON.stringify(workflowContext.requestPayload);
644
- const result = await workflowContext.qstashClient.publish({
645
- headers,
646
- method: "POST",
647
- body,
648
- url: workflowContext.url,
649
- delay
650
- });
651
- if (result.deduplicated) {
652
- await debug?.log("WARN", "SUBMIT_FIRST_INVOCATION", {
653
- message: `Workflow run ${workflowContext.workflowRunId} already exists. A new one isn't created.`,
625
+ var triggerFirstInvocation = async (params) => {
626
+ const firstInvocationParams = Array.isArray(params) ? params : [params];
627
+ const workflowContextClient = firstInvocationParams[0].workflowContext.qstashClient;
628
+ const invocationBatch = firstInvocationParams.map(
629
+ ({ workflowContext, useJSONContent, telemetry, invokeCount, delay }) => {
630
+ const { headers } = getHeaders({
631
+ initHeaderValue: "true",
632
+ workflowConfig: {
633
+ workflowRunId: workflowContext.workflowRunId,
634
+ workflowUrl: workflowContext.url,
635
+ failureUrl: workflowContext.failureUrl,
636
+ retries: workflowContext.retries,
637
+ telemetry,
638
+ flowControl: workflowContext.flowControl,
639
+ useJSONContent: useJSONContent ?? false
640
+ },
641
+ invokeCount: invokeCount ?? 0,
642
+ userHeaders: workflowContext.headers
643
+ });
644
+ if (workflowContext.headers.get("content-type")) {
645
+ headers["content-type"] = workflowContext.headers.get("content-type");
646
+ }
647
+ if (useJSONContent) {
648
+ headers["content-type"] = "application/json";
649
+ }
650
+ const body = typeof workflowContext.requestPayload === "string" ? workflowContext.requestPayload : JSON.stringify(workflowContext.requestPayload);
651
+ return {
654
652
  headers,
655
- requestPayload: workflowContext.requestPayload,
653
+ method: "POST",
654
+ body,
656
655
  url: workflowContext.url,
657
- messageId: result.messageId
658
- });
656
+ delay
657
+ };
658
+ }
659
+ );
660
+ try {
661
+ const results = await workflowContextClient.batch(invocationBatch);
662
+ const invocationStatuses = [];
663
+ for (let i = 0; i < results.length; i++) {
664
+ const result = results[i];
665
+ const invocationParams = firstInvocationParams[i];
666
+ if (result.deduplicated) {
667
+ await invocationParams.debug?.log("WARN", "SUBMIT_FIRST_INVOCATION", {
668
+ message: `Workflow run ${invocationParams.workflowContext.workflowRunId} already exists. A new one isn't created.`,
669
+ headers: invocationBatch[i].headers,
670
+ requestPayload: invocationParams.workflowContext.requestPayload,
671
+ url: invocationParams.workflowContext.url,
672
+ messageId: result.messageId
673
+ });
674
+ invocationStatuses.push("workflow-run-already-exists");
675
+ } else {
676
+ await invocationParams.debug?.log("SUBMIT", "SUBMIT_FIRST_INVOCATION", {
677
+ headers: invocationBatch[i].headers,
678
+ requestPayload: invocationParams.workflowContext.requestPayload,
679
+ url: invocationParams.workflowContext.url,
680
+ messageId: result.messageId
681
+ });
682
+ invocationStatuses.push("success");
683
+ }
684
+ }
685
+ const hasAnyDeduplicated = invocationStatuses.some(
686
+ (status) => status === "workflow-run-already-exists"
687
+ );
688
+ if (hasAnyDeduplicated) {
659
689
  return ok("workflow-run-already-exists");
660
690
  } else {
661
- await debug?.log("SUBMIT", "SUBMIT_FIRST_INVOCATION", {
662
- headers,
663
- requestPayload: workflowContext.requestPayload,
664
- url: workflowContext.url,
665
- messageId: result.messageId
666
- });
667
691
  return ok("success");
668
692
  }
669
693
  } catch (error) {
@@ -692,6 +716,8 @@ var triggerRouteFunction = async ({
692
716
  return ok("workflow-was-finished");
693
717
  } else if (!(error_ instanceof WorkflowAbort)) {
694
718
  return err(error_);
719
+ } else if (error_ instanceof WorkflowNonRetryableError) {
720
+ return ok(error_);
695
721
  } else if (error_.cancelWorkflow) {
696
722
  await onCancel();
697
723
  return ok("workflow-finished");
@@ -853,7 +879,7 @@ ${atob(callbackMessage.body ?? "")}`
853
879
  var getTelemetryHeaders = (telemetry) => {
854
880
  return {
855
881
  [TELEMETRY_HEADER_SDK]: telemetry.sdk,
856
- [TELEMETRY_HEADER_FRAMEWORK]: telemetry.framework,
882
+ [TELEMETRY_HEADER_FRAMEWORK]: telemetry.framework ?? "unknown",
857
883
  [TELEMETRY_HEADER_RUNTIME]: telemetry.runtime ?? "unknown"
858
884
  };
859
885
  };
@@ -1153,7 +1179,7 @@ var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
1153
1179
  return { header, status, body };
1154
1180
  }
1155
1181
  }
1156
- static applicationHeaders = /* @__PURE__ */ new Set([
1182
+ static applicationContentTypes = [
1157
1183
  "application/json",
1158
1184
  "application/xml",
1159
1185
  "application/javascript",
@@ -1162,12 +1188,12 @@ var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
1162
1188
  "application/ld+json",
1163
1189
  "application/rss+xml",
1164
1190
  "application/atom+xml"
1165
- ]);
1191
+ ];
1166
1192
  static isText = (contentTypeHeader) => {
1167
1193
  if (!contentTypeHeader) {
1168
1194
  return false;
1169
1195
  }
1170
- if (_LazyCallStep.applicationHeaders.has(contentTypeHeader)) {
1196
+ if (_LazyCallStep.applicationContentTypes.some((type) => contentTypeHeader.includes(type))) {
1171
1197
  return true;
1172
1198
  }
1173
1199
  if (contentTypeHeader.startsWith("text/")) {
@@ -2935,10 +2961,10 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
2935
2961
  throw new WorkflowAbort(_DisabledWorkflowContext.disabledMessage);
2936
2962
  }
2937
2963
  /**
2938
- * overwrite cancel method to do nothing
2964
+ * overwrite cancel method to throw WorkflowAbort with the disabledMessage
2939
2965
  */
2940
2966
  async cancel() {
2941
- return;
2967
+ throw new WorkflowAbort(_DisabledWorkflowContext.disabledMessage);
2942
2968
  }
2943
2969
  /**
2944
2970
  * copies the passed context to create a DisabledWorkflowContext. Then, runs the
@@ -2970,7 +2996,7 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
2970
2996
  try {
2971
2997
  await routeFunction(disabledContext);
2972
2998
  } catch (error) {
2973
- if (error instanceof WorkflowAbort && error.stepName === this.disabledMessage) {
2999
+ if (error instanceof WorkflowAbort && error.stepName === this.disabledMessage || error instanceof WorkflowNonRetryableError) {
2974
3000
  return ok("step-found");
2975
3001
  }
2976
3002
  return err(error);
@@ -3191,6 +3217,13 @@ var processOptions = (options) => {
3191
3217
  status: 400
3192
3218
  }
3193
3219
  );
3220
+ } else if (finishCondition instanceof WorkflowNonRetryableError) {
3221
+ return new Response(JSON.stringify(formatWorkflowError(finishCondition)), {
3222
+ headers: {
3223
+ "Upstash-NonRetryable-Error": "true"
3224
+ },
3225
+ status: 489
3226
+ });
3194
3227
  }
3195
3228
  return new Response(JSON.stringify({ workflowRunId }), {
3196
3229
  status: 200
@@ -3383,6 +3416,9 @@ var serveBase = (routeFunction, telemetry, options) => {
3383
3416
  },
3384
3417
  debug
3385
3418
  });
3419
+ if (result.isOk() && result.value instanceof WorkflowNonRetryableError) {
3420
+ return onStepFinish(workflowRunId, result.value);
3421
+ }
3386
3422
  if (result.isErr()) {
3387
3423
  await debug?.log("ERROR", "ERROR", { error: result.error.message });
3388
3424
  throw result.error;
@@ -3431,6 +3467,86 @@ var serve = (routeFunction, options) => {
3431
3467
 
3432
3468
  // src/client/index.ts
3433
3469
  var import_qstash12 = require("@upstash/qstash");
3470
+
3471
+ // src/client/dlq.ts
3472
+ var DLQ = class _DLQ {
3473
+ constructor(client) {
3474
+ this.client = client;
3475
+ }
3476
+ /**
3477
+ * list the items in the DLQ
3478
+ *
3479
+ * @param cursor - Optional cursor for pagination.
3480
+ * @param count - Optional number of items to return.
3481
+ * @param filter - Optional filter options to apply to the DLQ items.
3482
+ * The available filter options are:
3483
+ * - `fromDate`: Filter items which entered the DLQ after this date.
3484
+ * - `toDate`: Filter items which entered the DLQ before this date.
3485
+ * - `url`: Filter items by the URL they were sent to.
3486
+ * - `responseStatus`: Filter items by the response status code.
3487
+ * @returns
3488
+ */
3489
+ async list(parameters) {
3490
+ const { cursor, count, filter } = parameters || {};
3491
+ return await this.client.http.request({
3492
+ path: ["v2", "dlq"],
3493
+ method: "GET",
3494
+ query: {
3495
+ cursor,
3496
+ count,
3497
+ ...filter,
3498
+ source: "workflow"
3499
+ }
3500
+ });
3501
+ }
3502
+ async resume(parameters) {
3503
+ const { headers, queryParams } = _DLQ.handleDLQOptions(parameters);
3504
+ const { workflowRuns } = await this.client.http.request({
3505
+ path: ["v2", "workflows", "dlq", `resume?${queryParams}`],
3506
+ headers,
3507
+ method: "POST"
3508
+ });
3509
+ if (Array.isArray(parameters.dlqId)) {
3510
+ return workflowRuns;
3511
+ }
3512
+ return workflowRuns[0];
3513
+ }
3514
+ async restart(parameters) {
3515
+ const { headers, queryParams } = _DLQ.handleDLQOptions(parameters);
3516
+ const { workflowRuns } = await this.client.http.request({
3517
+ path: ["v2", "workflows", "dlq", `restart?${queryParams}`],
3518
+ headers,
3519
+ method: "POST"
3520
+ });
3521
+ if (Array.isArray(parameters.dlqId)) {
3522
+ return workflowRuns;
3523
+ }
3524
+ return workflowRuns[0];
3525
+ }
3526
+ static handleDLQOptions(options) {
3527
+ const { dlqId, flowControl, retries } = options;
3528
+ const headers = {};
3529
+ if (flowControl) {
3530
+ const { flowControlKey, flowControlValue } = prepareFlowControl(flowControl);
3531
+ headers["Upstash-Flow-Control-Key"] = flowControlKey;
3532
+ headers["Upstash-Flow-Control-Value"] = flowControlValue;
3533
+ }
3534
+ if (retries !== void 0) {
3535
+ headers["Upstash-Retries"] = retries.toString();
3536
+ }
3537
+ return {
3538
+ queryParams: _DLQ.getDlqIdQueryParameter(dlqId),
3539
+ headers
3540
+ };
3541
+ }
3542
+ static getDlqIdQueryParameter(dlqId) {
3543
+ const dlqIds = Array.isArray(dlqId) ? dlqId : [dlqId];
3544
+ const paramsArray = dlqIds.map((id) => ["dlqIds", id]);
3545
+ return new URLSearchParams(paramsArray).toString();
3546
+ }
3547
+ };
3548
+
3549
+ // src/client/index.ts
3434
3550
  var Client4 = class {
3435
3551
  client;
3436
3552
  constructor(clientConfig) {
@@ -3557,70 +3673,37 @@ var Client4 = class {
3557
3673
  async getWaiters({ eventId }) {
3558
3674
  return await makeGetWaitersRequest(this.client.http, eventId);
3559
3675
  }
3560
- /**
3561
- * Trigger new workflow run and returns the workflow run id
3562
- *
3563
- * ```ts
3564
- * const { workflowRunId } = await client.trigger({
3565
- * url: "https://workflow-endpoint.com",
3566
- * body: "hello there!", // Optional body
3567
- * headers: { ... }, // Optional headers
3568
- * workflowRunId: "my-workflow", // Optional workflow run ID
3569
- * retries: 3 // Optional retries for the initial request
3570
- * });
3571
- *
3572
- * console.log(workflowRunId)
3573
- * // wfr_my-workflow
3574
- * ```
3575
- *
3576
- * @param url URL of the workflow
3577
- * @param body body to start the workflow with
3578
- * @param headers headers to use in the request
3579
- * @param workflowRunId optional workflow run id to use. mind that
3580
- * you should pass different workflow run ids for different runs.
3581
- * The final workflowRunId will be `wfr_${workflowRunId}`, in
3582
- * other words: the workflow run id you pass will be prefixed
3583
- * with `wfr_`.
3584
- * @param retries retry to use in the initial request. in the rest of
3585
- * the workflow, `retries` option of the `serve` will be used.
3586
- * @param flowControl Settings for controlling the number of active requests
3587
- * and number of requests per second with the same key.
3588
- * @param delay Delay for the workflow run. This is used to delay the
3589
- * execution of the workflow run. The delay is in seconds or can be passed
3590
- * as a string with a time unit (e.g. "1h", "30m", "15s").
3591
- * @returns workflow run id
3592
- */
3593
- async trigger({
3594
- url,
3595
- body,
3596
- headers,
3597
- workflowRunId,
3598
- retries,
3599
- flowControl,
3600
- delay
3601
- }) {
3602
- const finalWorkflowRunId = getWorkflowRunId(workflowRunId);
3603
- const context = new WorkflowContext({
3604
- qstashClient: this.client,
3605
- // @ts-expect-error headers type mismatch
3606
- headers: new Headers(headers ?? {}),
3607
- initialPayload: body,
3608
- steps: [],
3609
- url,
3610
- workflowRunId: finalWorkflowRunId,
3611
- retries,
3612
- telemetry: void 0,
3613
- // can't know workflow telemetry here
3614
- flowControl
3615
- });
3616
- const result = await triggerFirstInvocation({
3617
- workflowContext: context,
3618
- telemetry: void 0,
3619
- // can't know workflow telemetry here
3620
- delay
3676
+ async trigger(params) {
3677
+ const isBatchInput = Array.isArray(params);
3678
+ const options = isBatchInput ? params : [params];
3679
+ const invocations = options.map((option) => {
3680
+ const failureUrl = option.useFailureFunction ? option.url : option.failureUrl;
3681
+ const finalWorkflowRunId = getWorkflowRunId(option.workflowRunId);
3682
+ const context = new WorkflowContext({
3683
+ qstashClient: this.client,
3684
+ // @ts-expect-error headers type mismatch
3685
+ headers: new Headers(option.headers ?? {}),
3686
+ initialPayload: option.body,
3687
+ steps: [],
3688
+ url: option.url,
3689
+ workflowRunId: finalWorkflowRunId,
3690
+ retries: option.retries,
3691
+ telemetry: { sdk: SDK_TELEMETRY },
3692
+ flowControl: option.flowControl,
3693
+ failureUrl
3694
+ });
3695
+ return {
3696
+ workflowContext: context,
3697
+ telemetry: { sdk: SDK_TELEMETRY },
3698
+ delay: option.delay
3699
+ };
3621
3700
  });
3701
+ const result = await triggerFirstInvocation(invocations);
3702
+ const workflowRunIds = invocations.map(
3703
+ (invocation) => invocation.workflowContext.workflowRunId
3704
+ );
3622
3705
  if (result.isOk()) {
3623
- return { workflowRunId: finalWorkflowRunId };
3706
+ return isBatchInput ? workflowRunIds.map((id) => ({ workflowRunId: id })) : { workflowRunId: workflowRunIds[0] };
3624
3707
  } else {
3625
3708
  throw result.error;
3626
3709
  }
@@ -3678,6 +3761,9 @@ var Client4 = class {
3678
3761
  });
3679
3762
  return result;
3680
3763
  }
3764
+ get dlq() {
3765
+ return new DLQ(this.client);
3766
+ }
3681
3767
  };
3682
3768
  // Annotate the CommonJS export names for ESM import in node:
3683
3769
  0 && (module.exports = {
@@ -3687,6 +3773,7 @@ var Client4 = class {
3687
3773
  WorkflowContext,
3688
3774
  WorkflowError,
3689
3775
  WorkflowLogger,
3776
+ WorkflowNonRetryableError,
3690
3777
  WorkflowTool,
3691
3778
  serve
3692
3779
  });
package/index.mjs CHANGED
@@ -1,19 +1,102 @@
1
1
  import {
2
+ SDK_TELEMETRY,
2
3
  StepTypes,
3
4
  WorkflowAbort,
4
5
  WorkflowContext,
5
6
  WorkflowError,
6
7
  WorkflowLogger,
8
+ WorkflowNonRetryableError,
7
9
  WorkflowTool,
8
10
  getWorkflowRunId,
9
11
  makeGetWaitersRequest,
10
12
  makeNotifyRequest,
13
+ prepareFlowControl,
11
14
  serve,
12
15
  triggerFirstInvocation
13
- } from "./chunk-XVNSBBDC.mjs";
16
+ } from "./chunk-AC5CQCN3.mjs";
14
17
 
15
18
  // src/client/index.ts
16
19
  import { Client as QStashClient } from "@upstash/qstash";
20
+
21
+ // src/client/dlq.ts
22
+ var DLQ = class _DLQ {
23
+ constructor(client) {
24
+ this.client = client;
25
+ }
26
+ /**
27
+ * list the items in the DLQ
28
+ *
29
+ * @param cursor - Optional cursor for pagination.
30
+ * @param count - Optional number of items to return.
31
+ * @param filter - Optional filter options to apply to the DLQ items.
32
+ * The available filter options are:
33
+ * - `fromDate`: Filter items which entered the DLQ after this date.
34
+ * - `toDate`: Filter items which entered the DLQ before this date.
35
+ * - `url`: Filter items by the URL they were sent to.
36
+ * - `responseStatus`: Filter items by the response status code.
37
+ * @returns
38
+ */
39
+ async list(parameters) {
40
+ const { cursor, count, filter } = parameters || {};
41
+ return await this.client.http.request({
42
+ path: ["v2", "dlq"],
43
+ method: "GET",
44
+ query: {
45
+ cursor,
46
+ count,
47
+ ...filter,
48
+ source: "workflow"
49
+ }
50
+ });
51
+ }
52
+ async resume(parameters) {
53
+ const { headers, queryParams } = _DLQ.handleDLQOptions(parameters);
54
+ const { workflowRuns } = await this.client.http.request({
55
+ path: ["v2", "workflows", "dlq", `resume?${queryParams}`],
56
+ headers,
57
+ method: "POST"
58
+ });
59
+ if (Array.isArray(parameters.dlqId)) {
60
+ return workflowRuns;
61
+ }
62
+ return workflowRuns[0];
63
+ }
64
+ async restart(parameters) {
65
+ const { headers, queryParams } = _DLQ.handleDLQOptions(parameters);
66
+ const { workflowRuns } = await this.client.http.request({
67
+ path: ["v2", "workflows", "dlq", `restart?${queryParams}`],
68
+ headers,
69
+ method: "POST"
70
+ });
71
+ if (Array.isArray(parameters.dlqId)) {
72
+ return workflowRuns;
73
+ }
74
+ return workflowRuns[0];
75
+ }
76
+ static handleDLQOptions(options) {
77
+ const { dlqId, flowControl, retries } = options;
78
+ const headers = {};
79
+ if (flowControl) {
80
+ const { flowControlKey, flowControlValue } = prepareFlowControl(flowControl);
81
+ headers["Upstash-Flow-Control-Key"] = flowControlKey;
82
+ headers["Upstash-Flow-Control-Value"] = flowControlValue;
83
+ }
84
+ if (retries !== void 0) {
85
+ headers["Upstash-Retries"] = retries.toString();
86
+ }
87
+ return {
88
+ queryParams: _DLQ.getDlqIdQueryParameter(dlqId),
89
+ headers
90
+ };
91
+ }
92
+ static getDlqIdQueryParameter(dlqId) {
93
+ const dlqIds = Array.isArray(dlqId) ? dlqId : [dlqId];
94
+ const paramsArray = dlqIds.map((id) => ["dlqIds", id]);
95
+ return new URLSearchParams(paramsArray).toString();
96
+ }
97
+ };
98
+
99
+ // src/client/index.ts
17
100
  var Client = class {
18
101
  client;
19
102
  constructor(clientConfig) {
@@ -140,70 +223,37 @@ var Client = class {
140
223
  async getWaiters({ eventId }) {
141
224
  return await makeGetWaitersRequest(this.client.http, eventId);
142
225
  }
143
- /**
144
- * Trigger new workflow run and returns the workflow run id
145
- *
146
- * ```ts
147
- * const { workflowRunId } = await client.trigger({
148
- * url: "https://workflow-endpoint.com",
149
- * body: "hello there!", // Optional body
150
- * headers: { ... }, // Optional headers
151
- * workflowRunId: "my-workflow", // Optional workflow run ID
152
- * retries: 3 // Optional retries for the initial request
153
- * });
154
- *
155
- * console.log(workflowRunId)
156
- * // wfr_my-workflow
157
- * ```
158
- *
159
- * @param url URL of the workflow
160
- * @param body body to start the workflow with
161
- * @param headers headers to use in the request
162
- * @param workflowRunId optional workflow run id to use. mind that
163
- * you should pass different workflow run ids for different runs.
164
- * The final workflowRunId will be `wfr_${workflowRunId}`, in
165
- * other words: the workflow run id you pass will be prefixed
166
- * with `wfr_`.
167
- * @param retries retry to use in the initial request. in the rest of
168
- * the workflow, `retries` option of the `serve` will be used.
169
- * @param flowControl Settings for controlling the number of active requests
170
- * and number of requests per second with the same key.
171
- * @param delay Delay for the workflow run. This is used to delay the
172
- * execution of the workflow run. The delay is in seconds or can be passed
173
- * as a string with a time unit (e.g. "1h", "30m", "15s").
174
- * @returns workflow run id
175
- */
176
- async trigger({
177
- url,
178
- body,
179
- headers,
180
- workflowRunId,
181
- retries,
182
- flowControl,
183
- delay
184
- }) {
185
- const finalWorkflowRunId = getWorkflowRunId(workflowRunId);
186
- const context = new WorkflowContext({
187
- qstashClient: this.client,
188
- // @ts-expect-error headers type mismatch
189
- headers: new Headers(headers ?? {}),
190
- initialPayload: body,
191
- steps: [],
192
- url,
193
- workflowRunId: finalWorkflowRunId,
194
- retries,
195
- telemetry: void 0,
196
- // can't know workflow telemetry here
197
- flowControl
198
- });
199
- const result = await triggerFirstInvocation({
200
- workflowContext: context,
201
- telemetry: void 0,
202
- // can't know workflow telemetry here
203
- delay
226
+ async trigger(params) {
227
+ const isBatchInput = Array.isArray(params);
228
+ const options = isBatchInput ? params : [params];
229
+ const invocations = options.map((option) => {
230
+ const failureUrl = option.useFailureFunction ? option.url : option.failureUrl;
231
+ const finalWorkflowRunId = getWorkflowRunId(option.workflowRunId);
232
+ const context = new WorkflowContext({
233
+ qstashClient: this.client,
234
+ // @ts-expect-error headers type mismatch
235
+ headers: new Headers(option.headers ?? {}),
236
+ initialPayload: option.body,
237
+ steps: [],
238
+ url: option.url,
239
+ workflowRunId: finalWorkflowRunId,
240
+ retries: option.retries,
241
+ telemetry: { sdk: SDK_TELEMETRY },
242
+ flowControl: option.flowControl,
243
+ failureUrl
244
+ });
245
+ return {
246
+ workflowContext: context,
247
+ telemetry: { sdk: SDK_TELEMETRY },
248
+ delay: option.delay
249
+ };
204
250
  });
251
+ const result = await triggerFirstInvocation(invocations);
252
+ const workflowRunIds = invocations.map(
253
+ (invocation) => invocation.workflowContext.workflowRunId
254
+ );
205
255
  if (result.isOk()) {
206
- return { workflowRunId: finalWorkflowRunId };
256
+ return isBatchInput ? workflowRunIds.map((id) => ({ workflowRunId: id })) : { workflowRunId: workflowRunIds[0] };
207
257
  } else {
208
258
  throw result.error;
209
259
  }
@@ -261,6 +311,9 @@ var Client = class {
261
311
  });
262
312
  return result;
263
313
  }
314
+ get dlq() {
315
+ return new DLQ(this.client);
316
+ }
264
317
  };
265
318
  export {
266
319
  Client,
@@ -269,6 +322,7 @@ export {
269
322
  WorkflowContext,
270
323
  WorkflowError,
271
324
  WorkflowLogger,
325
+ WorkflowNonRetryableError,
272
326
  WorkflowTool,
273
327
  serve
274
328
  };
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-C1WIgVLA.mjs';
3
- import { s as serveManyBase } from './serve-many-BF71QZHQ.mjs';
2
+ import { R as RouteFunction, n as PublicServeOptions, w as InvokableWorkflow } from './types-Dd-3bPoU.mjs';
3
+ import { s as serveManyBase } from './serve-many-AFwJPR3S.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-C1WIgVLA.js';
3
- import { s as serveManyBase } from './serve-many-BMlN2PAB.js';
2
+ import { R as RouteFunction, n as PublicServeOptions, w as InvokableWorkflow } from './types-Dd-3bPoU.js';
3
+ import { s as serveManyBase } from './serve-many-AaKSQyi7.js';
4
4
  import '@upstash/qstash';
5
5
  import 'zod';
6
6
  import 'ai';