@upstash/workflow 1.2.0-demo-rc.1 → 1.2.1
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/README.md +1 -0
- package/astro.d.mts +2 -2
- package/astro.d.ts +2 -2
- package/astro.js +72 -69
- package/astro.mjs +1 -1
- package/{chunk-NZCQPOPR.mjs → chunk-THS5AX2D.mjs} +128 -257
- package/cloudflare.d.mts +2 -2
- package/cloudflare.d.ts +2 -2
- package/cloudflare.js +72 -69
- package/cloudflare.mjs +1 -1
- package/express.d.mts +2 -2
- package/express.d.ts +2 -2
- package/express.js +72 -69
- package/express.mjs +1 -1
- package/h3.d.mts +2 -2
- package/h3.d.ts +2 -2
- package/h3.js +76 -73
- package/h3.mjs +5 -5
- package/hono.d.mts +2 -2
- package/hono.d.ts +2 -2
- package/hono.js +73 -265
- package/hono.mjs +2 -7
- package/index.d.mts +229 -138
- package/index.d.ts +229 -138
- package/index.js +275 -454
- package/index.mjs +144 -196
- package/nextjs.d.mts +2 -2
- package/nextjs.d.ts +2 -2
- package/nextjs.js +72 -263
- package/nextjs.mjs +1 -5
- package/package.json +1 -1
- package/react-router.d.mts +38 -0
- package/react-router.d.ts +38 -0
- package/react-router.js +3881 -0
- package/react-router.mjs +45 -0
- package/{serve-many-Bi8XaOyq.d.ts → serve-many-B-fe7bh7.d.ts} +1 -1
- package/{serve-many-CppVPJrh.d.mts → serve-many-C6sa_DxN.d.mts} +1 -1
- package/solidjs.d.mts +1 -1
- package/solidjs.d.ts +1 -1
- package/solidjs.js +72 -69
- package/solidjs.mjs +1 -1
- package/svelte.d.mts +2 -2
- package/svelte.d.ts +2 -2
- package/svelte.js +72 -69
- package/svelte.mjs +1 -1
- package/tanstack.d.mts +2 -2
- package/tanstack.d.ts +2 -2
- package/tanstack.js +72 -69
- package/tanstack.mjs +1 -1
- package/{types-CUwgrpCM.d.ts → types-B2S08hRU.d.mts} +18 -3
- package/{types-CUwgrpCM.d.mts → types-B2S08hRU.d.ts} +18 -3
package/index.js
CHANGED
|
@@ -133,9 +133,10 @@ function isInstanceOf(v, ctor) {
|
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
// src/client/utils.ts
|
|
136
|
-
var makeNotifyRequest = async (requester, eventId, eventData) => {
|
|
136
|
+
var makeNotifyRequest = async (requester, eventId, eventData, workflowRunId) => {
|
|
137
|
+
const path = workflowRunId ? ["v2", "notify", workflowRunId, eventId] : ["v2", "notify", eventId];
|
|
137
138
|
const result = await requester.request({
|
|
138
|
-
path
|
|
139
|
+
path,
|
|
139
140
|
method: "POST",
|
|
140
141
|
body: typeof eventData === "string" ? eventData : JSON.stringify(eventData)
|
|
141
142
|
});
|
|
@@ -195,11 +196,72 @@ var getSteps = async (requester, workflowRunId, messageId, dispatchDebug) => {
|
|
|
195
196
|
}
|
|
196
197
|
}
|
|
197
198
|
};
|
|
199
|
+
function normalizeCursor(response) {
|
|
200
|
+
const cursor = response.cursor;
|
|
201
|
+
return { ...response, cursor: cursor || void 0 };
|
|
202
|
+
}
|
|
203
|
+
var DEFAULT_BULK_COUNT = 100;
|
|
204
|
+
function buildBulkActionQueryParameters(request, options) {
|
|
205
|
+
const cursor = "cursor" in request ? request.cursor : void 0;
|
|
206
|
+
if ("all" in request) {
|
|
207
|
+
return { count: request.count ?? DEFAULT_BULK_COUNT, cursor };
|
|
208
|
+
}
|
|
209
|
+
if ("dlqIds" in request) {
|
|
210
|
+
const ids = request.dlqIds;
|
|
211
|
+
if (Array.isArray(ids) && ids.length === 0) {
|
|
212
|
+
throw new import_qstash2.QstashError(
|
|
213
|
+
"Empty dlqIds array provided. If you intend to target all DLQ messages, use { all: true } explicitly."
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
return { dlqIds: ids, cursor };
|
|
217
|
+
}
|
|
218
|
+
if ("workflowRunIds" in request && request.workflowRunIds) {
|
|
219
|
+
if (request.workflowRunIds.length === 0) {
|
|
220
|
+
throw new import_qstash2.QstashError(
|
|
221
|
+
"Empty workflowRunIds array provided. If you intend to target all workflow runs, use { all: true } explicitly."
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
return { workflowRunIds: request.workflowRunIds };
|
|
225
|
+
}
|
|
226
|
+
const filter = request.filter;
|
|
227
|
+
if (!filter) {
|
|
228
|
+
throw new import_qstash2.QstashError(
|
|
229
|
+
"No filter provided. Use { filter: { ... } } with at least one filter field, or { all: true }."
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
if (options?.translateWorkflowUrl) {
|
|
233
|
+
const { workflowUrlStartingWith, workflowUrl, ...rest } = filter;
|
|
234
|
+
if (workflowUrlStartingWith && workflowUrl) {
|
|
235
|
+
throw new import_qstash2.QstashError(
|
|
236
|
+
"workflowUrl and workflowUrlStartingWith are mutually exclusive. Use workflowUrl for exact match or workflowUrlStartingWith for prefix match."
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
const urlParams = {};
|
|
240
|
+
if (workflowUrlStartingWith) {
|
|
241
|
+
urlParams.workflowUrl = workflowUrlStartingWith;
|
|
242
|
+
} else if (workflowUrl) {
|
|
243
|
+
urlParams.workflowUrl = workflowUrl;
|
|
244
|
+
urlParams.workflowUrlExactMatch = true;
|
|
245
|
+
}
|
|
246
|
+
return {
|
|
247
|
+
...rest,
|
|
248
|
+
...urlParams,
|
|
249
|
+
count: request.count ?? DEFAULT_BULK_COUNT,
|
|
250
|
+
cursor
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
return {
|
|
254
|
+
...filter,
|
|
255
|
+
count: request.count ?? DEFAULT_BULK_COUNT,
|
|
256
|
+
cursor
|
|
257
|
+
};
|
|
258
|
+
}
|
|
198
259
|
|
|
199
260
|
// src/constants.ts
|
|
200
261
|
var WORKFLOW_ID_HEADER = "Upstash-Workflow-RunId";
|
|
201
262
|
var WORKFLOW_INIT_HEADER = "Upstash-Workflow-Init";
|
|
202
263
|
var WORKFLOW_URL_HEADER = "Upstash-Workflow-Url";
|
|
264
|
+
var WORKFLOW_CREATED_AT_HEADER = "Upstash-Workflow-CreatedAt";
|
|
203
265
|
var WORKFLOW_FAILURE_HEADER = "Upstash-Workflow-Is-Failure";
|
|
204
266
|
var WORKFLOW_FAILURE_CALLBACK_HEADER = "Upstash-Workflow-Failure-Callback";
|
|
205
267
|
var WORKFLOW_FEATURE_HEADER = "Upstash-Feature-Set";
|
|
@@ -735,6 +797,7 @@ var triggerFirstInvocation = async (params) => {
|
|
|
735
797
|
retries,
|
|
736
798
|
retryDelay,
|
|
737
799
|
flowControl,
|
|
800
|
+
redact,
|
|
738
801
|
unknownSdk
|
|
739
802
|
}) => {
|
|
740
803
|
const { headers } = getHeaders({
|
|
@@ -771,7 +834,8 @@ var triggerFirstInvocation = async (params) => {
|
|
|
771
834
|
body,
|
|
772
835
|
url: workflowContext.url,
|
|
773
836
|
delay,
|
|
774
|
-
notBefore
|
|
837
|
+
notBefore,
|
|
838
|
+
redact
|
|
775
839
|
};
|
|
776
840
|
}
|
|
777
841
|
);
|
|
@@ -930,7 +994,6 @@ ${atob(callbackMessage.body ?? "")}`
|
|
|
930
994
|
})}`
|
|
931
995
|
);
|
|
932
996
|
}
|
|
933
|
-
const userHeaders = recreateUserHeaders(request.headers);
|
|
934
997
|
const { headers: requestHeaders } = getHeaders({
|
|
935
998
|
initHeaderValue: "false",
|
|
936
999
|
workflowConfig: {
|
|
@@ -938,7 +1001,6 @@ ${atob(callbackMessage.body ?? "")}`
|
|
|
938
1001
|
workflowUrl,
|
|
939
1002
|
telemetry
|
|
940
1003
|
},
|
|
941
|
-
userHeaders,
|
|
942
1004
|
invokeCount: Number(invokeCount)
|
|
943
1005
|
});
|
|
944
1006
|
const callResponse = {
|
|
@@ -1087,7 +1149,6 @@ var BaseLazyStep = class _BaseLazyStep {
|
|
|
1087
1149
|
useJSONContent: false,
|
|
1088
1150
|
telemetry
|
|
1089
1151
|
},
|
|
1090
|
-
userHeaders: context.headers,
|
|
1091
1152
|
invokeCount,
|
|
1092
1153
|
stepInfo: {
|
|
1093
1154
|
step,
|
|
@@ -1445,9 +1506,9 @@ var LazyWaitEventStep = class extends BaseLazyStep {
|
|
|
1445
1506
|
};
|
|
1446
1507
|
var LazyNotifyStep = class extends LazyFunctionStep {
|
|
1447
1508
|
stepType = "Notify";
|
|
1448
|
-
constructor(context, stepName, eventId, eventData, requester) {
|
|
1509
|
+
constructor(context, stepName, eventId, eventData, requester, workflowRunId) {
|
|
1449
1510
|
super(context, stepName, async () => {
|
|
1450
|
-
const notifyResponse = await makeNotifyRequest(requester, eventId, eventData);
|
|
1511
|
+
const notifyResponse = await makeNotifyRequest(requester, eventId, eventData, workflowRunId);
|
|
1451
1512
|
return {
|
|
1452
1513
|
eventId,
|
|
1453
1514
|
eventData,
|
|
@@ -1517,7 +1578,6 @@ var LazyInvokeStep = class extends BaseLazyStep {
|
|
|
1517
1578
|
telemetry,
|
|
1518
1579
|
useJSONContent: false
|
|
1519
1580
|
},
|
|
1520
|
-
userHeaders: context.headers,
|
|
1521
1581
|
invokeCount
|
|
1522
1582
|
});
|
|
1523
1583
|
context.qstashClient.http.headers?.forEach((value, key) => {
|
|
@@ -1530,6 +1590,7 @@ var LazyInvokeStep = class extends BaseLazyStep {
|
|
|
1530
1590
|
Object.entries(invokerHeaders).map((pairs) => [pairs[0], [pairs[1]]])
|
|
1531
1591
|
),
|
|
1532
1592
|
workflowRunId: context.workflowRunId,
|
|
1593
|
+
workflowRunCreatedAt: context.workflowRunCreatedAt,
|
|
1533
1594
|
workflowUrl: context.url,
|
|
1534
1595
|
step
|
|
1535
1596
|
};
|
|
@@ -1625,12 +1686,14 @@ var LazyWaitForWebhookStep = class extends LazyWaitEventStep {
|
|
|
1625
1686
|
const parsedEventData = BaseLazyStep.tryParsing(eventData);
|
|
1626
1687
|
const body = parsedEventData.body;
|
|
1627
1688
|
const parsedBody = typeof body === "string" ? decodeBase64(body) : void 0;
|
|
1689
|
+
const methodUpper = parsedEventData.method.toUpperCase();
|
|
1690
|
+
const canHaveBody = methodUpper !== "GET" && methodUpper !== "HEAD";
|
|
1628
1691
|
const request = new Request(
|
|
1629
1692
|
`${parsedEventData.proto}://${parsedEventData.host}${parsedEventData.url}`,
|
|
1630
1693
|
{
|
|
1631
1694
|
method: parsedEventData.method,
|
|
1632
1695
|
headers: parsedEventData.header,
|
|
1633
|
-
body: parsedBody
|
|
1696
|
+
body: canHaveBody ? parsedBody : void 0
|
|
1634
1697
|
}
|
|
1635
1698
|
);
|
|
1636
1699
|
return {
|
|
@@ -1764,6 +1827,9 @@ var WorkflowHeaders = class {
|
|
|
1764
1827
|
}
|
|
1765
1828
|
}
|
|
1766
1829
|
addUserHeaders() {
|
|
1830
|
+
if (!this.userHeaders) {
|
|
1831
|
+
return;
|
|
1832
|
+
}
|
|
1767
1833
|
for (const [key, value] of this.userHeaders.entries()) {
|
|
1768
1834
|
const forwardKey = `Forward-${key}`;
|
|
1769
1835
|
this.headers.workflowHeaders[forwardKey] = value;
|
|
@@ -1870,7 +1936,6 @@ var submitParallelSteps = async ({
|
|
|
1870
1936
|
workflowUrl: context.url,
|
|
1871
1937
|
telemetry
|
|
1872
1938
|
},
|
|
1873
|
-
userHeaders: context.headers,
|
|
1874
1939
|
invokeCount
|
|
1875
1940
|
});
|
|
1876
1941
|
return {
|
|
@@ -2123,7 +2188,7 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
2123
2188
|
});
|
|
2124
2189
|
throw new WorkflowAbort(parallelStep.stepName, resultStep);
|
|
2125
2190
|
} catch (error) {
|
|
2126
|
-
if (isInstanceOf(error, WorkflowAbort) || isInstanceOf(error, import_qstash5.QstashError) && error.status === 400) {
|
|
2191
|
+
if (isInstanceOf(error, WorkflowAbort) || isInstanceOf(error, import_qstash5.QstashError) && error.status === 400 || isInstanceOf(error, import_qstash5.QstashError) && error.status === 412) {
|
|
2127
2192
|
throw error;
|
|
2128
2193
|
}
|
|
2129
2194
|
throw new WorkflowError(
|
|
@@ -2530,6 +2595,7 @@ var MiddlewareManager = class {
|
|
|
2530
2595
|
};
|
|
2531
2596
|
|
|
2532
2597
|
// src/context/context.ts
|
|
2598
|
+
var import_qstash9 = require("@upstash/qstash");
|
|
2533
2599
|
var WorkflowContext = class {
|
|
2534
2600
|
executor;
|
|
2535
2601
|
steps;
|
|
@@ -2556,6 +2622,10 @@ var WorkflowContext = class {
|
|
|
2556
2622
|
* Run id of the workflow
|
|
2557
2623
|
*/
|
|
2558
2624
|
workflowRunId;
|
|
2625
|
+
/**
|
|
2626
|
+
* Creation time of the workflow run
|
|
2627
|
+
*/
|
|
2628
|
+
workflowRunCreatedAt;
|
|
2559
2629
|
/**
|
|
2560
2630
|
* URL of the workflow
|
|
2561
2631
|
*
|
|
@@ -2647,6 +2717,7 @@ var WorkflowContext = class {
|
|
|
2647
2717
|
constructor({
|
|
2648
2718
|
qstashClient,
|
|
2649
2719
|
workflowRunId,
|
|
2720
|
+
workflowRunCreatedAt,
|
|
2650
2721
|
headers,
|
|
2651
2722
|
steps,
|
|
2652
2723
|
url,
|
|
@@ -2659,6 +2730,7 @@ var WorkflowContext = class {
|
|
|
2659
2730
|
}) {
|
|
2660
2731
|
this.qstashClient = qstashClient;
|
|
2661
2732
|
this.workflowRunId = workflowRunId;
|
|
2733
|
+
this.workflowRunCreatedAt = workflowRunCreatedAt;
|
|
2662
2734
|
this.steps = steps;
|
|
2663
2735
|
this.url = url;
|
|
2664
2736
|
this.headers = headers;
|
|
@@ -2833,14 +2905,23 @@ var WorkflowContext = class {
|
|
|
2833
2905
|
* a notifyResponse field which contains a list of `Waiter` objects, each corresponding
|
|
2834
2906
|
* to a notified workflow run.
|
|
2835
2907
|
*
|
|
2908
|
+
* Optionally, you can pass a workflowRunId to enable lookback functionality:
|
|
2909
|
+
*
|
|
2910
|
+
* ```ts
|
|
2911
|
+
* const { eventId, eventData, notifyResponse } = await context.notify(
|
|
2912
|
+
* "notify step", "event-id", "event-data", "wfr_123"
|
|
2913
|
+
* );
|
|
2914
|
+
* ```
|
|
2915
|
+
*
|
|
2836
2916
|
* @param stepName
|
|
2837
2917
|
* @param eventId event id to notify
|
|
2838
2918
|
* @param eventData event data to notify with
|
|
2919
|
+
* @param workflowRunId optional workflow run id for lookback support
|
|
2839
2920
|
* @returns notify response which has event id, event data and list of waiters which were notified
|
|
2840
2921
|
*/
|
|
2841
|
-
async notify(stepName, eventId, eventData) {
|
|
2922
|
+
async notify(stepName, eventId, eventData, workflowRunId) {
|
|
2842
2923
|
return await this.addStep(
|
|
2843
|
-
new LazyNotifyStep(this, stepName, eventId, eventData, this.qstashClient.http)
|
|
2924
|
+
new LazyNotifyStep(this, stepName, eventId, eventData, this.qstashClient.http, workflowRunId)
|
|
2844
2925
|
);
|
|
2845
2926
|
}
|
|
2846
2927
|
async invoke(stepName, settings) {
|
|
@@ -2868,7 +2949,14 @@ var WorkflowContext = class {
|
|
|
2868
2949
|
* DisabledWorkflowContext.
|
|
2869
2950
|
*/
|
|
2870
2951
|
async addStep(step) {
|
|
2871
|
-
|
|
2952
|
+
try {
|
|
2953
|
+
return await this.executor.addStep(step);
|
|
2954
|
+
} catch (error) {
|
|
2955
|
+
if (isInstanceOf(error, import_qstash9.QstashError) && error.status === 412) {
|
|
2956
|
+
throw new WorkflowNonRetryableError(error.message);
|
|
2957
|
+
}
|
|
2958
|
+
throw error;
|
|
2959
|
+
}
|
|
2872
2960
|
}
|
|
2873
2961
|
get api() {
|
|
2874
2962
|
return new WorkflowApi({
|
|
@@ -2877,214 +2965,8 @@ var WorkflowContext = class {
|
|
|
2877
2965
|
}
|
|
2878
2966
|
};
|
|
2879
2967
|
|
|
2880
|
-
// src/dev-server.ts
|
|
2881
|
-
var import_child_process = require("child_process");
|
|
2882
|
-
var import_fs = require("fs");
|
|
2883
|
-
var import_https = require("https");
|
|
2884
|
-
var import_http = require("http");
|
|
2885
|
-
var import_path = require("path");
|
|
2886
|
-
var import_os = require("os");
|
|
2887
|
-
var DEV_QSTASH_TOKEN = "eyJVc2VySUQiOiJkZWZhdWx0VXNlciIsIlBhc3N3b3JkIjoiZGVmYXVsdFBhc3N3b3JkIn0=";
|
|
2888
|
-
var DEV_QSTASH_CURRENT_SIGNING_KEY = "sig_7kYjw48mhY7kAjqNGcy6cr29RJ6r";
|
|
2889
|
-
var DEV_QSTASH_NEXT_SIGNING_KEY = "sig_5ZB6DVzB1wjE8S6rZ7eenA8Pdnhs";
|
|
2890
|
-
function getDevCredentials(port) {
|
|
2891
|
-
return {
|
|
2892
|
-
QSTASH_URL: `http://localhost:${port}`,
|
|
2893
|
-
QSTASH_TOKEN: DEV_QSTASH_TOKEN,
|
|
2894
|
-
QSTASH_CURRENT_SIGNING_KEY: DEV_QSTASH_CURRENT_SIGNING_KEY,
|
|
2895
|
-
QSTASH_NEXT_SIGNING_KEY: DEV_QSTASH_NEXT_SIGNING_KEY
|
|
2896
|
-
};
|
|
2897
|
-
}
|
|
2898
|
-
var CACHE_DIR = (0, import_path.join)("node_modules", ".cache", "upstash");
|
|
2899
|
-
function getPlatformArch() {
|
|
2900
|
-
const platform = process.platform === "darwin" ? "darwin" : "linux";
|
|
2901
|
-
const arch = process.arch === "arm64" ? "arm64" : "amd64";
|
|
2902
|
-
return { platform, arch };
|
|
2903
|
-
}
|
|
2904
|
-
function httpsGet(url) {
|
|
2905
|
-
return new Promise((resolve, reject) => {
|
|
2906
|
-
const request = (currentUrl) => {
|
|
2907
|
-
(0, import_https.get)(currentUrl, { headers: { "User-Agent": "upstash-workflow" } }, (res) => {
|
|
2908
|
-
if (res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
2909
|
-
request(res.headers.location);
|
|
2910
|
-
return;
|
|
2911
|
-
}
|
|
2912
|
-
if (res.statusCode && res.statusCode >= 400) {
|
|
2913
|
-
reject(new Error(`HTTP ${res.statusCode} fetching ${currentUrl}`));
|
|
2914
|
-
return;
|
|
2915
|
-
}
|
|
2916
|
-
const chunks = [];
|
|
2917
|
-
res.on("data", (chunk) => chunks.push(chunk));
|
|
2918
|
-
res.on("end", () => resolve(Buffer.concat(chunks)));
|
|
2919
|
-
res.on("error", reject);
|
|
2920
|
-
}).on("error", reject);
|
|
2921
|
-
};
|
|
2922
|
-
request(url);
|
|
2923
|
-
});
|
|
2924
|
-
}
|
|
2925
|
-
function downloadToFile(url, dest) {
|
|
2926
|
-
return new Promise((resolve, reject) => {
|
|
2927
|
-
const request = (currentUrl) => {
|
|
2928
|
-
(0, import_https.get)(currentUrl, { headers: { "User-Agent": "upstash-workflow" } }, (res) => {
|
|
2929
|
-
if (res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
2930
|
-
request(res.headers.location);
|
|
2931
|
-
return;
|
|
2932
|
-
}
|
|
2933
|
-
if (res.statusCode && res.statusCode >= 400) {
|
|
2934
|
-
reject(new Error(`HTTP ${res.statusCode} downloading ${currentUrl}`));
|
|
2935
|
-
return;
|
|
2936
|
-
}
|
|
2937
|
-
const file = (0, import_fs.createWriteStream)(dest);
|
|
2938
|
-
res.pipe(file);
|
|
2939
|
-
file.on("finish", () => {
|
|
2940
|
-
file.close(() => resolve());
|
|
2941
|
-
});
|
|
2942
|
-
file.on("error", reject);
|
|
2943
|
-
}).on("error", reject);
|
|
2944
|
-
};
|
|
2945
|
-
request(url);
|
|
2946
|
-
});
|
|
2947
|
-
}
|
|
2948
|
-
async function resolveLatestVersion() {
|
|
2949
|
-
const data = await httpsGet("https://api.github.com/repos/upstash/qstash-cli/releases/latest");
|
|
2950
|
-
const json = JSON.parse(data.toString());
|
|
2951
|
-
return json.tag_name;
|
|
2952
|
-
}
|
|
2953
|
-
async function ensureBinary() {
|
|
2954
|
-
const version = await resolveLatestVersion();
|
|
2955
|
-
const cacheDir = (0, import_path.join)(CACHE_DIR, `qstash-server-${version}`);
|
|
2956
|
-
const binaryPath = (0, import_path.join)(cacheDir, "qstash");
|
|
2957
|
-
if ((0, import_fs.existsSync)(binaryPath)) {
|
|
2958
|
-
return binaryPath;
|
|
2959
|
-
}
|
|
2960
|
-
const { platform, arch } = getPlatformArch();
|
|
2961
|
-
const downloadUrl = `https://artifacts.upstash.com/qstash/versions/${version}/qstash-server_${version}_${platform}_${arch}.tar.gz`;
|
|
2962
|
-
console.log(`[workflow-dev] Downloading QStash server...`);
|
|
2963
|
-
(0, import_fs.mkdirSync)(cacheDir, { recursive: true });
|
|
2964
|
-
const tempFile = (0, import_path.join)((0, import_os.tmpdir)(), `qstash-server-${version}-${Date.now()}.tar.gz`);
|
|
2965
|
-
await downloadToFile(downloadUrl, tempFile);
|
|
2966
|
-
(0, import_child_process.execSync)(`tar -xzf "${tempFile}" -C "${cacheDir}"`);
|
|
2967
|
-
(0, import_fs.chmodSync)(binaryPath, 493);
|
|
2968
|
-
return binaryPath;
|
|
2969
|
-
}
|
|
2970
|
-
function startServer(binaryPath, port) {
|
|
2971
|
-
return new Promise((resolve, reject) => {
|
|
2972
|
-
const child = (0, import_child_process.spawn)(binaryPath, ["dev", "-port", String(port)], {
|
|
2973
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
2974
|
-
});
|
|
2975
|
-
let resolved = false;
|
|
2976
|
-
const cleanup = () => {
|
|
2977
|
-
if (!child.killed) {
|
|
2978
|
-
child.kill("SIGTERM");
|
|
2979
|
-
}
|
|
2980
|
-
};
|
|
2981
|
-
process.on("exit", cleanup);
|
|
2982
|
-
process.on("SIGINT", () => {
|
|
2983
|
-
cleanup();
|
|
2984
|
-
process.exit(0);
|
|
2985
|
-
});
|
|
2986
|
-
process.on("SIGTERM", () => {
|
|
2987
|
-
cleanup();
|
|
2988
|
-
process.exit(0);
|
|
2989
|
-
});
|
|
2990
|
-
let stdoutBuffer = "";
|
|
2991
|
-
child.stdout.on("data", (data) => {
|
|
2992
|
-
const text = data.toString();
|
|
2993
|
-
stdoutBuffer += text;
|
|
2994
|
-
const lines = stdoutBuffer.split("\n");
|
|
2995
|
-
stdoutBuffer = lines.pop() ?? "";
|
|
2996
|
-
for (const line of lines) {
|
|
2997
|
-
if (line.match(/runn+ing at/) && !resolved) {
|
|
2998
|
-
resolved = true;
|
|
2999
|
-
const creds = getDevCredentials(port);
|
|
3000
|
-
console.log(`[workflow-dev] QStash server running at ${creds.QSTASH_URL}`);
|
|
3001
|
-
console.log(
|
|
3002
|
-
`[workflow-dev] View logs at \x1B[1;32mhttps://console.upstash.com/workflow/local-mode-user/logs\x1B[0m`
|
|
3003
|
-
);
|
|
3004
|
-
resolve(cleanup);
|
|
3005
|
-
}
|
|
3006
|
-
}
|
|
3007
|
-
});
|
|
3008
|
-
child.stderr.on("data", (data) => {
|
|
3009
|
-
const text = data.toString();
|
|
3010
|
-
if (!resolved) {
|
|
3011
|
-
process.stderr.write(`[workflow-dev] ${text}`);
|
|
3012
|
-
}
|
|
3013
|
-
});
|
|
3014
|
-
child.on("error", (err2) => {
|
|
3015
|
-
if (!resolved) {
|
|
3016
|
-
reject(new Error(`[workflow-dev] Failed to start QStash server: ${err2.message}`));
|
|
3017
|
-
}
|
|
3018
|
-
});
|
|
3019
|
-
child.on("exit", (code) => {
|
|
3020
|
-
if (!resolved) {
|
|
3021
|
-
reject(
|
|
3022
|
-
new Error(`[workflow-dev] QStash server exited with code ${code} before becoming ready`)
|
|
3023
|
-
);
|
|
3024
|
-
}
|
|
3025
|
-
});
|
|
3026
|
-
setTimeout(() => {
|
|
3027
|
-
if (!resolved) {
|
|
3028
|
-
cleanup();
|
|
3029
|
-
reject(new Error("[workflow-dev] QStash server did not become ready within 30 seconds"));
|
|
3030
|
-
}
|
|
3031
|
-
}, 3e4);
|
|
3032
|
-
});
|
|
3033
|
-
}
|
|
3034
|
-
function isDevServerRunning(port) {
|
|
3035
|
-
return new Promise((resolve) => {
|
|
3036
|
-
const req = (0, import_http.get)(
|
|
3037
|
-
`http://127.0.0.1:${port}/v2/keys`,
|
|
3038
|
-
{
|
|
3039
|
-
headers: { Authorization: `Bearer ${DEV_QSTASH_TOKEN}` },
|
|
3040
|
-
timeout: 2e3
|
|
3041
|
-
},
|
|
3042
|
-
(res) => {
|
|
3043
|
-
if (res.statusCode !== 200) {
|
|
3044
|
-
resolve(false);
|
|
3045
|
-
return;
|
|
3046
|
-
}
|
|
3047
|
-
const chunks = [];
|
|
3048
|
-
res.on("data", (chunk) => chunks.push(chunk));
|
|
3049
|
-
res.on("end", () => {
|
|
3050
|
-
try {
|
|
3051
|
-
const body = JSON.parse(Buffer.concat(chunks).toString());
|
|
3052
|
-
resolve(
|
|
3053
|
-
body.current === DEV_QSTASH_CURRENT_SIGNING_KEY && body.next === DEV_QSTASH_NEXT_SIGNING_KEY
|
|
3054
|
-
);
|
|
3055
|
-
} catch {
|
|
3056
|
-
resolve(false);
|
|
3057
|
-
}
|
|
3058
|
-
});
|
|
3059
|
-
res.on("error", () => resolve(false));
|
|
3060
|
-
}
|
|
3061
|
-
);
|
|
3062
|
-
req.on("error", () => resolve(false));
|
|
3063
|
-
req.on("timeout", () => {
|
|
3064
|
-
req.destroy();
|
|
3065
|
-
resolve(false);
|
|
3066
|
-
});
|
|
3067
|
-
});
|
|
3068
|
-
}
|
|
3069
|
-
var serverPromise = null;
|
|
3070
|
-
var serverCleanup = null;
|
|
3071
|
-
function ensureDevServer(environment) {
|
|
3072
|
-
if (!serverPromise) {
|
|
3073
|
-
const port = Number(environment.WORKFLOW_DEV_PORT) || 8080;
|
|
3074
|
-
serverPromise = isDevServerRunning(port).then((alreadyRunning) => {
|
|
3075
|
-
if (alreadyRunning) {
|
|
3076
|
-
return;
|
|
3077
|
-
}
|
|
3078
|
-
return ensureBinary().then((binaryPath) => startServer(binaryPath, port)).then((cleanup) => {
|
|
3079
|
-
serverCleanup = cleanup;
|
|
3080
|
-
});
|
|
3081
|
-
});
|
|
3082
|
-
}
|
|
3083
|
-
return serverPromise;
|
|
3084
|
-
}
|
|
3085
|
-
|
|
3086
2968
|
// src/serve/authorization.ts
|
|
3087
|
-
var
|
|
2969
|
+
var import_qstash10 = require("@upstash/qstash");
|
|
3088
2970
|
var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowContext {
|
|
3089
2971
|
static disabledMessage = "disabled-qstash-worklfow-run";
|
|
3090
2972
|
disabled = true;
|
|
@@ -3116,11 +2998,12 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
|
|
|
3116
2998
|
*/
|
|
3117
2999
|
static async tryAuthentication(routeFunction, context) {
|
|
3118
3000
|
const disabledContext = new _DisabledWorkflowContext({
|
|
3119
|
-
qstashClient: new
|
|
3001
|
+
qstashClient: new import_qstash10.Client({
|
|
3120
3002
|
baseUrl: "disabled-client",
|
|
3121
3003
|
token: "disabled-client"
|
|
3122
3004
|
}),
|
|
3123
3005
|
workflowRunId: context.workflowRunId,
|
|
3006
|
+
workflowRunCreatedAt: context.workflowRunCreatedAt,
|
|
3124
3007
|
headers: context.headers,
|
|
3125
3008
|
steps: [],
|
|
3126
3009
|
url: context.url,
|
|
@@ -3322,7 +3205,9 @@ var handleFailure = async ({
|
|
|
3322
3205
|
return ok({ result: "failure-function-undefined" });
|
|
3323
3206
|
}
|
|
3324
3207
|
try {
|
|
3325
|
-
const { status, header, body, url, sourceBody, workflowRunId } = JSON.parse(
|
|
3208
|
+
const { status, header, body, url, sourceBody, workflowRunId, workflowCreatedAt } = JSON.parse(
|
|
3209
|
+
requestPayload
|
|
3210
|
+
);
|
|
3326
3211
|
const decodedBody = body ? decodeBase64(body) : "{}";
|
|
3327
3212
|
let errorMessage = "";
|
|
3328
3213
|
let failStack = "";
|
|
@@ -3351,6 +3236,7 @@ var handleFailure = async ({
|
|
|
3351
3236
|
telemetry: void 0,
|
|
3352
3237
|
// not going to make requests in authentication check
|
|
3353
3238
|
label: userHeaders.get(WORKFLOW_LABEL_HEADER) ?? void 0,
|
|
3239
|
+
workflowRunCreatedAt: workflowCreatedAt,
|
|
3354
3240
|
middlewareManager: void 0
|
|
3355
3241
|
});
|
|
3356
3242
|
const authCheck = await DisabledWorkflowContext.tryAuthentication(
|
|
@@ -3379,7 +3265,7 @@ var handleFailure = async ({
|
|
|
3379
3265
|
};
|
|
3380
3266
|
|
|
3381
3267
|
// src/serve/multi-region/handlers.ts
|
|
3382
|
-
var
|
|
3268
|
+
var import_qstash11 = require("@upstash/qstash");
|
|
3383
3269
|
|
|
3384
3270
|
// src/serve/multi-region/utils.ts
|
|
3385
3271
|
var VALID_REGIONS = ["EU_CENTRAL_1", "US_EAST_1"];
|
|
@@ -3444,7 +3330,7 @@ var getHandlersForRequest = (qstashHandlers, regionHeader, isFirstInvocation) =>
|
|
|
3444
3330
|
};
|
|
3445
3331
|
var createRegionalHandler = (environment, receiverConfig, region, clientOptions) => {
|
|
3446
3332
|
const clientEnv = readClientEnvironmentVariables(environment, region);
|
|
3447
|
-
const client = new
|
|
3333
|
+
const client = new import_qstash11.Client({
|
|
3448
3334
|
...clientOptions,
|
|
3449
3335
|
baseUrl: clientEnv.QSTASH_URL,
|
|
3450
3336
|
token: clientEnv.QSTASH_TOKEN
|
|
@@ -3494,7 +3380,7 @@ var getQStashHandlers = ({
|
|
|
3494
3380
|
return {
|
|
3495
3381
|
mode: "single-region",
|
|
3496
3382
|
handlers: {
|
|
3497
|
-
client: qstashClientOption && "http" in qstashClientOption ? qstashClientOption : new
|
|
3383
|
+
client: qstashClientOption && "http" in qstashClientOption ? qstashClientOption : new import_qstash11.Client({
|
|
3498
3384
|
...qstashClientOption,
|
|
3499
3385
|
baseUrl: environment.QSTASH_URL,
|
|
3500
3386
|
token: environment.QSTASH_TOKEN
|
|
@@ -3510,7 +3396,7 @@ var getReceiver = (environment, receiverConfig, region) => {
|
|
|
3510
3396
|
return void 0;
|
|
3511
3397
|
}
|
|
3512
3398
|
const receiverEnv = readReceiverEnvironmentVariables(environment, region);
|
|
3513
|
-
return receiverEnv.QSTASH_CURRENT_SIGNING_KEY && receiverEnv.QSTASH_NEXT_SIGNING_KEY ? new
|
|
3399
|
+
return receiverEnv.QSTASH_CURRENT_SIGNING_KEY && receiverEnv.QSTASH_NEXT_SIGNING_KEY ? new import_qstash11.Receiver({
|
|
3514
3400
|
currentSigningKey: receiverEnv.QSTASH_CURRENT_SIGNING_KEY,
|
|
3515
3401
|
nextSigningKey: receiverEnv.QSTASH_NEXT_SIGNING_KEY
|
|
3516
3402
|
}) : void 0;
|
|
@@ -3736,33 +3622,19 @@ var AUTH_FAIL_MESSAGE = `Failed to authenticate Workflow request. If this is une
|
|
|
3736
3622
|
|
|
3737
3623
|
// src/serve/index.ts
|
|
3738
3624
|
var serveBase = (routeFunction, telemetry, options, internalOptions) => {
|
|
3739
|
-
const
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
const
|
|
3751
|
-
options,
|
|
3752
|
-
internalOptions
|
|
3753
|
-
);
|
|
3625
|
+
const {
|
|
3626
|
+
initialPayloadParser,
|
|
3627
|
+
url,
|
|
3628
|
+
failureFunction,
|
|
3629
|
+
baseUrl,
|
|
3630
|
+
env,
|
|
3631
|
+
disableTelemetry,
|
|
3632
|
+
middlewares,
|
|
3633
|
+
internal
|
|
3634
|
+
} = processOptions(options, internalOptions);
|
|
3635
|
+
telemetry = disableTelemetry ? void 0 : telemetry;
|
|
3636
|
+
const { generateResponse: responseGenerator, useJSONContent } = internal;
|
|
3754
3637
|
const handler = async (request, middlewareManager) => {
|
|
3755
|
-
const {
|
|
3756
|
-
initialPayloadParser,
|
|
3757
|
-
url,
|
|
3758
|
-
failureFunction,
|
|
3759
|
-
baseUrl,
|
|
3760
|
-
env,
|
|
3761
|
-
disableTelemetry: optDisableTelemetry,
|
|
3762
|
-
internal
|
|
3763
|
-
} = resolvedOptions;
|
|
3764
|
-
const currentTelemetry = optDisableTelemetry ? void 0 : telemetry;
|
|
3765
|
-
const { generateResponse: responseGenerator, useJSONContent } = internal;
|
|
3766
3638
|
await middlewareManager.dispatchDebug("onInfo", {
|
|
3767
3639
|
info: `Received request for workflow execution.`
|
|
3768
3640
|
});
|
|
@@ -3842,6 +3714,7 @@ var serveBase = (routeFunction, telemetry, options, internalOptions) => {
|
|
|
3842
3714
|
}
|
|
3843
3715
|
const invokeCount = Number(request.headers.get(WORKFLOW_INVOKE_COUNT_HEADER) ?? "0");
|
|
3844
3716
|
const label = request.headers.get(WORKFLOW_LABEL_HEADER) ?? void 0;
|
|
3717
|
+
const workflowRunCreatedAt = request.headers.get(WORKFLOW_CREATED_AT_HEADER);
|
|
3845
3718
|
const workflowContext = new WorkflowContext({
|
|
3846
3719
|
qstashClient: regionalClient,
|
|
3847
3720
|
workflowRunId,
|
|
@@ -3850,9 +3723,10 @@ var serveBase = (routeFunction, telemetry, options, internalOptions) => {
|
|
|
3850
3723
|
steps,
|
|
3851
3724
|
url: workflowUrl,
|
|
3852
3725
|
env,
|
|
3853
|
-
telemetry
|
|
3726
|
+
telemetry,
|
|
3854
3727
|
invokeCount,
|
|
3855
3728
|
label,
|
|
3729
|
+
workflowRunCreatedAt: Number(workflowRunCreatedAt),
|
|
3856
3730
|
middlewareManager
|
|
3857
3731
|
});
|
|
3858
3732
|
const authCheck = await DisabledWorkflowContext.tryAuthentication(
|
|
@@ -3876,7 +3750,7 @@ var serveBase = (routeFunction, telemetry, options, internalOptions) => {
|
|
|
3876
3750
|
requestPayload: rawInitialPayload,
|
|
3877
3751
|
client: regionalClient,
|
|
3878
3752
|
workflowUrl,
|
|
3879
|
-
telemetry
|
|
3753
|
+
telemetry,
|
|
3880
3754
|
middlewareManager
|
|
3881
3755
|
});
|
|
3882
3756
|
if (callReturnCheck.isErr()) {
|
|
@@ -3885,7 +3759,7 @@ var serveBase = (routeFunction, telemetry, options, internalOptions) => {
|
|
|
3885
3759
|
const result = isFirstInvocation ? await triggerFirstInvocation({
|
|
3886
3760
|
workflowContext,
|
|
3887
3761
|
useJSONContent,
|
|
3888
|
-
telemetry
|
|
3762
|
+
telemetry,
|
|
3889
3763
|
invokeCount,
|
|
3890
3764
|
middlewareManager,
|
|
3891
3765
|
unknownSdk
|
|
@@ -3953,9 +3827,7 @@ var serveBase = (routeFunction, telemetry, options, internalOptions) => {
|
|
|
3953
3827
|
);
|
|
3954
3828
|
};
|
|
3955
3829
|
const safeHandler = async (request) => {
|
|
3956
|
-
const middlewareManager = new MiddlewareManager(
|
|
3957
|
-
resolvedOptions.middlewares
|
|
3958
|
-
);
|
|
3830
|
+
const middlewareManager = new MiddlewareManager(middlewares);
|
|
3959
3831
|
try {
|
|
3960
3832
|
return await handler(request, middlewareManager);
|
|
3961
3833
|
} catch (error) {
|
|
@@ -3985,10 +3857,22 @@ var serve = (routeFunction, options) => {
|
|
|
3985
3857
|
};
|
|
3986
3858
|
|
|
3987
3859
|
// src/client/index.ts
|
|
3988
|
-
var
|
|
3860
|
+
var import_qstash12 = require("@upstash/qstash");
|
|
3989
3861
|
|
|
3990
3862
|
// src/client/dlq.ts
|
|
3991
|
-
|
|
3863
|
+
function buildResumeRestartHeaders(options) {
|
|
3864
|
+
const headers = {};
|
|
3865
|
+
if (options?.flowControl) {
|
|
3866
|
+
const { flowControlKey, flowControlValue } = prepareFlowControl(options.flowControl);
|
|
3867
|
+
headers["Upstash-Flow-Control-Key"] = flowControlKey;
|
|
3868
|
+
headers["Upstash-Flow-Control-Value"] = flowControlValue;
|
|
3869
|
+
}
|
|
3870
|
+
if (options?.retries !== void 0) {
|
|
3871
|
+
headers["Upstash-Retries"] = options.retries.toString();
|
|
3872
|
+
}
|
|
3873
|
+
return headers;
|
|
3874
|
+
}
|
|
3875
|
+
var DLQ = class {
|
|
3992
3876
|
constructor(client) {
|
|
3993
3877
|
this.client = client;
|
|
3994
3878
|
}
|
|
@@ -4011,40 +3895,66 @@ var DLQ = class _DLQ {
|
|
|
4011
3895
|
*/
|
|
4012
3896
|
async list(parameters) {
|
|
4013
3897
|
const { cursor, count, filter } = parameters || {};
|
|
4014
|
-
return
|
|
4015
|
-
|
|
4016
|
-
|
|
4017
|
-
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
-
|
|
4021
|
-
|
|
4022
|
-
|
|
4023
|
-
|
|
3898
|
+
return normalizeCursor(
|
|
3899
|
+
await this.client.http.request({
|
|
3900
|
+
path: ["v2", "dlq"],
|
|
3901
|
+
method: "GET",
|
|
3902
|
+
query: {
|
|
3903
|
+
cursor,
|
|
3904
|
+
count,
|
|
3905
|
+
...filter,
|
|
3906
|
+
source: "workflow"
|
|
3907
|
+
}
|
|
3908
|
+
})
|
|
3909
|
+
);
|
|
4024
3910
|
}
|
|
4025
|
-
async resume(
|
|
4026
|
-
|
|
4027
|
-
|
|
4028
|
-
|
|
4029
|
-
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
|
|
4033
|
-
|
|
3911
|
+
async resume(request, options) {
|
|
3912
|
+
if (typeof request === "object" && !Array.isArray(request) && "dlqId" in request) {
|
|
3913
|
+
const { dlqId, flowControl, retries } = request;
|
|
3914
|
+
const dlqIds = Array.isArray(dlqId) ? dlqId : [dlqId];
|
|
3915
|
+
const { workflowRuns } = await this.client.http.request({
|
|
3916
|
+
path: ["v2", "workflows", "dlq", "resume"],
|
|
3917
|
+
query: { dlqIds },
|
|
3918
|
+
method: "POST",
|
|
3919
|
+
headers: buildResumeRestartHeaders({ flowControl, retries })
|
|
3920
|
+
});
|
|
3921
|
+
return Array.isArray(dlqId) ? workflowRuns : workflowRuns[0];
|
|
4034
3922
|
}
|
|
4035
|
-
|
|
3923
|
+
if (typeof request === "string") request = [request];
|
|
3924
|
+
if (Array.isArray(request) && request.length === 0) return { workflowRuns: [] };
|
|
3925
|
+
const filters = Array.isArray(request) ? { dlqIds: request } : request;
|
|
3926
|
+
return normalizeCursor(
|
|
3927
|
+
await this.client.http.request({
|
|
3928
|
+
path: ["v2", "workflows", "dlq", "resume"],
|
|
3929
|
+
query: buildBulkActionQueryParameters(filters),
|
|
3930
|
+
method: "POST",
|
|
3931
|
+
headers: buildResumeRestartHeaders(options)
|
|
3932
|
+
})
|
|
3933
|
+
);
|
|
4036
3934
|
}
|
|
4037
|
-
async restart(
|
|
4038
|
-
|
|
4039
|
-
|
|
4040
|
-
|
|
4041
|
-
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
|
-
|
|
3935
|
+
async restart(request, options) {
|
|
3936
|
+
if (typeof request === "object" && !Array.isArray(request) && "dlqId" in request) {
|
|
3937
|
+
const { dlqId, flowControl, retries } = request;
|
|
3938
|
+
const dlqIds = Array.isArray(dlqId) ? dlqId : [dlqId];
|
|
3939
|
+
const { workflowRuns } = await this.client.http.request({
|
|
3940
|
+
path: ["v2", "workflows", "dlq", "restart"],
|
|
3941
|
+
query: { dlqIds },
|
|
3942
|
+
method: "POST",
|
|
3943
|
+
headers: buildResumeRestartHeaders({ flowControl, retries })
|
|
3944
|
+
});
|
|
3945
|
+
return Array.isArray(dlqId) ? workflowRuns : workflowRuns[0];
|
|
4046
3946
|
}
|
|
4047
|
-
|
|
3947
|
+
if (typeof request === "string") request = [request];
|
|
3948
|
+
if (Array.isArray(request) && request.length === 0) return { workflowRuns: [] };
|
|
3949
|
+
const filters = Array.isArray(request) ? { dlqIds: request } : request;
|
|
3950
|
+
return normalizeCursor(
|
|
3951
|
+
await this.client.http.request({
|
|
3952
|
+
path: ["v2", "workflows", "dlq", "restart"],
|
|
3953
|
+
query: buildBulkActionQueryParameters(filters),
|
|
3954
|
+
method: "POST",
|
|
3955
|
+
headers: buildResumeRestartHeaders(options)
|
|
3956
|
+
})
|
|
3957
|
+
);
|
|
4048
3958
|
}
|
|
4049
3959
|
/**
|
|
4050
3960
|
* Retry the failure callback of a workflow run whose failureUrl/failureFunction
|
|
@@ -4061,148 +3971,64 @@ var DLQ = class _DLQ {
|
|
|
4061
3971
|
return response;
|
|
4062
3972
|
}
|
|
4063
3973
|
/**
|
|
4064
|
-
*
|
|
3974
|
+
* Delete DLQ messages.
|
|
4065
3975
|
*
|
|
4066
|
-
*
|
|
4067
|
-
|
|
4068
|
-
|
|
4069
|
-
|
|
4070
|
-
|
|
4071
|
-
if (flowControl) {
|
|
4072
|
-
const { flowControlKey, flowControlValue } = prepareFlowControl(flowControl);
|
|
4073
|
-
headers["Upstash-Flow-Control-Key"] = flowControlKey;
|
|
4074
|
-
headers["Upstash-Flow-Control-Value"] = flowControlValue;
|
|
4075
|
-
}
|
|
4076
|
-
if (retries !== void 0) {
|
|
4077
|
-
headers["Upstash-Retries"] = retries.toString();
|
|
4078
|
-
}
|
|
4079
|
-
return {
|
|
4080
|
-
queryParams: _DLQ.getDlqIdQueryParameter(dlqId),
|
|
4081
|
-
headers
|
|
4082
|
-
};
|
|
4083
|
-
}
|
|
4084
|
-
/**
|
|
4085
|
-
* Converts DLQ ID(s) to query parameter string.
|
|
3976
|
+
* Can be called with:
|
|
3977
|
+
* - A single dlqId: `delete("id")`
|
|
3978
|
+
* - An array of dlqIds: `delete(["id1", "id2"])`
|
|
3979
|
+
* - A filter object: `delete({ filter: { label: "my-label", fromDate: 1640995200000 } })`
|
|
3980
|
+
* - To target all entries: `delete({ all: true })`
|
|
4086
3981
|
*
|
|
4087
|
-
*
|
|
3982
|
+
* Processes up to `count` messages per call (defaults to 100).
|
|
3983
|
+
* Call in a loop until cursor is undefined to process all:
|
|
3984
|
+
*
|
|
3985
|
+
* ```ts
|
|
3986
|
+
* let cursor: string | undefined;
|
|
3987
|
+
* do {
|
|
3988
|
+
* const result = await client.dlq.delete({ all: true, count: 100, cursor });
|
|
3989
|
+
* cursor = result.cursor;
|
|
3990
|
+
* } while (cursor);
|
|
3991
|
+
* ```
|
|
4088
3992
|
*/
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
3993
|
+
async delete(request) {
|
|
3994
|
+
if (typeof request === "string") request = [request];
|
|
3995
|
+
if (Array.isArray(request) && request.length === 0) return { deleted: 0 };
|
|
3996
|
+
const filters = Array.isArray(request) ? { dlqIds: request } : request;
|
|
3997
|
+
return normalizeCursor(
|
|
3998
|
+
await this.client.http.request({
|
|
3999
|
+
path: ["v2", "workflows", "dlq"],
|
|
4000
|
+
method: "DELETE",
|
|
4001
|
+
query: buildBulkActionQueryParameters(filters)
|
|
4002
|
+
})
|
|
4003
|
+
);
|
|
4093
4004
|
}
|
|
4094
4005
|
};
|
|
4095
4006
|
|
|
4096
4007
|
// src/client/index.ts
|
|
4097
4008
|
var Client4 = class {
|
|
4098
4009
|
client;
|
|
4099
|
-
devMode;
|
|
4100
4010
|
constructor(clientConfig) {
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
const
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
"[Upstash Workflow] Client requires a token. Either pass { token: '...' } or set WORKFLOW_DEV=true."
|
|
4114
|
-
);
|
|
4115
|
-
} else {
|
|
4116
|
-
this.client = new import_qstash11.Client(clientConfig);
|
|
4117
|
-
}
|
|
4118
|
-
}
|
|
4119
|
-
/**
|
|
4120
|
-
* In dev mode, ensures the dev server is running before making requests.
|
|
4121
|
-
* If a server is already listening on the port (started by another process
|
|
4122
|
-
* or by a platform's serve()), this is a no-op.
|
|
4123
|
-
*/
|
|
4124
|
-
async ensureReady() {
|
|
4125
|
-
if (this.devMode) {
|
|
4126
|
-
await ensureDevServer(process.env);
|
|
4127
|
-
}
|
|
4128
|
-
}
|
|
4129
|
-
/**
|
|
4130
|
-
* Cancel an ongoing workflow
|
|
4131
|
-
*
|
|
4132
|
-
* Returns true if workflow is canceled succesfully. Otherwise, throws error.
|
|
4133
|
-
*
|
|
4134
|
-
* There are multiple ways you can cancel workflows:
|
|
4135
|
-
* - pass one or more workflow run ids to cancel them
|
|
4136
|
-
* - pass a workflow url to cancel all runs starting with this url
|
|
4137
|
-
* - cancel all pending or active workflow runs
|
|
4138
|
-
*
|
|
4139
|
-
* ### Cancel a set of workflow runs
|
|
4140
|
-
*
|
|
4141
|
-
* ```ts
|
|
4142
|
-
* // cancel a single workflow
|
|
4143
|
-
* await client.cancel({ ids: "<WORKFLOW_RUN_ID>" })
|
|
4144
|
-
*
|
|
4145
|
-
* // cancel a set of workflow runs
|
|
4146
|
-
* await client.cancel({ ids: [
|
|
4147
|
-
* "<WORKFLOW_RUN_ID_1>",
|
|
4148
|
-
* "<WORKFLOW_RUN_ID_2>",
|
|
4149
|
-
* ]})
|
|
4150
|
-
* ```
|
|
4151
|
-
*
|
|
4152
|
-
* ### Cancel workflows starting with a url
|
|
4153
|
-
*
|
|
4154
|
-
* If you have an endpoint called `https://your-endpoint.com` and you
|
|
4155
|
-
* want to cancel all workflow runs on it, you can use `urlStartingWith`.
|
|
4156
|
-
*
|
|
4157
|
-
* Note that this will cancel workflows in all endpoints under
|
|
4158
|
-
* `https://your-endpoint.com`.
|
|
4159
|
-
*
|
|
4160
|
-
* ```ts
|
|
4161
|
-
* await client.cancel({ urlStartingWith: "https://your-endpoint.com" })
|
|
4162
|
-
* ```
|
|
4163
|
-
*
|
|
4164
|
-
* ### Cancel *all* workflows
|
|
4165
|
-
*
|
|
4166
|
-
* To cancel all pending and currently running workflows, you can
|
|
4167
|
-
* do it like this:
|
|
4168
|
-
*
|
|
4169
|
-
* ```ts
|
|
4170
|
-
* await client.cancel({ all: true })
|
|
4171
|
-
* ```
|
|
4172
|
-
*
|
|
4173
|
-
* @param ids run id of the workflow to delete
|
|
4174
|
-
* @param urlStartingWith cancel workflows starting with this url. Will be ignored
|
|
4175
|
-
* if `ids` parameter is set.
|
|
4176
|
-
* @param all set to true in order to cancel all workflows. Will be ignored
|
|
4177
|
-
* if `ids` or `urlStartingWith` parameters are set.
|
|
4178
|
-
* @returns true if workflow is succesfully deleted. Otherwise throws QStashError
|
|
4179
|
-
*/
|
|
4180
|
-
async cancel({
|
|
4181
|
-
ids,
|
|
4182
|
-
urlStartingWith,
|
|
4183
|
-
all
|
|
4184
|
-
}) {
|
|
4185
|
-
await this.ensureReady();
|
|
4186
|
-
let body;
|
|
4187
|
-
if (ids) {
|
|
4188
|
-
const runIdArray = typeof ids === "string" ? [ids] : ids;
|
|
4189
|
-
body = JSON.stringify({ workflowRunIds: runIdArray });
|
|
4190
|
-
} else if (urlStartingWith) {
|
|
4191
|
-
body = JSON.stringify({ workflowUrl: urlStartingWith });
|
|
4192
|
-
} else if (all) {
|
|
4193
|
-
body = "{}";
|
|
4194
|
-
} else {
|
|
4195
|
-
throw new TypeError("The `cancel` method cannot be called without any options.");
|
|
4011
|
+
this.client = new import_qstash12.Client(clientConfig);
|
|
4012
|
+
}
|
|
4013
|
+
async cancel(request) {
|
|
4014
|
+
if (typeof request === "object" && !Array.isArray(request) && ("ids" in request || "urlStartingWith" in request)) {
|
|
4015
|
+
const legacy = request;
|
|
4016
|
+
if (legacy.ids) {
|
|
4017
|
+
const ids = typeof legacy.ids === "string" ? [legacy.ids] : legacy.ids;
|
|
4018
|
+
return this.cancel(ids);
|
|
4019
|
+
}
|
|
4020
|
+
if (legacy.urlStartingWith) {
|
|
4021
|
+
return this.cancel({ filter: { workflowUrlStartingWith: legacy.urlStartingWith } });
|
|
4022
|
+
}
|
|
4196
4023
|
}
|
|
4197
|
-
|
|
4024
|
+
if (typeof request === "string") request = [request];
|
|
4025
|
+
if (Array.isArray(request) && request.length === 0) return { cancelled: 0 };
|
|
4026
|
+
const filters = Array.isArray(request) ? { workflowRunIds: request } : request;
|
|
4027
|
+
return await this.client.http.request({
|
|
4198
4028
|
path: ["v2", "workflows", "runs"],
|
|
4199
4029
|
method: "DELETE",
|
|
4200
|
-
|
|
4201
|
-
headers: {
|
|
4202
|
-
"Content-Type": "application/json"
|
|
4203
|
-
}
|
|
4030
|
+
query: buildBulkActionQueryParameters(filters, { translateWorkflowUrl: true })
|
|
4204
4031
|
});
|
|
4205
|
-
return result;
|
|
4206
4032
|
}
|
|
4207
4033
|
/**
|
|
4208
4034
|
* Notify a workflow run waiting for an event
|
|
@@ -4217,15 +4043,26 @@ var Client4 = class {
|
|
|
4217
4043
|
* });
|
|
4218
4044
|
* ```
|
|
4219
4045
|
*
|
|
4046
|
+
* Optionally, you can pass a workflowRunId to enable lookback functionality:
|
|
4047
|
+
*
|
|
4048
|
+
* ```ts
|
|
4049
|
+
* await client.notify({
|
|
4050
|
+
* eventId: "my-event-id",
|
|
4051
|
+
* eventData: "my-data",
|
|
4052
|
+
* workflowRunId: "wfr_123" // enables lookback
|
|
4053
|
+
* });
|
|
4054
|
+
* ```
|
|
4055
|
+
*
|
|
4220
4056
|
* @param eventId event id to notify
|
|
4221
4057
|
* @param eventData data to provide to the workflow
|
|
4058
|
+
* @param workflowRunId optional workflow run id for lookback support
|
|
4222
4059
|
*/
|
|
4223
4060
|
async notify({
|
|
4224
4061
|
eventId,
|
|
4225
|
-
eventData
|
|
4062
|
+
eventData,
|
|
4063
|
+
workflowRunId
|
|
4226
4064
|
}) {
|
|
4227
|
-
await this.
|
|
4228
|
-
return await makeNotifyRequest(this.client.http, eventId, eventData);
|
|
4065
|
+
return await makeNotifyRequest(this.client.http, eventId, eventData, workflowRunId);
|
|
4229
4066
|
}
|
|
4230
4067
|
/**
|
|
4231
4068
|
* Check waiters of an event
|
|
@@ -4242,11 +4079,9 @@ var Client4 = class {
|
|
|
4242
4079
|
* @param eventId event id to check
|
|
4243
4080
|
*/
|
|
4244
4081
|
async getWaiters({ eventId }) {
|
|
4245
|
-
await this.ensureReady();
|
|
4246
4082
|
return await makeGetWaitersRequest(this.client.http, eventId);
|
|
4247
4083
|
}
|
|
4248
4084
|
async trigger(params) {
|
|
4249
|
-
await this.ensureReady();
|
|
4250
4085
|
const isBatchInput = Array.isArray(params);
|
|
4251
4086
|
const options = isBatchInput ? params : [params];
|
|
4252
4087
|
const invocations = options.map((option) => {
|
|
@@ -4263,7 +4098,9 @@ var Client4 = class {
|
|
|
4263
4098
|
url: option.url,
|
|
4264
4099
|
workflowRunId: finalWorkflowRunId,
|
|
4265
4100
|
telemetry: option.disableTelemetry ? void 0 : { sdk: SDK_TELEMETRY },
|
|
4266
|
-
label: option.label
|
|
4101
|
+
label: option.label,
|
|
4102
|
+
workflowRunCreatedAt: Date.now()
|
|
4103
|
+
// pass a timestamp (server will override it)
|
|
4267
4104
|
});
|
|
4268
4105
|
return {
|
|
4269
4106
|
workflowContext: context,
|
|
@@ -4273,7 +4110,8 @@ var Client4 = class {
|
|
|
4273
4110
|
failureUrl,
|
|
4274
4111
|
retries: option.retries,
|
|
4275
4112
|
retryDelay: option.retryDelay,
|
|
4276
|
-
flowControl: option.flowControl
|
|
4113
|
+
flowControl: option.flowControl,
|
|
4114
|
+
redact: option.redact
|
|
4277
4115
|
};
|
|
4278
4116
|
});
|
|
4279
4117
|
const result = await triggerFirstInvocation(invocations);
|
|
@@ -4314,34 +4152,17 @@ var Client4 = class {
|
|
|
4314
4152
|
* ```
|
|
4315
4153
|
*/
|
|
4316
4154
|
async logs(params) {
|
|
4317
|
-
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
urlParams.append("count", count.toString());
|
|
4328
|
-
}
|
|
4329
|
-
if (state) {
|
|
4330
|
-
urlParams.append("state", state);
|
|
4331
|
-
}
|
|
4332
|
-
if (workflowUrl) {
|
|
4333
|
-
urlParams.append("workflowUrl", workflowUrl);
|
|
4334
|
-
}
|
|
4335
|
-
if (workflowCreatedAt) {
|
|
4336
|
-
urlParams.append("workflowCreatedAt", workflowCreatedAt.toString());
|
|
4337
|
-
}
|
|
4338
|
-
if (params?.label) {
|
|
4339
|
-
urlParams.append("label", params.label);
|
|
4340
|
-
}
|
|
4341
|
-
const result = await this.client.http.request({
|
|
4342
|
-
path: ["v2", "workflows", `events?${urlParams.toString()}`]
|
|
4155
|
+
const { cursor, count, filter, ...legacyFilter } = params ?? {};
|
|
4156
|
+
return await this.client.http.request({
|
|
4157
|
+
path: ["v2", "workflows", "events"],
|
|
4158
|
+
query: {
|
|
4159
|
+
groupBy: "workflowRunId",
|
|
4160
|
+
...legacyFilter,
|
|
4161
|
+
cursor,
|
|
4162
|
+
count,
|
|
4163
|
+
...filter
|
|
4164
|
+
}
|
|
4343
4165
|
});
|
|
4344
|
-
return result;
|
|
4345
4166
|
}
|
|
4346
4167
|
get dlq() {
|
|
4347
4168
|
return new DLQ(this.client);
|