@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/h3.js CHANGED
@@ -781,17 +781,23 @@ function normalizeCursor(response) {
781
781
  const cursor = response.cursor;
782
782
  return { ...response, cursor: cursor || void 0 };
783
783
  }
784
+ function _processGlobal() {
785
+ const proc = globalThis["process"];
786
+ return proc;
787
+ }
784
788
  function getRuntime() {
785
- if (typeof process === "object" && typeof process.versions == "object" && process.versions.bun)
786
- return `bun@${process.versions.bun}`;
789
+ const proc = _processGlobal();
790
+ if (proc?.versions?.bun)
791
+ return `bun@${proc.versions.bun}`;
787
792
  if (typeof EdgeRuntime === "string")
788
793
  return "edge-light";
789
- else if (typeof process === "object" && typeof process.version === "string")
790
- return `node@${process.version}`;
794
+ if (typeof proc?.version === "string")
795
+ return `node@${proc.version}`;
791
796
  return "";
792
797
  }
793
798
  function getSafeEnvironment() {
794
- return typeof process === "undefined" ? {} : process.env;
799
+ const proc = _processGlobal();
800
+ return proc?.env ?? {};
795
801
  }
796
802
 
797
803
  // src/client/multi-region/utils.ts
@@ -835,12 +841,451 @@ function normalizeRegionHeader(region) {
835
841
  return void 0;
836
842
  }
837
843
 
