runlocal 0.5.0 → 0.6.0
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/index.js +2 -2
- package/lib.js +15 -7
- package/package.json +12 -3
package/index.js
CHANGED
|
@@ -6,7 +6,7 @@ const { parseArgs, createConnection } = require("./lib");
|
|
|
6
6
|
const BOLD = "\x1b[1m";
|
|
7
7
|
const RESET = "\x1b[0m";
|
|
8
8
|
|
|
9
|
-
const { port, host, apiKey } = parseArgs(process.argv.slice(2));
|
|
9
|
+
const { port, host, apiKey, subdomain } = parseArgs(process.argv.slice(2));
|
|
10
10
|
|
|
11
11
|
console.log(`${BOLD}runlocal${RESET} — expose localhost:${port} to the internet`);
|
|
12
|
-
createConnection({ host, port, apiKey, WebSocket });
|
|
12
|
+
createConnection({ host, port, apiKey, subdomain, WebSocket });
|
package/lib.js
CHANGED
|
@@ -29,11 +29,14 @@ function parseArgs(argv) {
|
|
|
29
29
|
let port = 3000;
|
|
30
30
|
let host = process.env.RUNLOCAL_HOST || "wss://runlocal.eu";
|
|
31
31
|
let apiKey = process.env.RUNLATER_API_KEY || readApiKeyFile();
|
|
32
|
+
let subdomain = null;
|
|
32
33
|
for (let i = 0; i < argv.length; i++) {
|
|
33
34
|
if (argv[i] === "--host" && argv[i + 1]) {
|
|
34
35
|
host = argv[++i];
|
|
35
36
|
} else if (argv[i] === "--api-key" && argv[i + 1]) {
|
|
36
37
|
apiKey = argv[++i];
|
|
38
|
+
} else if (argv[i] === "--subdomain" && argv[i + 1]) {
|
|
39
|
+
subdomain = argv[++i];
|
|
37
40
|
} else if (argv[i] === "--help" || argv[i] === "-h") {
|
|
38
41
|
console.log("Usage: runlocal <port> [options]");
|
|
39
42
|
console.log("");
|
|
@@ -42,6 +45,7 @@ function parseArgs(argv) {
|
|
|
42
45
|
console.log("Options:");
|
|
43
46
|
console.log(" --host <url> Server URL (default: wss://runlocal.eu)");
|
|
44
47
|
console.log(" --api-key <key> Runlater API key for stable subdomain");
|
|
48
|
+
console.log(" --subdomain <name> Custom subdomain (Pro plan only)");
|
|
45
49
|
console.log(" --help, -h Show this help");
|
|
46
50
|
console.log("");
|
|
47
51
|
console.log("API key (checked in order):");
|
|
@@ -50,17 +54,19 @@ function parseArgs(argv) {
|
|
|
50
54
|
console.log(" 3. ~/.runlater/api-key file");
|
|
51
55
|
console.log("");
|
|
52
56
|
console.log("Examples:");
|
|
53
|
-
console.log(" npx runlocal 3000
|
|
54
|
-
console.log(" npx runlocal 3000 --api-key pk_xxx
|
|
57
|
+
console.log(" npx runlocal 3000 Random subdomain");
|
|
58
|
+
console.log(" npx runlocal 3000 --api-key pk_xxx Stable subdomain");
|
|
59
|
+
console.log(" npx runlocal 3000 --subdomain my-api Custom subdomain (Pro)");
|
|
55
60
|
console.log("");
|
|
56
61
|
console.log("A free runlater.eu account gives you a stable subdomain.");
|
|
62
|
+
console.log("Pro users can choose any available subdomain with --subdomain.");
|
|
57
63
|
process.exit(0);
|
|
58
64
|
} else if (!argv[i].startsWith("-")) {
|
|
59
65
|
port = parseInt(argv[i], 10);
|
|
60
66
|
}
|
|
61
67
|
}
|
|
62
68
|
|
|
63
|
-
return { port, host, apiKey };
|
|
69
|
+
return { port, host, apiKey, subdomain };
|
|
64
70
|
}
|
|
65
71
|
|
|
66
72
|
function filterHeaders(headers) {
|
|
@@ -75,9 +81,10 @@ function filterHeaders(headers) {
|
|
|
75
81
|
return filtered;
|
|
76
82
|
}
|
|
77
83
|
|
|
78
|
-
function buildWsUrl(host, apiKey) {
|
|
84
|
+
function buildWsUrl(host, apiKey, subdomain) {
|
|
79
85
|
const params = new URLSearchParams({ vsn: "2.0.0" });
|
|
80
86
|
if (apiKey) params.set("api_key", apiKey);
|
|
87
|
+
if (subdomain) params.set("subdomain", subdomain);
|
|
81
88
|
return `${host}/tunnel/websocket?${params.toString()}`;
|
|
82
89
|
}
|
|
83
90
|
|
|
@@ -170,13 +177,14 @@ function createConnection(options) {
|
|
|
170
177
|
host,
|
|
171
178
|
port,
|
|
172
179
|
apiKey,
|
|
180
|
+
subdomain,
|
|
173
181
|
WebSocket,
|
|
174
182
|
onTunnelCreated,
|
|
175
183
|
onClose,
|
|
176
184
|
log = console.log,
|
|
177
185
|
logError = console.error,
|
|
178
186
|
} = options;
|
|
179
|
-
const wsUrl = buildWsUrl(host, apiKey);
|
|
187
|
+
const wsUrl = buildWsUrl(host, apiKey, subdomain);
|
|
180
188
|
|
|
181
189
|
let refCounter = 0;
|
|
182
190
|
const nextRef = () => String(++refCounter);
|
|
@@ -224,13 +232,13 @@ function createConnection(options) {
|
|
|
224
232
|
if (event === "tunnel_created") {
|
|
225
233
|
const inspectUrl = payload.url.replace(/^https?:\/\/[^/]+/, (origin) => {
|
|
226
234
|
// Convert subdomain URL to main domain /inspect/ URL
|
|
227
|
-
// e.g., https://fuzzy-tiger.runlocal.eu → https://runlocal.eu/inspect/fuzzy-tiger
|
|
235
|
+
// e.g., https://fuzzy-tiger.runlocal.eu → https://runlocal.eu/inspect/fuzzy-tiger/<token>
|
|
228
236
|
const parts = new URL(origin);
|
|
229
237
|
const hostParts = parts.hostname.split(".");
|
|
230
238
|
if (hostParts.length > 2) {
|
|
231
239
|
parts.hostname = hostParts.slice(1).join(".");
|
|
232
240
|
}
|
|
233
|
-
return `${parts.origin}/inspect/${payload.subdomain}`;
|
|
241
|
+
return `${parts.origin}/inspect/${payload.subdomain}/${payload.inspect_token}`;
|
|
234
242
|
});
|
|
235
243
|
|
|
236
244
|
log("");
|
package/package.json
CHANGED
|
@@ -1,15 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "runlocal",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Expose localhost to the internet via runlocal.eu",
|
|
5
5
|
"bin": {
|
|
6
6
|
"runlocal": "./index.js"
|
|
7
7
|
},
|
|
8
|
-
"files": [
|
|
8
|
+
"files": [
|
|
9
|
+
"index.js",
|
|
10
|
+
"lib.js"
|
|
11
|
+
],
|
|
9
12
|
"scripts": {
|
|
10
13
|
"test": "node --test test/*.test.js"
|
|
11
14
|
},
|
|
12
|
-
"keywords": [
|
|
15
|
+
"keywords": [
|
|
16
|
+
"tunnel",
|
|
17
|
+
"localhost",
|
|
18
|
+
"ngrok",
|
|
19
|
+
"dev",
|
|
20
|
+
"https"
|
|
21
|
+
],
|
|
13
22
|
"license": "MIT",
|
|
14
23
|
"dependencies": {
|
|
15
24
|
"ws": "^8.0.0"
|