pinomad 0.10.0 → 0.12.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 +11 -9
- package/dist/chunk-41q0saz0.js +73 -0
- package/dist/chunk-42nqtx5r.js +22 -0
- package/dist/{chunk-wb10efyq.js → chunk-445cevpm.js} +1 -1
- package/dist/{chunk-jgd38rna.js → chunk-47ff1d1t.js} +206 -178
- package/dist/chunk-5qf1grkk.js +220 -0
- package/dist/{chunk-4h7pkkzr.js → chunk-7mn38n4f.js} +3 -3
- package/dist/{chunk-zehwx009.js → chunk-7wj0jh3t.js} +1 -1
- package/dist/{chunk-5791mb0b.js → chunk-agq4tn9r.js} +47 -23
- package/dist/{chunk-c5p9xkd8.js → chunk-aqj9wfmb.js} +3 -3
- package/dist/{chunk-cx8k63by.js → chunk-g3ahp7b9.js} +12 -1
- package/dist/chunk-gg2dcqbg.js +458 -0
- package/dist/{chunk-73efzaf1.js → chunk-jeqsdcj1.js} +30 -13
- package/dist/{chunk-czj9nfrz.js → chunk-ksfxqd8s.js} +500 -41
- package/dist/{chunk-p978qj9m.js → chunk-mnmqyq7d.js} +565 -39
- package/dist/{chunk-4sepcfpy.js → chunk-np4jd070.js} +155 -3
- package/dist/{chunk-v414b5pp.js → chunk-nppgxh6c.js} +2 -2
- package/dist/chunk-nq57fdnq.js +106 -0
- package/dist/{chunk-sygeb9qb.js → chunk-pqe7q1s7.js} +1 -1
- package/dist/{chunk-w2m9xkks.js → chunk-t5abqsva.js} +199 -72
- package/dist/{chunk-8gywfw5n.js → chunk-t91zt5f0.js} +2 -51
- package/dist/{chunk-vax4zspw.js → chunk-vqkb70d7.js} +3 -3
- package/dist/chunk-vx7dy07y.js +26 -0
- package/dist/pinomad.js +19 -12
- package/package.json +2 -1
- package/web/assets/astro-DOly5024.js +1 -0
- package/web/assets/c-BIGW1oBm.js +1 -0
- package/web/assets/core-DnpzcQzs.js +4 -0
- package/web/assets/cpp-DddhVWhK.js +1 -0
- package/web/assets/csharp-B_TYUkTI.js +1 -0
- package/web/assets/css-Z72CF80r.js +1 -0
- package/web/assets/dart-CtKP3W-j.js +1 -0
- package/web/assets/diff-D97Zzqfu.js +1 -0
- package/web/assets/dockerfile-BcOcwvcX.js +1 -0
- package/web/assets/elixir-DkJLSxtU.js +1 -0
- package/web/assets/engine-javascript-BHPwbUfN.js +141 -0
- package/web/assets/engine-oniguruma-CQjQPVHy.js +1 -0
- package/web/assets/fish-BvzEVeQv.js +1 -0
- package/web/assets/go-C27-OAKa.js +1 -0
- package/web/assets/graphql-ChdNCCLP.js +1 -0
- package/web/assets/haskell-Df6bDoY_.js +1 -0
- package/web/assets/hcl-BWvSN4gD.js +1 -0
- package/web/assets/highlighted-diff-Dn5ifsvK.js +175 -0
- package/web/assets/highlights-DnHv6NBM.js +4 -0
- package/web/assets/highlights-themes-CUdrlZk3.js +1 -0
- package/web/assets/html-BlS82ilI.js +1 -0
- package/web/assets/{index-DoyHMPwf.css → index-BV0ecolo.css} +1 -1
- package/web/assets/index-DNsTTgPE.js +396 -0
- package/web/assets/ini-BEwlwnbL.js +1 -0
- package/web/assets/java-CylS5w8V.js +1 -0
- package/web/assets/javascript-wDzz0qaB.js +1 -0
- package/web/assets/json-Cp-IABpG.js +1 -0
- package/web/assets/jsonc-Des-eS-w.js +1 -0
- package/web/assets/jsx-g9-lgVsj.js +1 -0
- package/web/assets/kotlin-BdnUsdx6.js +1 -0
- package/web/assets/less-B1dDrJ26.js +1 -0
- package/web/assets/lua-BaeVxFsk.js +1 -0
- package/web/assets/make-CHLpvVh8.js +1 -0
- package/web/assets/markdown-Cvjx9yec.js +1 -0
- package/web/assets/nix-CwoSXNpI.js +1 -0
- package/web/assets/objective-c-DXmwc3jG.js +1 -0
- package/web/assets/php-DoruYMF0.js +1 -0
- package/web/assets/pierre-dark-CyvmCCZW.js +1 -0
- package/web/assets/pierre-dark-VKo95ZgA.js +1 -0
- package/web/assets/pierre-light-480U9XYS.js +1 -0
- package/web/assets/pierre-light-BVSW-Xev.js +1 -0
- package/web/assets/postcss-DnzrXTVv.js +1 -0
- package/web/assets/powershell-Dd0kTxKP.js +1 -0
- package/web/assets/prisma-Vru482bI.js +1 -0
- package/web/assets/proto-C7zT0LnQ.js +1 -0
- package/web/assets/python-B6aJPvgy.js +1 -0
- package/web/assets/ruby-B43yHlf9.js +1 -0
- package/web/assets/rust-DPvrY3IQ.js +1 -0
- package/web/assets/scala-CqE71os6.js +1 -0
- package/web/assets/scss-Cw6XMfVs.js +1 -0
- package/web/assets/shellscript-Yzrsuije.js +1 -0
- package/web/assets/shiki-BuPP5HCg.js +2 -0
- package/web/assets/shiki-langs-FJk0v0Ga.js +2 -0
- package/web/assets/shiki-wasm-CgFRq91U.js +1 -0
- package/web/assets/sql-DkvoVjww.js +1 -0
- package/web/assets/stream-tokenizer-Bl6bisIa.js +4 -0
- package/web/assets/svelte-DoIXUgJc.js +1 -0
- package/web/assets/swift-C2oV4EkX.js +1 -0
- package/web/assets/terraform-BETggiCN.js +1 -0
- package/web/assets/theming-themes-BL_CC-Mm.js +1 -0
- package/web/assets/toml-vGWfd6FD.js +1 -0
- package/web/assets/tsx-COt5Ahok.js +1 -0
- package/web/assets/typescript-BPQ3VLAy.js +1 -0
- package/web/assets/vue-CwSeJimo.js +1 -0
- package/web/assets/xml-sdJ4AIDG.js +1 -0
- package/web/assets/xterm-view-6GBZ9nXN.css +32 -0
- package/web/assets/xterm-view-ZsuzJb2C.js +38 -0
- package/web/assets/yaml-Buea-lGh.js +1 -0
- package/web/assets/zig-VOosw3JB.js +1 -0
- package/web/index.html +2 -2
- package/dist/chunk-bhtx2c8a.js +0 -16
- package/dist/chunk-c05g401k.js +0 -170
- package/web/assets/index-BdBjP1qJ.js +0 -395
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
joinServer,
|
|
4
|
+
openServiceSlot,
|
|
5
|
+
writeService
|
|
6
|
+
} from "./chunk-gg2dcqbg.js";
|
|
7
|
+
import"./chunk-7mn38n4f.js";
|
|
8
|
+
import"./chunk-nppgxh6c.js";
|
|
9
|
+
import"./chunk-t91zt5f0.js";
|
|
10
|
+
import {
|
|
11
|
+
normalizeOrigin,
|
|
12
|
+
readRemovalNotice,
|
|
13
|
+
readServerConfig
|
|
14
|
+
} from "./chunk-nq57fdnq.js";
|
|
15
|
+
import"./chunk-g3ahp7b9.js";
|
|
16
|
+
import {
|
|
17
|
+
argValue,
|
|
18
|
+
serviceManager,
|
|
19
|
+
withoutArg,
|
|
20
|
+
withoutRelayArgs
|
|
21
|
+
} from "./chunk-t5abqsva.js";
|
|
22
|
+
import"./chunk-np4jd070.js";
|
|
23
|
+
import"./chunk-kzbzacz9.js";
|
|
24
|
+
import"./chunk-47ff1d1t.js";
|
|
25
|
+
import"./chunk-pqe7q1s7.js";
|
|
26
|
+
import {
|
|
27
|
+
DEFAULT_DATA_DIR
|
|
28
|
+
} from "./chunk-ngf1zatm.js";
|
|
29
|
+
import {
|
|
30
|
+
commandHint
|
|
31
|
+
} from "./chunk-7wj0jh3t.js";
|
|
32
|
+
import"./chunk-df32avw6.js";
|
|
33
|
+
|
|
34
|
+
// apps/host/src/cli/up.ts
|
|
35
|
+
import { resolve } from "node:path";
|
|
36
|
+
import { createInterface } from "node:readline/promises";
|
|
37
|
+
import { parseArgs } from "node:util";
|
|
38
|
+
var OFFICIAL_SERVER_ORIGIN = "https://app.pinomad.si";
|
|
39
|
+
var DEFAULT_REMOTE_PORT = "7422";
|
|
40
|
+
var message = (error) => error instanceof Error ? error.message : String(error);
|
|
41
|
+
function resolveReach(flags, current) {
|
|
42
|
+
if (flags.server === undefined && flags.lan === undefined)
|
|
43
|
+
return;
|
|
44
|
+
if (current !== undefined)
|
|
45
|
+
return { server: flags.server ?? current.server, lan: flags.lan ?? current.lan };
|
|
46
|
+
return { server: flags.server ?? !flags.lan, lan: flags.lan ?? !flags.server };
|
|
47
|
+
}
|
|
48
|
+
var lastRemovedOrigin = async (dataDir) => (await readRemovalNotice(dataDir).catch(() => {
|
|
49
|
+
return;
|
|
50
|
+
}))?.origin;
|
|
51
|
+
async function currentReach(dataDir, deps) {
|
|
52
|
+
const slot = await openServiceSlot(dataDir, deps?.manager ?? serviceManager());
|
|
53
|
+
const config = await readServerConfig(dataDir);
|
|
54
|
+
if (config === undefined && !slot.state.installed)
|
|
55
|
+
return;
|
|
56
|
+
return {
|
|
57
|
+
server: config !== undefined,
|
|
58
|
+
lan: argValue(slot.previous?.hostArgs ?? [], "--remote-port") !== undefined
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function withLan(hostArgs, port) {
|
|
62
|
+
if (port === undefined)
|
|
63
|
+
return withoutArg(withoutArg(hostArgs, "--remote-port"), "--public-url");
|
|
64
|
+
if (argValue(hostArgs, "--remote-port") === port)
|
|
65
|
+
return hostArgs;
|
|
66
|
+
return [...withoutArg(hostArgs, "--remote-port"), "--remote-port", port];
|
|
67
|
+
}
|
|
68
|
+
async function upHost(args, deps) {
|
|
69
|
+
const dataDir = resolve(args.dataDir);
|
|
70
|
+
const { reach } = args;
|
|
71
|
+
if (!reach.server && !reach.lan)
|
|
72
|
+
throw new Error("nothing to set up: choose the server, the LAN, or both");
|
|
73
|
+
const port = args.remotePort;
|
|
74
|
+
if (port !== undefined && !(/^\d+$/.test(port) && Number(port) >= 1 && Number(port) <= 65535)) {
|
|
75
|
+
throw new Error(`--remote-port must be a port number from 1 to 65535, got ${port}`);
|
|
76
|
+
}
|
|
77
|
+
const manager = deps?.manager ?? serviceManager();
|
|
78
|
+
const slot = await openServiceSlot(dataDir, manager);
|
|
79
|
+
const config = await readServerConfig(dataDir);
|
|
80
|
+
const origin = normalizeOrigin(args.origin ?? config?.origin ?? await lastRemovedOrigin(dataDir) ?? OFFICIAL_SERVER_ORIGIN);
|
|
81
|
+
if (reach.server && config !== undefined && normalizeOrigin(config.origin) !== origin) {
|
|
82
|
+
throw new Error(`this host is joined to ${config.origin} — run \`${commandHint("leave")}\` first to join ${origin}, ` + `or leave out --origin to stay`);
|
|
83
|
+
}
|
|
84
|
+
const lanPort = reach.lan ? args.remotePort ?? argValue(slot.previous?.hostArgs ?? [], "--remote-port") ?? DEFAULT_REMOTE_PORT : undefined;
|
|
85
|
+
const lan = (hostArgs) => withLan(hostArgs, lanPort);
|
|
86
|
+
const notes = [];
|
|
87
|
+
if (reach.server && config === undefined) {
|
|
88
|
+
const joined = await joinServer({ origin, dataDir, code: args.code, editHostArgs: lan }, { ...deps, manager });
|
|
89
|
+
return {
|
|
90
|
+
joined: { origin: joined.origin, username: joined.username, fresh: true },
|
|
91
|
+
...lanPort === undefined ? {} : { lanPort },
|
|
92
|
+
service: joined.service,
|
|
93
|
+
notes
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
const edit = reach.server ? (hostArgs) => lan(withoutRelayArgs(hostArgs)) : lan;
|
|
97
|
+
const service = await writeService(slot, edit, { changed: reach.server });
|
|
98
|
+
if (!reach.server && config !== undefined) {
|
|
99
|
+
notes.push(`still joined to ${config.origin} — run \`${commandHint("leave")}\` to leave it`);
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
...reach.server && config !== undefined ? { joined: { origin: config.origin, ...config.username === undefined ? {} : { username: config.username }, fresh: false } } : {},
|
|
103
|
+
...lanPort === undefined ? {} : { lanPort },
|
|
104
|
+
service,
|
|
105
|
+
notes
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
async function askOnTerminal(question) {
|
|
109
|
+
const terminal = createInterface({ input: process.stdin, output: process.stdout });
|
|
110
|
+
try {
|
|
111
|
+
return await terminal.question(question);
|
|
112
|
+
} finally {
|
|
113
|
+
terminal.close();
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
var CHOICES = [
|
|
117
|
+
{ server: true, lan: false },
|
|
118
|
+
{ server: false, lan: true },
|
|
119
|
+
{ server: true, lan: true }
|
|
120
|
+
];
|
|
121
|
+
async function askReach(origin, fallback, ask) {
|
|
122
|
+
const preset = CHOICES.findIndex((choice) => choice.server === fallback.server && choice.lan === fallback.lan) + 1;
|
|
123
|
+
let question = `How should your other devices reach this host?
|
|
124
|
+
` + ` 1) Through ${origin}: from anywhere, with push notifications
|
|
125
|
+
` + ` 2) Only on your local network and tailnet
|
|
126
|
+
` + ` 3) Both
|
|
127
|
+
` + `Choose 1, 2 or 3 [${preset}]: `;
|
|
128
|
+
for (;; ) {
|
|
129
|
+
const answer = (await ask(question)).trim();
|
|
130
|
+
if (answer === "")
|
|
131
|
+
return CHOICES[preset - 1];
|
|
132
|
+
const picked = CHOICES[Number(answer) - 1];
|
|
133
|
+
if (/^[123]$/.test(answer) && picked !== undefined)
|
|
134
|
+
return picked;
|
|
135
|
+
question = "Choose 1, 2 or 3: ";
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
var FLAGS = `choose with flags:
|
|
139
|
+
--server [--origin URL] through a PiNomad server (default ${OFFICIAL_SERVER_ORIGIN})
|
|
140
|
+
--lan [--remote-port N] only on the local network and tailnet (default port ${DEFAULT_REMOTE_PORT})
|
|
141
|
+
--server --lan both
|
|
142
|
+
--yes keep what this host has, or the server on a new host`;
|
|
143
|
+
async function main(argv, deps) {
|
|
144
|
+
const { values } = parseArgs({
|
|
145
|
+
args: [...argv],
|
|
146
|
+
allowNegative: true,
|
|
147
|
+
options: {
|
|
148
|
+
server: { type: "boolean" },
|
|
149
|
+
lan: { type: "boolean" },
|
|
150
|
+
yes: { type: "boolean", short: "y" },
|
|
151
|
+
origin: { type: "string" },
|
|
152
|
+
code: { type: "boolean" },
|
|
153
|
+
"remote-port": { type: "string" },
|
|
154
|
+
"data-dir": { type: "string" }
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
const log = deps?.log ?? ((line) => console.log(line));
|
|
158
|
+
try {
|
|
159
|
+
const dataDir = resolve(values["data-dir"] ?? DEFAULT_DATA_DIR);
|
|
160
|
+
const origin = normalizeOrigin(values.origin ?? (await readServerConfig(dataDir))?.origin ?? await lastRemovedOrigin(dataDir) ?? OFFICIAL_SERVER_ORIGIN);
|
|
161
|
+
const current = await currentReach(dataDir, deps);
|
|
162
|
+
let reach = resolveReach({ server: values.server, lan: values.lan }, current);
|
|
163
|
+
if (reach === undefined) {
|
|
164
|
+
const fallback = current !== undefined && (current.server || current.lan) ? current : { server: true, lan: false };
|
|
165
|
+
if (values.yes === true) {
|
|
166
|
+
reach = fallback;
|
|
167
|
+
} else if (!(deps?.interactive ?? (process.stdin.isTTY && process.stdout.isTTY))) {
|
|
168
|
+
console.error(`${commandHint("up")}: no terminal to ask how other devices reach this host — ${FLAGS}`);
|
|
169
|
+
process.exitCode = 2;
|
|
170
|
+
return;
|
|
171
|
+
} else {
|
|
172
|
+
reach = await askReach(origin, fallback, deps?.ask ?? askOnTerminal);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
if (!reach.server && !reach.lan) {
|
|
176
|
+
console.error(`${commandHint("up")}: neither the server nor the LAN would be on — ` + `\`${commandHint("service")} install\` runs a host only this machine can reach`);
|
|
177
|
+
process.exitCode = 2;
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
const outcome = await upHost({
|
|
181
|
+
dataDir,
|
|
182
|
+
origin,
|
|
183
|
+
reach,
|
|
184
|
+
...values["remote-port"] === undefined ? {} : { remotePort: values["remote-port"] },
|
|
185
|
+
...values.code === true ? { code: true } : {}
|
|
186
|
+
}, deps);
|
|
187
|
+
if (outcome.joined !== undefined) {
|
|
188
|
+
const who = outcome.joined.username ?? "an account";
|
|
189
|
+
log(outcome.joined.fresh ? `joined ${who} at ${outcome.joined.origin}` : `already joined ${who} at ${outcome.joined.origin}`);
|
|
190
|
+
log(`Sign in at ${outcome.joined.origin} on your other devices; they pair with this host on their own.`);
|
|
191
|
+
}
|
|
192
|
+
if (outcome.lanPort !== undefined) {
|
|
193
|
+
log(`LAN and tailnet: port ${outcome.lanPort}. Pair a device with \`${commandHint("pair")}\`.`);
|
|
194
|
+
}
|
|
195
|
+
for (const note of outcome.notes)
|
|
196
|
+
log(`note: ${note}`);
|
|
197
|
+
if (outcome.service === "installed")
|
|
198
|
+
log("service installed and started");
|
|
199
|
+
else if (outcome.service === "updated")
|
|
200
|
+
log("service updated; host restarted when idle");
|
|
201
|
+
else if (outcome.service === "unchanged")
|
|
202
|
+
log("service already running with these settings");
|
|
203
|
+
else {
|
|
204
|
+
console.error(`the service restart did not finish — check \`${commandHint("status")}\``);
|
|
205
|
+
process.exitCode = 1;
|
|
206
|
+
}
|
|
207
|
+
} catch (error) {
|
|
208
|
+
console.error(message(error));
|
|
209
|
+
process.exitCode = 1;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
if (false)
|
|
213
|
+
;
|
|
214
|
+
export {
|
|
215
|
+
upHost,
|
|
216
|
+
resolveReach,
|
|
217
|
+
main,
|
|
218
|
+
OFFICIAL_SERVER_ORIGIN,
|
|
219
|
+
DEFAULT_REMOTE_PORT
|
|
220
|
+
};
|
|
@@ -6,10 +6,10 @@ import {
|
|
|
6
6
|
relayWsBase,
|
|
7
7
|
signRelayChallenge,
|
|
8
8
|
signRelayChallengeV2
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-g3ahp7b9.js";
|
|
10
10
|
import {
|
|
11
11
|
toBase64Url
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-pqe7q1s7.js";
|
|
13
13
|
|
|
14
14
|
// apps/host/src/cli/server-ops.ts
|
|
15
15
|
import { WebSocket } from "ws";
|
|
@@ -130,4 +130,4 @@ async function runServerOperation(options) {
|
|
|
130
130
|
});
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
-
export { assertSecureServerOrigin, probeServerAccounts, runServerOperation };
|
|
133
|
+
export { isSecureServerOrigin, assertSecureServerOrigin, probeServerAccounts, runServerOperation };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// apps/host/src/distribution.ts
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
|
-
var packagedVersion = "0.
|
|
3
|
+
var packagedVersion = "0.12.0";
|
|
4
4
|
var webRoot = fileURLToPath(new URL(packagedVersion === undefined ? "../../web/dist" : "../web/", import.meta.url));
|
|
5
5
|
var hostEntry = packagedVersion === undefined ? { script: fileURLToPath(new URL("./main.ts", import.meta.url)), args: [] } : { script: fileURLToPath(new URL("./pinomad.js", import.meta.url)), args: ["host"] };
|
|
6
6
|
var commandHint = (name) => packagedVersion === undefined ? `bun run ${name}` : `pinomad ${name}`;
|
|
@@ -3,30 +3,35 @@ import {
|
|
|
3
3
|
assertSecureServerOrigin,
|
|
4
4
|
probeServerAccounts,
|
|
5
5
|
runServerOperation
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-7mn38n4f.js";
|
|
7
7
|
import {
|
|
8
8
|
loadHostKey,
|
|
9
|
-
loadRelayKey
|
|
9
|
+
loadRelayKey
|
|
10
|
+
} from "./chunk-t91zt5f0.js";
|
|
11
|
+
import {
|
|
12
|
+
readRemovalNotice,
|
|
10
13
|
readServerConfig,
|
|
11
14
|
removeServerConfig
|
|
12
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-nq57fdnq.js";
|
|
13
16
|
import {
|
|
14
17
|
relayHostId
|
|
15
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-g3ahp7b9.js";
|
|
16
19
|
import {
|
|
17
20
|
argValue,
|
|
18
21
|
restartService,
|
|
19
22
|
serviceManager,
|
|
20
23
|
withoutRelayArgs
|
|
21
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-t5abqsva.js";
|
|
25
|
+
import"./chunk-np4jd070.js";
|
|
22
26
|
import"./chunk-kzbzacz9.js";
|
|
23
|
-
import"./chunk-
|
|
24
|
-
import"./chunk-
|
|
25
|
-
import"./chunk-jgd38rna.js";
|
|
26
|
-
import"./chunk-sygeb9qb.js";
|
|
27
|
+
import"./chunk-47ff1d1t.js";
|
|
28
|
+
import"./chunk-pqe7q1s7.js";
|
|
27
29
|
import {
|
|
28
30
|
DEFAULT_DATA_DIR
|
|
29
31
|
} from "./chunk-ngf1zatm.js";
|
|
32
|
+
import {
|
|
33
|
+
commandHint
|
|
34
|
+
} from "./chunk-7wj0jh3t.js";
|
|
30
35
|
import"./chunk-df32avw6.js";
|
|
31
36
|
|
|
32
37
|
// apps/host/src/cli/leave.ts
|
|
@@ -37,8 +42,13 @@ var message = (error) => error instanceof Error ? error.message : String(error);
|
|
|
37
42
|
async function leaveServer(args, deps) {
|
|
38
43
|
const dataDir = resolve(args.dataDir);
|
|
39
44
|
const config = await readServerConfig(dataDir);
|
|
40
|
-
if (config === undefined)
|
|
41
|
-
|
|
45
|
+
if (config === undefined) {
|
|
46
|
+
const removed = await readRemovalNotice(dataDir);
|
|
47
|
+
if (removed === undefined)
|
|
48
|
+
throw new Error(`not joined — no server.json in ${dataDir}`);
|
|
49
|
+
await removeServerConfig(dataDir);
|
|
50
|
+
return { origin: removed.origin, warnings: [], notes: ["the account had already removed this host"] };
|
|
51
|
+
}
|
|
42
52
|
const origin = config.origin;
|
|
43
53
|
const warnings = [];
|
|
44
54
|
const notes = [];
|
|
@@ -76,7 +86,10 @@ async function leaveServer(args, deps) {
|
|
|
76
86
|
await removeServerConfig(dataDir);
|
|
77
87
|
const manager = deps?.manager ?? serviceManager();
|
|
78
88
|
try {
|
|
79
|
-
const
|
|
89
|
+
const state = await manager.state().catch(() => {
|
|
90
|
+
return;
|
|
91
|
+
});
|
|
92
|
+
const installed = state?.installed === true;
|
|
80
93
|
const previous = installed ? await manager.read() : undefined;
|
|
81
94
|
if (!installed) {
|
|
82
95
|
notes.push("no service installed — restart any running host so it stops dialing the server");
|
|
@@ -85,19 +98,30 @@ async function leaveServer(args, deps) {
|
|
|
85
98
|
} else {
|
|
86
99
|
const stripped = previous === undefined ? undefined : { ...previous, hostArgs: withoutRelayArgs(previous.hostArgs) };
|
|
87
100
|
const rewriting = stripped !== undefined && stripped.hostArgs.length !== previous.hostArgs.length;
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
argv: ["--data-dir", dataDir, ...port === undefined ? [] : ["--url", `ws://127.0.0.1:${port}`]],
|
|
92
|
-
manager,
|
|
93
|
-
...rewriting ? {
|
|
94
|
-
restart: async () => {
|
|
101
|
+
if (state.stopped) {
|
|
102
|
+
if (rewriting) {
|
|
103
|
+
try {
|
|
95
104
|
await manager.install(stripped);
|
|
105
|
+
} finally {
|
|
106
|
+
await manager.stop();
|
|
96
107
|
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
108
|
+
}
|
|
109
|
+
notes.push(`the service is stopped and stays off until \`${commandHint("service")} start\``);
|
|
110
|
+
} else {
|
|
111
|
+
const port = argValue(previous?.hostArgs ?? [], "--port");
|
|
112
|
+
const code = await restartService({
|
|
113
|
+
force: false,
|
|
114
|
+
argv: ["--data-dir", dataDir, ...port === undefined ? [] : ["--url", `ws://127.0.0.1:${port}`]],
|
|
115
|
+
manager,
|
|
116
|
+
...rewriting ? {
|
|
117
|
+
restart: async () => {
|
|
118
|
+
await manager.install(stripped);
|
|
119
|
+
}
|
|
120
|
+
} : {}
|
|
121
|
+
});
|
|
122
|
+
if (code !== 0)
|
|
123
|
+
warnings.push("the service restart did not finish — check `service status`");
|
|
124
|
+
}
|
|
101
125
|
}
|
|
102
126
|
} catch (error) {
|
|
103
127
|
warnings.push(`could not update the service definition: ${message(error)} — remove --relay from it and restart manually`);
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
fromBase64Url,
|
|
4
4
|
parseEndpointSet,
|
|
5
5
|
toBase64Url
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-pqe7q1s7.js";
|
|
7
7
|
|
|
8
8
|
// packages/protocol/src/relay.ts
|
|
9
9
|
import { ed25519 } from "@noble/curves/ed25519.js";
|
|
@@ -15,6 +15,7 @@ var RELAY_CLOSE = {
|
|
|
15
15
|
handshakeTimeout: 4608,
|
|
16
16
|
replaced: 4609,
|
|
17
17
|
acceptTimeout: 4610,
|
|
18
|
+
hostRemoved: 4611,
|
|
18
19
|
tooManyConnections: 4629,
|
|
19
20
|
trafficLimit: 4630
|
|
20
21
|
};
|
|
@@ -467,6 +468,14 @@ function startRelayLink(options) {
|
|
|
467
468
|
}
|
|
468
469
|
if (stopped)
|
|
469
470
|
return;
|
|
471
|
+
if (code === RELAY_CLOSE.hostRemoved) {
|
|
472
|
+
stopped = true;
|
|
473
|
+
setState({
|
|
474
|
+
status: "removed",
|
|
475
|
+
reason: `relay ${origin}: the account removed this host (${hostId}); join it again with \`pinomad up\` (${code})`
|
|
476
|
+
});
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
470
479
|
const rejection = REJECTION_REASONS[code];
|
|
471
480
|
if (rejection !== undefined) {
|
|
472
481
|
const reason = `relay ${origin}: ${rejection(hostId)} (${code})`;
|
|
@@ -494,6 +503,8 @@ function startRelayLink(options) {
|
|
|
494
503
|
origin,
|
|
495
504
|
state: () => state,
|
|
496
505
|
sendPush(request) {
|
|
506
|
+
if (state.status === "removed")
|
|
507
|
+
return Promise.resolve({ result: "unavailable", reason: "the account removed this host" });
|
|
497
508
|
const socket = control;
|
|
498
509
|
if (stopped || socket === undefined || socket.readyState !== WebSocket.OPEN || state.status !== "registered") {
|
|
499
510
|
return Promise.resolve({ result: "retry", reason: "control disconnected" });
|