@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/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/options.ts
3525
+ // src/serve/multi-region/handlers.ts
3526
3526
  var import_qstash10 = require("@upstash/qstash");
3527
- var import_qstash11 = require("@upstash/qstash");
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 receiverEnvironmentVariablesSet = Boolean(
3667
- environment.QSTASH_CURRENT_SIGNING_KEY && environment.QSTASH_NEXT_SIGNING_KEY
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: options?.qstashClient ?? new import_qstash11.Client({
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: receiverEnvironmentVariablesSet ? new import_qstash10.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: qstashClient.http,
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: qstashClient,
4007
+ client: regionalClient,
3858
4008
  workflowUrl,
3859
4009
  telemetry: telemetry2,
3860
4010
  middlewareManager
package/h3.mjs CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  SDK_TELEMETRY,
3
3
  serveBase,
4
4
  serveManyBase
5
- } from "./chunk-5GWDM6XJ.mjs";
5
+ } from "./chunk-2Z32SOYM.mjs";
6
6
 
7
7
  // node_modules/defu/dist/defu.mjs
8
8
  function isPlainObject(value) {
package/hono.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Context } from 'hono';
2
- import { a as RouteFunction, b as WorkflowServeOptions, x as InvokableWorkflow } from './types-ByzQdZjb.mjs';
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-qpxb-yr-.mjs';
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 { a as RouteFunction, b as WorkflowServeOptions, x as InvokableWorkflow } from './types-ByzQdZjb.js';
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-CFlNO2Iq.js';
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/options.ts
3216
+ // src/serve/multi-region/handlers.ts
3217
3217
  var import_qstash10 = require("@upstash/qstash");
3218
- var import_qstash11 = require("@upstash/qstash");
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 receiverEnvironmentVariablesSet = Boolean(
3358
- environment.QSTASH_CURRENT_SIGNING_KEY && environment.QSTASH_NEXT_SIGNING_KEY
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: options?.qstashClient ?? new import_qstash11.Client({
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: receiverEnvironmentVariablesSet ? new import_qstash10.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: qstashClient.http,
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: qstashClient,
3698
+ client: regionalClient,
3549
3699
  workflowUrl,
3550
3700
  telemetry: telemetry2,
3551
3701
  middlewareManager
package/hono.mjs CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  SDK_TELEMETRY,
3
3
  serveBase,
4
4
  serveManyBase
5
- } from "./chunk-5GWDM6XJ.mjs";
5
+ } from "./chunk-2Z32SOYM.mjs";
6
6
 
7
7
  // platforms/hono.ts
8
8
  var telemetry = {
package/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { S as StepType, R as RawStep, W as WorkflowMiddleware, a as RouteFunction, b as WorkflowServeOptions, T as Telemetry, N as NotifyResponse, c as Waiter } from './types-ByzQdZjb.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, p as RequiredExceptFields, l as Step, n as StepFunction, k as StepTypes, m as SyncStepFunction, u as WaitEventOptions, q as WaitRequest, r as WaitStepResponse, e as WorkflowAbort, i as WorkflowClient, h as WorkflowContext, d as WorkflowError, f as WorkflowNonRetryableError, j as WorkflowReceiver, g as WorkflowRetryAfterError } from './types-ByzQdZjb.mjs';
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 };