@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/solidjs.js
CHANGED
|
@@ -101,6 +101,22 @@ var formatWorkflowError = (error) => {
|
|
|
101
101
|
message: `An error occured while executing workflow: '${typeof error === "string" ? error : JSON.stringify(error)}'`
|
|
102
102
|
};
|
|
103
103
|
};
|
|
104
|
+
var attachStepNameToError = (error, stepName) => {
|
|
105
|
+
if (typeof error !== "object" || error === null) return;
|
|
106
|
+
if ("errorStepName" in error) return;
|
|
107
|
+
if (!Object.isExtensible(error)) return;
|
|
108
|
+
try {
|
|
109
|
+
error.errorStepName = stepName;
|
|
110
|
+
} catch {
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
var getStepNameFromError = (error) => {
|
|
114
|
+
if (typeof error === "object" && error !== null) {
|
|
115
|
+
const stepName = error.errorStepName;
|
|
116
|
+
return typeof stepName === "string" ? stepName : void 0;
|
|
117
|
+
}
|
|
118
|
+
return void 0;
|
|
119
|
+
};
|
|
104
120
|
function getConstructorName(obj) {
|
|
105
121
|
if (obj === null || obj === void 0) {
|
|
106
122
|
return null;
|
|
@@ -194,12 +210,13 @@ var WORKFLOW_RETRIED_HEADER = "Upstash-Retried";
|
|
|
194
210
|
var WORKFLOW_LABEL_HEADER = "Upstash-Label";
|
|
195
211
|
var WORKFLOW_UNKOWN_SDK_VERSION_HEADER = "Upstash-Workflow-Unknown-Sdk";
|
|
196
212
|
var WORKFLOW_UNKOWN_SDK_TRIGGER_HEADER = "upstash-workflow-trigger-by-sdk";
|
|
213
|
+
var WORKFLOW_ERROR_STEP_NAME_HEADER = "Upstash-Error-Step-Name";
|
|
197
214
|
var WORKFLOW_PROTOCOL_VERSION = "1";
|
|
198
215
|
var WORKFLOW_PROTOCOL_VERSION_HEADER = "Upstash-Workflow-Sdk-Version";
|
|
199
216
|
var DEFAULT_CONTENT_TYPE = "application/json";
|
|
200
217
|
var NO_CONCURRENCY = 1;
|
|
201
218
|
var DEFAULT_RETRIES = 3;
|
|
202
|
-
var VERSION = "v1.2
|
|
219
|
+
var VERSION = "v1.3.2";
|
|
203
220
|
var SDK_TELEMETRY = `@upstash/workflow@${VERSION}`;
|
|
204
221
|
var TELEMETRY_HEADER_SDK = "Upstash-Telemetry-Sdk";
|
|
205
222
|
var TELEMETRY_HEADER_FRAMEWORK = "Upstash-Telemetry-Framework";
|
|
@@ -214,6 +231,31 @@ var import_qstash4 = require("@upstash/qstash");
|
|
|
214
231
|
// src/utils.ts
|
|
215
232
|
var NANOID_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
|
|
216
233
|
var NANOID_LENGTH = 21;
|
|
234
|
+
var RESOURCE_NAME_PATTERN = /^[a-zA-Z0-9\-_.]+$/;
|
|
235
|
+
function validateLabel(label) {
|
|
236
|
+
if (label === void 0) return;
|
|
237
|
+
const labels = Array.isArray(label) ? label : [label];
|
|
238
|
+
if (labels.length === 0) {
|
|
239
|
+
throw new WorkflowNonRetryableError("Invalid label: label array must not be empty.");
|
|
240
|
+
}
|
|
241
|
+
for (const value of labels) {
|
|
242
|
+
if (!RESOURCE_NAME_PATTERN.test(value)) {
|
|
243
|
+
throw new WorkflowNonRetryableError(
|
|
244
|
+
`Invalid label "${value}": must be alphanumeric, hyphen, underscore, or period.`
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
function serializeLabel(label) {
|
|
250
|
+
return Array.isArray(label) ? label.join(",") : label;
|
|
251
|
+
}
|
|
252
|
+
function validateFlowControl(flowControl) {
|
|
253
|
+
if (flowControl?.key !== void 0 && !RESOURCE_NAME_PATTERN.test(flowControl.key)) {
|
|
254
|
+
throw new WorkflowNonRetryableError(
|
|
255
|
+
`Invalid flow control key "${flowControl.key}": must be alphanumeric, hyphen, underscore, or period.`
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
217
259
|
function getRandomInt() {
|
|
218
260
|
return Math.floor(Math.random() * NANOID_CHARS.length);
|
|
219
261
|
}
|
|
@@ -749,8 +791,8 @@ var triggerFirstInvocation = async (params) => {
|
|
|
749
791
|
if (unknownSdk) {
|
|
750
792
|
headers[WORKFLOW_UNKOWN_SDK_TRIGGER_HEADER] = "true";
|
|
751
793
|
}
|
|
752
|
-
if (workflowContext.
|
|
753
|
-
headers[WORKFLOW_LABEL_HEADER] = workflowContext.
|
|
794
|
+
if (workflowContext.labels.length > 0) {
|
|
795
|
+
headers[WORKFLOW_LABEL_HEADER] = serializeLabel(workflowContext.labels);
|
|
754
796
|
}
|
|
755
797
|
const body = typeof workflowContext.requestPayload === "string" ? workflowContext.requestPayload : JSON.stringify(workflowContext.requestPayload);
|
|
756
798
|
return {
|
|
@@ -1552,8 +1594,9 @@ var LazyInvokeStep = class extends BaseLazyStep {
|
|
|
1552
1594
|
});
|
|
1553
1595
|
triggerHeaders["Upstash-Workflow-Invoke"] = "true";
|
|
1554
1596
|
if (label) {
|
|
1555
|
-
|
|
1556
|
-
triggerHeaders[
|
|
1597
|
+
const labelHeader = serializeLabel(label);
|
|
1598
|
+
triggerHeaders[WORKFLOW_LABEL_HEADER] = labelHeader;
|
|
1599
|
+
triggerHeaders[`upstash-forward-${WORKFLOW_LABEL_HEADER}`] = labelHeader;
|
|
1557
1600
|
}
|
|
1558
1601
|
return { headers: triggerHeaders, contentType };
|
|
1559
1602
|
}
|
|
@@ -1896,7 +1939,13 @@ var submitSingleStep = async ({
|
|
|
1896
1939
|
await dispatchLifecycle("beforeExecution", {
|
|
1897
1940
|
stepName: lazyStep.stepName
|
|
1898
1941
|
});
|
|
1899
|
-
|
|
1942
|
+
let resultStep;
|
|
1943
|
+
try {
|
|
1944
|
+
resultStep = await lazyStep.getResultStep(concurrency, stepId);
|
|
1945
|
+
} catch (error) {
|
|
1946
|
+
attachStepNameToError(error, lazyStep.stepName);
|
|
1947
|
+
throw error;
|
|
1948
|
+
}
|
|
1900
1949
|
const { headers } = lazyStep.getHeaders({
|
|
1901
1950
|
context,
|
|
1902
1951
|
step: resultStep,
|
|
@@ -2119,9 +2168,11 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
2119
2168
|
if (isInstanceOf(error, WorkflowAbort) || isInstanceOf(error, import_qstash5.QstashError) && error.status === 400 || isInstanceOf(error, import_qstash5.QstashError) && error.status === 412) {
|
|
2120
2169
|
throw error;
|
|
2121
2170
|
}
|
|
2122
|
-
|
|
2171
|
+
const wrappedError = new WorkflowError(
|
|
2123
2172
|
`Error submitting steps to QStash in partial parallel step execution: ${error}`
|
|
2124
2173
|
);
|
|
2174
|
+
attachStepNameToError(wrappedError, parallelSteps[stepIndex].stepName);
|
|
2175
|
+
throw wrappedError;
|
|
2125
2176
|
}
|
|
2126
2177
|
break;
|
|
2127
2178
|
}
|
|
@@ -2627,9 +2678,10 @@ var WorkflowContext = class {
|
|
|
2627
2678
|
*/
|
|
2628
2679
|
env;
|
|
2629
2680
|
/**
|
|
2630
|
-
*
|
|
2681
|
+
* Labels attached to the workflow run.
|
|
2631
2682
|
*
|
|
2632
|
-
* Can be used to filter the workflow run logs.
|
|
2683
|
+
* Can be used to filter the workflow run logs. A run can have multiple
|
|
2684
|
+
* labels when triggered with `label: string[]`.
|
|
2633
2685
|
*
|
|
2634
2686
|
* Can be set by passing a `label` parameter when triggering the workflow
|
|
2635
2687
|
* with `client.trigger`:
|
|
@@ -2637,11 +2689,20 @@ var WorkflowContext = class {
|
|
|
2637
2689
|
* ```ts
|
|
2638
2690
|
* await client.trigger({
|
|
2639
2691
|
* url: "https://workflow-endpoint.com",
|
|
2640
|
-
* label: "
|
|
2692
|
+
* label: ["label-1", "label-2"]
|
|
2641
2693
|
* });
|
|
2642
2694
|
* ```
|
|
2643
2695
|
*/
|
|
2644
|
-
|
|
2696
|
+
labels;
|
|
2697
|
+
/**
|
|
2698
|
+
* Label of the workflow run.
|
|
2699
|
+
*
|
|
2700
|
+
* @deprecated Use `labels` instead. When a run has multiple labels, this
|
|
2701
|
+
* only returns the first one.
|
|
2702
|
+
*/
|
|
2703
|
+
get label() {
|
|
2704
|
+
return this.labels[0];
|
|
2705
|
+
}
|
|
2645
2706
|
/**
|
|
2646
2707
|
* Number of times QStash has retried delivering the current request.
|
|
2647
2708
|
*
|
|
@@ -2672,7 +2733,7 @@ var WorkflowContext = class {
|
|
|
2672
2733
|
this.headers = headers;
|
|
2673
2734
|
this.requestPayload = initialPayload;
|
|
2674
2735
|
this.env = env ?? {};
|
|
2675
|
-
this.
|
|
2736
|
+
this.labels = label === void 0 ? [] : Array.isArray(label) ? label : label ? label.split(",") : [];
|
|
2676
2737
|
this.retried = retried ?? 0;
|
|
2677
2738
|
const middlewareManagerInstance = middlewareManager ?? new MiddlewareManager([]);
|
|
2678
2739
|
middlewareManagerInstance.assignContext(this);
|
|
@@ -2753,8 +2814,10 @@ var WorkflowContext = class {
|
|
|
2753
2814
|
await this.addStep(new LazySleepUntilStep(this, stepName, time));
|
|
2754
2815
|
}
|
|
2755
2816
|
async call(stepName, settings) {
|
|
2817
|
+
validateFlowControl(settings.flowControl);
|
|
2756
2818
|
let callStep;
|
|
2757
2819
|
if ("workflow" in settings) {
|
|
2820
|
+
validateLabel(settings.label);
|
|
2758
2821
|
const url = getNewUrlFromWorkflowId(this.url, settings.workflow.workflowId);
|
|
2759
2822
|
const stringBody = typeof settings.body === "string" ? settings.body : settings.body === void 0 ? void 0 : JSON.stringify(settings.body);
|
|
2760
2823
|
callStep = new LazyCallStep({
|
|
@@ -2862,6 +2925,8 @@ var WorkflowContext = class {
|
|
|
2862
2925
|
);
|
|
2863
2926
|
}
|
|
2864
2927
|
async invoke(stepName, settings) {
|
|
2928
|
+
validateLabel(settings.label);
|
|
2929
|
+
validateFlowControl(settings.flowControl);
|
|
2865
2930
|
return await this.addStep(
|
|
2866
2931
|
new LazyInvokeStep(this, stepName, settings)
|
|
2867
2932
|
);
|
|
@@ -2947,7 +3012,7 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
|
|
|
2947
3012
|
url: context.url,
|
|
2948
3013
|
initialPayload: context.requestPayload,
|
|
2949
3014
|
env: context.env,
|
|
2950
|
-
label: context.
|
|
3015
|
+
label: context.labels,
|
|
2951
3016
|
retried: context.retried
|
|
2952
3017
|
});
|
|
2953
3018
|
try {
|
|
@@ -3785,10 +3850,12 @@ var serveBase = (routeFunction, telemetry, options, internalOptions) => {
|
|
|
3785
3850
|
await middlewareManager.dispatchDebug("onError", {
|
|
3786
3851
|
error: isInstanceOf(error, Error) ? error : new Error(formattedError.message)
|
|
3787
3852
|
});
|
|
3853
|
+
const stepName = getStepNameFromError(error)?.replace(/[\u0000-\u001F\u007F]+/g, " ").trim();
|
|
3788
3854
|
return new Response(JSON.stringify(formattedError), {
|
|
3789
3855
|
status: 500,
|
|
3790
3856
|
headers: {
|
|
3791
|
-
[WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION
|
|
3857
|
+
[WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION,
|
|
3858
|
+
...stepName ? { [WORKFLOW_ERROR_STEP_NAME_HEADER]: stepName } : {}
|
|
3792
3859
|
}
|
|
3793
3860
|
});
|
|
3794
3861
|
}
|
package/solidjs.mjs
CHANGED
package/svelte.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as _sveltejs_kit from '@sveltejs/kit';
|
|
2
2
|
import { RequestHandler } from '@sveltejs/kit';
|
|
3
|
-
import { c as RouteFunction, d as WorkflowServeOptions, I as InvokableWorkflow } from './types-
|
|
4
|
-
import { s as serveManyBase } from './serve-many-
|
|
3
|
+
import { c as RouteFunction, d as WorkflowServeOptions, I as InvokableWorkflow } from './types-CekOpKvz.mjs';
|
|
4
|
+
import { s as serveManyBase } from './serve-many-CG3BFvO3.mjs';
|
|
5
5
|
import '@upstash/qstash';
|
|
6
6
|
import 'zod';
|
|
7
7
|
|
package/svelte.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as _sveltejs_kit from '@sveltejs/kit';
|
|
2
2
|
import { RequestHandler } from '@sveltejs/kit';
|
|
3
|
-
import { c as RouteFunction, d as WorkflowServeOptions, I as InvokableWorkflow } from './types-
|
|
4
|
-
import { s as serveManyBase } from './serve-many-
|
|
3
|
+
import { c as RouteFunction, d as WorkflowServeOptions, I as InvokableWorkflow } from './types-CekOpKvz.js';
|
|
4
|
+
import { s as serveManyBase } from './serve-many-iJF1IUXk.js';
|
|
5
5
|
import '@upstash/qstash';
|
|
6
6
|
import 'zod';
|
|
7
7
|
|
package/svelte.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/svelte.mjs
CHANGED
package/tanstack.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { c as RouteFunction, d as WorkflowServeOptions, E as ExclusiveValidationOptions, I as InvokableWorkflow } from './types-
|
|
2
|
-
import { s as serveManyBase } from './serve-many-
|
|
1
|
+
import { c as RouteFunction, d as WorkflowServeOptions, E as ExclusiveValidationOptions, 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/tanstack.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { c as RouteFunction, d as WorkflowServeOptions, E as ExclusiveValidationOptions, I as InvokableWorkflow } from './types-
|
|
2
|
-
import { s as serveManyBase } from './serve-many-
|
|
1
|
+
import { c as RouteFunction, d as WorkflowServeOptions, E as ExclusiveValidationOptions, 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/tanstack.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
|
}
|