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
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
organize,
|
|
16
16
|
parseRtcMaxMessageSize,
|
|
17
17
|
rtcSelectedPair
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-47ff1d1t.js";
|
|
19
19
|
import {
|
|
20
20
|
SECURE_PROLOGUE,
|
|
21
21
|
SecureSession,
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
initiateIK,
|
|
25
25
|
isLoopbackUrl,
|
|
26
26
|
parseEndpointSet
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-pqe7q1s7.js";
|
|
28
28
|
|
|
29
29
|
// packages/protocol/src/remote-durable.ts
|
|
30
30
|
import { applyImmutable } from "@earendil-works/chord/delta";
|
|
@@ -286,6 +286,13 @@ function webSocketTransport(url, token) {
|
|
|
286
286
|
};
|
|
287
287
|
}
|
|
288
288
|
|
|
289
|
+
// packages/protocol/src/terminals.ts
|
|
290
|
+
function isTerminalsHello(value) {
|
|
291
|
+
return value !== null && typeof value === "object" && typeof value.limit === "number";
|
|
292
|
+
}
|
|
293
|
+
var terminalsStream = (id) => `terminals:${id}`;
|
|
294
|
+
var terminalStream = (id) => `terminal:${id}`;
|
|
295
|
+
|
|
289
296
|
// packages/protocol/src/transcript.ts
|
|
290
297
|
function isBusy(view) {
|
|
291
298
|
const live = view.docs?.["pi.live"];
|
|
@@ -458,6 +465,11 @@ class RemoteClient {
|
|
|
458
465
|
#helloModels = [];
|
|
459
466
|
#helloDefaults = {};
|
|
460
467
|
#hostVersion;
|
|
468
|
+
#hostTerminals;
|
|
469
|
+
#terminalWatchers = new Map;
|
|
470
|
+
#terminalSinks = new Map;
|
|
471
|
+
#terminalPositions = new Map;
|
|
472
|
+
#terminalSizes = new Map;
|
|
461
473
|
#attempt = 0;
|
|
462
474
|
#rtcAttemptNonce = randomHex(8);
|
|
463
475
|
#closed = false;
|
|
@@ -710,6 +722,7 @@ class RemoteClient {
|
|
|
710
722
|
this.#helloModels = frame.models;
|
|
711
723
|
this.#helloDefaults = frame.defaults ?? {};
|
|
712
724
|
this.#hostVersion = frame.hostVersion;
|
|
725
|
+
this.#hostTerminals = isTerminalsHello(frame.terminals) ? frame.terminals : undefined;
|
|
713
726
|
this.#fresh.clear();
|
|
714
727
|
const covered = new Set(hostStreams(hostMinor));
|
|
715
728
|
for (const name of HOST_STREAM_NAMES) {
|
|
@@ -727,6 +740,7 @@ class RemoteClient {
|
|
|
727
740
|
if (this.#side !== undefined)
|
|
728
741
|
for (const stream of this.#conversationStreams(this.#side))
|
|
729
742
|
this.#wanted.add(stream);
|
|
743
|
+
this.#terminalsAvailability();
|
|
730
744
|
for (const stream of this.#wanted)
|
|
731
745
|
this.#subscribe(stream);
|
|
732
746
|
if (frame.endpointSet !== undefined) {
|
|
@@ -815,6 +829,7 @@ class RemoteClient {
|
|
|
815
829
|
this.#resolveReady({
|
|
816
830
|
view: this.#viewSource(),
|
|
817
831
|
controller: this.#controller(),
|
|
832
|
+
terminals: this.#terminals(),
|
|
818
833
|
setConnectionMode: (mode) => this.setConnectionMode(mode),
|
|
819
834
|
rtcDiagnostics: () => this.rtcDiagnostics(),
|
|
820
835
|
close: () => this.#close()
|
|
@@ -828,6 +843,9 @@ class RemoteClient {
|
|
|
828
843
|
await this.#recoverSubmissions();
|
|
829
844
|
if (!this.#isActive(dial))
|
|
830
845
|
return;
|
|
846
|
+
for (const [terminalId, size] of this.#terminalSizes) {
|
|
847
|
+
this.#callNow("resizeTerminal", { terminalId, ...size }).catch(() => {});
|
|
848
|
+
}
|
|
831
849
|
this.#finishSyncGate();
|
|
832
850
|
this.#afterCarrierReady(dial);
|
|
833
851
|
}
|
|
@@ -1961,6 +1979,11 @@ class RemoteClient {
|
|
|
1961
1979
|
case "snapshot":
|
|
1962
1980
|
if (!this.#wanted.has(frame.stream))
|
|
1963
1981
|
return;
|
|
1982
|
+
if (frame.stream.startsWith("terminals:")) {
|
|
1983
|
+
this.#values.set(frame.stream, frame.value);
|
|
1984
|
+
this.#notifyTerminals(frame.stream, { kind: "ready", list: frame.value });
|
|
1985
|
+
return;
|
|
1986
|
+
}
|
|
1964
1987
|
this.#values.set(frame.stream, frame.value);
|
|
1965
1988
|
this.#fresh.add(frame.stream);
|
|
1966
1989
|
this.#streamVersions.set(frame.stream, (this.#streamVersions.get(frame.stream) ?? 0) + 1);
|
|
@@ -1974,7 +1997,19 @@ class RemoteClient {
|
|
|
1974
1997
|
this.#values.set(frame.stream, applyImmutable(this.#values.get(frame.stream), frame.ops));
|
|
1975
1998
|
this.#refresh();
|
|
1976
1999
|
return;
|
|
2000
|
+
case "output": {
|
|
2001
|
+
const sink = this.#terminalSinks.get(frame.stream);
|
|
2002
|
+
if (sink === undefined || !this.#wanted.has(frame.stream))
|
|
2003
|
+
return;
|
|
2004
|
+
this.#terminalPositions.set(frame.stream, frame.seq);
|
|
2005
|
+
sink.output(frame.data, frame.reset === true);
|
|
2006
|
+
return;
|
|
2007
|
+
}
|
|
1977
2008
|
case "ended": {
|
|
2009
|
+
if (frame.stream.startsWith("terminals:") || frame.stream.startsWith("terminal:")) {
|
|
2010
|
+
this.#endTerminalStream(frame.stream, frame.reason);
|
|
2011
|
+
return;
|
|
2012
|
+
}
|
|
1978
2013
|
this.#wanted.delete(frame.stream);
|
|
1979
2014
|
this.#values.delete(frame.stream);
|
|
1980
2015
|
this.#fresh.delete(frame.stream);
|
|
@@ -2070,7 +2105,124 @@ class RemoteClient {
|
|
|
2070
2105
|
}
|
|
2071
2106
|
#subscribe(stream) {
|
|
2072
2107
|
const refs = stream.startsWith("conversation:") && hostSupportsFeature(this.#hostMinor, "imageRefs");
|
|
2073
|
-
this.#
|
|
2108
|
+
const since = this.#terminalPositions.get(stream);
|
|
2109
|
+
this.#send({
|
|
2110
|
+
type: "subscribe",
|
|
2111
|
+
stream,
|
|
2112
|
+
...refs ? { images: "ref" } : {},
|
|
2113
|
+
...since === undefined ? {} : { since }
|
|
2114
|
+
});
|
|
2115
|
+
}
|
|
2116
|
+
#terminalsUnavailable() {
|
|
2117
|
+
if (!hostSupportsFeature(this.#hostMinor, "terminals")) {
|
|
2118
|
+
return "The host is too old for terminals (needs protocol 5.27); run `pinomad upgrade` on the host";
|
|
2119
|
+
}
|
|
2120
|
+
if (this.#hostTerminals === undefined)
|
|
2121
|
+
return "The host couldn't load its terminal module; its log says which package is missing";
|
|
2122
|
+
return;
|
|
2123
|
+
}
|
|
2124
|
+
#terminalsAvailability() {
|
|
2125
|
+
const reason = this.#terminalsUnavailable();
|
|
2126
|
+
if (reason === undefined) {
|
|
2127
|
+
for (const stream of this.#terminalWatchers.keys())
|
|
2128
|
+
this.#wanted.add(stream);
|
|
2129
|
+
for (const stream of this.#terminalSinks.keys())
|
|
2130
|
+
this.#wanted.add(stream);
|
|
2131
|
+
return;
|
|
2132
|
+
}
|
|
2133
|
+
for (const stream of [...this.#terminalWatchers.keys()]) {
|
|
2134
|
+
this.#wanted.delete(stream);
|
|
2135
|
+
this.#values.delete(stream);
|
|
2136
|
+
this.#notifyTerminals(stream, { kind: "unavailable", reason });
|
|
2137
|
+
}
|
|
2138
|
+
for (const stream of [...this.#terminalSinks.keys()])
|
|
2139
|
+
this.#endTerminalStream(stream, reason);
|
|
2140
|
+
}
|
|
2141
|
+
#notifyTerminals(stream, state) {
|
|
2142
|
+
for (const listener of [...this.#terminalWatchers.get(stream) ?? []])
|
|
2143
|
+
listener(state);
|
|
2144
|
+
}
|
|
2145
|
+
#endTerminalStream(stream, reason) {
|
|
2146
|
+
this.#wanted.delete(stream);
|
|
2147
|
+
this.#values.delete(stream);
|
|
2148
|
+
if (stream.startsWith("terminals:")) {
|
|
2149
|
+
this.#notifyTerminals(stream, { kind: "unavailable", reason });
|
|
2150
|
+
return;
|
|
2151
|
+
}
|
|
2152
|
+
const sink = this.#terminalSinks.get(stream);
|
|
2153
|
+
this.#terminalSinks.delete(stream);
|
|
2154
|
+
this.#terminalPositions.delete(stream);
|
|
2155
|
+
this.#terminalSizes.delete(stream.slice("terminal:".length));
|
|
2156
|
+
sink?.ended(reason);
|
|
2157
|
+
}
|
|
2158
|
+
#terminalCall(method, args) {
|
|
2159
|
+
const reason = this.#terminalsUnavailable();
|
|
2160
|
+
return reason === undefined ? this.#call(method, args) : Promise.reject(new Error(reason));
|
|
2161
|
+
}
|
|
2162
|
+
#terminals() {
|
|
2163
|
+
return {
|
|
2164
|
+
watch: (conversationId, listener) => {
|
|
2165
|
+
const stream = terminalsStream(conversationId);
|
|
2166
|
+
let listeners = this.#terminalWatchers.get(stream);
|
|
2167
|
+
const first = listeners === undefined;
|
|
2168
|
+
if (listeners === undefined)
|
|
2169
|
+
this.#terminalWatchers.set(stream, listeners = new Set);
|
|
2170
|
+
listeners.add(listener);
|
|
2171
|
+
const reason = this.#terminalsUnavailable();
|
|
2172
|
+
const list = this.#values.get(stream);
|
|
2173
|
+
listener(reason !== undefined ? { kind: "unavailable", reason } : list !== undefined ? { kind: "ready", list } : { kind: "loading" });
|
|
2174
|
+
if (first && reason === undefined) {
|
|
2175
|
+
this.#wanted.add(stream);
|
|
2176
|
+
if (this.#helloReceived)
|
|
2177
|
+
this.#subscribe(stream);
|
|
2178
|
+
}
|
|
2179
|
+
return () => {
|
|
2180
|
+
if (!listeners.delete(listener) || listeners.size > 0)
|
|
2181
|
+
return;
|
|
2182
|
+
this.#terminalWatchers.delete(stream);
|
|
2183
|
+
if (!this.#wanted.delete(stream))
|
|
2184
|
+
return;
|
|
2185
|
+
this.#values.delete(stream);
|
|
2186
|
+
this.#send({ type: "unsubscribe", stream });
|
|
2187
|
+
};
|
|
2188
|
+
},
|
|
2189
|
+
attach: (terminalId, sink) => {
|
|
2190
|
+
const stream = terminalStream(terminalId);
|
|
2191
|
+
const reason = this.#terminalsUnavailable();
|
|
2192
|
+
if (reason !== undefined) {
|
|
2193
|
+
sink.ended(reason);
|
|
2194
|
+
return () => {};
|
|
2195
|
+
}
|
|
2196
|
+
if (this.#terminalSinks.has(stream) && this.#wanted.has(stream))
|
|
2197
|
+
this.#send({ type: "unsubscribe", stream });
|
|
2198
|
+
this.#terminalSinks.set(stream, sink);
|
|
2199
|
+
this.#terminalPositions.delete(stream);
|
|
2200
|
+
this.#wanted.add(stream);
|
|
2201
|
+
if (this.#helloReceived)
|
|
2202
|
+
this.#subscribe(stream);
|
|
2203
|
+
return () => {
|
|
2204
|
+
if (this.#terminalSinks.get(stream) !== sink)
|
|
2205
|
+
return;
|
|
2206
|
+
this.#terminalSinks.delete(stream);
|
|
2207
|
+
this.#terminalPositions.delete(stream);
|
|
2208
|
+
this.#terminalSizes.delete(terminalId);
|
|
2209
|
+
if (this.#wanted.delete(stream))
|
|
2210
|
+
this.#send({ type: "unsubscribe", stream });
|
|
2211
|
+
};
|
|
2212
|
+
},
|
|
2213
|
+
open: (conversationId, size) => this.#terminalCall("openTerminal", { conversationId, ...size }).then(({ terminalId }) => terminalId),
|
|
2214
|
+
input: (terminalId, data) => {
|
|
2215
|
+
this.#terminalCall("terminalInput", { terminalId, data }).catch(() => {});
|
|
2216
|
+
},
|
|
2217
|
+
resize: (terminalId, size) => {
|
|
2218
|
+
if (this.#terminalSinks.has(terminalStream(terminalId)))
|
|
2219
|
+
this.#terminalSizes.set(terminalId, size);
|
|
2220
|
+
this.#terminalCall("resizeTerminal", { terminalId, ...size }).catch(() => {});
|
|
2221
|
+
},
|
|
2222
|
+
rename: (terminalId, name) => this.#terminalCall("renameTerminal", { terminalId, name }).then(() => {}),
|
|
2223
|
+
restart: (terminalId, size) => this.#terminalCall("restartTerminal", { terminalId, ...this.#terminalSizes.get(terminalId) ?? size }).then(() => {}),
|
|
2224
|
+
close: (terminalId) => this.#terminalCall("closeTerminal", { terminalId }).then(() => {})
|
|
2225
|
+
};
|
|
2074
2226
|
}
|
|
2075
2227
|
#host(name) {
|
|
2076
2228
|
return this.#values.get(name);
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
RTC_DEFAULT_STUN
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-47ff1d1t.js";
|
|
4
4
|
import {
|
|
5
5
|
HOST_SETTING_KEYS,
|
|
6
6
|
cleanHostName,
|
|
7
7
|
isQueueMode,
|
|
8
8
|
isThinkingLevel,
|
|
9
9
|
normalizeHostName
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-pqe7q1s7.js";
|
|
11
11
|
|
|
12
12
|
// apps/host/src/host-value.ts
|
|
13
13
|
function constantValue(value) {
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
// apps/host/src/server-config.ts
|
|
2
|
+
import { randomBytes } from "node:crypto";
|
|
3
|
+
import { readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
var SERVER_CONFIG_FILE = "server.json";
|
|
6
|
+
var REMOVAL_NOTICE_FILE = "server-removed.json";
|
|
7
|
+
var normalizeOrigin = (origin) => origin.replace(/\/+$/, "");
|
|
8
|
+
async function readServerConfig(dataDir) {
|
|
9
|
+
const config = await readServerConfigAt(join(dataDir, SERVER_CONFIG_FILE));
|
|
10
|
+
if (config === undefined)
|
|
11
|
+
return;
|
|
12
|
+
const notice = await readRemovalNotice(dataDir).catch(() => {
|
|
13
|
+
return;
|
|
14
|
+
});
|
|
15
|
+
return notice !== undefined && endsJoin(notice, config) ? undefined : config;
|
|
16
|
+
}
|
|
17
|
+
var endsJoin = (notice, config) => normalizeOrigin(notice.origin) === normalizeOrigin(config.origin) && notice.binding === config.binding;
|
|
18
|
+
async function readServerConfigAt(path) {
|
|
19
|
+
let text;
|
|
20
|
+
try {
|
|
21
|
+
text = await readFile(path, "utf8");
|
|
22
|
+
} catch (error) {
|
|
23
|
+
if (error.code === "ENOENT")
|
|
24
|
+
return;
|
|
25
|
+
throw error;
|
|
26
|
+
}
|
|
27
|
+
let value;
|
|
28
|
+
try {
|
|
29
|
+
value = JSON.parse(text);
|
|
30
|
+
} catch {
|
|
31
|
+
throw new Error(`${path} is not valid JSON — delete it or run \`pinomad leave\``);
|
|
32
|
+
}
|
|
33
|
+
const origin = value?.origin;
|
|
34
|
+
if (typeof origin !== "string" || origin.trim() === "") {
|
|
35
|
+
throw new Error(`${path} is missing a string "origin"`);
|
|
36
|
+
}
|
|
37
|
+
const { binding, username } = value;
|
|
38
|
+
return {
|
|
39
|
+
origin,
|
|
40
|
+
...typeof binding === "string" && binding !== "" ? { binding } : {},
|
|
41
|
+
...typeof username === "string" && username !== "" ? { username } : {}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
async function writeJsonFile(path, value) {
|
|
45
|
+
const tmp = `${path}.tmp-${process.pid}`;
|
|
46
|
+
await writeFile(tmp, `${JSON.stringify(value)}
|
|
47
|
+
`, { mode: 384 });
|
|
48
|
+
await rename(tmp, path);
|
|
49
|
+
}
|
|
50
|
+
async function writeServerConfig(dataDir, config) {
|
|
51
|
+
await writeJsonFile(join(dataDir, SERVER_CONFIG_FILE), {
|
|
52
|
+
origin: normalizeOrigin(config.origin),
|
|
53
|
+
binding: randomBytes(16).toString("base64url"),
|
|
54
|
+
...config.username === undefined ? {} : { username: config.username }
|
|
55
|
+
});
|
|
56
|
+
await rm(join(dataDir, REMOVAL_NOTICE_FILE), { force: true });
|
|
57
|
+
}
|
|
58
|
+
async function markRemoved(dataDir, removed, removedAt = Date.now()) {
|
|
59
|
+
await writeJsonFile(join(dataDir, REMOVAL_NOTICE_FILE), {
|
|
60
|
+
origin: normalizeOrigin(removed.origin),
|
|
61
|
+
...removed.binding === undefined ? {} : { binding: removed.binding },
|
|
62
|
+
...removed.username === undefined ? {} : { username: removed.username },
|
|
63
|
+
removedAt
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
async function readRemovalNotice(dataDir) {
|
|
67
|
+
const path = join(dataDir, REMOVAL_NOTICE_FILE);
|
|
68
|
+
let text;
|
|
69
|
+
try {
|
|
70
|
+
text = await readFile(path, "utf8");
|
|
71
|
+
} catch (error) {
|
|
72
|
+
if (error.code === "ENOENT")
|
|
73
|
+
return;
|
|
74
|
+
throw error;
|
|
75
|
+
}
|
|
76
|
+
let value;
|
|
77
|
+
try {
|
|
78
|
+
value = JSON.parse(text);
|
|
79
|
+
} catch {
|
|
80
|
+
throw new Error(`${path} is not valid JSON — delete it`);
|
|
81
|
+
}
|
|
82
|
+
const { origin, binding, username, removedAt } = value ?? {};
|
|
83
|
+
if (typeof origin !== "string" || typeof removedAt !== "number")
|
|
84
|
+
throw new Error(`${path} is missing "origin" or "removedAt" — delete it`);
|
|
85
|
+
return {
|
|
86
|
+
origin,
|
|
87
|
+
...typeof binding === "string" && binding !== "" ? { binding } : {},
|
|
88
|
+
...typeof username === "string" && username !== "" ? { username } : {},
|
|
89
|
+
removedAt
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
async function removeServerConfig(dataDir) {
|
|
93
|
+
await rm(join(dataDir, SERVER_CONFIG_FILE), { force: true });
|
|
94
|
+
await rm(join(dataDir, REMOVAL_NOTICE_FILE), { force: true });
|
|
95
|
+
}
|
|
96
|
+
async function readServerBinding(dataDir) {
|
|
97
|
+
return (await readServerConfig(dataDir))?.binding;
|
|
98
|
+
}
|
|
99
|
+
function resolveRelayOrigin(flag, config) {
|
|
100
|
+
if (flag !== undefined && config !== undefined && normalizeOrigin(flag) !== normalizeOrigin(config.origin)) {
|
|
101
|
+
throw new Error(`--relay ${flag} disagrees with ${SERVER_CONFIG_FILE} (${config.origin}) — remove one`);
|
|
102
|
+
}
|
|
103
|
+
return flag ?? config?.origin;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export { REMOVAL_NOTICE_FILE, normalizeOrigin, readServerConfig, writeServerConfig, markRemoved, readRemovalNotice, removeServerConfig, readServerBinding, resolveRelayOrigin };
|
|
@@ -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 };
|