@upstash/workflow 0.2.21 → 0.2.22

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/cloudflare.js CHANGED
@@ -39,7 +39,7 @@ var WORKFLOW_PROTOCOL_VERSION_HEADER = "Upstash-Workflow-Sdk-Version";
39
39
  var DEFAULT_CONTENT_TYPE = "application/json";
40
40
  var NO_CONCURRENCY = 1;
41
41
  var DEFAULT_RETRIES = 3;
42
- var VERSION = "v0.2.21";
42
+ var VERSION = "v0.2.22";
43
43
  var SDK_TELEMETRY = `@upstash/workflow@${VERSION}`;
44
44
  var TELEMETRY_HEADER_SDK = "Upstash-Telemetry-Sdk";
45
45
  var TELEMETRY_HEADER_FRAMEWORK = "Upstash-Telemetry-Framework";
@@ -47,61 +47,11 @@ var TELEMETRY_HEADER_RUNTIME = "Upstash-Telemetry-Runtime";
47
47
  var TELEMETRY_HEADER_AGENT = "Upstash-Telemetry-Agent";
48
48
 
49
49
  // src/client/utils.ts
50
- var import_qstash = require("@upstash/qstash");
51
- var makeNotifyRequest = async (requester, eventId, eventData) => {
52
- const result = await requester.request({
53
- path: ["v2", "notify", eventId],
54
- method: "POST",
55
- body: typeof eventData === "string" ? eventData : JSON.stringify(eventData)
56
- });
57
- return result;
58
- };
59
- var makeCancelRequest = async (requester, workflowRunId) => {
60
- await requester.request({
61
- path: ["v2", "workflows", "runs", `${workflowRunId}?cancel=true`],
62
- method: "DELETE",
63
- parseResponseAsJson: false
64
- });
65
- return true;
66
- };
67
- var getSteps = async (requester, workflowRunId, messageId, debug) => {
68
- try {
69
- const steps = await requester.request({
70
- path: ["v2", "workflows", "runs", workflowRunId],
71
- parseResponseAsJson: true
72
- });
73
- if (!messageId) {
74
- await debug?.log("INFO", "ENDPOINT_START", {
75
- message: `Pulled ${steps.length} steps from QStashand returned them without filtering with messageId.`
76
- });
77
- return { steps, workflowRunEnded: false };
78
- } else {
79
- const index = steps.findIndex((item) => item.messageId === messageId);
80
- if (index === -1) {
81
- return { steps: [], workflowRunEnded: false };
82
- }
83
- const filteredSteps = steps.slice(0, index + 1);
84
- await debug?.log("INFO", "ENDPOINT_START", {
85
- message: `Pulled ${steps.length} steps from QStash and filtered them to ${filteredSteps.length} using messageId.`
86
- });
87
- return { steps: filteredSteps, workflowRunEnded: false };
88
- }
89
- } catch (error) {
90
- if (error instanceof import_qstash.QstashError && error.status === 404) {
91
- await debug?.log("WARN", "ENDPOINT_START", {
92
- message: "Couldn't fetch workflow run steps. This can happen if the workflow run succesfully ends before some callback is executed.",
93
- error
94
- });
95
- return { steps: void 0, workflowRunEnded: true };
96
- } else {
97
- throw error;
98
- }
99
- }
100
- };
50
+ var import_qstash2 = require("@upstash/qstash");
101
51
 
102
52
  // src/error.ts
