portless 0.8.0 → 0.9.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/README.md +51 -51
- package/dist/{chunk-KKXL2CMI.js → chunk-5BR7NCNI.js} +66 -30
- package/dist/cli.js +381 -204
- package/dist/index.d.ts +6 -1
- package/dist/index.js +3 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,26 +9,29 @@ Replace port numbers with stable, named .localhost URLs for local development. F
|
|
|
9
9
|
|
|
10
10
|
## Install
|
|
11
11
|
|
|
12
|
+
**Global (recommended):**
|
|
13
|
+
|
|
12
14
|
```bash
|
|
13
15
|
npm install -g portless
|
|
14
16
|
```
|
|
15
17
|
|
|
16
|
-
|
|
18
|
+
**Or as a project dev dependency:**
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install -D portless
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
> portless is pre-1.0. When installed per-project, different contributors may run different versions. The state directory format may change between releases, which can require re-running `portless trust`.
|
|
17
25
|
|
|
18
26
|
## Run your app
|
|
19
27
|
|
|
20
28
|
```bash
|
|
21
|
-
# Enable HTTPS (one-time setup, auto-generates certs)
|
|
22
|
-
portless proxy start --https
|
|
23
|
-
|
|
24
29
|
portless myapp next dev
|
|
25
30
|
# -> https://myapp.localhost
|
|
26
|
-
|
|
27
|
-
# Without --https, runs on port 1355
|
|
28
|
-
portless myapp next dev
|
|
29
|
-
# -> http://myapp.localhost:1355
|
|
30
31
|
```
|
|
31
32
|
|
|
33
|
+
HTTPS with HTTP/2 is enabled by default. On first run, portless generates a local CA, trusts it, and binds port 443 (auto-elevates with sudo on macOS/Linux). Use `--no-tls` for plain HTTP.
|
|
34
|
+
|
|
32
35
|
The proxy auto-starts when you run an app. A random port (4000--4999) is assigned via the `PORT` environment variable. Most frameworks (Next.js, Express, Nuxt, etc.) respect this automatically. For frameworks that ignore `PORT` (Vite, Astro, React Router, Angular, Expo, React Native), portless auto-injects `--port` and `--host` flags.
|
|
33
36
|
|
|
34
37
|
## Use in package.json
|
|
@@ -47,45 +50,45 @@ Organize services with subdomains:
|
|
|
47
50
|
|
|
48
51
|
```bash
|
|
49
52
|
portless api.myapp pnpm start
|
|
50
|
-
# ->
|
|
53
|
+
# -> https://api.myapp.localhost
|
|
51
54
|
|
|
52
55
|
portless docs.myapp next dev
|
|
53
|
-
# ->
|
|
56
|
+
# -> https://docs.myapp.localhost
|
|
54
57
|
```
|
|
55
58
|
|
|
56
|
-
By default, only explicitly registered subdomains are routed (strict mode). Use `--wildcard` when starting the proxy to allow any subdomain of a registered route to fall back to that app (e.g. `tenant1.myapp.localhost
|
|
59
|
+
By default, only explicitly registered subdomains are routed (strict mode). Use `--wildcard` when starting the proxy to allow any subdomain of a registered route to fall back to that app (e.g. `tenant1.myapp.localhost` routes to the `myapp` app without extra registration).
|
|
57
60
|
|
|
58
61
|
## Git Worktrees
|
|
59
62
|
|
|
60
63
|
`portless run` automatically detects git worktrees. In a linked worktree, the branch name is prepended as a subdomain so each worktree gets its own URL without any config changes:
|
|
61
64
|
|
|
62
65
|
```bash
|
|
63
|
-
# Main worktree
|
|
64
|
-
portless run next dev # ->
|
|
66
|
+
# Main worktree (no prefix)
|
|
67
|
+
portless run next dev # -> https://myapp.localhost
|
|
65
68
|
|
|
66
69
|
# Linked worktree on branch "fix-ui"
|
|
67
|
-
portless run next dev # ->
|
|
70
|
+
portless run next dev # -> https://fix-ui.myapp.localhost
|
|
68
71
|
```
|
|
69
72
|
|
|
70
73
|
Use `--name` to override the inferred base name while keeping the worktree prefix:
|
|
71
74
|
|
|
72
75
|
```bash
|
|
73
|
-
portless run --name myapp next dev # ->
|
|
76
|
+
portless run --name myapp next dev # -> https://fix-ui.myapp.localhost
|
|
74
77
|
```
|
|
75
78
|
|
|
76
|
-
Put `portless run` in your `package.json` once and it works everywhere
|
|
79
|
+
Put `portless run` in your `package.json` once and it works everywhere. The main checkout uses the plain name, each worktree gets a unique subdomain. No collisions, no `--force`.
|
|
77
80
|
|
|
78
81
|
## Custom TLD
|
|
79
82
|
|
|
80
83
|
By default, portless uses `.localhost` which auto-resolves to `127.0.0.1` in most browsers. If you prefer a different TLD (e.g. `.test`), use `--tld`:
|
|
81
84
|
|
|
82
85
|
```bash
|
|
83
|
-
|
|
86
|
+
portless proxy start --tld test
|
|
84
87
|
portless myapp next dev
|
|
85
88
|
# -> https://myapp.test
|
|
86
89
|
```
|
|
87
90
|
|
|
88
|
-
The proxy auto-syncs `/etc/hosts` for custom TLDs
|
|
91
|
+
The proxy auto-syncs `/etc/hosts` for custom TLDs, so `.test` domains resolve correctly.
|
|
89
92
|
|
|
90
93
|
Recommended: `.test` (IANA-reserved, no collision risk). Avoid `.local` (conflicts with mDNS/Bonjour) and `.dev` (Google-owned, forces HTTPS via HSTS).
|
|
91
94
|
|
|
@@ -93,40 +96,35 @@ Recommended: `.test` (IANA-reserved, no collision risk). Avoid `.local` (conflic
|
|
|
93
96
|
|
|
94
97
|
```mermaid
|
|
95
98
|
flowchart TD
|
|
96
|
-
Browser["Browser<br>myapp.localhost
|
|
97
|
-
Proxy["portless proxy<br>(port
|
|
99
|
+
Browser["Browser<br>myapp.localhost"]
|
|
100
|
+
Proxy["portless proxy<br>(port 80 or 443)"]
|
|
98
101
|
App1[":4123<br>myapp"]
|
|
99
102
|
App2[":4567<br>api"]
|
|
100
103
|
|
|
101
|
-
Browser
|
|
104
|
+
Browser --> Proxy
|
|
102
105
|
Proxy --> App1
|
|
103
106
|
Proxy --> App2
|
|
104
107
|
```
|
|
105
108
|
|
|
106
|
-
1. **Start the proxy
|
|
107
|
-
2. **Run apps
|
|
108
|
-
3. **Access via URL
|
|
109
|
+
1. **Start the proxy**: auto-starts when you run an app, or start explicitly with `portless proxy start`
|
|
110
|
+
2. **Run apps**: `portless <name> <command>` assigns a free port and registers with the proxy
|
|
111
|
+
3. **Access via URL**: `https://<name>.localhost` routes through the proxy to your app
|
|
109
112
|
|
|
110
113
|
## HTTP/2 + HTTPS
|
|
111
114
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
```bash
|
|
115
|
-
# Start with HTTPS/2 -- generates certs and trusts them automatically
|
|
116
|
-
portless proxy start --https
|
|
117
|
-
|
|
118
|
-
# First run prompts for sudo once to add the CA to your system trust store.
|
|
119
|
-
# After that, no prompts. No browser warnings.
|
|
115
|
+
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.
|
|
120
116
|
|
|
121
|
-
|
|
122
|
-
export PORTLESS_HTTPS=1
|
|
123
|
-
portless proxy start # HTTPS by default now
|
|
117
|
+
On first run, portless generates a local CA and adds it to your system trust store. No browser warnings. No manual setup.
|
|
124
118
|
|
|
119
|
+
```bash
|
|
125
120
|
# Use your own certs (e.g., from mkcert)
|
|
126
121
|
portless proxy start --cert ./cert.pem --key ./key.pem
|
|
127
122
|
|
|
128
|
-
#
|
|
129
|
-
|
|
123
|
+
# Disable HTTPS (plain HTTP on port 80)
|
|
124
|
+
portless proxy start --no-tls
|
|
125
|
+
|
|
126
|
+
# If you skipped the trust prompt on first run, trust the CA later
|
|
127
|
+
portless trust
|
|
130
128
|
```
|
|
131
129
|
|
|
132
130
|
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.
|
|
@@ -135,7 +133,7 @@ On Linux, `portless trust` supports Debian/Ubuntu, Arch, Fedora/RHEL/CentOS, and
|
|
|
135
133
|
|
|
136
134
|
```bash
|
|
137
135
|
portless run [--name <name>] <cmd> [args...] # Infer name (or override with --name), run through proxy
|
|
138
|
-
portless <name> <cmd> [args...] # Run app at
|
|
136
|
+
portless <name> <cmd> [args...] # Run app at https://<name>.localhost
|
|
139
137
|
portless alias <name> <port> # Register a static route (e.g. for Docker)
|
|
140
138
|
portless alias <name> <port> --force # Overwrite an existing route
|
|
141
139
|
portless alias --remove <name> # Remove a static route
|
|
@@ -148,9 +146,9 @@ portless hosts clean # Remove portless entries from /etc/hosts
|
|
|
148
146
|
PORTLESS=0 pnpm dev # Bypasses proxy, uses default port
|
|
149
147
|
|
|
150
148
|
# Proxy control
|
|
151
|
-
portless proxy start # Start the proxy (port
|
|
152
|
-
portless proxy start --
|
|
153
|
-
portless proxy start -p
|
|
149
|
+
portless proxy start # Start the HTTPS proxy (port 443, daemon)
|
|
150
|
+
portless proxy start --no-tls # Start without HTTPS (port 80)
|
|
151
|
+
portless proxy start -p 1355 # Start on a custom port (no sudo)
|
|
154
152
|
portless proxy start --foreground # Start in foreground (for debugging)
|
|
155
153
|
portless proxy start --wildcard # Allow unregistered subdomains to fall back to parent
|
|
156
154
|
portless proxy stop # Stop the proxy
|
|
@@ -159,11 +157,11 @@ portless proxy stop # Stop the proxy
|
|
|
159
157
|
### Options
|
|
160
158
|
|
|
161
159
|
```
|
|
162
|
-
-p, --port <number> Port for the proxy (default:
|
|
163
|
-
--
|
|
164
|
-
--
|
|
165
|
-
--
|
|
166
|
-
--
|
|
160
|
+
-p, --port <number> Port for the proxy (default: 443, or 80 with --no-tls)
|
|
161
|
+
--no-tls Disable HTTPS (use plain HTTP on port 80)
|
|
162
|
+
--https Enable HTTPS (default, accepted for compatibility)
|
|
163
|
+
--cert <path> Use a custom TLS certificate
|
|
164
|
+
--key <path> Use a custom TLS private key
|
|
167
165
|
--foreground Run proxy in foreground instead of daemon
|
|
168
166
|
--tld <tld> Use a custom TLD instead of .localhost (e.g. test)
|
|
169
167
|
--wildcard Allow unregistered subdomains to fall back to parent route
|
|
@@ -178,7 +176,7 @@ portless proxy stop # Stop the proxy
|
|
|
178
176
|
# Configuration
|
|
179
177
|
PORTLESS_PORT=<number> Override the default proxy port
|
|
180
178
|
PORTLESS_APP_PORT=<number> Use a fixed port for the app (same as --app-port)
|
|
181
|
-
PORTLESS_HTTPS
|
|
179
|
+
PORTLESS_HTTPS HTTPS on by default; set to 0 to disable (same as --no-tls)
|
|
182
180
|
PORTLESS_TLD=<tld> Use a custom TLD (e.g. test; default: localhost)
|
|
183
181
|
PORTLESS_WILDCARD=1 Allow unregistered subdomains to fall back to parent route
|
|
184
182
|
PORTLESS_SYNC_HOSTS=1 Auto-sync /etc/hosts (auto-enabled for custom TLDs)
|
|
@@ -199,8 +197,8 @@ PORTLESS_URL Public URL (e.g. https://myapp.localhost)
|
|
|
199
197
|
If Safari can't find your `.localhost` URL:
|
|
200
198
|
|
|
201
199
|
```bash
|
|
202
|
-
|
|
203
|
-
|
|
200
|
+
portless hosts sync # Add current routes to /etc/hosts
|
|
201
|
+
portless hosts clean # Clean up later
|
|
204
202
|
```
|
|
205
203
|
|
|
206
204
|
Auto-syncs `/etc/hosts` for custom TLDs (e.g. `--tld test`). For `.localhost`, set `PORTLESS_SYNC_HOSTS=1` to enable. Disable with `PORTLESS_SYNC_HOSTS=0`.
|
|
@@ -215,7 +213,7 @@ If your frontend dev server (e.g. Vite, webpack) proxies API requests to another
|
|
|
215
213
|
server: {
|
|
216
214
|
proxy: {
|
|
217
215
|
"/api": {
|
|
218
|
-
target: "
|
|
216
|
+
target: "https://api.myapp.localhost",
|
|
219
217
|
changeOrigin: true,
|
|
220
218
|
ws: true,
|
|
221
219
|
},
|
|
@@ -229,12 +227,14 @@ server: {
|
|
|
229
227
|
devServer: {
|
|
230
228
|
proxy: [{
|
|
231
229
|
context: ["/api"],
|
|
232
|
-
target: "
|
|
230
|
+
target: "https://api.myapp.localhost",
|
|
233
231
|
changeOrigin: true,
|
|
234
232
|
}],
|
|
235
233
|
}
|
|
236
234
|
```
|
|
237
235
|
|
|
236
|
+
If your tooling doesn't trust the portless CA, point Node.js at it: `NODE_EXTRA_CA_CERTS=/tmp/portless/ca.pem` (or `~/.portless/ca.pem` when the proxy runs on a non-privileged port like 1355). Alternatively, use `--no-tls` for plain HTTP.
|
|
237
|
+
|
|
238
238
|
Portless detects this misconfiguration and responds with `508 Loop Detected` along with a message pointing to this fix.
|
|
239
239
|
|
|
240
240
|
## Development
|
|
@@ -286,6 +286,9 @@ function getRequestHost(req) {
|
|
|
286
286
|
if (typeof authority === "string" && authority) return authority;
|
|
287
287
|
return req.headers.host || "";
|
|
288
288
|
}
|
|
289
|
+
function isEncrypted(req) {
|
|
290
|
+
return !!req.socket.encrypted;
|
|
291
|
+
}
|
|
289
292
|
function buildForwardedHeaders(req, tls) {
|
|
290
293
|
const headers = {};
|
|
291
294
|
const remoteAddress = req.socket.remoteAddress || "127.0.0.1";
|
|
@@ -313,8 +316,8 @@ function createProxyServer(options) {
|
|
|
313
316
|
tls
|
|
314
317
|
} = options;
|
|
315
318
|
const tldSuffix = `.${tld}`;
|
|
316
|
-
const isTls = !!tls;
|
|
317
319
|
const handleRequest = (req, res) => {
|
|
320
|
+
const reqTls = isEncrypted(req);
|
|
318
321
|
res.setHeader(PORTLESS_HEADER, "1");
|
|
319
322
|
const routes = getRoutes();
|
|
320
323
|
const host = getRequestHost(req).split(":")[0];
|
|
@@ -335,7 +338,7 @@ function createProxyServer(options) {
|
|
|
335
338
|
"Loop Detected",
|
|
336
339
|
`<div class="content"><p class="desc">This request has passed through portless ${hops} times. This usually means a dev server (Vite, webpack, etc.) is proxying requests back through portless without rewriting the Host header.</p><div class="section"><p class="label">Fix: add changeOrigin to your proxy config</p><pre class="terminal">proxy: {
|
|
337
340
|
"/api": {
|
|
338
|
-
target: "http://<backend>${escapeHtml(tldSuffix)}:<port>",
|
|
341
|
+
target: "${reqTls ? "https" : "http"}://<backend>${escapeHtml(tldSuffix)}${reqTls ? "" : ":<port>"}",
|
|
339
342
|
changeOrigin: true,
|
|
340
343
|
},
|
|
341
344
|
}</pre></div></div>`
|
|
@@ -348,7 +351,7 @@ function createProxyServer(options) {
|
|
|
348
351
|
const safeHost = escapeHtml(host);
|
|
349
352
|
const strippedHost = host.endsWith(tldSuffix) ? host.slice(0, -tldSuffix.length) : host;
|
|
350
353
|
const safeSuggestion = escapeHtml(strippedHost);
|
|
351
|
-
const routesList = routes.length > 0 ? `<div class="section"><p class="label">Active apps</p><ul class="card">${routes.map((r) => `<li><a href="${escapeHtml(formatUrl(r.hostname, proxyPort,
|
|
354
|
+
const routesList = routes.length > 0 ? `<div class="section"><p class="label">Active apps</p><ul class="card">${routes.map((r) => `<li><a href="${escapeHtml(formatUrl(r.hostname, proxyPort, reqTls))}" class="card-link"><span class="name">${escapeHtml(r.hostname)}</span><span class="meta"><code class="port">127.0.0.1:${escapeHtml(String(r.port))}</code><span class="arrow">${ARROW_SVG}</span></span></a></li>`).join("")}</ul></div>` : '<p class="empty">No apps running.</p>';
|
|
352
355
|
res.writeHead(404, { "Content-Type": "text/html" });
|
|
353
356
|
res.end(
|
|
354
357
|
renderPage(
|
|
@@ -359,7 +362,7 @@ function createProxyServer(options) {
|
|
|
359
362
|
);
|
|
360
363
|
return;
|
|
361
364
|
}
|
|
362
|
-
const forwardedHeaders = buildForwardedHeaders(req,
|
|
365
|
+
const forwardedHeaders = buildForwardedHeaders(req, reqTls);
|
|
363
366
|
const proxyReqHeaders = { ...req.headers };
|
|
364
367
|
for (const [key, value] of Object.entries(forwardedHeaders)) {
|
|
365
368
|
proxyReqHeaders[key] = value;
|
|
@@ -380,7 +383,7 @@ function createProxyServer(options) {
|
|
|
380
383
|
},
|
|
381
384
|
(proxyRes) => {
|
|
382
385
|
const responseHeaders = { ...proxyRes.headers };
|
|
383
|
-
if (
|
|
386
|
+
if (reqTls) {
|
|
384
387
|
for (const h of HOP_BY_HOP_HEADERS) {
|
|
385
388
|
delete responseHeaders[h];
|
|
386
389
|
}
|
|
@@ -442,7 +445,7 @@ function createProxyServer(options) {
|
|
|
442
445
|
socket.destroy();
|
|
443
446
|
return;
|
|
444
447
|
}
|
|
445
|
-
const forwardedHeaders = buildForwardedHeaders(req,
|
|
448
|
+
const forwardedHeaders = buildForwardedHeaders(req, isEncrypted(req));
|
|
446
449
|
const proxyReqHeaders = { ...req.headers };
|
|
447
450
|
for (const [key, value] of Object.entries(forwardedHeaders)) {
|
|
448
451
|
proxyReqHeaders[key] = value;
|
|
@@ -513,8 +516,19 @@ function createProxyServer(options) {
|
|
|
513
516
|
h2Server.on("upgrade", (req, socket, head) => {
|
|
514
517
|
handleUpgrade(req, socket, head);
|
|
515
518
|
});
|
|
516
|
-
const plainServer = http.createServer(
|
|
517
|
-
|
|
519
|
+
const plainServer = http.createServer((req, res) => {
|
|
520
|
+
const host = getRequestHost(req).split(":")[0] || "localhost";
|
|
521
|
+
const location = `https://${host}${proxyPort === 443 ? "" : `:${proxyPort}`}${req.url || "/"}`;
|
|
522
|
+
res.writeHead(302, { Location: location, [PORTLESS_HEADER]: "1" });
|
|
523
|
+
res.end();
|
|
524
|
+
});
|
|
525
|
+
plainServer.on("upgrade", (req, socket) => {
|
|
526
|
+
const host = getRequestHost(req);
|
|
527
|
+
console.warn(
|
|
528
|
+
`[portless] Dropped plain-HTTP WebSocket upgrade for ${host}; use wss:// instead`
|
|
529
|
+
);
|
|
530
|
+
socket.destroy();
|
|
531
|
+
});
|
|
518
532
|
const wrapper = net.createServer((socket) => {
|
|
519
533
|
socket.on("error", () => {
|
|
520
534
|
socket.destroy();
|
|
@@ -545,6 +559,15 @@ function createProxyServer(options) {
|
|
|
545
559
|
httpServer.on("upgrade", handleUpgrade);
|
|
546
560
|
return httpServer;
|
|
547
561
|
}
|
|
562
|
+
function createHttpRedirectServer(httpsPort) {
|
|
563
|
+
return http.createServer((req, res) => {
|
|
564
|
+
const host = (req.headers.host || "localhost").split(":")[0];
|
|
565
|
+
const portSuffix = httpsPort === 443 ? "" : `:${httpsPort}`;
|
|
566
|
+
const location = `https://${host}${portSuffix}${req.url || "/"}`;
|
|
567
|
+
res.writeHead(302, { Location: location, [PORTLESS_HEADER]: "1" });
|
|
568
|
+
res.end();
|
|
569
|
+
});
|
|
570
|
+
}
|
|
548
571
|
|
|
549
572
|
// src/hosts.ts
|
|
550
573
|
import * as fs2 from "fs";
|
|
@@ -637,7 +660,7 @@ import * as path2 from "path";
|
|
|
637
660
|
import * as readline from "readline";
|
|
638
661
|
import { execSync, spawn } from "child_process";
|
|
639
662
|
var isWindows2 = process.platform === "win32";
|
|
640
|
-
var
|
|
663
|
+
var FALLBACK_PROXY_PORT = 1355;
|
|
641
664
|
var PRIVILEGED_PORT_THRESHOLD = 1024;
|
|
642
665
|
var SYSTEM_STATE_DIR = isWindows2 ? path2.join(os.tmpdir(), "portless") : "/tmp/portless";
|
|
643
666
|
var USER_STATE_DIR = path2.join(os.homedir(), ".portless");
|
|
@@ -656,13 +679,16 @@ var SIGNAL_CODES = {
|
|
|
656
679
|
SIGKILL: 9,
|
|
657
680
|
SIGTERM: 15
|
|
658
681
|
};
|
|
659
|
-
function
|
|
682
|
+
function getProtocolPort(tls) {
|
|
683
|
+
return tls ? 443 : 80;
|
|
684
|
+
}
|
|
685
|
+
function getDefaultPort(tls) {
|
|
660
686
|
const envPort = process.env.PORTLESS_PORT;
|
|
661
687
|
if (envPort) {
|
|
662
688
|
const port = parseInt(envPort, 10);
|
|
663
689
|
if (!isNaN(port) && port >= 1 && port <= 65535) return port;
|
|
664
690
|
}
|
|
665
|
-
return
|
|
691
|
+
return tls === void 0 ? FALLBACK_PROXY_PORT : getProtocolPort(tls);
|
|
666
692
|
}
|
|
667
693
|
function resolveStateDir(port) {
|
|
668
694
|
if (process.env.PORTLESS_STATE_DIR) return process.env.PORTLESS_STATE_DIR;
|
|
@@ -701,15 +727,15 @@ var DEFAULT_TLD = "localhost";
|
|
|
701
727
|
var RISKY_TLDS = /* @__PURE__ */ new Map([
|
|
702
728
|
["local", "conflicts with mDNS/Bonjour on macOS"],
|
|
703
729
|
["dev", "Google-owned; browsers force HTTPS via preloaded HSTS"],
|
|
704
|
-
["com", "public TLD
|
|
705
|
-
["org", "public TLD
|
|
706
|
-
["net", "public TLD
|
|
707
|
-
["io", "public TLD
|
|
708
|
-
["app", "public TLD
|
|
709
|
-
["edu", "public TLD
|
|
710
|
-
["gov", "public TLD
|
|
711
|
-
["mil", "public TLD
|
|
712
|
-
["int", "public TLD
|
|
730
|
+
["com", "public TLD; DNS requests will leak to the internet"],
|
|
731
|
+
["org", "public TLD; DNS requests will leak to the internet"],
|
|
732
|
+
["net", "public TLD; DNS requests will leak to the internet"],
|
|
733
|
+
["io", "public TLD; DNS requests will leak to the internet"],
|
|
734
|
+
["app", "public TLD; DNS requests will leak to the internet"],
|
|
735
|
+
["edu", "public TLD; DNS requests will leak to the internet"],
|
|
736
|
+
["gov", "public TLD; DNS requests will leak to the internet"],
|
|
737
|
+
["mil", "public TLD; DNS requests will leak to the internet"],
|
|
738
|
+
["int", "public TLD; DNS requests will leak to the internet"]
|
|
713
739
|
]);
|
|
714
740
|
function validateTld(tld) {
|
|
715
741
|
if (!tld) return "TLD cannot be empty";
|
|
@@ -745,9 +771,9 @@ function getDefaultTld() {
|
|
|
745
771
|
if (err) throw new Error(`PORTLESS_TLD: ${err}`);
|
|
746
772
|
return val;
|
|
747
773
|
}
|
|
748
|
-
function
|
|
774
|
+
function isHttpsEnvDisabled() {
|
|
749
775
|
const val = process.env.PORTLESS_HTTPS;
|
|
750
|
-
return val === "
|
|
776
|
+
return val === "0" || val === "false";
|
|
751
777
|
}
|
|
752
778
|
function isWildcardEnvEnabled() {
|
|
753
779
|
const val = process.env.PORTLESS_WILDCARD;
|
|
@@ -777,8 +803,8 @@ async function discoverState() {
|
|
|
777
803
|
return { dir: SYSTEM_STATE_DIR, port: systemPort, tls, tld };
|
|
778
804
|
}
|
|
779
805
|
}
|
|
780
|
-
const
|
|
781
|
-
const probePorts = /* @__PURE__ */ new Set([
|
|
806
|
+
const configuredPort = getDefaultPort();
|
|
807
|
+
const probePorts = /* @__PURE__ */ new Set([443, 80, FALLBACK_PROXY_PORT, configuredPort]);
|
|
782
808
|
for (const port of probePorts) {
|
|
783
809
|
if (await isProxyRunning(port)) {
|
|
784
810
|
const dir = resolveStateDir(port);
|
|
@@ -787,7 +813,12 @@ async function discoverState() {
|
|
|
787
813
|
return { dir, port, tls, tld };
|
|
788
814
|
}
|
|
789
815
|
}
|
|
790
|
-
return {
|
|
816
|
+
return {
|
|
817
|
+
dir: resolveStateDir(configuredPort),
|
|
818
|
+
port: configuredPort,
|
|
819
|
+
tls: false,
|
|
820
|
+
tld: getDefaultTld()
|
|
821
|
+
};
|
|
791
822
|
}
|
|
792
823
|
async function findFreePort(minPort = MIN_APP_PORT, maxPort = MAX_APP_PORT) {
|
|
793
824
|
if (minPort > maxPort) {
|
|
@@ -1093,7 +1124,8 @@ var RouteStore = class _RouteStore {
|
|
|
1093
1124
|
getRoutesPath() {
|
|
1094
1125
|
return this.routesPath;
|
|
1095
1126
|
}
|
|
1096
|
-
//
|
|
1127
|
+
// Locking
|
|
1128
|
+
// ---------------------------------------------------------------------------
|
|
1097
1129
|
static sleepBuffer = new Int32Array(new SharedArrayBuffer(4));
|
|
1098
1130
|
syncSleep(ms) {
|
|
1099
1131
|
Atomics.wait(_RouteStore.sleepBuffer, 0, 0, ms);
|
|
@@ -1128,7 +1160,8 @@ var RouteStore = class _RouteStore {
|
|
|
1128
1160
|
} catch {
|
|
1129
1161
|
}
|
|
1130
1162
|
}
|
|
1131
|
-
//
|
|
1163
|
+
// Route I/O
|
|
1164
|
+
// ---------------------------------------------------------------------------
|
|
1132
1165
|
isProcessAlive(pid) {
|
|
1133
1166
|
try {
|
|
1134
1167
|
process.kill(pid, 0);
|
|
@@ -1219,6 +1252,7 @@ export {
|
|
|
1219
1252
|
parseHostname,
|
|
1220
1253
|
PORTLESS_HEADER,
|
|
1221
1254
|
createProxyServer,
|
|
1255
|
+
createHttpRedirectServer,
|
|
1222
1256
|
extractManagedBlock,
|
|
1223
1257
|
removeBlock,
|
|
1224
1258
|
buildBlock,
|
|
@@ -1227,18 +1261,20 @@ export {
|
|
|
1227
1261
|
getManagedHostnames,
|
|
1228
1262
|
checkHostResolution,
|
|
1229
1263
|
isWindows2 as isWindows,
|
|
1264
|
+
FALLBACK_PROXY_PORT,
|
|
1230
1265
|
PRIVILEGED_PORT_THRESHOLD,
|
|
1266
|
+
WAIT_FOR_PROXY_MAX_ATTEMPTS,
|
|
1267
|
+
WAIT_FOR_PROXY_INTERVAL_MS,
|
|
1268
|
+
getProtocolPort,
|
|
1231
1269
|
getDefaultPort,
|
|
1232
1270
|
resolveStateDir,
|
|
1233
|
-
readTlsMarker,
|
|
1234
1271
|
writeTlsMarker,
|
|
1235
1272
|
DEFAULT_TLD,
|
|
1236
1273
|
RISKY_TLDS,
|
|
1237
1274
|
validateTld,
|
|
1238
|
-
readTldFromDir,
|
|
1239
1275
|
writeTldFile,
|
|
1240
1276
|
getDefaultTld,
|
|
1241
|
-
|
|
1277
|
+
isHttpsEnvDisabled,
|
|
1242
1278
|
isWildcardEnvEnabled,
|
|
1243
1279
|
discoverState,
|
|
1244
1280
|
findFreePort,
|