shiplocal 0.1.3 → 0.1.4

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
@@ -4153,6 +4153,7 @@ import { WebSocket } from "ws";
4153
4153
 
4154
4154
  // ../tunnel-client/dist/local-proxy.js
4155
4155
  import http from "node:http";
4156
+ var LOOPBACK_HOSTS = ["127.0.0.1", "::1"];
4156
4157
  var HOP_BY_HOP_HEADERS = /* @__PURE__ */ new Set([
4157
4158
  "connection",
4158
4159
  "keep-alive",
@@ -4168,6 +4169,9 @@ var STRIP_RESPONSE_HEADERS = /* @__PURE__ */ new Set([
4168
4169
  "content-encoding",
4169
4170
  "content-length"
4170
4171
  ]);
4172
+ function isConnectionRefused(err) {
4173
+ return err instanceof Error && "code" in err && err.code === "ECONNREFUSED";
4174
+ }
4171
4175
  function sanitizeRequestHeaders(headers, localPort) {
4172
4176
  const result = {};
4173
4177
  for (const [key, value] of Object.entries(headers)) {
@@ -4192,12 +4196,10 @@ function sanitizeResponseHeaders(headers) {
4192
4196
  }
4193
4197
  return result;
4194
4198
  }
4195
- async function forwardToLocal(localPort, message) {
4196
- const body = decodeBody(message.body);
4197
- const pathWithQuery = message.query ? `${message.path}?${message.query}` : message.path;
4199
+ function forwardToHost(hostname, localPort, message, body, pathWithQuery) {
4198
4200
  return new Promise((resolve, reject) => {
4199
4201
  const req = http.request({
4200
- hostname: "127.0.0.1",
4202
+ hostname,
4201
4203
  port: localPort,
4202
4204
  method: message.method,
4203
4205
  path: pathWithQuery,
@@ -4234,6 +4236,23 @@ async function forwardToLocal(localPort, message) {
4234
4236
  req.end();
4235
4237
  });
4236
4238
  }
4239
+ async function forwardToLocal(localPort, message) {
4240
+ const body = decodeBody(message.body);
4241
+ const pathWithQuery = message.query ? `${message.path}?${message.query}` : message.path;
4242
+ let lastError;
4243
+ for (const hostname of LOOPBACK_HOSTS) {
4244
+ try {
4245
+ return await forwardToHost(hostname, localPort, message, body, pathWithQuery);
4246
+ } catch (err) {
4247
+ if (isConnectionRefused(err)) {
4248
+ lastError = err;
4249
+ continue;
4250
+ }
4251
+ throw err;
4252
+ }
4253
+ }
4254
+ throw lastError ?? new Error("Local server unreachable");
4255
+ }
4237
4256
 
4238
4257
  // ../tunnel-client/dist/client.js
4239
4258
  function toWebSocketUrl(serverUrl) {
@@ -4247,9 +4266,11 @@ function toWebSocketUrl(serverUrl) {
4247
4266
  function formatLocalProxyError(err, localPort) {
4248
4267
  if (err instanceof Error && "code" in err && err.code === "ECONNREFUSED") {
4249
4268
  return [
4250
- `Nothing is running on http://127.0.0.1:${String(localPort)}.`,
4269
+ `Nothing is listening on port ${String(localPort)} (tried 127.0.0.1 and ::1).`,
4251
4270
  "",
4252
4271
  "Start your local server on that port, then refresh this page.",
4272
+ "If your browser works on localhost but the tunnel does not, your dev server may only",
4273
+ "listen on IPv6 \u2014 bind to 0.0.0.0 or 127.0.0.1 (e.g. next dev -H 0.0.0.0).",
4253
4274
  `If your app uses a different port, restart the CLI with that port (e.g. shiplocal ${String(localPort)}).`
4254
4275
  ].join("\n");
4255
4276
  }
@@ -4465,7 +4486,7 @@ async function resolveToken() {
4465
4486
  }
4466
4487
 
4467
4488
  // src/api.ts
4468
- function isConnectionRefused(err) {
4489
+ function isConnectionRefused2(err) {
4469
4490
  if (!(err instanceof Error)) return false;
4470
4491
  const cause = err.cause;
4471
4492
  if (cause instanceof Error && "code" in cause && cause.code === "ECONNREFUSED") {
@@ -4477,7 +4498,7 @@ function isConnectionRefused(err) {
4477
4498
  return err.message.includes("ECONNREFUSED") || err.message.includes("fetch failed");
4478
4499
  }
4479
4500
  function formatServerConnectionError(apiUrl, err) {
4480
- if (isConnectionRefused(err)) {
4501
+ if (isConnectionRefused2(err)) {
4481
4502
  return [
4482
4503
  `Cannot reach ShipLocal server at ${apiUrl}.`,
4483
4504
  "",
@@ -4508,9 +4529,10 @@ async function postJson(path, body, apiUrl) {
4508
4529
 
4509
4530
  // src/local-port.ts
4510
4531
  import net from "node:net";
4511
- function isLocalPortOpen(port, timeoutMs = 2e3) {
4532
+ var LOOPBACK_HOSTS2 = ["127.0.0.1", "::1"];
4533
+ function canConnect(host, port, timeoutMs) {
4512
4534
  return new Promise((resolve) => {
4513
- const socket = net.connect({ port, host: "127.0.0.1" });
4535
+ const socket = net.connect({ port, host });
4514
4536
  const finish = (open) => {
4515
4537
  socket.removeAllListeners();
4516
4538
  socket.destroy();
@@ -4528,10 +4550,18 @@ function isLocalPortOpen(port, timeoutMs = 2e3) {
4528
4550
  });
4529
4551
  });
4530
4552
  }
4553
+ async function isLocalPortOpen(port, timeoutMs = 2e3) {
4554
+ for (const host of LOOPBACK_HOSTS2) {
4555
+ if (await canConnect(host, port, timeoutMs)) {
4556
+ return true;
4557
+ }
4558
+ }
4559
+ return false;
4560
+ }
4531
4561
 
4532
4562
  // src/index.ts
4533
4563
  var program = new Command();
4534
- program.name("shiplocal").description("Share localhost with clients in seconds").version("0.1.3");
4564
+ program.name("shiplocal").description("Share localhost with clients in seconds").version("0.1.4");
4535
4565
  program.command("login").description("Authenticate with ShipLocal Cloud").action(async () => {
4536
4566
  const rl = createInterface({ input, output });
4537
4567
  const apiUrl = await resolveApiUrlAsync();