lunel-cli 0.1.35 → 0.1.36

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.
Files changed (2) hide show
  1. package/dist/index.js +72 -31
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -51,6 +51,7 @@ const PROXY_WS_CONNECT_RETRY_ATTEMPTS = 1;
51
51
  const PROXY_WS_RETRY_JITTER_MIN_MS = 200;
52
52
  const PROXY_WS_RETRY_JITTER_MAX_MS = 500;
53
53
  const PROXY_TUNNEL_LINGER_MS = 1_200;
54
+ const LOOPBACK_HOSTS = ["127.0.0.1", "::1"];
54
55
  let portSyncTimer = null;
55
56
  let portScanInFlight = false;
56
57
  let lastDiscoveredPorts = [];
@@ -1690,20 +1691,36 @@ async function scanDevPorts() {
1690
1691
  const openPorts = [];
1691
1692
  const checks = SCAN_PORTS.map((port) => {
1692
1693
  return new Promise((resolve) => {
1693
- const socket = createConnection({ port, host: "127.0.0.1" });
1694
- socket.setTimeout(200);
1695
- socket.on("connect", () => {
1696
- openPorts.push(port);
1697
- socket.destroy();
1698
- resolve();
1699
- });
1700
- socket.on("timeout", () => {
1701
- socket.destroy();
1702
- resolve();
1703
- });
1704
- socket.on("error", () => {
1705
- resolve();
1706
- });
1694
+ let finished = false;
1695
+ let pending = LOOPBACK_HOSTS.length;
1696
+ for (const host of LOOPBACK_HOSTS) {
1697
+ const socket = createConnection({ port, host });
1698
+ socket.setTimeout(200);
1699
+ socket.on("connect", () => {
1700
+ if (finished)
1701
+ return;
1702
+ finished = true;
1703
+ openPorts.push(port);
1704
+ socket.destroy();
1705
+ resolve();
1706
+ });
1707
+ const onDone = () => {
1708
+ if (finished)
1709
+ return;
1710
+ pending -= 1;
1711
+ if (pending <= 0) {
1712
+ finished = true;
1713
+ resolve();
1714
+ }
1715
+ };
1716
+ socket.on("timeout", () => {
1717
+ socket.destroy();
1718
+ onDone();
1719
+ });
1720
+ socket.on("error", () => {
1721
+ onDone();
1722
+ });
1723
+ }
1707
1724
  });
1708
1725
  });
1709
1726
  await Promise.all(checks);
@@ -1765,23 +1782,47 @@ async function handleProxyConnect(payload) {
1765
1782
  if (getRemainingSetupMs() <= 0) {
1766
1783
  throw Object.assign(new Error("Tunnel setup timeout before start"), { code: "ETIMEOUT" });
1767
1784
  }
1768
- // 1. Open TCP connection to the local service
1769
- const tcpSocket = createConnection({ port, host: "127.0.0.1" });
1770
- const tcpConnectTimeoutMs = Math.min(CLI_LOCAL_TCP_CONNECT_TIMEOUT_MS, Math.max(250, getRemainingSetupMs()));
1771
- await new Promise((resolve, reject) => {
1772
- const timeout = setTimeout(() => {
1773
- tcpSocket.destroy();
1774
- reject(Object.assign(new Error(`TCP connect timeout to localhost:${port}`), { code: "ETIMEOUT" }));
1775
- }, tcpConnectTimeoutMs);
1776
- tcpSocket.on("connect", () => {
1777
- clearTimeout(timeout);
1778
- resolve();
1779
- });
1780
- tcpSocket.on("error", (err) => {
1781
- clearTimeout(timeout);
1782
- reject(Object.assign(new Error(`TCP connect failed: ${err.message}`), { code: "ECONNREFUSED" }));
1783
- });
1784
- });
1785
+ // 1. Open TCP connection to the local service (dual-stack localhost fallback)
1786
+ let tcpSocket = null;
1787
+ let tcpConnectError = null;
1788
+ for (const host of LOOPBACK_HOSTS) {
1789
+ const remainingMs = getRemainingSetupMs();
1790
+ if (remainingMs <= 0) {
1791
+ throw Object.assign(new Error("Tunnel setup timeout before local TCP connect"), { code: "ETIMEOUT" });
1792
+ }
1793
+ const tcpConnectTimeoutMs = Math.min(CLI_LOCAL_TCP_CONNECT_TIMEOUT_MS, Math.max(250, remainingMs));
1794
+ const candidate = createConnection({ port, host });
1795
+ try {
1796
+ await new Promise((resolve, reject) => {
1797
+ const timeout = setTimeout(() => {
1798
+ candidate.destroy();
1799
+ reject(Object.assign(new Error(`TCP connect timeout to ${host}:${port}`), { code: "ETIMEOUT" }));
1800
+ }, tcpConnectTimeoutMs);
1801
+ candidate.on("connect", () => {
1802
+ clearTimeout(timeout);
1803
+ resolve();
1804
+ });
1805
+ candidate.on("error", (err) => {
1806
+ clearTimeout(timeout);
1807
+ reject(Object.assign(new Error(`TCP connect failed to ${host}:${port}: ${err.message}`), { code: "ECONNREFUSED" }));
1808
+ });
1809
+ });
1810
+ tcpSocket = candidate;
1811
+ break;
1812
+ }
1813
+ catch (error) {
1814
+ tcpConnectError = error;
1815
+ try {
1816
+ candidate.destroy();
1817
+ }
1818
+ catch {
1819
+ // ignore
1820
+ }
1821
+ }
1822
+ }
1823
+ if (!tcpSocket) {
1824
+ throw tcpConnectError || Object.assign(new Error(`TCP connect failed to localhost:${port}`), { code: "ECONNREFUSED" });
1825
+ }
1785
1826
  // 2. Open proxy WebSocket to gateway
1786
1827
  const wsBase = activeGatewayUrl.replace(/^http/, "ws");
1787
1828
  const authQuery = currentSessionPassword
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lunel-cli",
3
- "version": "0.1.35",
3
+ "version": "0.1.36",
4
4
  "author": [
5
5
  {
6
6
  "name": "Soham Bharambe",