negotium 0.1.12 → 0.1.13

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.
Files changed (137) hide show
  1. package/dist/canonical-mcp-bridge.js +2 -3
  2. package/dist/canonical-mcp-bridge.js.map +1 -1
  3. package/dist/chunk-a9y2rwxf.js.map +1 -1
  4. package/dist/{chunk-j0kjscb7.js → chunk-s2gez3wg.js} +20 -2
  5. package/dist/{chunk-j0kjscb7.js.map → chunk-s2gez3wg.js.map} +2 -2
  6. package/dist/cron.js +49 -25
  7. package/dist/cron.js.map +15 -14
  8. package/dist/hosted-agent.js +3012 -17
  9. package/dist/hosted-agent.js.map +30 -3
  10. package/dist/main.js +31323 -36
  11. package/dist/main.js.map +198 -3
  12. package/dist/prompts.js +11 -8
  13. package/dist/prompts.js.map +4 -4
  14. package/dist/runtime/src/application/submit-user-message.ts +3 -0
  15. package/dist/runtime/src/index.ts +7 -0
  16. package/dist/runtime/src/mcp/runtime-spec.ts +3 -0
  17. package/dist/runtime/src/mcp/session-comm/server.ts +1 -1
  18. package/dist/runtime/src/platform/mcp-config.ts +13 -0
  19. package/dist/runtime/src/prompts/builders.ts +20 -6
  20. package/dist/runtime/src/query/active-rooms.ts +2 -0
  21. package/dist/runtime/src/runtime/delivery-ack.ts +112 -0
  22. package/dist/runtime/src/runtime/errors.ts +12 -12
  23. package/dist/runtime/src/runtime/turn-runner.ts +12 -0
  24. package/dist/runtime/src/storage/runtime-turn-requests.ts +1 -0
  25. package/dist/runtime/src/types/api.ts +2 -0
  26. package/dist/runtime/src/types.ts +2 -0
  27. package/dist/runtime/src/version.ts +1 -1
  28. package/dist/runtime-helpers.js.map +1 -1
  29. package/dist/storage.js.map +1 -1
  30. package/dist/types/packages/core/src/mcp/runtime-spec.d.ts +2 -0
  31. package/dist/types/packages/core/src/platform/mcp-config.d.ts +4 -0
  32. package/dist/types/packages/core/src/prompts/builders.d.ts +2 -0
  33. package/dist/types/packages/core/src/types/api.d.ts +2 -0
  34. package/dist/types/packages/core/src/types.d.ts +2 -0
  35. package/dist/types/packages/core/src/version.d.ts +1 -1
  36. package/dist/vault.js.map +1 -1
  37. package/package.json +1 -1
  38. package/dist/chunk-00q25k7p.js +0 -2387
  39. package/dist/chunk-00q25k7p.js.map +0 -26
  40. package/dist/chunk-03kv7mvj.js +0 -2152
  41. package/dist/chunk-03kv7mvj.js.map +0 -15
  42. package/dist/chunk-05pm51dh.js +0 -589
  43. package/dist/chunk-05pm51dh.js.map +0 -11
  44. package/dist/chunk-0eh16bk1.js +0 -2936
  45. package/dist/chunk-0eh16bk1.js.map +0 -20
  46. package/dist/chunk-0yfqyv88.js +0 -108
  47. package/dist/chunk-0yfqyv88.js.map +0 -10
  48. package/dist/chunk-1k7t7bnx.js +0 -97
  49. package/dist/chunk-1k7t7bnx.js.map +0 -10
  50. package/dist/chunk-3gkfr9vb.js +0 -431
  51. package/dist/chunk-3gkfr9vb.js.map +0 -11
  52. package/dist/chunk-5akd1gbj.js +0 -281
  53. package/dist/chunk-5akd1gbj.js.map +0 -10
  54. package/dist/chunk-7k19pcg8.js +0 -577
  55. package/dist/chunk-7k19pcg8.js.map +0 -14
  56. package/dist/chunk-81tbfbmt.js +0 -10
  57. package/dist/chunk-81tbfbmt.js.map +0 -10
  58. package/dist/chunk-82qhv1mq.js +0 -512
  59. package/dist/chunk-82qhv1mq.js.map +0 -13
  60. package/dist/chunk-8dy7e2a9.js +0 -103
  61. package/dist/chunk-8dy7e2a9.js.map +0 -10
  62. package/dist/chunk-8f2sqmrj.js +0 -1712
  63. package/dist/chunk-8f2sqmrj.js.map +0 -18
  64. package/dist/chunk-9hjeemfz.js +0 -372
  65. package/dist/chunk-9hjeemfz.js.map +0 -10
  66. package/dist/chunk-a4aa2ccv.js +0 -141
  67. package/dist/chunk-a4aa2ccv.js.map +0 -10
  68. package/dist/chunk-bsg215q3.js +0 -3536
  69. package/dist/chunk-bsg215q3.js.map +0 -20
  70. package/dist/chunk-bxnfsc7w.js +0 -58
  71. package/dist/chunk-bxnfsc7w.js.map +0 -10
  72. package/dist/chunk-c500xe9z.js +0 -33
  73. package/dist/chunk-c500xe9z.js.map +0 -10
  74. package/dist/chunk-cngrf7ab.js +0 -149
  75. package/dist/chunk-cngrf7ab.js.map +0 -10
  76. package/dist/chunk-d7tprf06.js +0 -53
  77. package/dist/chunk-d7tprf06.js.map +0 -10
  78. package/dist/chunk-ddnrmkrv.js +0 -61
  79. package/dist/chunk-ddnrmkrv.js.map +0 -10
  80. package/dist/chunk-edb07sjp.js +0 -567
  81. package/dist/chunk-edb07sjp.js.map +0 -14
  82. package/dist/chunk-ejcm6zx8.js +0 -591
  83. package/dist/chunk-ejcm6zx8.js.map +0 -11
  84. package/dist/chunk-ezs352qs.js +0 -237
  85. package/dist/chunk-ezs352qs.js.map +0 -11
  86. package/dist/chunk-f5xgprg1.js +0 -59
  87. package/dist/chunk-f5xgprg1.js.map +0 -10
  88. package/dist/chunk-fbtb3v0s.js +0 -1339
  89. package/dist/chunk-fbtb3v0s.js.map +0 -16
  90. package/dist/chunk-ffefbd3r.js +0 -17
  91. package/dist/chunk-ffefbd3r.js.map +0 -10
  92. package/dist/chunk-gaknyw04.js +0 -708
  93. package/dist/chunk-gaknyw04.js.map +0 -14
  94. package/dist/chunk-gxmny6tq.js +0 -1637
  95. package/dist/chunk-gxmny6tq.js.map +0 -15
  96. package/dist/chunk-h7bj5zwb.js +0 -3069
  97. package/dist/chunk-h7bj5zwb.js.map +0 -32
  98. package/dist/chunk-hp4g7wx7.js +0 -46
  99. package/dist/chunk-hp4g7wx7.js.map +0 -10
  100. package/dist/chunk-hwy3n31w.js +0 -21
  101. package/dist/chunk-hwy3n31w.js.map +0 -9
  102. package/dist/chunk-jzz91jwh.js +0 -70
  103. package/dist/chunk-jzz91jwh.js.map +0 -10
  104. package/dist/chunk-k778y16p.js +0 -153
  105. package/dist/chunk-k778y16p.js.map +0 -11
  106. package/dist/chunk-mh5mexsf.js +0 -147
  107. package/dist/chunk-mh5mexsf.js.map +0 -11
  108. package/dist/chunk-mnwaext5.js +0 -318
  109. package/dist/chunk-mnwaext5.js.map +0 -10
  110. package/dist/chunk-nkgs40ch.js +0 -23
  111. package/dist/chunk-nkgs40ch.js.map +0 -10
  112. package/dist/chunk-pz57vwsm.js +0 -250
  113. package/dist/chunk-pz57vwsm.js.map +0 -11
  114. package/dist/chunk-r6kdp7gn.js +0 -252
  115. package/dist/chunk-r6kdp7gn.js.map +0 -10
  116. package/dist/chunk-rkvrkcgx.js +0 -117
  117. package/dist/chunk-rkvrkcgx.js.map +0 -10
  118. package/dist/chunk-s74rdyqe.js +0 -117
  119. package/dist/chunk-s74rdyqe.js.map +0 -12
  120. package/dist/chunk-sa874j5c.js +0 -9
  121. package/dist/chunk-sa874j5c.js.map +0 -10
  122. package/dist/chunk-sffqdkvq.js +0 -122
  123. package/dist/chunk-sffqdkvq.js.map +0 -10
  124. package/dist/chunk-tcs9qjps.js +0 -64
  125. package/dist/chunk-tcs9qjps.js.map +0 -10
  126. package/dist/chunk-wx83ep8e.js +0 -131
  127. package/dist/chunk-wx83ep8e.js.map +0 -10
  128. package/dist/chunk-xag86ng3.js +0 -122
  129. package/dist/chunk-xag86ng3.js.map +0 -10
  130. package/dist/chunk-xfdkep71.js +0 -371
  131. package/dist/chunk-xfdkep71.js.map +0 -11
  132. package/dist/chunk-xhm1rfpt.js +0 -2907
  133. package/dist/chunk-xhm1rfpt.js.map +0 -24
  134. package/dist/chunk-xpcps28p.js +0 -2138
  135. package/dist/chunk-xpcps28p.js.map +0 -29
  136. package/dist/chunk-yb4rbev9.js +0 -214
  137. package/dist/chunk-yb4rbev9.js.map +0 -10