103
- var import_qstash2 = require("@upstash/qstash");
104
- var WorkflowError = class extends import_qstash2.QstashError {
53
+ var import_qstash = require("@upstash/qstash");
54
+ var WorkflowError = class extends import_qstash.QstashError {
105
55
  constructor(message) {
106
56
  super(message);
107
57
  this.name = "WorkflowError";
@@ -140,6 +90,19 @@ var WorkflowNonRetryableError = class extends WorkflowAbort {
140
90
  if (message) this.message = message;
141
91
  }
142
92
  };
93
+ var WorkflowRetryAfterError = class extends WorkflowAbort {
94
+ retryAfter;
95
+ /**
96
+ * @param retryAfter time in seconds after which the workflow should be retried
97
+ * @param message error message to be displayed
98
+ */
99
+ constructor(message, retryAfter) {
100
+ super("retry", void 0, false);
101
+ this.name = "WorkflowRetryAfterError";
102
+ this.retryAfter = retryAfter;
103
+ if (message) this.message = message;
104
+ }
105
+ };
143
106
  var formatWorkflowError = (error) => {
144
107
  return error instanceof Error ? {
145
108
  error: error.name,
@@ -150,6 +113,79 @@ var formatWorkflowError = (error) => {
150
113
  message: `An error occured while executing workflow: '${typeof error === "string" ? error : JSON.stringify(error)}'`
151
114
  };
152
115
  };
116
+ function getConstructorName(obj) {
117
+ if (obj === null || obj === void 0) {
118
+ return null;
119
+ }
120
+ const ctor = obj.constructor;
121
+ if (!ctor || ctor.name === "Object") {
122
+ return null;
123
+ }
124
+ return ctor.name;
125
+ }
126
+ function getConstructorNames(obj) {
127
+ const proto = Object.getPrototypeOf(obj);
128
+ const name = getConstructorName(proto);
129
+ if (name === null) {
130
+ return [];
131
+ }
132
+ return [name, ...getConstructorNames(proto)];
133
+ }
134
+ function isInstanceOf(v, ctor) {
135
+ return getConstructorNames(v).includes(ctor.name);
136
+ }
137
+
138
+ // src/client/utils.ts
139
+ var makeNotifyRequest = async (requester, eventId, eventData) => {
140
+ const result = await requester.request({
141
+ path: ["v2", "notify", eventId],
142
+ method: "POST",
143
+ body: typeof eventData === "string" ? eventData : JSON.stringify(eventData)
144
+ });
145
+ return result;
146
+ };
147
+ var makeCancelRequest = async (requester, workflowRunId) => {
148
+ await requester.request({
149
+ path: ["v2", "workflows", "runs", `${workflowRunId}?cancel=true`],
150
+ method: "DELETE",
151
+ parseResponseAsJson: false
152
+ });
153
+ return true;
154
+ };
155
+ var getSteps = async (requester, workflowRunId, messageId, debug) => {
156
+ try {
157
+ const steps = await requester.request({
158
+ path: ["v2", "workflows", "runs", workflowRunId],
159
+ parseResponseAsJson: true
160
+ });
161
+ if (!messageId) {
162
+ await debug?.log("INFO", "ENDPOINT_START", {
163
+ message: `Pulled ${steps.length} steps from QStashand returned them without filtering with messageId.`
164
+ });
165
+ return { steps, workflowRunEnded: false };
166
+ } else {
167
+ const index = steps.findIndex((item) => item.messageId === messageId);
168
+ if (index === -1) {
169
+ return { steps: [], workflowRunEnded: false };
170
+ }
171
+ const filteredSteps = steps.slice(0, index + 1);
172
+ await debug?.log("INFO", "ENDPOINT_START", {
173
+ message: `Pulled ${steps.length} steps from QStash and filtered them to ${filteredSteps.length} using messageId.`
174
+ });
175
+ return { steps: filteredSteps, workflowRunEnded: false };
176
+ }
177
+ } catch (error) {
178
+ if (isInstanceOf(error, import_qstash2.QstashError) && error.status === 404) {
179
+ await debug?.log("WARN", "ENDPOINT_START", {
180
+ message: "Couldn't fetch workflow run steps. This can happen if the workflow run succesfully ends before some callback is executed.",
181
+ error
182
+ });
183
+ return { steps: void 0, workflowRunEnded: true };
184
+ } else {
185
+ throw error;
186
+ }
187
+ }
188
+ };
153
189
 
154
190
  // src/context/auto-executor.ts
155
191
  var import_qstash5 = require("@upstash/qstash");
@@ -710,17 +746,17 @@ var triggerRouteFunction = async ({
710
746
  return ok("workflow-finished");
711
747
  } catch (error) {
712
748
  const error_ = error;
713
- if (error instanceof import_qstash3.QstashError && error.status === 400) {
749
+ if (isInstanceOf(error, import_qstash3.QstashError) && error.status === 400) {
714
750
  await debug?.log("WARN", "RESPONSE_WORKFLOW", {
715
751
  message: `tried to append to a cancelled workflow. exiting without publishing.`,
716
752
  name: error.name,
717
753
  errorMessage: error.message
718
754
  });
719
755
  return ok("workflow-was-finished");
720
- } else if (!(error_ instanceof WorkflowAbort)) {
721
- return err(error_);
722
- } else if (error_ instanceof WorkflowNonRetryableError) {
756
+ } else if (isInstanceOf(error_, WorkflowNonRetryableError) || isInstanceOf(error_, WorkflowRetryAfterError)) {
723
757
  return ok(error_);
758
+ } else if (!isInstanceOf(error_, WorkflowAbort)) {
759
+ return err(error_);
724
760
  } else if (error_.cancelWorkflow) {
725
761
  await onCancel();
726
762
  return ok("workflow-finished");
@@ -2027,7 +2063,7 @@ var AutoExecutor = class _AutoExecutor {
2027
2063
  });
2028
2064
  throw new WorkflowAbort(parallelStep.stepName, resultStep);
2029
2065
  } catch (error) {
2030
- if (error instanceof WorkflowAbort || error instanceof import_qstash5.QstashError && error.status === 400) {
2066
+ if (isInstanceOf(error, WorkflowAbort) || isInstanceOf(error, import_qstash5.QstashError) && error.status === 400) {
2031
2067
  throw error;
2032
2068
  }
2033
2069
  throw new WorkflowError(
@@ -2134,7 +2170,7 @@ var validateParallelSteps = (lazySteps, stepsFromRequest) => {
2134
2170
  validateStep(lazySteps[index], stepFromRequest);
2135
2171
  }
2136
2172
  } catch (error) {
2137
- if (error instanceof WorkflowError) {
2173
+ if (isInstanceOf(error, WorkflowError)) {
2138
2174
  const lazyStepNames = lazySteps.map((lazyStep) => lazyStep.stepName);
2139
2175
  const lazyStepTypes = lazySteps.map((lazyStep) => lazyStep.stepType);
2140
2176
  const requestStepNames = stepsFromRequest.map((step) => step.stepName);
@@ -2315,7 +2351,7 @@ var fetchWithContextCall = async (context, agentCallParams, ...params) => {
2315
2351
  headers: responseHeaders
2316
2352
  });
2317
2353
  } catch (error) {
2318
- if (error instanceof Error && error.name === "WorkflowAbort") {
2354
+ if (error instanceof Error && isInstanceOf(error, WorkflowAbort)) {
2319
2355
  throw error;
2320
2356
  } else {
2321
2357
  console.error("Error in fetch implementation:", error);
@@ -2417,10 +2453,10 @@ var Agent = class {
2417
2453
  });
2418
2454
  return { text: result.text };
2419
2455
  } catch (error) {
2420
- if (error instanceof import_ai2.ToolExecutionError) {
2421
- if (error.cause instanceof Error && error.cause.name === "WorkflowAbort") {
2456
+ if (isInstanceOf(error, import_ai2.ToolExecutionError)) {
2457
+ if (error.cause instanceof Error && isInstanceOf(error.cause, WorkflowAbort)) {
2422
2458
  throw error.cause;
2423
- } else if (error.cause instanceof import_ai2.ToolExecutionError && error.cause.cause instanceof Error && error.cause.cause.name === "WorkflowAbort") {
2459
+ } else if (isInstanceOf(error.cause, import_ai2.ToolExecutionError) && isInstanceOf(error.cause.cause, WorkflowAbort)) {
2424
2460
  throw error.cause.cause;
2425
2461
  } else {
2426
2462
  throw error;
@@ -3169,7 +3205,7 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
3169
3205
  try {
3170
3206
  await routeFunction(disabledContext);
3171
3207
  } catch (error) {
3172
- if (error instanceof WorkflowAbort && error.stepName === this.disabledMessage || error instanceof WorkflowNonRetryableError) {
3208
+ if (isInstanceOf(error, WorkflowAbort) && error.stepName === this.disabledMessage || isInstanceOf(error, WorkflowNonRetryableError) || isInstanceOf(error, WorkflowRetryAfterError)) {
3173
3209
  return ok("step-found");
3174
3210
  }
3175
3211
  console.warn(
@@ -3422,13 +3458,24 @@ var processOptions = (options) => {
3422
3458
  },
3423
3459
  status: 489
3424
3460
  });
3425
- } else if (detailedFinishCondition?.condition === "failure-callback") {
3426
- return new Response(detailedFinishCondition.result ?? void 0, {
3427
- status: 200,
3461
+ } else if (detailedFinishCondition?.condition === "retry-after-error") {
3462
+ return new Response(JSON.stringify(formatWorkflowError(detailedFinishCondition.result)), {
3428
3463
  headers: {
3464
+ "Retry-After": detailedFinishCondition.result.retryAfter.toString(),
3429
3465
  [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION
3430
- }
3466
+ },
3467
+ status: 429
3431
3468
  });
3469
+ } else if (detailedFinishCondition?.condition === "failure-callback") {
3470
+ return new Response(
3471
+ JSON.stringify({ result: detailedFinishCondition.result ?? void 0 }),
3472
+ {
3473
+ status: 200,
3474
+ headers: {
3475
+ [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION
3476
+ }
3477
+ }
3478
+ );
3432
3479
  }
3433
3480
  return new Response(JSON.stringify({ workflowRunId }), {
3434
3481
  status: 200,
@@ -3638,12 +3685,18 @@ var serveBase = (routeFunction, telemetry2, options) => {
3638
3685
  },
3639
3686
  debug
3640
3687
  });
3641
- if (result.isOk() && result.value instanceof WorkflowNonRetryableError) {
3688
+ if (result.isOk() && isInstanceOf(result.value, WorkflowNonRetryableError)) {
3642
3689
  return onStepFinish(workflowRunId, result.value, {
3643
3690
  condition: "non-retryable-error",
3644
3691
  result: result.value
3645
3692
  });
3646
3693
  }
3694
+ if (result.isOk() && isInstanceOf(result.value, WorkflowRetryAfterError)) {
3695
+ return onStepFinish(workflowRunId, result.value, {
3696
+ condition: "retry-after-error",
3697
+ result: result.value
3698
+ });
3699
+ }
3647
3700
  if (result.isErr()) {
3648
3701
  await debug?.log("ERROR", "ERROR", { error: result.error.message });
3649
3702
  throw result.error;
@@ -3674,7 +3727,7 @@ var serveBase = (routeFunction, telemetry2, options) => {
3674
3727
  const errorMessage = `Error while running onError callback: '${formattedOnErrorError.message}'.
3675
3728
  Original error: '${formattedError.message}'`;
3676
3729
  console.error(errorMessage);
3677
- return new Response(errorMessage, {
3730
+ return new Response(JSON.stringify({ error: errorMessage }), {
3678
3731
  status: 500,
3679
3732
  headers: {
3680
3733
  [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION
package/cloudflare.mjs CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  SDK_TELEMETRY,
3
3
  serveBase,
4
4
  serveManyBase
5
- } from "./chunk-NQDNC5P4.mjs";
5
+ } from "./chunk-BON2RKOR.mjs";
6
6
 
7
7
  // platforms/cloudflare.ts
8
8
  var getArgs = (args) => {
package/express.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as express_serve_static_core from 'express-serve-static-core';
2
- import { R as RouteFunction, W as WorkflowServeOptions, y as InvokableWorkflow } from './types-Q3dM0UlR.mjs';
2
+ import { R as RouteFunction, W as WorkflowServeOptions, z as InvokableWorkflow } from './types-9nCq6bRP.mjs';
3
3
  import { Router } from 'express';
4
- import { s as serveManyBase } from './serve-many-BNusWYgt.mjs';
4
+ import { s as serveManyBase } from './serve-many-CctdYIfB.mjs';
5
5
  import '@upstash/qstash';
6
6
  import 'zod';
7
7
  import 'ai';
package/express.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as express_serve_static_core from 'express-serve-static-core';
2
- import { R as RouteFunction, W as WorkflowServeOptions, y as InvokableWorkflow } from './types-Q3dM0UlR.js';
2
+ import { R as RouteFunction, W as WorkflowServeOptions, z as InvokableWorkflow } from './types-9nCq6bRP.js';
3
3
  import { Router } from 'express';
4
- import { s as serveManyBase } from './serve-many-CXqQP3RI.js';
4
+ import { s as serveManyBase } from './serve-many-BXDr30rl.js';
5
5
  import '@upstash/qstash';
6
6
  import 'zod';
7
7
  import 'ai';