844
+ // src/dev-server/constants.ts
845
+ var DEFAULT_DEV_PORT = 8080;
846
+ var DEV_CREDENTIALS = {
847
+ token: "eyJVc2VySUQiOiJkZWZhdWx0VXNlciIsIlBhc3N3b3JkIjoiZGVmYXVsdFBhc3N3b3JkIn0=",
848
+ currentSigningKey: "sig_7kYjw48mhY7kAjqNGcy6cr29RJ6r",
849
+ nextSigningKey: "sig_5ZB6DVzB1wjE8S6rZ7eenA8Pdnhs"
850
+ };
851
+ var GITHUB_RELEASES_URL = "https://api.github.com/repos/upstash/qstash-cli/releases/latest";
852
+ var BINARY_URL_BASE = "https://artifacts.upstash.com/qstash/versions";
853
+ var CONSOLE_URL = "https://console.upstash.com/qstash/local-mode-user";
854
+ var DEV_PREFIX = "\x1B[2m[QStash Dev]\x1B[0m";
855
+ var CLI_PREFIX = "\x1B[2m[QStash CLI]\x1B[0m";
856
+ var _n = (m) => `node:${m}`;
857
+ var importHttp = () => import(
858
+ /* webpackIgnore: true */
859
+ _n("http")
860
+ );
861
+ var importHttps = () => import(
862
+ /* webpackIgnore: true */
863
+ _n("https")
864
+ );
865
+ var importFs = () => import(
866
+ /* webpackIgnore: true */
867
+ _n("fs")
868
+ );
869
+ var importChildProcess = () => import(
870
+ /* webpackIgnore: true */
871
+ _n("child_process")
872
+ );
873
+ var importOs = () => import(
874
+ /* webpackIgnore: true */
875
+ _n("os")
876
+ );
877
+
878
+ // src/dev-server/http.ts
879
+ var HTTP_OK = 200;
880
+ var HTTP_MULTI_CHOICE = 300;
881
+ var nativeGet = async (url, headers, timeoutMs) => {
882
+ const parsedUrl = new URL(url);
883
+ const httpModule = parsedUrl.protocol === "https:" ? await importHttps() : await importHttp();
884
+ return new Promise((resolve, reject) => {
885
+ const request = httpModule.get(url, { headers }, (response) => {
886
+ const chunks = [];
887
+ response.on("data", (chunk) => chunks.push(chunk));
888
+ response.on("end", () => {
889
+ const statusCode = response.statusCode ?? 0;
890
+ resolve({
891
+ ok: statusCode >= HTTP_OK && statusCode < HTTP_MULTI_CHOICE,
892
+ statusCode,
893
+ body: Buffer.concat(chunks)
894
+ });
895
+ });
896
+ response.on("error", reject);
897
+ });
898
+ if (timeoutMs) {
899
+ request.setTimeout(timeoutMs, () => {
900
+ request.destroy(new Error("Request timed out"));
901
+ });
902
+ }
903
+ request.on("error", reject);
904
+ });
905
+ };
906
+
907
+ // src/dev-server/health.ts
908
+ var HEALTH_CHECK_TIMEOUT_MS = 2e3;
909
+ var isDevServerRunning = async (baseUrl) => {
910
+ try {
911
+ const { ok: ok4, body } = await nativeGet(
912
+ `${baseUrl}/v2/keys`,
913
+ { Authorization: `Bearer ${DEV_CREDENTIALS.token}` },
914
+ HEALTH_CHECK_TIMEOUT_MS
915
+ );
916
+ if (!ok4)
917
+ return false;
918
+ const data = JSON.parse(body.toString());
919
+ return data.current === DEV_CREDENTIALS.currentSigningKey && data.next === DEV_CREDENTIALS.nextSigningKey;
920
+ } catch {
921
+ return false;
922
+ }
923
+ };
924
+ var _didLogUnreachable = false;
925
+ var checkDevServerReachable = async (baseUrl, runtime) => {
926
+ if (await pingEdge(baseUrl))
927
+ return;
928
+ if (!_didLogUnreachable) {
929
+ console.error(unreachableMessage(baseUrl, runtime));
930
+ _didLogUnreachable = true;
931
+ }
932
+ throw new Error(`${DEV_PREFIX} dev server unreachable at ${baseUrl}`);
933
+ };
934
+ var pingEdge = async (baseUrl) => {
935
+ try {
936
+ const controller = new AbortController();
937
+ const timeout = setTimeout(() => controller.abort(), HEALTH_CHECK_TIMEOUT_MS);
938
+ const response = await fetch(`${baseUrl}/v2/keys`, {
939
+ headers: { Authorization: `Bearer ${DEV_CREDENTIALS.token}` },
940
+ signal: controller.signal
941
+ });
942
+ clearTimeout(timeout);
943
+ return response.ok;
944
+ } catch {
945
+ return false;
946
+ }
947
+ };
948
+ var unreachableMessage = (baseUrl, runtime) => {
949
+ const port = new URL(baseUrl).port;
950
+ const manualStartCmd = `npx @upstash/qstash-cli dev --port ${port}`;
951
+ const header = `
952
+ ${DEV_PREFIX} The dev server is not running at ${baseUrl}.
953
+
954
+ `;
955
+ if (runtime === "cloudflare-workers") {
956
+ return header + `Cloudflare Workers cannot start the dev server automatically.
957
+ Start it manually before running wrangler dev:
958
+
959
+ ${manualStartCmd}
960
+ `;
961
+ }
962
+ return header + `Edge runtimes cannot start the dev server automatically.
963
+ Either:
964
+ 1. Add the instrumentation hook to start it with your app:
965
+
966
+ // instrumentation.ts
967
+ import { registerQStashDev } from "@upstash/qstash/nextjs";
968
+ export async function register() { await registerQStashDev(); }
969
+
970
+ 2. Or start it manually:
971
+
972
+ ${manualStartCmd}
973
+ `;
974
+ };
975
+
976
+ // src/dev-server/binary.ts
977
+ var ensureBinary = async () => {
978
+ const fs = await importFs();
979
+ const os = await importOs();
980
+ const cacheDirectory = await findCacheDirectory();
981
+ const isWindows = os.platform() === "win32";
982
+ const binaryName = isWindows ? "qstash.exe" : "qstash";
983
+ const binaryPath = `${cacheDirectory}/${binaryName}`;
984
+ const versionFile = `${cacheDirectory}/.version`;
985
+ let version;
986
+ try {
987
+ version = await fetchLatestVersion();
988
+ } catch (error) {
989
+ if (fs.existsSync(binaryPath)) {
990
+ const cachedVersion = fs.existsSync(versionFile) ? fs.readFileSync(versionFile, "utf8").trim() : "unknown";
991
+ console.log(`${DEV_PREFIX} Offline, using local v${cachedVersion}`);
992
+ return binaryPath;
993
+ }
994
+ throw error;
995
+ }
996
+ return downloadBinary(version, cacheDirectory);
997
+ };
998
+ var fetchLatestVersion = async () => {
999
+ const { ok: ok4, statusCode, body } = await nativeGet(GITHUB_RELEASES_URL, {
1000
+ Accept: "application/vnd.github.v3+json",
1001
+ "User-Agent": "upstash-qstash-js"
1002
+ });
1003
+ if (!ok4) {
1004
+ throw new Error(`[QStash Dev] Failed to fetch latest version: HTTP ${statusCode}`);
1005
+ }
1006
+ const data = JSON.parse(body.toString());
1007
+ return data.tag_name.replace(/^v/, "");
1008
+ };
1009
+ var findCacheDirectory = async () => {
1010
+ const fs = await importFs();
1011
+ const os = await importOs();
1012
+ const home = os.homedir();
1013
+ const platform = os.platform();
1014
+ let base;
1015
+ if (platform === "darwin") {
1016
+ base = `${home}/Library/Caches/upstash`;
1017
+ } else if (platform === "win32") {
1018
+ base = `${process.env.LOCALAPPDATA ?? `${home}/AppData/Local`}/upstash`;
1019
+ } else {
1020
+ base = `${home}/.cache/upstash`;
1021
+ }
1022
+ const cacheDirectory = `${base}/qstash-dev`;
1023
+ await fs.promises.mkdir(cacheDirectory, { recursive: true });
1024
+ return cacheDirectory;
1025
+ };
1026
+ var downloadBinary = async (version, cacheDirectory) => {
1027
+ const fs = await importFs();
1028
+ const childProcess = await importChildProcess();
1029
+ const os = await importOs();
1030
+ const osPlatform = os.platform();
1031
+ const isWindows = osPlatform === "win32";
1032
+ const platform = isWindows ? "windows" : osPlatform === "darwin" ? "darwin" : "linux";
1033
+ const arch = os.arch() === "arm64" ? "arm64" : "amd64";
1034
+ const archiveName = `qstash-server_${version}_${platform}_${arch}`;
1035
+ const binaryName = isWindows ? "qstash.exe" : "qstash";
1036
+ const binaryPath = `${cacheDirectory}/${binaryName}`;
1037
+ const versionFile = `${cacheDirectory}/.version`;
1038
+ if (fs.existsSync(binaryPath) && fs.existsSync(versionFile)) {
1039
+ const cachedVersion = fs.readFileSync(versionFile, "utf8").trim();
1040
+ if (cachedVersion === version) {
1041
+ return binaryPath;
1042
+ }
1043
+ }
1044
+ await fs.promises.rm(cacheDirectory, { recursive: true, force: true });
1045
+ await fs.promises.mkdir(cacheDirectory, { recursive: true });
1046
+ const extension = isWindows ? "zip" : "tar.gz";
1047
+ const archiveUrl = `${BINARY_URL_BASE}/${version}/${archiveName}.${extension}`;
1048
+ console.log(`${DEV_PREFIX} Downloading dev server v${version}...`);
1049
+ const { ok: ok4, statusCode, body } = await nativeGet(archiveUrl);
1050
+ if (!ok4) {
1051
+ throw new Error(`[QStash Dev] Failed to download binary: HTTP ${statusCode}`);
1052
+ }
1053
+ const archivePath = `${cacheDirectory}/${archiveName}.${extension}`;
1054
+ await fs.promises.writeFile(archivePath, new Uint8Array(body));
1055
+ childProcess.execFileSync("tar", ["-xf", archivePath, "-C", cacheDirectory], {
1056
+ stdio: "pipe"
1057
+ });
1058
+ if (!isWindows) {
1059
+ const EXECUTABLE_PERMISSION = 493;
1060
+ await fs.promises.chmod(binaryPath, EXECUTABLE_PERMISSION);
1061
+ }
1062
+ await fs.promises.writeFile(versionFile, version);
1063
+ await fs.promises.unlink(archivePath).catch(() => {
1064
+ });
1065
+ return binaryPath;
1066
+ };
1067
+
1068
+ // src/dev-server/process.ts
1069
+ var STARTUP_TIMEOUT_MS = 3e4;
1070
+ var _proc = () => {
1071
+ return globalThis["process"] ?? {};
1072
+ };
1073
+ var spawnServer = async (binaryPath, port, onUnexpectedExit) => {
1074
+ const childProcess = await importChildProcess();
1075
+ const child = await new Promise((resolve, reject) => {
1076
+ const child2 = childProcess.spawn(binaryPath, ["dev", "--port", String(port)], {
1077
+ stdio: ["ignore", "pipe", "pipe"]
1078
+ });
1079
+ const timeout = setTimeout(() => {
1080
+ child2.kill();
1081
+ reject(new Error("[QStash Dev] Server failed to start within 30 seconds"));
1082
+ }, STARTUP_TIMEOUT_MS);
1083
+ let startupOutput = "";
1084
+ let started = false;
1085
+ const bufferLine = (line) => {
1086
+ if (!started)
1087
+ startupOutput += `${line}
1088
+ `;
1089
+ };
1090
+ forwardWithPrefix(child2.stdout, _proc().stdout, (line) => {
1091
+ bufferLine(line);
1092
+ if (!started && /runn+ing( at|\.)/i.test(line)) {
1093
+ clearTimeout(timeout);
1094
+ started = true;
1095
+ resolve(child2);
1096
+ }
1097
+ });
1098
+ forwardWithPrefix(child2.stderr, _proc().stderr, bufferLine);
1099
+ child2.on("error", (error) => {
1100
+ clearTimeout(timeout);
1101
+ reject(new Error(`[QStash Dev] Failed to start server: ${error.message}`));
1102
+ });
1103
+ child2.on("close", (code, _signal) => {
1104
+ if (started) {
1105
+ onUnexpectedExit?.();
1106
+ return;
1107
+ }
1108
+ clearTimeout(timeout);
1109
+ reject(new Error(formatStartupError(code, startupOutput)));
1110
+ });
1111
+ });
1112
+ registerCleanup(child);
1113
+ child.unref?.();
1114
+ child.stdout?.unref?.();
1115
+ child.stderr?.unref?.();
1116
+ };
1117
+ var formatStartupError = (code, startupOutput) => {
1118
+ const cleaned = startupOutput.replaceAll(/\u001B\[[\d;]*m/g, "").replaceAll(/^\d{1,2}:\d{2}(AM|PM)\s+\w{3}\s+/gm, "").trim();
1119
+ if (/address already in use/i.test(cleaned)) {
1120
+ const match = /:(\d+)\s*$/.exec(cleaned);
1121
+ const portHint = match ? ` on port ${match[1]}` : "";
1122
+ return `[QStash Dev] Port already in use${portHint}. Set QSTASH_DEV_PORT to use a different port, or stop the process holding it.`;
1123
+ }
1124
+ const codeSuffix = code ? ` with code ${code}` : "";
1125
+ const detail = cleaned ? `: ${cleaned}` : "";
1126
+ return `[QStash Dev] Server exited unexpectedly${codeSuffix}${detail}`;
1127
+ };
1128
+ var forwardWithPrefix = (source, destination, onLine) => {
1129
+ if (!source)
1130
+ return;
1131
+ let buffer = "";
1132
+ const flushLine = (line) => {
1133
+ destination?.write(`${CLI_PREFIX} ${line}
1134
+ `);
1135
+ onLine(line);
1136
+ };
1137
+ source.on("data", (data) => {
1138
+ buffer += data.toString();
1139
+ let newlineIndex = buffer.indexOf("\n");
1140
+ while (newlineIndex !== -1) {
1141
+ flushLine(buffer.slice(0, newlineIndex));
1142
+ buffer = buffer.slice(newlineIndex + 1);
1143
+ newlineIndex = buffer.indexOf("\n");
1144
+ }
1145
+ });
1146
+ source.on("end", () => {
1147
+ if (buffer.length > 0) {
1148
+ flushLine(buffer);
1149
+ buffer = "";
1150
+ }
1151
+ });
1152
+ source.on("error", () => {
1153
+ });
1154
+ };
1155
+ var currentChild;
1156
+ var processHandlersRegistered = false;
1157
+ var killCurrentChild = () => {
1158
+ if (!currentChild)
1159
+ return;
1160
+ try {
1161
+ currentChild.kill("SIGTERM");
1162
+ } catch {
1163
+ }
1164
+ currentChild = void 0;
1165
+ };
1166
+ var registerCleanup = (child) => {
1167
+ currentChild = child;
1168
+ if (!processHandlersRegistered) {
1169
+ processHandlersRegistered = true;
1170
+ const proc = _proc();
1171
+ proc.on?.("exit", killCurrentChild);
1172
+ proc.on?.("SIGINT", () => {
1173
+ killCurrentChild();
1174
+ proc.exit?.(0);
1175
+ });
1176
+ proc.on?.("SIGTERM", () => {
1177
+ killCurrentChild();
1178
+ proc.exit?.(0);
1179
+ });
1180
+ }
1181
+ };
1182
+
1183
+ // src/dev-server/index.ts
1184
+ var _processGlobal2 = () => {
1185
+ const proc = globalThis["process"];
1186
+ return proc;
1187
+ };
1188
+ var devServerPromise;
1189
+ var ensureDevelopmentServer = (env, devMode) => {
1190
+ if (!shouldUseDevelopmentMode(devMode, env))
1191
+ return Promise.resolve();
1192
+ const procEnv = _processGlobal2()?.env;
1193
+ if (procEnv?.NEXT_PHASE === "phase-production-build")
1194
+ return Promise.resolve();
1195
+ if (procEnv?.NODE_ENV === "production")
1196
+ return Promise.resolve();
1197
+ const runtime = getRuntime2();
1198
+ if (runtime !== "nodejs") {
1199
+ return checkDevServerReachable(getDevUrl(env), runtime);
1200
+ }
1201
+ if (!devServerPromise) {
1202
+ devServerPromise = startPipeline(env).catch((error) => {
1203
+ devServerPromise = void 0;
1204
+ throw error;
1205
+ });
1206
+ }
1207
+ return devServerPromise;
1208
+ };
1209
+ var startPipeline = async (env) => {
1210
+ const baseUrl = getDevUrl(env);
1211
+ const port = new URL(baseUrl).port;
1212
+ const consoleLink = `\x1B[36m${CONSOLE_URL}?port=${port}\x1B[0m`;
1213
+ if (await isDevServerRunning(baseUrl)) {
1214
+ console.log(
1215
+ `${DEV_PREFIX} Server already running at ${baseUrl}
1216
+ ${DEV_PREFIX} Console: ${consoleLink}`
1217
+ );
1218
+ return;
1219
+ }
1220
+ const binaryPath = await ensureBinary();
1221
+ await spawnServer(binaryPath, port, () => {
1222
+ devServerPromise = void 0;
1223
+ });
1224
+ };
1225
+ var shouldUseDevelopmentMode = (devMode, env) => {
1226
+ if (devMode !== void 0)
1227
+ return devMode;
1228
+ const value = env?.QSTASH_DEV ?? getProcessEnvironment("QSTASH_DEV");
1229
+ if (value === void 0 || value === "" || value === "false" || value === "0")
1230
+ return false;
1231
+ if (value === "true" || value === "1")
1232
+ return true;
1233
+ throw new Error(`[QStash Dev] Invalid value for QSTASH_DEV in environment: ${value}`);
1234
+ };
1235
+ var getDevelopmentCredentials = (env) => {
1236
+ return {
1237
+ ...DEV_CREDENTIALS,
1238
+ baseUrl: getDevUrl(env)
1239
+ };
1240
+ };
1241
+ var getDevUrl = (env) => {
1242
+ const portString = env?.QSTASH_DEV_PORT ?? getProcessEnvironment("QSTASH_DEV_PORT");
1243
+ let port = DEFAULT_DEV_PORT;
1244
+ if (portString) {
1245
+ const parsed = Number.parseInt(portString, 10);
1246
+ if (!Number.isNaN(parsed) && parsed > 0) {
1247
+ port = parsed;
1248
+ }
1249
+ }
1250
+ return `http://127.0.0.1:${port}`;
1251
+ };
1252
+ var getRuntime2 = () => {
1253
+ if (typeof navigator !== "undefined" && navigator.userAgent === "Cloudflare-Workers") {
1254
+ return "cloudflare-workers";
1255
+ }
1256
+ const proc = _processGlobal2();
1257
+ if (!proc) {
1258
+ return "browser";
1259
+ }
1260
+ if (!proc.release?.name) {
1261
+ return "edge";
1262
+ }
1263
+ return "nodejs";
1264
+ };
1265
+ var getProcessEnvironment = (key) => {
1266
+ const proc = _processGlobal2();
1267
+ return proc?.env ? proc.env[key] : void 0;
1268
+ };
1269
+
838
1270
  // src/client/multi-region/incoming.ts
839
1271
  var getReceiverSigningKeys = ({
840
1272
  environment,
841
1273
  regionFromHeader,
842
- config
1274
+ config,
1275
+ devMode
843
1276
  }) => {
1277
+ if (shouldUseDevelopmentMode(devMode, environment)) {
1278
+ if (config?.currentSigningKey || config?.nextSigningKey) {
1279
+ console.warn(
1280
+ `${DEV_PREFIX} Dev mode is active. Ignoring signing keys from config. Set devMode: false to use your own keys.`
1281
+ );
1282
+ }
1283
+ const developmentCreds = getDevelopmentCredentials(environment);
1284
+ return {
1285
+ currentSigningKey: developmentCreds.currentSigningKey,
1286
+ nextSigningKey: developmentCreds.nextSigningKey
1287
+ };
1288
+ }
844
1289
  if (config?.currentSigningKey && config.nextSigningKey) {
845
1290
  return {
846
1291
  currentSigningKey: config.currentSigningKey,
@@ -885,8 +1330,21 @@ var getClientCredentials = (clientCredentialConfig) => {
885
1330
  };
886
1331
  var resolveCredentials = ({
887
1332
  environment,
888
- config
1333
+ config,
1334
+ devMode
889
1335
  }) => {
1336
+ if (shouldUseDevelopmentMode(devMode, environment)) {
1337
+ if (config?.baseUrl || config?.token) {
1338
+ console.warn(
1339
+ `${DEV_PREFIX} Dev mode is active. Ignoring baseUrl/token from config. Set devMode: false to use your own credentials.`
1340
+ );
1341
+ }
1342
+ const developmentCreds = getDevelopmentCredentials(environment);
1343
+ return {
1344
+ baseUrl: developmentCreds.baseUrl,
1345
+ token: developmentCreds.token
1346
+ };
1347
+ }
890
1348
  if (config?.baseUrl && config.token) {
891
1349
  return {
892
1350
  baseUrl: config.baseUrl,
@@ -939,9 +1397,11 @@ var SignatureError = class extends Error {
939
1397
  var Receiver = class {
940
1398
  currentSigningKey;
941
1399
  nextSigningKey;
1400
+ devMode;
942
1401
  constructor(config) {
943
1402
  this.currentSigningKey = config?.currentSigningKey;
944
1403
  this.nextSigningKey = config?.nextSigningKey;
1404
+ this.devMode = config?.devMode;
945
1405
  }
946
1406
  /**
947
1407
  * Verify the signature of a request.
@@ -960,7 +1420,8 @@ var Receiver = class {
960
1420
  config: {
961
1421
  currentSigningKey: this.currentSigningKey,
962
1422
  nextSigningKey: this.nextSigningKey
963
- }
1423
+ },
1424
+ devMode: this.devMode
964
1425
  });
965
1426
  if (!signingKeys) {
966
1427
  throw new Error(
@@ -1226,12 +1687,14 @@ var HttpClient = class {
1226
1687
  baseUrl;
1227
1688
  authorization;
1228
1689
  options;
1690
+ devMode;
1229
1691
  retry;
1230
1692
  headers;
1231
1693
  telemetryHeaders;
1232
1694
  constructor(config) {
1233
1695
  this.baseUrl = config.baseUrl.replace(/\/$/, "");
1234
1696
  this.authorization = config.authorization;
1697
+ this.devMode = config.devMode;
1235
1698
  this.retry = // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1236
1699
  typeof config.retry === "boolean" && !config.retry ? {
1237
1700
  attempts: 1,
@@ -1244,6 +1707,7 @@ var HttpClient = class {
1244
1707
  this.telemetryHeaders = config.telemetryHeaders;
1245
1708
  }
1246
1709
  async request(request) {
1710
+ await ensureDevelopmentServer(void 0, this.devMode);
1247
1711
  const { response } = await this.requestWithBackoff(request);
1248
1712
  if (request.parseResponseAsJson === false) {
1249
1713
  return void 0;
@@ -1251,6 +1715,7 @@ var HttpClient = class {
1251
1715
  return await response.json();
1252
1716
  }
1253
1717
  async *requestStream(request) {
1718
+ await ensureDevelopmentServer(void 0, this.devMode);
1254
1719
  const { response } = await this.requestWithBackoff(request);
1255
1720
  if (!response.body) {
1256
1721
  throw new Error("No response body");
@@ -3359,7 +3824,7 @@ var Workflow = class {
3359
3824
  };
3360
3825
 
3361
3826
  // version.ts
3362
- var VERSION = "2.10.0";
3827
+ var VERSION = "2.11.0";
3363
3828
 
3364
3829
  // src/client/client.ts
3365
3830
  var Client = class {
@@ -3367,7 +3832,14 @@ var Client = class {
3367
3832
  token;
3368
3833
  constructor(config) {
3369
3834
  const environment = getSafeEnvironment();
3370
- const { baseUrl, token } = getClientCredentials({ environment, config });
3835
+ const { baseUrl, token } = getClientCredentials({
3836
+ environment,
3837
+ config,
3838
+ devMode: config?.devMode
3839
+ });
3840
+ if (shouldUseDevelopmentMode(config?.devMode, environment)) {
3841
+ void ensureDevelopmentServer(environment, config?.devMode);
3842
+ }
3371
3843
  const enableTelemetry = environment.UPSTASH_DISABLE_TELEMETRY ? false : config?.enableTelemetry ?? true;
3372
3844
  const isCloudflare = typeof caches !== "undefined" && "default" in caches;
3373
3845
  const telemetryHeaders = new Headers(
@@ -3384,7 +3856,8 @@ var Client = class {
3384
3856
  //@ts-expect-error caused by undici and bunjs type overlap
3385
3857
  headers: prefixHeaders(new Headers(config?.headers ?? {})),
3386
3858
  //@ts-expect-error caused by undici and bunjs type overlap
3387
- telemetryHeaders
3859
+ telemetryHeaders,
3860
+ devMode: config?.devMode
3388
3861
  });
3389
3862
  this.token = token;
3390
3863
  }
package/h3.mjs CHANGED
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  serve,
3
3
  verifySignatureH3
4
- } from "./chunk-FE7GQ4RU.mjs";
5
- import "./chunk-FAMFGAMR.mjs";
6
- import "./chunk-X3MMU3BQ.mjs";
4
+ } from "./chunk-JQP6NQUW.mjs";
5
+ import "./chunk-7DSF3QVE.mjs";
6
+ import "./chunk-LB3C5PJP.mjs";
7
7
  export {
8
8
  serve,
9
9
  verifySignatureH3
package/hono.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Context } from 'hono';
2
- import { ae as RouteFunction, af as WorkflowServeOptions } from './client-CsM1dTnz.mjs';
2
+ import { ae as RouteFunction, af as WorkflowServeOptions } from './client-CUioGZfg.mjs';
3
3
  import 'neverthrow';
4
4
 
5
5
  type WorkflowBindings = {
package/hono.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Context } from 'hono';
2
- import { ae as RouteFunction, af as WorkflowServeOptions } from './client-CsM1dTnz.js';
2
+ import { ae as RouteFunction, af as WorkflowServeOptions } from './client-CUioGZfg.js';
3
3
  import 'neverthrow';
4
4
 
5
5
  type WorkflowBindings = {