@upstash/workflow 1.0.0 → 1.1.0-rc1
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 +173 -23
- package/astro.mjs +1 -1
- package/{chunk-5GWDM6XJ.mjs → chunk-C5HFGF7Q.mjs} +175 -23
- package/cloudflare.d.mts +2 -2
- package/cloudflare.d.ts +2 -2
- package/cloudflare.js +173 -23
- package/cloudflare.mjs +1 -1
- package/express.d.mts +2 -2
- package/express.d.ts +2 -2
- package/express.js +173 -23
- package/express.mjs +1 -1
- package/h3.d.mts +2 -2
- package/h3.d.ts +2 -2
- package/h3.js +173 -23
- package/h3.mjs +1 -1
- package/hono.d.mts +2 -2
- package/hono.d.ts +2 -2
- package/hono.js +173 -23
- package/hono.mjs +1 -1
- package/index.d.mts +28 -3
- package/index.d.ts +28 -3
- package/index.js +175 -30
- package/index.mjs +1 -6
- package/nextjs.d.mts +2 -2
- package/nextjs.d.ts +2 -2
- package/nextjs.js +173 -23
- package/nextjs.mjs +1 -1
- package/package.json +1 -1
- package/{serve-many-qpxb-yr-.d.mts → serve-many-DhB8-zPD.d.mts} +1 -1
- package/{serve-many-CFlNO2Iq.d.ts → serve-many-qnfynN1x.d.ts} +1 -1
- package/solidjs.d.mts +1 -1
- package/solidjs.d.ts +1 -1
- package/solidjs.js +173 -23
- package/solidjs.mjs +1 -1
- package/svelte.d.mts +2 -2
- package/svelte.d.ts +2 -2
- package/svelte.js +173 -23
- package/svelte.mjs +1 -1
- package/tanstack.d.mts +2 -2
- package/tanstack.d.ts +2 -2
- package/tanstack.js +173 -23
- package/tanstack.mjs +1 -1
- package/{types-ByzQdZjb.d.ts → types-pEje3VEB.d.mts} +8 -3
- package/{types-ByzQdZjb.d.mts → types-pEje3VEB.d.ts} +8 -3
package/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { S as StepType, R as RawStep, W as WorkflowMiddleware, a as
|
|
2
|
-
export { A as AsyncStepFunction, C as CallResponse, v as CallSettings, D as DetailedFinishCondition, t as Duration, E as ExclusiveValidationOptions, o as FailureFunctionPayload, F as FinishCondition, H as HeaderParams, x as InvokableWorkflow, w as InvokeStepResponse, I as InvokeWorkflowRequest, L as LazyInvokeStepParams, s as NotifyStepResponse, P as ParallelCallState, p as RequiredExceptFields, l as Step, n as StepFunction, k as StepTypes, m as SyncStepFunction, u as WaitEventOptions, q as WaitRequest, r as WaitStepResponse,
|
|
1
|
+
import { S as StepType, R as RawStep, W as WorkflowMiddleware, a as WorkflowClient, b as WorkflowReceiver, c as RouteFunction, d as WorkflowServeOptions, T as Telemetry, N as NotifyResponse, e as Waiter } from './types-pEje3VEB.js';
|
|
2
|
+
export { A as AsyncStepFunction, C as CallResponse, v as CallSettings, D as DetailedFinishCondition, t as Duration, E as ExclusiveValidationOptions, o as FailureFunctionPayload, F as FinishCondition, H as HeaderParams, x as InvokableWorkflow, w as InvokeStepResponse, I as InvokeWorkflowRequest, L as LazyInvokeStepParams, s as NotifyStepResponse, P as ParallelCallState, Q as QStashClientExtraConfig, p as RequiredExceptFields, l as Step, n as StepFunction, k as StepTypes, m as SyncStepFunction, u as WaitEventOptions, q as WaitRequest, r as WaitStepResponse, g as WorkflowAbort, j as WorkflowContext, f as WorkflowError, h as WorkflowNonRetryableError, i as WorkflowRetryAfterError } from './types-pEje3VEB.js';
|
|
3
3
|
import { HTTPMethods, FlowControl, PublishRequest, Client as Client$1 } from '@upstash/qstash';
|
|
4
4
|
import 'zod';
|
|
5
5
|
|
|
@@ -434,6 +434,27 @@ type DLQResumeRestartResponse = {
|
|
|
434
434
|
|
|
435
435
|
declare const loggingMiddleware: WorkflowMiddleware<unknown, unknown>;
|
|
436
436
|
|
|
437
|
+
declare const VALID_REGIONS: readonly ["EU_CENTRAL_1", "US_EAST_1"];
|
|
438
|
+
type QStashRegion = (typeof VALID_REGIONS)[number];
|
|
439
|
+
/**
|
|
440
|
+
* Regional handler containing client and optional receiver
|
|
441
|
+
*/
|
|
442
|
+
type RegionalHandler = {
|
|
443
|
+
client: WorkflowClient;
|
|
444
|
+
receiver?: WorkflowReceiver;
|
|
445
|
+
};
|
|
446
|
+
/**
|
|
447
|
+
* QStash handlers for single or multi-region mode
|
|
448
|
+
*/
|
|
449
|
+
type QStashHandlers = {
|
|
450
|
+
mode: "single-region";
|
|
451
|
+
handlers: RegionalHandler;
|
|
452
|
+
} | {
|
|
453
|
+
mode: "multi-region";
|
|
454
|
+
handlers: Record<QStashRegion, RegionalHandler>;
|
|
455
|
+
defaultRegion: QStashRegion;
|
|
456
|
+
};
|
|
457
|
+
|
|
437
458
|
type ResponseData = {
|
|
438
459
|
text: string;
|
|
439
460
|
status: number;
|
|
@@ -452,6 +473,10 @@ type InternalServeOptions<TResponse extends Response = Response> = {
|
|
|
452
473
|
* in `triggerFirstInvocation`.
|
|
453
474
|
*/
|
|
454
475
|
useJSONContent: boolean;
|
|
476
|
+
/**
|
|
477
|
+
* QStash handlers for single or multi-region mode
|
|
478
|
+
*/
|
|
479
|
+
qstashHandlers: QStashHandlers;
|
|
455
480
|
};
|
|
456
481
|
|
|
457
482
|
/**
|
|
@@ -884,4 +909,4 @@ declare class Client {
|
|
|
884
909
|
get dlq(): DLQ;
|
|
885
910
|
}
|
|
886
911
|
|
|
887
|
-
export { Client, type DLQResumeRestartOptions, type DLQResumeRestartResponse, NotifyResponse, RawStep, RouteFunction, type StepError, type StepLog, StepType, Telemetry, type TriggerOptions, Waiter, WorkflowMiddleware, type WorkflowRunLog, type WorkflowRunLogs, WorkflowServeOptions, loggingMiddleware, serve };
|
|
912
|
+
export { Client, type DLQResumeRestartOptions, type DLQResumeRestartResponse, NotifyResponse, RawStep, RouteFunction, type StepError, type StepLog, StepType, Telemetry, type TriggerOptions, Waiter, WorkflowClient, WorkflowMiddleware, WorkflowReceiver, type WorkflowRunLog, type WorkflowRunLogs, WorkflowServeOptions, loggingMiddleware, serve };
|
package/index.js
CHANGED
|
@@ -855,7 +855,7 @@ var recreateUserHeaders = (headers) => {
|
|
|
855
855
|
const pairs = headers.entries();
|
|
856
856
|
for (const [header, value] of pairs) {
|
|
857
857
|
const headerLowerCase = header.toLowerCase();
|
|
858
|
-
const isUserHeader = !headerLowerCase.startsWith("upstash-workflow-") && // https://vercel.com/docs/edge-network/headers/request-headers#x-vercel-id
|
|
858
|
+
const isUserHeader = headerLowerCase !== "upstash-region" && !headerLowerCase.startsWith("upstash-workflow-") && // https://vercel.com/docs/edge-network/headers/request-headers#x-vercel-id
|
|
859
859
|
!headerLowerCase.startsWith("x-vercel-") && !headerLowerCase.startsWith("x-forwarded-") && // https://blog.cloudflare.com/preventing-request-loops-using-cdn-loop/
|
|
860
860
|
headerLowerCase !== "cf-connecting-ip" && headerLowerCase !== "cdn-loop" && headerLowerCase !== "cf-ew-via" && headerLowerCase !== "cf-ray" && // For Render https://render.com
|
|
861
861
|
headerLowerCase !== "render-proxy-ttl" || headerLowerCase === WORKFLOW_LABEL_HEADER.toLocaleLowerCase();
|
|
@@ -3160,9 +3160,154 @@ var handleFailure = async ({
|
|
|
3160
3160
|
}
|
|
3161
3161
|
};
|
|
3162
3162
|
|
|
3163
|
-
// src/serve/
|
|
3163
|
+
// src/serve/multi-region/handlers.ts
|
|
3164
3164
|
var import_qstash10 = require("@upstash/qstash");
|
|
3165
|
-
|
|
3165
|
+
|
|
3166
|
+
// src/serve/multi-region/utils.ts
|
|
3167
|
+
var VALID_REGIONS = ["EU_CENTRAL_1", "US_EAST_1"];
|
|
3168
|
+
var getRegionFromEnvironment = (environment) => {
|
|
3169
|
+
const region = environment.QSTASH_REGION;
|
|
3170
|
+
return normalizeRegionHeader(region);
|
|
3171
|
+
};
|
|
3172
|
+
function readEnvironmentVariables(environmentVariables, environment, region) {
|
|
3173
|
+
const result = {};
|
|
3174
|
+
for (const variable of environmentVariables) {
|
|
3175
|
+
const key = region ? `${region}_${variable}` : variable;
|
|
3176
|
+
result[variable] = environment[key];
|
|
3177
|
+
}
|
|
3178
|
+
return result;
|
|
3179
|
+
}
|
|
3180
|
+
function readClientEnvironmentVariables(environment, region) {
|
|
3181
|
+
return readEnvironmentVariables(["QSTASH_URL", "QSTASH_TOKEN"], environment, region);
|
|
3182
|
+
}
|
|
3183
|
+
function readReceiverEnvironmentVariables(environment, region) {
|
|
3184
|
+
return readEnvironmentVariables(
|
|
3185
|
+
["QSTASH_CURRENT_SIGNING_KEY", "QSTASH_NEXT_SIGNING_KEY"],
|
|
3186
|
+
environment,
|
|
3187
|
+
region
|
|
3188
|
+
);
|
|
3189
|
+
}
|
|
3190
|
+
function normalizeRegionHeader(region) {
|
|
3191
|
+
if (!region) {
|
|
3192
|
+
return void 0;
|
|
3193
|
+
}
|
|
3194
|
+
region = region.replaceAll("-", "_").toUpperCase();
|
|
3195
|
+
if (VALID_REGIONS.includes(region)) {
|
|
3196
|
+
return region;
|
|
3197
|
+
}
|
|
3198
|
+
console.warn(
|
|
3199
|
+
`[Upstash Workflow] Invalid UPSTASH-REGION header value: "${region}". Expected one of: ${VALID_REGIONS.join(
|
|
3200
|
+
", "
|
|
3201
|
+
)}.`
|
|
3202
|
+
);
|
|
3203
|
+
return void 0;
|
|
3204
|
+
}
|
|
3205
|
+
|
|
3206
|
+
// src/serve/multi-region/handlers.ts
|
|
3207
|
+
var getHandlersForRequest = (qstashHandlers, regionHeader, isFirstInvocation) => {
|
|
3208
|
+
if (qstashHandlers.mode === "single-region") {
|
|
3209
|
+
return qstashHandlers.handlers;
|
|
3210
|
+
}
|
|
3211
|
+
let targetRegion;
|
|
3212
|
+
if (isFirstInvocation && !regionHeader) {
|
|
3213
|
+
targetRegion = qstashHandlers.defaultRegion;
|
|
3214
|
+
} else {
|
|
3215
|
+
const normalizedRegion = regionHeader ? normalizeRegionHeader(regionHeader) : void 0;
|
|
3216
|
+
targetRegion = normalizedRegion ?? qstashHandlers.defaultRegion;
|
|
3217
|
+
}
|
|
3218
|
+
const handler = qstashHandlers.handlers[targetRegion];
|
|
3219
|
+
if (!handler) {
|
|
3220
|
+
console.warn(
|
|
3221
|
+
`[Upstash Workflow] No handler found for region "${targetRegion}". Falling back to default region.`
|
|
3222
|
+
);
|
|
3223
|
+
return qstashHandlers.handlers[qstashHandlers.defaultRegion];
|
|
3224
|
+
}
|
|
3225
|
+
return handler;
|
|
3226
|
+
};
|
|
3227
|
+
var createRegionalHandler = (environment, receiverConfig, region, clientOptions) => {
|
|
3228
|
+
const clientEnv = readClientEnvironmentVariables(environment, region);
|
|
3229
|
+
const client = new import_qstash10.Client({
|
|
3230
|
+
...clientOptions,
|
|
3231
|
+
baseUrl: clientEnv.QSTASH_URL,
|
|
3232
|
+
token: clientEnv.QSTASH_TOKEN
|
|
3233
|
+
});
|
|
3234
|
+
const receiver = getReceiver(environment, receiverConfig, region);
|
|
3235
|
+
return { client, receiver };
|
|
3236
|
+
};
|
|
3237
|
+
var shouldUseMultiRegionMode = (environment, qstashClientOption) => {
|
|
3238
|
+
const hasRegionEnv = Boolean(getRegionFromEnvironment(environment));
|
|
3239
|
+
if (hasRegionEnv && (!qstashClientOption || !("http" in qstashClientOption))) {
|
|
3240
|
+
return {
|
|
3241
|
+
isMultiRegion: true,
|
|
3242
|
+
defaultRegion: getRegionFromEnvironment(environment),
|
|
3243
|
+
clientOptions: qstashClientOption
|
|
3244
|
+
};
|
|
3245
|
+
} else {
|
|
3246
|
+
return { isMultiRegion: false };
|
|
3247
|
+
}
|
|
3248
|
+
};
|
|
3249
|
+
var getQStashHandlers = ({
|
|
3250
|
+
environment,
|
|
3251
|
+
qstashClientOption,
|
|
3252
|
+
receiverConfig
|
|
3253
|
+
}) => {
|
|
3254
|
+
const multiRegion = shouldUseMultiRegionMode(environment, qstashClientOption);
|
|
3255
|
+
if (multiRegion.isMultiRegion) {
|
|
3256
|
+
const regions = ["US_EAST_1", "EU_CENTRAL_1"];
|
|
3257
|
+
const handlers = {};
|
|
3258
|
+
for (const region of regions) {
|
|
3259
|
+
try {
|
|
3260
|
+
handlers[region] = createRegionalHandler(
|
|
3261
|
+
environment,
|
|
3262
|
+
receiverConfig,
|
|
3263
|
+
region,
|
|
3264
|
+
multiRegion.clientOptions
|
|
3265
|
+
);
|
|
3266
|
+
} catch (error) {
|
|
3267
|
+
console.warn(`[Upstash Workflow] Failed to create handler for region ${region}:`, error);
|
|
3268
|
+
}
|
|
3269
|
+
}
|
|
3270
|
+
return {
|
|
3271
|
+
mode: "multi-region",
|
|
3272
|
+
handlers,
|
|
3273
|
+
defaultRegion: multiRegion.defaultRegion
|
|
3274
|
+
};
|
|
3275
|
+
} else {
|
|
3276
|
+
return {
|
|
3277
|
+
mode: "single-region",
|
|
3278
|
+
handlers: {
|
|
3279
|
+
client: qstashClientOption && "http" in qstashClientOption ? qstashClientOption : new import_qstash10.Client({
|
|
3280
|
+
...qstashClientOption,
|
|
3281
|
+
baseUrl: environment.QSTASH_URL,
|
|
3282
|
+
token: environment.QSTASH_TOKEN
|
|
3283
|
+
}),
|
|
3284
|
+
receiver: getReceiver(environment, receiverConfig)
|
|
3285
|
+
}
|
|
3286
|
+
};
|
|
3287
|
+
}
|
|
3288
|
+
};
|
|
3289
|
+
var getReceiver = (environment, receiverConfig, region) => {
|
|
3290
|
+
if (typeof receiverConfig === "string") {
|
|
3291
|
+
if (receiverConfig === "set-to-undefined") {
|
|
3292
|
+
return void 0;
|
|
3293
|
+
}
|
|
3294
|
+
const receiverEnv = readReceiverEnvironmentVariables(environment, region);
|
|
3295
|
+
return receiverEnv.QSTASH_CURRENT_SIGNING_KEY && receiverEnv.QSTASH_NEXT_SIGNING_KEY ? new import_qstash10.Receiver({
|
|
3296
|
+
currentSigningKey: receiverEnv.QSTASH_CURRENT_SIGNING_KEY,
|
|
3297
|
+
nextSigningKey: receiverEnv.QSTASH_NEXT_SIGNING_KEY
|
|
3298
|
+
}) : void 0;
|
|
3299
|
+
} else {
|
|
3300
|
+
return receiverConfig;
|
|
3301
|
+
}
|
|
3302
|
+
};
|
|
3303
|
+
var getQStashHandlerOptions = (...params) => {
|
|
3304
|
+
const handlers = getQStashHandlers(...params);
|
|
3305
|
+
return {
|
|
3306
|
+
qstashHandlers: handlers,
|
|
3307
|
+
defaultReceiver: handlers.mode === "single-region" ? handlers.handlers.receiver : handlers.handlers[handlers.defaultRegion].receiver,
|
|
3308
|
+
defaultClient: handlers.mode === "single-region" ? handlers.handlers.client : handlers.handlers[handlers.defaultRegion].client
|
|
3309
|
+
};
|
|
3310
|
+
};
|
|
3166
3311
|
|
|
3167
3312
|
// src/middleware/middleware.ts
|
|
3168
3313
|
var WorkflowMiddleware = class {
|
|
@@ -3301,14 +3446,17 @@ var createResponseData = (workflowRunId, detailedFinishCondition) => {
|
|
|
3301
3446
|
};
|
|
3302
3447
|
var processOptions = (options, internalOptions) => {
|
|
3303
3448
|
const environment = options?.env ?? (typeof process === "undefined" ? {} : process.env);
|
|
3304
|
-
const
|
|
3305
|
-
|
|
3306
|
-
|
|
3449
|
+
const {
|
|
3450
|
+
qstashHandlers,
|
|
3451
|
+
defaultClient: qstashClient,
|
|
3452
|
+
defaultReceiver: receiver
|
|
3453
|
+
} = getQStashHandlerOptions({
|
|
3454
|
+
environment,
|
|
3455
|
+
qstashClientOption: options?.qstashClient,
|
|
3456
|
+
receiverConfig: options && "receiver" in options ? options.receiver ? options.receiver : "set-to-undefined" : "not-set"
|
|
3457
|
+
});
|
|
3307
3458
|
return {
|
|
3308
|
-
qstashClient
|
|
3309
|
-
baseUrl: environment.QSTASH_URL,
|
|
3310
|
-
token: environment.QSTASH_TOKEN
|
|
3311
|
-
}),
|
|
3459
|
+
qstashClient,
|
|
3312
3460
|
initialPayloadParser: (initialRequest) => {
|
|
3313
3461
|
if (!initialRequest) {
|
|
3314
3462
|
return void 0;
|
|
@@ -3323,10 +3471,7 @@ var processOptions = (options, internalOptions) => {
|
|
|
3323
3471
|
throw error;
|
|
3324
3472
|
}
|
|
3325
3473
|
},
|
|
3326
|
-
receiver
|
|
3327
|
-
currentSigningKey: environment.QSTASH_CURRENT_SIGNING_KEY,
|
|
3328
|
-
nextSigningKey: environment.QSTASH_NEXT_SIGNING_KEY
|
|
3329
|
-
}) : void 0,
|
|
3474
|
+
receiver,
|
|
3330
3475
|
baseUrl: environment.UPSTASH_WORKFLOW_URL,
|
|
3331
3476
|
env: environment,
|
|
3332
3477
|
disableTelemetry: false,
|
|
@@ -3340,7 +3485,8 @@ var processOptions = (options, internalOptions) => {
|
|
|
3340
3485
|
headers: responseData.headers
|
|
3341
3486
|
});
|
|
3342
3487
|
}),
|
|
3343
|
-
useJSONContent: internalOptions?.useJSONContent ?? false
|
|
3488
|
+
useJSONContent: internalOptions?.useJSONContent ?? false,
|
|
3489
|
+
qstashHandlers
|
|
3344
3490
|
}
|
|
3345
3491
|
};
|
|
3346
3492
|
};
|
|
@@ -3373,10 +3519,8 @@ var AUTH_FAIL_MESSAGE = `Failed to authenticate Workflow request. If this is une
|
|
|
3373
3519
|
// src/serve/index.ts
|
|
3374
3520
|
var serveBase = (routeFunction, telemetry, options, internalOptions) => {
|
|
3375
3521
|
const {
|
|
3376
|
-
qstashClient,
|
|
3377
3522
|
initialPayloadParser,
|
|
3378
3523
|
url,
|
|
3379
|
-
receiver,
|
|
3380
3524
|
failureFunction,
|
|
3381
3525
|
baseUrl,
|
|
3382
3526
|
env,
|
|
@@ -3396,9 +3540,15 @@ var serveBase = (routeFunction, telemetry, options, internalOptions) => {
|
|
|
3396
3540
|
baseUrl,
|
|
3397
3541
|
middlewareManager.dispatchDebug.bind(middlewareManager)
|
|
3398
3542
|
);
|
|
3399
|
-
const requestPayload = await getPayload(request) ?? "";
|
|
3400
|
-
await verifyRequest(requestPayload, request.headers.get("upstash-signature"), receiver);
|
|
3401
3543
|
const { isFirstInvocation, workflowRunId, unknownSdk } = validateRequest(request);
|
|
3544
|
+
const regionHeader = request.headers.get("upstash-region");
|
|
3545
|
+
const { client: regionalClient, receiver: regionalReceiver } = getHandlersForRequest(
|
|
3546
|
+
internal.qstashHandlers,
|
|
3547
|
+
regionHeader,
|
|
3548
|
+
isFirstInvocation
|
|
3549
|
+
);
|
|
3550
|
+
const requestPayload = await getPayload(request) ?? "";
|
|
3551
|
+
await verifyRequest(requestPayload, request.headers.get("upstash-signature"), regionalReceiver);
|
|
3402
3552
|
middlewareManager.assignWorkflowRunId(workflowRunId);
|
|
3403
3553
|
await middlewareManager.dispatchDebug("onInfo", {
|
|
3404
3554
|
info: `Run id identified. isFirstInvocation: ${isFirstInvocation}, unknownSdk: ${unknownSdk}`
|
|
@@ -3408,7 +3558,7 @@ var serveBase = (routeFunction, telemetry, options, internalOptions) => {
|
|
|
3408
3558
|
isFirstInvocation,
|
|
3409
3559
|
unknownSdk,
|
|
3410
3560
|
workflowRunId,
|
|
3411
|
-
requester:
|
|
3561
|
+
requester: regionalClient.http,
|
|
3412
3562
|
messageId: request.headers.get("upstash-message-id"),
|
|
3413
3563
|
dispatchDebug: middlewareManager.dispatchDebug.bind(middlewareManager)
|
|
3414
3564
|
});
|
|
@@ -3429,7 +3579,7 @@ var serveBase = (routeFunction, telemetry, options, internalOptions) => {
|
|
|
3429
3579
|
const failureCheck = await handleFailure({
|
|
3430
3580
|
request,
|
|
3431
3581
|
requestPayload,
|
|
3432
|
-
qstashClient,
|
|
3582
|
+
qstashClient: regionalClient,
|
|
3433
3583
|
initialPayloadParser,
|
|
3434
3584
|
routeFunction,
|
|
3435
3585
|
failureFunction,
|
|
@@ -3461,7 +3611,7 @@ var serveBase = (routeFunction, telemetry, options, internalOptions) => {
|
|
|
3461
3611
|
const invokeCount = Number(request.headers.get(WORKFLOW_INVOKE_COUNT_HEADER) ?? "0");
|
|
3462
3612
|
const label = request.headers.get(WORKFLOW_LABEL_HEADER) ?? void 0;
|
|
3463
3613
|
const workflowContext = new WorkflowContext({
|
|
3464
|
-
qstashClient,
|
|
3614
|
+
qstashClient: regionalClient,
|
|
3465
3615
|
workflowRunId,
|
|
3466
3616
|
initialPayload: initialPayloadParser(rawInitialPayload),
|
|
3467
3617
|
headers: recreateUserHeaders(request.headers),
|
|
@@ -3492,7 +3642,7 @@ var serveBase = (routeFunction, telemetry, options, internalOptions) => {
|
|
|
3492
3642
|
const callReturnCheck = await handleThirdPartyCallResult({
|
|
3493
3643
|
request,
|
|
3494
3644
|
requestPayload: rawInitialPayload,
|
|
3495
|
-
client:
|
|
3645
|
+
client: regionalClient,
|
|
3496
3646
|
workflowUrl,
|
|
3497
3647
|
telemetry,
|
|
3498
3648
|
middlewareManager
|
|
@@ -3601,7 +3751,7 @@ var serve = (routeFunction, options) => {
|
|
|
3601
3751
|
};
|
|
3602
3752
|
|
|
3603
3753
|
// src/client/index.ts
|
|
3604
|
-
var
|
|
3754
|
+
var import_qstash11 = require("@upstash/qstash");
|
|
3605
3755
|
|
|
3606
3756
|
// src/client/dlq.ts
|
|
3607
3757
|
var DLQ = class _DLQ {
|
|
@@ -3713,12 +3863,7 @@ var DLQ = class _DLQ {
|
|
|
3713
3863
|
var Client4 = class {
|
|
3714
3864
|
client;
|
|
3715
3865
|
constructor(clientConfig) {
|
|
3716
|
-
|
|
3717
|
-
console.error(
|
|
3718
|
-
"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 });"
|
|
3719
|
-
);
|
|
3720
|
-
}
|
|
3721
|
-
this.client = new import_qstash12.Client(clientConfig);
|
|
3866
|
+
this.client = new import_qstash11.Client(clientConfig);
|
|
3722
3867
|
}
|
|
3723
3868
|
/**
|
|
3724
3869
|
* Cancel an ongoing workflow
|
package/index.mjs
CHANGED
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
prepareFlowControl,
|
|
16
16
|
serve,
|
|
17
17
|
triggerFirstInvocation
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-C5HFGF7Q.mjs";
|
|
19
19
|
|
|
20
20
|
// src/client/index.ts
|
|
21
21
|
import { Client as QStashClient } from "@upstash/qstash";
|
|
@@ -130,11 +130,6 @@ var DLQ = class _DLQ {
|
|
|
130
130
|
var Client = class {
|
|
131
131
|
client;
|
|
132
132
|
constructor(clientConfig) {
|
|
133
|
-
if (!clientConfig?.token) {
|
|
134
|
-
console.error(
|
|
135
|
-
"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 });"
|
|
136
|
-
);
|
|
137
|
-
}
|
|
138
133
|
this.client = new QStashClient(clientConfig);
|
|
139
134
|
}
|
|
140
135
|
/**
|
package/nextjs.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { NextApiHandler, NextApiRequest, NextApiResponse } from 'next';
|
|
2
|
-
import {
|
|
3
|
-
import { s as serveManyBase } from './serve-many-
|
|
2
|
+
import { c as RouteFunction, d as WorkflowServeOptions, x as InvokableWorkflow } from './types-pEje3VEB.mjs';
|
|
3
|
+
import { s as serveManyBase } from './serve-many-DhB8-zPD.mjs';
|
|
4
4
|
import '@upstash/qstash';
|
|
5
5
|
import 'zod';
|
|
6
6
|
|
package/nextjs.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { NextApiHandler, NextApiRequest, NextApiResponse } from 'next';
|
|
2
|
-
import {
|
|
3
|
-
import { s as serveManyBase } from './serve-many-
|
|
2
|
+
import { c as RouteFunction, d as WorkflowServeOptions, x as InvokableWorkflow } from './types-pEje3VEB.js';
|
|
3
|
+
import { s as serveManyBase } from './serve-many-qnfynN1x.js';
|
|
4
4
|
import '@upstash/qstash';
|
|
5
5
|
import 'zod';
|
|
6
6
|
|
package/nextjs.js
CHANGED
|
@@ -844,7 +844,7 @@ var recreateUserHeaders = (headers) => {
|
|
|
844
844
|
const pairs = headers.entries();
|
|
845
845
|
for (const [header, value] of pairs) {
|
|
846
846
|
const headerLowerCase = header.toLowerCase();
|
|
847
|
-
const isUserHeader = !headerLowerCase.startsWith("upstash-workflow-") && // https://vercel.com/docs/edge-network/headers/request-headers#x-vercel-id
|
|
847
|
+
const isUserHeader = headerLowerCase !== "upstash-region" && !headerLowerCase.startsWith("upstash-workflow-") && // https://vercel.com/docs/edge-network/headers/request-headers#x-vercel-id
|
|
848
848
|
!headerLowerCase.startsWith("x-vercel-") && !headerLowerCase.startsWith("x-forwarded-") && // https://blog.cloudflare.com/preventing-request-loops-using-cdn-loop/
|
|
849
849
|
headerLowerCase !== "cf-connecting-ip" && headerLowerCase !== "cdn-loop" && headerLowerCase !== "cf-ew-via" && headerLowerCase !== "cf-ray" && // For Render https://render.com
|
|
850
850
|
headerLowerCase !== "render-proxy-ttl" || headerLowerCase === WORKFLOW_LABEL_HEADER.toLocaleLowerCase();
|
|
@@ -3216,9 +3216,154 @@ var handleFailure = async ({
|
|
|
3216
3216
|
}
|
|
3217
3217
|
};
|
|
3218
3218
|
|
|
3219
|
-
// src/serve/
|
|
3219
|
+
// src/serve/multi-region/handlers.ts
|
|
3220
3220
|
var import_qstash10 = require("@upstash/qstash");
|
|
3221
|
-
|
|
3221
|
+
|
|
3222
|
+
// src/serve/multi-region/utils.ts
|
|
3223
|
+
var VALID_REGIONS = ["EU_CENTRAL_1", "US_EAST_1"];
|
|
3224
|
+
var getRegionFromEnvironment = (environment) => {
|
|
3225
|
+
const region = environment.QSTASH_REGION;
|
|
3226
|
+
return normalizeRegionHeader(region);
|
|
3227
|
+
};
|
|
3228
|
+
function readEnvironmentVariables(environmentVariables, environment, region) {
|
|
3229
|
+
const result = {};
|
|
3230
|
+
for (const variable of environmentVariables) {
|
|
3231
|
+
const key = region ? `${region}_${variable}` : variable;
|
|
3232
|
+
result[variable] = environment[key];
|
|
3233
|
+
}
|
|
3234
|
+
return result;
|
|
3235
|
+
}
|
|
3236
|
+
function readClientEnvironmentVariables(environment, region) {
|
|
3237
|
+
return readEnvironmentVariables(["QSTASH_URL", "QSTASH_TOKEN"], environment, region);
|
|
3238
|
+
}
|
|
3239
|
+
function readReceiverEnvironmentVariables(environment, region) {
|
|
3240
|
+
return readEnvironmentVariables(
|
|
3241
|
+
["QSTASH_CURRENT_SIGNING_KEY", "QSTASH_NEXT_SIGNING_KEY"],
|
|
3242
|
+
environment,
|
|
3243
|
+
region
|
|
3244
|
+
);
|
|
3245
|
+
}
|
|
3246
|
+
function normalizeRegionHeader(region) {
|
|
3247
|
+
if (!region) {
|
|
3248
|
+
return void 0;
|
|
3249
|
+
}
|
|
3250
|
+
region = region.replaceAll("-", "_").toUpperCase();
|
|
3251
|
+
if (VALID_REGIONS.includes(region)) {
|
|
3252
|
+
return region;
|
|
3253
|
+
}
|
|
3254
|
+
console.warn(
|
|
3255
|
+
`[Upstash Workflow] Invalid UPSTASH-REGION header value: "${region}". Expected one of: ${VALID_REGIONS.join(
|
|
3256
|
+
", "
|
|
3257
|
+
)}.`
|
|
3258
|
+
);
|
|
3259
|
+
return void 0;
|
|
3260
|
+
}
|
|
3261
|
+
|
|
3262
|
+
// src/serve/multi-region/handlers.ts
|
|
3263
|
+
var getHandlersForRequest = (qstashHandlers, regionHeader, isFirstInvocation) => {
|
|
3264
|
+
if (qstashHandlers.mode === "single-region") {
|
|
3265
|
+
return qstashHandlers.handlers;
|
|
3266
|
+
}
|
|
3267
|
+
let targetRegion;
|
|
3268
|
+
if (isFirstInvocation && !regionHeader) {
|
|
3269
|
+
targetRegion = qstashHandlers.defaultRegion;
|
|
3270
|
+
} else {
|
|
3271
|
+
const normalizedRegion = regionHeader ? normalizeRegionHeader(regionHeader) : void 0;
|
|
3272
|
+
targetRegion = normalizedRegion ?? qstashHandlers.defaultRegion;
|
|
3273
|
+
}
|
|
3274
|
+
const handler = qstashHandlers.handlers[targetRegion];
|
|
3275
|
+
if (!handler) {
|
|
3276
|
+
console.warn(
|
|
3277
|
+
`[Upstash Workflow] No handler found for region "${targetRegion}". Falling back to default region.`
|
|
3278
|
+
);
|
|
3279
|
+
return qstashHandlers.handlers[qstashHandlers.defaultRegion];
|
|
3280
|
+
}
|
|
3281
|
+
return handler;
|
|
3282
|
+
};
|
|
3283
|
+
var createRegionalHandler = (environment, receiverConfig, region, clientOptions) => {
|
|
3284
|
+
const clientEnv = readClientEnvironmentVariables(environment, region);
|
|
3285
|
+
const client = new import_qstash10.Client({
|
|
3286
|
+
...clientOptions,
|
|
3287
|
+
baseUrl: clientEnv.QSTASH_URL,
|
|
3288
|
+
token: clientEnv.QSTASH_TOKEN
|
|
3289
|
+
});
|
|
3290
|
+
const receiver = getReceiver(environment, receiverConfig, region);
|
|
3291
|
+
return { client, receiver };
|
|
3292
|
+
};
|
|
3293
|
+
var shouldUseMultiRegionMode = (environment, qstashClientOption) => {
|
|
3294
|
+
const hasRegionEnv = Boolean(getRegionFromEnvironment(environment));
|
|
3295
|
+
if (hasRegionEnv && (!qstashClientOption || !("http" in qstashClientOption))) {
|
|
3296
|
+
return {
|
|
3297
|
+
isMultiRegion: true,
|
|
3298
|
+
defaultRegion: getRegionFromEnvironment(environment),
|
|
3299
|
+
clientOptions: qstashClientOption
|
|
3300
|
+
};
|
|
3301
|
+
} else {
|
|
3302
|
+
return { isMultiRegion: false };
|
|
3303
|
+
}
|
|
3304
|
+
};
|
|
3305
|
+
var getQStashHandlers = ({
|
|
3306
|
+
environment,
|
|
3307
|
+
qstashClientOption,
|
|
3308
|
+
receiverConfig
|
|
3309
|
+
}) => {
|
|
3310
|
+
const multiRegion = shouldUseMultiRegionMode(environment, qstashClientOption);
|
|
3311
|
+
if (multiRegion.isMultiRegion) {
|
|
3312
|
+
const regions = ["US_EAST_1", "EU_CENTRAL_1"];
|
|
3313
|
+
const handlers = {};
|
|
3314
|
+
for (const region of regions) {
|
|
3315
|
+
try {
|
|
3316
|
+
handlers[region] = createRegionalHandler(
|
|
3317
|
+
environment,
|
|
3318
|
+
receiverConfig,
|
|
3319
|
+
region,
|
|
3320
|
+
multiRegion.clientOptions
|
|
3321
|
+
);
|
|
3322
|
+
} catch (error) {
|
|
3323
|
+
console.warn(`[Upstash Workflow] Failed to create handler for region ${region}:`, error);
|
|
3324
|
+
}
|
|
3325
|
+
}
|
|
3326
|
+
return {
|
|
3327
|
+
mode: "multi-region",
|
|
3328
|
+
handlers,
|
|
3329
|
+
defaultRegion: multiRegion.defaultRegion
|
|
3330
|
+
};
|
|
3331
|
+
} else {
|
|
3332
|
+
return {
|
|
3333
|
+
mode: "single-region",
|
|
3334
|
+
handlers: {
|
|
3335
|
+
client: qstashClientOption && "http" in qstashClientOption ? qstashClientOption : new import_qstash10.Client({
|
|
3336
|
+
...qstashClientOption,
|
|
3337
|
+
baseUrl: environment.QSTASH_URL,
|
|
3338
|
+
token: environment.QSTASH_TOKEN
|
|
3339
|
+
}),
|
|
3340
|
+
receiver: getReceiver(environment, receiverConfig)
|
|
3341
|
+
}
|
|
3342
|
+
};
|
|
3343
|
+
}
|
|
3344
|
+
};
|
|
3345
|
+
var getReceiver = (environment, receiverConfig, region) => {
|
|
3346
|
+
if (typeof receiverConfig === "string") {
|
|
3347
|
+
if (receiverConfig === "set-to-undefined") {
|
|
3348
|
+
return void 0;
|
|
3349
|
+
}
|
|
3350
|
+
const receiverEnv = readReceiverEnvironmentVariables(environment, region);
|
|
3351
|
+
return receiverEnv.QSTASH_CURRENT_SIGNING_KEY && receiverEnv.QSTASH_NEXT_SIGNING_KEY ? new import_qstash10.Receiver({
|
|
3352
|
+
currentSigningKey: receiverEnv.QSTASH_CURRENT_SIGNING_KEY,
|
|
3353
|
+
nextSigningKey: receiverEnv.QSTASH_NEXT_SIGNING_KEY
|
|
3354
|
+
}) : void 0;
|
|
3355
|
+
} else {
|
|
3356
|
+
return receiverConfig;
|
|
3357
|
+
}
|
|
3358
|
+
};
|
|
3359
|
+
var getQStashHandlerOptions = (...params) => {
|
|
3360
|
+
const handlers = getQStashHandlers(...params);
|
|
3361
|
+
return {
|
|
3362
|
+
qstashHandlers: handlers,
|
|
3363
|
+
defaultReceiver: handlers.mode === "single-region" ? handlers.handlers.receiver : handlers.handlers[handlers.defaultRegion].receiver,
|
|
3364
|
+
defaultClient: handlers.mode === "single-region" ? handlers.handlers.client : handlers.handlers[handlers.defaultRegion].client
|
|
3365
|
+
};
|
|
3366
|
+
};
|
|
3222
3367
|
|
|
3223
3368
|
// src/middleware/middleware.ts
|
|
3224
3369
|
var WorkflowMiddleware = class {
|
|
@@ -3357,14 +3502,17 @@ var createResponseData = (workflowRunId, detailedFinishCondition) => {
|
|
|
3357
3502
|
};
|
|
3358
3503
|
var processOptions = (options, internalOptions) => {
|
|
3359
3504
|
const environment = options?.env ?? (typeof process === "undefined" ? {} : process.env);
|
|
3360
|
-
const
|
|
3361
|
-
|
|
3362
|
-
|
|
3505
|
+
const {
|
|
3506
|
+
qstashHandlers,
|
|
3507
|
+
defaultClient: qstashClient,
|
|
3508
|
+
defaultReceiver: receiver
|
|
3509
|
+
} = getQStashHandlerOptions({
|
|
3510
|
+
environment,
|
|
3511
|
+
qstashClientOption: options?.qstashClient,
|
|
3512
|
+
receiverConfig: options && "receiver" in options ? options.receiver ? options.receiver : "set-to-undefined" : "not-set"
|
|
3513
|
+
});
|
|
3363
3514
|
return {
|
|
3364
|
-
qstashClient
|
|
3365
|
-
baseUrl: environment.QSTASH_URL,
|
|
3366
|
-
token: environment.QSTASH_TOKEN
|
|
3367
|
-
}),
|
|
3515
|
+
qstashClient,
|
|
3368
3516
|
initialPayloadParser: (initialRequest) => {
|
|
3369
3517
|
if (!initialRequest) {
|
|
3370
3518
|
return void 0;
|
|
@@ -3379,10 +3527,7 @@ var processOptions = (options, internalOptions) => {
|
|
|
3379
3527
|
throw error;
|
|
3380
3528
|
}
|
|
3381
3529
|
},
|
|
3382
|
-
receiver
|
|
3383
|
-
currentSigningKey: environment.QSTASH_CURRENT_SIGNING_KEY,
|
|
3384
|
-
nextSigningKey: environment.QSTASH_NEXT_SIGNING_KEY
|
|
3385
|
-
}) : void 0,
|
|
3530
|
+
receiver,
|
|
3386
3531
|
baseUrl: environment.UPSTASH_WORKFLOW_URL,
|
|
3387
3532
|
env: environment,
|
|
3388
3533
|
disableTelemetry: false,
|
|
@@ -3396,7 +3541,8 @@ var processOptions = (options, internalOptions) => {
|
|
|
3396
3541
|
headers: responseData.headers
|
|
3397
3542
|
});
|
|
3398
3543
|
}),
|
|
3399
|
-
useJSONContent: internalOptions?.useJSONContent ?? false
|
|
3544
|
+
useJSONContent: internalOptions?.useJSONContent ?? false,
|
|
3545
|
+
qstashHandlers
|
|
3400
3546
|
}
|
|
3401
3547
|
};
|
|
3402
3548
|
};
|
|
@@ -3429,10 +3575,8 @@ var AUTH_FAIL_MESSAGE = `Failed to authenticate Workflow request. If this is une
|
|
|
3429
3575
|
// src/serve/index.ts
|
|
3430
3576
|
var serveBase = (routeFunction, telemetry, options, internalOptions) => {
|
|
3431
3577
|
const {
|
|
3432
|
-
qstashClient,
|
|
3433
3578
|
initialPayloadParser,
|
|
3434
3579
|
url,
|
|
3435
|
-
receiver,
|
|
3436
3580
|
failureFunction,
|
|
3437
3581
|
baseUrl,
|
|
3438
3582
|
env,
|
|
@@ -3452,9 +3596,15 @@ var serveBase = (routeFunction, telemetry, options, internalOptions) => {
|
|
|
3452
3596
|
baseUrl,
|
|
3453
3597
|
middlewareManager.dispatchDebug.bind(middlewareManager)
|
|
3454
3598
|
);
|
|
3455
|
-
const requestPayload = await getPayload(request) ?? "";
|
|
3456
|
-
await verifyRequest(requestPayload, request.headers.get("upstash-signature"), receiver);
|
|
3457
3599
|
const { isFirstInvocation, workflowRunId, unknownSdk } = validateRequest(request);
|
|
3600
|
+
const regionHeader = request.headers.get("upstash-region");
|
|
3601
|
+
const { client: regionalClient, receiver: regionalReceiver } = getHandlersForRequest(
|
|
3602
|
+
internal.qstashHandlers,
|
|
3603
|
+
regionHeader,
|
|
3604
|
+
isFirstInvocation
|
|
3605
|
+
);
|
|
3606
|
+
const requestPayload = await getPayload(request) ?? "";
|
|
3607
|
+
await verifyRequest(requestPayload, request.headers.get("upstash-signature"), regionalReceiver);
|
|
3458
3608
|
middlewareManager.assignWorkflowRunId(workflowRunId);
|
|
3459
3609
|
await middlewareManager.dispatchDebug("onInfo", {
|
|
3460
3610
|
info: `Run id identified. isFirstInvocation: ${isFirstInvocation}, unknownSdk: ${unknownSdk}`
|
|
@@ -3464,7 +3614,7 @@ var serveBase = (routeFunction, telemetry, options, internalOptions) => {
|
|
|
3464
3614
|
isFirstInvocation,
|
|
3465
3615
|
unknownSdk,
|
|
3466
3616
|
workflowRunId,
|
|
3467
|
-
requester:
|
|
3617
|
+
requester: regionalClient.http,
|
|
3468
3618
|
messageId: request.headers.get("upstash-message-id"),
|
|
3469
3619
|
dispatchDebug: middlewareManager.dispatchDebug.bind(middlewareManager)
|
|
3470
3620
|
});
|
|
@@ -3485,7 +3635,7 @@ var serveBase = (routeFunction, telemetry, options, internalOptions) => {
|
|
|
3485
3635
|
const failureCheck = await handleFailure({
|
|
3486
3636
|
request,
|
|
3487
3637
|
requestPayload,
|
|
3488
|
-
qstashClient,
|
|
3638
|
+
qstashClient: regionalClient,
|
|
3489
3639
|
initialPayloadParser,
|
|
3490
3640
|
routeFunction,
|
|
3491
3641
|
failureFunction,
|
|
@@ -3517,7 +3667,7 @@ var serveBase = (routeFunction, telemetry, options, internalOptions) => {
|
|
|
3517
3667
|
const invokeCount = Number(request.headers.get(WORKFLOW_INVOKE_COUNT_HEADER) ?? "0");
|
|
3518
3668
|
const label = request.headers.get(WORKFLOW_LABEL_HEADER) ?? void 0;
|
|
3519
3669
|
const workflowContext = new WorkflowContext({
|
|
3520
|
-
qstashClient,
|
|
3670
|
+
qstashClient: regionalClient,
|
|
3521
3671
|
workflowRunId,
|
|
3522
3672
|
initialPayload: initialPayloadParser(rawInitialPayload),
|
|
3523
3673
|
headers: recreateUserHeaders(request.headers),
|
|
@@ -3548,7 +3698,7 @@ var serveBase = (routeFunction, telemetry, options, internalOptions) => {
|
|
|
3548
3698
|
const callReturnCheck = await handleThirdPartyCallResult({
|
|
3549
3699
|
request,
|
|
3550
3700
|
requestPayload: rawInitialPayload,
|
|
3551
|
-
client:
|
|
3701
|
+
client: regionalClient,
|
|
3552
3702
|
workflowUrl,
|
|
3553
3703
|
telemetry,
|
|
3554
3704
|
middlewareManager
|