portless 0.9.4 → 0.9.5
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 +1 -1
- package/dist/{chunk-63BOQNMU.js → chunk-D3LR3J7L.js} +18 -3
- package/dist/cli.js +24 -11
- package/dist/index.d.ts +11 -3
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -166,7 +166,7 @@ portless proxy stop # Stop the proxy
|
|
|
166
166
|
--tld <tld> Use a custom TLD instead of .localhost (e.g. test)
|
|
167
167
|
--wildcard Allow unregistered subdomains to fall back to parent route
|
|
168
168
|
--app-port <number> Use a fixed port for the app (skip auto-assignment)
|
|
169
|
-
--force
|
|
169
|
+
--force Kill the existing process and take over its route
|
|
170
170
|
--name <name> Use <name> as the app name
|
|
171
171
|
```
|
|
172
172
|
|
|
@@ -505,7 +505,7 @@ function createProxyServer(options) {
|
|
|
505
505
|
};
|
|
506
506
|
if (tls) {
|
|
507
507
|
const h2Server = http2.createSecureServer({
|
|
508
|
-
cert: tls.cert,
|
|
508
|
+
cert: tls.ca ? Buffer.concat([tls.cert, tls.ca]) : tls.cert,
|
|
509
509
|
key: tls.key,
|
|
510
510
|
allowHTTP1: true,
|
|
511
511
|
...tls.SNICallback ? { SNICallback: tls.SNICallback } : {}
|
|
@@ -1297,16 +1297,30 @@ var RouteStore = class _RouteStore {
|
|
|
1297
1297
|
fs4.writeFileSync(this.routesPath, JSON.stringify(routes, null, 2), { mode: this.fileMode });
|
|
1298
1298
|
fixOwnership(this.routesPath);
|
|
1299
1299
|
}
|
|
1300
|
+
/**
|
|
1301
|
+
* Register a route. When `force` is true and the hostname is already claimed
|
|
1302
|
+
* by another live process, that process is sent SIGTERM before the route is
|
|
1303
|
+
* replaced. Returns the PID of the killed process (if any) so the caller can
|
|
1304
|
+
* log it.
|
|
1305
|
+
*/
|
|
1300
1306
|
addRoute(hostname, port, pid, force = false) {
|
|
1301
1307
|
this.ensureDir();
|
|
1302
1308
|
if (!this.acquireLock()) {
|
|
1303
1309
|
throw new Error("Failed to acquire route lock");
|
|
1304
1310
|
}
|
|
1311
|
+
let killedPid;
|
|
1305
1312
|
try {
|
|
1306
1313
|
const routes = this.loadRoutes(true);
|
|
1307
1314
|
const existing = routes.find((r) => r.hostname === hostname);
|
|
1308
|
-
if (existing && existing.pid !== pid && this.isProcessAlive(existing.pid)
|
|
1309
|
-
|
|
1315
|
+
if (existing && existing.pid !== pid && this.isProcessAlive(existing.pid)) {
|
|
1316
|
+
if (!force) {
|
|
1317
|
+
throw new RouteConflictError(hostname, existing.pid);
|
|
1318
|
+
}
|
|
1319
|
+
try {
|
|
1320
|
+
process.kill(existing.pid, "SIGTERM");
|
|
1321
|
+
killedPid = existing.pid;
|
|
1322
|
+
} catch {
|
|
1323
|
+
}
|
|
1310
1324
|
}
|
|
1311
1325
|
const filtered = routes.filter((r) => r.hostname !== hostname);
|
|
1312
1326
|
filtered.push({ hostname, port, pid });
|
|
@@ -1314,6 +1328,7 @@ var RouteStore = class _RouteStore {
|
|
|
1314
1328
|
} finally {
|
|
1315
1329
|
this.releaseLock();
|
|
1316
1330
|
}
|
|
1331
|
+
return killedPid;
|
|
1317
1332
|
}
|
|
1318
1333
|
removeRoute(hostname) {
|
|
1319
1334
|
this.ensureDir();
|
package/dist/cli.js
CHANGED
|
@@ -35,7 +35,7 @@ import {
|
|
|
35
35
|
waitForProxy,
|
|
36
36
|
writeTldFile,
|
|
37
37
|
writeTlsMarker
|
|
38
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-D3LR3J7L.js";
|
|
39
39
|
|
|
40
40
|
// src/colors.ts
|
|
41
41
|
function supportsColor() {
|
|
@@ -471,10 +471,13 @@ async function generateHostCertAsync(stateDir, hostname) {
|
|
|
471
471
|
fixOwnership(keyPath, certPath);
|
|
472
472
|
return { certPath, keyPath };
|
|
473
473
|
}
|
|
474
|
-
function createSNICallback(stateDir, defaultCert, defaultKey, tld = "localhost") {
|
|
474
|
+
function createSNICallback(stateDir, defaultCert, defaultKey, tld = "localhost", caCert) {
|
|
475
475
|
const cache = /* @__PURE__ */ new Map();
|
|
476
476
|
const pending = /* @__PURE__ */ new Map();
|
|
477
|
-
const defaultCtx = tls.createSecureContext({
|
|
477
|
+
const defaultCtx = tls.createSecureContext({
|
|
478
|
+
cert: caCert ? Buffer.concat([defaultCert, caCert]) : defaultCert,
|
|
479
|
+
key: defaultKey
|
|
480
|
+
});
|
|
478
481
|
return (servername, cb) => {
|
|
479
482
|
if (servername === tld) {
|
|
480
483
|
cb(null, defaultCtx);
|
|
@@ -490,8 +493,9 @@ function createSNICallback(stateDir, defaultCert, defaultKey, tld = "localhost")
|
|
|
490
493
|
const keyPath = path.join(hostDir, `${safeName}-key.pem`);
|
|
491
494
|
if (fileExists(certPath) && fileExists(keyPath) && isCertValid(certPath) && isCertSignatureStrong(certPath)) {
|
|
492
495
|
try {
|
|
496
|
+
const hostCert = fs.readFileSync(certPath);
|
|
493
497
|
const ctx = tls.createSecureContext({
|
|
494
|
-
cert:
|
|
498
|
+
cert: caCert ? Buffer.concat([hostCert, caCert]) : hostCert,
|
|
495
499
|
key: fs.readFileSync(keyPath)
|
|
496
500
|
});
|
|
497
501
|
cache.set(servername, ctx);
|
|
@@ -505,11 +509,14 @@ function createSNICallback(stateDir, defaultCert, defaultKey, tld = "localhost")
|
|
|
505
509
|
return;
|
|
506
510
|
}
|
|
507
511
|
const promise = generateHostCertAsync(stateDir, servername).then(async (generated) => {
|
|
508
|
-
const [
|
|
512
|
+
const [hostCert, key] = await Promise.all([
|
|
509
513
|
fs.promises.readFile(generated.certPath),
|
|
510
514
|
fs.promises.readFile(generated.keyPath)
|
|
511
515
|
]);
|
|
512
|
-
return tls.createSecureContext({
|
|
516
|
+
return tls.createSecureContext({
|
|
517
|
+
cert: caCert ? Buffer.concat([hostCert, caCert]) : hostCert,
|
|
518
|
+
key
|
|
519
|
+
});
|
|
513
520
|
});
|
|
514
521
|
pending.set(servername, promise);
|
|
515
522
|
promise.then((ctx) => {
|
|
@@ -1157,8 +1164,9 @@ portless
|
|
|
1157
1164
|
} else {
|
|
1158
1165
|
console.log(colors_default.green(`-- Using port ${port}`));
|
|
1159
1166
|
}
|
|
1167
|
+
let killedPid;
|
|
1160
1168
|
try {
|
|
1161
|
-
store.addRoute(hostname, port, process.pid, force);
|
|
1169
|
+
killedPid = store.addRoute(hostname, port, process.pid, force);
|
|
1162
1170
|
} catch (err) {
|
|
1163
1171
|
if (err instanceof RouteConflictError) {
|
|
1164
1172
|
console.error(colors_default.red(`Error: ${err.message}`));
|
|
@@ -1166,6 +1174,9 @@ portless
|
|
|
1166
1174
|
}
|
|
1167
1175
|
throw err;
|
|
1168
1176
|
}
|
|
1177
|
+
if (killedPid !== void 0) {
|
|
1178
|
+
console.log(colors_default.yellow(`Killed existing process (PID ${killedPid})`));
|
|
1179
|
+
}
|
|
1169
1180
|
const finalUrl = formatUrl(hostname, proxyPort, tls2);
|
|
1170
1181
|
console.log(colors_default.cyan.bold(`
|
|
1171
1182
|
-> ${finalUrl}
|
|
@@ -1233,7 +1244,7 @@ ${colors_default.bold("Usage:")}
|
|
|
1233
1244
|
|
|
1234
1245
|
${colors_default.bold("Options:")}
|
|
1235
1246
|
--name <name> Override the inferred base name (worktree prefix still applies)
|
|
1236
|
-
--force
|
|
1247
|
+
--force Kill the existing process and take over its route
|
|
1237
1248
|
--app-port <number> Use a fixed port for the app (skip auto-assignment)
|
|
1238
1249
|
--help, -h Show this help
|
|
1239
1250
|
|
|
@@ -1388,7 +1399,7 @@ ${colors_default.bold("Options:")}
|
|
|
1388
1399
|
--tld <tld> Use a custom TLD instead of .localhost (e.g. test, dev)
|
|
1389
1400
|
--wildcard Allow unregistered subdomains to fall back to parent route
|
|
1390
1401
|
--app-port <number> Use a fixed port for the app (skip auto-assignment)
|
|
1391
|
-
--force
|
|
1402
|
+
--force Kill the existing process and take over its route
|
|
1392
1403
|
--name <name> Use <name> as the app name (bypasses subcommand dispatch)
|
|
1393
1404
|
-- Stop flag parsing; everything after is passed to the child
|
|
1394
1405
|
|
|
@@ -1427,7 +1438,7 @@ ${colors_default.bold("Reserved names:")}
|
|
|
1427
1438
|
process.exit(0);
|
|
1428
1439
|
}
|
|
1429
1440
|
function printVersion() {
|
|
1430
|
-
console.log("0.9.
|
|
1441
|
+
console.log("0.9.5");
|
|
1431
1442
|
process.exit(0);
|
|
1432
1443
|
}
|
|
1433
1444
|
async function handleTrust() {
|
|
@@ -1954,10 +1965,12 @@ ${colors_default.bold("Usage:")}
|
|
|
1954
1965
|
}
|
|
1955
1966
|
const cert = fs3.readFileSync(certs.certPath);
|
|
1956
1967
|
const key = fs3.readFileSync(certs.keyPath);
|
|
1968
|
+
const ca = fs3.readFileSync(certs.caPath);
|
|
1957
1969
|
tlsOptions = {
|
|
1958
1970
|
cert,
|
|
1959
1971
|
key,
|
|
1960
|
-
|
|
1972
|
+
ca,
|
|
1973
|
+
SNICallback: createSNICallback(stateDir, cert, key, tld, ca)
|
|
1961
1974
|
};
|
|
1962
1975
|
}
|
|
1963
1976
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -26,6 +26,8 @@ interface ProxyServerOptions {
|
|
|
26
26
|
tls?: {
|
|
27
27
|
cert: Buffer;
|
|
28
28
|
key: Buffer;
|
|
29
|
+
/** CA certificate to include in the chain so clients can verify the leaf. */
|
|
30
|
+
ca?: Buffer;
|
|
29
31
|
/** SNI callback for per-hostname certificate selection. */
|
|
30
32
|
SNICallback?: (servername: string, cb: (err: Error | null, ctx?: node_tls.SecureContext) => void) => void;
|
|
31
33
|
};
|
|
@@ -65,8 +67,8 @@ interface RouteMapping extends RouteInfo {
|
|
|
65
67
|
pid: number;
|
|
66
68
|
}
|
|
67
69
|
/**
|
|
68
|
-
* Thrown when a route is already registered by a live process and --force
|
|
69
|
-
*
|
|
70
|
+
* Thrown when a route is already registered by a live process and --force was
|
|
71
|
+
* not specified. With --force, the existing process is killed instead.
|
|
70
72
|
*/
|
|
71
73
|
declare class RouteConflictError extends Error {
|
|
72
74
|
readonly hostname: string;
|
|
@@ -106,7 +108,13 @@ declare class RouteStore {
|
|
|
106
108
|
*/
|
|
107
109
|
loadRoutes(persistCleanup?: boolean): RouteMapping[];
|
|
108
110
|
private saveRoutes;
|
|
109
|
-
|
|
111
|
+
/**
|
|
112
|
+
* Register a route. When `force` is true and the hostname is already claimed
|
|
113
|
+
* by another live process, that process is sent SIGTERM before the route is
|
|
114
|
+
* replaced. Returns the PID of the killed process (if any) so the caller can
|
|
115
|
+
* log it.
|
|
116
|
+
*/
|
|
117
|
+
addRoute(hostname: string, port: number, pid: number, force?: boolean): number | undefined;
|
|
110
118
|
removeRoute(hostname: string): void;
|
|
111
119
|
}
|
|
112
120
|
|
package/dist/index.js
CHANGED