@upstash/qstash 2.10.0 → 2.11.0

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/cloudflare.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { ae as RouteFunction, af as WorkflowServeOptions } from './client-CsM1dTnz.js';
1
+ import { ae as RouteFunction, af as WorkflowServeOptions } from './client-CUioGZfg.js';
2
2
  import 'neverthrow';
3
3
 
4
4
  type WorkflowBindings = {
package/cloudflare.js CHANGED
@@ -457,17 +457,23 @@ function normalizeCursor(response) {
457
457
  const cursor = response.cursor;
458
458
  return { ...response, cursor: cursor || void 0 };
459
459
  }
460
+ function _processGlobal() {
461
+ const proc = globalThis["process"];
462
+ return proc;
463
+ }
460
464
  function getRuntime() {
461
- if (typeof process === "object" && typeof process.versions == "object" && process.versions.bun)
462
- return `bun@${process.versions.bun}`;
465
+ const proc = _processGlobal();
466
+ if (proc?.versions?.bun)
467
+ return `bun@${proc.versions.bun}`;
463
468
  if (typeof EdgeRuntime === "string")
464
469
  return "edge-light";
465
- else if (typeof process === "object" && typeof process.version === "string")
466
- return `node@${process.version}`;
470
+ if (typeof proc?.version === "string")
471
+ return `node@${proc.version}`;
467
472
  return "";
468
473
  }
469
474
  function getSafeEnvironment() {
470
- return typeof process === "undefined" ? {} : process.env;
475
+ const proc = _processGlobal();
476
+ return proc?.env ?? {};
471
477
  }
472
478
 
473
479
  // src/client/multi-region/utils.ts
@@ -511,12 +517,451 @@ function normalizeRegionHeader(region) {
511
517
  return void 0;
512
518
  }
513
519
 
520
+ // src/dev-server/constants.ts
521
+ var DEFAULT_DEV_PORT = 8080;
522
+ var DEV_CREDENTIALS = {
523
+ token: "eyJVc2VySUQiOiJkZWZhdWx0VXNlciIsIlBhc3N3b3JkIjoiZGVmYXVsdFBhc3N3b3JkIn0=",
524
+ currentSigningKey: "sig_7kYjw48mhY7kAjqNGcy6cr29RJ6r",
525
+ nextSigningKey: "sig_5ZB6DVzB1wjE8S6rZ7eenA8Pdnhs"
526
+ };
527
+ var GITHUB_RELEASES_URL = "https://api.github.com/repos/upstash/qstash-cli/releases/latest";
528
+ var BINARY_URL_BASE = "https://artifacts.upstash.com/qstash/versions";
529
+ var CONSOLE_URL = "https://console.upstash.com/qstash/local-mode-user";
530
+ var DEV_PREFIX = "\x1B[2m[QStash Dev]\x1B[0m";
531
+ var CLI_PREFIX = "\x1B[2m[QStash CLI]\x1B[0m";
532
+ var _n = (m) => `node:${m}`;
533
+ var importHttp = () => import(
534
+ /* webpackIgnore: true */
535
+ _n("http")
536
+ );
537
+ var importHttps = () => import(
538
+ /* webpackIgnore: true */
539
+ _n("https")
540
+ );
541
+ var importFs = () => import(
542
+ /* webpackIgnore: true */
543
+ _n("fs")
544
+ );
545
+ var importChildProcess = () => import(
546
+ /* webpackIgnore: true */
547
+ _n("child_process")
548
+ );
549
+ var importOs = () => import(
550
+ /* webpackIgnore: true */
551
+ _n("os")
552
+ );
553
+
554
+ // src/dev-server/http.ts
555
+ var HTTP_OK = 200;
556
+ var HTTP_MULTI_CHOICE = 300;
557
+ var nativeGet = async (url, headers, timeoutMs) => {
558
+ const parsedUrl = new URL(url);
559
+ const httpModule = parsedUrl.protocol === "https:" ? await importHttps() : await importHttp();
560
+ return new Promise((resolve, reject) => {
561
+ const request = httpModule.get(url, { headers }, (response) => {
562
+ const chunks = [];
563
+ response.on("data", (chunk) => chunks.push(chunk));
564
+ response.on("end", () => {
565
+ const statusCode = response.statusCode ?? 0;
566
+ resolve({
567
+ ok: statusCode >= HTTP_OK && statusCode < HTTP_MULTI_CHOICE,
568
+ statusCode,
569
+ body: Buffer.concat(chunks)
570
+ });
571
+ });
572
+ response.on("error", reject);
573
+ });
574
+ if (timeoutMs) {
575
+ request.setTimeout(timeoutMs, () => {
576
+ request.destroy(new Error("Request timed out"));
577
+ });
578
+ }
579
+ request.on("error", reject);
580
+ });
581
+ };
582
+
583
+ // src/dev-server/health.ts
584
+ var HEALTH_CHECK_TIMEOUT_MS = 2e3;
585
+ var isDevServerRunning = async (baseUrl) => {
586
+ try {
587
+ const { ok: ok4, body } = await nativeGet(
588
+ `${baseUrl}/v2/keys`,
589
+ { Authorization: `Bearer ${DEV_CREDENTIALS.token}` },
590
+ HEALTH_CHECK_TIMEOUT_MS
591
+ );
592
+ if (!ok4)
593
+ return false;
594
+ const data = JSON.parse(body.toString());
595
+ return data.current === DEV_CREDENTIALS.currentSigningKey && data.next === DEV_CREDENTIALS.nextSigningKey;
596
+ } catch {
597
+ return false;
598
+ }
599
+ };
600
+ var _didLogUnreachable = false;
601
+ var checkDevServerReachable = async (baseUrl, runtime) => {
602
+ if (await pingEdge(baseUrl))
603
+ return;
604
+ if (!_didLogUnreachable) {
605
+ console.error(unreachableMessage(baseUrl, runtime));
606
+ _didLogUnreachable = true;
607
+ }
608
+ throw new Error(`${DEV_PREFIX} dev server unreachable at ${baseUrl}`);
609
+ };
610
+ var pingEdge = async (baseUrl) => {
611
+ try {
612
+ const controller = new AbortController();
613
+ const timeout = setTimeout(() => controller.abort(), HEALTH_CHECK_TIMEOUT_MS);
614
+ const response = await fetch(`${baseUrl}/v2/keys`, {
615
+ headers: { Authorization: `Bearer ${DEV_CREDENTIALS.token}` },
616
+ signal: controller.signal
617
+ });
618
+ clearTimeout(timeout);
619
+ return response.ok;
620
+ } catch {
621
+ return false;
622
+ }
623
+ };
624
+ var unreachableMessage = (baseUrl, runtime) => {
625
+ const port = new URL(baseUrl).port;
626
+ const manualStartCmd = `npx @upstash/qstash-cli dev --port ${port}`;
627
+ const header = `
628
+ ${DEV_PREFIX} The dev server is not running at ${baseUrl}.
629
+
630
+ `;
631
+ if (runtime === "cloudflare-workers") {
632
+ return header + `Cloudflare Workers cannot start the dev server automatically.
633
+ Start it manually before running wrangler dev:
634
+
635
+ ${manualStartCmd}
636
+ `;
637
+ }
638
+ return header + `Edge runtimes cannot start the dev server automatically.
639
+ Either:
640
+ 1. Add the instrumentation hook to start it with your app:
641
+
642
+ // instrumentation.ts
643
+ import { registerQStashDev } from "@upstash/qstash/nextjs";
644
+ export async function register() { await registerQStashDev(); }
645
+
646
+ 2. Or start it manually:
647
+
648
+ ${manualStartCmd}
649
+ `;
650
+ };
651
+
652
+ // src/dev-server/binary.ts
653
+ var ensureBinary = async () => {
654
+ const fs = await importFs();
655
+ const os = await importOs();
656
+ const cacheDirectory = await findCacheDirectory();
657
+ const isWindows = os.platform() === "win32";
658
+ const binaryName = isWindows ? "qstash.exe" : "qstash";
659
+ const binaryPath = `${cacheDirectory}/${binaryName}`;
660
+ const versionFile = `${cacheDirectory}/.version`;
661
+ let version;
662
+ try {
663
+ version = await fetchLatestVersion();
664
+ } catch (error) {
665
+ if (fs.existsSync(binaryPath)) {
666
+ const cachedVersion = fs.existsSync(versionFile) ? fs.readFileSync(versionFile, "utf8").trim() : "unknown";
667
+ console.log(`${DEV_PREFIX} Offline, using local v${cachedVersion}`);
668
+ return binaryPath;
669
+ }
670
+ throw error;
671
+ }
672
+ return downloadBinary(version, cacheDirectory);
673
+ };
674
+ var fetchLatestVersion = async () => {
675
+ const { ok: ok4, statusCode, body } = await nativeGet(GITHUB_RELEASES_URL, {
676
+ Accept: "application/vnd.github.v3+json",
677
+ "User-Agent": "upstash-qstash-js"
678
+ });
679
+ if (!ok4) {
680
+ throw new Error(`[QStash Dev] Failed to fetch latest version: HTTP ${statusCode}`);
681
+ }
682
+ const data = JSON.parse(body.toString());
683
+ return data.tag_name.replace(/^v/, "");
684
+ };
685
+ var findCacheDirectory = async () => {
686
+ const fs = await importFs();
687
+ const os = await importOs();
688
+ const home = os.homedir();
689
+ const platform = os.platform();
690
+ let base;
691
+ if (platform === "darwin") {
692
+ base = `${home}/Library/Caches/upstash`;
693
+ } else if (platform === "win32") {
694
+ base = `${process.env.LOCALAPPDATA ?? `${home}/AppData/Local`}/upstash`;
695
+ } else {
696
+ base = `${home}/.cache/upstash`;
697
+ }
698
+ const cacheDirectory = `${base}/qstash-dev`;
699
+ await fs.promises.mkdir(cacheDirectory, { recursive: true });
700
+ return cacheDirectory;
701
+ };
702
+ var downloadBinary = async (version, cacheDirectory) => {
703
+ const fs = await importFs();
704
+ const childProcess = await importChildProcess();
705
+ const os = await importOs();
706
+ const osPlatform = os.platform();
707
+ const isWindows = osPlatform === "win32";
708
+ const platform = isWindows ? "windows" : osPlatform === "darwin" ? "darwin" : "linux";
709
+ const arch = os.arch() === "arm64" ? "arm64" : "amd64";
710
+ const archiveName = `qstash-server_${version}_${platform}_${arch}`;
711
+ const binaryName = isWindows ? "qstash.exe" : "qstash";
712
+ const binaryPath = `${cacheDirectory}/${binaryName}`;
713
+ const versionFile = `${cacheDirectory}/.version`;
714
+ if (fs.existsSync(binaryPath) && fs.existsSync(versionFile)) {
715
+ const cachedVersion = fs.readFileSync(versionFile, "utf8").trim();
716
+ if (cachedVersion === version) {
717
+ return binaryPath;
718
+ }
719
+ }
720
+ await fs.promises.rm(cacheDirectory, { recursive: true, force: true });
721
+ await fs.promises.mkdir(cacheDirectory, { recursive: true });
722
+ const extension = isWindows ? "zip" : "tar.gz";
723
+ const archiveUrl = `${BINARY_URL_BASE}/${version}/${archiveName}.${extension}`;
724
+ console.log(`${DEV_PREFIX} Downloading dev server v${version}...`);
725
+ const { ok: ok4, statusCode, body } = await nativeGet(archiveUrl);
726
+ if (!ok4) {
727
+ throw new Error(`[QStash Dev] Failed to download binary: HTTP ${statusCode}`);
728
+ }
729
+ const archivePath = `${cacheDirectory}/${archiveName}.${extension}`;
730
+ await fs.promises.writeFile(archivePath, new Uint8Array(body));
731
+ childProcess.execFileSync("tar", ["-xf", archivePath, "-C", cacheDirectory], {
732
+ stdio: "pipe"
733
+ });
734
+ if (!isWindows) {
735
+ const EXECUTABLE_PERMISSION = 493;
736
+ await fs.promises.chmod(binaryPath, EXECUTABLE_PERMISSION);
737
+ }
738
+ await fs.promises.writeFile(versionFile, version);
739
+ await fs.promises.unlink(archivePath).catch(() => {
740
+ });
741
+ return binaryPath;
742
+ };
743
+
744
+ // src/dev-server/process.ts
745
+ var STARTUP_TIMEOUT_MS = 3e4;
746
+ var _proc = () => {
747
+ return globalThis["process"] ?? {};
748
+ };
749
+ var spawnServer = async (binaryPath, port, onUnexpectedExit) => {
750
+ const childProcess = await importChildProcess();
751
+ const child = await new Promise((resolve, reject) => {
752
+ const child2 = childProcess.spawn(binaryPath, ["dev", "--port", String(port)], {
753
+ stdio: ["ignore", "pipe", "pipe"]
754
+ });
755
+ const timeout = setTimeout(() => {
756
+ child2.kill();
757
+ reject(new Error("[QStash Dev] Server failed to start within 30 seconds"));
758
+ }, STARTUP_TIMEOUT_MS);
759
+ let startupOutput = "";
760
+ let started = false;
761
+ const bufferLine = (line) => {
762
+ if (!started)
763
+ startupOutput += `${line}
764
+ `;
765
+ };
766
+ forwardWithPrefix(child2.stdout, _proc().stdout, (line) => {
767
+ bufferLine(line);
768
+ if (!started && /runn+ing( at|\.)/i.test(line)) {
769
+ clearTimeout(timeout);
770
+ started = true;
771
+ resolve(child2);
772
+ }
773
+ });
774
+ forwardWithPrefix(child2.stderr, _proc().stderr, bufferLine);
775
+ child2.on("error", (error) => {
776
+ clearTimeout(timeout);
777
+ reject(new Error(`[QStash Dev] Failed to start server: ${error.message}`));
778
+ });
779
+ child2.on("close", (code, _signal) => {
780
+ if (started) {
781
+ onUnexpectedExit?.();
782
+ return;
783
+ }
784
+ clearTimeout(timeout);
785
+ reject(new Error(formatStartupError(code, startupOutput)));
786
+ });
787
+ });
788
+ registerCleanup(child);
789
+ child.unref?.();
790
+ child.stdout?.unref?.();
791
+ child.stderr?.unref?.();
792
+ };
793
+ var formatStartupError = (code, startupOutput) => {
794
+ const cleaned = startupOutput.replaceAll(/\u001B\[[\d;]*m/g, "").replaceAll(/^\d{1,2}:\d{2}(AM|PM)\s+\w{3}\s+/gm, "").trim();
795
+ if (/address already in use/i.test(cleaned)) {
796
+ const match = /:(\d+)\s*$/.exec(cleaned);
797
+ const portHint = match ? ` on port ${match[1]}` : "";
798
+ return `[QStash Dev] Port already in use${portHint}. Set QSTASH_DEV_PORT to use a different port, or stop the process holding it.`;
799
+ }
800
+ const codeSuffix = code ? ` with code ${code}` : "";
801
+ const detail = cleaned ? `: ${cleaned}` : "";
802
+ return `[QStash Dev] Server exited unexpectedly${codeSuffix}${detail}`;
803
+ };
804
+ var forwardWithPrefix = (source, destination, onLine) => {
805
+ if (!source)
806
+ return;
807
+ let buffer = "";
808
+ const flushLine = (line) => {
809
+ destination?.write(`${CLI_PREFIX} ${line}
810
+ `);
811
+ onLine(line);
812
+ };
813
+ source.on("data", (data) => {
814
+ buffer += data.toString();
815
+ let newlineIndex = buffer.indexOf("\n");
816
+ while (newlineIndex !== -1) {
817
+ flushLine(buffer.slice(0, newlineIndex));
818
+ buffer = buffer.slice(newlineIndex + 1);
819
+ newlineIndex = buffer.indexOf("\n");
820
+ }
821
+ });
822
+ source.on("end", () => {
823
+ if (buffer.length > 0) {
824
+ flushLine(buffer);
825
+ buffer = "";
826
+ }
827
+ });
828
+ source.on("error", () => {
829
+ });
830
+ };
831
+ var currentChild;
832
+ var processHandlersRegistered = false;
833
+ var killCurrentChild = () => {
834
+ if (!currentChild)
835
+ return;
836
+ try {
837
+ currentChild.kill("SIGTERM");
838
+ } catch {
839
+ }
840
+ currentChild = void 0;
841
+ };
842
+ var registerCleanup = (child) => {
843
+ currentChild = child;
844
+ if (!processHandlersRegistered) {
845
+ processHandlersRegistered = true;
846
+ const proc = _proc();
847
+ proc.on?.("exit", killCurrentChild);
848
+ proc.on?.("SIGINT", () => {
849
+ killCurrentChild();
850
+ proc.exit?.(0);
851
+ });
852
+ proc.on?.("SIGTERM", () => {
853
+ killCurrentChild();
854
+ proc.exit?.(0);
855
+ });
856
+ }
857
+ };
858
+
859
+ // src/dev-server/index.ts
860
+ var _processGlobal2 = () => {
861
+ const proc = globalThis["process"];
862
+ return proc;
863
+ };
864
+ var devServerPromise;
865
+ var ensureDevelopmentServer = (env, devMode) => {
866
+ if (!shouldUseDevelopmentMode(devMode, env))
867
+ return Promise.resolve();
868
+ const procEnv = _processGlobal2()?.env;
869
+ if (procEnv?.NEXT_PHASE === "phase-production-build")
870
+ return Promise.resolve();
871
+ if (procEnv?.NODE_ENV === "production")
872
+ return Promise.resolve();
873
+ const runtime = getRuntime2();
874
+ if (runtime !== "nodejs") {
875
+ return checkDevServerReachable(getDevUrl(env), runtime);
876
+ }
877
+ if (!devServerPromise) {
878
+ devServerPromise = startPipeline(env).catch((error) => {
879
+ devServerPromise = void 0;
880
+ throw error;
881
+ });
882
+ }
883
+ return devServerPromise;
884
+ };
885
+ var startPipeline = async (env) => {
886
+ const baseUrl = getDevUrl(env);
887
+ const port = new URL(baseUrl).port;
888
+ const consoleLink = `\x1B[36m${CONSOLE_URL}?port=${port}\x1B[0m`;
889
+ if (await isDevServerRunning(baseUrl)) {
890
+ console.log(
891
+ `${DEV_PREFIX} Server already running at ${baseUrl}
892
+ ${DEV_PREFIX} Console: ${consoleLink}`
893
+ );
894
+ return;
895
+ }
896
+ const binaryPath = await ensureBinary();
897
+ await spawnServer(binaryPath, port, () => {
898
+ devServerPromise = void 0;
899
+ });
900
+ };
901
+ var shouldUseDevelopmentMode = (devMode, env) => {
902
+ if (devMode !== void 0)
903
+ return devMode;
904
+ const value = env?.QSTASH_DEV ?? getProcessEnvironment("QSTASH_DEV");
905
+ if (value === void 0 || value === "" || value === "false" || value === "0")
906
+ return false;
907
+ if (value === "true" || value === "1")
908
+ return true;
909
+ throw new Error(`[QStash Dev] Invalid value for QSTASH_DEV in environment: ${value}`);
910
+ };
911
+ var getDevelopmentCredentials = (env) => {
912
+ return {
913
+ ...DEV_CREDENTIALS,
914
+ baseUrl: getDevUrl(env)
915
+ };
916
+ };
917
+ var getDevUrl = (env) => {
918
+ const portString = env?.QSTASH_DEV_PORT ?? getProcessEnvironment("QSTASH_DEV_PORT");
919
+ let port = DEFAULT_DEV_PORT;
920
+ if (portString) {
921
+ const parsed = Number.parseInt(portString, 10);
922
+ if (!Number.isNaN(parsed) && parsed > 0) {
923
+ port = parsed;
924
+ }
925
+ }
926
+ return `http://127.0.0.1:${port}`;
927
+ };
928
+ var getRuntime2 = () => {
929
+ if (typeof navigator !== "undefined" && navigator.userAgent === "Cloudflare-Workers") {
930
+ return "cloudflare-workers";
931
+ }
932
+ const proc = _processGlobal2();
933
+ if (!proc) {
934
+ return "browser";
935
+ }
936
+ if (!proc.release?.name) {
937
+ return "edge";
938
+ }
939
+ return "nodejs";
940
+ };
941
+ var getProcessEnvironment = (key) => {
942
+ const proc = _processGlobal2();
943
+ return proc?.env ? proc.env[key] : void 0;
944
+ };
945
+
514
946
  // src/client/multi-region/incoming.ts
515
947
  var getReceiverSigningKeys = ({
516
948
  environment,
517
949
  regionFromHeader,
518
- config
950
+ config,
951
+ devMode
519
952
  }) => {
953
+ if (shouldUseDevelopmentMode(devMode, environment)) {
954
+ if (config?.currentSigningKey || config?.nextSigningKey) {
955
+ console.warn(
956
+ `${DEV_PREFIX} Dev mode is active. Ignoring signing keys from config. Set devMode: false to use your own keys.`
957
+ );
958
+ }
959
+ const developmentCreds = getDevelopmentCredentials(environment);
960
+ return {
961
+ currentSigningKey: developmentCreds.currentSigningKey,
962
+ nextSigningKey: developmentCreds.nextSigningKey
963
+ };
964
+ }
520
965
  if (config?.currentSigningKey && config.nextSigningKey) {
521
966
  return {
522
967
  currentSigningKey: config.currentSigningKey,
@@ -561,8 +1006,21 @@ var getClientCredentials = (clientCredentialConfig) => {
561
1006
  };
562
1007
  var resolveCredentials = ({
563
1008
  environment,
564
- config
1009
+ config,
1010
+ devMode
565
1011
  }) => {
1012
+ if (shouldUseDevelopmentMode(devMode, environment)) {
1013
+ if (config?.baseUrl || config?.token) {
1014
+ console.warn(
1015
+ `${DEV_PREFIX} Dev mode is active. Ignoring baseUrl/token from config. Set devMode: false to use your own credentials.`
1016
+ );
1017
+ }
1018
+ const developmentCreds = getDevelopmentCredentials(environment);
1019
+ return {
1020
+ baseUrl: developmentCreds.baseUrl,
1021
+ token: developmentCreds.token
1022
+ };
1023
+ }
566
1024
  if (config?.baseUrl && config.token) {
567
1025
  return {
568
1026
  baseUrl: config.baseUrl,
@@ -615,9 +1073,11 @@ var SignatureError = class extends Error {
615
1073
  var Receiver = class {
616
1074
  currentSigningKey;
617
1075
  nextSigningKey;
1076
+ devMode;
618
1077
  constructor(config) {
619
1078
  this.currentSigningKey = config?.currentSigningKey;
620
1079
  this.nextSigningKey = config?.nextSigningKey;
1080
+ this.devMode = config?.devMode;
621
1081
  }
622
1082
  /**
623
1083
  * Verify the signature of a request.
@@ -636,7 +1096,8 @@ var Receiver = class {
636
1096
  config: {
637
1097
  currentSigningKey: this.currentSigningKey,
638
1098
  nextSigningKey: this.nextSigningKey
639
- }
1099
+ },
1100
+ devMode: this.devMode
640
1101
  });
641
1102
  if (!signingKeys) {
642
1103
  throw new Error(
@@ -902,12 +1363,14 @@ var HttpClient = class {
902
1363
  baseUrl;
903
1364
  authorization;
904
1365
  options;
1366
+ devMode;
905
1367
  retry;
906
1368
  headers;
907
1369
  telemetryHeaders;
908
1370
  constructor(config) {
909
1371
  this.baseUrl = config.baseUrl.replace(/\/$/, "");
910
1372
  this.authorization = config.authorization;
1373
+ this.devMode = config.devMode;
911
1374
  this.retry = // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
912
1375
  typeof config.retry === "boolean" && !config.retry ? {
913
1376
  attempts: 1,
@@ -920,6 +1383,7 @@ var HttpClient = class {
920
1383
  this.telemetryHeaders = config.telemetryHeaders;
921
1384
  }
922
1385
  async request(request) {
1386
+ await ensureDevelopmentServer(void 0, this.devMode);
923
1387
  const { response } = await this.requestWithBackoff(request);
924
1388
  if (request.parseResponseAsJson === false) {
925
1389
  return void 0;
@@ -927,6 +1391,7 @@ var HttpClient = class {
927
1391
  return await response.json();
928
1392
  }
929
1393
  async *requestStream(request) {
1394
+ await ensureDevelopmentServer(void 0, this.devMode);
930
1395
  const { response } = await this.requestWithBackoff(request);
931
1396
  if (!response.body) {
932
1397
  throw new Error("No response body");
@@ -1649,7 +2114,7 @@ var UrlGroups = class {
1649
2114
  };
1650
2115
 
1651
2116
  // version.ts
1652
- var VERSION = "2.10.0";
2117
+ var VERSION = "2.11.0";
1653
2118
 
1654
2119
  // src/client/client.ts
1655
2120
  var Client = class {
@@ -1657,7 +2122,14 @@ var Client = class {
1657
2122
  token;
1658
2123
  constructor(config) {
1659
2124
  const environment = getSafeEnvironment();
1660
- const { baseUrl, token } = getClientCredentials({ environment, config });
2125
+ const { baseUrl, token } = getClientCredentials({
2126
+ environment,
2127
+ config,
2128
+ devMode: config?.devMode
2129
+ });
2130
+ if (shouldUseDevelopmentMode(config?.devMode, environment)) {
2131
+ void ensureDevelopmentServer(environment, config?.devMode);
2132
+ }
1661
2133
  const enableTelemetry = environment.UPSTASH_DISABLE_TELEMETRY ? false : config?.enableTelemetry ?? true;
1662
2134
  const isCloudflare = typeof caches !== "undefined" && "default" in caches;
1663
2135
  const telemetryHeaders = new Headers(
@@ -1674,7 +2146,8 @@ var Client = class {
1674
2146
  //@ts-expect-error caused by undici and bunjs type overlap
1675
2147
  headers: prefixHeaders(new Headers(config?.headers ?? {})),
1676
2148
  //@ts-expect-error caused by undici and bunjs type overlap
1677
- telemetryHeaders
2149
+ telemetryHeaders,
2150
+ devMode: config?.devMode
1678
2151
  });
1679
2152
  this.token = token;
1680
2153
  }
package/cloudflare.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  serve
3
- } from "./chunk-X3MMU3BQ.mjs";
3
+ } from "./chunk-LB3C5PJP.mjs";
4
4
 
5
5
  // platforms/cloudflare.ts
6
6
  var getArgs = (args) => {
package/h3.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as h3 from 'h3';
2
2
  import { H3Event } from 'h3';
3
- import { ae as RouteFunction, af as WorkflowServeOptions } from './client-CsM1dTnz.mjs';
3
+ import { ae as RouteFunction, af as WorkflowServeOptions } from './client-CUioGZfg.mjs';
4
4
  import 'neverthrow';
5
5
 
6
6
  type VerifySignatureConfig = {
package/h3.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as h3 from 'h3';
2
2
  import { H3Event } from 'h3';
3
- import { ae as RouteFunction, af as WorkflowServeOptions } from './client-CsM1dTnz.js';
3
+ import { ae as RouteFunction, af as WorkflowServeOptions } from './client-CUioGZfg.js';
4
4
  import 'neverthrow';
5
5
 
6
6
  type VerifySignatureConfig = {