@upstash/workflow 1.3.0 → 1.3.2-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.
- package/astro.d.mts +2 -2
- package/astro.d.ts +2 -2
- package/astro.js +81 -14
- package/astro.mjs +1 -1
- package/{chunk-G24J5PCC.mjs → chunk-ICDNN4UW.mjs} +84 -14
- package/cloudflare.d.mts +2 -2
- package/cloudflare.d.ts +2 -2
- package/cloudflare.js +81 -14
- package/cloudflare.mjs +1 -1
- package/express.d.mts +2 -2
- package/express.d.ts +2 -2
- package/express.js +81 -14
- package/express.mjs +1 -1
- package/h3.d.mts +2 -2
- package/h3.d.ts +2 -2
- package/h3.js +81 -14
- package/h3.mjs +1 -1
- package/hono.d.mts +2 -2
- package/hono.d.ts +2 -2
- package/hono.js +81 -14
- package/hono.mjs +1 -1
- package/index.d.mts +43 -7
- package/index.d.ts +43 -7
- package/index.js +84 -15
- package/index.mjs +8 -3
- package/nextjs.d.mts +2 -2
- package/nextjs.d.ts +2 -2
- package/nextjs.js +81 -14
- package/nextjs.mjs +1 -1
- package/package.json +1 -1
- package/react-router.d.mts +2 -2
- package/react-router.d.ts +2 -2
- package/react-router.js +81 -14
- package/react-router.mjs +1 -1
- package/{serve-many-D3D9uE4u.d.mts → serve-many-CG3BFvO3.d.mts} +1 -1
- package/{serve-many-kPOasiyb.d.ts → serve-many-iJF1IUXk.d.ts} +1 -1
- package/solidjs.d.mts +1 -1
- package/solidjs.d.ts +1 -1
- package/solidjs.js +81 -14
- package/solidjs.mjs +1 -1
- package/svelte.d.mts +2 -2
- package/svelte.d.ts +2 -2
- package/svelte.js +81 -14
- package/svelte.mjs +1 -1
- package/tanstack.d.mts +2 -2
- package/tanstack.d.ts +2 -2
- package/tanstack.js +81 -14
- package/tanstack.mjs +1 -1
- package/{types-B_E1VAK6.d.ts → types-CekOpKvz.d.mts} +14 -6
- package/{types-B_E1VAK6.d.mts → types-CekOpKvz.d.ts} +14 -6
package/astro.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { APIContext, APIRoute } from 'astro';
|
|
2
|
-
import { u as WorkflowContext, d as WorkflowServeOptions, I as InvokableWorkflow } from './types-
|
|
3
|
-
import { s as serveManyBase } from './serve-many-
|
|
2
|
+
import { u as WorkflowContext, d as WorkflowServeOptions, I as InvokableWorkflow } from './types-CekOpKvz.mjs';
|
|
3
|
+
import { s as serveManyBase } from './serve-many-CG3BFvO3.mjs';
|
|
4
4
|
import '@upstash/qstash';
|
|
5
5
|
import 'zod';
|
|
6
6
|
|
package/astro.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { APIContext, APIRoute } from 'astro';
|
|
2
|
-
import { u as WorkflowContext, d as WorkflowServeOptions, I as InvokableWorkflow } from './types-
|
|
3
|
-
import { s as serveManyBase } from './serve-many-
|
|
2
|
+
import { u as WorkflowContext, d as WorkflowServeOptions, I as InvokableWorkflow } from './types-CekOpKvz.js';
|
|
3
|
+
import { s as serveManyBase } from './serve-many-iJF1IUXk.js';
|
|
4
4
|
import '@upstash/qstash';
|
|
5
5
|
import 'zod';
|
|
6
6
|
|
package/astro.js
CHANGED
|
@@ -103,6 +103,22 @@ var formatWorkflowError = (error) => {
|
|
|
103
103
|
message: `An error occured while executing workflow: '${typeof error === "string" ? error : JSON.stringify(error)}'`
|
|
104
104
|
};
|
|
105
105
|
};
|
|
106
|
+
var attachStepNameToError = (error, stepName) => {
|
|
107
|
+
if (typeof error !== "object" || error === null) return;
|
|
108
|
+
if ("errorStepName" in error) return;
|
|
109
|
+
if (!Object.isExtensible(error)) return;
|
|
110
|
+
try {
|
|
111
|
+
error.errorStepName = stepName;
|
|
112
|
+
} catch {
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
var getStepNameFromError = (error) => {
|
|
116
|
+
if (typeof error === "object" && error !== null) {
|
|
117
|
+
const stepName = error.errorStepName;
|
|
118
|
+
return typeof stepName === "string" ? stepName : void 0;
|
|
119
|
+
}
|
|
120
|
+
return void 0;
|
|
121
|
+
};
|
|
106
122
|
function getConstructorName(obj) {
|
|
107
123
|
if (obj === null || obj === void 0) {
|
|
108
124
|
return null;
|
|
@@ -196,12 +212,13 @@ var WORKFLOW_RETRIED_HEADER = "Upstash-Retried";
|
|
|
196
212
|
var WORKFLOW_LABEL_HEADER = "Upstash-Label";
|
|
197
213
|
var WORKFLOW_UNKOWN_SDK_VERSION_HEADER = "Upstash-Workflow-Unknown-Sdk";
|
|
198
214
|
var WORKFLOW_UNKOWN_SDK_TRIGGER_HEADER = "upstash-workflow-trigger-by-sdk";
|
|
215
|
+
var WORKFLOW_ERROR_STEP_NAME_HEADER = "Upstash-Error-Step-Name";
|
|
199
216
|
var WORKFLOW_PROTOCOL_VERSION = "1";
|
|
200
217
|
var WORKFLOW_PROTOCOL_VERSION_HEADER = "Upstash-Workflow-Sdk-Version";
|
|
201
218
|
var DEFAULT_CONTENT_TYPE = "application/json";
|
|
202
219
|
var NO_CONCURRENCY = 1;
|
|
203
220
|
var DEFAULT_RETRIES = 3;
|
|
204
|
-
var VERSION = "v1.2
|
|
221
|
+
var VERSION = "v1.3.2";
|
|
205
222
|
var SDK_TELEMETRY = `@upstash/workflow@${VERSION}`;
|
|
206
223
|
var TELEMETRY_HEADER_SDK = "Upstash-Telemetry-Sdk";
|
|
207
224
|
var TELEMETRY_HEADER_FRAMEWORK = "Upstash-Telemetry-Framework";
|
|
@@ -216,6 +233,31 @@ var import_qstash4 = require("@upstash/qstash");
|
|
|
216
233
|
// src/utils.ts
|
|
217
234
|
var NANOID_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
|
|
218
235
|
var NANOID_LENGTH = 21;
|
|
236
|
+
var RESOURCE_NAME_PATTERN = /^[a-zA-Z0-9\-_.]+$/;
|
|
237
|
+
function validateLabel(label) {
|
|
238
|
+
if (label === void 0) return;
|
|
239
|
+
const labels = Array.isArray(label) ? label : [label];
|
|
240
|
+
if (labels.length === 0) {
|
|
241
|
+
throw new WorkflowNonRetryableError("Invalid label: label array must not be empty.");
|
|
242
|
+
}
|
|
243
|
+
for (const value of labels) {
|
|
244
|
+
if (!RESOURCE_NAME_PATTERN.test(value)) {
|
|
245
|
+
throw new WorkflowNonRetryableError(
|
|
246
|
+
`Invalid label "${value}": must be alphanumeric, hyphen, underscore, or period.`
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
function serializeLabel(label) {
|
|
252
|
+
return Array.isArray(label) ? label.join(",") : label;
|
|
253
|
+
}
|
|
254
|
+
function validateFlowControl(flowControl) {
|
|
255
|
+
if (flowControl?.key !== void 0 && !RESOURCE_NAME_PATTERN.test(flowControl.key)) {
|
|
256
|
+
throw new WorkflowNonRetryableError(
|
|
257
|
+
`Invalid flow control key "${flowControl.key}": must be alphanumeric, hyphen, underscore, or period.`
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
219
261
|
function getRandomInt() {
|
|
220
262
|
return Math.floor(Math.random() * NANOID_CHARS.length);
|
|
221
263
|
}
|
|
@@ -751,8 +793,8 @@ var triggerFirstInvocation = async (params) => {
|
|
|
751
793
|
if (unknownSdk) {
|
|
752
794
|
headers[WORKFLOW_UNKOWN_SDK_TRIGGER_HEADER] = "true";
|
|
753
795
|
}
|
|
754
|
-
if (workflowContext.
|
|
755
|
-
headers[WORKFLOW_LABEL_HEADER] = workflowContext.
|
|
796
|
+
if (workflowContext.labels.length > 0) {
|
|
797
|
+
headers[WORKFLOW_LABEL_HEADER] = serializeLabel(workflowContext.labels);
|
|
756
798
|
}
|
|
757
799
|
const body = typeof workflowContext.requestPayload === "string" ? workflowContext.requestPayload : JSON.stringify(workflowContext.requestPayload);
|
|
758
800
|
return {
|
|
@@ -1554,8 +1596,9 @@ var LazyInvokeStep = class extends BaseLazyStep {
|
|
|
1554
1596
|
});
|
|
1555
1597
|
triggerHeaders["Upstash-Workflow-Invoke"] = "true";
|
|
1556
1598
|
if (label) {
|
|
1557
|
-
|
|
1558
|
-
triggerHeaders[
|
|
1599
|
+
const labelHeader = serializeLabel(label);
|
|
1600
|
+
triggerHeaders[WORKFLOW_LABEL_HEADER] = labelHeader;
|
|
1601
|
+
triggerHeaders[`upstash-forward-${WORKFLOW_LABEL_HEADER}`] = labelHeader;
|
|
1559
1602
|
}
|
|
1560
1603
|
return { headers: triggerHeaders, contentType };
|
|
1561
1604
|
}
|
|
@@ -1898,7 +1941,13 @@ var submitSingleStep = async ({
|
|
|
1898
1941
|
await dispatchLifecycle("beforeExecution", {
|
|
1899
1942
|
stepName: lazyStep.stepName
|
|
1900
1943
|
});
|
|
1901
|
-
|
|
1944
|
+
let resultStep;
|
|
1945
|
+
try {
|
|
1946
|
+
resultStep = await lazyStep.getResultStep(concurrency, stepId);
|
|
1947
|
+
} catch (error) {
|
|
1948
|
+
attachStepNameToError(error, lazyStep.stepName);
|
|
1949
|
+
throw error;
|
|
1950
|
+
}
|
|
1902
1951
|
const { headers } = lazyStep.getHeaders({
|
|
1903
1952
|
context,
|
|
1904
1953
|
step: resultStep,
|
|
@@ -2121,9 +2170,11 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
2121
2170
|
if (isInstanceOf(error, WorkflowAbort) || isInstanceOf(error, import_qstash5.QstashError) && error.status === 400 || isInstanceOf(error, import_qstash5.QstashError) && error.status === 412) {
|
|
2122
2171
|
throw error;
|
|
2123
2172
|
}
|
|
2124
|
-
|
|
2173
|
+
const wrappedError = new WorkflowError(
|
|
2125
2174
|
`Error submitting steps to QStash in partial parallel step execution: ${error}`
|
|
2126
2175
|
);
|
|
2176
|
+
attachStepNameToError(wrappedError, parallelSteps[stepIndex].stepName);
|
|
2177
|
+
throw wrappedError;
|
|
2127
2178
|
}
|
|
2128
2179
|
break;
|
|
2129
2180
|
}
|
|
@@ -2696,9 +2747,10 @@ var WorkflowContext = class {
|
|
|
2696
2747
|
*/
|
|
2697
2748
|
env;
|
|
2698
2749
|
/**
|
|
2699
|
-
*
|
|
2750
|
+
* Labels attached to the workflow run.
|
|
2700
2751
|
*
|
|
2701
|
-
* Can be used to filter the workflow run logs.
|
|
2752
|
+
* Can be used to filter the workflow run logs. A run can have multiple
|
|
2753
|
+
* labels when triggered with `label: string[]`.
|
|
2702
2754
|
*
|
|
2703
2755
|
* Can be set by passing a `label` parameter when triggering the workflow
|
|
2704
2756
|
* with `client.trigger`:
|
|
@@ -2706,11 +2758,20 @@ var WorkflowContext = class {
|
|
|
2706
2758
|
* ```ts
|
|
2707
2759
|
* await client.trigger({
|
|
2708
2760
|
* url: "https://workflow-endpoint.com",
|
|
2709
|
-
* label: "
|
|
2761
|
+
* label: ["label-1", "label-2"]
|
|
2710
2762
|
* });
|
|
2711
2763
|
* ```
|
|
2712
2764
|
*/
|
|
2713
|
-
|
|
2765
|
+
labels;
|
|
2766
|
+
/**
|
|
2767
|
+
* Label of the workflow run.
|
|
2768
|
+
*
|
|
2769
|
+
* @deprecated Use `labels` instead. When a run has multiple labels, this
|
|
2770
|
+
* only returns the first one.
|
|
2771
|
+
*/
|
|
2772
|
+
get label() {
|
|
2773
|
+
return this.labels[0];
|
|
2774
|
+
}
|
|
2714
2775
|
/**
|
|
2715
2776
|
* Number of times QStash has retried delivering the current request.
|
|
2716
2777
|
*
|
|
@@ -2741,7 +2802,7 @@ var WorkflowContext = class {
|
|
|
2741
2802
|
this.headers = headers;
|
|
2742
2803
|
this.requestPayload = initialPayload;
|
|
2743
2804
|
this.env = env ?? {};
|
|
2744
|
-
this.
|
|
2805
|
+
this.labels = label === void 0 ? [] : Array.isArray(label) ? label : label ? label.split(",") : [];
|
|
2745
2806
|
this.retried = retried ?? 0;
|
|
2746
2807
|
const middlewareManagerInstance = middlewareManager ?? new MiddlewareManager([]);
|
|
2747
2808
|
middlewareManagerInstance.assignContext(this);
|
|
@@ -2822,8 +2883,10 @@ var WorkflowContext = class {
|
|
|
2822
2883
|
await this.addStep(new LazySleepUntilStep(this, stepName, time));
|
|
2823
2884
|
}
|
|
2824
2885
|
async call(stepName, settings) {
|
|
2886
|
+
validateFlowControl(settings.flowControl);
|
|
2825
2887
|
let callStep;
|
|
2826
2888
|
if ("workflow" in settings) {
|
|
2889
|
+
validateLabel(settings.label);
|
|
2827
2890
|
const url = getNewUrlFromWorkflowId(this.url, settings.workflow.workflowId);
|
|
2828
2891
|
const stringBody = typeof settings.body === "string" ? settings.body : settings.body === void 0 ? void 0 : JSON.stringify(settings.body);
|
|
2829
2892
|
callStep = new LazyCallStep({
|
|
@@ -2931,6 +2994,8 @@ var WorkflowContext = class {
|
|
|
2931
2994
|
);
|
|
2932
2995
|
}
|
|
2933
2996
|
async invoke(stepName, settings) {
|
|
2997
|
+
validateLabel(settings.label);
|
|
2998
|
+
validateFlowControl(settings.flowControl);
|
|
2934
2999
|
return await this.addStep(
|
|
2935
3000
|
new LazyInvokeStep(this, stepName, settings)
|
|
2936
3001
|
);
|
|
@@ -3016,7 +3081,7 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
|
|
|
3016
3081
|
url: context.url,
|
|
3017
3082
|
initialPayload: context.requestPayload,
|
|
3018
3083
|
env: context.env,
|
|
3019
|
-
label: context.
|
|
3084
|
+
label: context.labels,
|
|
3020
3085
|
retried: context.retried
|
|
3021
3086
|
});
|
|
3022
3087
|
try {
|
|
@@ -3854,10 +3919,12 @@ var serveBase = (routeFunction, telemetry2, options, internalOptions) => {
|
|
|
3854
3919
|
await middlewareManager.dispatchDebug("onError", {
|
|
3855
3920
|
error: isInstanceOf(error, Error) ? error : new Error(formattedError.message)
|
|
3856
3921
|
});
|
|
3922
|
+
const stepName = getStepNameFromError(error)?.replace(/[\u0000-\u001F\u007F]+/g, " ").trim();
|
|
3857
3923
|
return new Response(JSON.stringify(formattedError), {
|
|
3858
3924
|
status: 500,
|
|
3859
3925
|
headers: {
|
|
3860
|
-
[WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION
|
|
3926
|
+
[WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION,
|
|
3927
|
+
...stepName ? { [WORKFLOW_ERROR_STEP_NAME_HEADER]: stepName } : {}
|
|
3861
3928
|
}
|
|
3862
3929
|
});
|
|
3863
3930
|
}
|
package/astro.mjs
CHANGED
|
@@ -72,6 +72,22 @@ var formatWorkflowError = (error) => {
|
|
|
72
72
|
message: `An error occured while executing workflow: '${typeof error === "string" ? error : JSON.stringify(error)}'`
|
|
73
73
|
};
|
|
74
74
|
};
|
|
75
|
+
var attachStepNameToError = (error, stepName) => {
|
|
76
|
+
if (typeof error !== "object" || error === null) return;
|
|
77
|
+
if ("errorStepName" in error) return;
|
|
78
|
+
if (!Object.isExtensible(error)) return;
|
|
79
|
+
try {
|
|
80
|
+
error.errorStepName = stepName;
|
|
81
|
+
} catch {
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
var getStepNameFromError = (error) => {
|
|
85
|
+
if (typeof error === "object" && error !== null) {
|
|
86
|
+
const stepName = error.errorStepName;
|
|
87
|
+
return typeof stepName === "string" ? stepName : void 0;
|
|
88
|
+
}
|
|
89
|
+
return void 0;
|
|
90
|
+
};
|
|
75
91
|
function getConstructorName(obj) {
|
|
76
92
|
if (obj === null || obj === void 0) {
|
|
77
93
|
return null;
|
|
@@ -107,12 +123,13 @@ var WORKFLOW_RETRIED_HEADER = "Upstash-Retried";
|
|
|
107
123
|
var WORKFLOW_LABEL_HEADER = "Upstash-Label";
|
|
108
124
|
var WORKFLOW_UNKOWN_SDK_VERSION_HEADER = "Upstash-Workflow-Unknown-Sdk";
|
|
109
125
|
var WORKFLOW_UNKOWN_SDK_TRIGGER_HEADER = "upstash-workflow-trigger-by-sdk";
|
|
126
|
+
var WORKFLOW_ERROR_STEP_NAME_HEADER = "Upstash-Error-Step-Name";
|
|
110
127
|
var WORKFLOW_PROTOCOL_VERSION = "1";
|
|
111
128
|
var WORKFLOW_PROTOCOL_VERSION_HEADER = "Upstash-Workflow-Sdk-Version";
|
|
112
129
|
var DEFAULT_CONTENT_TYPE = "application/json";
|
|
113
130
|
var NO_CONCURRENCY = 1;
|
|
114
131
|
var DEFAULT_RETRIES = 3;
|
|
115
|
-
var VERSION = "v1.2
|
|
132
|
+
var VERSION = "v1.3.2";
|
|
116
133
|
var SDK_TELEMETRY = `@upstash/workflow@${VERSION}`;
|
|
117
134
|
var TELEMETRY_HEADER_SDK = "Upstash-Telemetry-Sdk";
|
|
118
135
|
var TELEMETRY_HEADER_FRAMEWORK = "Upstash-Telemetry-Framework";
|
|
@@ -342,6 +359,31 @@ function buildBulkActionQueryParameters(request, options) {
|
|
|
342
359
|
// src/utils.ts
|
|
343
360
|
var NANOID_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
|
|
344
361
|
var NANOID_LENGTH = 21;
|
|
362
|
+
var RESOURCE_NAME_PATTERN = /^[a-zA-Z0-9\-_.]+$/;
|
|
363
|
+
function validateLabel(label) {
|
|
364
|
+
if (label === void 0) return;
|
|
365
|
+
const labels = Array.isArray(label) ? label : [label];
|
|
366
|
+
if (labels.length === 0) {
|
|
367
|
+
throw new WorkflowNonRetryableError("Invalid label: label array must not be empty.");
|
|
368
|
+
}
|
|
369
|
+
for (const value of labels) {
|
|
370
|
+
if (!RESOURCE_NAME_PATTERN.test(value)) {
|
|
371
|
+
throw new WorkflowNonRetryableError(
|
|
372
|
+
`Invalid label "${value}": must be alphanumeric, hyphen, underscore, or period.`
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
function serializeLabel(label) {
|
|
378
|
+
return Array.isArray(label) ? label.join(",") : label;
|
|
379
|
+
}
|
|
380
|
+
function validateFlowControl(flowControl) {
|
|
381
|
+
if (flowControl?.key !== void 0 && !RESOURCE_NAME_PATTERN.test(flowControl.key)) {
|
|
382
|
+
throw new WorkflowNonRetryableError(
|
|
383
|
+
`Invalid flow control key "${flowControl.key}": must be alphanumeric, hyphen, underscore, or period.`
|
|
384
|
+
);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
345
387
|
function getRandomInt() {
|
|
346
388
|
return Math.floor(Math.random() * NANOID_CHARS.length);
|
|
347
389
|
}
|
|
@@ -863,8 +905,8 @@ var triggerFirstInvocation = async (params) => {
|
|
|
863
905
|
if (unknownSdk) {
|
|
864
906
|
headers[WORKFLOW_UNKOWN_SDK_TRIGGER_HEADER] = "true";
|
|
865
907
|
}
|
|
866
|
-
if (workflowContext.
|
|
867
|
-
headers[WORKFLOW_LABEL_HEADER] = workflowContext.
|
|
908
|
+
if (workflowContext.labels.length > 0) {
|
|
909
|
+
headers[WORKFLOW_LABEL_HEADER] = serializeLabel(workflowContext.labels);
|
|
868
910
|
}
|
|
869
911
|
const body = typeof workflowContext.requestPayload === "string" ? workflowContext.requestPayload : JSON.stringify(workflowContext.requestPayload);
|
|
870
912
|
return {
|
|
@@ -1666,8 +1708,9 @@ var LazyInvokeStep = class extends BaseLazyStep {
|
|
|
1666
1708
|
});
|
|
1667
1709
|
triggerHeaders["Upstash-Workflow-Invoke"] = "true";
|
|
1668
1710
|
if (label) {
|
|
1669
|
-
|
|
1670
|
-
triggerHeaders[
|
|
1711
|
+
const labelHeader = serializeLabel(label);
|
|
1712
|
+
triggerHeaders[WORKFLOW_LABEL_HEADER] = labelHeader;
|
|
1713
|
+
triggerHeaders[`upstash-forward-${WORKFLOW_LABEL_HEADER}`] = labelHeader;
|
|
1671
1714
|
}
|
|
1672
1715
|
return { headers: triggerHeaders, contentType };
|
|
1673
1716
|
}
|
|
@@ -2010,7 +2053,13 @@ var submitSingleStep = async ({
|
|
|
2010
2053
|
await dispatchLifecycle("beforeExecution", {
|
|
2011
2054
|
stepName: lazyStep.stepName
|
|
2012
2055
|
});
|
|
2013
|
-
|
|
2056
|
+
let resultStep;
|
|
2057
|
+
try {
|
|
2058
|
+
resultStep = await lazyStep.getResultStep(concurrency, stepId);
|
|
2059
|
+
} catch (error) {
|
|
2060
|
+
attachStepNameToError(error, lazyStep.stepName);
|
|
2061
|
+
throw error;
|
|
2062
|
+
}
|
|
2014
2063
|
const { headers } = lazyStep.getHeaders({
|
|
2015
2064
|
context,
|
|
2016
2065
|
step: resultStep,
|
|
@@ -2233,9 +2282,11 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
2233
2282
|
if (isInstanceOf(error, WorkflowAbort) || isInstanceOf(error, QstashError5) && error.status === 400 || isInstanceOf(error, QstashError5) && error.status === 412) {
|
|
2234
2283
|
throw error;
|
|
2235
2284
|
}
|
|
2236
|
-
|
|
2285
|
+
const wrappedError = new WorkflowError(
|
|
2237
2286
|
`Error submitting steps to QStash in partial parallel step execution: ${error}`
|
|
2238
2287
|
);
|
|
2288
|
+
attachStepNameToError(wrappedError, parallelSteps[stepIndex].stepName);
|
|
2289
|
+
throw wrappedError;
|
|
2239
2290
|
}
|
|
2240
2291
|
break;
|
|
2241
2292
|
}
|
|
@@ -2733,9 +2784,10 @@ var WorkflowContext = class {
|
|
|
2733
2784
|
*/
|
|
2734
2785
|
env;
|
|
2735
2786
|
/**
|
|
2736
|
-
*
|
|
2787
|
+
* Labels attached to the workflow run.
|
|
2737
2788
|
*
|
|
2738
|
-
* Can be used to filter the workflow run logs.
|
|
2789
|
+
* Can be used to filter the workflow run logs. A run can have multiple
|
|
2790
|
+
* labels when triggered with `label: string[]`.
|
|
2739
2791
|
*
|
|
2740
2792
|
* Can be set by passing a `label` parameter when triggering the workflow
|
|
2741
2793
|
* with `client.trigger`:
|
|
@@ -2743,11 +2795,20 @@ var WorkflowContext = class {
|
|
|
2743
2795
|
* ```ts
|
|
2744
2796
|
* await client.trigger({
|
|
2745
2797
|
* url: "https://workflow-endpoint.com",
|
|
2746
|
-
* label: "
|
|
2798
|
+
* label: ["label-1", "label-2"]
|
|
2747
2799
|
* });
|
|
2748
2800
|
* ```
|
|
2749
2801
|
*/
|
|
2750
|
-
|
|
2802
|
+
labels;
|
|
2803
|
+
/**
|
|
2804
|
+
* Label of the workflow run.
|
|
2805
|
+
*
|
|
2806
|
+
* @deprecated Use `labels` instead. When a run has multiple labels, this
|
|
2807
|
+
* only returns the first one.
|
|
2808
|
+
*/
|
|
2809
|
+
get label() {
|
|
2810
|
+
return this.labels[0];
|
|
2811
|
+
}
|
|
2751
2812
|
/**
|
|
2752
2813
|
* Number of times QStash has retried delivering the current request.
|
|
2753
2814
|
*
|
|
@@ -2778,7 +2839,7 @@ var WorkflowContext = class {
|
|
|
2778
2839
|
this.headers = headers;
|
|
2779
2840
|
this.requestPayload = initialPayload;
|
|
2780
2841
|
this.env = env ?? {};
|
|
2781
|
-
this.
|
|
2842
|
+
this.labels = label === void 0 ? [] : Array.isArray(label) ? label : label ? label.split(",") : [];
|
|
2782
2843
|
this.retried = retried ?? 0;
|
|
2783
2844
|
const middlewareManagerInstance = middlewareManager ?? new MiddlewareManager([]);
|
|
2784
2845
|
middlewareManagerInstance.assignContext(this);
|
|
@@ -2859,8 +2920,10 @@ var WorkflowContext = class {
|
|
|
2859
2920
|
await this.addStep(new LazySleepUntilStep(this, stepName, time));
|
|
2860
2921
|
}
|
|
2861
2922
|
async call(stepName, settings) {
|
|
2923
|
+
validateFlowControl(settings.flowControl);
|
|
2862
2924
|
let callStep;
|
|
2863
2925
|
if ("workflow" in settings) {
|
|
2926
|
+
validateLabel(settings.label);
|
|
2864
2927
|
const url = getNewUrlFromWorkflowId(this.url, settings.workflow.workflowId);
|
|
2865
2928
|
const stringBody = typeof settings.body === "string" ? settings.body : settings.body === void 0 ? void 0 : JSON.stringify(settings.body);
|
|
2866
2929
|
callStep = new LazyCallStep({
|
|
@@ -2968,6 +3031,8 @@ var WorkflowContext = class {
|
|
|
2968
3031
|
);
|
|
2969
3032
|
}
|
|
2970
3033
|
async invoke(stepName, settings) {
|
|
3034
|
+
validateLabel(settings.label);
|
|
3035
|
+
validateFlowControl(settings.flowControl);
|
|
2971
3036
|
return await this.addStep(
|
|
2972
3037
|
new LazyInvokeStep(this, stepName, settings)
|
|
2973
3038
|
);
|
|
@@ -3127,7 +3192,7 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
|
|
|
3127
3192
|
url: context.url,
|
|
3128
3193
|
initialPayload: context.requestPayload,
|
|
3129
3194
|
env: context.env,
|
|
3130
|
-
label: context.
|
|
3195
|
+
label: context.labels,
|
|
3131
3196
|
retried: context.retried
|
|
3132
3197
|
});
|
|
3133
3198
|
try {
|
|
@@ -3891,10 +3956,12 @@ var serveBase = (routeFunction, telemetry, options, internalOptions) => {
|
|
|
3891
3956
|
await middlewareManager.dispatchDebug("onError", {
|
|
3892
3957
|
error: isInstanceOf(error, Error) ? error : new Error(formattedError.message)
|
|
3893
3958
|
});
|
|
3959
|
+
const stepName = getStepNameFromError(error)?.replace(/[\u0000-\u001F\u007F]+/g, " ").trim();
|
|
3894
3960
|
return new Response(JSON.stringify(formattedError), {
|
|
3895
3961
|
status: 500,
|
|
3896
3962
|
headers: {
|
|
3897
|
-
[WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION
|
|
3963
|
+
[WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION,
|
|
3964
|
+
...stepName ? { [WORKFLOW_ERROR_STEP_NAME_HEADER]: stepName } : {}
|
|
3898
3965
|
}
|
|
3899
3966
|
});
|
|
3900
3967
|
}
|
|
@@ -3923,6 +3990,9 @@ export {
|
|
|
3923
3990
|
buildBulkActionQueryParameters,
|
|
3924
3991
|
WORKFLOW_LABEL_HEADER,
|
|
3925
3992
|
SDK_TELEMETRY,
|
|
3993
|
+
validateLabel,
|
|
3994
|
+
serializeLabel,
|
|
3995
|
+
validateFlowControl,
|
|
3926
3996
|
getWorkflowRunId,
|
|
3927
3997
|
StepTypes,
|
|
3928
3998
|
triggerFirstInvocation,
|
package/cloudflare.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { c as RouteFunction, d as WorkflowServeOptions, I as InvokableWorkflow } from './types-
|
|
2
|
-
import { s as serveManyBase } from './serve-many-
|
|
1
|
+
import { c as RouteFunction, d as WorkflowServeOptions, I as InvokableWorkflow } from './types-CekOpKvz.mjs';
|
|
2
|
+
import { s as serveManyBase } from './serve-many-CG3BFvO3.mjs';
|
|
3
3
|
import '@upstash/qstash';
|
|
4
4
|
import 'zod';
|
|
5
5
|
|
package/cloudflare.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { c as RouteFunction, d as WorkflowServeOptions, I as InvokableWorkflow } from './types-
|
|
2
|
-
import { s as serveManyBase } from './serve-many-
|
|
1
|
+
import { c as RouteFunction, d as WorkflowServeOptions, I as InvokableWorkflow } from './types-CekOpKvz.js';
|
|
2
|
+
import { s as serveManyBase } from './serve-many-iJF1IUXk.js';
|
|
3
3
|
import '@upstash/qstash';
|
|
4
4
|
import 'zod';
|
|
5
5
|
|
package/cloudflare.js
CHANGED
|
@@ -39,12 +39,13 @@ var WORKFLOW_RETRIED_HEADER = "Upstash-Retried";
|
|
|
39
39
|
var WORKFLOW_LABEL_HEADER = "Upstash-Label";
|
|
40
40
|
var WORKFLOW_UNKOWN_SDK_VERSION_HEADER = "Upstash-Workflow-Unknown-Sdk";
|
|
41
41
|
var WORKFLOW_UNKOWN_SDK_TRIGGER_HEADER = "upstash-workflow-trigger-by-sdk";
|
|
42
|
+
var WORKFLOW_ERROR_STEP_NAME_HEADER = "Upstash-Error-Step-Name";
|
|
42
43
|
var WORKFLOW_PROTOCOL_VERSION = "1";
|
|
43
44
|
var WORKFLOW_PROTOCOL_VERSION_HEADER = "Upstash-Workflow-Sdk-Version";
|
|
44
45
|
var DEFAULT_CONTENT_TYPE = "application/json";
|
|
45
46
|
var NO_CONCURRENCY = 1;
|
|
46
47
|
var DEFAULT_RETRIES = 3;
|
|
47
|
-
var VERSION = "v1.2
|
|
48
|
+
var VERSION = "v1.3.2";
|
|
48
49
|
var SDK_TELEMETRY = `@upstash/workflow@${VERSION}`;
|
|
49
50
|
var TELEMETRY_HEADER_SDK = "Upstash-Telemetry-Sdk";
|
|
50
51
|
var TELEMETRY_HEADER_FRAMEWORK = "Upstash-Telemetry-Framework";
|
|
@@ -127,6 +128,22 @@ var formatWorkflowError = (error) => {
|
|
|
127
128
|
message: `An error occured while executing workflow: '${typeof error === "string" ? error : JSON.stringify(error)}'`
|
|
128
129
|
};
|
|
129
130
|
};
|
|
131
|
+
var attachStepNameToError = (error, stepName) => {
|
|
132
|
+
if (typeof error !== "object" || error === null) return;
|
|
133
|
+
if ("errorStepName" in error) return;
|
|
134
|
+
if (!Object.isExtensible(error)) return;
|
|
135
|
+
try {
|
|
136
|
+
error.errorStepName = stepName;
|
|
137
|
+
} catch {
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
var getStepNameFromError = (error) => {
|
|
141
|
+
if (typeof error === "object" && error !== null) {
|
|
142
|
+
const stepName = error.errorStepName;
|
|
143
|
+
return typeof stepName === "string" ? stepName : void 0;
|
|
144
|
+
}
|
|
145
|
+
return void 0;
|
|
146
|
+
};
|
|
130
147
|
function getConstructorName(obj) {
|
|
131
148
|
if (obj === null || obj === void 0) {
|
|
132
149
|
return null;
|
|
@@ -216,6 +233,31 @@ var import_qstash4 = require("@upstash/qstash");
|
|
|
216
233
|
// src/utils.ts
|
|
217
234
|
var NANOID_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
|
|
218
235
|
var NANOID_LENGTH = 21;
|
|
236
|
+
var RESOURCE_NAME_PATTERN = /^[a-zA-Z0-9\-_.]+$/;
|
|
237
|
+
function validateLabel(label) {
|
|
238
|
+
if (label === void 0) return;
|
|
239
|
+
const labels = Array.isArray(label) ? label : [label];
|
|
240
|
+
if (labels.length === 0) {
|
|
241
|
+
throw new WorkflowNonRetryableError("Invalid label: label array must not be empty.");
|
|
242
|
+
}
|
|
243
|
+
for (const value of labels) {
|
|
244
|
+
if (!RESOURCE_NAME_PATTERN.test(value)) {
|
|
245
|
+
throw new WorkflowNonRetryableError(
|
|
246
|
+
`Invalid label "${value}": must be alphanumeric, hyphen, underscore, or period.`
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
function serializeLabel(label) {
|
|
252
|
+
return Array.isArray(label) ? label.join(",") : label;
|
|
253
|
+
}
|
|
254
|
+
function validateFlowControl(flowControl) {
|
|
255
|
+
if (flowControl?.key !== void 0 && !RESOURCE_NAME_PATTERN.test(flowControl.key)) {
|
|
256
|
+
throw new WorkflowNonRetryableError(
|
|
257
|
+
`Invalid flow control key "${flowControl.key}": must be alphanumeric, hyphen, underscore, or period.`
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
219
261
|
function getRandomInt() {
|
|
220
262
|
return Math.floor(Math.random() * NANOID_CHARS.length);
|
|
221
263
|
}
|
|
@@ -751,8 +793,8 @@ var triggerFirstInvocation = async (params) => {
|
|
|
751
793
|
if (unknownSdk) {
|
|
752
794
|
headers[WORKFLOW_UNKOWN_SDK_TRIGGER_HEADER] = "true";
|
|
753
795
|
}
|
|
754
|
-
if (workflowContext.
|
|
755
|
-
headers[WORKFLOW_LABEL_HEADER] = workflowContext.
|
|
796
|
+
if (workflowContext.labels.length > 0) {
|
|
797
|
+
headers[WORKFLOW_LABEL_HEADER] = serializeLabel(workflowContext.labels);
|
|
756
798
|
}
|
|
757
799
|
const body = typeof workflowContext.requestPayload === "string" ? workflowContext.requestPayload : JSON.stringify(workflowContext.requestPayload);
|
|
758
800
|
return {
|
|
@@ -1554,8 +1596,9 @@ var LazyInvokeStep = class extends BaseLazyStep {
|
|
|
1554
1596
|
});
|
|
1555
1597
|
triggerHeaders["Upstash-Workflow-Invoke"] = "true";
|
|
1556
1598
|
if (label) {
|
|
1557
|
-
|
|
1558
|
-
triggerHeaders[
|
|
1599
|
+
const labelHeader = serializeLabel(label);
|
|
1600
|
+
triggerHeaders[WORKFLOW_LABEL_HEADER] = labelHeader;
|
|
1601
|
+
triggerHeaders[`upstash-forward-${WORKFLOW_LABEL_HEADER}`] = labelHeader;
|
|
1559
1602
|
}
|
|
1560
1603
|
return { headers: triggerHeaders, contentType };
|
|
1561
1604
|
}
|
|
@@ -1898,7 +1941,13 @@ var submitSingleStep = async ({
|
|
|
1898
1941
|
await dispatchLifecycle("beforeExecution", {
|
|
1899
1942
|
stepName: lazyStep.stepName
|
|
1900
1943
|
});
|
|
1901
|
-
|
|
1944
|
+
let resultStep;
|
|
1945
|
+
try {
|
|
1946
|
+
resultStep = await lazyStep.getResultStep(concurrency, stepId);
|
|
1947
|
+
} catch (error) {
|
|
1948
|
+
attachStepNameToError(error, lazyStep.stepName);
|
|
1949
|
+
throw error;
|
|
1950
|
+
}
|
|
1902
1951
|
const { headers } = lazyStep.getHeaders({
|
|
1903
1952
|
context,
|
|
1904
1953
|
step: resultStep,
|
|
@@ -2121,9 +2170,11 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
2121
2170
|
if (isInstanceOf(error, WorkflowAbort) || isInstanceOf(error, import_qstash5.QstashError) && error.status === 400 || isInstanceOf(error, import_qstash5.QstashError) && error.status === 412) {
|
|
2122
2171
|
throw error;
|
|
2123
2172
|
}
|
|
2124
|
-
|
|
2173
|
+
const wrappedError = new WorkflowError(
|
|
2125
2174
|
`Error submitting steps to QStash in partial parallel step execution: ${error}`
|
|
2126
2175
|
);
|
|
2176
|
+
attachStepNameToError(wrappedError, parallelSteps[stepIndex].stepName);
|
|
2177
|
+
throw wrappedError;
|
|
2127
2178
|
}
|
|
2128
2179
|
break;
|
|
2129
2180
|
}
|
|
@@ -2696,9 +2747,10 @@ var WorkflowContext = class {
|
|
|
2696
2747
|
*/
|
|
2697
2748
|
env;
|
|
2698
2749
|
/**
|
|
2699
|
-
*
|
|
2750
|
+
* Labels attached to the workflow run.
|
|
2700
2751
|
*
|
|
2701
|
-
* Can be used to filter the workflow run logs.
|
|
2752
|
+
* Can be used to filter the workflow run logs. A run can have multiple
|
|
2753
|
+
* labels when triggered with `label: string[]`.
|
|
2702
2754
|
*
|
|
2703
2755
|
* Can be set by passing a `label` parameter when triggering the workflow
|
|
2704
2756
|
* with `client.trigger`:
|
|
@@ -2706,11 +2758,20 @@ var WorkflowContext = class {
|
|
|
2706
2758
|
* ```ts
|
|
2707
2759
|
* await client.trigger({
|
|
2708
2760
|
* url: "https://workflow-endpoint.com",
|
|
2709
|
-
* label: "
|
|
2761
|
+
* label: ["label-1", "label-2"]
|
|
2710
2762
|
* });
|
|
2711
2763
|
* ```
|
|
2712
2764
|
*/
|
|
2713
|
-
|
|
2765
|
+
labels;
|
|
2766
|
+
/**
|
|
2767
|
+
* Label of the workflow run.
|
|
2768
|
+
*
|
|
2769
|
+
* @deprecated Use `labels` instead. When a run has multiple labels, this
|
|
2770
|
+
* only returns the first one.
|
|
2771
|
+
*/
|
|
2772
|
+
get label() {
|
|
2773
|
+
return this.labels[0];
|
|
2774
|
+
}
|
|
2714
2775
|
/**
|
|
2715
2776
|
* Number of times QStash has retried delivering the current request.
|
|
2716
2777
|
*
|
|
@@ -2741,7 +2802,7 @@ var WorkflowContext = class {
|
|
|
2741
2802
|
this.headers = headers;
|
|
2742
2803
|
this.requestPayload = initialPayload;
|
|
2743
2804
|
this.env = env ?? {};
|
|
2744
|
-
this.
|
|
2805
|
+
this.labels = label === void 0 ? [] : Array.isArray(label) ? label : label ? label.split(",") : [];
|
|
2745
2806
|
this.retried = retried ?? 0;
|
|
2746
2807
|
const middlewareManagerInstance = middlewareManager ?? new MiddlewareManager([]);
|
|
2747
2808
|
middlewareManagerInstance.assignContext(this);
|
|
@@ -2822,8 +2883,10 @@ var WorkflowContext = class {
|
|
|
2822
2883
|
await this.addStep(new LazySleepUntilStep(this, stepName, time));
|
|
2823
2884
|
}
|
|
2824
2885
|
async call(stepName, settings) {
|
|
2886
|
+
validateFlowControl(settings.flowControl);
|
|
2825
2887
|
let callStep;
|
|
2826
2888
|
if ("workflow" in settings) {
|
|
2889
|
+
validateLabel(settings.label);
|
|
2827
2890
|
const url = getNewUrlFromWorkflowId(this.url, settings.workflow.workflowId);
|
|
2828
2891
|
const stringBody = typeof settings.body === "string" ? settings.body : settings.body === void 0 ? void 0 : JSON.stringify(settings.body);
|
|
2829
2892
|
callStep = new LazyCallStep({
|
|
@@ -2931,6 +2994,8 @@ var WorkflowContext = class {
|
|
|
2931
2994
|
);
|
|
2932
2995
|
}
|
|
2933
2996
|
async invoke(stepName, settings) {
|
|
2997
|
+
validateLabel(settings.label);
|
|
2998
|
+
validateFlowControl(settings.flowControl);
|
|
2934
2999
|
return await this.addStep(
|
|
2935
3000
|
new LazyInvokeStep(this, stepName, settings)
|
|
2936
3001
|
);
|
|
@@ -3016,7 +3081,7 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
|
|
|
3016
3081
|
url: context.url,
|
|
3017
3082
|
initialPayload: context.requestPayload,
|
|
3018
3083
|
env: context.env,
|
|
3019
|
-
label: context.
|
|
3084
|
+
label: context.labels,
|
|
3020
3085
|
retried: context.retried
|
|
3021
3086
|
});
|
|
3022
3087
|
try {
|
|
@@ -3854,10 +3919,12 @@ var serveBase = (routeFunction, telemetry2, options, internalOptions) => {
|
|
|
3854
3919
|
await middlewareManager.dispatchDebug("onError", {
|
|
3855
3920
|
error: isInstanceOf(error, Error) ? error : new Error(formattedError.message)
|
|
3856
3921
|
});
|
|
3922
|
+
const stepName = getStepNameFromError(error)?.replace(/[\u0000-\u001F\u007F]+/g, " ").trim();
|
|
3857
3923
|
return new Response(JSON.stringify(formattedError), {
|
|
3858
3924
|
status: 500,
|
|
3859
3925
|
headers: {
|
|
3860
|
-
[WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION
|
|
3926
|
+
[WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION,
|
|
3927
|
+
...stepName ? { [WORKFLOW_ERROR_STEP_NAME_HEADER]: stepName } : {}
|
|
3861
3928
|
}
|
|
3862
3929
|
});
|
|
3863
3930
|
}
|