@upstash/workflow 0.2.0 → 0.2.2
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 +175 -88
- package/astro.mjs +5 -5
- package/{chunk-5R2BFC3N.mjs → chunk-Z7WS5XIR.mjs} +150 -234
- package/cloudflare.d.mts +2 -2
- package/cloudflare.d.ts +2 -2
- package/cloudflare.js +175 -88
- package/cloudflare.mjs +5 -5
- package/express.d.mts +1 -1
- package/express.d.ts +1 -1
- package/express.js +187 -93
- package/express.mjs +17 -10
- package/h3.d.mts +2 -2
- package/h3.d.ts +2 -2
- package/h3.js +175 -88
- package/h3.mjs +5 -5
- package/hono.d.mts +4 -2
- package/hono.d.ts +4 -2
- package/hono.js +175 -88
- package/hono.mjs +5 -5
- package/index.d.mts +3 -3
- package/index.d.ts +3 -3
- package/index.js +179 -86
- package/index.mjs +189 -3
- package/nextjs.d.mts +3 -3
- package/nextjs.d.ts +3 -3
- package/nextjs.js +179 -92
- package/nextjs.mjs +9 -9
- package/package.json +1 -1
- package/solidjs.d.mts +2 -2
- package/solidjs.d.ts +2 -2
- package/solidjs.js +175 -88
- package/solidjs.mjs +5 -5
- package/svelte.d.mts +3 -3
- package/svelte.d.ts +3 -3
- package/svelte.js +178 -88
- package/svelte.mjs +8 -5
- package/{types-Cki_MHrh.d.mts → types-APRap-aV.d.mts} +12 -2
- package/{types-Cki_MHrh.d.ts → types-APRap-aV.d.ts} +12 -2
|
@@ -71,7 +71,19 @@ var formatWorkflowError = (error) => {
|
|
|
71
71
|
};
|
|
72
72
|
};
|
|
73
73
|
|
|
74
|
+
// src/types.ts
|
|
75
|
+
var StepTypes = [
|
|
76
|
+
"Initial",
|
|
77
|
+
"Run",
|
|
78
|
+
"SleepFor",
|
|
79
|
+
"SleepUntil",
|
|
80
|
+
"Call",
|
|
81
|
+
"Wait",
|
|
82
|
+
"Notify"
|
|
83
|
+
];
|
|
84
|
+
|
|
74
85
|
// src/client/utils.ts
|
|
86
|
+
import { QstashError as QstashError2 } from "@upstash/qstash";
|
|
75
87
|
var makeNotifyRequest = async (requester, eventId, eventData) => {
|
|
76
88
|
const result = await requester.request({
|
|
77
89
|
path: ["v2", "notify", eventId],
|
|
@@ -105,24 +117,28 @@ var getSteps = async (requester, workflowRunId, messageId, debug) => {
|
|
|
105
117
|
await debug?.log("INFO", "ENDPOINT_START", {
|
|
106
118
|
message: `Pulled ${steps.length} steps from QStashand returned them without filtering with messageId.`
|
|
107
119
|
});
|
|
108
|
-
return steps;
|
|
120
|
+
return { steps, workflowRunEnded: false };
|
|
109
121
|
} else {
|
|
110
122
|
const index = steps.findIndex((item) => item.messageId === messageId);
|
|
111
123
|
if (index === -1) {
|
|
112
|
-
return [];
|
|
124
|
+
return { steps: [], workflowRunEnded: false };
|
|
113
125
|
}
|
|
114
126
|
const filteredSteps = steps.slice(0, index + 1);
|
|
115
127
|
await debug?.log("INFO", "ENDPOINT_START", {
|
|
116
128
|
message: `Pulled ${steps.length} steps from QStash and filtered them to ${filteredSteps.length} using messageId.`
|
|
117
129
|
});
|
|
118
|
-
return filteredSteps;
|
|
130
|
+
return { steps: filteredSteps, workflowRunEnded: false };
|
|
119
131
|
}
|
|
120
132
|
} catch (error) {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
133
|
+
if (error instanceof QstashError2 && error.status === 404) {
|
|
134
|
+
await debug?.log("WARN", "ENDPOINT_START", {
|
|
135
|
+
message: "Couldn't fetch workflow run steps. This can happen if the workflow run succesfully ends before some callback is executed.",
|
|
136
|
+
error
|
|
137
|
+
});
|
|
138
|
+
return { steps: void 0, workflowRunEnded: true };
|
|
139
|
+
} else {
|
|
140
|
+
throw error;
|
|
141
|
+
}
|
|
126
142
|
}
|
|
127
143
|
};
|
|
128
144
|
|
|
@@ -131,6 +147,11 @@ var BaseLazyStep = class {
|
|
|
131
147
|
stepName;
|
|
132
148
|
// will be set in the subclasses
|
|
133
149
|
constructor(stepName) {
|
|
150
|
+
if (!stepName) {
|
|
151
|
+
throw new WorkflowError(
|
|
152
|
+
"A workflow step name cannot be undefined or an empty string. Please provide a name for your workflow step."
|
|
153
|
+
);
|
|
154
|
+
}
|
|
134
155
|
this.stepName = stepName;
|
|
135
156
|
}
|
|
136
157
|
};
|
|
@@ -223,15 +244,17 @@ var LazyCallStep = class extends BaseLazyStep {
|
|
|
223
244
|
method;
|
|
224
245
|
body;
|
|
225
246
|
headers;
|
|
226
|
-
stepType = "Call";
|
|
227
247
|
retries;
|
|
228
|
-
|
|
248
|
+
timeout;
|
|
249
|
+
stepType = "Call";
|
|
250
|
+
constructor(stepName, url, method, body, headers, retries, timeout) {
|
|
229
251
|
super(stepName);
|
|
230
252
|
this.url = url;
|
|
231
253
|
this.method = method;
|
|
232
254
|
this.body = body;
|
|
233
255
|
this.headers = headers;
|
|
234
256
|
this.retries = retries;
|
|
257
|
+
this.timeout = timeout;
|
|
235
258
|
}
|
|
236
259
|
getPlanStep(concurrent, targetStep) {
|
|
237
260
|
return {
|
|
@@ -727,20 +750,9 @@ var DEFAULT_CONTENT_TYPE = "application/json";
|
|
|
727
750
|
var NO_CONCURRENCY = 1;
|
|
728
751
|
var DEFAULT_RETRIES = 3;
|
|
729
752
|
|
|
730
|
-
// src/types.ts
|
|
731
|
-
var StepTypes = [
|
|
732
|
-
"Initial",
|
|
733
|
-
"Run",
|
|
734
|
-
"SleepFor",
|
|
735
|
-
"SleepUntil",
|
|
736
|
-
"Call",
|
|
737
|
-
"Wait",
|
|
738
|
-
"Notify"
|
|
739
|
-
];
|
|
740
|
-
|
|
741
753
|
// src/workflow-requests.ts
|
|
742
|
-
import { QstashError as
|
|
743
|
-
var triggerFirstInvocation = async (workflowContext, retries, debug) => {
|
|
754
|
+
import { QstashError as QstashError3 } from "@upstash/qstash";
|
|
755
|
+
var triggerFirstInvocation = async (workflowContext, retries, useJSONContent, debug) => {
|
|
744
756
|
const { headers } = getHeaders(
|
|
745
757
|
"true",
|
|
746
758
|
workflowContext.workflowRunId,
|
|
@@ -750,6 +762,9 @@ var triggerFirstInvocation = async (workflowContext, retries, debug) => {
|
|
|
750
762
|
workflowContext.failureUrl,
|
|
751
763
|
retries
|
|
752
764
|
);
|
|
765
|
+
if (useJSONContent) {
|
|
766
|
+
headers["content-type"] = "application/json";
|
|
767
|
+
}
|
|
753
768
|
try {
|
|
754
769
|
const body = typeof workflowContext.requestPayload === "string" ? workflowContext.requestPayload : JSON.stringify(workflowContext.requestPayload);
|
|
755
770
|
const result = await workflowContext.qstashClient.publish({
|
|
@@ -793,7 +808,7 @@ var triggerRouteFunction = async ({
|
|
|
793
808
|
return ok("workflow-finished");
|
|
794
809
|
} catch (error) {
|
|
795
810
|
const error_ = error;
|
|
796
|
-
if (error instanceof
|
|
811
|
+
if (error instanceof QstashError3 && error.status === 400) {
|
|
797
812
|
await debug?.log("WARN", "RESPONSE_WORKFLOW", {
|
|
798
813
|
message: `tried to append to a cancelled workflow. exiting without publishing.`,
|
|
799
814
|
name: error.name,
|
|
@@ -827,7 +842,7 @@ var triggerWorkflowDelete = async (workflowContext, debug, cancel = false) => {
|
|
|
827
842
|
);
|
|
828
843
|
return { deleted: true };
|
|
829
844
|
} catch (error) {
|
|
830
|
-
if (error instanceof
|
|
845
|
+
if (error instanceof QstashError3 && error.status === 404) {
|
|
831
846
|
await debug?.log("WARN", "SUBMIT_CLEANUP", {
|
|
832
847
|
message: `Failed to remove workflow run ${workflowContext.workflowRunId} as it doesn't exist.`,
|
|
833
848
|
name: error.name,
|
|
@@ -843,7 +858,10 @@ var recreateUserHeaders = (headers) => {
|
|
|
843
858
|
const pairs = headers.entries();
|
|
844
859
|
for (const [header, value] of pairs) {
|
|
845
860
|
const headerLowerCase = header.toLowerCase();
|
|
846
|
-
if (!headerLowerCase.startsWith("upstash-workflow-") &&
|
|
861
|
+
if (!headerLowerCase.startsWith("upstash-workflow-") && // https://vercel.com/docs/edge-network/headers/request-headers#x-vercel-id
|
|
862
|
+
!headerLowerCase.startsWith("x-vercel-") && !headerLowerCase.startsWith("x-forwarded-") && // https://blog.cloudflare.com/preventing-request-loops-using-cdn-loop/
|
|
863
|
+
headerLowerCase !== "cf-connecting-ip" && headerLowerCase !== "cdn-loop" && headerLowerCase !== "cf-ew-via" && headerLowerCase !== "cf-ray" && // For Render https://render.com
|
|
864
|
+
headerLowerCase !== "render-proxy-ttl") {
|
|
847
865
|
filteredHeaders.append(header, value);
|
|
848
866
|
}
|
|
849
867
|
}
|
|
@@ -861,11 +879,19 @@ var handleThirdPartyCallResult = async (request, requestPayload, client, workflo
|
|
|
861
879
|
if (!workflowRunId2)
|
|
862
880
|
throw new WorkflowError("workflow run id missing in context.call lazy fetch.");
|
|
863
881
|
if (!messageId) throw new WorkflowError("message id missing in context.call lazy fetch.");
|
|
864
|
-
const steps = await getSteps(
|
|
882
|
+
const { steps, workflowRunEnded } = await getSteps(
|
|
883
|
+
client.http,
|
|
884
|
+
workflowRunId2,
|
|
885
|
+
messageId,
|
|
886
|
+
debug
|
|
887
|
+
);
|
|
888
|
+
if (workflowRunEnded) {
|
|
889
|
+
return ok("workflow-ended");
|
|
890
|
+
}
|
|
865
891
|
const failingStep = steps.find((step) => step.messageId === messageId);
|
|
866
892
|
if (!failingStep)
|
|
867
893
|
throw new WorkflowError(
|
|
868
|
-
"Failed to submit the context.call." + (steps.length === 0 ? "No steps found." : `No step was found with matching messageId ${messageId} out of ${steps.length} steps.`)
|
|
894
|
+
"Failed to submit the context.call. " + (steps.length === 0 ? "No steps found." : `No step was found with matching messageId ${messageId} out of ${steps.length} steps.`)
|
|
869
895
|
);
|
|
870
896
|
callbackPayload = atob(failingStep.body);
|
|
871
897
|
}
|
|
@@ -946,7 +972,7 @@ ${atob(callbackMessage.body ?? "")}`
|
|
|
946
972
|
);
|
|
947
973
|
}
|
|
948
974
|
};
|
|
949
|
-
var getHeaders = (initHeaderValue, workflowRunId, workflowUrl, userHeaders, step, failureUrl, retries, callRetries) => {
|
|
975
|
+
var getHeaders = (initHeaderValue, workflowRunId, workflowUrl, userHeaders, step, failureUrl, retries, callRetries, callTimeout) => {
|
|
950
976
|
const baseHeaders = {
|
|
951
977
|
[WORKFLOW_INIT_HEADER]: initHeaderValue,
|
|
952
978
|
[WORKFLOW_ID_HEADER]: workflowRunId,
|
|
@@ -956,6 +982,9 @@ var getHeaders = (initHeaderValue, workflowRunId, workflowUrl, userHeaders, step
|
|
|
956
982
|
if (!step?.callUrl) {
|
|
957
983
|
baseHeaders[`Upstash-Forward-${WORKFLOW_PROTOCOL_VERSION_HEADER}`] = WORKFLOW_PROTOCOL_VERSION;
|
|
958
984
|
}
|
|
985
|
+
if (callTimeout) {
|
|
986
|
+
baseHeaders[`Upstash-Timeout`] = callTimeout.toString();
|
|
987
|
+
}
|
|
959
988
|
if (failureUrl) {
|
|
960
989
|
baseHeaders[`Upstash-Failure-Callback-Forward-${WORKFLOW_FAILURE_HEADER}`] = "true";
|
|
961
990
|
if (!step?.callUrl) {
|
|
@@ -1331,7 +1360,8 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
1331
1360
|
singleStep,
|
|
1332
1361
|
this.context.failureUrl,
|
|
1333
1362
|
this.context.retries,
|
|
1334
|
-
lazyStep instanceof LazyCallStep ? lazyStep.retries : void 0
|
|
1363
|
+
lazyStep instanceof LazyCallStep ? lazyStep.retries : void 0,
|
|
1364
|
+
lazyStep instanceof LazyCallStep ? lazyStep.timeout : void 0
|
|
1335
1365
|
);
|
|
1336
1366
|
const willWait = singleStep.concurrent === NO_CONCURRENCY || singleStep.stepId === 0;
|
|
1337
1367
|
singleStep.out = JSON.stringify(singleStep.out);
|
|
@@ -1681,6 +1711,7 @@ var WorkflowContext = class {
|
|
|
1681
1711
|
* @param body call body
|
|
1682
1712
|
* @param headers call headers
|
|
1683
1713
|
* @param retries number of call retries. 0 by default
|
|
1714
|
+
* @param timeout max duration to wait for the endpoint to respond. in seconds.
|
|
1684
1715
|
* @returns call result as {
|
|
1685
1716
|
* status: number;
|
|
1686
1717
|
* body: unknown;
|
|
@@ -1688,9 +1719,17 @@ var WorkflowContext = class {
|
|
|
1688
1719
|
* }
|
|
1689
1720
|
*/
|
|
1690
1721
|
async call(stepName, settings) {
|
|
1691
|
-
const { url, method = "GET", body, headers = {}, retries = 0 } = settings;
|
|
1722
|
+
const { url, method = "GET", body, headers = {}, retries = 0, timeout } = settings;
|
|
1692
1723
|
const result = await this.addStep(
|
|
1693
|
-
new LazyCallStep(
|
|
1724
|
+
new LazyCallStep(
|
|
1725
|
+
stepName,
|
|
1726
|
+
url,
|
|
1727
|
+
method,
|
|
1728
|
+
body,
|
|
1729
|
+
headers,
|
|
1730
|
+
retries,
|
|
1731
|
+
timeout
|
|
1732
|
+
)
|
|
1694
1733
|
);
|
|
1695
1734
|
if (typeof result === "string") {
|
|
1696
1735
|
try {
|
|
@@ -1891,7 +1930,7 @@ function decodeBase64(base64) {
|
|
|
1891
1930
|
}
|
|
1892
1931
|
|
|
1893
1932
|
// src/serve/authorization.ts
|
|
1894
|
-
import { Client } from "@upstash/qstash";
|
|
1933
|
+
import { Client as Client2 } from "@upstash/qstash";
|
|
1895
1934
|
var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowContext {
|
|
1896
1935
|
static disabledMessage = "disabled-qstash-worklfow-run";
|
|
1897
1936
|
/**
|
|
@@ -1922,7 +1961,7 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
|
|
|
1922
1961
|
*/
|
|
1923
1962
|
static async tryAuthentication(routeFunction, context) {
|
|
1924
1963
|
const disabledContext = new _DisabledWorkflowContext({
|
|
1925
|
-
qstashClient: new
|
|
1964
|
+
qstashClient: new Client2({
|
|
1926
1965
|
baseUrl: "disabled-client",
|
|
1927
1966
|
token: "disabled-client"
|
|
1928
1967
|
}),
|
|
@@ -2046,7 +2085,8 @@ var parseRequest = async (requestPayload, isFirstInvocation, workflowRunId, requ
|
|
|
2046
2085
|
return {
|
|
2047
2086
|
rawInitialPayload: requestPayload ?? "",
|
|
2048
2087
|
steps: [],
|
|
2049
|
-
isLastDuplicate: false
|
|
2088
|
+
isLastDuplicate: false,
|
|
2089
|
+
workflowRunEnded: false
|
|
2050
2090
|
};
|
|
2051
2091
|
} else {
|
|
2052
2092
|
let rawSteps;
|
|
@@ -2056,7 +2096,21 @@ var parseRequest = async (requestPayload, isFirstInvocation, workflowRunId, requ
|
|
|
2056
2096
|
"ENDPOINT_START",
|
|
2057
2097
|
"request payload is empty, steps will be fetched from QStash."
|
|
2058
2098
|
);
|
|
2059
|
-
|
|
2099
|
+
const { steps: fetchedSteps, workflowRunEnded } = await getSteps(
|
|
2100
|
+
requester,
|
|
2101
|
+
workflowRunId,
|
|
2102
|
+
messageId,
|
|
2103
|
+
debug
|
|
2104
|
+
);
|
|
2105
|
+
if (workflowRunEnded) {
|
|
2106
|
+
return {
|
|
2107
|
+
rawInitialPayload: void 0,
|
|
2108
|
+
steps: void 0,
|
|
2109
|
+
isLastDuplicate: void 0,
|
|
2110
|
+
workflowRunEnded: true
|
|
2111
|
+
};
|
|
2112
|
+
}
|
|
2113
|
+
rawSteps = fetchedSteps;
|
|
2060
2114
|
} else {
|
|
2061
2115
|
rawSteps = JSON.parse(requestPayload);
|
|
2062
2116
|
}
|
|
@@ -2066,7 +2120,8 @@ var parseRequest = async (requestPayload, isFirstInvocation, workflowRunId, requ
|
|
|
2066
2120
|
return {
|
|
2067
2121
|
rawInitialPayload,
|
|
2068
2122
|
steps: deduplicatedSteps,
|
|
2069
|
-
isLastDuplicate
|
|
2123
|
+
isLastDuplicate,
|
|
2124
|
+
workflowRunEnded: false
|
|
2070
2125
|
};
|
|
2071
2126
|
}
|
|
2072
2127
|
};
|
|
@@ -2090,7 +2145,7 @@ var handleFailure = async (request, requestPayload, qstashClient, initialPayload
|
|
|
2090
2145
|
const workflowContext = new WorkflowContext({
|
|
2091
2146
|
qstashClient,
|
|
2092
2147
|
workflowRunId,
|
|
2093
|
-
initialPayload: initialPayloadParser(decodeBase64(sourceBody)),
|
|
2148
|
+
initialPayload: sourceBody ? initialPayloadParser(decodeBase64(sourceBody)) : void 0,
|
|
2094
2149
|
headers: recreateUserHeaders(new Headers(sourceHeader)),
|
|
2095
2150
|
steps: [],
|
|
2096
2151
|
url,
|
|
@@ -2121,21 +2176,34 @@ var handleFailure = async (request, requestPayload, qstashClient, initialPayload
|
|
|
2121
2176
|
|
|
2122
2177
|
// src/serve/options.ts
|
|
2123
2178
|
import { Receiver } from "@upstash/qstash";
|
|
2124
|
-
import { Client as
|
|
2179
|
+
import { Client as Client3 } from "@upstash/qstash";
|
|
2125
2180
|
var processOptions = (options) => {
|
|
2126
2181
|
const environment = options?.env ?? (typeof process === "undefined" ? {} : process.env);
|
|
2127
2182
|
const receiverEnvironmentVariablesSet = Boolean(
|
|
2128
2183
|
environment.QSTASH_CURRENT_SIGNING_KEY && environment.QSTASH_NEXT_SIGNING_KEY
|
|
2129
2184
|
);
|
|
2130
2185
|
return {
|
|
2131
|
-
qstashClient: new
|
|
2186
|
+
qstashClient: new Client3({
|
|
2132
2187
|
baseUrl: environment.QSTASH_URL,
|
|
2133
2188
|
token: environment.QSTASH_TOKEN
|
|
2134
2189
|
}),
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2190
|
+
onStepFinish: (workflowRunId, finishCondition) => {
|
|
2191
|
+
if (finishCondition === "auth-fail") {
|
|
2192
|
+
console.error(AUTH_FAIL_MESSAGE);
|
|
2193
|
+
return new Response(
|
|
2194
|
+
JSON.stringify({
|
|
2195
|
+
message: AUTH_FAIL_MESSAGE,
|
|
2196
|
+
workflowRunId
|
|
2197
|
+
}),
|
|
2198
|
+
{
|
|
2199
|
+
status: 400
|
|
2200
|
+
}
|
|
2201
|
+
);
|
|
2202
|
+
}
|
|
2203
|
+
return new Response(JSON.stringify({ workflowRunId }), {
|
|
2204
|
+
status: 200
|
|
2205
|
+
});
|
|
2206
|
+
},
|
|
2139
2207
|
initialPayloadParser: (initialRequest) => {
|
|
2140
2208
|
if (!initialRequest) {
|
|
2141
2209
|
return void 0;
|
|
@@ -2156,6 +2224,7 @@ var processOptions = (options) => {
|
|
|
2156
2224
|
baseUrl: environment.UPSTASH_WORKFLOW_URL,
|
|
2157
2225
|
env: environment,
|
|
2158
2226
|
retries: DEFAULT_RETRIES,
|
|
2227
|
+
useJSONContent: false,
|
|
2159
2228
|
...options
|
|
2160
2229
|
};
|
|
2161
2230
|
};
|
|
@@ -2172,14 +2241,25 @@ var determineUrls = async (request, url, baseUrl, failureFunction, failureUrl, d
|
|
|
2172
2241
|
});
|
|
2173
2242
|
}
|
|
2174
2243
|
const workflowFailureUrl = failureFunction ? workflowUrl : failureUrl;
|
|
2244
|
+
if (workflowUrl.includes("localhost")) {
|
|
2245
|
+
await debug?.log("WARN", "ENDPOINT_START", {
|
|
2246
|
+
message: `Workflow URL contains localhost. This can happen in local development, but shouldn't happen in production unless you have a route which contains localhost. Received: ${workflowUrl}`
|
|
2247
|
+
});
|
|
2248
|
+
}
|
|
2249
|
+
if (!(workflowUrl.startsWith("http://") || workflowUrl.startsWith("https://"))) {
|
|
2250
|
+
throw new WorkflowError(
|
|
2251
|
+
`Workflow URL should start with 'http://' or 'https://'. Recevied is '${workflowUrl}'`
|
|
2252
|
+
);
|
|
2253
|
+
}
|
|
2175
2254
|
return {
|
|
2176
2255
|
workflowUrl,
|
|
2177
2256
|
workflowFailureUrl
|
|
2178
2257
|
};
|
|
2179
2258
|
};
|
|
2259
|
+
var AUTH_FAIL_MESSAGE = `Failed to authenticate Workflow request. If this is unexpected, see the caveat https://upstash.com/docs/workflow/basics/caveats#avoid-non-deterministic-code-outside-context-run`;
|
|
2180
2260
|
|
|
2181
2261
|
// src/serve/index.ts
|
|
2182
|
-
var
|
|
2262
|
+
var serveBase = (routeFunction, options) => {
|
|
2183
2263
|
const {
|
|
2184
2264
|
qstashClient,
|
|
2185
2265
|
onStepFinish,
|
|
@@ -2191,7 +2271,8 @@ var serve = (routeFunction, options) => {
|
|
|
2191
2271
|
failureFunction,
|
|
2192
2272
|
baseUrl,
|
|
2193
2273
|
env,
|
|
2194
|
-
retries
|
|
2274
|
+
retries,
|
|
2275
|
+
useJSONContent
|
|
2195
2276
|
} = processOptions(options);
|
|
2196
2277
|
const debug = WorkflowLogger.getLogger(verbose);
|
|
2197
2278
|
const handler = async (request) => {
|
|
@@ -2208,7 +2289,7 @@ var serve = (routeFunction, options) => {
|
|
|
2208
2289
|
await verifyRequest(requestPayload, request.headers.get("upstash-signature"), receiver);
|
|
2209
2290
|
const { isFirstInvocation, workflowRunId } = validateRequest(request);
|
|
2210
2291
|
debug?.setWorkflowRunId(workflowRunId);
|
|
2211
|
-
const { rawInitialPayload, steps, isLastDuplicate } = await parseRequest(
|
|
2292
|
+
const { rawInitialPayload, steps, isLastDuplicate, workflowRunEnded } = await parseRequest(
|
|
2212
2293
|
requestPayload,
|
|
2213
2294
|
isFirstInvocation,
|
|
2214
2295
|
workflowRunId,
|
|
@@ -2216,8 +2297,11 @@ var serve = (routeFunction, options) => {
|
|
|
2216
2297
|
request.headers.get("upstash-message-id"),
|
|
2217
2298
|
debug
|
|
2218
2299
|
);
|
|
2300
|
+
if (workflowRunEnded) {
|
|
2301
|
+
return onStepFinish(workflowRunId, "workflow-already-ended");
|
|
2302
|
+
}
|
|
2219
2303
|
if (isLastDuplicate) {
|
|
2220
|
-
return onStepFinish(
|
|
2304
|
+
return onStepFinish(workflowRunId, "duplicate-step");
|
|
2221
2305
|
}
|
|
2222
2306
|
const failureCheck = await handleFailure(
|
|
2223
2307
|
request,
|
|
@@ -2231,7 +2315,7 @@ var serve = (routeFunction, options) => {
|
|
|
2231
2315
|
throw failureCheck.error;
|
|
2232
2316
|
} else if (failureCheck.value === "is-failure-callback") {
|
|
2233
2317
|
await debug?.log("WARN", "RESPONSE_DEFAULT", "failureFunction executed");
|
|
2234
|
-
return onStepFinish(
|
|
2318
|
+
return onStepFinish(workflowRunId, "failure-callback");
|
|
2235
2319
|
}
|
|
2236
2320
|
const workflowContext = new WorkflowContext({
|
|
2237
2321
|
qstashClient,
|
|
@@ -2253,7 +2337,11 @@ var serve = (routeFunction, options) => {
|
|
|
2253
2337
|
await debug?.log("ERROR", "ERROR", { error: authCheck.error.message });
|
|
2254
2338
|
throw authCheck.error;
|
|
2255
2339
|
} else if (authCheck.value === "run-ended") {
|
|
2256
|
-
|
|
2340
|
+
await debug?.log("ERROR", "ERROR", { error: AUTH_FAIL_MESSAGE });
|
|
2341
|
+
return onStepFinish(
|
|
2342
|
+
isFirstInvocation ? "no-workflow-id" : workflowContext.workflowRunId,
|
|
2343
|
+
"auth-fail"
|
|
2344
|
+
);
|
|
2257
2345
|
}
|
|
2258
2346
|
const callReturnCheck = await handleThirdPartyCallResult(
|
|
2259
2347
|
request,
|
|
@@ -2270,7 +2358,7 @@ var serve = (routeFunction, options) => {
|
|
|
2270
2358
|
});
|
|
2271
2359
|
throw callReturnCheck.error;
|
|
2272
2360
|
} else if (callReturnCheck.value === "continue-workflow") {
|
|
2273
|
-
const result = isFirstInvocation ? await triggerFirstInvocation(workflowContext, retries, debug) : await triggerRouteFunction({
|
|
2361
|
+
const result = isFirstInvocation ? await triggerFirstInvocation(workflowContext, retries, useJSONContent, debug) : await triggerRouteFunction({
|
|
2274
2362
|
onStep: async () => routeFunction(workflowContext),
|
|
2275
2363
|
onCleanup: async () => {
|
|
2276
2364
|
await triggerWorkflowDelete(workflowContext, debug);
|
|
@@ -2286,6 +2374,8 @@ var serve = (routeFunction, options) => {
|
|
|
2286
2374
|
}
|
|
2287
2375
|
await debug?.log("INFO", "RESPONSE_WORKFLOW");
|
|
2288
2376
|
return onStepFinish(workflowContext.workflowRunId, "success");
|
|
2377
|
+
} else if (callReturnCheck.value === "workflow-ended") {
|
|
2378
|
+
return onStepFinish(workflowContext.workflowRunId, "workflow-already-ended");
|
|
2289
2379
|
}
|
|
2290
2380
|
await debug?.log("INFO", "RESPONSE_DEFAULT");
|
|
2291
2381
|
return onStepFinish("no-workflow-id", "fromCallback");
|
|
@@ -2302,198 +2392,24 @@ var serve = (routeFunction, options) => {
|
|
|
2302
2392
|
};
|
|
2303
2393
|
return { handler: safeHandler };
|
|
2304
2394
|
};
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
import { Client as QStashClient } from "@upstash/qstash";
|
|
2308
|
-
var Client3 = class {
|
|
2309
|
-
client;
|
|
2310
|
-
constructor(clientConfig) {
|
|
2311
|
-
if (!clientConfig.token) {
|
|
2312
|
-
console.error(
|
|
2313
|
-
"QStash token is required for Upstash Workflow!\n\nTo fix this:\n1. Get your token from the Upstash Console (https://console.upstash.com/qstash)\n2. Initialize the workflow client with:\n\n const client = new Client({\n token: '<YOUR_QSTASH_TOKEN>'\n });"
|
|
2314
|
-
);
|
|
2315
|
-
}
|
|
2316
|
-
this.client = new QStashClient(clientConfig);
|
|
2317
|
-
}
|
|
2318
|
-
/**
|
|
2319
|
-
* Cancel an ongoing workflow
|
|
2320
|
-
*
|
|
2321
|
-
* Returns true if workflow is canceled succesfully. Otherwise, throws error.
|
|
2322
|
-
*
|
|
2323
|
-
* There are multiple ways you can cancel workflows:
|
|
2324
|
-
* - pass one or more workflow run ids to cancel them
|
|
2325
|
-
* - pass a workflow url to cancel all runs starting with this url
|
|
2326
|
-
* - cancel all pending or active workflow runs
|
|
2327
|
-
*
|
|
2328
|
-
* ### Cancel a set of workflow runs
|
|
2329
|
-
*
|
|
2330
|
-
* ```ts
|
|
2331
|
-
* // cancel a single workflow
|
|
2332
|
-
* await client.cancel({ ids: "<WORKFLOW_RUN_ID>" })
|
|
2333
|
-
*
|
|
2334
|
-
* // cancel a set of workflow runs
|
|
2335
|
-
* await client.cancel({ ids: [
|
|
2336
|
-
* "<WORKFLOW_RUN_ID_1>",
|
|
2337
|
-
* "<WORKFLOW_RUN_ID_2>",
|
|
2338
|
-
* ]})
|
|
2339
|
-
* ```
|
|
2340
|
-
*
|
|
2341
|
-
* ### Cancel workflows starting with a url
|
|
2342
|
-
*
|
|
2343
|
-
* If you have an endpoint called `https://your-endpoint.com` and you
|
|
2344
|
-
* want to cancel all workflow runs on it, you can use `urlStartingWith`.
|
|
2345
|
-
*
|
|
2346
|
-
* Note that this will cancel workflows in all endpoints under
|
|
2347
|
-
* `https://your-endpoint.com`.
|
|
2348
|
-
*
|
|
2349
|
-
* ```ts
|
|
2350
|
-
* await client.cancel({ urlStartingWith: "https://your-endpoint.com" })
|
|
2351
|
-
* ```
|
|
2352
|
-
*
|
|
2353
|
-
* ### Cancel *all* workflows
|
|
2354
|
-
*
|
|
2355
|
-
* To cancel all pending and currently running workflows, you can
|
|
2356
|
-
* do it like this:
|
|
2357
|
-
*
|
|
2358
|
-
* ```ts
|
|
2359
|
-
* await client.cancel({ all: true })
|
|
2360
|
-
* ```
|
|
2361
|
-
*
|
|
2362
|
-
* @param ids run id of the workflow to delete
|
|
2363
|
-
* @param urlStartingWith cancel workflows starting with this url. Will be ignored
|
|
2364
|
-
* if `ids` parameter is set.
|
|
2365
|
-
* @param all set to true in order to cancel all workflows. Will be ignored
|
|
2366
|
-
* if `ids` or `urlStartingWith` parameters are set.
|
|
2367
|
-
* @returns true if workflow is succesfully deleted. Otherwise throws QStashError
|
|
2368
|
-
*/
|
|
2369
|
-
async cancel({
|
|
2370
|
-
ids,
|
|
2371
|
-
urlStartingWith,
|
|
2372
|
-
all
|
|
2373
|
-
}) {
|
|
2374
|
-
let body;
|
|
2375
|
-
if (ids) {
|
|
2376
|
-
const runIdArray = typeof ids === "string" ? [ids] : ids;
|
|
2377
|
-
body = JSON.stringify({ workflowRunIds: runIdArray });
|
|
2378
|
-
} else if (urlStartingWith) {
|
|
2379
|
-
body = JSON.stringify({ workflowUrl: urlStartingWith });
|
|
2380
|
-
} else if (all) {
|
|
2381
|
-
body = "{}";
|
|
2382
|
-
} else {
|
|
2383
|
-
throw new TypeError("The `cancel` method cannot be called without any options.");
|
|
2384
|
-
}
|
|
2385
|
-
const result = await this.client.http.request({
|
|
2386
|
-
path: ["v2", "workflows", "runs"],
|
|
2387
|
-
method: "DELETE",
|
|
2388
|
-
body,
|
|
2389
|
-
headers: {
|
|
2390
|
-
"Content-Type": "application/json"
|
|
2391
|
-
}
|
|
2392
|
-
});
|
|
2393
|
-
return result;
|
|
2394
|
-
}
|
|
2395
|
-
/**
|
|
2396
|
-
* Notify a workflow run waiting for an event
|
|
2397
|
-
*
|
|
2398
|
-
* ```ts
|
|
2399
|
-
* import { Client } from "@upstash/workflow";
|
|
2400
|
-
*
|
|
2401
|
-
* const client = new Client({ token: "<QSTASH_TOKEN>" })
|
|
2402
|
-
* await client.notify({
|
|
2403
|
-
* eventId: "my-event-id",
|
|
2404
|
-
* eventData: "my-data" // data passed to the workflow run
|
|
2405
|
-
* });
|
|
2406
|
-
* ```
|
|
2407
|
-
*
|
|
2408
|
-
* @param eventId event id to notify
|
|
2409
|
-
* @param eventData data to provide to the workflow
|
|
2410
|
-
*/
|
|
2411
|
-
async notify({
|
|
2412
|
-
eventId,
|
|
2413
|
-
eventData
|
|
2414
|
-
}) {
|
|
2415
|
-
return await makeNotifyRequest(this.client.http, eventId, eventData);
|
|
2416
|
-
}
|
|
2417
|
-
/**
|
|
2418
|
-
* Check waiters of an event
|
|
2419
|
-
*
|
|
2420
|
-
* ```ts
|
|
2421
|
-
* import { Client } from "@upstash/workflow";
|
|
2422
|
-
*
|
|
2423
|
-
* const client = new Client({ token: "<QSTASH_TOKEN>" })
|
|
2424
|
-
* const result = await client.getWaiters({
|
|
2425
|
-
* eventId: "my-event-id"
|
|
2426
|
-
* })
|
|
2427
|
-
* ```
|
|
2428
|
-
*
|
|
2429
|
-
* @param eventId event id to check
|
|
2430
|
-
*/
|
|
2431
|
-
async getWaiters({ eventId }) {
|
|
2432
|
-
return await makeGetWaitersRequest(this.client.http, eventId);
|
|
2433
|
-
}
|
|
2434
|
-
/**
|
|
2435
|
-
* Trigger new workflow run and returns the workflow run id
|
|
2436
|
-
*
|
|
2437
|
-
* ```ts
|
|
2438
|
-
* const { workflowRunId } = await client.trigger({
|
|
2439
|
-
* url: "https://workflow-endpoint.com",
|
|
2440
|
-
* body: "hello there!", // Optional body
|
|
2441
|
-
* headers: { ... }, // Optional headers
|
|
2442
|
-
* workflowRunId: "my-workflow", // Optional workflow run ID
|
|
2443
|
-
* retries: 3 // Optional retries for the initial request
|
|
2444
|
-
* });
|
|
2445
|
-
*
|
|
2446
|
-
* console.log(workflowRunId)
|
|
2447
|
-
* // wfr_my-workflow
|
|
2448
|
-
* ```
|
|
2449
|
-
*
|
|
2450
|
-
* @param url URL of the workflow
|
|
2451
|
-
* @param body body to start the workflow with
|
|
2452
|
-
* @param headers headers to use in the request
|
|
2453
|
-
* @param workflowRunId optional workflow run id to use. mind that
|
|
2454
|
-
* you should pass different workflow run ids for different runs.
|
|
2455
|
-
* The final workflowRunId will be `wfr_${workflowRunId}`, in
|
|
2456
|
-
* other words: the workflow run id you pass will be prefixed
|
|
2457
|
-
* with `wfr_`.
|
|
2458
|
-
* @param retries retry to use in the initial request. in the rest of
|
|
2459
|
-
* the workflow, `retries` option of the `serve` will be used.
|
|
2460
|
-
* @returns workflow run id
|
|
2461
|
-
*/
|
|
2462
|
-
async trigger({
|
|
2463
|
-
url,
|
|
2464
|
-
body,
|
|
2465
|
-
headers,
|
|
2466
|
-
workflowRunId,
|
|
2467
|
-
retries
|
|
2468
|
-
}) {
|
|
2469
|
-
const finalWorkflowRunId = getWorkflowRunId(workflowRunId);
|
|
2470
|
-
const context = new WorkflowContext({
|
|
2471
|
-
qstashClient: this.client,
|
|
2472
|
-
// @ts-expect-error headers type mismatch
|
|
2473
|
-
headers: new Headers(headers ?? {}),
|
|
2474
|
-
initialPayload: body,
|
|
2475
|
-
steps: [],
|
|
2476
|
-
url,
|
|
2477
|
-
workflowRunId: finalWorkflowRunId
|
|
2478
|
-
});
|
|
2479
|
-
const result = await triggerFirstInvocation(context, retries ?? DEFAULT_RETRIES);
|
|
2480
|
-
if (result.isOk()) {
|
|
2481
|
-
return { workflowRunId: finalWorkflowRunId };
|
|
2482
|
-
} else {
|
|
2483
|
-
throw result.error;
|
|
2484
|
-
}
|
|
2485
|
-
}
|
|
2395
|
+
var serve = (routeFunction, options) => {
|
|
2396
|
+
return serveBase(routeFunction, options);
|
|
2486
2397
|
};
|
|
2487
2398
|
|
|
2488
2399
|
export {
|
|
2489
2400
|
__require,
|
|
2490
2401
|
__commonJS,
|
|
2491
2402
|
__toESM,
|
|
2403
|
+
makeNotifyRequest,
|
|
2404
|
+
makeGetWaitersRequest,
|
|
2492
2405
|
WorkflowError,
|
|
2493
2406
|
WorkflowAbort,
|
|
2407
|
+
DEFAULT_RETRIES,
|
|
2494
2408
|
StepTypes,
|
|
2409
|
+
triggerFirstInvocation,
|
|
2495
2410
|
WorkflowContext,
|
|
2496
2411
|
WorkflowLogger,
|
|
2497
|
-
|
|
2498
|
-
|
|
2412
|
+
getWorkflowRunId,
|
|
2413
|
+
serveBase,
|
|
2414
|
+
serve
|
|
2499
2415
|
};
|
package/cloudflare.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { R as RouteFunction,
|
|
1
|
+
import { R as RouteFunction, j as PublicServeOptions } from './types-APRap-aV.mjs';
|
|
2
2
|
import '@upstash/qstash';
|
|
3
3
|
|
|
4
4
|
type WorkflowBindings = {
|
|
@@ -28,7 +28,7 @@ type WorkersHandlerArgs = [Request, Record<string, string | undefined>];
|
|
|
28
28
|
* @param options workflow options
|
|
29
29
|
* @returns
|
|
30
30
|
*/
|
|
31
|
-
declare const serve: <TInitialPayload = unknown>(routeFunction: RouteFunction<TInitialPayload>, options?:
|
|
31
|
+
declare const serve: <TInitialPayload = unknown>(routeFunction: RouteFunction<TInitialPayload>, options?: PublicServeOptions<TInitialPayload>) => {
|
|
32
32
|
fetch: (...args: PagesHandlerArgs | WorkersHandlerArgs) => Promise<Response>;
|
|
33
33
|
};
|
|
34
34
|
|
package/cloudflare.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { R as RouteFunction,
|
|
1
|
+
import { R as RouteFunction, j as PublicServeOptions } from './types-APRap-aV.js';
|
|
2
2
|
import '@upstash/qstash';
|
|
3
3
|
|
|
4
4
|
type WorkflowBindings = {
|
|
@@ -28,7 +28,7 @@ type WorkersHandlerArgs = [Request, Record<string, string | undefined>];
|
|
|
28
28
|
* @param options workflow options
|
|
29
29
|
* @returns
|
|
30
30
|
*/
|
|
31
|
-
declare const serve: <TInitialPayload = unknown>(routeFunction: RouteFunction<TInitialPayload>, options?:
|
|
31
|
+
declare const serve: <TInitialPayload = unknown>(routeFunction: RouteFunction<TInitialPayload>, options?: PublicServeOptions<TInitialPayload>) => {
|
|
32
32
|
fetch: (...args: PagesHandlerArgs | WorkersHandlerArgs) => Promise<Response>;
|
|
33
33
|
};
|
|
34
34
|
|