portless 0.4.0 → 0.4.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/cli.js +34 -3
- package/package.json +11 -30
- package/README.md +0 -160
package/dist/cli.js
CHANGED
|
@@ -599,6 +599,28 @@ function spawnCommand(commandArgs, options) {
|
|
|
599
599
|
process.exit(code ?? 1);
|
|
600
600
|
});
|
|
601
601
|
}
|
|
602
|
+
var FRAMEWORKS_NEEDING_PORT = {
|
|
603
|
+
vite: { strictPort: true },
|
|
604
|
+
"react-router": { strictPort: true },
|
|
605
|
+
astro: { strictPort: false },
|
|
606
|
+
ng: { strictPort: false }
|
|
607
|
+
};
|
|
608
|
+
function injectFrameworkFlags(commandArgs, port) {
|
|
609
|
+
const cmd = commandArgs[0];
|
|
610
|
+
if (!cmd) return;
|
|
611
|
+
const basename2 = path2.basename(cmd);
|
|
612
|
+
const framework = FRAMEWORKS_NEEDING_PORT[basename2];
|
|
613
|
+
if (!framework) return;
|
|
614
|
+
if (!commandArgs.includes("--port")) {
|
|
615
|
+
commandArgs.push("--port", port.toString());
|
|
616
|
+
if (framework.strictPort) {
|
|
617
|
+
commandArgs.push("--strictPort");
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
if (!commandArgs.includes("--host")) {
|
|
621
|
+
commandArgs.push("--host", "127.0.0.1");
|
|
622
|
+
}
|
|
623
|
+
}
|
|
602
624
|
function prompt(question) {
|
|
603
625
|
const rl = readline.createInterface({
|
|
604
626
|
input: process.stdin,
|
|
@@ -891,10 +913,16 @@ portless
|
|
|
891
913
|
console.log(chalk.cyan.bold(`
|
|
892
914
|
-> ${finalUrl}
|
|
893
915
|
`));
|
|
894
|
-
|
|
916
|
+
injectFrameworkFlags(commandArgs, port);
|
|
917
|
+
console.log(chalk.gray(`Running: PORT=${port} HOST=127.0.0.1 ${commandArgs.join(" ")}
|
|
895
918
|
`));
|
|
896
919
|
spawnCommand(commandArgs, {
|
|
897
|
-
env: {
|
|
920
|
+
env: {
|
|
921
|
+
...process.env,
|
|
922
|
+
PORT: port.toString(),
|
|
923
|
+
HOST: "127.0.0.1",
|
|
924
|
+
__VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS: ".localhost"
|
|
925
|
+
},
|
|
898
926
|
onCleanup: () => {
|
|
899
927
|
try {
|
|
900
928
|
store.removeRoute(hostname);
|
|
@@ -942,6 +970,7 @@ ${chalk.bold("Examples:")}
|
|
|
942
970
|
portless proxy start # Start proxy on port 1355
|
|
943
971
|
portless proxy start --https # Start with HTTPS/2 (faster page loads)
|
|
944
972
|
portless myapp next dev # -> http://myapp.localhost:1355
|
|
973
|
+
portless myapp vite dev # -> http://myapp.localhost:1355
|
|
945
974
|
portless api.myapp pnpm start # -> http://api.myapp.localhost:1355
|
|
946
975
|
|
|
947
976
|
${chalk.bold("In package.json:")}
|
|
@@ -956,6 +985,8 @@ ${chalk.bold("How it works:")}
|
|
|
956
985
|
2. Run your apps - they auto-start the proxy and register automatically
|
|
957
986
|
3. Access via http://<name>.localhost:1355
|
|
958
987
|
4. .localhost domains auto-resolve to 127.0.0.1
|
|
988
|
+
5. Frameworks that ignore PORT (Vite, Astro, React Router, Angular) get
|
|
989
|
+
--port and --host flags injected automatically
|
|
959
990
|
|
|
960
991
|
${chalk.bold("HTTP/2 + HTTPS:")}
|
|
961
992
|
Use --https for HTTP/2 multiplexing (faster dev server page loads).
|
|
@@ -984,7 +1015,7 @@ ${chalk.bold("Skip portless:")}
|
|
|
984
1015
|
process.exit(0);
|
|
985
1016
|
}
|
|
986
1017
|
if (args[0] === "--version" || args[0] === "-v") {
|
|
987
|
-
console.log("0.4.
|
|
1018
|
+
console.log("0.4.1");
|
|
988
1019
|
process.exit(0);
|
|
989
1020
|
}
|
|
990
1021
|
if (args[0] === "trust") {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "portless",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Replace port numbers with stable, named .localhost URLs. For humans and agents.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -17,7 +17,6 @@
|
|
|
17
17
|
"files": [
|
|
18
18
|
"dist"
|
|
19
19
|
],
|
|
20
|
-
"packageManager": "pnpm@9.15.4",
|
|
21
20
|
"engines": {
|
|
22
21
|
"node": ">=20"
|
|
23
22
|
},
|
|
@@ -25,21 +24,6 @@
|
|
|
25
24
|
"darwin",
|
|
26
25
|
"linux"
|
|
27
26
|
],
|
|
28
|
-
"scripts": {
|
|
29
|
-
"build": "tsup",
|
|
30
|
-
"dev": "tsup --watch",
|
|
31
|
-
"format": "prettier --write .",
|
|
32
|
-
"format:check": "prettier --check .",
|
|
33
|
-
"lint": "eslint src/",
|
|
34
|
-
"lint:fix": "eslint src/ --fix",
|
|
35
|
-
"prepublishOnly": "pnpm build",
|
|
36
|
-
"pretest": "pnpm build",
|
|
37
|
-
"test": "vitest run",
|
|
38
|
-
"test:coverage": "vitest run --coverage",
|
|
39
|
-
"test:watch": "vitest",
|
|
40
|
-
"typecheck": "tsc --noEmit",
|
|
41
|
-
"prepare": "husky"
|
|
42
|
-
},
|
|
43
27
|
"keywords": [
|
|
44
28
|
"local",
|
|
45
29
|
"development",
|
|
@@ -60,24 +44,21 @@
|
|
|
60
44
|
"chalk": "^5.3.0"
|
|
61
45
|
},
|
|
62
46
|
"devDependencies": {
|
|
63
|
-
"@eslint/js": "^9.39.2",
|
|
64
47
|
"@types/node": "^20.11.0",
|
|
65
48
|
"@vitest/coverage-v8": "^4.0.18",
|
|
66
49
|
"eslint": "^9.39.2",
|
|
67
|
-
"eslint-config-prettier": "^10.1.8",
|
|
68
|
-
"husky": "^9.1.7",
|
|
69
|
-
"lint-staged": "^16.2.7",
|
|
70
|
-
"prettier": "^3.8.1",
|
|
71
50
|
"tsup": "^8.0.1",
|
|
72
51
|
"typescript": "^5.3.3",
|
|
73
|
-
"typescript-eslint": "^8.55.0",
|
|
74
52
|
"vitest": "^4.0.18"
|
|
75
53
|
},
|
|
76
|
-
"
|
|
77
|
-
"
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
"
|
|
54
|
+
"scripts": {
|
|
55
|
+
"build": "tsup",
|
|
56
|
+
"dev": "tsup --watch",
|
|
57
|
+
"lint": "eslint src/",
|
|
58
|
+
"lint:fix": "eslint src/ --fix",
|
|
59
|
+
"test": "vitest run",
|
|
60
|
+
"test:coverage": "vitest run --coverage",
|
|
61
|
+
"test:watch": "vitest",
|
|
62
|
+
"typecheck": "tsc --noEmit"
|
|
82
63
|
}
|
|
83
|
-
}
|
|
64
|
+
}
|
package/README.md
DELETED
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
# portless
|
|
2
|
-
|
|
3
|
-
Replace port numbers with stable, named .localhost URLs. For humans and agents.
|
|
4
|
-
|
|
5
|
-
```diff
|
|
6
|
-
- "dev": "next dev" # http://localhost:3000
|
|
7
|
-
+ "dev": "portless myapp next dev" # http://myapp.localhost:1355
|
|
8
|
-
```
|
|
9
|
-
|
|
10
|
-
## Quick Start
|
|
11
|
-
|
|
12
|
-
```bash
|
|
13
|
-
# Install
|
|
14
|
-
npm install -g portless
|
|
15
|
-
|
|
16
|
-
# Start the proxy (once, no sudo needed)
|
|
17
|
-
portless proxy start
|
|
18
|
-
|
|
19
|
-
# Run your app (auto-starts the proxy if needed)
|
|
20
|
-
portless myapp next dev
|
|
21
|
-
# -> http://myapp.localhost:1355
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
> The proxy auto-starts when you run an app. You can also start it explicitly with `portless proxy start`.
|
|
25
|
-
|
|
26
|
-
## Why
|
|
27
|
-
|
|
28
|
-
Local dev with port numbers is fragile:
|
|
29
|
-
|
|
30
|
-
- **Port conflicts** -- two projects default to the same port and you get `EADDRINUSE`
|
|
31
|
-
- **Memorizing ports** -- was the API on 3001 or 8080?
|
|
32
|
-
- **Refreshing shows the wrong app** -- stop one server, start another on the same port, and your open tab now shows something completely different
|
|
33
|
-
- **Monorepo multiplier** -- every problem above scales with each service in the repo
|
|
34
|
-
- **Agents test the wrong port** -- AI coding agents guess or hardcode the wrong port, especially in monorepos
|
|
35
|
-
- **Cookie and storage clashes** -- cookies set on `localhost` bleed across apps on different ports; localStorage is lost when ports shift
|
|
36
|
-
- **Hardcoded ports in config** -- CORS allowlists, OAuth redirect URIs, and `.env` files all break when ports change
|
|
37
|
-
- **Sharing URLs with teammates** -- "what port is that on?" becomes a Slack question
|
|
38
|
-
- **Browser history is useless** -- your history for `localhost:3000` is a jumble of unrelated projects
|
|
39
|
-
|
|
40
|
-
Portless fixes all of this by giving each dev server a stable, named `.localhost` URL that both humans and agents can rely on.
|
|
41
|
-
|
|
42
|
-
## Usage
|
|
43
|
-
|
|
44
|
-
```bash
|
|
45
|
-
# Basic
|
|
46
|
-
portless myapp next dev
|
|
47
|
-
# -> http://myapp.localhost:1355
|
|
48
|
-
|
|
49
|
-
# Subdomains
|
|
50
|
-
portless api.myapp pnpm start
|
|
51
|
-
# -> http://api.myapp.localhost:1355
|
|
52
|
-
|
|
53
|
-
portless docs.myapp next dev
|
|
54
|
-
# -> http://docs.myapp.localhost:1355
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
### In package.json
|
|
58
|
-
|
|
59
|
-
```json
|
|
60
|
-
{
|
|
61
|
-
"scripts": {
|
|
62
|
-
"dev": "portless myapp next dev"
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
The proxy auto-starts when you run an app. Or start it explicitly: `portless proxy start`.
|
|
68
|
-
|
|
69
|
-
## How It Works
|
|
70
|
-
|
|
71
|
-
```mermaid
|
|
72
|
-
flowchart TD
|
|
73
|
-
Browser["Browser\nmyapp.localhost:1355"]
|
|
74
|
-
Proxy["portless proxy\n(port 1355)"]
|
|
75
|
-
App1[":4123\nmyapp"]
|
|
76
|
-
App2[":4567\napi"]
|
|
77
|
-
|
|
78
|
-
Browser -->|port 1355| Proxy
|
|
79
|
-
Proxy --> App1
|
|
80
|
-
Proxy --> App2
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
1. **Start the proxy** -- auto-starts when you run an app, or start explicitly with `portless proxy start`
|
|
84
|
-
2. **Run apps** -- `portless <name> <command>` assigns a free port and registers with the proxy
|
|
85
|
-
3. **Access via URL** -- `http://<name>.localhost:1355` routes through the proxy to your app
|
|
86
|
-
|
|
87
|
-
Apps are assigned a random port (4000-4999) via the `PORT` environment variable. Most frameworks (Next.js, Vite, etc.) respect this automatically.
|
|
88
|
-
|
|
89
|
-
## HTTP/2 + HTTPS
|
|
90
|
-
|
|
91
|
-
Enable HTTP/2 for faster dev server page loads. 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.
|
|
92
|
-
|
|
93
|
-
```bash
|
|
94
|
-
# Start with HTTPS/2 -- generates certs and trusts them automatically
|
|
95
|
-
portless proxy start --https
|
|
96
|
-
|
|
97
|
-
# First run prompts for sudo once to add the CA to your system trust store.
|
|
98
|
-
# After that, no prompts. No browser warnings.
|
|
99
|
-
|
|
100
|
-
# Make it permanent (add to .bashrc / .zshrc)
|
|
101
|
-
export PORTLESS_HTTPS=1
|
|
102
|
-
portless proxy start # HTTPS by default now
|
|
103
|
-
|
|
104
|
-
# Use your own certs (e.g., from mkcert)
|
|
105
|
-
portless proxy start --cert ./cert.pem --key ./key.pem
|
|
106
|
-
|
|
107
|
-
# If you skipped sudo on first run, trust the CA later
|
|
108
|
-
sudo portless trust
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
## Commands
|
|
112
|
-
|
|
113
|
-
```bash
|
|
114
|
-
portless <name> <cmd> [args...] # Run app at http://<name>.localhost:1355
|
|
115
|
-
portless list # Show active routes
|
|
116
|
-
portless trust # Add local CA to system trust store
|
|
117
|
-
|
|
118
|
-
# Disable portless (run command directly)
|
|
119
|
-
PORTLESS=0 pnpm dev # Bypasses proxy, uses default port
|
|
120
|
-
# Also accepts PORTLESS=skip
|
|
121
|
-
|
|
122
|
-
# Proxy control
|
|
123
|
-
portless proxy start # Start the proxy (port 1355, daemon)
|
|
124
|
-
portless proxy start --https # Start with HTTP/2 + TLS
|
|
125
|
-
portless proxy start -p 80 # Start on port 80 (requires sudo)
|
|
126
|
-
portless proxy start --foreground # Start in foreground (for debugging)
|
|
127
|
-
portless proxy stop # Stop the proxy
|
|
128
|
-
|
|
129
|
-
# Options
|
|
130
|
-
-p, --port <number> # Port for the proxy (default: 1355)
|
|
131
|
-
# Ports < 1024 require sudo
|
|
132
|
-
--https # Enable HTTP/2 + TLS with auto-generated certs
|
|
133
|
-
--cert <path> # Use a custom TLS certificate (implies --https)
|
|
134
|
-
--key <path> # Use a custom TLS private key (implies --https)
|
|
135
|
-
--no-tls # Disable HTTPS (overrides PORTLESS_HTTPS)
|
|
136
|
-
--foreground # Run proxy in foreground instead of daemon
|
|
137
|
-
|
|
138
|
-
# Environment variables
|
|
139
|
-
PORTLESS_PORT=<number> # Override the default proxy port
|
|
140
|
-
PORTLESS_HTTPS=1 # Always enable HTTPS
|
|
141
|
-
PORTLESS_STATE_DIR=<path> # Override the state directory
|
|
142
|
-
|
|
143
|
-
# Info
|
|
144
|
-
portless --help # Show help
|
|
145
|
-
portless --version # Show version
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
## State Directory
|
|
149
|
-
|
|
150
|
-
Portless stores its state (routes, PID file, port file) in a directory that depends on the proxy port:
|
|
151
|
-
|
|
152
|
-
- **Port < 1024** (sudo required): `/tmp/portless` -- shared between root and user processes
|
|
153
|
-
- **Port >= 1024** (no sudo): `~/.portless` -- user-scoped, no root involvement
|
|
154
|
-
|
|
155
|
-
Override with the `PORTLESS_STATE_DIR` environment variable if needed.
|
|
156
|
-
|
|
157
|
-
## Requirements
|
|
158
|
-
|
|
159
|
-
- Node.js 20+
|
|
160
|
-
- macOS or Linux
|