@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/h3.js
CHANGED
|
@@ -1150,7 +1150,7 @@ var recreateUserHeaders = (headers) => {
|
|
|
1150
1150
|
const pairs = headers.entries();
|
|
1151
1151
|
for (const [header, value] of pairs) {
|
|
1152
1152
|
const headerLowerCase = header.toLowerCase();
|
|
1153
|
-
const isUserHeader = !headerLowerCase.startsWith("upstash-workflow-") && // https://vercel.com/docs/edge-network/headers/request-headers#x-vercel-id
|
|
1153
|
+
const isUserHeader = headerLowerCase !== "upstash-region" && !headerLowerCase.startsWith("upstash-workflow-") && // https://vercel.com/docs/edge-network/headers/request-headers#x-vercel-id
|
|
1154
1154
|
!headerLowerCase.startsWith("x-vercel-") && !headerLowerCase.startsWith("x-forwarded-") && // https://blog.cloudflare.com/preventing-request-loops-using-cdn-loop/
|
|
1155
1155
|
headerLowerCase !== "cf-connecting-ip" && headerLowerCase !== "cdn-loop" && headerLowerCase !== "cf-ew-via" && headerLowerCase !== "cf-ray" && // For Render https://render.com
|
|
1156
1156
|
headerLowerCase !== "render-proxy-ttl" || headerLowerCase === WORKFLOW_LABEL_HEADER.toLocaleLowerCase();
|
|
@@ -3522,9 +3522,154 @@ var handleFailure = async ({
|
|
|
3522
3522
|
}
|
|
3523
3523
|
};
|
|
3524
3524
|
|
|
3525
|
-
// src/serve/
|
|
3525
|
+
// src/serve/multi-region/handlers.ts
|
|
3526
3526
|
var import_qstash10 = require("@upstash/qstash");
|
|
3527
|
-
|
|
3527
|
+
|
|
3528
|
+
// src/serve/multi-region/utils.ts
|
|
3529
|
+
var VALID_REGIONS = ["EU_CENTRAL_1", "US_EAST_1"];
|
|
3530
|
+
var getRegionFromEnvironment = (environment) => {
|
|
3531
|
+
const region = environment.QSTASH_REGION;
|
|
3532
|
+
return normalizeRegionHeader(region);
|
|
3533
|
+
};
|
|
3534
|
+
function readEnvironmentVariables(environmentVariables, environment, region) {
|
|
3535
|
+
const result = {};
|
|
3536
|
+
for (const variable of environmentVariables) {
|
|
3537
|
+
const key = region ? `${region}_${variable}` : variable;
|
|
3538
|
+
result[variable] = environment[key];
|
|
3539
|
+
}
|
|
3540
|
+
return result;
|
|
3541
|
+
}
|
|
3542
|
+
function readClientEnvironmentVariables(environment, region) {
|
|
3543
|
+
return readEnvironmentVariables(["QSTASH_URL", "QSTASH_TOKEN"], environment, region);
|
|
3544
|
+
}
|
|
3545
|
+
function readReceiverEnvironmentVariables(environment, region) {
|
|
3546
|
+
return readEnvironmentVariables(
|
|
3547
|
+
["QSTASH_CURRENT_SIGNING_KEY", "QSTASH_NEXT_SIGNING_KEY"],
|
|
3548
|
+
environment,
|
|
3549
|
+
region
|
|
3550
|
+
);
|
|
3551
|
+
}
|
|
3552
|
+
function normalizeRegionHeader(region) {
|
|
3553
|
+
if (!region) {
|
|
3554
|
+
return void 0;
|
|
3555
|
+
}
|
|
3556
|
+
region = region.replaceAll("-", "_").toUpperCase();
|
|
3557
|
+
if (VALID_REGIONS.includes(region)) {
|
|
3558
|
+
return region;
|
|
3559
|
+
}
|
|
3560
|
+
console.warn(
|
|
3561
|
+
`[Upstash Workflow] Invalid UPSTASH-REGION header value: "${region}". Expected one of: ${VALID_REGIONS.join(
|
|
3562
|
+
", "
|
|
3563
|
+
)}.`
|
|
3564
|
+
);
|
|
3565
|
+
return void 0;
|
|
3566
|
+
}
|
|
3567
|
+
|
|
3568
|
+
// src/serve/multi-region/handlers.ts
|
|
3569
|
+
var getHandlersForRequest = (qstashHandlers, regionHeader, isFirstInvocation) => {
|
|
3570
|
+
if (qstashHandlers.mode === "single-region") {
|
|
3571
|
+
return qstashHandlers.handlers;
|
|
3572
|
+
}
|
|
3573
|
+
let targetRegion;
|
|
3574
|
+
if (isFirstInvocation) {
|
|
3575
|
+
targetRegion = qstashHandlers.defaultRegion;
|
|
3576
|
+
} else {
|
|
3577
|
+
const normalizedRegion = regionHeader ? normalizeRegionHeader(regionHeader) : void 0;
|
|
3578
|
+
targetRegion = normalizedRegion ?? qstashHandlers.defaultRegion;
|
|
3579
|
+
}
|
|
3580
|
+
const handler = qstashHandlers.handlers[targetRegion];
|
|
3581
|
+
if (!handler) {
|
|
3582
|
+
console.warn(
|
|
3583
|
+
`[Upstash Workflow] No handler found for region "${targetRegion}". Falling back to default region.`
|
|
3584
|
+
);
|
|
3585
|
+
return qstashHandlers.handlers[qstashHandlers.defaultRegion];
|
|
3586
|
+
}
|
|
3587
|
+
return handler;
|
|
3588
|
+
};
|
|
3589
|
+
var createRegionalHandler = (environment, receiverConfig, region, clientOptions) => {
|
|
3590
|
+
const clientEnv = readClientEnvironmentVariables(environment, region);
|
|
3591
|
+
const client = new import_qstash10.Client({
|
|
3592
|
+
...clientOptions,
|
|
3593
|
+
baseUrl: clientEnv.QSTASH_URL,
|
|
3594
|
+
token: clientEnv.QSTASH_TOKEN
|
|
3595
|
+
});
|
|
3596
|
+
const receiver = getReceiver(environment, receiverConfig, region);
|
|
3597
|
+
return { client, receiver };
|
|
3598
|
+
};
|
|
3599
|
+
var shouldUseMultiRegionMode = (environment, qstashClientOption) => {
|
|
3600
|
+
const hasRegionEnv = Boolean(getRegionFromEnvironment(environment));
|
|
3601
|
+
if (hasRegionEnv && (!qstashClientOption || !("http" in qstashClientOption))) {
|
|
3602
|
+
return {
|
|
3603
|
+
isMultiRegion: true,
|
|
3604
|
+
defaultRegion: getRegionFromEnvironment(environment),
|
|
3605
|
+
clientOptions: qstashClientOption
|
|
3606
|
+
};
|
|
3607
|
+
} else {
|
|
3608
|
+
return { isMultiRegion: false };
|
|
3609
|
+
}
|
|
3610
|
+
};
|
|
3611
|
+
var getQStashHandlers = ({
|
|
3612
|
+
environment,
|
|
3613
|
+
qstashClientOption,
|
|
3614
|
+
receiverConfig
|
|
3615
|
+
}) => {
|
|
3616
|
+
const multiRegion = shouldUseMultiRegionMode(environment, qstashClientOption);
|
|
3617
|
+
if (multiRegion.isMultiRegion) {
|
|
3618
|
+
const regions = ["US_EAST_1", "EU_CENTRAL_1"];
|
|
3619
|
+
const handlers = {};
|
|
3620
|
+
for (const region of regions) {
|
|
3621
|
+
try {
|
|
3622
|
+
handlers[region] = createRegionalHandler(
|
|
3623
|
+
environment,
|
|
3624
|
+
receiverConfig,
|
|
3625
|
+
region,
|
|
3626
|
+
multiRegion.clientOptions
|
|
3627
|
+
);
|
|
3628
|
+
} catch (error) {
|
|
3629
|
+
console.warn(`[Upstash Workflow] Failed to create handler for region ${region}:`, error);
|
|
3630
|
+
}
|
|
3631
|
+
}
|
|
3632
|
+
return {
|
|
3633
|
+
mode: "multi-region",
|
|
3634
|
+
handlers,
|
|
3635
|
+
defaultRegion: multiRegion.defaultRegion
|
|
3636
|
+
};
|
|
3637
|
+
} else {
|
|
3638
|
+
return {
|
|
3639
|
+
mode: "single-region",
|
|
3640
|
+
handlers: {
|
|
3641
|
+
client: qstashClientOption && "http" in qstashClientOption ? qstashClientOption : new import_qstash10.Client({
|
|
3642
|
+
...qstashClientOption,
|
|
3643
|
+
baseUrl: environment.QSTASH_URL,
|
|
3644
|
+
token: environment.QSTASH_TOKEN
|
|
3645
|
+
}),
|
|
3646
|
+
receiver: getReceiver(environment, receiverConfig)
|
|
3647
|
+
}
|
|
3648
|
+
};
|
|
3649
|
+
}
|
|
3650
|
+
};
|
|
3651
|
+
var getReceiver = (environment, receiverConfig, region) => {
|
|
3652
|
+
if (typeof receiverConfig === "string") {
|
|
3653
|
+
if (receiverConfig === "set-to-undefined") {
|
|
3654
|
+
return void 0;
|
|
3655
|
+
}
|
|
3656
|
+
const receiverEnv = readReceiverEnvironmentVariables(environment, region);
|
|
3657
|
+
return receiverEnv.QSTASH_CURRENT_SIGNING_KEY && receiverEnv.QSTASH_NEXT_SIGNING_KEY ? new import_qstash10.Receiver({
|
|
3658
|
+
currentSigningKey: receiverEnv.QSTASH_CURRENT_SIGNING_KEY,
|
|
3659
|
+
nextSigningKey: receiverEnv.QSTASH_NEXT_SIGNING_KEY
|
|
3660
|
+
}) : void 0;
|
|
3661
|
+
} else {
|
|
3662
|
+
return receiverConfig;
|
|
3663
|
+
}
|
|
3664
|
+
};
|
|
3665
|
+
var getQStashHandlerOptions = (...params) => {
|
|
3666
|
+
const handlers = getQStashHandlers(...params);
|
|
3667
|
+
return {
|
|
3668
|
+
qstashHandlers: handlers,
|
|
3669
|
+
defaultReceiver: handlers.mode === "single-region" ? handlers.handlers.receiver : handlers.handlers[handlers.defaultRegion].receiver,
|
|
3670
|
+
defaultClient: handlers.mode === "single-region" ? handlers.handlers.client : handlers.handlers[handlers.defaultRegion].client
|
|
3671
|
+
};
|
|
3672
|
+
};
|
|
3528
3673
|
|
|
3529
3674
|
// src/middleware/middleware.ts
|
|
3530
3675
|
var WorkflowMiddleware = class {
|
|
@@ -3663,14 +3808,17 @@ var createResponseData = (workflowRunId, detailedFinishCondition) => {
|
|
|
3663
3808
|
};
|
|
3664
3809
|
var processOptions = (options, internalOptions) => {
|
|
3665
3810
|
const environment = options?.env ?? (typeof process === "undefined" ? {} : process.env);
|
|
3666
|
-
const
|
|
3667
|
-
|
|
3668
|
-
|
|
3811
|
+
const {
|
|
3812
|
+
qstashHandlers,
|
|
3813
|
+
defaultClient: qstashClient,
|
|
3814
|
+
defaultReceiver: receiver
|
|
3815
|
+
} = getQStashHandlerOptions({
|
|
3816
|
+
environment,
|
|
3817
|
+
qstashClientOption: options?.qstashClient,
|
|
3818
|
+
receiverConfig: options && "receiver" in options ? options.receiver ? options.receiver : "set-to-undefined" : "not-set"
|
|
3819
|
+
});
|
|
3669
3820
|
return {
|
|
3670
|
-
qstashClient
|
|
3671
|
-
baseUrl: environment.QSTASH_URL,
|
|
3672
|
-
token: environment.QSTASH_TOKEN
|
|
3673
|
-
}),
|
|
3821
|
+
qstashClient,
|
|
3674
3822
|
initialPayloadParser: (initialRequest) => {
|
|
3675
3823
|
if (!initialRequest) {
|
|
3676
3824
|
return void 0;
|
|
@@ -3685,10 +3833,7 @@ var processOptions = (options, internalOptions) => {
|
|
|
3685
3833
|
throw error;
|
|
3686
3834
|
}
|
|
3687
3835
|
},
|
|
3688
|
-
receiver
|
|
3689
|
-
currentSigningKey: environment.QSTASH_CURRENT_SIGNING_KEY,
|
|
3690
|
-
nextSigningKey: environment.QSTASH_NEXT_SIGNING_KEY
|
|
3691
|
-
}) : void 0,
|
|
3836
|
+
receiver,
|
|
3692
3837
|
baseUrl: environment.UPSTASH_WORKFLOW_URL,
|
|
3693
3838
|
env: environment,
|
|
3694
3839
|
disableTelemetry: false,
|
|
@@ -3702,7 +3847,8 @@ var processOptions = (options, internalOptions) => {
|
|
|
3702
3847
|
headers: responseData.headers
|
|
3703
3848
|
});
|
|
3704
3849
|
}),
|
|
3705
|
-
useJSONContent: internalOptions?.useJSONContent ?? false
|
|
3850
|
+
useJSONContent: internalOptions?.useJSONContent ?? false,
|
|
3851
|
+
qstashHandlers
|
|
3706
3852
|
}
|
|
3707
3853
|
};
|
|
3708
3854
|
};
|
|
@@ -3735,10 +3881,8 @@ var AUTH_FAIL_MESSAGE = `Failed to authenticate Workflow request. If this is une
|
|
|
3735
3881
|
// src/serve/index.ts
|
|
3736
3882
|
var serveBase = (routeFunction, telemetry2, options, internalOptions) => {
|
|
3737
3883
|
const {
|
|
3738
|
-
qstashClient,
|
|
3739
3884
|
initialPayloadParser,
|
|
3740
3885
|
url,
|
|
3741
|
-
receiver,
|
|
3742
3886
|
failureFunction,
|
|
3743
3887
|
baseUrl,
|
|
3744
3888
|
env,
|
|
@@ -3758,9 +3902,15 @@ var serveBase = (routeFunction, telemetry2, options, internalOptions) => {
|
|
|
3758
3902
|
baseUrl,
|
|
3759
3903
|
middlewareManager.dispatchDebug.bind(middlewareManager)
|
|
3760
3904
|
);
|
|
3761
|
-
const requestPayload = await getPayload(request) ?? "";
|
|
3762
|
-
await verifyRequest(requestPayload, request.headers.get("upstash-signature"), receiver);
|
|
3763
3905
|
const { isFirstInvocation, workflowRunId, unknownSdk } = validateRequest(request);
|
|
3906
|
+
const regionHeader = request.headers.get("upstash-region");
|
|
3907
|
+
const { client: regionalClient, receiver: regionalReceiver } = getHandlersForRequest(
|
|
3908
|
+
internal.qstashHandlers,
|
|
3909
|
+
regionHeader,
|
|
3910
|
+
isFirstInvocation
|
|
3911
|
+
);
|
|
3912
|
+
const requestPayload = await getPayload(request) ?? "";
|
|
3913
|
+
await verifyRequest(requestPayload, request.headers.get("upstash-signature"), regionalReceiver);
|
|
3764
3914
|
middlewareManager.assignWorkflowRunId(workflowRunId);
|
|
3765
3915
|
await middlewareManager.dispatchDebug("onInfo", {
|
|
3766
3916
|
info: `Run id identified. isFirstInvocation: ${isFirstInvocation}, unknownSdk: ${unknownSdk}`
|
|
@@ -3770,7 +3920,7 @@ var serveBase = (routeFunction, telemetry2, options, internalOptions) => {
|
|
|
3770
3920
|
isFirstInvocation,
|
|
3771
3921
|
unknownSdk,
|
|
3772
3922
|
workflowRunId,
|
|
3773
|
-
requester:
|
|
3923
|
+
requester: regionalClient.http,
|
|
3774
3924
|
messageId: request.headers.get("upstash-message-id"),
|
|
3775
3925
|
dispatchDebug: middlewareManager.dispatchDebug.bind(middlewareManager)
|
|
3776
3926
|
});
|
|
@@ -3791,7 +3941,7 @@ var serveBase = (routeFunction, telemetry2, options, internalOptions) => {
|
|
|
3791
3941
|
const failureCheck = await handleFailure({
|
|
3792
3942
|
request,
|
|
3793
3943
|
requestPayload,
|
|
3794
|
-
qstashClient,
|
|
3944
|
+
qstashClient: regionalClient,
|
|
3795
3945
|
initialPayloadParser,
|
|
3796
3946
|
routeFunction,
|
|
3797
3947
|
failureFunction,
|
|
@@ -3823,7 +3973,7 @@ var serveBase = (routeFunction, telemetry2, options, internalOptions) => {
|
|
|
3823
3973
|
const invokeCount = Number(request.headers.get(WORKFLOW_INVOKE_COUNT_HEADER) ?? "0");
|
|
3824
3974
|
const label = request.headers.get(WORKFLOW_LABEL_HEADER) ?? void 0;
|
|
3825
3975
|
const workflowContext = new WorkflowContext({
|
|
3826
|
-
qstashClient,
|
|
3976
|
+
qstashClient: regionalClient,
|
|
3827
3977
|
workflowRunId,
|
|
3828
3978
|
initialPayload: initialPayloadParser(rawInitialPayload),
|
|
3829
3979
|
headers: recreateUserHeaders(request.headers),
|
|
@@ -3854,7 +4004,7 @@ var serveBase = (routeFunction, telemetry2, options, internalOptions) => {
|
|
|
3854
4004
|
const callReturnCheck = await handleThirdPartyCallResult({
|
|
3855
4005
|
request,
|
|
3856
4006
|
requestPayload: rawInitialPayload,
|
|
3857
|
-
client:
|
|
4007
|
+
client: regionalClient,
|
|
3858
4008
|
workflowUrl,
|
|
3859
4009
|
telemetry: telemetry2,
|
|
3860
4010
|
middlewareManager
|
package/h3.mjs
CHANGED
package/hono.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Context } from 'hono';
|
|
2
|
-
import {
|
|
2
|
+
import { c as RouteFunction, d as WorkflowServeOptions, x as InvokableWorkflow } from './types-pEje3VEB.mjs';
|
|
3
3
|
import { Variables } from 'hono/types';
|
|
4
|
-
import { s as serveManyBase } from './serve-many-
|
|
4
|
+
import { s as serveManyBase } from './serve-many-DhB8-zPD.mjs';
|
|
5
5
|
import '@upstash/qstash';
|
|
6
6
|
import 'zod';
|
|
7
7
|
|
package/hono.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Context } from 'hono';
|
|
2
|
-
import {
|
|
2
|
+
import { c as RouteFunction, d as WorkflowServeOptions, x as InvokableWorkflow } from './types-pEje3VEB.js';
|
|
3
3
|
import { Variables } from 'hono/types';
|
|
4
|
-
import { s as serveManyBase } from './serve-many-
|
|
4
|
+
import { s as serveManyBase } from './serve-many-qnfynN1x.js';
|
|
5
5
|
import '@upstash/qstash';
|
|
6
6
|
import 'zod';
|
|
7
7
|
|
package/hono.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/hono.mjs
CHANGED
package/index.d.mts
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.mjs';
|
|
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.mjs';
|
|
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 };
|