wrangler 4.90.0 → 4.91.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.
@@ -30381,7 +30381,9 @@ function normalizeAndValidateEnvironment(diagnostics, configPath, rawEnv, isDisp
30381
30381
  "Removed",
30382
30382
  "error"
30383
30383
  );
30384
- experimental(diagnostics, rawEnv, "unsafe");
30384
+ if (topLevelEnv === void 0 || rawConfig?.unsafe === void 0) {
30385
+ experimental(diagnostics, rawEnv, "unsafe");
30386
+ }
30385
30387
  const route = normalizeAndValidateRoute(diagnostics, topLevelEnv, rawEnv);
30386
30388
  const account_id = inheritableInWranglerEnvironments(
30387
30389
  diagnostics,
@@ -32262,17 +32264,14 @@ function startTunnel(options) {
32262
32264
  const timeoutMs = options.timeoutMs ?? TUNNEL_STARTUP_TIMEOUT_MS;
32263
32265
  const reminderIntervalMs = options.reminderIntervalMs ?? DEFAULT_TUNNEL_REMINDER_INTERVAL_MS;
32264
32266
  const defaultExpiryMs = options.expiryMs ?? DEFAULT_TUNNEL_EXPIRY_MS;
32267
+ const isNamedTunnel = options.token !== void 0;
32265
32268
  const timeFormatter = new Intl.DateTimeFormat(void 0, {
32266
32269
  timeStyle: "short"
32267
32270
  });
32268
- const cloudflaredArgs = [
32269
- "tunnel",
32270
- "--no-autoupdate",
32271
- "--url",
32272
- options.origin.href
32273
- ];
32271
+ const cloudflaredArgs = isNamedTunnel ? ["tunnel", "--no-autoupdate", "run"] : ["tunnel", "--no-autoupdate", "--url", options.origin.href];
32274
32272
  const cloudflaredPromise = spawnCloudflared(cloudflaredArgs, {
32275
32273
  stdio: "pipe",
32274
+ env: options.token ? { TUNNEL_TOKEN: options.token } : void 0,
32276
32275
  skipVersionCheck: true,
32277
32276
  logger: logger4
32278
32277
  }).then((process22) => {
@@ -32282,15 +32281,20 @@ function startTunnel(options) {
32282
32281
  }
32283
32282
  return process22;
32284
32283
  });
32285
- const readyPromise = cloudflaredPromise.then(
32286
- (process22) => waitForQuickTunnelReady(process22, timeoutMs, {
32284
+ const readyPromise = cloudflaredPromise.then((process22) => {
32285
+ if (isNamedTunnel) {
32286
+ return { mode: "named" };
32287
+ }
32288
+ return waitForQuickTunnelReady(process22, timeoutMs, {
32287
32289
  logger: logger4,
32288
32290
  origin: options.origin
32289
- })
32290
- ).then((result) => {
32291
+ });
32292
+ }).then((result) => {
32291
32293
  expiresAt = Date.now() + defaultExpiryMs;
32292
32294
  scheduleExpiryTimeout();
32293
- scheduleReminder(result.publicUrl.origin);
32295
+ scheduleReminder(
32296
+ result.mode === "quick" ? result.publicUrl.origin : void 0
32297
+ );
32294
32298
  return result;
32295
32299
  });
32296
32300
  function disposeTunnel() {
@@ -32325,7 +32329,7 @@ function startTunnel(options) {
32325
32329
  return;
32326
32330
  }
32327
32331
  logger4?.log(
32328
- `The tunnel is still open at ${publicURL}. It expires in ${formatTunnelDuration(remainingMs)}. ${options.extendHint ?? ""}`
32332
+ `${publicURL ? `The tunnel is still open at ${publicURL}.` : "The tunnel is still open."} It expires in ${formatTunnelDuration(remainingMs)}. ${options.extendHint ?? ""}`
32329
32333
  );
32330
32334
  }, reminderIntervalMs);
32331
32335
  reminderInterval.unref?.();
@@ -32381,6 +32385,7 @@ function startTunnel(options) {
32381
32385
  __name2(extendExpiry, "extendExpiry");
32382
32386
  return {
32383
32387
  ready: /* @__PURE__ */ __name2(() => readyPromise, "ready"),
32388
+ isOpen: /* @__PURE__ */ __name2(() => !disposed, "isOpen"),
32384
32389
  dispose: disposeTunnel,
32385
32390
  extendExpiry
32386
32391
  };
@@ -32439,7 +32444,7 @@ function waitForQuickTunnelReady(cloudflared, timeoutMs, options) {
32439
32444
  if (match3 && !resolved) {
32440
32445
  resolved = true;
32441
32446
  clearTimeout(timeoutId);
32442
- resolve32({ publicUrl: new URL(match3[0]) });
32447
+ resolve32({ mode: "quick", publicUrl: new URL(match3[0]) });
32443
32448
  }
32444
32449
  });
32445
32450
  }
@@ -38028,14 +38033,16 @@ var init_dist = __esm({
38028
38033
  if (configDefines.length > 0) {
38029
38034
  if (typeof value === "object" && value !== null) {
38030
38035
  const configEnvDefines = config === void 0 ? [] : Object.keys(value);
38031
- for (const varName of configDefines) {
38032
- if (!(varName in value)) {
38033
- diagnostics.warnings.push(
38034
- `"define.${varName}" exists at the top level, but not on "${fieldPath}".
38035
- This is not what you probably want, since "define" configuration is not inherited by environments.
38036
- Please add "define.${varName}" to "env.${envName}".`
38037
- );
38038
- }
38036
+ const missingDefines = configDefines.filter(
38037
+ (varName) => !(varName in value)
38038
+ );
38039
+ if (missingDefines.length > 0) {
38040
+ diagnostics.warnings.push(
38041
+ `The following define entries exist at the top level, but not on "${fieldPath}".
38042
+ This is probably not what you want, since "define" configuration is not inherited by environments.
38043
+ Please add these entries to "env.${envName}.define":
38044
+ ` + missingDefines.map((varName) => `- ${varName}`).join("\n")
38045
+ );
38039
38046
  }
38040
38047
  for (const varName of configEnvDefines) {
38041
38048
  if (!configDefines.includes(varName)) {
@@ -38076,14 +38083,14 @@ Please remove "${fieldPath}.${varName}", or add "define.${varName}".`
38076
38083
  const configVars = Object.keys(config?.vars ?? {});
38077
38084
  if (configVars.length > 0) {
38078
38085
  if (typeof value === "object" && value !== null) {
38079
- for (const varName of configVars) {
38080
- if (!(varName in value)) {
38081
- diagnostics.warnings.push(
38082
- `"vars.${varName}" exists at the top level, but not on "${fieldPath}".
38083
- This is not what you probably want, since "vars" configuration is not inherited by environments.
38084
- Please add "vars.${varName}" to "env.${envName}".`
38085
- );
38086
- }
38086
+ const missingVars = configVars.filter((varName) => !(varName in value));
38087
+ if (missingVars.length > 0) {
38088
+ diagnostics.warnings.push(
38089
+ `The following vars exist at the top level, but not on "${fieldPath}".
38090
+ This is probably not what you want, since "vars" configuration is not inherited by environments.
38091
+ Please add these vars to "env.${envName}.vars":
38092
+ ` + missingVars.map((varName) => `- ${varName}`).join("\n")
38093
+ );
38087
38094
  }
38088
38095
  }
38089
38096
  }
@@ -46851,18 +46858,18 @@ var require_async = __commonJS({
46851
46858
  ];
46852
46859
  }, "defaultPaths");
46853
46860
  var defaultIsFile = /* @__PURE__ */ __name(function isFile2(file3, cb2) {
46854
- fs33.stat(file3, function(err, stat9) {
46861
+ fs33.stat(file3, function(err, stat10) {
46855
46862
  if (!err) {
46856
- return cb2(null, stat9.isFile() || stat9.isFIFO());
46863
+ return cb2(null, stat10.isFile() || stat10.isFIFO());
46857
46864
  }
46858
46865
  if (err.code === "ENOENT" || err.code === "ENOTDIR") return cb2(null, false);
46859
46866
  return cb2(err);
46860
46867
  });
46861
46868
  }, "isFile");
46862
46869
  var defaultIsDir = /* @__PURE__ */ __name(function isDirectory3(dir2, cb2) {
46863
- fs33.stat(dir2, function(err, stat9) {
46870
+ fs33.stat(dir2, function(err, stat10) {
46864
46871
  if (!err) {
46865
- return cb2(null, stat9.isDirectory());
46872
+ return cb2(null, stat10.isDirectory());
46866
46873
  }
46867
46874
  if (err.code === "ENOENT" || err.code === "ENOTDIR") return cb2(null, false);
46868
46875
  return cb2(err);
@@ -47353,21 +47360,21 @@ var require_sync = __commonJS({
47353
47360
  }, "defaultPaths");
47354
47361
  var defaultIsFile = /* @__PURE__ */ __name(function isFile2(file3) {
47355
47362
  try {
47356
- var stat9 = fs33.statSync(file3, { throwIfNoEntry: false });
47363
+ var stat10 = fs33.statSync(file3, { throwIfNoEntry: false });
47357
47364
  } catch (e10) {
47358
47365
  if (e10 && (e10.code === "ENOENT" || e10.code === "ENOTDIR")) return false;
47359
47366
  throw e10;
47360
47367
  }
47361
- return !!stat9 && (stat9.isFile() || stat9.isFIFO());
47368
+ return !!stat10 && (stat10.isFile() || stat10.isFIFO());
47362
47369
  }, "isFile");
47363
47370
  var defaultIsDir = /* @__PURE__ */ __name(function isDirectory3(dir2) {
47364
47371
  try {
47365
- var stat9 = fs33.statSync(dir2, { throwIfNoEntry: false });
47372
+ var stat10 = fs33.statSync(dir2, { throwIfNoEntry: false });
47366
47373
  } catch (e10) {
47367
47374
  if (e10 && (e10.code === "ENOENT" || e10.code === "ENOTDIR")) return false;
47368
47375
  throw e10;
47369
47376
  }
47370
- return !!stat9 && stat9.isDirectory();
47377
+ return !!stat10 && stat10.isDirectory();
47371
47378
  }, "isDirectory");
47372
47379
  var defaultRealpathSync = /* @__PURE__ */ __name(function realpathSync4(x6) {
47373
47380
  try {
@@ -49650,7 +49657,40 @@ function getDebugFilepath() {
49650
49657
  const filepath = dir2.endsWith(".log") ? dir2 : path3__namespace.default.join(dir2, `wrangler-${date}.log`);
49651
49658
  return path3__namespace.default.resolve(filepath);
49652
49659
  }
49660
+ async function cleanupOldLogFiles(logsDir) {
49661
+ if (!fs29.existsSync(logsDir)) {
49662
+ return;
49663
+ }
49664
+ const maxAgeDays = 30;
49665
+ const cutoffMs = maxAgeDays * 24 * 60 * 60 * 1e3;
49666
+ try {
49667
+ const files = await fs9.readdir(logsDir);
49668
+ const now = Date.now();
49669
+ for (const f7 of files.filter(
49670
+ (filename) => filename.startsWith("wrangler-") && filename.endsWith(".log")
49671
+ )) {
49672
+ const filePath = path3__namespace.default.join(logsDir, f7);
49673
+ try {
49674
+ const fileStat = await fs9.stat(filePath);
49675
+ if (now - fileStat.mtimeMs > cutoffMs) {
49676
+ await fs9.unlink(filePath);
49677
+ }
49678
+ } catch {
49679
+ }
49680
+ }
49681
+ } catch {
49682
+ }
49683
+ }
49684
+ function tryCleanupLogs() {
49685
+ const debugFileDir = getDebugFileDir();
49686
+ if (hasStartedLogCleanup || debugFileDir.endsWith(".log")) {
49687
+ return;
49688
+ }
49689
+ hasStartedLogCleanup = true;
49690
+ void cleanupOldLogFiles(debugFileDir);
49691
+ }
49653
49692
  async function appendToDebugLogFile(messageLevel, message) {
49693
+ tryCleanupLogs();
49654
49694
  const entry = `
49655
49695
  --- ${(/* @__PURE__ */ new Date()).toISOString()} ${messageLevel}
49656
49696
  ${util4.stripVTControlCharacters(message)}
@@ -49684,7 +49724,7 @@ ${util4.stripVTControlCharacters(message)}
49684
49724
  }
49685
49725
  });
49686
49726
  }
49687
- var import_signal_exit, getDebugFileDir, debugLogFilepath, mutex, hasLoggedLocation, hasLoggedError, hasSeenErrorMessage;
49727
+ var import_signal_exit, getDebugFileDir, debugLogFilepath, mutex, hasStartedLogCleanup, hasLoggedLocation, hasLoggedError, hasSeenErrorMessage;
49688
49728
  var init_log_file = __esm({
49689
49729
  "src/utils/log-file.ts"() {
49690
49730
  init_import_meta_url();
@@ -49700,8 +49740,11 @@ var init_log_file = __esm({
49700
49740
  }
49701
49741
  });
49702
49742
  __name(getDebugFilepath, "getDebugFilepath");
49743
+ __name(cleanupOldLogFiles, "cleanupOldLogFiles");
49703
49744
  debugLogFilepath = getDebugFilepath();
49704
49745
  mutex = new miniflare.Mutex();
49746
+ hasStartedLogCleanup = false;
49747
+ __name(tryCleanupLogs, "tryCleanupLogs");
49705
49748
  hasLoggedLocation = false;
49706
49749
  hasLoggedError = false;
49707
49750
  hasSeenErrorMessage = false;
@@ -49723,6 +49766,13 @@ function getLoggerLevel() {
49723
49766
  }
49724
49767
  return "log";
49725
49768
  }
49769
+ function shouldLogToDisk(isTestEnvironment = typeof vitest !== "undefined") {
49770
+ if (isTestEnvironment) {
49771
+ return false;
49772
+ }
49773
+ const setting = process.env.WRANGLER_WRITE_LOGS?.toLowerCase();
49774
+ return setting !== "false" && setting !== "0";
49775
+ }
49726
49776
  function consoleMethodToLoggerLevel(method) {
49727
49777
  if (method in LOGGER_LEVELS) {
49728
49778
  return method;
@@ -49776,6 +49826,7 @@ var init_logger = __esm({
49776
49826
  __name(getLoggerLevel, "getLoggerLevel");
49777
49827
  overrideLoggerLevel = new async_hooks.AsyncLocalStorage();
49778
49828
  runWithLogLevel = /* @__PURE__ */ __name((overrideLogLevel, cb2) => overrideLoggerLevel.run({ logLevel: overrideLogLevel }, cb2), "runWithLogLevel");
49829
+ __name(shouldLogToDisk, "shouldLogToDisk");
49779
49830
  __name(consoleMethodToLoggerLevel, "consoleMethodToLoggerLevel");
49780
49831
  Logger = class _Logger {
49781
49832
  static {
@@ -49865,8 +49916,7 @@ var init_logger = __esm({
49865
49916
  }
49866
49917
  doLog(messageLevel, args) {
49867
49918
  const message = Array.isArray(args) ? this.formatMessage(messageLevel, util4.format(...args)) : args;
49868
- const inUnitTests = typeof vitest !== "undefined";
49869
- if (!inUnitTests) {
49919
+ if (shouldLogToDisk()) {
49870
49920
  void appendToDebugLogFile(messageLevel, message);
49871
49921
  }
49872
49922
  if (LOGGER_LEVELS[this.loggerLevel] >= LOGGER_LEVELS[messageLevel]) {
@@ -53968,16 +54018,16 @@ var require_windows = __commonJS({
53968
54018
  return false;
53969
54019
  }
53970
54020
  __name(checkPathExt, "checkPathExt");
53971
- function checkStat(stat9, path85, options) {
53972
- if (!stat9.isSymbolicLink() && !stat9.isFile()) {
54021
+ function checkStat(stat10, path85, options) {
54022
+ if (!stat10.isSymbolicLink() && !stat10.isFile()) {
53973
54023
  return false;
53974
54024
  }
53975
54025
  return checkPathExt(path85, options);
53976
54026
  }
53977
54027
  __name(checkStat, "checkStat");
53978
54028
  function isexe(path85, options, cb2) {
53979
- fs33.stat(path85, function(er2, stat9) {
53980
- cb2(er2, er2 ? false : checkStat(stat9, path85, options));
54029
+ fs33.stat(path85, function(er2, stat10) {
54030
+ cb2(er2, er2 ? false : checkStat(stat10, path85, options));
53981
54031
  });
53982
54032
  }
53983
54033
  __name(isexe, "isexe");
@@ -53996,8 +54046,8 @@ var require_mode = __commonJS({
53996
54046
  isexe.sync = sync;
53997
54047
  var fs33 = __require("fs");
53998
54048
  function isexe(path85, options, cb2) {
53999
- fs33.stat(path85, function(er2, stat9) {
54000
- cb2(er2, er2 ? false : checkStat(stat9, options));
54049
+ fs33.stat(path85, function(er2, stat10) {
54050
+ cb2(er2, er2 ? false : checkStat(stat10, options));
54001
54051
  });
54002
54052
  }
54003
54053
  __name(isexe, "isexe");
@@ -54005,14 +54055,14 @@ var require_mode = __commonJS({
54005
54055
  return checkStat(fs33.statSync(path85), options);
54006
54056
  }
54007
54057
  __name(sync, "sync");
54008
- function checkStat(stat9, options) {
54009
- return stat9.isFile() && checkMode(stat9, options);
54058
+ function checkStat(stat10, options) {
54059
+ return stat10.isFile() && checkMode(stat10, options);
54010
54060
  }
54011
54061
  __name(checkStat, "checkStat");
54012
- function checkMode(stat9, options) {
54013
- var mod = stat9.mode;
54014
- var uid = stat9.uid;
54015
- var gid = stat9.gid;
54062
+ function checkMode(stat10, options) {
54063
+ var mod = stat10.mode;
54064
+ var uid = stat10.uid;
54065
+ var gid = stat10.gid;
54016
54066
  var myUid = options.uid !== void 0 ? options.uid : process.getuid && process.getuid();
54017
54067
  var myGid = options.gid !== void 0 ? options.gid : process.getgid && process.getgid();
54018
54068
  var u8 = parseInt("100", 8);
@@ -55818,7 +55868,7 @@ var name, version;
55818
55868
  var init_package = __esm({
55819
55869
  "package.json"() {
55820
55870
  name = "wrangler";
55821
- version = "4.90.0";
55871
+ version = "4.91.0";
55822
55872
  }
55823
55873
  });
55824
55874
  function getWranglerVersion() {
@@ -135822,8 +135872,8 @@ var init_esm6 = __esm({
135822
135872
  }
135823
135873
  return this._userIgnored(path85, stats);
135824
135874
  }
135825
- _isntIgnored(path85, stat9) {
135826
- return !this._isIgnored(path85, stat9);
135875
+ _isntIgnored(path85, stat10) {
135876
+ return !this._isIgnored(path85, stat10);
135827
135877
  }
135828
135878
  /**
135829
135879
  * Provides a set of common helpers and properties relating to symlink handling.
@@ -137304,13 +137354,13 @@ var require_eventemitter3 = __commonJS({
137304
137354
  }
137305
137355
  __name(EventEmitter5, "EventEmitter");
137306
137356
  EventEmitter5.prototype.eventNames = /* @__PURE__ */ __name(function eventNames() {
137307
- var names = [], events6, name2;
137357
+ var names = [], events7, name2;
137308
137358
  if (this._eventsCount === 0) return names;
137309
- for (name2 in events6 = this._events) {
137310
- if (has2.call(events6, name2)) names.push(prefix ? name2.slice(1) : name2);
137359
+ for (name2 in events7 = this._events) {
137360
+ if (has2.call(events7, name2)) names.push(prefix ? name2.slice(1) : name2);
137311
137361
  }
137312
137362
  if (Object.getOwnPropertySymbols) {
137313
- return names.concat(Object.getOwnPropertySymbols(events6));
137363
+ return names.concat(Object.getOwnPropertySymbols(events7));
137314
137364
  }
137315
137365
  return names;
137316
137366
  }, "eventNames");
@@ -137399,12 +137449,12 @@ var require_eventemitter3 = __commonJS({
137399
137449
  clearEvent(this, evt);
137400
137450
  }
137401
137451
  } else {
137402
- for (var i7 = 0, events6 = [], length = listeners.length; i7 < length; i7++) {
137452
+ for (var i7 = 0, events7 = [], length = listeners.length; i7 < length; i7++) {
137403
137453
  if (listeners[i7].fn !== fn2 || once && !listeners[i7].once || context2 && listeners[i7].context !== context2) {
137404
- events6.push(listeners[i7]);
137454
+ events7.push(listeners[i7]);
137405
137455
  }
137406
137456
  }
137407
- if (events6.length) this._events[evt] = events6.length === 1 ? events6[0] : events6;
137457
+ if (events7.length) this._events[evt] = events7.length === 1 ? events7[0] : events7;
137408
137458
  else clearEvent(this, evt);
137409
137459
  }
137410
137460
  return this;
@@ -139547,7 +139597,8 @@ function getInstanceTypeUsage(instanceType) {
139547
139597
  function inferInstanceType(config) {
139548
139598
  for (const [instanceType, configuration] of Object.entries(instanceTypes)) {
139549
139599
  if (config.vcpu === configuration.vcpu && config.memory_mib === configuration.memory_mib && config.disk?.size_mb === configuration.disk_mb) {
139550
- return instanceType;
139600
+ const canonical = instanceType in LEGACY_TO_CANONICAL ? LEGACY_TO_CANONICAL[instanceType] : void 0;
139601
+ return canonical ?? instanceType;
139551
139602
  }
139552
139603
  }
139553
139604
  }
@@ -139565,11 +139616,12 @@ function cleanForInstanceType(app) {
139565
139616
  delete app.configuration.vcpu;
139566
139617
  return app;
139567
139618
  }
139568
- var instanceTypes, instanceTypeNames;
139619
+ var instanceTypes, instanceTypeNames, LEGACY_TO_CANONICAL;
139569
139620
  var init_instance_type = __esm({
139570
139621
  "src/cloudchamber/instance-type/instance-type.ts"() {
139571
139622
  init_import_meta_url();
139572
139623
  init_interactive();
139624
+ init_containers_shared();
139573
139625
  init_dist();
139574
139626
  instanceTypes = {
139575
139627
  // lite is the default instance type when REQUIRE_INSTANCE_TYPE is set
@@ -139618,6 +139670,10 @@ var init_instance_type = __esm({
139618
139670
  __name(promptForInstanceType, "promptForInstanceType");
139619
139671
  __name(checkInstanceType, "checkInstanceType");
139620
139672
  __name(getInstanceTypeUsage, "getInstanceTypeUsage");
139673
+ LEGACY_TO_CANONICAL = {
139674
+ dev: "lite" /* LITE */,
139675
+ standard: "standard-1" /* STANDARD_1 */
139676
+ };
139621
139677
  __name(inferInstanceType, "inferInstanceType");
139622
139678
  __name(cleanForInstanceType, "cleanForInstanceType");
139623
139679
  }
@@ -179982,8 +180038,8 @@ function getLayerRoutePathString(isArray, lrp) {
179982
180038
  return lrp && lrp.toString();
179983
180039
  }
179984
180040
  function preventDuplicateSegments(originalUrl, reconstructedRoute, layerPath) {
179985
- const normalizeURL = stripUrlQueryAndFragment(originalUrl || "");
179986
- const originalUrlSplit = _optionalChain([normalizeURL, "optionalAccess", (_14) => _14.split, "call", (_15) => _15("/"), "access", (_16) => _16.filter, "call", (_17) => _17((v7) => !!v7)]);
180041
+ const normalizeURL2 = stripUrlQueryAndFragment(originalUrl || "");
180042
+ const originalUrlSplit = _optionalChain([normalizeURL2, "optionalAccess", (_14) => _14.split, "call", (_15) => _15("/"), "access", (_16) => _16.filter, "call", (_17) => _17((v7) => !!v7)]);
179987
180043
  let tempCounter = 0;
179988
180044
  const currentOffset = _optionalChain([reconstructedRoute, "optionalAccess", (_18) => _18.split, "call", (_19) => _19("/"), "access", (_20) => _20.filter, "call", (_21) => _21((v7) => !!v7), "access", (_22) => _22.length]) || 0;
179989
180045
  const result = _optionalChain([
@@ -184446,14 +184502,16 @@ function createHandler(def, argv) {
184446
184502
  addBreadcrumb2(def.command);
184447
184503
  try {
184448
184504
  const shouldPrintBanner = def.behaviour?.printBanner ?? true;
184449
- if (shouldPrintBanner === true || typeof shouldPrintBanner === "function" && shouldPrintBanner(args) === true) {
184505
+ const bannerEnabled = shouldPrintBanner === true || typeof shouldPrintBanner === "function" && shouldPrintBanner(args) === true;
184506
+ if (bannerEnabled) {
184450
184507
  await printWranglerBanner();
184451
184508
  }
184509
+ const statusMessageEnabled = typeof shouldPrintBanner !== "function" || bannerEnabled;
184452
184510
  if (!getWranglerHideBanner()) {
184453
184511
  if (def.metadata.deprecated) {
184454
184512
  logger.warn(def.metadata.deprecatedMessage);
184455
184513
  }
184456
- if (def.metadata.statusMessage) {
184514
+ if (statusMessageEnabled && def.metadata.statusMessage) {
184457
184515
  logger.warn(def.metadata.statusMessage);
184458
184516
  }
184459
184517
  }
@@ -233993,8 +234051,8 @@ async function locatePath(paths, {
233993
234051
  const statFunction = allowSymlinks ? fs29.promises.stat : fs29.promises.lstat;
233994
234052
  return pLocate(paths, async (path_) => {
233995
234053
  try {
233996
- const stat9 = await statFunction(path3__namespace.default.resolve(cwd2, path_));
233997
- return matchType(type, stat9);
234054
+ const stat10 = await statFunction(path3__namespace.default.resolve(cwd2, path_));
234055
+ return matchType(type, stat10);
233998
234056
  } catch {
233999
234057
  return false;
234000
234058
  }
@@ -234010,7 +234068,7 @@ var init_locate_path = __esm({
234010
234068
  file: "isFile"
234011
234069
  };
234012
234070
  __name(checkType, "checkType");
234013
- matchType = /* @__PURE__ */ __name((type, stat9) => stat9[typeMappings[type]](), "matchType");
234071
+ matchType = /* @__PURE__ */ __name((type, stat10) => stat10[typeMappings[type]](), "matchType");
234014
234072
  toPath = /* @__PURE__ */ __name((urlOrPath) => urlOrPath instanceof URL ? Url.fileURLToPath(urlOrPath) : urlOrPath, "toPath");
234015
234073
  __name(locatePath, "locatePath");
234016
234074
  }
@@ -247846,6 +247904,7 @@ ${JSON.stringify(defaultRoutesJSONSpec, null, 2)}`
247846
247904
  tsconfig: void 0,
247847
247905
  minify: void 0,
247848
247906
  legacyEnv: void 0,
247907
+ tunnelName: void 0,
247849
247908
  env: void 0,
247850
247909
  envFile: void 0,
247851
247910
  ip,
@@ -285500,6 +285559,8 @@ function getBindingValue(binding) {
285500
285559
  switch (binding.type) {
285501
285560
  case "plain_text":
285502
285561
  return `"${binding.text}"`;
285562
+ case "json":
285563
+ return JSON.stringify(binding.json);
285503
285564
  case "secret_text":
285504
285565
  return "********";
285505
285566
  case "kv_namespace":
@@ -285549,10 +285610,7 @@ function extractConfigBindings(config) {
285549
285610
  const env6 = {};
285550
285611
  const vars = previews?.vars ?? {};
285551
285612
  for (const [name2, value] of Object.entries(vars)) {
285552
- env6[name2] = {
285553
- type: "plain_text",
285554
- text: typeof value === "string" ? value : JSON.stringify(value)
285555
- };
285613
+ env6[name2] = typeof value === "string" ? { type: "plain_text", text: value } : { type: "json", json: value };
285556
285614
  }
285557
285615
  for (const kv of previews?.kv_namespaces ?? []) {
285558
285616
  env6[kv.binding] = { type: "kv_namespace", namespace_id: kv.id };
@@ -285568,10 +285626,14 @@ function extractConfigBindings(config) {
285568
285626
  env6[r22.binding] = { type: "r2_bucket", bucket_name: r22.bucket_name };
285569
285627
  }
285570
285628
  for (const service of previews?.services ?? []) {
285629
+ const crossAccountGrant = service.cross_account_grant;
285571
285630
  env6[service.binding] = {
285572
285631
  type: "service",
285573
285632
  service: service.service,
285574
- entrypoint: service.entrypoint
285633
+ entrypoint: service.entrypoint,
285634
+ ...crossAccountGrant !== void 0 && {
285635
+ cross_account_grant: crossAccountGrant
285636
+ }
285575
285637
  };
285576
285638
  }
285577
285639
  for (const doBinding of previews?.durable_objects?.bindings ?? []) {
@@ -285698,6 +285760,10 @@ function extractConfigBindings(config) {
285698
285760
  if (config.assets?.binding) {
285699
285761
  env6[config.assets.binding] = { type: "assets" };
285700
285762
  }
285763
+ for (const binding of previews?.unsafe?.bindings ?? []) {
285764
+ const { name: name2, type, ...rest } = binding;
285765
+ env6[name2] = { type, ...rest };
285766
+ }
285701
285767
  return env6;
285702
285768
  }
285703
285769
  function assemblePreviewScriptSettings(config) {
@@ -290797,8 +290863,8 @@ var init_create14 = __esm({
290797
290863
  workerName: args.workerName,
290798
290864
  workflowName: args.workflowName
290799
290865
  });
290800
- const events6 = args.events.split(",").map((event) => event.trim()).filter(Boolean);
290801
- if (events6.length === 0) {
290866
+ const events7 = args.events.split(",").map((event) => event.trim()).filter(Boolean);
290867
+ if (events7.length === 0) {
290802
290868
  throw new UserError(
290803
290869
  "No events specified. Use --events to provide a comma-separated list of event types to subscribe to. For a complete list of sources and corresponding events, please refer to: https://developers.cloudflare.com/queues/event-subscriptions/events-schemas/",
290804
290870
  { telemetryMessage: "queues subscription create missing events" }
@@ -290812,7 +290878,7 @@ var init_create14 = __esm({
290812
290878
  type: "queues.queue",
290813
290879
  queue_id: ""
290814
290880
  },
290815
- events: events6
290881
+ events: events7
290816
290882
  };
290817
290883
  logger.log(`Creating event subscription for queue '${args.queue}'...`);
290818
290884
  const subscription = await createEventSubscription(
@@ -291100,14 +291166,14 @@ var init_update6 = __esm({
291100
291166
  updateRequest.name = args.name;
291101
291167
  }
291102
291168
  if (args.events !== void 0) {
291103
- const events6 = args.events.split(",").map((event) => event.trim()).filter(Boolean);
291104
- if (events6.length === 0) {
291169
+ const events7 = args.events.split(",").map((event) => event.trim()).filter(Boolean);
291170
+ if (events7.length === 0) {
291105
291171
  throw new UserError(
291106
291172
  "No events specified. Use --events to provide a comma-separated list of event types to subscribe to. For a complete list of sources and corresponding events, please refer to: https://developers.cloudflare.com/queues/event-subscriptions/events-schemas/",
291107
291173
  { telemetryMessage: "queues subscription update missing events" }
291108
291174
  );
291109
291175
  }
291110
- updateRequest.events = events6;
291176
+ updateRequest.events = events7;
291111
291177
  }
291112
291178
  if (args.enabled !== void 0) {
291113
291179
  updateRequest.enabled = args.enabled;
@@ -294059,13 +294125,13 @@ function validateBulkPutFile(filename) {
294059
294125
  telemetryMessage: "r2 object bulk put entry file not found"
294060
294126
  });
294061
294127
  }
294062
- const stat9 = fs29__namespace.default.statSync(entry.file, { throwIfNoEntry: false });
294063
- if (!stat9?.isFile()) {
294128
+ const stat10 = fs29__namespace.default.statSync(entry.file, { throwIfNoEntry: false });
294129
+ if (!stat10?.isFile()) {
294064
294130
  throw new UserError(`The path "${entry.file}" is not a file.`, {
294065
294131
  telemetryMessage: "r2 object bulk put entry path not file"
294066
294132
  });
294067
294133
  }
294068
- if (stat9.size > MAX_UPLOAD_SIZE_BYTES) {
294134
+ if (stat10.size > MAX_UPLOAD_SIZE_BYTES) {
294069
294135
  throw new UserError(
294070
294136
  `The file "${entry.file}" exceeds the maximum upload size of ${prettyBytes(
294071
294137
  MAX_UPLOAD_SIZE_BYTES,
@@ -294074,7 +294140,7 @@ function validateBulkPutFile(filename) {
294074
294140
  { telemetryMessage: "r2 object bulk put entry file too large" }
294075
294141
  );
294076
294142
  }
294077
- entry.size = stat9.size;
294143
+ entry.size = stat10.size;
294078
294144
  }
294079
294145
  return entries2;
294080
294146
  }
@@ -296858,6 +296924,119 @@ async function getTunnelToken(sdk, accountId, tunnelId) {
296858
296924
  return String(response);
296859
296925
  });
296860
296926
  }
296927
+ async function resolveNamedTunnel(name2, origin, options) {
296928
+ let accountId = options.accountId;
296929
+ if (!accountId) {
296930
+ accountId = await requireAuth({
296931
+ account_id: options.accountId,
296932
+ compliance_region: options.complianceRegion
296933
+ });
296934
+ }
296935
+ const sdk = createCloudflareClient({
296936
+ compliance_region: options.complianceRegion
296937
+ });
296938
+ const tunnel = await withTunnelErrorHandling(async () => {
296939
+ for await (const item of sdk.zeroTrust.tunnels.cloudflared.list({
296940
+ account_id: accountId,
296941
+ name: name2,
296942
+ is_deleted: false
296943
+ })) {
296944
+ if (item.name === name2) {
296945
+ return normalizeTunnelResponse(item);
296946
+ }
296947
+ }
296948
+ return null;
296949
+ });
296950
+ if (!tunnel) {
296951
+ throw new UserError(
296952
+ `No Cloudflare Tunnel named "${name2}" was found in this account. Use "wrangler tunnel list" to see available tunnels.`,
296953
+ { telemetryMessage: "tunnel resolve named missing tunnel" }
296954
+ );
296955
+ }
296956
+ const tunnelId = tunnel.id;
296957
+ if (!tunnelId) {
296958
+ throw new FatalError(
296959
+ `Tunnel "${name2}" was found but has no ID. This is unexpected.`,
296960
+ { telemetryMessage: "tunnel resolve named missing tunnel id" }
296961
+ );
296962
+ }
296963
+ const configuration = await withTunnelErrorHandling(
296964
+ () => sdk.zeroTrust.tunnels.cloudflared.configurations.get(tunnelId, {
296965
+ account_id: accountId
296966
+ })
296967
+ );
296968
+ const hostnames = getMatchingIngressHostnames(
296969
+ origin,
296970
+ configuration.config?.ingress ?? []
296971
+ );
296972
+ if (hostnames.length === 0) {
296973
+ throw new UserError(
296974
+ createMissingIngressMessage(
296975
+ name2,
296976
+ origin,
296977
+ `https://dash.cloudflare.com/${accountId}/tunnels/${tunnelId}`,
296978
+ configuration.config?.ingress ?? []
296979
+ ),
296980
+ { telemetryMessage: "tunnel resolve named ingress mismatch" }
296981
+ );
296982
+ }
296983
+ const token = await getTunnelToken(sdk, accountId, tunnelId);
296984
+ return { hostnames, token };
296985
+ }
296986
+ function getMatchingIngressHostnames(origin, ingressConfig) {
296987
+ const hostnames = /* @__PURE__ */ new Set();
296988
+ const originUrl = normalizeURL(origin);
296989
+ for (const ingress of ingressConfig) {
296990
+ try {
296991
+ const serviceUrl = normalizeURL(ingress.service);
296992
+ if (ingress.hostname && serviceUrl.toString() === originUrl.toString()) {
296993
+ hostnames.add(ingress.hostname);
296994
+ }
296995
+ } catch {
296996
+ }
296997
+ }
296998
+ return [...hostnames];
296999
+ }
297000
+ function normalizeURL(url4) {
297001
+ const normalizedUrl = new URL(url4);
297002
+ if (LOCAL_TUNNEL_HOSTNAMES.has(normalizedUrl.hostname)) {
297003
+ normalizedUrl.hostname = "localhost";
297004
+ }
297005
+ if (!normalizedUrl.port) {
297006
+ switch (normalizedUrl.protocol) {
297007
+ case "http:":
297008
+ normalizedUrl.port = "80";
297009
+ break;
297010
+ case "https:":
297011
+ normalizedUrl.port = "443";
297012
+ break;
297013
+ }
297014
+ }
297015
+ return normalizedUrl;
297016
+ }
297017
+ function createMissingIngressMessage(name2, origin, dashboardUrl, ingress) {
297018
+ if (ingress.length === 0) {
297019
+ return [
297020
+ `Tunnel "${name2}" has no routes configured.`,
297021
+ "",
297022
+ `Add a route for ${origin} in the Cloudflare dashboard:`,
297023
+ dashboardUrl,
297024
+ ""
297025
+ ].join("\n");
297026
+ }
297027
+ return [
297028
+ `Tunnel "${name2}" has no route for ${origin}`,
297029
+ "",
297030
+ "Resolved routes:",
297031
+ ...ingress.map(
297032
+ ({ hostname: hostname2, service }) => ` - ${hostname2 ?? "(no hostname)"} -> ${service}`
297033
+ ),
297034
+ "",
297035
+ "Update your local server settings or the tunnel routes in the Cloudflare dashboard:",
297036
+ dashboardUrl,
297037
+ ""
297038
+ ].join("\n");
297039
+ }
296861
297040
  function normalizeTunnelResponse(response) {
296862
297041
  return response;
296863
297042
  }
@@ -296900,12 +297079,21 @@ async function resolveTunnelId(sdk, accountId, input) {
296900
297079
  }
296901
297080
  return tunnelId;
296902
297081
  }
296903
- var TUNNEL_PERMISSION_ERROR_MESSAGE, TUNNEL_ID_REGEX;
297082
+ var LOCAL_TUNNEL_HOSTNAMES, TUNNEL_PERMISSION_ERROR_MESSAGE, TUNNEL_ID_REGEX;
296904
297083
  var init_client12 = __esm({
296905
297084
  "src/tunnel/client.ts"() {
296906
297085
  init_import_meta_url();
296907
297086
  init_dist();
296908
297087
  init_cloudflare();
297088
+ init_internal();
297089
+ init_user3();
297090
+ LOCAL_TUNNEL_HOSTNAMES = /* @__PURE__ */ new Set([
297091
+ "localhost",
297092
+ "127.0.0.1",
297093
+ "::1",
297094
+ "0.0.0.0",
297095
+ "::"
297096
+ ]);
296909
297097
  TUNNEL_PERMISSION_ERROR_MESSAGE = `
296910
297098
  Cloudflare Tunnel commands require API token authentication with tunnel permissions.
296911
297099
 
@@ -296928,6 +297116,10 @@ Then run your tunnel command again.
296928
297116
  __name(listTunnels, "listTunnels");
296929
297117
  __name(deleteTunnel, "deleteTunnel");
296930
297118
  __name(getTunnelToken, "getTunnelToken");
297119
+ __name(resolveNamedTunnel, "resolveNamedTunnel");
297120
+ __name(getMatchingIngressHostnames, "getMatchingIngressHostnames");
297121
+ __name(normalizeURL, "normalizeURL");
297122
+ __name(createMissingIngressMessage, "createMissingIngressMessage");
296931
297123
  __name(normalizeTunnelResponse, "normalizeTunnelResponse");
296932
297124
  TUNNEL_ID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
296933
297125
  __name(isTunnelId, "isTunnelId");
@@ -315070,8 +315262,12 @@ var init_dev2 = __esm({
315070
315262
  type: "boolean"
315071
315263
  },
315072
315264
  tunnel: {
315073
- describe: "Expose your local dev server via a Cloudflare Quick Tunnel (https://try.cloudflare.com)",
315265
+ describe: "Expose your local dev server via a Cloudflare Tunnel. Use `--tunnel` for a Quick Tunnel and `--tunnel-name` with `--tunnel` for a named tunnel.",
315074
315266
  type: "boolean"
315267
+ },
315268
+ "tunnel-name": {
315269
+ describe: "Use an existing named Cloudflare Tunnel when `--tunnel` is enabled.",
315270
+ type: "string"
315075
315271
  }
315076
315272
  },
315077
315273
  async validateArgs(args) {
@@ -317000,7 +317196,7 @@ var init_ProxyController = __esm({
317000
317196
  logger.debug("[ProxyWorker]", ...message.args);
317001
317197
  break;
317002
317198
  case "sseResponseDetected":
317003
- if (this.latestConfig?.dev?.tunnel) {
317199
+ if (this.latestConfig?.dev?.tunnel?.enabled && this.latestConfig.dev.tunnel.name === void 0) {
317004
317200
  logger.once.warn(
317005
317201
  "Quick tunnels do not support Server-Sent Events (SSE). Use a named Cloudflare Tunnel if you need SSE over a public URL."
317006
317202
  );
@@ -317641,6 +317837,9 @@ var init_RemoteRuntimeController = __esm({
317641
317837
  }
317642
317838
  );
317643
317839
  this.#activeTail.on("message", realishPrintLogs);
317840
+ this.#activeTail.on("error", (err) => {
317841
+ logger.debug("Active tail WebSocket error (ignored):", err);
317842
+ });
317644
317843
  }
317645
317844
  return workerPreviewToken;
317646
317845
  } catch (err) {
@@ -318000,6 +318199,10 @@ var init_DevEnv = __esm({
318000
318199
  * - RuntimeController emits devRegistryUpdate → ConfigController
318001
318200
  * - ProxyController emits previewTokenExpired → RuntimeControllers
318002
318201
  * - Any controller emits error → DevEnv error handler
318202
+ *
318203
+ * `reloadComplete` is also re-emitted as an external EventEmitter event
318204
+ * (`devEnv.on("reloadComplete", ...)`) so callers like
318205
+ * `RemoteProxySession.updateBindings` can wait for the reload to finish.
318003
318206
  */
318004
318207
  dispatch(event) {
318005
318208
  switch (event.type) {
@@ -318026,6 +318229,7 @@ var init_DevEnv = __esm({
318026
318229
  break;
318027
318230
  case "reloadComplete":
318028
318231
  this.proxy.onReloadComplete(event);
318232
+ this.emit("reloadComplete", event);
318029
318233
  break;
318030
318234
  case "devRegistryUpdate":
318031
318235
  this.config.onDevRegistryUpdate(event);
@@ -318184,7 +318388,17 @@ ${errorMessage}`
318184
318388
  { ...binding, raw: true }
318185
318389
  ])
318186
318390
  );
318391
+ const reloadComplete = events__default.default.once(worker.raw, "reloadComplete");
318187
318392
  await worker.patchConfig({ bindings: rawNewBindings });
318393
+ try {
318394
+ await reloadComplete;
318395
+ } catch (errOrEvent) {
318396
+ throw errOrEvent instanceof Error ? errOrEvent : new Error(
318397
+ `RemoteProxySession.updateBindings failed during reload: ${errOrEvent?.reason ?? "unknown"}`,
318398
+ { cause: errOrEvent }
318399
+ );
318400
+ }
318401
+ await worker.raw.proxy.runtimeMessageMutex.drained();
318188
318402
  }, "updateBindings");
318189
318403
  return {
318190
318404
  ready: worker.ready,
@@ -319049,6 +319263,13 @@ function cli_hotkeys_default(options, render2 = true) {
319049
319263
  \u2570\u2500\u2500${"\u2500".repeat(maxLineLength)}\u2500\u2500\u256F`;
319050
319264
  }
319051
319265
  __name(formatInstructions, "formatInstructions");
319266
+ function isKeyMatch(input, key) {
319267
+ if (input === key) {
319268
+ return true;
319269
+ }
319270
+ return /^[a-z]$/.test(key) && input === `shift+${key}`;
319271
+ }
319272
+ __name(isKeyMatch, "isKeyMatch");
319052
319273
  const unregisterKeyPress = onKeyPress(async (key) => {
319053
319274
  const entries2 = [];
319054
319275
  if (key.name) {
@@ -319068,7 +319289,7 @@ function cli_hotkeys_default(options, render2 = true) {
319068
319289
  if (unwrapHook(disabled)) {
319069
319290
  continue;
319070
319291
  }
319071
- if (keys.includes(char)) {
319292
+ if (keys.some((registeredKey) => isKeyMatch(char, registeredKey))) {
319072
319293
  try {
319073
319294
  await handler();
319074
319295
  } catch {
@@ -319102,7 +319323,7 @@ var init_cli_hotkeys = __esm({
319102
319323
  }
319103
319324
  });
319104
319325
  function registerDevHotKeys(devEnvs, args, options = {}) {
319105
- const { render: render2 = true, getTunnel: getTunnel2 } = options;
319326
+ const { render: render2 = true, tunnelManager } = options;
319106
319327
  const primaryDevEnv = devEnvs[0];
319107
319328
  const unregisterHotKeys = cli_hotkeys_default(
319108
319329
  [
@@ -319176,7 +319397,7 @@ function registerDevHotKeys(devEnvs, args, options = {}) {
319176
319397
  {
319177
319398
  keys: ["l"],
319178
319399
  // Remote mode is not supported when using tunnels
319179
- disabled: /* @__PURE__ */ __name(() => args.forceLocal || args.tunnel, "disabled"),
319400
+ disabled: /* @__PURE__ */ __name(() => args.forceLocal || !!tunnelManager?.isOpen(), "disabled"),
319180
319401
  handler: /* @__PURE__ */ __name(async () => {
319181
319402
  await primaryDevEnv.config.patch({
319182
319403
  dev: {
@@ -319187,16 +319408,29 @@ function registerDevHotKeys(devEnvs, args, options = {}) {
319187
319408
  }, "handler")
319188
319409
  },
319189
319410
  {
319190
- // We remind users about the tunnel hotkey every 10mins
319191
- // Hiding this hotkey to reduce noise on startup
319192
319411
  keys: ["t"],
319193
- disabled: /* @__PURE__ */ __name(() => !args.tunnel, "disabled"),
319412
+ label: /* @__PURE__ */ __name(() => tunnelManager?.isOpen() ? "close tunnel" : "start tunnel", "label"),
319413
+ disabled: /* @__PURE__ */ __name(() => primaryDevEnv.config.latestConfig?.dev?.remote === true, "disabled"),
319194
319414
  handler: /* @__PURE__ */ __name(async () => {
319195
- const tunnel = getTunnel2?.();
319196
- if (!tunnel) {
319197
- return;
319415
+ try {
319416
+ if (!tunnelManager?.isOpen()) {
319417
+ await tunnelManager?.start(true);
319418
+ return;
319419
+ }
319420
+ await tunnelManager.stop();
319421
+ } catch (error2) {
319422
+ logger.error(
319423
+ error2 instanceof Error ? error2.message : String(error2)
319424
+ );
319198
319425
  }
319199
- tunnel.extendExpiry();
319426
+ }, "handler")
319427
+ },
319428
+ {
319429
+ keys: ["a"],
319430
+ label: "extend tunnel by 1 hour",
319431
+ disabled: /* @__PURE__ */ __name(() => !tunnelManager?.isOpen(), "disabled"),
319432
+ handler: /* @__PURE__ */ __name(async () => {
319433
+ tunnelManager?.getTunnel()?.extendExpiry();
319200
319434
  }, "handler")
319201
319435
  },
319202
319436
  {
@@ -319244,6 +319478,126 @@ var init_hotkeys = __esm({
319244
319478
  __name(registerDevHotKeys, "registerDevHotKeys");
319245
319479
  }
319246
319480
  });
319481
+
319482
+ // src/tunnel/dev.ts
319483
+ var TunnelManager;
319484
+ var init_dev3 = __esm({
319485
+ "src/tunnel/dev.ts"() {
319486
+ init_import_meta_url();
319487
+ init_colors();
319488
+ init_dist();
319489
+ init_source();
319490
+ init_start_dev();
319491
+ init_logger();
319492
+ init_client12();
319493
+ TunnelManager = class {
319494
+ static {
319495
+ __name(this, "TunnelManager");
319496
+ }
319497
+ primaryDevEnv;
319498
+ args;
319499
+ tunnel;
319500
+ constructor(primaryDevEnv, args) {
319501
+ this.primaryDevEnv = primaryDevEnv;
319502
+ this.args = args;
319503
+ }
319504
+ getTunnel() {
319505
+ return this.tunnel;
319506
+ }
319507
+ isOpen() {
319508
+ return this.tunnel !== void 0;
319509
+ }
319510
+ async start(shortcutPressed = false) {
319511
+ if (this.tunnel) {
319512
+ return;
319513
+ }
319514
+ logger.log(dim("\u2394 Starting tunnel (usually takes a few seconds)..."));
319515
+ const origin = this.getTunnelOrigin();
319516
+ const tunnelConfig = this.getCurrentTunnelConfig();
319517
+ const isQuickTunnel = tunnelConfig?.name === void 0;
319518
+ logger.warn(
319519
+ (isQuickTunnel ? source_default.dim("Once connected, this tunnel will be ") + "publicly accessible" : source_default.dim(
319520
+ "Once connected, this tunnel may be reachable from the Internet"
319521
+ )) + source_default.dim(". Anyone who can reach it can:\n") + source_default.dim(
319522
+ "- Call ungated endpoints\n- Trigger logic that uses remote bindings\n- Reach internal services if your Worker proxies requests\n\n" + (isQuickTunnel ? "Consider using a named tunnel with Cloudflare Access to restrict access.\n" : "Consider using Cloudflare Access to restrict access.\n")
319523
+ ) + (shortcutPressed ? "\nPress [t] again to close the tunnel." : "")
319524
+ );
319525
+ const namedTunnel = tunnelConfig?.name !== void 0 ? await resolveNamedTunnel(tunnelConfig.name, origin, {
319526
+ accountId: this.args.accountId,
319527
+ complianceRegion: this.primaryDevEnv.config.latestConfig?.complianceRegion
319528
+ }) : void 0;
319529
+ const nextTunnel = startTunnel({
319530
+ origin,
319531
+ token: namedTunnel?.token,
319532
+ extendHint: "Press [a] to extend by 1 hour.",
319533
+ logger
319534
+ });
319535
+ this.tunnel = nextTunnel;
319536
+ try {
319537
+ const result = await nextTunnel.ready();
319538
+ if (this.tunnel !== nextTunnel) {
319539
+ return;
319540
+ }
319541
+ await this.syncTunnelState(true);
319542
+ this.logTunnelDetails(result, namedTunnel);
319543
+ } catch (error2) {
319544
+ if (this.tunnel === nextTunnel) {
319545
+ this.tunnel = void 0;
319546
+ await this.syncTunnelState(false);
319547
+ }
319548
+ throw error2;
319549
+ }
319550
+ }
319551
+ async stop() {
319552
+ if (!this.tunnel) {
319553
+ return;
319554
+ }
319555
+ logger.log(dim("\u2394 Closing tunnel..."));
319556
+ this.tunnel.dispose();
319557
+ this.tunnel = void 0;
319558
+ await this.syncTunnelState(false);
319559
+ logger.log("\u2B23 Tunnel closed");
319560
+ }
319561
+ getCurrentTunnelConfig() {
319562
+ return this.primaryDevEnv.config.latestConfig?.dev?.tunnel;
319563
+ }
319564
+ getTunnelOrigin() {
319565
+ const config = this.primaryDevEnv.config.latestConfig;
319566
+ const protocol = config?.dev?.server?.secure ? "https" : "http";
319567
+ const hostname2 = config?.dev?.server?.hostname ?? "localhost";
319568
+ const port = config?.dev?.server?.port ?? 8787;
319569
+ return new URL(`${protocol}://${formatHostname(hostname2)}:${port}`);
319570
+ }
319571
+ async syncTunnelState(enabled) {
319572
+ const latestDevConfig = this.primaryDevEnv.config.latestConfig?.dev;
319573
+ if (!latestDevConfig?.tunnel || latestDevConfig.tunnel.enabled === enabled) {
319574
+ return;
319575
+ }
319576
+ await this.primaryDevEnv.config.patch({
319577
+ dev: {
319578
+ ...latestDevConfig,
319579
+ tunnel: {
319580
+ ...latestDevConfig.tunnel,
319581
+ enabled
319582
+ }
319583
+ }
319584
+ });
319585
+ }
319586
+ logTunnelDetails(result, namedTunnel) {
319587
+ const publicUrls = result.mode === "quick" ? [result.publicUrl.toString()] : namedTunnel ? namedTunnel.hostnames.map((hostname2) => `https://${hostname2}`) : [];
319588
+ if (publicUrls.length === 1) {
319589
+ logger.log(
319590
+ `\u2B23 Sharing via Cloudflare Tunnel: ${source_default.green(publicUrls[0])}`
319591
+ );
319592
+ } else if (publicUrls.length > 1) {
319593
+ logger.log(
319594
+ "\u2B23 Sharing via Cloudflare Tunnel:\n" + publicUrls.map((url4) => ` ${source_default.green(url4)}`).join("\n")
319595
+ );
319596
+ }
319597
+ }
319598
+ };
319599
+ }
319600
+ });
319247
319601
  function constructRedirects({
319248
319602
  redirects,
319249
319603
  redirectsFile,
@@ -321525,7 +321879,7 @@ var init_assets6 = __esm({
321525
321879
  });
321526
321880
  async function startDev(args) {
321527
321881
  let devEnv;
321528
- let tunnel;
321882
+ let tunnelManager;
321529
321883
  let unregisterHotKeys;
321530
321884
  try {
321531
321885
  if (args.logLevel) {
@@ -321542,7 +321896,10 @@ async function startDev(args) {
321542
321896
  unregisterHotKeys = registerDevHotKeys(
321543
321897
  Array.isArray(devEnv) ? devEnv : [devEnv],
321544
321898
  args,
321545
- { getTunnel: /* @__PURE__ */ __name(() => tunnel, "getTunnel"), render: false }
321899
+ {
321900
+ tunnelManager,
321901
+ render: false
321902
+ }
321546
321903
  );
321547
321904
  }
321548
321905
  }
@@ -321590,21 +321947,19 @@ async function startDev(args) {
321590
321947
  })
321591
321948
  )
321592
321949
  );
321593
- if (isInteractive3() && args.showInteractiveDevSession !== false) {
321594
- unregisterHotKeys = registerDevHotKeys(devEnv, args, {
321595
- getTunnel: /* @__PURE__ */ __name(() => tunnel, "getTunnel")
321596
- });
321597
- }
321598
321950
  } else {
321599
321951
  devEnv = new exports.unstable_DevEnv();
321600
321952
  await setupDevEnv(devEnv, args.config, authHook, args);
321601
- if (isInteractive3() && args.showInteractiveDevSession !== false) {
321602
- unregisterHotKeys = registerDevHotKeys([devEnv], args, {
321603
- getTunnel: /* @__PURE__ */ __name(() => tunnel, "getTunnel")
321604
- });
321605
- }
321606
321953
  }
321607
- const [primaryDevEnv, ...secondary] = Array.isArray(devEnv) ? devEnv : [devEnv];
321954
+ const devEnvs = Array.isArray(devEnv) ? devEnv : [devEnv];
321955
+ const [primaryDevEnv, ...secondary] = devEnvs;
321956
+ tunnelManager = new TunnelManager(primaryDevEnv, args);
321957
+ primaryDevEnv.on("teardown", () => {
321958
+ tunnelManager?.getTunnel()?.dispose();
321959
+ });
321960
+ if (isInteractive3() && args.showInteractiveDevSession !== false) {
321961
+ unregisterHotKeys = registerDevHotKeys(devEnvs, args, { tunnelManager });
321962
+ }
321608
321963
  void primaryDevEnv.proxy.ready.promise.then(({ url: url4 }) => {
321609
321964
  if (args.onReady) {
321610
321965
  args.onReady(url4.hostname, parseInt(url4.port));
@@ -321625,37 +321980,12 @@ async function startDev(args) {
321625
321980
  maybePrintScheduledWorkerWarning(hasCrons, !!args.testScheduled, url4);
321626
321981
  });
321627
321982
  if (args.tunnel) {
321628
- const config = primaryDevEnv.config.latestConfig;
321629
- const protocol = config?.dev?.server?.secure ? "https" : "http";
321630
- const hostname2 = config?.dev?.server?.hostname ?? "localhost";
321631
- const port = config?.dev?.server?.port ?? 8787;
321632
- const origin = new URL(
321633
- `${protocol}://${formatHostname(hostname2)}:${port}`
321634
- );
321635
- logger.log(dim("\u2394 Starting tunnel (usually takes a few seconds)..."));
321636
- tunnel = startTunnel({
321637
- origin,
321638
- extendHint: "Press [t] to extend by 1 hour.",
321639
- logger
321640
- });
321641
- primaryDevEnv.on("teardown", () => {
321642
- tunnel?.dispose();
321643
- });
321644
- const { publicUrl } = await tunnel.ready();
321645
- logger.log(
321646
- `\u2B23 Sharing via Cloudflare Tunnel: ${source_default.green(publicUrl.origin)}
321647
- `
321648
- );
321649
- logger.warn(
321650
- source_default.dim("This URL is ") + "publicly accessible" + source_default.dim(". Anyone with it can:\n") + source_default.dim(
321651
- "- Call ungated endpoints\n- Trigger logic that uses remote bindings\n- Reach internal services if your Worker proxies requests\n\nConsider using a named tunnel with Cloudflare Access to restrict access."
321652
- )
321653
- );
321983
+ await tunnelManager.start();
321654
321984
  }
321655
321985
  return {
321656
321986
  devEnv: primaryDevEnv,
321657
321987
  secondary,
321658
- unregisterHotKeys
321988
+ unregisterHotKeys: /* @__PURE__ */ __name(() => unregisterHotKeys?.(), "unregisterHotKeys")
321659
321989
  };
321660
321990
  } catch (e10) {
321661
321991
  await Promise.allSettled([
@@ -321664,7 +321994,7 @@ async function startDev(args) {
321664
321994
  unregisterHotKeys?.();
321665
321995
  })(),
321666
321996
  (async () => {
321667
- tunnel?.dispose();
321997
+ tunnelManager?.getTunnel()?.dispose();
321668
321998
  })()
321669
321999
  ]);
321670
322000
  throw e10;
@@ -321743,7 +322073,10 @@ async function setupDevEnv(devEnv, configPath, auth, args) {
321743
322073
  // initialise with a random id
321744
322074
  containerBuildId: generateContainerBuildId(),
321745
322075
  generateTypes: args.types,
321746
- tunnel: args.tunnel
322076
+ tunnel: {
322077
+ enabled: args.tunnel ?? false,
322078
+ name: args.tunnelName
322079
+ }
321747
322080
  },
321748
322081
  legacy: {
321749
322082
  site: /* @__PURE__ */ __name((configParam) => {
@@ -321812,7 +322145,6 @@ var init_start_dev = __esm({
321812
322145
  init_colors();
321813
322146
  init_containers_shared();
321814
322147
  init_dist();
321815
- init_source();
321816
322148
  init_esm2();
321817
322149
  init_api4();
321818
322150
  init_MultiworkerRuntimeController();
@@ -321823,6 +322155,7 @@ var init_start_dev = __esm({
321823
322155
  init_is_interactive();
321824
322156
  init_logger();
321825
322157
  init_sites2();
322158
+ init_dev3();
321826
322159
  init_user3();
321827
322160
  init_collectKeyValues();
321828
322161
  __name(startDev, "startDev");
@@ -321947,7 +322280,8 @@ unstable_dev()'s behaviour will likely change in future releases`
321947
322280
  dockerPath,
321948
322281
  containerEngine: options?.experimental?.containerEngine,
321949
322282
  types: false,
321950
- tunnel: void 0
322283
+ tunnel: void 0,
322284
+ tunnelName: void 0
321951
322285
  };
321952
322286
  const devServer = await run(
321953
322287
  {
@@ -321993,7 +322327,7 @@ function parseRequestInput(readyAddress, readyPort, input = "/", init4, protocol
321993
322327
  return [url4, forward];
321994
322328
  }
321995
322329
  var import_undici31;
321996
- var init_dev3 = __esm({
322330
+ var init_dev4 = __esm({
321997
322331
  "src/api/dev.ts"() {
321998
322332
  init_import_meta_url();
321999
322333
  init_dist();
@@ -322352,7 +322686,7 @@ var init_integrations6 = __esm({
322352
322686
  var init_api4 = __esm({
322353
322687
  "src/api/index.ts"() {
322354
322688
  init_import_meta_url();
322355
- init_dev3();
322689
+ init_dev4();
322356
322690
  init_pages4();
322357
322691
  init_generate_types();
322358
322692
  init_mtls_certificate();
@@ -322469,6 +322803,7 @@ init_esm();
322469
322803
  init_api4();
322470
322804
  init_src3();
322471
322805
  init_print_bindings();
322806
+ init_client12();
322472
322807
  init_splitter();
322473
322808
  init_dist();
322474
322809
  init_dist();
@@ -323158,5 +323493,6 @@ exports.unstable_getVarsForDev = getVarsForDev;
323158
323493
  exports.unstable_getWorkerNameFromProject = getWorkerNameFromProject;
323159
323494
  exports.unstable_printBindings = printBindings;
323160
323495
  exports.unstable_readConfig = readConfig;
323496
+ exports.unstable_resolveNamedTunnel = resolveNamedTunnel;
323161
323497
  exports.unstable_splitSqlQuery = splitSqlQuery;
323162
323498
  exports.unstable_startWorker = startWorker;