portless 0.15.2 → 0.15.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/README.md +7 -3
- package/dist/{chunk-T7CGCIRO.js → chunk-JSJUKQRJ.js} +34 -7
- package/dist/cli.js +452 -302
- package/dist/index.d.ts +13 -1
- package/dist/index.js +3 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -36,6 +36,8 @@ The proxy auto-starts when you run an app. A random port (4000-4999) is assigned
|
|
|
36
36
|
|
|
37
37
|
When auto-starting, portless reuses the configuration (port, TLS, TLDs) from the most recent proxy run, so a restart or reboot does not silently revert to defaults. Explicit env vars (`PORTLESS_PORT`, `PORTLESS_HTTPS`, etc.) always take priority.
|
|
38
38
|
|
|
39
|
+
Portless stores per-user state in `~/.portless`. When the proxy runs under sudo, it resolves this path from the invoking user's home so the proxy and unprivileged app processes share the same route registrations.
|
|
40
|
+
|
|
39
41
|
In non-interactive environments (no TTY, or `CI=1`), portless exits with a descriptive error instead of prompting, so task runners like turborepo and CI scripts fail early with a clear message.
|
|
40
42
|
|
|
41
43
|
## Configuration
|
|
@@ -241,6 +243,8 @@ flowchart TD
|
|
|
241
243
|
2. **Run apps**: `portless <name> <command>` assigns a free port and registers with the proxy
|
|
242
244
|
3. **Access via URL**: `https://<name>.localhost` routes through the proxy to your app
|
|
243
245
|
|
|
246
|
+
Outside LAN mode, the proxy and its HTTP redirect listener bind only to the IPv4 and IPv6 loopback addresses, `127.0.0.1` and `::1`. They do not accept connections through LAN, VPN, or other network interfaces.
|
|
247
|
+
|
|
244
248
|
## HTTP/2 + HTTPS
|
|
245
249
|
|
|
246
250
|
HTTPS with HTTP/2 is enabled by default. Browsers limit HTTP/1.1 to 6 connections per host, which bottlenecks dev servers that serve many unbundled files (Vite, Nuxt, etc.). HTTP/2 multiplexes all requests over a single connection.
|
|
@@ -258,7 +262,7 @@ portless proxy start --no-tls
|
|
|
258
262
|
portless trust
|
|
259
263
|
```
|
|
260
264
|
|
|
261
|
-
On Linux, `portless trust` supports Debian/Ubuntu, Arch, Fedora/RHEL/CentOS, and openSUSE (via `update-ca-certificates` or `update-ca-trust`). On Windows, it uses `certutil` to add the CA to the system trust store.
|
|
265
|
+
On Linux, `portless trust` supports Debian/Ubuntu, Arch, Fedora/RHEL/CentOS, and openSUSE (via `update-ca-certificates` or `update-ca-trust`). On Windows, it uses `certutil` to add the CA to the system trust store. On WSL, it updates both the Linux trust store and the Windows current-user Root store so Windows browsers trust portless HTTPS certificates.
|
|
262
266
|
|
|
263
267
|
## Start at OS startup
|
|
264
268
|
|
|
@@ -285,7 +289,7 @@ portless proxy start --lan --https
|
|
|
285
289
|
portless proxy start --lan --ip 192.168.1.42
|
|
286
290
|
```
|
|
287
291
|
|
|
288
|
-
`--lan`
|
|
292
|
+
`--lan` explicitly binds the proxy to the IPv4 and IPv6 unspecified addresses, `0.0.0.0` and `::`, and switches to mDNS discovery. This makes services available as `<name>.local` to devices on the same network. Portless auto-detects your LAN IP and follows Wi-Fi/IP changes automatically, but you can pin another address with `--ip <address>` or by exporting `PORTLESS_LAN_IP`. Set `PORTLESS_LAN=1` in your shell (0/1 boolean) to make LAN mode the default whenever the proxy starts.
|
|
289
293
|
|
|
290
294
|
Portless remembers LAN mode via `proxy.lan`, so if you stop a LAN proxy and start it again, it stays in LAN mode. All proxy settings (port, TLS, TLDs, LAN) are persisted and reused on auto-start unless overridden by explicit flags or env vars. Use `PORTLESS_LAN=0` for one start to switch back to `.localhost` mode. If a proxy is already running with different explicit LAN/TLS/TLD settings, portless warns and asks you to stop it first.
|
|
291
295
|
|
|
@@ -445,7 +449,7 @@ To remove portless data from your machine (proxy state under `~/.portless` and t
|
|
|
445
449
|
portless clean
|
|
446
450
|
```
|
|
447
451
|
|
|
448
|
-
macOS/Linux may prompt for `sudo`. Custom certificate paths passed with `--cert` and `--key` are not deleted.
|
|
452
|
+
macOS/Linux may prompt for `sudo`. Custom certificate paths passed with `--cert` and `--key` are not deleted. If trust-store removal fails, portless retains its CA certificate and key so a later `portless clean` can safely retry.
|
|
449
453
|
|
|
450
454
|
## Safari / DNS
|
|
451
455
|
|
|
@@ -1,6 +1,32 @@
|
|
|
1
1
|
// src/utils.ts
|
|
2
2
|
import * as fs from "fs";
|
|
3
3
|
import * as net from "net";
|
|
4
|
+
import * as os from "os";
|
|
5
|
+
import * as path from "path";
|
|
6
|
+
function readPasswdHome(username) {
|
|
7
|
+
try {
|
|
8
|
+
const passwd = fs.readFileSync("/etc/passwd", "utf-8");
|
|
9
|
+
for (const line of passwd.split("\n")) {
|
|
10
|
+
const fields = line.split(":");
|
|
11
|
+
if (fields[0] === username && fields[5]) return fields[5];
|
|
12
|
+
}
|
|
13
|
+
} catch {
|
|
14
|
+
}
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
function resolveUserHome(options = {}) {
|
|
18
|
+
const platform = options.platform ?? process.platform;
|
|
19
|
+
const env = options.env ?? process.env;
|
|
20
|
+
const homedir2 = options.homedir ?? os.homedir();
|
|
21
|
+
if (platform === "win32") return env.USERPROFILE || homedir2;
|
|
22
|
+
const sudoUser = env.SUDO_USER;
|
|
23
|
+
if (!sudoUser || sudoUser === "root") return homedir2;
|
|
24
|
+
const home = env.HOME;
|
|
25
|
+
if (home && home !== "/root" && home !== "/var/root") return home;
|
|
26
|
+
const passwdHome = (options.passwdHome ?? readPasswdHome)(sudoUser);
|
|
27
|
+
if (passwdHome) return passwdHome;
|
|
28
|
+
return platform === "darwin" ? path.posix.join("/Users", sudoUser) : path.posix.join("/home", sudoUser);
|
|
29
|
+
}
|
|
4
30
|
function loopbackLookup(_hostname, _options, callback) {
|
|
5
31
|
callback(null, [
|
|
6
32
|
{ address: "127.0.0.1", family: 4 },
|
|
@@ -653,9 +679,9 @@ function createHttpRedirectServer(httpsPort) {
|
|
|
653
679
|
// src/hosts.ts
|
|
654
680
|
import * as fs2 from "fs";
|
|
655
681
|
import * as dns from "dns";
|
|
656
|
-
import * as
|
|
682
|
+
import * as path2 from "path";
|
|
657
683
|
var isWindows = process.platform === "win32";
|
|
658
|
-
var HOSTS_PATH = isWindows ?
|
|
684
|
+
var HOSTS_PATH = isWindows ? path2.join(process.env.SystemRoot ?? "C:\\Windows", "System32", "drivers", "etc", "hosts") : "/etc/hosts";
|
|
659
685
|
var MARKER_START = "# portless-start";
|
|
660
686
|
var MARKER_END = "# portless-end";
|
|
661
687
|
function readHostsFile() {
|
|
@@ -736,7 +762,7 @@ function checkHostResolution(hostname) {
|
|
|
736
762
|
|
|
737
763
|
// src/routes.ts
|
|
738
764
|
import * as fs3 from "fs";
|
|
739
|
-
import * as
|
|
765
|
+
import * as path3 from "path";
|
|
740
766
|
var STALE_LOCK_THRESHOLD_MS = 1e4;
|
|
741
767
|
var LOCK_TIMEOUT_MS = 15e3;
|
|
742
768
|
var LOCK_RETRY_BASE_MS = 10;
|
|
@@ -768,10 +794,10 @@ var RouteStore = class _RouteStore {
|
|
|
768
794
|
onWarning;
|
|
769
795
|
constructor(dir, options) {
|
|
770
796
|
this.dir = dir;
|
|
771
|
-
this.routesPath =
|
|
772
|
-
this.lockPath =
|
|
773
|
-
this.pidPath =
|
|
774
|
-
this.portFilePath =
|
|
797
|
+
this.routesPath = path3.join(dir, "routes.json");
|
|
798
|
+
this.lockPath = path3.join(dir, "routes.lock");
|
|
799
|
+
this.pidPath = path3.join(dir, "proxy.pid");
|
|
800
|
+
this.portFilePath = path3.join(dir, "proxy.port");
|
|
775
801
|
this.onWarning = options?.onWarning;
|
|
776
802
|
}
|
|
777
803
|
ensureDir() {
|
|
@@ -1033,6 +1059,7 @@ var RouteStore = class _RouteStore {
|
|
|
1033
1059
|
};
|
|
1034
1060
|
|
|
1035
1061
|
export {
|
|
1062
|
+
resolveUserHome,
|
|
1036
1063
|
createLoopbackConnection,
|
|
1037
1064
|
fixOwnership,
|
|
1038
1065
|
isErrnoException,
|