autotel-devtools 6.0.0 → 6.0.1

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/dist/index.js CHANGED
@@ -368,6 +368,9 @@ var DevtoolsServer = class {
368
368
  this.onData = options.onData;
369
369
  this.httpServer = options.server ?? createServer();
370
370
  this.wss = new WebSocketServer({ server: this.httpServer, path: options.path ?? "/ws" });
371
+ this.wss.on("error", (err) => {
372
+ if (this.httpServer.listening) throw err;
373
+ });
371
374
  this.wss.on("connection", (ws) => {
372
375
  this.clients.add(ws);
373
376
  this.log(`Client connected (${this.clients.size} total)`);
@@ -1029,43 +1032,79 @@ function attachDevtoolsRoutes(httpServer, devtools) {
1029
1032
  });
1030
1033
  }
1031
1034
  var LOOPBACK = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "::1"]);
1035
+ var DEFAULT_MAX_PORT_TRIES = 20;
1032
1036
  function formatAddress(host, port) {
1033
1037
  return host.includes(":") ? `[${host}]:${port}` : `${host}:${port}`;
1034
1038
  }
1035
1039
  function listenLoopbackDualStack(args) {
1036
- const { primary, port, host, attachSecondary } = args;
1040
+ const { primary, port, host, attachSecondary, maxTries } = args;
1041
+ const maxAttempts = Math.max(1, maxTries ?? DEFAULT_MAX_PORT_TRIES);
1037
1042
  let sibling;
1038
1043
  const ready = new Promise(
1039
- (resolve2) => {
1044
+ (resolve2, reject) => {
1040
1045
  const addresses = [];
1041
1046
  const warnings = [];
1042
1047
  const primaryHost = host === "localhost" ? "127.0.0.1" : host;
1043
- primary.listen(port, primaryHost, () => {
1048
+ let candidate = port;
1049
+ let attempt = 0;
1050
+ const bindFailed = (atPort, msg) => reject(
1051
+ new Error(`could not bind ${formatAddress(primaryHost, atPort)}: ${msg}`)
1052
+ );
1053
+ const onError = (e) => {
1054
+ if (e.code !== "EADDRINUSE") return bindFailed(candidate, e.message);
1055
+ if (++attempt >= maxAttempts) {
1056
+ reject(
1057
+ new Error(
1058
+ `could not bind ${formatAddress(primaryHost, port)}: ${maxAttempts} consecutive ports in use`
1059
+ )
1060
+ );
1061
+ return;
1062
+ }
1063
+ candidate++;
1064
+ listen();
1065
+ };
1066
+ const onListening = () => {
1067
+ primary.removeListener("error", onError);
1068
+ if (candidate !== port) {
1069
+ warnings.push(`port ${port} was busy; using ${candidate} instead`);
1070
+ }
1044
1071
  const addr = primary.address();
1045
- const resolvedPort = addr && typeof addr === "object" ? addr.port : port;
1072
+ const resolvedPort = addr && typeof addr === "object" ? addr.port : candidate;
1046
1073
  addresses.push(formatAddress(primaryHost, resolvedPort));
1047
1074
  if (!LOOPBACK.has(host)) {
1048
- resolve2({ addresses, warnings });
1075
+ resolve2({ addresses, port: resolvedPort, warnings });
1049
1076
  return;
1050
1077
  }
1051
1078
  const siblingHost = primaryHost === "::1" ? "127.0.0.1" : "::1";
1052
1079
  const s = createServer();
1053
1080
  attachSecondary(s);
1054
- const onError = (e) => {
1081
+ const onSiblingError = (se) => {
1055
1082
  s.close();
1056
1083
  warnings.push(
1057
- `could not also bind ${formatAddress(siblingHost, resolvedPort)} (${e.message}); clients using the ${siblingHost === "::1" ? "IPv6" : "IPv4"} form of "localhost" may not connect.`
1084
+ `could not also bind ${formatAddress(siblingHost, resolvedPort)} (${se.message}); clients using the ${siblingHost === "::1" ? "IPv6" : "IPv4"} form of "localhost" may not connect.`
1058
1085
  );
1059
- resolve2({ addresses, warnings });
1086
+ resolve2({ addresses, port: resolvedPort, warnings });
1060
1087
  };
1061
- s.once("error", onError);
1088
+ s.once("error", onSiblingError);
1062
1089
  s.listen(resolvedPort, siblingHost, () => {
1063
- s.off("error", onError);
1090
+ s.off("error", onSiblingError);
1064
1091
  sibling = s;
1065
1092
  addresses.push(formatAddress(siblingHost, resolvedPort));
1066
- resolve2({ addresses, warnings });
1093
+ resolve2({ addresses, port: resolvedPort, warnings });
1067
1094
  });
1068
- });
1095
+ };
1096
+ const listen = () => {
1097
+ try {
1098
+ primary.listen(candidate, primaryHost);
1099
+ } catch (e) {
1100
+ primary.removeListener("error", onError);
1101
+ primary.removeListener("listening", onListening);
1102
+ bindFailed(candidate, e.message);
1103
+ }
1104
+ };
1105
+ primary.on("error", onError);
1106
+ primary.once("listening", onListening);
1107
+ listen();
1069
1108
  }
1070
1109
  );
1071
1110
  return {