@upstash/workflow 1.0.0 → 1.1.0-rc
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/astro.d.mts +2 -2
- package/astro.d.ts +2 -2
- package/astro.js +173 -23
- package/astro.mjs +1 -1
- package/{chunk-5GWDM6XJ.mjs → chunk-2Z32SOYM.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/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@upstash/workflow","version":"v1.
|
|
1
|
+
{"name":"@upstash/workflow","version":"v1.1.0-rc","description":"Durable, Reliable and Performant Serverless Functions","main":"./index.js","module":"./index.mjs","types":"./index.d.ts","files":["./*"],"exports":{".":{"import":"./index.mjs","require":"./index.js"},"./dist/nextjs":{"import":"./nextjs.mjs","require":"./nextjs.js"},"./nextjs":{"import":"./nextjs.mjs","require":"./nextjs.js"},"./h3":{"import":"./h3.mjs","require":"./h3.js"},"./svelte":{"import":"./svelte.mjs","require":"./svelte.js"},"./solidjs":{"import":"./solidjs.mjs","require":"./solidjs.js"},"./workflow":{"import":"./workflow.mjs","require":"./workflow.js"},"./hono":{"import":"./hono.mjs","require":"./hono.js"},"./cloudflare":{"import":"./cloudflare.mjs","require":"./cloudflare.js"},"./astro":{"import":"./astro.mjs","require":"./astro.js"},"./express":{"import":"./express.mjs","require":"./express.js"},"./tanstack":{"import":"./tanstack.mjs","require":"./tanstack.js"}},"scripts":{"build":"tsup && cp README.md ./dist/ && cp package.json ./dist/ && cp LICENSE ./dist/","test":"bun test src","fmt":"prettier --write .","lint":"tsc && eslint \"{src,platforms}/**/*.{js,ts,tsx}\" --quiet --fix","check-exports":"bun run build && cd dist && attw -P"},"repository":{"type":"git","url":"git+https://github.com/upstash/workflow-ts.git"},"keywords":["upstash","qstash","workflow","serverless"],"author":"Cahid Arda Oz","license":"MIT","bugs":{"url":"https://github.com/upstash/workflow-ts/issues"},"homepage":"https://github.com/upstash/workflow-ts#readme","devDependencies":{"@commitlint/cli":"^19.5.0","@commitlint/config-conventional":"^19.5.0","@eslint/js":"^9.11.1","@solidjs/start":"^1.0.8","@sveltejs/kit":"^2.6.1","@types/bun":"^1.1.10","@types/express":"^5.0.3","astro":"^4.16.7","eslint":"^9.11.1","eslint-plugin-unicorn":"^55.0.0","express":"^5.1.0","globals":"^15.10.0","h3":"^1.12.0","hono":"^4.6.20","husky":"^9.1.6","next":"^14.2.14","prettier":"3.3.3","tsup":"^8.3.0","typescript":"^5.7.2","typescript-eslint":"^8.18.0"},"dependencies":{"@upstash/qstash":"2.9.0-rc"},"directories":{"example":"examples"},"peerDependencies":{"zod":"^3.25.0 || ^4.0.0"}}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { d as WorkflowServeOptions, c as RouteFunction, x as InvokableWorkflow } from './types-pEje3VEB.mjs';
|
|
2
2
|
|
|
3
3
|
type OmitOptionsInServeMany<TOptions> = Omit<TOptions, "env" | "url" | "schema" | "initialPayloadParser">;
|
|
4
4
|
declare const serveManyBase: <THandler extends (...params: any[]) => any, TOptions extends OmitOptionsInServeMany<WorkflowServeOptions> = OmitOptionsInServeMany<WorkflowServeOptions>, TServeParams extends [routeFunction: RouteFunction<any, any>, options: TOptions] = [routeFunction: RouteFunction<any, any>, options: TOptions]>({ workflows, getUrl, serveMethod, options, }: {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { d as WorkflowServeOptions, c as RouteFunction, x as InvokableWorkflow } from './types-pEje3VEB.js';
|
|
2
2
|
|
|
3
3
|
type OmitOptionsInServeMany<TOptions> = Omit<TOptions, "env" | "url" | "schema" | "initialPayloadParser">;
|
|
4
4
|
declare const serveManyBase: <THandler extends (...params: any[]) => any, TOptions extends OmitOptionsInServeMany<WorkflowServeOptions> = OmitOptionsInServeMany<WorkflowServeOptions>, TServeParams extends [routeFunction: RouteFunction<any, any>, options: TOptions] = [routeFunction: RouteFunction<any, any>, options: TOptions]>({ workflows, getUrl, serveMethod, options, }: {
|
package/solidjs.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { APIEvent } from '@solidjs/start/server';
|
|
2
|
-
import {
|
|
2
|
+
import { c as RouteFunction, d as WorkflowServeOptions } from './types-pEje3VEB.mjs';
|
|
3
3
|
import '@upstash/qstash';
|
|
4
4
|
import 'zod';
|
|
5
5
|
|
package/solidjs.d.ts
CHANGED
package/solidjs.js
CHANGED
|
@@ -839,7 +839,7 @@ var recreateUserHeaders = (headers) => {
|
|
|
839
839
|
const pairs = headers.entries();
|
|
840
840
|
for (const [header, value] of pairs) {
|
|
841
841
|
const headerLowerCase = header.toLowerCase();
|
|
842
|
-
const isUserHeader = !headerLowerCase.startsWith("upstash-workflow-") && // https://vercel.com/docs/edge-network/headers/request-headers#x-vercel-id
|
|
842
|
+
const isUserHeader = headerLowerCase !== "upstash-region" && !headerLowerCase.startsWith("upstash-workflow-") && // https://vercel.com/docs/edge-network/headers/request-headers#x-vercel-id
|
|
843
843
|
!headerLowerCase.startsWith("x-vercel-") && !headerLowerCase.startsWith("x-forwarded-") && // https://blog.cloudflare.com/preventing-request-loops-using-cdn-loop/
|
|
844
844
|
headerLowerCase !== "cf-connecting-ip" && headerLowerCase !== "cdn-loop" && headerLowerCase !== "cf-ew-via" && headerLowerCase !== "cf-ray" && // For Render https://render.com
|
|
845
845
|
headerLowerCase !== "render-proxy-ttl" || headerLowerCase === WORKFLOW_LABEL_HEADER.toLocaleLowerCase();
|
|
@@ -3144,9 +3144,154 @@ var handleFailure = async ({
|
|
|
3144
3144
|
}
|
|
3145
3145
|
};
|
|
3146
3146
|
|
|
3147
|
-
// src/serve/
|
|
3147
|
+
// src/serve/multi-region/handlers.ts
|
|
3148
3148
|
var import_qstash10 = require("@upstash/qstash");
|
|
3149
|
-
|
|
3149
|
+
|
|
3150
|
+
// src/serve/multi-region/utils.ts
|
|
3151
|
+
var VALID_REGIONS = ["EU_CENTRAL_1", "US_EAST_1"];
|
|
3152
|
+
var getRegionFromEnvironment = (environment) => {
|
|
3153
|
+
const region = environment.QSTASH_REGION;
|
|
3154
|
+
return normalizeRegionHeader(region);
|
|
3155
|
+
};
|
|
3156
|
+
function readEnvironmentVariables(environmentVariables, environment, region) {
|
|
3157
|
+
const result = {};
|
|
3158
|
+
for (const variable of environmentVariables) {
|
|
3159
|
+
const key = region ? `${region}_${variable}` : variable;
|
|
3160
|
+
result[variable] = environment[key];
|
|
3161
|
+
}
|
|
3162
|
+
return result;
|
|
3163
|
+
}
|
|
3164
|
+
function readClientEnvironmentVariables(environment, region) {
|
|
3165
|
+
return readEnvironmentVariables(["QSTASH_URL", "QSTASH_TOKEN"], environment, region);
|
|
3166
|
+
}
|
|
3167
|
+
function readReceiverEnvironmentVariables(environment, region) {
|
|
3168
|
+
return readEnvironmentVariables(
|
|
3169
|
+
["QSTASH_CURRENT_SIGNING_KEY", "QSTASH_NEXT_SIGNING_KEY"],
|
|
3170
|
+
environment,
|
|
3171
|
+
region
|
|
3172
|
+
);
|
|
3173
|
+
}
|
|
3174
|
+
function normalizeRegionHeader(region) {
|
|
3175
|
+
if (!region) {
|
|
3176
|
+
return void 0;
|
|
3177
|
+
}
|
|
3178
|
+
region = region.replaceAll("-", "_").toUpperCase();
|
|
3179
|
+
if (VALID_REGIONS.includes(region)) {
|
|
3180
|
+
return region;
|
|
3181
|
+
}
|
|
3182
|
+
console.warn(
|
|
3183
|
+
`[Upstash Workflow] Invalid UPSTASH-REGION header value: "${region}". Expected one of: ${VALID_REGIONS.join(
|
|
3184
|
+
", "
|
|
3185
|
+
)}.`
|
|
3186
|
+
);
|
|
3187
|
+
return void 0;
|
|
3188
|
+
}
|
|
3189
|
+
|
|
3190
|
+
// src/serve/multi-region/handlers.ts
|
|
3191
|
+
var getHandlersForRequest = (qstashHandlers, regionHeader, isFirstInvocation) => {
|
|
3192
|
+
if (qstashHandlers.mode === "single-region") {
|
|
3193
|
+
return qstashHandlers.handlers;
|
|
3194
|
+
}
|
|
3195
|
+
let targetRegion;
|
|
3196
|
+
if (isFirstInvocation) {
|
|
3197
|
+
targetRegion = qstashHandlers.defaultRegion;
|
|
3198
|
+
} else {
|
|
3199
|
+
const normalizedRegion = regionHeader ? normalizeRegionHeader(regionHeader) : void 0;
|
|
3200
|
+
targetRegion = normalizedRegion ?? qstashHandlers.defaultRegion;
|
|
3201
|
+
}
|
|
3202
|
+
const handler = qstashHandlers.handlers[targetRegion];
|
|
3203
|
+
if (!handler) {
|
|
3204
|
+
console.warn(
|
|
3205
|
+
`[Upstash Workflow] No handler found for region "${targetRegion}". Falling back to default region.`
|
|
3206
|
+
);
|
|
3207
|
+
return qstashHandlers.handlers[qstashHandlers.defaultRegion];
|
|
3208
|
+
}
|
|
3209
|
+
return handler;
|
|
3210
|
+
};
|
|
3211
|
+
var createRegionalHandler = (environment, receiverConfig, region, clientOptions) => {
|
|
3212
|
+
const clientEnv = readClientEnvironmentVariables(environment, region);
|
|
3213
|
+
const client = new import_qstash10.Client({
|
|
3214
|
+
...clientOptions,
|
|
3215
|
+
baseUrl: clientEnv.QSTASH_URL,
|
|
3216
|
+
token: clientEnv.QSTASH_TOKEN
|
|
3217
|
+
});
|
|
3218
|
+
const receiver = getReceiver(environment, receiverConfig, region);
|
|
3219
|
+
return { client, receiver };
|
|
3220
|
+
};
|
|
3221
|
+
var shouldUseMultiRegionMode = (environment, qstashClientOption) => {
|
|
3222
|
+
const hasRegionEnv = Boolean(getRegionFromEnvironment(environment));
|
|
3223
|
+
if (hasRegionEnv && (!qstashClientOption || !("http" in qstashClientOption))) {
|
|
3224
|
+
return {
|
|
3225
|
+
isMultiRegion: true,
|
|
3226
|
+
defaultRegion: getRegionFromEnvironment(environment),
|
|
3227
|
+
clientOptions: qstashClientOption
|
|
3228
|
+
};
|
|
3229
|
+
} else {
|
|
3230
|
+
return { isMultiRegion: false };
|
|
3231
|
+
}
|
|
3232
|
+
};
|
|
3233
|
+
var getQStashHandlers = ({
|
|
3234
|
+
environment,
|
|
3235
|
+
qstashClientOption,
|
|
3236
|
+
receiverConfig
|
|
3237
|
+
}) => {
|
|
3238
|
+
const multiRegion = shouldUseMultiRegionMode(environment, qstashClientOption);
|
|
3239
|
+
if (multiRegion.isMultiRegion) {
|
|
3240
|
+
const regions = ["US_EAST_1", "EU_CENTRAL_1"];
|
|
3241
|
+
const handlers = {};
|
|
3242
|
+
for (const region of regions) {
|
|
3243
|
+
try {
|
|
3244
|
+
handlers[region] = createRegionalHandler(
|
|
3245
|
+
environment,
|
|
3246
|
+
receiverConfig,
|
|
3247
|
+
region,
|
|
3248
|
+
multiRegion.clientOptions
|
|
3249
|
+
);
|
|
3250
|
+
} catch (error) {
|
|
3251
|
+
console.warn(`[Upstash Workflow] Failed to create handler for region ${region}:`, error);
|
|
3252
|
+
}
|
|
3253
|
+
}
|
|
3254
|
+
return {
|
|
3255
|
+
mode: "multi-region",
|
|
3256
|
+
handlers,
|
|
3257
|
+
defaultRegion: multiRegion.defaultRegion
|
|
3258
|
+
};
|
|
3259
|
+
} else {
|
|
3260
|
+
return {
|
|
3261
|
+
mode: "single-region",
|
|
3262
|
+
handlers: {
|
|
3263
|
+
client: qstashClientOption && "http" in qstashClientOption ? qstashClientOption : new import_qstash10.Client({
|
|
3264
|
+
...qstashClientOption,
|
|
3265
|
+
baseUrl: environment.QSTASH_URL,
|
|
3266
|
+
token: environment.QSTASH_TOKEN
|
|
3267
|
+
}),
|
|
3268
|
+
receiver: getReceiver(environment, receiverConfig)
|
|
3269
|
+
}
|
|
3270
|
+
};
|
|
3271
|
+
}
|
|
3272
|
+
};
|
|
3273
|
+
var getReceiver = (environment, receiverConfig, region) => {
|
|
3274
|
+
if (typeof receiverConfig === "string") {
|
|
3275
|
+
if (receiverConfig === "set-to-undefined") {
|
|
3276
|
+
return void 0;
|
|
3277
|
+
}
|
|
3278
|
+
const receiverEnv = readReceiverEnvironmentVariables(environment, region);
|
|
3279
|
+
return receiverEnv.QSTASH_CURRENT_SIGNING_KEY && receiverEnv.QSTASH_NEXT_SIGNING_KEY ? new import_qstash10.Receiver({
|
|
3280
|
+
currentSigningKey: receiverEnv.QSTASH_CURRENT_SIGNING_KEY,
|
|
3281
|
+
nextSigningKey: receiverEnv.QSTASH_NEXT_SIGNING_KEY
|
|
3282
|
+
}) : void 0;
|
|
3283
|
+
} else {
|
|
3284
|
+
return receiverConfig;
|
|
3285
|
+
}
|
|
3286
|
+
};
|
|
3287
|
+
var getQStashHandlerOptions = (...params) => {
|
|
3288
|
+
const handlers = getQStashHandlers(...params);
|
|
3289
|
+
return {
|
|
3290
|
+
qstashHandlers: handlers,
|
|
3291
|
+
defaultReceiver: handlers.mode === "single-region" ? handlers.handlers.receiver : handlers.handlers[handlers.defaultRegion].receiver,
|
|
3292
|
+
defaultClient: handlers.mode === "single-region" ? handlers.handlers.client : handlers.handlers[handlers.defaultRegion].client
|
|
3293
|
+
};
|
|
3294
|
+
};
|
|
3150
3295
|
|
|
3151
3296
|
// src/middleware/middleware.ts
|
|
3152
3297
|
var WorkflowMiddleware = class {
|
|
@@ -3285,14 +3430,17 @@ var createResponseData = (workflowRunId, detailedFinishCondition) => {
|
|
|
3285
3430
|
};
|
|
3286
3431
|
var processOptions = (options, internalOptions) => {
|
|
3287
3432
|
const environment = options?.env ?? (typeof process === "undefined" ? {} : process.env);
|
|
3288
|
-
const
|
|
3289
|
-
|
|
3290
|
-
|
|
3433
|
+
const {
|
|
3434
|
+
qstashHandlers,
|
|
3435
|
+
defaultClient: qstashClient,
|
|
3436
|
+
defaultReceiver: receiver
|
|
3437
|
+
} = getQStashHandlerOptions({
|
|
3438
|
+
environment,
|
|
3439
|
+
qstashClientOption: options?.qstashClient,
|
|
3440
|
+
receiverConfig: options && "receiver" in options ? options.receiver ? options.receiver : "set-to-undefined" : "not-set"
|
|
3441
|
+
});
|
|
3291
3442
|
return {
|
|
3292
|
-
qstashClient
|
|
3293
|
-
baseUrl: environment.QSTASH_URL,
|
|
3294
|
-
token: environment.QSTASH_TOKEN
|
|
3295
|
-
}),
|
|
3443
|
+
qstashClient,
|
|
3296
3444
|
initialPayloadParser: (initialRequest) => {
|
|
3297
3445
|
if (!initialRequest) {
|
|
3298
3446
|
return void 0;
|
|
@@ -3307,10 +3455,7 @@ var processOptions = (options, internalOptions) => {
|
|
|
3307
3455
|
throw error;
|
|
3308
3456
|
}
|
|
3309
3457
|
},
|
|
3310
|
-
receiver
|
|
3311
|
-
currentSigningKey: environment.QSTASH_CURRENT_SIGNING_KEY,
|
|
3312
|
-
nextSigningKey: environment.QSTASH_NEXT_SIGNING_KEY
|
|
3313
|
-
}) : void 0,
|
|
3458
|
+
receiver,
|
|
3314
3459
|
baseUrl: environment.UPSTASH_WORKFLOW_URL,
|
|
3315
3460
|
env: environment,
|
|
3316
3461
|
disableTelemetry: false,
|
|
@@ -3324,7 +3469,8 @@ var processOptions = (options, internalOptions) => {
|
|
|
3324
3469
|
headers: responseData.headers
|
|
3325
3470
|
});
|
|
3326
3471
|
}),
|
|
3327
|
-
useJSONContent: internalOptions?.useJSONContent ?? false
|
|
3472
|
+
useJSONContent: internalOptions?.useJSONContent ?? false,
|
|
3473
|
+
qstashHandlers
|
|
3328
3474
|
}
|
|
3329
3475
|
};
|
|
3330
3476
|
};
|
|
@@ -3357,10 +3503,8 @@ var AUTH_FAIL_MESSAGE = `Failed to authenticate Workflow request. If this is une
|
|
|
3357
3503
|
// src/serve/index.ts
|
|
3358
3504
|
var serveBase = (routeFunction, telemetry, options, internalOptions) => {
|
|
3359
3505
|
const {
|
|
3360
|
-
qstashClient,
|
|
3361
3506
|
initialPayloadParser,
|
|
3362
3507
|
url,
|
|
3363
|
-
receiver,
|
|
3364
3508
|
failureFunction,
|
|
3365
3509
|
baseUrl,
|
|
3366
3510
|
env,
|
|
@@ -3380,9 +3524,15 @@ var serveBase = (routeFunction, telemetry, options, internalOptions) => {
|
|
|
3380
3524
|
baseUrl,
|
|
3381
3525
|
middlewareManager.dispatchDebug.bind(middlewareManager)
|
|
3382
3526
|
);
|
|
3383
|
-
const requestPayload = await getPayload(request) ?? "";
|
|
3384
|
-
await verifyRequest(requestPayload, request.headers.get("upstash-signature"), receiver);
|
|
3385
3527
|
const { isFirstInvocation, workflowRunId, unknownSdk } = validateRequest(request);
|
|
3528
|
+
const regionHeader = request.headers.get("upstash-region");
|
|
3529
|
+
const { client: regionalClient, receiver: regionalReceiver } = getHandlersForRequest(
|
|
3530
|
+
internal.qstashHandlers,
|
|
3531
|
+
regionHeader,
|
|
3532
|
+
isFirstInvocation
|
|
3533
|
+
);
|
|
3534
|
+
const requestPayload = await getPayload(request) ?? "";
|
|
3535
|
+
await verifyRequest(requestPayload, request.headers.get("upstash-signature"), regionalReceiver);
|
|
3386
3536
|
middlewareManager.assignWorkflowRunId(workflowRunId);
|
|
3387
3537
|
await middlewareManager.dispatchDebug("onInfo", {
|
|
3388
3538
|
info: `Run id identified. isFirstInvocation: ${isFirstInvocation}, unknownSdk: ${unknownSdk}`
|
|
@@ -3392,7 +3542,7 @@ var serveBase = (routeFunction, telemetry, options, internalOptions) => {
|
|
|
3392
3542
|
isFirstInvocation,
|
|
3393
3543
|
unknownSdk,
|
|
3394
3544
|
workflowRunId,
|
|
3395
|
-
requester:
|
|
3545
|
+
requester: regionalClient.http,
|
|
3396
3546
|
messageId: request.headers.get("upstash-message-id"),
|
|
3397
3547
|
dispatchDebug: middlewareManager.dispatchDebug.bind(middlewareManager)
|
|
3398
3548
|
});
|
|
@@ -3413,7 +3563,7 @@ var serveBase = (routeFunction, telemetry, options, internalOptions) => {
|
|
|
3413
3563
|
const failureCheck = await handleFailure({
|
|
3414
3564
|
request,
|
|
3415
3565
|
requestPayload,
|
|
3416
|
-
qstashClient,
|
|
3566
|
+
qstashClient: regionalClient,
|
|
3417
3567
|
initialPayloadParser,
|
|
3418
3568
|
routeFunction,
|
|
3419
3569
|
failureFunction,
|
|
@@ -3445,7 +3595,7 @@ var serveBase = (routeFunction, telemetry, options, internalOptions) => {
|
|
|
3445
3595
|
const invokeCount = Number(request.headers.get(WORKFLOW_INVOKE_COUNT_HEADER) ?? "0");
|
|
3446
3596
|
const label = request.headers.get(WORKFLOW_LABEL_HEADER) ?? void 0;
|
|
3447
3597
|
const workflowContext = new WorkflowContext({
|
|
3448
|
-
qstashClient,
|
|
3598
|
+
qstashClient: regionalClient,
|
|
3449
3599
|
workflowRunId,
|
|
3450
3600
|
initialPayload: initialPayloadParser(rawInitialPayload),
|
|
3451
3601
|
headers: recreateUserHeaders(request.headers),
|
|
@@ -3476,7 +3626,7 @@ var serveBase = (routeFunction, telemetry, options, internalOptions) => {
|
|
|
3476
3626
|
const callReturnCheck = await handleThirdPartyCallResult({
|
|
3477
3627
|
request,
|
|
3478
3628
|
requestPayload: rawInitialPayload,
|
|
3479
|
-
client:
|
|
3629
|
+
client: regionalClient,
|
|
3480
3630
|
workflowUrl,
|
|
3481
3631
|
telemetry,
|
|
3482
3632
|
middlewareManager
|
package/solidjs.mjs
CHANGED
package/svelte.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as _sveltejs_kit from '@sveltejs/kit';
|
|
2
2
|
import { RequestHandler } from '@sveltejs/kit';
|
|
3
|
-
import {
|
|
4
|
-
import { s as serveManyBase } from './serve-many-
|
|
3
|
+
import { c as RouteFunction, d as WorkflowServeOptions, x as InvokableWorkflow } from './types-pEje3VEB.mjs';
|
|
4
|
+
import { s as serveManyBase } from './serve-many-DhB8-zPD.mjs';
|
|
5
5
|
import '@upstash/qstash';
|
|
6
6
|
import 'zod';
|
|
7
7
|
|
package/svelte.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as _sveltejs_kit from '@sveltejs/kit';
|
|
2
2
|
import { RequestHandler } from '@sveltejs/kit';
|
|
3
|
-
import {
|
|
4
|
-
import { s as serveManyBase } from './serve-many-
|
|
3
|
+
import { c as RouteFunction, d as WorkflowServeOptions, x as InvokableWorkflow } from './types-pEje3VEB.js';
|
|
4
|
+
import { s as serveManyBase } from './serve-many-qnfynN1x.js';
|
|
5
5
|
import '@upstash/qstash';
|
|
6
6
|
import 'zod';
|
|
7
7
|
|
package/svelte.js
CHANGED
|
@@ -841,7 +841,7 @@ var recreateUserHeaders = (headers) => {
|
|
|
841
841
|
const pairs = headers.entries();
|
|
842
842
|
for (const [header, value] of pairs) {
|
|
843
843
|
const headerLowerCase = header.toLowerCase();
|
|
844
|
-
const isUserHeader = !headerLowerCase.startsWith("upstash-workflow-") && // https://vercel.com/docs/edge-network/headers/request-headers#x-vercel-id
|
|
844
|
+
const isUserHeader = headerLowerCase !== "upstash-region" && !headerLowerCase.startsWith("upstash-workflow-") && // https://vercel.com/docs/edge-network/headers/request-headers#x-vercel-id
|
|
845
845
|
!headerLowerCase.startsWith("x-vercel-") && !headerLowerCase.startsWith("x-forwarded-") && // https://blog.cloudflare.com/preventing-request-loops-using-cdn-loop/
|
|
846
846
|
headerLowerCase !== "cf-connecting-ip" && headerLowerCase !== "cdn-loop" && headerLowerCase !== "cf-ew-via" && headerLowerCase !== "cf-ray" && // For Render https://render.com
|
|
847
847
|
headerLowerCase !== "render-proxy-ttl" || headerLowerCase === WORKFLOW_LABEL_HEADER.toLocaleLowerCase();
|
|
@@ -3213,9 +3213,154 @@ var handleFailure = async ({
|
|
|
3213
3213
|
}
|
|
3214
3214
|
};
|
|
3215
3215
|
|
|
3216
|
-
// src/serve/
|
|
3216
|
+
// src/serve/multi-region/handlers.ts
|
|
3217
3217
|
var import_qstash10 = require("@upstash/qstash");
|
|
3218
|
-
|
|
3218
|
+
|
|
3219
|
+
// src/serve/multi-region/utils.ts
|
|
3220
|
+
var VALID_REGIONS = ["EU_CENTRAL_1", "US_EAST_1"];
|
|
3221
|
+
var getRegionFromEnvironment = (environment) => {
|
|
3222
|
+
const region = environment.QSTASH_REGION;
|
|
3223
|
+
return normalizeRegionHeader(region);
|
|
3224
|
+
};
|
|
3225
|
+
function readEnvironmentVariables(environmentVariables, environment, region) {
|
|
3226
|
+
const result = {};
|
|
3227
|
+
for (const variable of environmentVariables) {
|
|
3228
|
+
const key = region ? `${region}_${variable}` : variable;
|
|
3229
|
+
result[variable] = environment[key];
|
|
3230
|
+
}
|
|
3231
|
+
return result;
|
|
3232
|
+
}
|
|
3233
|
+
function readClientEnvironmentVariables(environment, region) {
|
|
3234
|
+
return readEnvironmentVariables(["QSTASH_URL", "QSTASH_TOKEN"], environment, region);
|
|
3235
|
+
}
|
|
3236
|
+
function readReceiverEnvironmentVariables(environment, region) {
|
|
3237
|
+
return readEnvironmentVariables(
|
|
3238
|
+
["QSTASH_CURRENT_SIGNING_KEY", "QSTASH_NEXT_SIGNING_KEY"],
|
|
3239
|
+
environment,
|
|
3240
|
+
region
|
|
3241
|
+
);
|
|
3242
|
+
}
|
|
3243
|
+
function normalizeRegionHeader(region) {
|
|
3244
|
+
if (!region) {
|
|
3245
|
+
return void 0;
|
|
3246
|
+
}
|
|
3247
|
+
region = region.replaceAll("-", "_").toUpperCase();
|
|
3248
|
+
if (VALID_REGIONS.includes(region)) {
|
|
3249
|
+
return region;
|
|
3250
|
+
}
|
|
3251
|
+
console.warn(
|
|
3252
|
+
`[Upstash Workflow] Invalid UPSTASH-REGION header value: "${region}". Expected one of: ${VALID_REGIONS.join(
|
|
3253
|
+
", "
|
|
3254
|
+
)}.`
|
|
3255
|
+
);
|
|
3256
|
+
return void 0;
|
|
3257
|
+
}
|
|
3258
|
+
|
|
3259
|
+
// src/serve/multi-region/handlers.ts
|
|
3260
|
+
var getHandlersForRequest = (qstashHandlers, regionHeader, isFirstInvocation) => {
|
|
3261
|
+
if (qstashHandlers.mode === "single-region") {
|
|
3262
|
+
return qstashHandlers.handlers;
|
|
3263
|
+
}
|
|
3264
|
+
let targetRegion;
|
|
3265
|
+
if (isFirstInvocation) {
|
|
3266
|
+
targetRegion = qstashHandlers.defaultRegion;
|
|
3267
|
+
} else {
|
|
3268
|
+
const normalizedRegion = regionHeader ? normalizeRegionHeader(regionHeader) : void 0;
|
|
3269
|
+
targetRegion = normalizedRegion ?? qstashHandlers.defaultRegion;
|
|
3270
|
+
}
|
|
3271
|
+
const handler = qstashHandlers.handlers[targetRegion];
|
|
3272
|
+
if (!handler) {
|
|
3273
|
+
console.warn(
|
|
3274
|
+
`[Upstash Workflow] No handler found for region "${targetRegion}". Falling back to default region.`
|
|
3275
|
+
);
|
|
3276
|
+
return qstashHandlers.handlers[qstashHandlers.defaultRegion];
|
|
3277
|
+
}
|
|
3278
|
+
return handler;
|
|
3279
|
+
};
|
|
3280
|
+
var createRegionalHandler = (environment, receiverConfig, region, clientOptions) => {
|
|
3281
|
+
const clientEnv = readClientEnvironmentVariables(environment, region);
|
|
3282
|
+
const client = new import_qstash10.Client({
|
|
3283
|
+
...clientOptions,
|
|
3284
|
+
baseUrl: clientEnv.QSTASH_URL,
|
|
3285
|
+
token: clientEnv.QSTASH_TOKEN
|
|
3286
|
+
});
|
|
3287
|
+
const receiver = getReceiver(environment, receiverConfig, region);
|
|
3288
|
+
return { client, receiver };
|
|
3289
|
+
};
|
|
3290
|
+
var shouldUseMultiRegionMode = (environment, qstashClientOption) => {
|
|
3291
|
+
const hasRegionEnv = Boolean(getRegionFromEnvironment(environment));
|
|
3292
|
+
if (hasRegionEnv && (!qstashClientOption || !("http" in qstashClientOption))) {
|
|
3293
|
+
return {
|
|
3294
|
+
isMultiRegion: true,
|
|
3295
|
+
defaultRegion: getRegionFromEnvironment(environment),
|
|
3296
|
+
clientOptions: qstashClientOption
|
|
3297
|
+
};
|
|
3298
|
+
} else {
|
|
3299
|
+
return { isMultiRegion: false };
|
|
3300
|
+
}
|
|
3301
|
+
};
|
|
3302
|
+
var getQStashHandlers = ({
|
|
3303
|
+
environment,
|
|
3304
|
+
qstashClientOption,
|
|
3305
|
+
receiverConfig
|
|
3306
|
+
}) => {
|
|
3307
|
+
const multiRegion = shouldUseMultiRegionMode(environment, qstashClientOption);
|
|
3308
|
+
if (multiRegion.isMultiRegion) {
|
|
3309
|
+
const regions = ["US_EAST_1", "EU_CENTRAL_1"];
|
|
3310
|
+
const handlers = {};
|
|
3311
|
+
for (const region of regions) {
|
|
3312
|
+
try {
|
|
3313
|
+
handlers[region] = createRegionalHandler(
|
|
3314
|
+
environment,
|
|
3315
|
+
receiverConfig,
|
|
3316
|
+
region,
|
|
3317
|
+
multiRegion.clientOptions
|
|
3318
|
+
);
|
|
3319
|
+
} catch (error) {
|
|
3320
|
+
console.warn(`[Upstash Workflow] Failed to create handler for region ${region}:`, error);
|
|
3321
|
+
}
|
|
3322
|
+
}
|
|
3323
|
+
return {
|
|
3324
|
+
mode: "multi-region",
|
|
3325
|
+
handlers,
|
|
3326
|
+
defaultRegion: multiRegion.defaultRegion
|
|
3327
|
+
};
|
|
3328
|
+
} else {
|
|
3329
|
+
return {
|
|
3330
|
+
mode: "single-region",
|
|
3331
|
+
handlers: {
|
|
3332
|
+
client: qstashClientOption && "http" in qstashClientOption ? qstashClientOption : new import_qstash10.Client({
|
|
3333
|
+
...qstashClientOption,
|
|
3334
|
+
baseUrl: environment.QSTASH_URL,
|
|
3335
|
+
token: environment.QSTASH_TOKEN
|
|
3336
|
+
}),
|
|
3337
|
+
receiver: getReceiver(environment, receiverConfig)
|
|
3338
|
+
}
|
|
3339
|
+
};
|
|
3340
|
+
}
|
|
3341
|
+
};
|
|
3342
|
+
var getReceiver = (environment, receiverConfig, region) => {
|
|
3343
|
+
if (typeof receiverConfig === "string") {
|
|
3344
|
+
if (receiverConfig === "set-to-undefined") {
|
|
3345
|
+
return void 0;
|
|
3346
|
+
}
|
|
3347
|
+
const receiverEnv = readReceiverEnvironmentVariables(environment, region);
|
|
3348
|
+
return receiverEnv.QSTASH_CURRENT_SIGNING_KEY && receiverEnv.QSTASH_NEXT_SIGNING_KEY ? new import_qstash10.Receiver({
|
|
3349
|
+
currentSigningKey: receiverEnv.QSTASH_CURRENT_SIGNING_KEY,
|
|
3350
|
+
nextSigningKey: receiverEnv.QSTASH_NEXT_SIGNING_KEY
|
|
3351
|
+
}) : void 0;
|
|
3352
|
+
} else {
|
|
3353
|
+
return receiverConfig;
|
|
3354
|
+
}
|
|
3355
|
+
};
|
|
3356
|
+
var getQStashHandlerOptions = (...params) => {
|
|
3357
|
+
const handlers = getQStashHandlers(...params);
|
|
3358
|
+
return {
|
|
3359
|
+
qstashHandlers: handlers,
|
|
3360
|
+
defaultReceiver: handlers.mode === "single-region" ? handlers.handlers.receiver : handlers.handlers[handlers.defaultRegion].receiver,
|
|
3361
|
+
defaultClient: handlers.mode === "single-region" ? handlers.handlers.client : handlers.handlers[handlers.defaultRegion].client
|
|
3362
|
+
};
|
|
3363
|
+
};
|
|
3219
3364
|
|
|
3220
3365
|
// src/middleware/middleware.ts
|
|
3221
3366
|
var WorkflowMiddleware = class {
|
|
@@ -3354,14 +3499,17 @@ var createResponseData = (workflowRunId, detailedFinishCondition) => {
|
|
|
3354
3499
|
};
|
|
3355
3500
|
var processOptions = (options, internalOptions) => {
|
|
3356
3501
|
const environment = options?.env ?? (typeof process === "undefined" ? {} : process.env);
|
|
3357
|
-
const
|
|
3358
|
-
|
|
3359
|
-
|
|
3502
|
+
const {
|
|
3503
|
+
qstashHandlers,
|
|
3504
|
+
defaultClient: qstashClient,
|
|
3505
|
+
defaultReceiver: receiver
|
|
3506
|
+
} = getQStashHandlerOptions({
|
|
3507
|
+
environment,
|
|
3508
|
+
qstashClientOption: options?.qstashClient,
|
|
3509
|
+
receiverConfig: options && "receiver" in options ? options.receiver ? options.receiver : "set-to-undefined" : "not-set"
|
|
3510
|
+
});
|
|
3360
3511
|
return {
|
|
3361
|
-
qstashClient
|
|
3362
|
-
baseUrl: environment.QSTASH_URL,
|
|
3363
|
-
token: environment.QSTASH_TOKEN
|
|
3364
|
-
}),
|
|
3512
|
+
qstashClient,
|
|
3365
3513
|
initialPayloadParser: (initialRequest) => {
|
|
3366
3514
|
if (!initialRequest) {
|
|
3367
3515
|
return void 0;
|
|
@@ -3376,10 +3524,7 @@ var processOptions = (options, internalOptions) => {
|
|
|
3376
3524
|
throw error;
|
|
3377
3525
|
}
|
|
3378
3526
|
},
|
|
3379
|
-
receiver
|
|
3380
|
-
currentSigningKey: environment.QSTASH_CURRENT_SIGNING_KEY,
|
|
3381
|
-
nextSigningKey: environment.QSTASH_NEXT_SIGNING_KEY
|
|
3382
|
-
}) : void 0,
|
|
3527
|
+
receiver,
|
|
3383
3528
|
baseUrl: environment.UPSTASH_WORKFLOW_URL,
|
|
3384
3529
|
env: environment,
|
|
3385
3530
|
disableTelemetry: false,
|
|
@@ -3393,7 +3538,8 @@ var processOptions = (options, internalOptions) => {
|
|
|
3393
3538
|
headers: responseData.headers
|
|
3394
3539
|
});
|
|
3395
3540
|
}),
|
|
3396
|
-
useJSONContent: internalOptions?.useJSONContent ?? false
|
|
3541
|
+
useJSONContent: internalOptions?.useJSONContent ?? false,
|
|
3542
|
+
qstashHandlers
|
|
3397
3543
|
}
|
|
3398
3544
|
};
|
|
3399
3545
|
};
|
|
@@ -3426,10 +3572,8 @@ var AUTH_FAIL_MESSAGE = `Failed to authenticate Workflow request. If this is une
|
|
|
3426
3572
|
// src/serve/index.ts
|
|
3427
3573
|
var serveBase = (routeFunction, telemetry2, options, internalOptions) => {
|
|
3428
3574
|
const {
|
|
3429
|
-
qstashClient,
|
|
3430
3575
|
initialPayloadParser,
|
|
3431
3576
|
url,
|
|
3432
|
-
receiver,
|
|
3433
3577
|
failureFunction,
|
|
3434
3578
|
baseUrl,
|
|
3435
3579
|
env,
|
|
@@ -3449,9 +3593,15 @@ var serveBase = (routeFunction, telemetry2, options, internalOptions) => {
|
|
|
3449
3593
|
baseUrl,
|
|
3450
3594
|
middlewareManager.dispatchDebug.bind(middlewareManager)
|
|
3451
3595
|
);
|
|
3452
|
-
const requestPayload = await getPayload(request) ?? "";
|
|
3453
|
-
await verifyRequest(requestPayload, request.headers.get("upstash-signature"), receiver);
|
|
3454
3596
|
const { isFirstInvocation, workflowRunId, unknownSdk } = validateRequest(request);
|
|
3597
|
+
const regionHeader = request.headers.get("upstash-region");
|
|
3598
|
+
const { client: regionalClient, receiver: regionalReceiver } = getHandlersForRequest(
|
|
3599
|
+
internal.qstashHandlers,
|
|
3600
|
+
regionHeader,
|
|
3601
|
+
isFirstInvocation
|
|
3602
|
+
);
|
|
3603
|
+
const requestPayload = await getPayload(request) ?? "";
|
|
3604
|
+
await verifyRequest(requestPayload, request.headers.get("upstash-signature"), regionalReceiver);
|
|
3455
3605
|
middlewareManager.assignWorkflowRunId(workflowRunId);
|
|
3456
3606
|
await middlewareManager.dispatchDebug("onInfo", {
|
|
3457
3607
|
info: `Run id identified. isFirstInvocation: ${isFirstInvocation}, unknownSdk: ${unknownSdk}`
|
|
@@ -3461,7 +3611,7 @@ var serveBase = (routeFunction, telemetry2, options, internalOptions) => {
|
|
|
3461
3611
|
isFirstInvocation,
|
|
3462
3612
|
unknownSdk,
|
|
3463
3613
|
workflowRunId,
|
|
3464
|
-
requester:
|
|
3614
|
+
requester: regionalClient.http,
|
|
3465
3615
|
messageId: request.headers.get("upstash-message-id"),
|
|
3466
3616
|
dispatchDebug: middlewareManager.dispatchDebug.bind(middlewareManager)
|
|
3467
3617
|
});
|
|
@@ -3482,7 +3632,7 @@ var serveBase = (routeFunction, telemetry2, options, internalOptions) => {
|
|
|
3482
3632
|
const failureCheck = await handleFailure({
|
|
3483
3633
|
request,
|
|
3484
3634
|
requestPayload,
|
|
3485
|
-
qstashClient,
|
|
3635
|
+
qstashClient: regionalClient,
|
|
3486
3636
|
initialPayloadParser,
|
|
3487
3637
|
routeFunction,
|
|
3488
3638
|
failureFunction,
|
|
@@ -3514,7 +3664,7 @@ var serveBase = (routeFunction, telemetry2, options, internalOptions) => {
|
|
|
3514
3664
|
const invokeCount = Number(request.headers.get(WORKFLOW_INVOKE_COUNT_HEADER) ?? "0");
|
|
3515
3665
|
const label = request.headers.get(WORKFLOW_LABEL_HEADER) ?? void 0;
|
|
3516
3666
|
const workflowContext = new WorkflowContext({
|
|
3517
|
-
qstashClient,
|
|
3667
|
+
qstashClient: regionalClient,
|
|
3518
3668
|
workflowRunId,
|
|
3519
3669
|
initialPayload: initialPayloadParser(rawInitialPayload),
|
|
3520
3670
|
headers: recreateUserHeaders(request.headers),
|
|
@@ -3545,7 +3695,7 @@ var serveBase = (routeFunction, telemetry2, options, internalOptions) => {
|
|
|
3545
3695
|
const callReturnCheck = await handleThirdPartyCallResult({
|
|
3546
3696
|
request,
|
|
3547
3697
|
requestPayload: rawInitialPayload,
|
|
3548
|
-
client:
|
|
3698
|
+
client: regionalClient,
|
|
3549
3699
|
workflowUrl,
|
|
3550
3700
|
telemetry: telemetry2,
|
|
3551
3701
|
middlewareManager
|
package/svelte.mjs
CHANGED
package/tanstack.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { s as serveManyBase } from './serve-many-
|
|
1
|
+
import { c as RouteFunction, d as WorkflowServeOptions, E as ExclusiveValidationOptions, x as InvokableWorkflow } from './types-pEje3VEB.mjs';
|
|
2
|
+
import { s as serveManyBase } from './serve-many-DhB8-zPD.mjs';
|
|
3
3
|
import '@upstash/qstash';
|
|
4
4
|
import 'zod';
|
|
5
5
|
|
package/tanstack.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { s as serveManyBase } from './serve-many-
|
|
1
|
+
import { c as RouteFunction, d as WorkflowServeOptions, E as ExclusiveValidationOptions, x as InvokableWorkflow } from './types-pEje3VEB.js';
|
|
2
|
+
import { s as serveManyBase } from './serve-many-qnfynN1x.js';
|
|
3
3
|
import '@upstash/qstash';
|
|
4
4
|
import 'zod';
|
|
5
5
|
|