pinomad 0.9.1 → 0.11.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-v414b5pp.js → chunk-44pnts98.js} +2 -2
- package/dist/{chunk-nj5gz6qh.js → chunk-4dcs8sbj.js} +11 -9
- package/dist/{chunk-n8cz7skh.js → chunk-67gq282t.js} +53 -32
- package/dist/{chunk-azarj0f4.js → chunk-6d16c2fv.js} +21 -11
- package/dist/{chunk-cx8jgpdt.js → chunk-9h5vawnm.js} +1040 -79
- package/dist/{chunk-029mmh7d.js → chunk-as6pyf00.js} +3 -3
- package/dist/chunk-b457q0tm.js +70 -0
- package/dist/chunk-etf7ef97.js +55 -0
- package/dist/chunk-greb3dp6.js +22 -0
- package/dist/chunk-gtdpjqa3.js +317 -0
- package/dist/chunk-h5q2y57m.js +20 -0
- package/dist/{chunk-4sepcfpy.js → chunk-jt34g8st.js} +2 -2
- package/dist/chunk-n1m1tjrk.js +214 -0
- package/dist/{chunk-3p1eysm9.js → chunk-ncbqa8jk.js} +5 -4
- package/dist/{chunk-sygeb9qb.js → chunk-pqe7q1s7.js} +1 -1
- package/dist/{chunk-fqgvf8v0.js → chunk-sd5fkxjj.js} +1 -1
- package/dist/{chunk-5gp9svzs.js → chunk-t91zt5f0.js} +4 -53
- package/dist/{chunk-vax4zspw.js → chunk-tj57aqav.js} +3 -3
- package/dist/{chunk-32g3m2h0.js → chunk-vvj9b1gc.js} +29 -24
- package/dist/{chunk-jgd38rna.js → chunk-xqycs43g.js} +171 -171
- package/dist/{chunk-khcpv54k.js → chunk-y127fe1a.js} +59 -4
- package/dist/pinomad.js +18 -12
- package/package.json +1 -1
- package/web/assets/index-BhHrKpoo.js +395 -0
- package/web/index.html +1 -1
- package/dist/chunk-3gcpzpjq.js +0 -16
- package/dist/chunk-n58m5hgh.js +0 -170
- package/web/assets/index-1g60bhv2.js +0 -395
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
joinServer,
|
|
4
|
+
openServiceSlot,
|
|
5
|
+
writeService
|
|
6
|
+
} from "./chunk-gtdpjqa3.js";
|
|
7
|
+
import"./chunk-ncbqa8jk.js";
|
|
8
|
+
import"./chunk-44pnts98.js";
|
|
9
|
+
import"./chunk-t91zt5f0.js";
|
|
10
|
+
import {
|
|
11
|
+
normalizeOrigin,
|
|
12
|
+
readServerConfig
|
|
13
|
+
} from "./chunk-etf7ef97.js";
|
|
14
|
+
import"./chunk-y127fe1a.js";
|
|
15
|
+
import {
|
|
16
|
+
argValue,
|
|
17
|
+
serviceManager,
|
|
18
|
+
withoutArg,
|
|
19
|
+
withoutRelayArgs
|
|
20
|
+
} from "./chunk-vvj9b1gc.js";
|
|
21
|
+
import"./chunk-jt34g8st.js";
|
|
22
|
+
import"./chunk-kzbzacz9.js";
|
|
23
|
+
import"./chunk-xqycs43g.js";
|
|
24
|
+
import"./chunk-pqe7q1s7.js";
|
|
25
|
+
import {
|
|
26
|
+
DEFAULT_DATA_DIR
|
|
27
|
+
} from "./chunk-ngf1zatm.js";
|
|
28
|
+
import {
|
|
29
|
+
commandHint
|
|
30
|
+
} from "./chunk-sd5fkxjj.js";
|
|
31
|
+
import"./chunk-df32avw6.js";
|
|
32
|
+
|
|
33
|
+
// apps/host/src/cli/up.ts
|
|
34
|
+
import { resolve } from "node:path";
|
|
35
|
+
import { createInterface } from "node:readline/promises";
|
|
36
|
+
import { parseArgs } from "node:util";
|
|
37
|
+
var OFFICIAL_SERVER_ORIGIN = "https://app.pinomad.si";
|
|
38
|
+
var DEFAULT_REMOTE_PORT = "7422";
|
|
39
|
+
var message = (error) => error instanceof Error ? error.message : String(error);
|
|
40
|
+
function resolveReach(flags, current) {
|
|
41
|
+
if (flags.server === undefined && flags.lan === undefined)
|
|
42
|
+
return;
|
|
43
|
+
if (current !== undefined)
|
|
44
|
+
return { server: flags.server ?? current.server, lan: flags.lan ?? current.lan };
|
|
45
|
+
return { server: flags.server ?? !flags.lan, lan: flags.lan ?? !flags.server };
|
|
46
|
+
}
|
|
47
|
+
async function currentReach(dataDir, deps) {
|
|
48
|
+
const slot = await openServiceSlot(dataDir, deps?.manager ?? serviceManager());
|
|
49
|
+
const config = await readServerConfig(dataDir);
|
|
50
|
+
if (config === undefined && !slot.state.installed)
|
|
51
|
+
return;
|
|
52
|
+
return {
|
|
53
|
+
server: config !== undefined,
|
|
54
|
+
lan: argValue(slot.previous?.hostArgs ?? [], "--remote-port") !== undefined
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function withLan(hostArgs, port) {
|
|
58
|
+
if (port === undefined)
|
|
59
|
+
return withoutArg(withoutArg(hostArgs, "--remote-port"), "--public-url");
|
|
60
|
+
if (argValue(hostArgs, "--remote-port") === port)
|
|
61
|
+
return hostArgs;
|
|
62
|
+
return [...withoutArg(hostArgs, "--remote-port"), "--remote-port", port];
|
|
63
|
+
}
|
|
64
|
+
async function upHost(args, deps) {
|
|
65
|
+
const dataDir = resolve(args.dataDir);
|
|
66
|
+
const { reach } = args;
|
|
67
|
+
if (!reach.server && !reach.lan)
|
|
68
|
+
throw new Error("nothing to set up: choose the server, the LAN, or both");
|
|
69
|
+
const port = args.remotePort;
|
|
70
|
+
if (port !== undefined && !(/^\d+$/.test(port) && Number(port) >= 1 && Number(port) <= 65535)) {
|
|
71
|
+
throw new Error(`--remote-port must be a port number from 1 to 65535, got ${port}`);
|
|
72
|
+
}
|
|
73
|
+
const manager = deps?.manager ?? serviceManager();
|
|
74
|
+
const slot = await openServiceSlot(dataDir, manager);
|
|
75
|
+
const config = await readServerConfig(dataDir);
|
|
76
|
+
const origin = normalizeOrigin(args.origin ?? config?.origin ?? OFFICIAL_SERVER_ORIGIN);
|
|
77
|
+
if (reach.server && config !== undefined && normalizeOrigin(config.origin) !== origin) {
|
|
78
|
+
throw new Error(`this host is joined to ${config.origin} — run \`${commandHint("leave")}\` first to join ${origin}, ` + `or leave out --origin to stay`);
|
|
79
|
+
}
|
|
80
|
+
const lanPort = reach.lan ? args.remotePort ?? argValue(slot.previous?.hostArgs ?? [], "--remote-port") ?? DEFAULT_REMOTE_PORT : undefined;
|
|
81
|
+
const lan = (hostArgs) => withLan(hostArgs, lanPort);
|
|
82
|
+
const notes = [];
|
|
83
|
+
if (reach.server && config === undefined) {
|
|
84
|
+
const joined = await joinServer({ origin, dataDir, editHostArgs: lan }, { ...deps, manager });
|
|
85
|
+
return {
|
|
86
|
+
joined: { origin: joined.origin, username: joined.username, fresh: true },
|
|
87
|
+
...lanPort === undefined ? {} : { lanPort },
|
|
88
|
+
service: joined.service,
|
|
89
|
+
notes
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
const edit = reach.server ? (hostArgs) => lan(withoutRelayArgs(hostArgs)) : lan;
|
|
93
|
+
const service = await writeService(slot, edit, { changed: reach.server });
|
|
94
|
+
if (!reach.server && config !== undefined) {
|
|
95
|
+
notes.push(`still joined to ${config.origin} — run \`${commandHint("leave")}\` to leave it`);
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
...reach.server && config !== undefined ? { joined: { origin: config.origin, ...config.username === undefined ? {} : { username: config.username }, fresh: false } } : {},
|
|
99
|
+
...lanPort === undefined ? {} : { lanPort },
|
|
100
|
+
service,
|
|
101
|
+
notes
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
async function askOnTerminal(question) {
|
|
105
|
+
const terminal = createInterface({ input: process.stdin, output: process.stdout });
|
|
106
|
+
try {
|
|
107
|
+
return await terminal.question(question);
|
|
108
|
+
} finally {
|
|
109
|
+
terminal.close();
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
var CHOICES = [
|
|
113
|
+
{ server: true, lan: false },
|
|
114
|
+
{ server: false, lan: true },
|
|
115
|
+
{ server: true, lan: true }
|
|
116
|
+
];
|
|
117
|
+
async function askReach(origin, fallback, ask) {
|
|
118
|
+
const preset = CHOICES.findIndex((choice) => choice.server === fallback.server && choice.lan === fallback.lan) + 1;
|
|
119
|
+
let question = `How should your other devices reach this host?
|
|
120
|
+
` + ` 1) Through ${origin}: from anywhere, with push notifications
|
|
121
|
+
` + ` 2) Only on your local network and tailnet
|
|
122
|
+
` + ` 3) Both
|
|
123
|
+
` + `Choose 1, 2 or 3 [${preset}]: `;
|
|
124
|
+
for (;; ) {
|
|
125
|
+
const answer = (await ask(question)).trim();
|
|
126
|
+
if (answer === "")
|
|
127
|
+
return CHOICES[preset - 1];
|
|
128
|
+
const picked = CHOICES[Number(answer) - 1];
|
|
129
|
+
if (/^[123]$/.test(answer) && picked !== undefined)
|
|
130
|
+
return picked;
|
|
131
|
+
question = "Choose 1, 2 or 3: ";
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
var FLAGS = `choose with flags:
|
|
135
|
+
--server [--origin URL] through a PiNomad server (default ${OFFICIAL_SERVER_ORIGIN})
|
|
136
|
+
--lan [--remote-port N] only on the local network and tailnet (default port ${DEFAULT_REMOTE_PORT})
|
|
137
|
+
--server --lan both
|
|
138
|
+
--yes keep what this host has, or the server on a new host`;
|
|
139
|
+
async function main(argv, deps) {
|
|
140
|
+
const { values } = parseArgs({
|
|
141
|
+
args: [...argv],
|
|
142
|
+
allowNegative: true,
|
|
143
|
+
options: {
|
|
144
|
+
server: { type: "boolean" },
|
|
145
|
+
lan: { type: "boolean" },
|
|
146
|
+
yes: { type: "boolean", short: "y" },
|
|
147
|
+
origin: { type: "string" },
|
|
148
|
+
"remote-port": { type: "string" },
|
|
149
|
+
"data-dir": { type: "string" }
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
const log = deps?.log ?? ((line) => console.log(line));
|
|
153
|
+
try {
|
|
154
|
+
const dataDir = resolve(values["data-dir"] ?? DEFAULT_DATA_DIR);
|
|
155
|
+
const origin = normalizeOrigin(values.origin ?? (await readServerConfig(dataDir))?.origin ?? OFFICIAL_SERVER_ORIGIN);
|
|
156
|
+
const current = await currentReach(dataDir, deps);
|
|
157
|
+
let reach = resolveReach({ server: values.server, lan: values.lan }, current);
|
|
158
|
+
if (reach === undefined) {
|
|
159
|
+
const fallback = current !== undefined && (current.server || current.lan) ? current : { server: true, lan: false };
|
|
160
|
+
if (values.yes === true) {
|
|
161
|
+
reach = fallback;
|
|
162
|
+
} else if (!(deps?.interactive ?? (process.stdin.isTTY && process.stdout.isTTY))) {
|
|
163
|
+
console.error(`${commandHint("up")}: no terminal to ask how other devices reach this host — ${FLAGS}`);
|
|
164
|
+
process.exitCode = 2;
|
|
165
|
+
return;
|
|
166
|
+
} else {
|
|
167
|
+
reach = await askReach(origin, fallback, deps?.ask ?? askOnTerminal);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if (!reach.server && !reach.lan) {
|
|
171
|
+
console.error(`${commandHint("up")}: neither the server nor the LAN would be on — ` + `\`${commandHint("service")} install\` runs a host only this machine can reach`);
|
|
172
|
+
process.exitCode = 2;
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
const outcome = await upHost({
|
|
176
|
+
dataDir,
|
|
177
|
+
origin,
|
|
178
|
+
reach,
|
|
179
|
+
...values["remote-port"] === undefined ? {} : { remotePort: values["remote-port"] }
|
|
180
|
+
}, deps);
|
|
181
|
+
if (outcome.joined !== undefined) {
|
|
182
|
+
const who = outcome.joined.username ?? "an account";
|
|
183
|
+
log(outcome.joined.fresh ? `joined ${who} at ${outcome.joined.origin}` : `already joined ${who} at ${outcome.joined.origin}`);
|
|
184
|
+
log(`Sign in at ${outcome.joined.origin} on your other devices; they pair with this host on their own.`);
|
|
185
|
+
}
|
|
186
|
+
if (outcome.lanPort !== undefined) {
|
|
187
|
+
log(`LAN and tailnet: port ${outcome.lanPort}. Pair a device with \`${commandHint("pair")}\`.`);
|
|
188
|
+
}
|
|
189
|
+
for (const note of outcome.notes)
|
|
190
|
+
log(`note: ${note}`);
|
|
191
|
+
if (outcome.service === "installed")
|
|
192
|
+
log("service installed and started");
|
|
193
|
+
else if (outcome.service === "updated")
|
|
194
|
+
log("service updated; host restarted when idle");
|
|
195
|
+
else if (outcome.service === "unchanged")
|
|
196
|
+
log("service already running with these settings");
|
|
197
|
+
else {
|
|
198
|
+
console.error(`the service restart did not finish — check \`${commandHint("status")}\``);
|
|
199
|
+
process.exitCode = 1;
|
|
200
|
+
}
|
|
201
|
+
} catch (error) {
|
|
202
|
+
console.error(message(error));
|
|
203
|
+
process.exitCode = 1;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
if (false)
|
|
207
|
+
;
|
|
208
|
+
export {
|
|
209
|
+
upHost,
|
|
210
|
+
resolveReach,
|
|
211
|
+
main,
|
|
212
|
+
OFFICIAL_SERVER_ORIGIN,
|
|
213
|
+
DEFAULT_REMOTE_PORT
|
|
214
|
+
};
|
|
@@ -6,10 +6,10 @@ import {
|
|
|
6
6
|
relayWsBase,
|
|
7
7
|
signRelayChallenge,
|
|
8
8
|
signRelayChallengeV2
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-y127fe1a.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";
|
|
@@ -55,6 +55,7 @@ function isSecureServerOrigin(origin) {
|
|
|
55
55
|
const loopback = host === "localhost" || host.endsWith(".localhost") || ipv4Loopback || host === "::1" || host === "[::1]";
|
|
56
56
|
return url.protocol === "https:" || url.protocol === "http:" && loopback;
|
|
57
57
|
}
|
|
58
|
+
var DEVICE_HOST_STATES = new Set(["registered", "revoking", "revoked"]);
|
|
58
59
|
|
|
59
60
|
// apps/host/src/cli/server-ops.ts
|
|
60
61
|
function assertSecureServerOrigin(origin) {
|
|
@@ -122,11 +123,11 @@ async function runServerOperation(options) {
|
|
|
122
123
|
finish(() => reject(new Error(`${origin} ignored the operation — the server is too old for accounts; upgrade it first`)));
|
|
123
124
|
return;
|
|
124
125
|
}
|
|
125
|
-
if (frame.t === "incoming" || frame.t === "pairing-request" || frame.t === "push-result")
|
|
126
|
+
if (frame.t === "incoming" || frame.t === "pairing-request" || frame.t === "push-result" || frame.t === "revoke-device")
|
|
126
127
|
return;
|
|
127
128
|
finish(() => resolve(frame));
|
|
128
129
|
});
|
|
129
130
|
});
|
|
130
131
|
}
|
|
131
132
|
|
|
132
|
-
export { assertSecureServerOrigin, probeServerAccounts, runServerOperation };
|
|
133
|
+
export { isSecureServerOrigin, assertSecureServerOrigin, probeServerAccounts, runServerOperation };
|
|
@@ -427,4 +427,4 @@ function concatParts(parts) {
|
|
|
427
427
|
return out;
|
|
428
428
|
}
|
|
429
429
|
|
|
430
|
-
export { ENDPOINT_SET_SCHEMA_VERSION, MAX_HOST_ENDPOINT_URL_LENGTH, isLoopbackUrl, parseEndpointSet, encodeEndpointSetParam,
|
|
430
|
+
export { ENDPOINT_SET_SCHEMA_VERSION, MAX_HOST_ENDPOINT_URL_LENGTH, isLoopbackUrl, parseEndpointSet, encodeEndpointSetParam, generateKeyPair, keyPairFromPrivate, initiateIK, respondIK, SECURE_PROLOGUE, SIGNAL_PROLOGUE, encodeClientHello, encodeHostHello, decodeClientHello, decodeHostHello, toBase64Url, fromBase64Url, SecureSession, HOST_SETTING_KEYS, THINKING_LEVELS, isThinkingLevel, isQueueMode, HOST_NAME_MAX_UNITS, cleanHostName, normalizeHostName };
|
|
@@ -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.11.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,7 +3,7 @@ import {
|
|
|
3
3
|
generateKeyPair,
|
|
4
4
|
keyPairFromPrivate,
|
|
5
5
|
toBase64Url
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-pqe7q1s7.js";
|
|
7
7
|
|
|
8
8
|
// apps/host/src/devices.ts
|
|
9
9
|
import { link, readFile, unlink, writeFile } from "node:fs/promises";
|
|
@@ -52,7 +52,7 @@ async function admitDevice(harness, input, context) {
|
|
|
52
52
|
if (revocations.revoked.includes(input.publicKey)) {
|
|
53
53
|
revocations.revoked = revocations.revoked.filter((key) => key !== input.publicKey);
|
|
54
54
|
}
|
|
55
|
-
return { outcome: "admitted", entry };
|
|
55
|
+
return { outcome: "admitted", entry, ...offer.requestId === undefined ? {} : { requestId: offer.requestId } };
|
|
56
56
|
}, context);
|
|
57
57
|
}
|
|
58
58
|
async function loadHostKey(dataDir) {
|
|
@@ -117,7 +117,7 @@ function pairingOffers(ttlMs = 5 * 60 * 1000) {
|
|
|
117
117
|
};
|
|
118
118
|
return {
|
|
119
119
|
create: (source) => mint({ source }),
|
|
120
|
-
createAccount: (binding) => mint({ source: "account", binding }),
|
|
120
|
+
createAccount: (binding, requestId) => mint({ source: "account", binding, ...requestId === undefined ? {} : { requestId } }),
|
|
121
121
|
consume(secret) {
|
|
122
122
|
prune();
|
|
123
123
|
const candidate = Buffer.from(secret);
|
|
@@ -140,53 +140,4 @@ function pairingOffers(ttlMs = 5 * 60 * 1000) {
|
|
|
140
140
|
};
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
-
|
|
144
|
-
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
145
|
-
import { readFile as readFile2, rename, rm, writeFile as writeFile2 } from "node:fs/promises";
|
|
146
|
-
import { join as join2 } from "node:path";
|
|
147
|
-
var SERVER_CONFIG_FILE = "server.json";
|
|
148
|
-
var normalizeOrigin = (origin) => origin.replace(/\/+$/, "");
|
|
149
|
-
async function readServerConfig(dataDir) {
|
|
150
|
-
let text;
|
|
151
|
-
try {
|
|
152
|
-
text = await readFile2(join2(dataDir, SERVER_CONFIG_FILE), "utf8");
|
|
153
|
-
} catch (error) {
|
|
154
|
-
if (error.code === "ENOENT")
|
|
155
|
-
return;
|
|
156
|
-
throw error;
|
|
157
|
-
}
|
|
158
|
-
let value;
|
|
159
|
-
try {
|
|
160
|
-
value = JSON.parse(text);
|
|
161
|
-
} catch {
|
|
162
|
-
throw new Error(`${join2(dataDir, SERVER_CONFIG_FILE)} is not valid JSON — delete it or run \`pinomad leave\``);
|
|
163
|
-
}
|
|
164
|
-
const origin = value?.origin;
|
|
165
|
-
if (typeof origin !== "string" || origin.trim() === "") {
|
|
166
|
-
throw new Error(`${join2(dataDir, SERVER_CONFIG_FILE)} is missing a string "origin"`);
|
|
167
|
-
}
|
|
168
|
-
const binding = value.binding;
|
|
169
|
-
return {
|
|
170
|
-
origin,
|
|
171
|
-
...typeof binding === "string" && binding !== "" ? { binding } : {}
|
|
172
|
-
};
|
|
173
|
-
}
|
|
174
|
-
async function writeServerConfig(dataDir, config) {
|
|
175
|
-
const path = join2(dataDir, SERVER_CONFIG_FILE);
|
|
176
|
-
const tmp = `${path}.tmp-${process.pid}`;
|
|
177
|
-
await writeFile2(tmp, `${JSON.stringify({ origin: normalizeOrigin(config.origin), binding: randomBytes2(16).toString("base64url") })}
|
|
178
|
-
`, { mode: 384 });
|
|
179
|
-
await rename(tmp, path);
|
|
180
|
-
}
|
|
181
|
-
var removeServerConfig = (dataDir) => rm(join2(dataDir, SERVER_CONFIG_FILE), { force: true });
|
|
182
|
-
async function readServerBinding(dataDir) {
|
|
183
|
-
return (await readServerConfig(dataDir))?.binding;
|
|
184
|
-
}
|
|
185
|
-
function resolveRelayOrigin(flag, config) {
|
|
186
|
-
if (flag !== undefined && config !== undefined && normalizeOrigin(flag) !== normalizeOrigin(config.origin)) {
|
|
187
|
-
throw new Error(`--relay ${flag} disagrees with ${SERVER_CONFIG_FILE} (${config.origin}) — remove one`);
|
|
188
|
-
}
|
|
189
|
-
return flag ?? config?.origin;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
export { DevicesDoc, ensureDevices, RevocationsDoc, admitDevice, loadHostKey, loadRelayKey, pairingOffers, normalizeOrigin, readServerConfig, writeServerConfig, removeServerConfig, readServerBinding, resolveRelayOrigin };
|
|
143
|
+
export { DevicesDoc, ensureDevices, RevocationsDoc, admitDevice, loadHostKey, loadRelayKey, pairingOffers };
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
connectRemoteDurable
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import"./chunk-
|
|
3
|
+
} from "./chunk-jt34g8st.js";
|
|
4
|
+
import"./chunk-xqycs43g.js";
|
|
5
5
|
import {
|
|
6
6
|
isLoopbackUrl
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-pqe7q1s7.js";
|
|
8
8
|
import {
|
|
9
9
|
hostAddress
|
|
10
10
|
} from "./chunk-ngf1zatm.js";
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
isParseArgsError
|
|
3
|
-
} from "./chunk-kzbzacz9.js";
|
|
4
|
-
import {
|
|
5
|
-
commandHint,
|
|
6
|
-
hostEntry,
|
|
7
|
-
packagedVersion
|
|
8
|
-
} from "./chunk-fqgvf8v0.js";
|
|
9
1
|
import {
|
|
10
2
|
ProtocolMismatchError,
|
|
11
3
|
connectRemoteDurable
|
|
12
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-jt34g8st.js";
|
|
5
|
+
import {
|
|
6
|
+
isParseArgsError
|
|
7
|
+
} from "./chunk-kzbzacz9.js";
|
|
13
8
|
import {
|
|
14
9
|
DEFAULT_DATA_DIR,
|
|
15
10
|
hostAddress
|
|
16
11
|
} from "./chunk-ngf1zatm.js";
|
|
12
|
+
import {
|
|
13
|
+
commandHint,
|
|
14
|
+
hostEntry,
|
|
15
|
+
packagedVersion
|
|
16
|
+
} from "./chunk-sd5fkxjj.js";
|
|
17
17
|
|
|
18
18
|
// apps/host/src/cli/service.ts
|
|
19
19
|
import { execFile as execFile2 } from "node:child_process";
|
|
@@ -81,20 +81,21 @@ function argValue(args, flag) {
|
|
|
81
81
|
}
|
|
82
82
|
return value;
|
|
83
83
|
}
|
|
84
|
-
function
|
|
84
|
+
function withoutArg(args, flag) {
|
|
85
85
|
const out = [];
|
|
86
86
|
for (let i = 0;i < args.length; i += 1) {
|
|
87
87
|
const arg = args[i];
|
|
88
|
-
if (arg ===
|
|
88
|
+
if (arg === flag) {
|
|
89
89
|
i += 1;
|
|
90
90
|
continue;
|
|
91
91
|
}
|
|
92
|
-
if (arg.startsWith(
|
|
92
|
+
if (arg.startsWith(`${flag}=`))
|
|
93
93
|
continue;
|
|
94
94
|
out.push(arg);
|
|
95
95
|
}
|
|
96
96
|
return out;
|
|
97
97
|
}
|
|
98
|
+
var withoutRelayArgs = (args) => withoutArg(args, "--relay");
|
|
98
99
|
var unescapeExec = (value) => value.replace(/\\(.)/g, "$1");
|
|
99
100
|
var unspecify = (value) => value.replace(/%%/g, "%").replace(/\$\$/g, "$");
|
|
100
101
|
var xmlUnescape = (value) => value.replace(/"/g, '"').replace(/'/g, "'").replace(/</g, "<").replace(/>/g, ">").replace(/&/g, "&");
|
|
@@ -409,15 +410,13 @@ async function install(argv) {
|
|
|
409
410
|
console.log(`data dir: ${spec.dataDir}`);
|
|
410
411
|
console.log(`browser link: ${commandHint("link")} pairing QR: ${commandHint("pair")}`);
|
|
411
412
|
}
|
|
412
|
-
async function
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
console.log(`version: ${packagedVersion}`);
|
|
420
|
-
}
|
|
413
|
+
async function versionLine() {
|
|
414
|
+
if (packagedVersion !== undefined)
|
|
415
|
+
return `version: ${packagedVersion}`;
|
|
416
|
+
const head = await run2("git", ["rev-parse", "--short", "HEAD"], { cwd: repoRoot }).then(({ stdout }) => stdout.trim(), () => "unknown");
|
|
417
|
+
return `checkout: ${head}`;
|
|
418
|
+
}
|
|
419
|
+
async function reachabilityLine(argv) {
|
|
421
420
|
try {
|
|
422
421
|
const { url, token } = await hostAddress(argv);
|
|
423
422
|
const remote = await connectToHost(url, token);
|
|
@@ -425,14 +424,20 @@ async function status(argv) {
|
|
|
425
424
|
await remote.controller.toggleTasks();
|
|
426
425
|
const tasks = remote.view.current().tasks;
|
|
427
426
|
const count = tasks === undefined ? 0 : Object.keys(tasks.tasks).length;
|
|
428
|
-
console.log(`host: reachable at ${url}, ${count} live task${count === 1 ? "" : "s"}`);
|
|
429
427
|
remote.close();
|
|
428
|
+
return `host: reachable at ${url}, ${count} live task${count === 1 ? "" : "s"}`;
|
|
430
429
|
} catch (error) {
|
|
431
430
|
if (isParseArgsError(error))
|
|
432
431
|
throw error;
|
|
433
|
-
|
|
432
|
+
return `host: unreachable (${message(error)})`;
|
|
434
433
|
}
|
|
435
434
|
}
|
|
435
|
+
async function status(argv) {
|
|
436
|
+
const state = await serviceManager().state();
|
|
437
|
+
console.log(`service: ${state.installed ? state.detail : "not installed"}`);
|
|
438
|
+
console.log(await versionLine());
|
|
439
|
+
console.log(await reachabilityLine(argv));
|
|
440
|
+
}
|
|
436
441
|
async function restartService({
|
|
437
442
|
force,
|
|
438
443
|
argv,
|
|
@@ -536,4 +541,4 @@ async function main(argv) {
|
|
|
536
541
|
}
|
|
537
542
|
if (false) {}
|
|
538
543
|
|
|
539
|
-
export { installSpec, argValue, withoutRelayArgs, serviceManager, restartService, main };
|
|
544
|
+
export { installSpec, argValue, withoutArg, withoutRelayArgs, serviceManager, versionLine, reachabilityLine, restartService, main };
|