@@ -1,371 +0,0 @@
1
- // @bun
2
- import"./chunk-h7bj5zwb.js";
3
- import"./chunk-tcs9qjps.js";
4
- import"./chunk-7k19pcg8.js";
5
- import"./chunk-8dy7e2a9.js";
6
- import"./chunk-9hjeemfz.js";
7
- import"./chunk-1k7t7bnx.js";
8
- import"./chunk-xhm1rfpt.js";
9
- import"./chunk-mnwaext5.js";
10
- import"./chunk-xpcps28p.js";
11
- import"./chunk-fbtb3v0s.js";
12
- import"./chunk-ejcm6zx8.js";
13
- import"./chunk-hp4g7wx7.js";
14
- import"./chunk-s74rdyqe.js";
15
- import"./chunk-k778y16p.js";
16
- import"./chunk-xag86ng3.js";
17
- import"./chunk-wx83ep8e.js";
18
- import"./chunk-00q25k7p.js";
19
- import"./chunk-gaknyw04.js";
20
- import"./chunk-mh5mexsf.js";
21
- import {
22
- DATA_DIR
23
- } from "./chunk-ezs352qs.js";
24
- import"./chunk-j0kjscb7.js";
25
- import"./chunk-82qhv1mq.js";
26
- import {
27
- logger
28
- } from "./chunk-ffefbd3r.js";
29
- import"./chunk-81tbfbmt.js";
30
- import"./chunk-sffqdkvq.js";
31
- import"./chunk-f5xgprg1.js";
32
- import"./chunk-hwy3n31w.js";
33
-
34
- // ../../adapters/otium/src/join.ts
35
- import { createHash, randomUUID } from "crypto";
36
- import {
37
- chmodSync,
38
- closeSync,
39
- existsSync,
40
- fsyncSync,
41
- linkSync,
42
- lstatSync,
43
- mkdirSync,
44
- openSync,
45
- readFileSync,
46
- renameSync,
47
- rmSync,
48
- statSync,
49
- unlinkSync,
50
- writeFileSync
51
- } from "fs";
52
- import { dirname, resolve } from "path";
53
-
54
- // ../../adapters/otium/src/secure-transport.ts
55
- function isLoopbackHostname(hostname) {
56
- const normalized = hostname.toLowerCase();
57
- if (normalized === "localhost" || normalized === "::1" || normalized === "[::1]")
58
- return true;
59
- const octets = normalized.split(".");
60
- return octets.length === 4 && octets[0] === "127" && octets.every((octet) => /^\d{1,3}$/.test(octet) && Number(octet) <= 255);
61
- }
62
- function credentialTransportUrl(value, label) {
63
- let url;
64
- try {
65
- url = new URL(value);
66
- } catch {
67
- throw new Error(`${label} is not a valid URL`);
68
- }
69
- if (url.username || url.password)
70
- throw new Error(`${label} must not contain URL credentials`);
71
- return url;
72
- }
73
- function assertSecureCentralUrl(value) {
74
- const url = credentialTransportUrl(value, "Otium central URL");
75
- if (url.protocol === "https:")
76
- return;
77
- if (url.protocol === "http:" && isLoopbackHostname(url.hostname))
78
- return;
79
- throw new Error("Otium central requires HTTPS or loopback HTTP");
80
- }
81
- function assertSecureRelayUrl(value) {
82
- const url = credentialTransportUrl(value, "Otium relay URL");
83
- if (url.protocol === "https:" || url.protocol === "wss:")
84
- return;
85
- if ((url.protocol === "http:" || url.protocol === "ws:") && isLoopbackHostname(url.hostname)) {
86
- return;
87
- }
88
- throw new Error("Otium relay requires HTTPS/WSS or loopback HTTP/WS");
89
- }
90
-
91
- // ../../adapters/otium/src/join.ts
92
- function joinFilePath() {
93
- return resolve(DATA_DIR, "otium-join.json");
94
- }
95
- function isHttpUrl(value) {
96
- return /^https?:\/\//.test(value);
97
- }
98
- function isRelayUrl(value) {
99
- return /^(?:https?|wss?):\/\//.test(value);
100
- }
101
- function normalizeJoin(raw) {
102
- const central = typeof raw.central === "string" ? raw.central.trim().replace(/\/+$/, "") : "";
103
- const relay = typeof raw.relay === "string" ? raw.relay.trim().replace(/\/+$/, "") : "";
104
- const cellId = typeof raw.cellId === "string" ? raw.cellId.trim() : "";
105
- const secret = typeof raw.secret === "string" ? raw.secret.trim() : "";
106
- if (!central || !isHttpUrl(central)) {
107
- throw new Error("invite code is missing a valid http(s) central URL");
108
- }
109
- if (relay && !isRelayUrl(relay))
110
- throw new Error("invite code has an invalid relay URL");
111
- if (!cellId)
112
- throw new Error("invite code is missing cellId");
113
- if (!secret)
114
- throw new Error("invite code is missing secret");
115
- assertSecureCentralUrl(central);
116
- if (relay)
117
- assertSecureRelayUrl(relay);
118
- return {
119
- ...typeof raw.v === "number" ? { v: raw.v } : {},
120
- central,
121
- ...relay ? { relay } : {},
122
- cellId,
123
- secret
124
- };
125
- }
126
- function parseInviteCode(code) {
127
- const trimmed = code.trim();
128
- if (!trimmed)
129
- throw new Error("invite code is empty");
130
- let decoded;
131
- try {
132
- decoded = Buffer.from(trimmed, "base64url").toString("utf-8");
133
- } catch {
134
- throw new Error("invite code is not valid base64url");
135
- }
136
- let parsed;
137
- try {
138
- parsed = JSON.parse(decoded);
139
- } catch {
140
- throw new Error("invite code does not decode to JSON");
141
- }
142
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
143
- throw new Error("invite code does not decode to a JSON object");
144
- }
145
- return normalizeJoin(parsed);
146
- }
147
- var JOIN_LOCK_STALE_MS = 30000;
148
- function joinLockPath() {
149
- return resolve(DATA_DIR, ".otium-join.lock");
150
- }
151
- function processIsAlive(pid) {
152
- if (!Number.isSafeInteger(pid) || pid <= 0)
153
- return false;
154
- try {
155
- process.kill(pid, 0);
156
- return true;
157
- } catch (error) {
158
- return error.code !== "ESRCH";
159
- }
160
- }
161
- function withJoinCredentialLock(operation) {
162
- const lockPath = joinLockPath();
163
- const ownerPath = resolve(lockPath, "owner.json");
164
- const owner = { pid: process.pid, token: randomUUID() };
165
- mkdirSync(dirname(lockPath), { recursive: true });
166
- for (let attempt = 0;; attempt += 1) {
167
- let created = false;
168
- try {
169
- mkdirSync(lockPath, { mode: 448 });
170
- created = true;
171
- writeFileSync(ownerPath, `${JSON.stringify(owner)}
172
- `, { mode: 384 });
173
- const ownerFd = openSync(ownerPath, "r");
174
- try {
175
- fsyncSync(ownerFd);
176
- } finally {
177
- closeSync(ownerFd);
178
- }
179
- break;
180
- } catch (error) {
181
- if (created) {
182
- rmSync(lockPath, { recursive: true, force: true });
183
- throw error;
184
- }
185
- if (error.code !== "EEXIST")
186
- throw error;
187
- let current = null;
188
- try {
189
- current = JSON.parse(readFileSync(ownerPath, "utf8"));
190
- } catch {}
191
- let ageMs;
192
- try {
193
- ageMs = Date.now() - statSync(lockPath).mtimeMs;
194
- } catch (statError) {
195
- if (statError.code === "ENOENT")
196
- continue;
197
- throw statError;
198
- }
199
- if (current && processIsAlive(current.pid) || !current && ageMs <= JOIN_LOCK_STALE_MS) {
200
- throw new Error(`another Otium join credential operation is in progress at ${lockPath}`);
201
- }
202
- if (attempt > 0) {
203
- throw new Error(`could not recover stale Otium join credential lock at ${lockPath}`);
204
- }
205
- const stalePath = `${lockPath}.stale.${process.pid}.${randomUUID()}`;
206
- try {
207
- renameSync(lockPath, stalePath);
208
- rmSync(stalePath, { recursive: true, force: true });
209
- } catch (staleError) {
210
- if (staleError.code !== "ENOENT")
211
- throw staleError;
212
- }
213
- }
214
- }
215
- try {
216
- return operation();
217
- } finally {
218
- try {
219
- const current = JSON.parse(readFileSync(ownerPath, "utf8"));
220
- if (current.pid === owner.pid && current.token === owner.token) {
221
- rmSync(lockPath, { recursive: true, force: true });
222
- }
223
- } catch {}
224
- }
225
- }
226
- function joinsEqual(left, right) {
227
- return left.central === right.central && left.relay === right.relay && left.cellId === right.cellId && left.secret === right.secret;
228
- }
229
- function normalizedJoin(join) {
230
- return normalizeJoin({
231
- v: join.v,
232
- central: join.central,
233
- relay: join.relay,
234
- cellId: join.cellId,
235
- secret: join.secret
236
- });
237
- }
238
- function joinCredentialDigest(join) {
239
- return createHash("sha256").update(JSON.stringify(normalizedJoin(join))).digest("base64url");
240
- }
241
- function readPersistedJoin(path = joinFilePath()) {
242
- if (!existsSync(path))
243
- return null;
244
- const parsed = JSON.parse(readFileSync(path, "utf-8"));
245
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
246
- throw new Error("persisted join credentials are not a JSON object");
247
- }
248
- return normalizeJoin(parsed);
249
- }
250
- function isJoinPersisted(join) {
251
- try {
252
- const persisted = readPersistedJoin();
253
- return persisted !== null && joinsEqual(persisted, normalizedJoin(join));
254
- } catch {
255
- return false;
256
- }
257
- }
258
- function saveJoinWhileLocked(join, options = {}) {
259
- const path = joinFilePath();
260
- const directory = dirname(path);
261
- const normalized = normalizedJoin(join);
262
- mkdirSync(directory, { recursive: true });
263
- if (existsSync(path)) {
264
- if (lstatSync(path).isSymbolicLink()) {
265
- throw new Error(`refusing to replace symlinked Otium join file at ${path}`);
266
- }
267
- let existing = null;
268
- try {
269
- existing = readPersistedJoin(path);
270
- } catch (error) {
271
- if (!options.replaceExisting) {
272
- throw new Error(`existing Otium join file at ${path} is invalid; pass --replace to replace it`, { cause: error });
273
- }
274
- }
275
- if (existing && joinsEqual(existing, normalized)) {
276
- chmodSync(path, 384);
277
- const fileFd = openSync(path, "r");
278
- try {
279
- fsyncSync(fileFd);
280
- } finally {
281
- closeSync(fileFd);
282
- }
283
- const directoryFd = openSync(directory, "r");
284
- try {
285
- fsyncSync(directoryFd);
286
- } finally {
287
- closeSync(directoryFd);
288
- }
289
- return path;
290
- }
291
- if (!options.replaceExisting) {
292
- throw new Error(`this node is already joined${existing ? ` as ${existing.cellId}` : " with an invalid join file"}; pass --replace to replace its credentials`);
293
- }
294
- }
295
- const temporaryPath = resolve(directory, `.otium-join.json.${process.pid}.${randomUUID()}.tmp`);
296
- let fd;
297
- try {
298
- fd = openSync(temporaryPath, "wx", 384);
299
- writeFileSync(fd, `${JSON.stringify(normalized, null, 2)}
300
- `, "utf8");
301
- fsyncSync(fd);
302
- closeSync(fd);
303
- fd = undefined;
304
- if (options.replaceExisting) {
305
- renameSync(temporaryPath, path);
306
- } else {
307
- linkSync(temporaryPath, path);
308
- unlinkSync(temporaryPath);
309
- }
310
- chmodSync(path, 384);
311
- const directoryFd = openSync(directory, "r");
312
- try {
313
- fsyncSync(directoryFd);
314
- } finally {
315
- closeSync(directoryFd);
316
- }
317
- } catch (error) {
318
- if (fd !== undefined)
319
- closeSync(fd);
320
- if (existsSync(temporaryPath))
321
- unlinkSync(temporaryPath);
322
- throw error;
323
- }
324
- return path;
325
- }
326
- function saveJoin(join, options = {}) {
327
- return withJoinCredentialLock(() => saveJoinWhileLocked(join, options));
328
- }
329
- function loadJoin() {
330
- const central = process.env.OTIUM_CENTRAL_URL?.trim();
331
- const cellId = process.env.OTIUM_CELL_ID?.trim();
332
- const secret = process.env.OTIUM_CELL_SECRET?.trim();
333
- const relay = process.env.OTIUM_RELAY_URL?.trim();
334
- if (central && cellId && secret) {
335
- try {
336
- return normalizeJoin({ central, relay, cellId, secret });
337
- } catch (err) {
338
- logger.warn({ err }, "otium: invalid OTIUM_CENTRAL_URL/OTIUM_CELL_ID/OTIUM_CELL_SECRET env");
339
- return null;
340
- }
341
- }
342
- if (central || cellId || secret) {
343
- logger.warn("otium: OTIUM_CENTRAL_URL, OTIUM_CELL_ID, OTIUM_CELL_SECRET must be set together \u2014 ignoring partial env");
344
- }
345
- const path = joinFilePath();
346
- if (!existsSync(path))
347
- return null;
348
- try {
349
- const parsed = JSON.parse(readFileSync(path, "utf-8"));
350
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
351
- return null;
352
- return normalizeJoin(parsed);
353
- } catch (err) {
354
- logger.warn({ err, path }, "otium: failed to read join file");
355
- return null;
356
- }
357
- }
358
- export {
359
- withJoinCredentialLock,
360
- saveJoinWhileLocked,
361
- saveJoin,
362
- parseInviteCode,
363
- loadJoin,
364
- joinFilePath,
365
- joinCredentialDigest,
366
- isJoinPersisted
367
- };
368
-
369
- export { assertSecureCentralUrl, assertSecureRelayUrl, joinFilePath, parseInviteCode, withJoinCredentialLock, joinCredentialDigest, isJoinPersisted, saveJoinWhileLocked, saveJoin, loadJoin };
370
-
371
- //# debugId=4EF2651906A11C3664756E2164756E21
@@ -1,11 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../adapters/otium/src/join.ts", "../../../adapters/otium/src/secure-transport.ts"],
4
- "sourcesContent": [
5
- "/**\n * otium node join credentials — the v0 \"invite code\" is a base64url JSON\n * bundle `{ v, central, cellId, secret }` produced by the hub operator\n * (scripts/otium-experiment/hub-setup.ts). `negotium otium join <code>` decodes it\n * and persists it under `${DATA_DIR}/otium-join.json` (0600); `serve` mounts\n * the peer routes whenever that file (or the env triple) is present.\n */\n\nimport { createHash, randomUUID } from \"node:crypto\";\nimport {\n chmodSync,\n closeSync,\n existsSync,\n fsyncSync,\n linkSync,\n lstatSync,\n mkdirSync,\n openSync,\n readFileSync,\n renameSync,\n rmSync,\n statSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\nimport { DATA_DIR, logger } from \"@negotium/core\";\nimport { assertSecureCentralUrl, assertSecureRelayUrl } from \"@/secure-transport\";\n\nexport interface OtiumJoin {\n /** Invite code format version (v0 bundles carry 1). */\n v?: number;\n /** central-api origin, e.g. \"http://127.0.0.1:4600\". */\n central: string;\n /** Optional relay origin used for outbound NAT traversal. */\n relay?: string;\n /** This node's runtime cell id (cell_…). */\n cellId: string;\n /** This node's runtime cell secret (rcs_…) — never leaves this process. */\n secret: string;\n}\n\nexport function joinFilePath(): string {\n return resolve(DATA_DIR, \"otium-join.json\");\n}\n\nfunction isHttpUrl(value: string): boolean {\n return /^https?:\\/\\//.test(value);\n}\n\nfunction isRelayUrl(value: string): boolean {\n return /^(?:https?|wss?):\\/\\//.test(value);\n}\n\nfunction normalizeJoin(raw: Record<string, unknown>): OtiumJoin {\n const central = typeof raw.central === \"string\" ? raw.central.trim().replace(/\\/+$/, \"\") : \"\";\n const relay = typeof raw.relay === \"string\" ? raw.relay.trim().replace(/\\/+$/, \"\") : \"\";\n const cellId = typeof raw.cellId === \"string\" ? raw.cellId.trim() : \"\";\n const secret = typeof raw.secret === \"string\" ? raw.secret.trim() : \"\";\n if (!central || !isHttpUrl(central)) {\n throw new Error(\"invite code is missing a valid http(s) central URL\");\n }\n if (relay && !isRelayUrl(relay)) throw new Error(\"invite code has an invalid relay URL\");\n if (!cellId) throw new Error(\"invite code is missing cellId\");\n if (!secret) throw new Error(\"invite code is missing secret\");\n assertSecureCentralUrl(central);\n if (relay) assertSecureRelayUrl(relay);\n return {\n ...(typeof raw.v === \"number\" ? { v: raw.v } : {}),\n central,\n ...(relay ? { relay } : {}),\n cellId,\n secret,\n };\n}\n\n/** Decode a v0 invite code: base64url(JSON {v, central, cellId, secret}). */\nexport function parseInviteCode(code: string): OtiumJoin {\n const trimmed = code.trim();\n if (!trimmed) throw new Error(\"invite code is empty\");\n let decoded: string;\n try {\n decoded = Buffer.from(trimmed, \"base64url\").toString(\"utf-8\");\n } catch {\n throw new Error(\"invite code is not valid base64url\");\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(decoded);\n } catch {\n throw new Error(\"invite code does not decode to JSON\");\n }\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n throw new Error(\"invite code does not decode to a JSON object\");\n }\n return normalizeJoin(parsed as Record<string, unknown>);\n}\n\nexport interface SaveJoinOptions {\n /** Explicitly replace credentials for a different cell/workspace. */\n replaceExisting?: boolean;\n}\n\ninterface JoinLockOwner {\n pid: number;\n token: string;\n}\n\nconst JOIN_LOCK_STALE_MS = 30_000;\n\nfunction joinLockPath(): string {\n return resolve(DATA_DIR, \".otium-join.lock\");\n}\n\nfunction processIsAlive(pid: number): boolean {\n if (!Number.isSafeInteger(pid) || pid <= 0) return false;\n try {\n process.kill(pid, 0);\n return true;\n } catch (error) {\n return (error as NodeJS.ErrnoException).code !== \"ESRCH\";\n }\n}\n\n/** @internal Cross-process critical section for join/enrollment credential state. */\nexport function withJoinCredentialLock<T>(operation: () => T): T {\n const lockPath = joinLockPath();\n const ownerPath = resolve(lockPath, \"owner.json\");\n const owner: JoinLockOwner = { pid: process.pid, token: randomUUID() };\n mkdirSync(dirname(lockPath), { recursive: true });\n\n for (let attempt = 0; ; attempt += 1) {\n let created = false;\n try {\n mkdirSync(lockPath, { mode: 0o700 });\n created = true;\n writeFileSync(ownerPath, `${JSON.stringify(owner)}\\n`, { mode: 0o600 });\n const ownerFd = openSync(ownerPath, \"r\");\n try {\n fsyncSync(ownerFd);\n } finally {\n closeSync(ownerFd);\n }\n break;\n } catch (error) {\n if (created) {\n rmSync(lockPath, { recursive: true, force: true });\n throw error;\n }\n if ((error as NodeJS.ErrnoException).code !== \"EEXIST\") throw error;\n let current: JoinLockOwner | null = null;\n try {\n current = JSON.parse(readFileSync(ownerPath, \"utf8\")) as JoinLockOwner;\n } catch {\n // A live acquirer may be between mkdir and owner write. Only recover an\n // ownerless lock after it has been stale long enough.\n }\n let ageMs: number;\n try {\n ageMs = Date.now() - statSync(lockPath).mtimeMs;\n } catch (statError) {\n if ((statError as NodeJS.ErrnoException).code === \"ENOENT\") continue;\n throw statError;\n }\n if ((current && processIsAlive(current.pid)) || (!current && ageMs <= JOIN_LOCK_STALE_MS)) {\n throw new Error(`another Otium join credential operation is in progress at ${lockPath}`);\n }\n if (attempt > 0) {\n throw new Error(`could not recover stale Otium join credential lock at ${lockPath}`);\n }\n const stalePath = `${lockPath}.stale.${process.pid}.${randomUUID()}`;\n try {\n renameSync(lockPath, stalePath);\n rmSync(stalePath, { recursive: true, force: true });\n } catch (staleError) {\n if ((staleError as NodeJS.ErrnoException).code !== \"ENOENT\") throw staleError;\n }\n }\n }\n\n try {\n return operation();\n } finally {\n try {\n const current = JSON.parse(readFileSync(ownerPath, \"utf8\")) as JoinLockOwner;\n if (current.pid === owner.pid && current.token === owner.token) {\n rmSync(lockPath, { recursive: true, force: true });\n }\n } catch {\n // Never remove a lock whose ownership can no longer be proven.\n }\n }\n}\n\nfunction joinsEqual(left: OtiumJoin, right: OtiumJoin): boolean {\n return (\n left.central === right.central &&\n left.relay === right.relay &&\n left.cellId === right.cellId &&\n left.secret === right.secret\n );\n}\n\nfunction normalizedJoin(join: OtiumJoin): OtiumJoin {\n return normalizeJoin({\n v: join.v,\n central: join.central,\n relay: join.relay,\n cellId: join.cellId,\n secret: join.secret,\n });\n}\n\n/** Stable digest used to bind pending enrollment material to one exact join. */\nexport function joinCredentialDigest(join: OtiumJoin): string {\n return createHash(\"sha256\")\n .update(JSON.stringify(normalizedJoin(join)))\n .digest(\"base64url\");\n}\n\nfunction readPersistedJoin(path = joinFilePath()): OtiumJoin | null {\n if (!existsSync(path)) return null;\n const parsed = JSON.parse(readFileSync(path, \"utf-8\"));\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n throw new Error(\"persisted join credentials are not a JSON object\");\n }\n return normalizeJoin(parsed as Record<string, unknown>);\n}\n\n/** True only when the join file on disk contains these exact credentials. */\nexport function isJoinPersisted(join: OtiumJoin): boolean {\n try {\n const persisted = readPersistedJoin();\n return persisted !== null && joinsEqual(persisted, normalizedJoin(join));\n } catch {\n return false;\n }\n}\n\n/**\n * Persist join credentials atomically (0600 — the cell secret is a bearer\n * credential). Re-saving the same join is idempotent. Replacing a different\n * join must be explicit so an enrollment retry cannot silently detach a node.\n */\n/** @internal Caller must hold withJoinCredentialLock. */\nexport function saveJoinWhileLocked(join: OtiumJoin, options: SaveJoinOptions = {}): string {\n const path = joinFilePath();\n const directory = dirname(path);\n const normalized = normalizedJoin(join);\n mkdirSync(directory, { recursive: true });\n\n if (existsSync(path)) {\n if (lstatSync(path).isSymbolicLink()) {\n throw new Error(`refusing to replace symlinked Otium join file at ${path}`);\n }\n let existing: OtiumJoin | null = null;\n try {\n existing = readPersistedJoin(path)!;\n } catch (error) {\n if (!options.replaceExisting) {\n throw new Error(\n `existing Otium join file at ${path} is invalid; pass --replace to replace it`,\n { cause: error },\n );\n }\n }\n if (existing && joinsEqual(existing, normalized)) {\n chmodSync(path, 0o600);\n const fileFd = openSync(path, \"r\");\n try {\n fsyncSync(fileFd);\n } finally {\n closeSync(fileFd);\n }\n const directoryFd = openSync(directory, \"r\");\n try {\n fsyncSync(directoryFd);\n } finally {\n closeSync(directoryFd);\n }\n return path;\n }\n if (!options.replaceExisting) {\n throw new Error(\n `this node is already joined${existing ? ` as ${existing.cellId}` : \" with an invalid join file\"}; pass --replace to replace its credentials`,\n );\n }\n }\n\n const temporaryPath = resolve(directory, `.otium-join.json.${process.pid}.${randomUUID()}.tmp`);\n let fd: number | undefined;\n try {\n fd = openSync(temporaryPath, \"wx\", 0o600);\n writeFileSync(fd, `${JSON.stringify(normalized, null, 2)}\\n`, \"utf8\");\n fsyncSync(fd);\n closeSync(fd);\n fd = undefined;\n if (options.replaceExisting) {\n renameSync(temporaryPath, path);\n } else {\n // Unlike rename(), link fails when another process won the initial join\n // race, so a non-explicit save can never overwrite its credentials.\n linkSync(temporaryPath, path);\n unlinkSync(temporaryPath);\n }\n chmodSync(path, 0o600);\n const directoryFd = openSync(directory, \"r\");\n try {\n fsyncSync(directoryFd);\n } finally {\n closeSync(directoryFd);\n }\n } catch (error) {\n if (fd !== undefined) closeSync(fd);\n if (existsSync(temporaryPath)) unlinkSync(temporaryPath);\n throw error;\n }\n return path;\n}\n\nexport function saveJoin(join: OtiumJoin, options: SaveJoinOptions = {}): string {\n return withJoinCredentialLock(() => saveJoinWhileLocked(join, options));\n}\n\n/**\n * Load join credentials. Env triple (OTIUM_CENTRAL_URL / OTIUM_CELL_ID /\n * OTIUM_CELL_SECRET) wins when all three are set — same values `negotium\n * join` persists, useful for tests and multi-node-on-one-box. Fail-closed:\n * a partial env triple or a corrupt file yields null (worker stays off).\n */\nexport function loadJoin(): OtiumJoin | null {\n const central = process.env.OTIUM_CENTRAL_URL?.trim();\n const cellId = process.env.OTIUM_CELL_ID?.trim();\n const secret = process.env.OTIUM_CELL_SECRET?.trim();\n const relay = process.env.OTIUM_RELAY_URL?.trim();\n if (central && cellId && secret) {\n try {\n return normalizeJoin({ central, relay, cellId, secret });\n } catch (err) {\n logger.warn({ err }, \"otium: invalid OTIUM_CENTRAL_URL/OTIUM_CELL_ID/OTIUM_CELL_SECRET env\");\n return null;\n }\n }\n if (central || cellId || secret) {\n logger.warn(\n \"otium: OTIUM_CENTRAL_URL, OTIUM_CELL_ID, OTIUM_CELL_SECRET must be set together — ignoring partial env\",\n );\n }\n const path = joinFilePath();\n if (!existsSync(path)) return null;\n try {\n const parsed = JSON.parse(readFileSync(path, \"utf-8\"));\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) return null;\n return normalizeJoin(parsed as Record<string, unknown>);\n } catch (err) {\n logger.warn({ err, path }, \"otium: failed to read join file\");\n return null;\n }\n}\n",
6
- "function isLoopbackHostname(hostname: string): boolean {\n const normalized = hostname.toLowerCase();\n if (normalized === \"localhost\" || normalized === \"::1\" || normalized === \"[::1]\") return true;\n const octets = normalized.split(\".\");\n return (\n octets.length === 4 &&\n octets[0] === \"127\" &&\n octets.every((octet) => /^\\d{1,3}$/.test(octet) && Number(octet) <= 255)\n );\n}\n\nfunction credentialTransportUrl(value: string, label: string): URL {\n let url: URL;\n try {\n url = new URL(value);\n } catch {\n throw new Error(`${label} is not a valid URL`);\n }\n if (url.username || url.password) throw new Error(`${label} must not contain URL credentials`);\n return url;\n}\n\nexport function assertSecureCentralUrl(value: string): void {\n const url = credentialTransportUrl(value, \"Otium central URL\");\n if (url.protocol === \"https:\") return;\n if (url.protocol === \"http:\" && isLoopbackHostname(url.hostname)) return;\n throw new Error(\"Otium central requires HTTPS or loopback HTTP\");\n}\n\nexport function assertSecureRelayUrl(value: string): void {\n const url = credentialTransportUrl(value, \"Otium relay URL\");\n if (url.protocol === \"https:\" || url.protocol === \"wss:\") return;\n if ((url.protocol === \"http:\" || url.protocol === \"ws:\") && isLoopbackHostname(url.hostname)) {\n return;\n }\n throw new Error(\"Otium relay requires HTTPS/WSS or loopback HTTP/WS\");\n}\n"
7
- ],
8
- "mappings": "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",
9
- "debugId": "4EF2651906A11C3664756E2164756E21",
10
- "names": []
11
- }