meldivo 1.1.1 → 2.0.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/README.md +36 -17
- package/bin/meldivo.mjs +115 -64
- package/dist/server/access.js +1 -1
- package/dist/server/access.js.map +1 -1
- package/dist/server/hub.js +386 -108
- package/dist/server/hub.js.map +1 -1
- package/dist/server/index.js +183 -137
- package/dist/server/index.js.map +1 -1
- package/dist/server/logger.js +6 -1
- package/dist/server/logger.js.map +1 -1
- package/dist/server/machine-client.js +272 -0
- package/dist/server/machine-client.js.map +1 -0
- package/dist/server/protocol.js +45 -0
- package/dist/server/protocol.js.map +1 -0
- package/dist/web/assets/{index-of0Gr3pq.js → index-B4ZxmMdT.js} +11 -11
- package/dist/web/index.html +1 -1
- package/package.json +7 -4
package/README.md
CHANGED
|
@@ -77,7 +77,11 @@ project.
|
|
|
77
77
|
| `meldivo remote cloudflare` | Publish the hub through a Cloudflare quick tunnel. |
|
|
78
78
|
| `meldivo remote certificate` | Publish the hub over HTTPS using your own certificate. |
|
|
79
79
|
| `meldivo remote stop` | Turn remote access off. |
|
|
80
|
-
| `meldivo
|
|
80
|
+
| `meldivo hub enable` | Make this machine a hub that your other machines join. `meldivo hub disable` turns it off. |
|
|
81
|
+
| `meldivo hub code` | Print a one-time code (10 minutes, single use) and the `meldivo join` command for adding a machine. |
|
|
82
|
+
| `meldivo hub machines` | List the machines that joined this hub. `meldivo hub remove <name>` removes one at once. |
|
|
83
|
+
| `meldivo join <hub-address> <code>` | Join a hub, so this machine's sessions appear there. Options: `--name <name>`, `--allow pi,opencode,claude`, `--speech` (also do speech for the hub). |
|
|
84
|
+
| `meldivo leave` | Leave the hub this machine joined. |
|
|
81
85
|
| `meldivo logs` | Show the service's recent log output. |
|
|
82
86
|
| `meldivo uninstall [--purge]` | Remove the background service. `--purge` also deletes configuration, models, and logs. |
|
|
83
87
|
| `meldivo --version` | Print the installed version. |
|
|
@@ -101,28 +105,42 @@ how to trust a certificate on iPhone and Android.
|
|
|
101
105
|
|
|
102
106
|
## Several machines, one hub
|
|
103
107
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
+
If you use coding agents on more than one computer, make one of them (or a
|
|
109
|
+
small always-on box such as a Raspberry Pi) a **hub**. Every other machine
|
|
110
|
+
joins it and keeps an outbound connection to it, so those machines need no
|
|
111
|
+
open ports. The hub's single link then lists every machine with its sessions
|
|
112
|
+
and new-chat tiles. Only the text of each turn goes to the machine that runs
|
|
113
|
+
it. Speech runs on the hub, or on a faster machine that joins with `--speech`,
|
|
114
|
+
which is recommended when the hub is a small computer.
|
|
108
115
|
|
|
109
|
-
|
|
110
|
-
VPN. On each other machine:
|
|
116
|
+
On the hub:
|
|
111
117
|
|
|
112
118
|
```sh
|
|
113
|
-
|
|
114
|
-
meldivo
|
|
119
|
+
meldivo hub enable # prints the hub link
|
|
120
|
+
meldivo hub code # prints a one-time code and the join command
|
|
115
121
|
```
|
|
116
122
|
|
|
117
|
-
|
|
123
|
+
On each other machine (with meldivo installed and started):
|
|
118
124
|
|
|
119
125
|
```sh
|
|
120
|
-
meldivo
|
|
126
|
+
meldivo join http://<hub-address>:4100 <code>
|
|
121
127
|
```
|
|
122
128
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
129
|
+
The hub address must be reachable from that machine, ideally over a private
|
|
130
|
+
network such as a VPN: set `MELDIVO_HOST=<vpn-ip>` when starting the hub so it
|
|
131
|
+
also listens there. See the [self-hosting guide](docs/self-hosting-hub.md) for
|
|
132
|
+
a full walkthrough, including running the hub on a Raspberry Pi.
|
|
133
|
+
|
|
134
|
+
How it stays private:
|
|
135
|
+
|
|
136
|
+
- A machine joins only with a one-time code, and gets its own credential; the
|
|
137
|
+
hub stores only a hash of it. `meldivo hub remove <name>` cuts a machine off
|
|
138
|
+
immediately.
|
|
139
|
+
- The hub proves its identity on every connection with a key the machine
|
|
140
|
+
pinned when it joined, so a machine never talks to a look-alike hub.
|
|
141
|
+
- The hub can only ask a machine to run or cancel a text turn in one of its
|
|
142
|
+
own sessions, never a command. `--allow` limits which agents it may use.
|
|
143
|
+
- Session lists are kept in memory on the hub, never written to disk.
|
|
126
144
|
|
|
127
145
|
## How it works
|
|
128
146
|
|
|
@@ -144,7 +162,7 @@ All settings are optional.
|
|
|
144
162
|
| `MELDIVO_PORT` | `4100` | Port of the local server (`127.0.0.1` only). |
|
|
145
163
|
| `MELDIVO_HTTPS_PORT` | `4443` | HTTPS port used by the "own certificate" remote option. |
|
|
146
164
|
| `MELDIVO_PUBLIC_URL` | unset | Base URL to print when you run your own reverse proxy. |
|
|
147
|
-
| `MELDIVO_HOST` | unset | Extra addresses to listen on besides `127.0.0.1` (comma-separated), e.g. a VPN address your reverse proxy
|
|
165
|
+
| `MELDIVO_HOST` | unset | Extra addresses to listen on besides `127.0.0.1` (comma-separated), e.g. a VPN address that joined machines or your reverse proxy connect to. |
|
|
148
166
|
| `MELDIVO_MODELS_DIR` | `~/.cache/meldivo/models` | Location of the downloaded speech models. |
|
|
149
167
|
|
|
150
168
|
## Files and locations
|
|
@@ -152,7 +170,8 @@ All settings are optional.
|
|
|
152
170
|
| Path | Contents |
|
|
153
171
|
|---|---|
|
|
154
172
|
| `~/.config/meldivo/secret` | The hub's shared secret, generated automatically. |
|
|
155
|
-
| `~/.config/meldivo/
|
|
173
|
+
| `~/.config/meldivo/hub.json` | On a machine that joined a hub: the hub's address, this machine's credential, and the hub's pinned key. |
|
|
174
|
+
| `~/.config/meldivo/machines.json`, `hub-key.pem` | On a hub: joined machines (names and credential hashes) and the hub's signing key. |
|
|
156
175
|
| `~/.cache/meldivo/models` | Downloaded speech models. |
|
|
157
176
|
| `~/.local/state/meldivo` | Service logs and runtime state. |
|
|
158
177
|
|
|
@@ -162,7 +181,7 @@ The server listens on `127.0.0.1` only; it is never exposed on the network
|
|
|
162
181
|
unless you explicitly turn on phone access. Every hub link, local or remote,
|
|
163
182
|
embeds a random token, and requests without it are rejected. Treat the hub
|
|
164
183
|
link like a password: anyone who has it can use every session in the hub,
|
|
165
|
-
including the sessions of every
|
|
184
|
+
including the sessions of every machine that joined it.
|
|
166
185
|
|
|
167
186
|
## Uninstall
|
|
168
187
|
|
package/bin/meldivo.mjs
CHANGED
|
@@ -42,8 +42,8 @@ function runtimePath() {
|
|
|
42
42
|
return path.join(configDir(), "runtime.json");
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
function
|
|
46
|
-
return path.join(configDir(), "
|
|
45
|
+
function hubLinkPath() {
|
|
46
|
+
return path.join(configDir(), "hub.json");
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
function pidPath() {
|
|
@@ -171,6 +171,7 @@ function serviceEnv(port, httpsPort) {
|
|
|
171
171
|
if (publicUrl) env.MELDIVO_PUBLIC_URL = publicUrl;
|
|
172
172
|
const host = resolveHost();
|
|
173
173
|
if (host) env.MELDIVO_HOST = host;
|
|
174
|
+
if (readRuntime().hub) env.MELDIVO_HUB = "1";
|
|
174
175
|
if (process.env.MELDIVO_MODELS_DIR) env.MELDIVO_MODELS_DIR = process.env.MELDIVO_MODELS_DIR;
|
|
175
176
|
env.PATH = servicePath();
|
|
176
177
|
return env;
|
|
@@ -312,19 +313,19 @@ function serviceMode() {
|
|
|
312
313
|
return "detached";
|
|
313
314
|
}
|
|
314
315
|
|
|
315
|
-
async function cmdStart(args) {
|
|
316
|
+
async function cmdStart(args, { quiet = false } = {}) {
|
|
316
317
|
const foreground = args.includes("--foreground");
|
|
317
318
|
const port = resolvePort();
|
|
318
319
|
const httpsPort = resolveHttpsPort();
|
|
319
320
|
const secret = ensureSecret();
|
|
320
|
-
writeRuntime({ port, httpsPort, publicUrl: resolvePublicUrl() || undefined, host: resolveHost() || undefined });
|
|
321
|
+
writeRuntime({ ...readRuntime(), port, httpsPort, publicUrl: resolvePublicUrl() || undefined, host: resolveHost() || undefined });
|
|
321
322
|
|
|
322
323
|
if (foreground) {
|
|
323
324
|
process.env.MELDIVO_SECRET = secret;
|
|
324
325
|
process.env.MELDIVO_PORT = String(port);
|
|
325
326
|
process.env.MELDIVO_HTTPS_PORT = String(httpsPort);
|
|
326
327
|
const { startServer } = await import(pathToFileURL(serverEntry).href);
|
|
327
|
-
const server = await startServer({ port, host: "127.0.0.1", secret, httpsPort });
|
|
328
|
+
const server = await startServer({ port, host: "127.0.0.1", secret, httpsPort, hub: Boolean(readRuntime().hub), version: pkgJson.version });
|
|
328
329
|
console.log(`meldivo running in the foreground on port ${server.port}`);
|
|
329
330
|
await printUrl(secret);
|
|
330
331
|
const shutdown = () => server.close().then(() => process.exit(0));
|
|
@@ -337,17 +338,19 @@ async function cmdStart(args) {
|
|
|
337
338
|
const mode = serviceMode();
|
|
338
339
|
if (mode === "systemd") {
|
|
339
340
|
installSystemdUnit(env);
|
|
340
|
-
console.log("Installed and started the meldivo systemd user service.");
|
|
341
|
-
console.log("To keep it running after logout: loginctl enable-linger $USER");
|
|
341
|
+
if (!quiet) console.log("Installed and started the meldivo systemd user service.");
|
|
342
|
+
if (!quiet) console.log("To keep it running after logout: loginctl enable-linger $USER");
|
|
342
343
|
} else if (mode === "launchd") {
|
|
343
344
|
installLaunchAgent(env);
|
|
344
|
-
console.log("Installed and started the meldivo LaunchAgent.");
|
|
345
|
+
if (!quiet) console.log("Installed and started the meldivo LaunchAgent.");
|
|
345
346
|
} else {
|
|
347
|
+
stopDetached();
|
|
346
348
|
startDetached(env);
|
|
347
|
-
console.log(`Started meldivo as a background process (no user service manager found). Logs: ${logPath()}`);
|
|
349
|
+
if (!quiet) console.log(`Started meldivo as a background process (no user service manager found). Logs: ${logPath()}`);
|
|
348
350
|
}
|
|
349
351
|
|
|
350
352
|
await waitForHealth(port);
|
|
353
|
+
if (quiet) return;
|
|
351
354
|
console.log("meldivo is up:");
|
|
352
355
|
await printUrl(secret);
|
|
353
356
|
}
|
|
@@ -379,6 +382,8 @@ async function cmdStatus() {
|
|
|
379
382
|
try {
|
|
380
383
|
const health = await waitForHealth(port, 2_000);
|
|
381
384
|
console.log(`Health: ok, speech=${JSON.stringify(health.speech)}`);
|
|
385
|
+
if (health.hub) console.log("Hub: on (meldivo hub machines lists joined machines)");
|
|
386
|
+
if (health.joined) console.log(`Joined hub as "${health.joined.name}": ${health.joined.connected ? "connected" : "not connected"}`);
|
|
382
387
|
} catch {
|
|
383
388
|
console.log("Health: unreachable");
|
|
384
389
|
}
|
|
@@ -388,59 +393,9 @@ async function cmdOpen(args) {
|
|
|
388
393
|
const secret = ensureSecret();
|
|
389
394
|
const url = hubUrl(secret);
|
|
390
395
|
await printUrl(secret).then(() => {}).catch(() => {});
|
|
391
|
-
// Extra private addresses (MELDIVO_HOST) are what another hub uses with `meldivo peer add`.
|
|
392
|
-
for (const host of resolveHost().split(",").map((value) => value.trim()).filter((value) => value && value !== "127.0.0.1")) {
|
|
393
|
-
console.log(`Also on http://${host.includes(":") ? `[${host}]` : host}:${resolvePort()}/#token=${encodeURIComponent(secret)}`);
|
|
394
|
-
}
|
|
395
396
|
if (args.includes("--browser")) openInBrowser(url);
|
|
396
397
|
}
|
|
397
398
|
|
|
398
|
-
function readPeers() {
|
|
399
|
-
try {
|
|
400
|
-
const peers = JSON.parse(readFileSync(peersPath(), "utf8"));
|
|
401
|
-
return Array.isArray(peers) ? peers : [];
|
|
402
|
-
} catch {
|
|
403
|
-
return [];
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
function writePeers(peers) {
|
|
408
|
-
ensureDir(configDir(), 0o700);
|
|
409
|
-
writePrivate(peersPath(), JSON.stringify(peers, null, 2));
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
// Peers are other machines' hubs shown in this one. The hub rereads the file, so no restart is needed.
|
|
413
|
-
function cmdPeer(args) {
|
|
414
|
-
const [sub, name, link] = args;
|
|
415
|
-
if (!sub || sub === "list") {
|
|
416
|
-
const peers = readPeers();
|
|
417
|
-
if (peers.length === 0) console.log("No peers. Add one with: meldivo peer add <name> <link>");
|
|
418
|
-
for (const peer of peers) console.log(`${peer.name}\t${peer.url}`);
|
|
419
|
-
return;
|
|
420
|
-
}
|
|
421
|
-
if (sub === "remove" && name) {
|
|
422
|
-
const peers = readPeers();
|
|
423
|
-
const remaining = peers.filter((peer) => peer.name !== name);
|
|
424
|
-
if (remaining.length === peers.length) throw new Error(`No peer named "${name}"`);
|
|
425
|
-
writePeers(remaining);
|
|
426
|
-
console.log(`Removed ${name}.`);
|
|
427
|
-
return;
|
|
428
|
-
}
|
|
429
|
-
if (sub === "add" && name && link) {
|
|
430
|
-
if (!/^[A-Za-z0-9._-]{1,40}$/.test(name)) throw new Error("Peer names may use letters, digits, dot, dash, and underscore");
|
|
431
|
-
const parsed = new URL(link);
|
|
432
|
-
const token = decodeURIComponent(/(?:^#|&)token=([^&]+)/.exec(parsed.hash)?.[1] ?? "");
|
|
433
|
-
if (!token) throw new Error("The link must end in #token=<key> (run `meldivo open` on that machine)");
|
|
434
|
-
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") throw new Error("The link must be http(s)");
|
|
435
|
-
const peers = readPeers().filter((peer) => peer.name !== name);
|
|
436
|
-
peers.push({ name, url: parsed.origin, token });
|
|
437
|
-
writePeers(peers);
|
|
438
|
-
console.log(`Added ${name} (${parsed.origin}).`);
|
|
439
|
-
return;
|
|
440
|
-
}
|
|
441
|
-
throw new Error("Usage: meldivo peer [list] | add <name> <link> | remove <name>");
|
|
442
|
-
}
|
|
443
|
-
|
|
444
399
|
function openInBrowser(url) {
|
|
445
400
|
const opener = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
446
401
|
try {
|
|
@@ -489,6 +444,90 @@ async function cmdRemote(args) {
|
|
|
489
444
|
for (const alt of result.alternatives ?? []) console.log(`Also reachable at: ${alt}`);
|
|
490
445
|
}
|
|
491
446
|
|
|
447
|
+
// Addresses other machines can use to reach this hub: MELDIVO_HOST addresses, then the public URL.
|
|
448
|
+
function hubAddresses() {
|
|
449
|
+
const port = resolvePort();
|
|
450
|
+
const addresses = resolveHost().split(",").map((value) => value.trim()).filter((value) => value && value !== "127.0.0.1")
|
|
451
|
+
.map((host) => `http://${host.includes(":") ? `[${host}]` : host}:${port}`);
|
|
452
|
+
if (resolvePublicUrl()) addresses.push(resolvePublicUrl());
|
|
453
|
+
return addresses.length ? addresses : [baseUrl()];
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
async function cmdHub(args) {
|
|
457
|
+
const [sub, name] = args;
|
|
458
|
+
const secret = ensureSecret();
|
|
459
|
+
if (sub === "enable" || sub === "disable") {
|
|
460
|
+
writeRuntime({ ...readRuntime(), hub: sub === "enable" || undefined });
|
|
461
|
+
await cmdStart([], { quiet: true });
|
|
462
|
+
if (sub === "disable") {
|
|
463
|
+
console.log("Hub mode is off. Machines that joined this hub keep trying to reconnect until you run `meldivo leave` on them.");
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
console.log("This machine is now a hub. Open it with:");
|
|
467
|
+
await printUrl(secret);
|
|
468
|
+
console.log("To add a machine, run `meldivo hub code` here and follow the instructions it prints.");
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
if (!readRuntime().hub) throw new Error("This machine is not a hub. Turn hub mode on with: meldivo hub enable");
|
|
472
|
+
if (sub === "code") {
|
|
473
|
+
const { code, expiresAt } = await apiCall("/api/hub/codes", "POST", secret);
|
|
474
|
+
const minutes = Math.round((expiresAt - Date.now()) / 60_000);
|
|
475
|
+
console.log(`One-time code (valid ${minutes} minutes, single use): ${code}`);
|
|
476
|
+
console.log("\nOn the machine you want to add, run:");
|
|
477
|
+
for (const address of hubAddresses()) console.log(` meldivo join ${address} ${code}`);
|
|
478
|
+
console.log("\nUse an address that machine can reach privately, such as a VPN address (see MELDIVO_HOST).");
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
if (!sub || sub === "machines") {
|
|
482
|
+
const { machines } = await apiCall("/api/hub/machines", "GET", secret);
|
|
483
|
+
if (machines.length === 0) console.log("No machines yet. Add one with: meldivo hub code");
|
|
484
|
+
for (const machine of machines) {
|
|
485
|
+
console.log(`${machine.name}\t${machine.online ? "online" : "offline"}${machine.version ? `\t${machine.version}` : ""}\tjoined ${new Date(machine.joinedAt).toISOString().slice(0, 10)}`);
|
|
486
|
+
}
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
if (sub === "remove" && name) {
|
|
490
|
+
await apiCall(`/api/hub/machines/${encodeURIComponent(name)}`, "DELETE", secret);
|
|
491
|
+
console.log(`Removed ${name}. It can no longer connect; run \`meldivo leave\` on it to stop it trying.`);
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
throw new Error("Usage: meldivo hub enable | disable | code | machines | remove <name>");
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
function optionValue(args, flag) {
|
|
498
|
+
const index = args.indexOf(flag);
|
|
499
|
+
return index >= 0 ? args[index + 1] : undefined;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
async function cmdJoin(args) {
|
|
503
|
+
const positional = args.filter((arg, index) => !arg.startsWith("--") && !(index > 0 && args[index - 1].startsWith("--")));
|
|
504
|
+
const [hubAddress, code] = positional;
|
|
505
|
+
if (!hubAddress || !code) throw new Error("Usage: meldivo join <hub-address> <code> [--name <name>] [--allow pi,opencode,claude] [--speech]");
|
|
506
|
+
const requestedName = optionValue(args, "--name") ?? os.hostname().split(".")[0].replace(/[^A-Za-z0-9._-]/g, "-").slice(0, 40);
|
|
507
|
+
const allow = optionValue(args, "--allow")?.split(",").map((id) => id.trim()).filter(Boolean);
|
|
508
|
+
const url = new URL(hubAddress);
|
|
509
|
+
if (url.protocol === "http:" && !/^(127\.|localhost$|\[::1\]$)/.test(url.hostname)) {
|
|
510
|
+
console.log("Note: this hub address is plain http. That is fine on a private VPN; over any other network use https.");
|
|
511
|
+
}
|
|
512
|
+
const { joinHub } = await import(pathToFileURL(path.join(pkgRoot, "dist", "server", "machine-client.js")).href);
|
|
513
|
+
const link = await joinHub(hubAddress, code, requestedName);
|
|
514
|
+
ensureDir(configDir(), 0o700);
|
|
515
|
+
const speech = args.includes("--speech") || undefined;
|
|
516
|
+
writePrivate(hubLinkPath(), JSON.stringify({ ...link, ...(allow?.length ? { allow } : {}), ...(speech ? { speech } : {}) }, null, 2));
|
|
517
|
+
await cmdStart([], { quiet: true });
|
|
518
|
+
console.log(`Joined the hub as "${link.name}". This machine's sessions now appear in the hub.`);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
async function cmdLeave() {
|
|
522
|
+
if (!existsSync(hubLinkPath())) {
|
|
523
|
+
console.log("This machine has not joined a hub.");
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
rmSync(hubLinkPath(), { force: true });
|
|
527
|
+
await cmdStart([], { quiet: true });
|
|
528
|
+
console.log("Left the hub. Also remove this machine on the hub with: meldivo hub remove <name>");
|
|
529
|
+
}
|
|
530
|
+
|
|
492
531
|
async function cmdUninstall(args) {
|
|
493
532
|
await cmdStop();
|
|
494
533
|
const mode = serviceMode();
|
|
@@ -524,14 +563,20 @@ function printHelp() {
|
|
|
524
563
|
Usage: meldivo <command> [options]
|
|
525
564
|
|
|
526
565
|
Commands:
|
|
527
|
-
start [--foreground] Start
|
|
566
|
+
start [--foreground] Start meldivo as a user service
|
|
528
567
|
stop Stop and disable the service
|
|
529
568
|
status Show health, speech, and service state
|
|
530
569
|
open [--browser] Print the hub URL and QR (optionally open it)
|
|
531
570
|
remote [tailscale|cloudflare|certificate|stop]
|
|
532
571
|
Manage remote access
|
|
533
|
-
|
|
534
|
-
|
|
572
|
+
hub enable|disable Make this machine a hub that other machines join (or stop)
|
|
573
|
+
hub code Print a one-time code for adding a machine to this hub
|
|
574
|
+
hub machines List the machines that joined this hub
|
|
575
|
+
hub remove <name> Remove a machine from this hub
|
|
576
|
+
join <hub-address> <code> [--name <name>] [--allow pi,opencode,claude] [--speech]
|
|
577
|
+
Join a hub: this machine's sessions appear there
|
|
578
|
+
(--speech: also do speech for the hub)
|
|
579
|
+
leave Leave the hub this machine joined
|
|
535
580
|
uninstall [--purge] Stop and remove the service (optionally wipe config/cache/state)
|
|
536
581
|
logs Tail service logs
|
|
537
582
|
--version Print the version
|
|
@@ -558,8 +603,14 @@ async function main() {
|
|
|
558
603
|
case "remote":
|
|
559
604
|
await cmdRemote(rest);
|
|
560
605
|
break;
|
|
561
|
-
case "
|
|
562
|
-
|
|
606
|
+
case "hub":
|
|
607
|
+
await cmdHub(rest);
|
|
608
|
+
break;
|
|
609
|
+
case "join":
|
|
610
|
+
await cmdJoin(rest);
|
|
611
|
+
break;
|
|
612
|
+
case "leave":
|
|
613
|
+
await cmdLeave();
|
|
563
614
|
break;
|
|
564
615
|
case "uninstall":
|
|
565
616
|
await cmdUninstall(rest);
|
package/dist/server/access.js
CHANGED
|
@@ -39,7 +39,7 @@ export function createAccessGate(secret) {
|
|
|
39
39
|
return { middleware, unlock, isAuthorized };
|
|
40
40
|
}
|
|
41
41
|
// The same bare 404 for every unauthenticated request, page or API, right key path or not.
|
|
42
|
-
function notFound(req, res) {
|
|
42
|
+
export function notFound(req, res) {
|
|
43
43
|
res.removeHeader("X-Request-Id");
|
|
44
44
|
res.status(404).set({ "Cache-Control": "no-store", "Content-Type": "text/html" });
|
|
45
45
|
res.end(req.method === "HEAD" ? undefined : NOT_FOUND_PAGE);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"access.js","sourceRoot":"","sources":["../../server/src/access.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAG1D,8FAA8F;AAC9F,0FAA0F;AAC1F,+FAA+F;AAC/F,4FAA4F;AAC5F,4FAA4F;AAC5F,+FAA+F;AAC/F,uEAAuE;AAEvE,MAAM,WAAW,GAAG,iBAAiB,CAAC;AACtC,MAAM,gBAAgB,GAAG,GAAG,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;AAW5C,MAAM,UAAU,gBAAgB,CAAC,MAAc;IAC7C,kFAAkF;IAClF,MAAM,WAAW,GAAG,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAE5F,SAAS,YAAY,CAAC,GAAY;QAChC,MAAM,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,iBAAiB,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,eAAe,CAAC,EAAE,KAAK,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACrG,IAAI,KAAK,IAAI,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QACnD,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;QAC5C,OAAO,MAAM,KAAK,SAAS,IAAI,SAAS,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IAChE,CAAC;IAED,MAAM,UAAU,GAAmB,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACpD,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,IAAI,GAAG,CAAC,IAAI,KAAK,aAAa;YAAE,OAAO,IAAI,EAAE,CAAC;QACvE,IAAI,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC;YACtB,mEAAmE;YACnE,GAAG,CAAC,SAAS,CAAC,eAAe,EAAE,mBAAmB,CAAC,CAAC;YACpD,OAAO,IAAI,EAAE,CAAC;QAChB,CAAC;QACD,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACrB,CAAC,CAAC;IAEF,MAAM,MAAM,GAAmB,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QAC1C,MAAM,KAAK,GAAG,OAAO,GAAG,CAAC,IAAI,EAAE,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/E,IAAI,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC;YAAE,OAAO,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACnE,GAAG,CAAC,SAAS,CAAC,eAAe,EAAE,UAAU,CAAC,CAAC;QAC3C,gBAAgB,CAAC,GAAG,EAAE,GAAG,EAAE,WAAW,CAAC,CAAC;QACxC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;IACxB,CAAC,CAAC;IAEF,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC;AAC9C,CAAC;AAED,2FAA2F;AAC3F,
|
|
1
|
+
{"version":3,"file":"access.js","sourceRoot":"","sources":["../../server/src/access.ts"],"names":[],"mappings":"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"}
|