pinomad 0.12.0 → 0.13.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/dist/{chunk-np4jd070.js → chunk-4fferbxw.js} +97 -29
- package/dist/{chunk-ksfxqd8s.js → chunk-53xv3fny.js} +241 -48
- package/dist/{chunk-nppgxh6c.js → chunk-563fnad9.js} +1 -1
- package/dist/{chunk-41q0saz0.js → chunk-6th9xv39.js} +4 -4
- package/dist/{chunk-aqj9wfmb.js → chunk-90g1cg9n.js} +1 -1
- package/dist/{chunk-mnmqyq7d.js → chunk-aapsc9g0.js} +42 -48
- package/dist/{chunk-5qf1grkk.js → chunk-d4tq62yr.js} +46 -11
- package/dist/{chunk-gg2dcqbg.js → chunk-d9mq5d46.js} +22 -7
- package/dist/{chunk-47ff1d1t.js → chunk-kmzzjv53.js} +51 -4
- package/dist/{chunk-agq4tn9r.js → chunk-m51mq8vh.js} +4 -4
- package/dist/{chunk-vqkb70d7.js → chunk-maqv34cs.js} +2 -2
- package/dist/{chunk-vx7dy07y.js → chunk-ra86wjp5.js} +4 -4
- package/dist/{chunk-7wj0jh3t.js → chunk-s0h7c7da.js} +1 -1
- package/dist/{chunk-42nqtx5r.js → chunk-sd640dt7.js} +6 -6
- package/dist/{chunk-jeqsdcj1.js → chunk-t6fw0wa9.js} +4 -4
- package/dist/{chunk-t5abqsva.js → chunk-wd7aracm.js} +17 -5
- package/dist/pinomad.js +12 -12
- package/package.json +12 -11
- package/web/assets/{core-DnpzcQzs.js → core-BHm2gdHL.js} +1 -1
- package/web/assets/geist-mono-cyrillic-ext-wght-normal-X_5orZeX.woff2 +0 -0
- package/web/assets/geist-mono-cyrillic-wght-normal-DiZS0aHC.woff2 +0 -0
- package/web/assets/geist-mono-latin-ext-wght-normal-Bwz-egvJ.woff2 +0 -0
- package/web/assets/geist-mono-latin-wght-normal-XN7g48iV.woff2 +0 -0
- package/web/assets/geist-mono-symbols2-wght-normal-CO5SzqOn.woff2 +0 -0
- package/web/assets/geist-mono-vietnamese-wght-normal-DadHysG0.woff2 +0 -0
- package/web/assets/{highlighted-diff-Dn5ifsvK.js → highlighted-diff-DrHvSLK9.js} +2 -2
- package/web/assets/{highlights-DnHv6NBM.js → highlights-1aLwssz-.js} +1 -1
- package/web/assets/{highlights-themes-CUdrlZk3.js → highlights-themes-C1p4pFYS.js} +1 -1
- package/web/assets/index-A_AUJoO6.css +1 -0
- package/web/assets/index-BafYMKiN.js +396 -0
- package/web/assets/{shiki-BuPP5HCg.js → shiki-BwyCm3kZ.js} +2 -2
- package/web/assets/{shiki-langs-FJk0v0Ga.js → shiki-langs-CMlALLSg.js} +1 -1
- package/web/assets/{stream-tokenizer-Bl6bisIa.js → stream-tokenizer-BlgIhw0y.js} +1 -1
- package/web/assets/{theming-themes-BL_CC-Mm.js → theming-themes-DDvoqEqT.js} +1 -1
- package/web/assets/{xterm-view-ZsuzJb2C.js → xterm-view-BnKOnF3C.js} +1 -1
- package/web/index.html +2 -2
- package/web/assets/index-BV0ecolo.css +0 -1
- package/web/assets/index-DNsTTgPE.js +0 -396
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
import {
|
|
17
17
|
commandHint,
|
|
18
18
|
webRoot
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-s0h7c7da.js";
|
|
20
20
|
import"./chunk-df32avw6.js";
|
|
21
21
|
|
|
22
22
|
// apps/server/src/main.ts
|
|
@@ -1609,6 +1609,15 @@ async function readJson(request, optional = false) {
|
|
|
1609
1609
|
return { ok: false, tooLarge: false };
|
|
1610
1610
|
}
|
|
1611
1611
|
}
|
|
1612
|
+
async function authedJson(accounts, request, token, optional = false) {
|
|
1613
|
+
const body = await readJson(request, optional);
|
|
1614
|
+
if (!body.ok)
|
|
1615
|
+
return { ok: false, status: body.tooLarge ? 413 : 400, error: body.tooLarge ? "payload_too_large" : "invalid_json" };
|
|
1616
|
+
const session = accounts.authenticate(token);
|
|
1617
|
+
if (session === undefined)
|
|
1618
|
+
return { ok: false, status: 401, error: "unauthenticated" };
|
|
1619
|
+
return { ok: true, value: body.value, session };
|
|
1620
|
+
}
|
|
1612
1621
|
function sessionToken(request) {
|
|
1613
1622
|
const authorization = request.headers.authorization;
|
|
1614
1623
|
if (authorization !== undefined && authorization.startsWith("Bearer "))
|
|
@@ -1829,9 +1838,9 @@ async function handleApiRequest(request, response, ctx) {
|
|
|
1829
1838
|
deny(401, "unauthenticated");
|
|
1830
1839
|
return;
|
|
1831
1840
|
}
|
|
1832
|
-
const body = await
|
|
1841
|
+
const body = await authedJson(accounts, request, token);
|
|
1833
1842
|
if (!body.ok) {
|
|
1834
|
-
deny(body.
|
|
1843
|
+
deny(body.status, body.error);
|
|
1835
1844
|
return;
|
|
1836
1845
|
}
|
|
1837
1846
|
const named = body.value;
|
|
@@ -1840,12 +1849,7 @@ async function handleApiRequest(request, response, ctx) {
|
|
|
1840
1849
|
deny(400, "invalid_request");
|
|
1841
1850
|
return;
|
|
1842
1851
|
}
|
|
1843
|
-
const
|
|
1844
|
-
if (session === undefined) {
|
|
1845
|
-
deny(401, "unauthenticated");
|
|
1846
|
-
return;
|
|
1847
|
-
}
|
|
1848
|
-
const args = { userId: session.userId, ip: clientIp(request, ctx.trustProxy), ...ref };
|
|
1852
|
+
const args = { userId: body.session.userId, ip: clientIp(request, ctx.trustProxy), ...ref };
|
|
1849
1853
|
const result = pathname === "/api/host-link/lookup" ? accounts.lookupHostLink(args) : pathname === "/api/host-link/confirm" ? accounts.confirmHostLink(args) : accounts.denyHostLink(args);
|
|
1850
1854
|
if (result.status === "limited") {
|
|
1851
1855
|
deny(429, "rate_limited");
|
|
@@ -1886,9 +1890,13 @@ async function handleApiRequest(request, response, ctx) {
|
|
|
1886
1890
|
send(200, accounts.createInvite(session.userId));
|
|
1887
1891
|
return;
|
|
1888
1892
|
}
|
|
1889
|
-
const body = await
|
|
1893
|
+
const body = await authedJson(accounts, request, token);
|
|
1890
1894
|
if (!body.ok) {
|
|
1891
|
-
deny(body.
|
|
1895
|
+
deny(body.status, body.error);
|
|
1896
|
+
return;
|
|
1897
|
+
}
|
|
1898
|
+
if (!body.session.admin) {
|
|
1899
|
+
deny(401, "unauthenticated");
|
|
1892
1900
|
return;
|
|
1893
1901
|
}
|
|
1894
1902
|
const id = body.value?.id;
|
|
@@ -1896,10 +1904,6 @@ async function handleApiRequest(request, response, ctx) {
|
|
|
1896
1904
|
deny(400, "invalid_request");
|
|
1897
1905
|
return;
|
|
1898
1906
|
}
|
|
1899
|
-
if (accounts.authenticate(token)?.admin !== true) {
|
|
1900
|
-
deny(401, "unauthenticated");
|
|
1901
|
-
return;
|
|
1902
|
-
}
|
|
1903
1907
|
if (accounts.revokeInvite(id))
|
|
1904
1908
|
send(204);
|
|
1905
1909
|
else
|
|
@@ -1917,9 +1921,9 @@ async function handleApiRequest(request, response, ctx) {
|
|
|
1917
1921
|
deny(401, "unauthenticated");
|
|
1918
1922
|
return;
|
|
1919
1923
|
}
|
|
1920
|
-
const body = await
|
|
1924
|
+
const body = await authedJson(accounts, request, token);
|
|
1921
1925
|
if (!body.ok) {
|
|
1922
|
-
deny(body.
|
|
1926
|
+
deny(body.status, body.error);
|
|
1923
1927
|
return;
|
|
1924
1928
|
}
|
|
1925
1929
|
const value = body.value;
|
|
@@ -1927,11 +1931,7 @@ async function handleApiRequest(request, response, ctx) {
|
|
|
1927
1931
|
deny(400, "invalid_request");
|
|
1928
1932
|
return;
|
|
1929
1933
|
}
|
|
1930
|
-
const current =
|
|
1931
|
-
if (current === undefined) {
|
|
1932
|
-
deny(401, "unauthenticated");
|
|
1933
|
-
return;
|
|
1934
|
-
}
|
|
1934
|
+
const current = body.session;
|
|
1935
1935
|
const result = await accounts.removeHost({
|
|
1936
1936
|
userId: current.userId,
|
|
1937
1937
|
username: current.username,
|
|
@@ -2044,9 +2044,9 @@ async function handleApiRequest(request, response, ctx) {
|
|
|
2044
2044
|
send(200, accounts.listDevices(session.userId).map((device) => ({ ...device, current: device.id === session.deviceId })));
|
|
2045
2045
|
return;
|
|
2046
2046
|
}
|
|
2047
|
-
const body = await
|
|
2047
|
+
const body = await authedJson(accounts, request, token);
|
|
2048
2048
|
if (!body.ok) {
|
|
2049
|
-
deny(body.
|
|
2049
|
+
deny(body.status, body.error);
|
|
2050
2050
|
return;
|
|
2051
2051
|
}
|
|
2052
2052
|
const value = body.value;
|
|
@@ -2054,11 +2054,7 @@ async function handleApiRequest(request, response, ctx) {
|
|
|
2054
2054
|
deny(400, "invalid_request");
|
|
2055
2055
|
return;
|
|
2056
2056
|
}
|
|
2057
|
-
const current =
|
|
2058
|
-
if (current === undefined) {
|
|
2059
|
-
deny(401, "unauthenticated");
|
|
2060
|
-
return;
|
|
2061
|
-
}
|
|
2057
|
+
const current = body.session;
|
|
2062
2058
|
const result = await accounts.kickDevice({
|
|
2063
2059
|
userId: current.userId,
|
|
2064
2060
|
username: current.username,
|
|
@@ -2096,9 +2092,9 @@ async function handleApiRequest(request, response, ctx) {
|
|
|
2096
2092
|
return;
|
|
2097
2093
|
}
|
|
2098
2094
|
if (pathname === "/api/push-tokens" || pathname === "/api/push-tokens/remove") {
|
|
2099
|
-
const body = await
|
|
2095
|
+
const body = await authedJson(accounts, request, token);
|
|
2100
2096
|
if (!body.ok) {
|
|
2101
|
-
deny(body.
|
|
2097
|
+
deny(body.status, body.error);
|
|
2102
2098
|
return;
|
|
2103
2099
|
}
|
|
2104
2100
|
const value = body.value;
|
|
@@ -2108,30 +2104,27 @@ async function handleApiRequest(request, response, ctx) {
|
|
|
2108
2104
|
deny(400, "invalid_request");
|
|
2109
2105
|
return;
|
|
2110
2106
|
}
|
|
2111
|
-
const current =
|
|
2112
|
-
if (current === undefined) {
|
|
2113
|
-
deny(401, "unauthenticated");
|
|
2114
|
-
return;
|
|
2115
|
-
}
|
|
2107
|
+
const current = body.session;
|
|
2116
2108
|
if (pathname === "/api/push-tokens")
|
|
2117
|
-
accounts.registerPushToken(
|
|
2109
|
+
accounts.registerPushToken(current.userId, apns, environment, current.deviceId);
|
|
2118
2110
|
else
|
|
2119
|
-
accounts.removePushToken(
|
|
2111
|
+
accounts.removePushToken(current.userId, apns, environment);
|
|
2120
2112
|
send(204);
|
|
2121
2113
|
return;
|
|
2122
2114
|
}
|
|
2123
2115
|
if (pathname === "/api/me/delete") {
|
|
2124
|
-
const body = await
|
|
2116
|
+
const body = await authedJson(accounts, request, token);
|
|
2125
2117
|
if (!body.ok) {
|
|
2126
|
-
deny(body.
|
|
2118
|
+
deny(body.status, body.error);
|
|
2127
2119
|
return;
|
|
2128
2120
|
}
|
|
2121
|
+
const current = body.session;
|
|
2129
2122
|
const value = body.value;
|
|
2130
2123
|
if (typeof value?.password !== "string" || [...value.password].length > MAX_PASSWORD_CODEPOINTS) {
|
|
2131
2124
|
deny(400, "invalid_request");
|
|
2132
2125
|
return;
|
|
2133
2126
|
}
|
|
2134
|
-
const result = await accounts.deleteAccount({ userId:
|
|
2127
|
+
const result = await accounts.deleteAccount({ userId: current.userId, username: current.username, password: value.password });
|
|
2135
2128
|
if (result.status === "limited") {
|
|
2136
2129
|
deny(429, "rate_limited");
|
|
2137
2130
|
return;
|
|
@@ -2142,24 +2135,25 @@ async function handleApiRequest(request, response, ctx) {
|
|
|
2142
2135
|
}
|
|
2143
2136
|
for (const hostId of result.hostIds)
|
|
2144
2137
|
ctx.disconnectHost(hostId);
|
|
2145
|
-
ctx.forgetAccount(
|
|
2138
|
+
ctx.forgetAccount(current.userId);
|
|
2146
2139
|
send(204, undefined, { "set-cookie": clearSessionCookie });
|
|
2147
2140
|
return;
|
|
2148
2141
|
}
|
|
2149
2142
|
if (pathname === "/api/password") {
|
|
2150
|
-
const body = await
|
|
2143
|
+
const body = await authedJson(accounts, request, token);
|
|
2151
2144
|
if (!body.ok) {
|
|
2152
|
-
deny(body.
|
|
2145
|
+
deny(body.status, body.error);
|
|
2153
2146
|
return;
|
|
2154
2147
|
}
|
|
2148
|
+
const current = body.session;
|
|
2155
2149
|
const value = body.value;
|
|
2156
2150
|
if (typeof value?.currentPassword !== "string" || typeof value.newPassword !== "string" || [...value.currentPassword].length > MAX_PASSWORD_CODEPOINTS) {
|
|
2157
2151
|
deny(400, "invalid_request");
|
|
2158
2152
|
return;
|
|
2159
2153
|
}
|
|
2160
2154
|
const result = await accounts.changePassword({
|
|
2161
|
-
userId:
|
|
2162
|
-
username:
|
|
2155
|
+
userId: current.userId,
|
|
2156
|
+
username: current.username,
|
|
2163
2157
|
keepToken: token,
|
|
2164
2158
|
currentPassword: value.currentPassword,
|
|
2165
2159
|
newPassword: value.newPassword
|
|
@@ -2185,9 +2179,9 @@ async function handleApiRequest(request, response, ctx) {
|
|
|
2185
2179
|
return;
|
|
2186
2180
|
}
|
|
2187
2181
|
if (pathname === "/api/logout") {
|
|
2188
|
-
const body = await
|
|
2182
|
+
const body = await authedJson(accounts, request, token, true);
|
|
2189
2183
|
if (!body.ok) {
|
|
2190
|
-
deny(body.
|
|
2184
|
+
deny(body.status, body.error);
|
|
2191
2185
|
return;
|
|
2192
2186
|
}
|
|
2193
2187
|
const value = body.value;
|
|
@@ -3,9 +3,9 @@ import {
|
|
|
3
3
|
joinServer,
|
|
4
4
|
openServiceSlot,
|
|
5
5
|
writeService
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-d9mq5d46.js";
|
|
7
7
|
import"./chunk-7mn38n4f.js";
|
|
8
|
-
import"./chunk-
|
|
8
|
+
import"./chunk-563fnad9.js";
|
|
9
9
|
import"./chunk-t91zt5f0.js";
|
|
10
10
|
import {
|
|
11
11
|
normalizeOrigin,
|
|
@@ -14,25 +14,28 @@ import {
|
|
|
14
14
|
} from "./chunk-nq57fdnq.js";
|
|
15
15
|
import"./chunk-g3ahp7b9.js";
|
|
16
16
|
import {
|
|
17
|
+
LAUNCHER_EXECUTABLE,
|
|
17
18
|
argValue,
|
|
19
|
+
isLauncher,
|
|
18
20
|
serviceManager,
|
|
19
21
|
withoutArg,
|
|
20
22
|
withoutRelayArgs
|
|
21
|
-
} from "./chunk-
|
|
22
|
-
import"./chunk-
|
|
23
|
+
} from "./chunk-wd7aracm.js";
|
|
24
|
+
import"./chunk-4fferbxw.js";
|
|
23
25
|
import"./chunk-kzbzacz9.js";
|
|
24
|
-
import"./chunk-
|
|
26
|
+
import"./chunk-kmzzjv53.js";
|
|
25
27
|
import"./chunk-pqe7q1s7.js";
|
|
26
28
|
import {
|
|
27
29
|
DEFAULT_DATA_DIR
|
|
28
30
|
} from "./chunk-ngf1zatm.js";
|
|
29
31
|
import {
|
|
30
32
|
commandHint
|
|
31
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-s0h7c7da.js";
|
|
32
34
|
import"./chunk-df32avw6.js";
|
|
33
35
|
|
|
34
36
|
// apps/host/src/cli/up.ts
|
|
35
|
-
import {
|
|
37
|
+
import { existsSync } from "node:fs";
|
|
38
|
+
import { isAbsolute, resolve } from "node:path";
|
|
36
39
|
import { createInterface } from "node:readline/promises";
|
|
37
40
|
import { parseArgs } from "node:util";
|
|
38
41
|
var OFFICIAL_SERVER_ORIGIN = "https://app.pinomad.si";
|
|
@@ -85,7 +88,14 @@ async function upHost(args, deps) {
|
|
|
85
88
|
const lan = (hostArgs) => withLan(hostArgs, lanPort);
|
|
86
89
|
const notes = [];
|
|
87
90
|
if (reach.server && config === undefined) {
|
|
88
|
-
const joined = await joinServer({
|
|
91
|
+
const joined = await joinServer({
|
|
92
|
+
origin,
|
|
93
|
+
dataDir,
|
|
94
|
+
code: args.code,
|
|
95
|
+
...args.token === undefined ? {} : { token: args.token },
|
|
96
|
+
...args.launcher === undefined ? {} : { launcher: args.launcher },
|
|
97
|
+
editHostArgs: lan
|
|
98
|
+
}, { ...deps, manager });
|
|
89
99
|
return {
|
|
90
100
|
joined: { origin: joined.origin, username: joined.username, fresh: true },
|
|
91
101
|
...lanPort === undefined ? {} : { lanPort },
|
|
@@ -94,7 +104,7 @@ async function upHost(args, deps) {
|
|
|
94
104
|
};
|
|
95
105
|
}
|
|
96
106
|
const edit = reach.server ? (hostArgs) => lan(withoutRelayArgs(hostArgs)) : lan;
|
|
97
|
-
const service = await writeService(slot, edit, { changed: reach.server });
|
|
107
|
+
const service = await writeService(slot, edit, { changed: reach.server, launcher: args.launcher });
|
|
98
108
|
if (!reach.server && config !== undefined) {
|
|
99
109
|
notes.push(`still joined to ${config.origin} — run \`${commandHint("leave")}\` to leave it`);
|
|
100
110
|
}
|
|
@@ -105,6 +115,12 @@ async function upHost(args, deps) {
|
|
|
105
115
|
notes
|
|
106
116
|
};
|
|
107
117
|
}
|
|
118
|
+
async function readAllStdin() {
|
|
119
|
+
let text = "";
|
|
120
|
+
for await (const chunk of process.stdin)
|
|
121
|
+
text += String(chunk);
|
|
122
|
+
return text;
|
|
123
|
+
}
|
|
108
124
|
async function askOnTerminal(question) {
|
|
109
125
|
const terminal = createInterface({ input: process.stdin, output: process.stdout });
|
|
110
126
|
try {
|
|
@@ -139,7 +155,8 @@ var FLAGS = `choose with flags:
|
|
|
139
155
|
--server [--origin URL] through a PiNomad server (default ${OFFICIAL_SERVER_ORIGIN})
|
|
140
156
|
--lan [--remote-port N] only on the local network and tailnet (default port ${DEFAULT_REMOTE_PORT})
|
|
141
157
|
--server --lan both
|
|
142
|
-
--yes keep what this host has, or the server on a new host
|
|
158
|
+
--yes keep what this host has, or the server on a new host
|
|
159
|
+
--token-stdin join with a one-time token read from stdin, without a code`;
|
|
143
160
|
async function main(argv, deps) {
|
|
144
161
|
const { values } = parseArgs({
|
|
145
162
|
args: [...argv],
|
|
@@ -150,6 +167,8 @@ async function main(argv, deps) {
|
|
|
150
167
|
yes: { type: "boolean", short: "y" },
|
|
151
168
|
origin: { type: "string" },
|
|
152
169
|
code: { type: "boolean" },
|
|
170
|
+
"token-stdin": { type: "boolean" },
|
|
171
|
+
launcher: { type: "string" },
|
|
153
172
|
"remote-port": { type: "string" },
|
|
154
173
|
"data-dir": { type: "string" }
|
|
155
174
|
}
|
|
@@ -157,6 +176,20 @@ async function main(argv, deps) {
|
|
|
157
176
|
const log = deps?.log ?? ((line) => console.log(line));
|
|
158
177
|
try {
|
|
159
178
|
const dataDir = resolve(values["data-dir"] ?? DEFAULT_DATA_DIR);
|
|
179
|
+
const launcher = values.launcher;
|
|
180
|
+
if (launcher !== undefined && process.platform !== "darwin")
|
|
181
|
+
throw new Error("--launcher is for the Mac App's service only");
|
|
182
|
+
if (launcher !== undefined && !(isAbsolute(launcher) && isLauncher(launcher))) {
|
|
183
|
+
throw new Error(`--launcher ${launcher}: not a path to the launcher inside an app (….app/Contents/MacOS/${LAUNCHER_EXECUTABLE})`);
|
|
184
|
+
}
|
|
185
|
+
if (launcher !== undefined && !existsSync(launcher))
|
|
186
|
+
throw new Error(`--launcher ${launcher}: no such file`);
|
|
187
|
+
let token;
|
|
188
|
+
if (values["token-stdin"] === true) {
|
|
189
|
+
token = (await (deps?.readStdin ?? readAllStdin)()).trim();
|
|
190
|
+
if (token === "")
|
|
191
|
+
throw new Error("--token-stdin: no join token on stdin");
|
|
192
|
+
}
|
|
160
193
|
const origin = normalizeOrigin(values.origin ?? (await readServerConfig(dataDir))?.origin ?? await lastRemovedOrigin(dataDir) ?? OFFICIAL_SERVER_ORIGIN);
|
|
161
194
|
const current = await currentReach(dataDir, deps);
|
|
162
195
|
let reach = resolveReach({ server: values.server, lan: values.lan }, current);
|
|
@@ -182,7 +215,9 @@ async function main(argv, deps) {
|
|
|
182
215
|
origin,
|
|
183
216
|
reach,
|
|
184
217
|
...values["remote-port"] === undefined ? {} : { remotePort: values["remote-port"] },
|
|
185
|
-
...values.code === true ? { code: true } : {}
|
|
218
|
+
...values.code === true ? { code: true } : {},
|
|
219
|
+
...token === undefined ? {} : { token },
|
|
220
|
+
...launcher === undefined ? {} : { launcher }
|
|
186
221
|
}, deps);
|
|
187
222
|
if (outcome.joined !== undefined) {
|
|
188
223
|
const who = outcome.joined.username ?? "an account";
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
import {
|
|
8
8
|
constantValue,
|
|
9
9
|
openHostSettings
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-563fnad9.js";
|
|
11
11
|
import {
|
|
12
12
|
loadHostKey,
|
|
13
13
|
loadRelayKey
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
restartService,
|
|
25
25
|
serviceManager,
|
|
26
26
|
withoutRelayArgs
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-wd7aracm.js";
|
|
28
28
|
import {
|
|
29
29
|
cleanHostName,
|
|
30
30
|
normalizeHostName
|
|
@@ -35,7 +35,7 @@ import {
|
|
|
35
35
|
import {
|
|
36
36
|
commandHint,
|
|
37
37
|
hostEntry
|
|
38
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-s0h7c7da.js";
|
|
39
39
|
|
|
40
40
|
// apps/host/src/cli/join.ts
|
|
41
41
|
import { mkdir } from "node:fs/promises";
|
|
@@ -315,6 +315,7 @@ async function requestJoinToken(args, deps) {
|
|
|
315
315
|
}
|
|
316
316
|
|
|
317
317
|
// apps/host/src/cli/service-slot.ts
|
|
318
|
+
import { existsSync } from "node:fs";
|
|
318
319
|
import { homedir } from "node:os";
|
|
319
320
|
import { resolve } from "node:path";
|
|
320
321
|
async function openServiceSlot(dataDir, manager) {
|
|
@@ -325,8 +326,19 @@ async function openServiceSlot(dataDir, manager) {
|
|
|
325
326
|
}
|
|
326
327
|
return { dataDir, manager, state, previous };
|
|
327
328
|
}
|
|
329
|
+
function launcherFor(given, previous) {
|
|
330
|
+
if (given !== undefined)
|
|
331
|
+
return given;
|
|
332
|
+
const installed = previous?.launcher;
|
|
333
|
+
return installed !== undefined && existsSync(installed) ? installed : undefined;
|
|
334
|
+
}
|
|
328
335
|
async function writeService(slot, edit, options) {
|
|
329
336
|
const { dataDir, manager, previous } = slot;
|
|
337
|
+
const launcher = launcherFor(options.launcher, previous);
|
|
338
|
+
const withLauncher = (spec2) => {
|
|
339
|
+
const { launcher: _, ...rest } = spec2;
|
|
340
|
+
return launcher === undefined ? rest : { ...rest, launcher };
|
|
341
|
+
};
|
|
330
342
|
const fresh = installSpec(["--data-dir", dataDir, ...edit([])], {
|
|
331
343
|
execPath: process.execPath,
|
|
332
344
|
env: process.env,
|
|
@@ -336,11 +348,11 @@ async function writeService(slot, edit, options) {
|
|
|
336
348
|
entryArgs: hostEntry.args
|
|
337
349
|
});
|
|
338
350
|
if (!slot.state.installed) {
|
|
339
|
-
await manager.install(fresh);
|
|
351
|
+
await manager.install(withLauncher(fresh));
|
|
340
352
|
return "installed";
|
|
341
353
|
}
|
|
342
|
-
const spec = previous === undefined ? fresh : { ...previous, hostArgs: edit(previous.hostArgs) };
|
|
343
|
-
const same = previous !== undefined && spec.hostArgs.join("\x00") === previous.hostArgs.join("\x00");
|
|
354
|
+
const spec = withLauncher(previous === undefined ? fresh : { ...previous, hostArgs: edit(previous.hostArgs) });
|
|
355
|
+
const same = previous !== undefined && spec.hostArgs.join("\x00") === previous.hostArgs.join("\x00") && spec.launcher === previous.launcher;
|
|
344
356
|
if (same && !options.changed && slot.state.running)
|
|
345
357
|
return "unchanged";
|
|
346
358
|
const port = argValue(spec.hostArgs, "--port");
|
|
@@ -409,7 +421,10 @@ async function joinServer(args, deps) {
|
|
|
409
421
|
if (args.name !== undefined)
|
|
410
422
|
await settings.update({ hostName: args.name });
|
|
411
423
|
const edit = args.editHostArgs ?? ((hostArgs) => hostArgs);
|
|
412
|
-
service = await writeService(slot, (hostArgs) => edit(withoutRelayArgs(hostArgs)), {
|
|
424
|
+
service = await writeService(slot, (hostArgs) => edit(withoutRelayArgs(hostArgs)), {
|
|
425
|
+
changed: true,
|
|
426
|
+
launcher: args.launcher
|
|
427
|
+
});
|
|
413
428
|
} catch (error) {
|
|
414
429
|
throw new Error(`joined ${username} at ${origin}, but local setup failed: ${message(error)}
|
|
415
430
|
` + (args.token === undefined ? `run the command again and confirm it again (re-joining the same host is safe)` : `generate a fresh join token and run the command again (re-joining the same host is safe)`));
|
|
@@ -187,7 +187,7 @@ var conversationStream = (id) => `conversation:${id}`;
|
|
|
187
187
|
var docStream = (kind, id) => `doc:${kind}:${id}`;
|
|
188
188
|
var UNAUTHORIZED_CLOSE_CODE = 4401;
|
|
189
189
|
var INVALID_FRAME_CLOSE_CODE = 4400;
|
|
190
|
-
var PROTOCOL = { major: 5, minor:
|
|
190
|
+
var PROTOCOL = { major: 5, minor: 29 };
|
|
191
191
|
var CALL_SINCE = {
|
|
192
192
|
addProject: 0,
|
|
193
193
|
removeProject: 0,
|
|
@@ -202,6 +202,7 @@ var CALL_SINCE = {
|
|
|
202
202
|
submission: 25,
|
|
203
203
|
withdrawQueued: 14,
|
|
204
204
|
steerQueued: 14,
|
|
205
|
+
reorderQueued: 29,
|
|
205
206
|
abort: 0,
|
|
206
207
|
compact: 0,
|
|
207
208
|
runCommand: 17,
|
|
@@ -226,6 +227,7 @@ var CALL_SINCE = {
|
|
|
226
227
|
deleteAgent: 6,
|
|
227
228
|
setPushToken: 7,
|
|
228
229
|
image: 15,
|
|
230
|
+
earlierEntries: 28,
|
|
229
231
|
beginAttachment: 19,
|
|
230
232
|
appendAttachment: 19,
|
|
231
233
|
rtcOffer: 23,
|
|
@@ -253,7 +255,8 @@ var FEATURE_SINCE = {
|
|
|
253
255
|
imageVariants: 20,
|
|
254
256
|
rtc: 23,
|
|
255
257
|
submitEntry: 25,
|
|
256
|
-
terminals: 27
|
|
258
|
+
terminals: 27,
|
|
259
|
+
transcriptPaging: 28
|
|
257
260
|
};
|
|
258
261
|
function hostSupportsFeature(hostMinor, feature) {
|
|
259
262
|
return hostMinor >= FEATURE_SINCE[feature];
|
|
@@ -275,7 +278,18 @@ function parseClientFrame(value) {
|
|
|
275
278
|
return { kind: "frame", frame: { type: "subscribe", stream, since } };
|
|
276
279
|
}
|
|
277
280
|
const refs = value.images === "ref";
|
|
278
|
-
|
|
281
|
+
let window;
|
|
282
|
+
if (stream.startsWith("conversation:") && value.window !== undefined) {
|
|
283
|
+
if (!record(value.window) || !positive(value.window.limit) || !(value.window.from === undefined || positive(value.window.from))) {
|
|
284
|
+
return { kind: "malformed" };
|
|
285
|
+
}
|
|
286
|
+
const limit = value.window.limit;
|
|
287
|
+
window = value.window.from === undefined ? { limit } : { limit, from: value.window.from };
|
|
288
|
+
}
|
|
289
|
+
return {
|
|
290
|
+
kind: "frame",
|
|
291
|
+
frame: { type: "subscribe", stream, ...refs ? { images: "ref" } : {}, ...window === undefined ? {} : { window } }
|
|
292
|
+
};
|
|
279
293
|
}
|
|
280
294
|
const prefix = stream.slice(0, stream.indexOf(":") === -1 ? undefined : stream.indexOf(":"));
|
|
281
295
|
if (STREAM_KINDS.has(prefix))
|
|
@@ -335,6 +349,8 @@ function validCallArgs(method, args) {
|
|
|
335
349
|
case "withdrawQueued":
|
|
336
350
|
case "steerQueued":
|
|
337
351
|
return conversationId() && submissionId();
|
|
352
|
+
case "reorderQueued":
|
|
353
|
+
return conversationId() && submissionId() && (args.before === undefined || typeof args.before === "number" && Number.isSafeInteger(args.before) && args.before >= 1);
|
|
338
354
|
case "abort":
|
|
339
355
|
return conversationId();
|
|
340
356
|
case "setThinkingLevel":
|
|
@@ -355,6 +371,8 @@ function validCallArgs(method, args) {
|
|
|
355
371
|
return conversationId() && nonempty(args.kind) && nonempty(args.requestId) && Array.isArray(args.answers) && args.answers.every((answer) => record(answer) && Array.isArray(answer.selected) && answer.selected.every((l) => typeof l === "string") && (answer.other === undefined || typeof answer.other === "string"));
|
|
356
372
|
case "changes":
|
|
357
373
|
return conversationId();
|
|
374
|
+
case "earlierEntries":
|
|
375
|
+
return conversationId() && positive(args.before) && positive(args.limit);
|
|
358
376
|
case "image":
|
|
359
377
|
return nonempty(args.ref) && (args.variant === undefined || args.variant === "thumbnail" || args.variant === "preview");
|
|
360
378
|
case "beginAttachment":
|
|
@@ -411,6 +429,9 @@ function validCallArgs(method, args) {
|
|
|
411
429
|
function record(value) {
|
|
412
430
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
413
431
|
}
|
|
432
|
+
function positive(value) {
|
|
433
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 1;
|
|
434
|
+
}
|
|
414
435
|
function nonempty(value) {
|
|
415
436
|
return typeof value === "string" && value.length > 0;
|
|
416
437
|
}
|
|
@@ -647,4 +668,30 @@ function homeOf(index, summaries, id) {
|
|
|
647
668
|
return;
|
|
648
669
|
}
|
|
649
670
|
|
|
650
|
-
|
|
671
|
+
// packages/protocol/src/transcript.ts
|
|
672
|
+
var TRANSCRIPT_PAGE = 50;
|
|
673
|
+
var MAX_TRANSCRIPT_PAGE = 500;
|
|
674
|
+
function withEarlier(view, earlier) {
|
|
675
|
+
if (earlier === undefined)
|
|
676
|
+
return view;
|
|
677
|
+
const { before: _window, ...rest } = view;
|
|
678
|
+
return {
|
|
679
|
+
...rest,
|
|
680
|
+
entries: [...earlier.entries, ...view.entries],
|
|
681
|
+
...earlier.before === undefined ? {} : { before: earlier.before }
|
|
682
|
+
};
|
|
683
|
+
}
|
|
684
|
+
function addEarlier(shown, earlier, requested, page) {
|
|
685
|
+
if (shown.before !== requested)
|
|
686
|
+
return earlier;
|
|
687
|
+
return {
|
|
688
|
+
entries: [...page.entries, ...earlier?.entries ?? []],
|
|
689
|
+
...page.before === undefined ? {} : { before: page.before }
|
|
690
|
+
};
|
|
691
|
+
}
|
|
692
|
+
function isBusy(view) {
|
|
693
|
+
const live = view.docs?.["pi.live"];
|
|
694
|
+
return live?.run !== undefined;
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
export { rtcSelectedPair, RTC_DEFAULT_STUN, RTC_DATA_CHANNEL_LABEL, RTC_MAX_RECORD_BYTES, isRtcHello, rtcCandidateType, sdpCandidates, withRtcCandidates, parseRtcMaxMessageSize, isCustomProviderApi, HOST_STREAM_NAMES, hostStreams, conversationStream, docStream, UNAUTHORIZED_CLOSE_CODE, INVALID_FRAME_CLOSE_CODE, PROTOCOL, hostSupportsCall, hostSupportsFeature, parseClientFrame, MAX_ATTACHMENTS_PER_MESSAGE, MAX_PENDING_ATTACHMENTS, MAX_PENDING_ATTACHMENT_BYTES, ATTACHMENT_TTL_MS, MAX_ATTACHMENT_NAME_LENGTH, isAttachmentId, base64DecodedLength, attachmentBeginProblem, attachmentChunkProblem, attachmentBlock, parseAttachmentBlock, organize, checkoutOf, homeOf, TRANSCRIPT_PAGE, MAX_TRANSCRIPT_PAGE, withEarlier, addEarlier, isBusy };
|
|
@@ -21,17 +21,17 @@ import {
|
|
|
21
21
|
restartService,
|
|
22
22
|
serviceManager,
|
|
23
23
|
withoutRelayArgs
|
|
24
|
-
} from "./chunk-
|
|
25
|
-
import"./chunk-
|
|
24
|
+
} from "./chunk-wd7aracm.js";
|
|
25
|
+
import"./chunk-4fferbxw.js";
|
|
26
26
|
import"./chunk-kzbzacz9.js";
|
|
27
|
-
import"./chunk-
|
|
27
|
+
import"./chunk-kmzzjv53.js";
|
|
28
28
|
import"./chunk-pqe7q1s7.js";
|
|
29
29
|
import {
|
|
30
30
|
DEFAULT_DATA_DIR
|
|
31
31
|
} from "./chunk-ngf1zatm.js";
|
|
32
32
|
import {
|
|
33
33
|
commandHint
|
|
34
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-s0h7c7da.js";
|
|
35
35
|
import"./chunk-df32avw6.js";
|
|
36
36
|
|
|
37
37
|
// apps/host/src/cli/leave.ts
|
|
@@ -7,13 +7,13 @@ import {
|
|
|
7
7
|
startService,
|
|
8
8
|
stopService,
|
|
9
9
|
versionLine
|
|
10
|
-
} from "./chunk-
|
|
11
|
-
import"./chunk-
|
|
10
|
+
} from "./chunk-wd7aracm.js";
|
|
11
|
+
import"./chunk-4fferbxw.js";
|
|
12
12
|
import"./chunk-kzbzacz9.js";
|
|
13
|
-
import"./chunk-
|
|
13
|
+
import"./chunk-kmzzjv53.js";
|
|
14
14
|
import"./chunk-pqe7q1s7.js";
|
|
15
15
|
import"./chunk-ngf1zatm.js";
|
|
16
|
-
import"./chunk-
|
|
16
|
+
import"./chunk-s0h7c7da.js";
|
|
17
17
|
import"./chunk-df32avw6.js";
|
|
18
18
|
export {
|
|
19
19
|
versionLine,
|
|
@@ -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.13.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}`;
|
|
@@ -2,19 +2,19 @@
|
|
|
2
2
|
import {
|
|
3
3
|
joinServer,
|
|
4
4
|
main
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-d9mq5d46.js";
|
|
6
6
|
import"./chunk-7mn38n4f.js";
|
|
7
|
-
import"./chunk-
|
|
7
|
+
import"./chunk-563fnad9.js";
|
|
8
8
|
import"./chunk-t91zt5f0.js";
|
|
9
9
|
import"./chunk-nq57fdnq.js";
|
|
10
10
|
import"./chunk-g3ahp7b9.js";
|
|
11
|
-
import"./chunk-
|
|
12
|
-
import"./chunk-
|
|
11
|
+
import"./chunk-wd7aracm.js";
|
|
12
|
+
import"./chunk-4fferbxw.js";
|
|
13
13
|
import"./chunk-kzbzacz9.js";
|
|
14
|
-
import"./chunk-
|
|
14
|
+
import"./chunk-kmzzjv53.js";
|
|
15
15
|
import"./chunk-pqe7q1s7.js";
|
|
16
16
|
import"./chunk-ngf1zatm.js";
|
|
17
|
-
import"./chunk-
|
|
17
|
+
import"./chunk-s0h7c7da.js";
|
|
18
18
|
import"./chunk-df32avw6.js";
|
|
19
19
|
export {
|
|
20
20
|
main,
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
import {
|
|
3
3
|
restartService,
|
|
4
4
|
serviceManager
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import"./chunk-
|
|
5
|
+
} from "./chunk-wd7aracm.js";
|
|
6
|
+
import"./chunk-4fferbxw.js";
|
|
7
7
|
import"./chunk-kzbzacz9.js";
|
|
8
|
-
import"./chunk-
|
|
8
|
+
import"./chunk-kmzzjv53.js";
|
|
9
9
|
import"./chunk-pqe7q1s7.js";
|
|
10
10
|
import {
|
|
11
11
|
hostAddressOptions
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
globalPrefixOf,
|
|
16
16
|
packageDir,
|
|
17
17
|
packagedVersion
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-s0h7c7da.js";
|
|
19
19
|
import"./chunk-df32avw6.js";
|
|
20
20
|
|
|
21
21
|
// apps/host/src/cli/upgrade.ts
|