rovloom 0.4.0 → 0.5.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.
Files changed (29) hide show
  1. package/README.md +13 -41
  2. package/dist/src/admin/index.js +1 -1
  3. package/dist/src/{chunk-1fyfrgte.js → chunk-0ake7e4r.js} +4 -4
  4. package/dist/src/{chunk-qfyefed3.js → chunk-1bf0wmgk.js} +1 -1
  5. package/dist/src/chunk-5j0gj6w2.js +7 -0
  6. package/dist/src/{chunk-dtj9y82v.js → chunk-5n8csngz.js} +119 -34
  7. package/dist/src/{chunk-v1httsp6.js → chunk-64ftwe9b.js} +2 -2
  8. package/dist/src/{chunk-76wgt2g5.js → chunk-9y36gntb.js} +6 -5
  9. package/dist/src/{chunk-ydmabg5t.js → chunk-9yg6x3gt.js} +5 -5
  10. package/dist/src/{chunk-keg92d31.js → chunk-abd4envz.js} +13 -11
  11. package/dist/src/{chunk-6hxy1fcg.js → chunk-bspzg8er.js} +2 -2
  12. package/dist/src/{chunk-t3pn1435.js → chunk-e7x51y0t.js} +2 -2
  13. package/dist/src/{chunk-qab3m6nh.js → chunk-ebm3kvnq.js} +18 -5
  14. package/dist/src/{chunk-ymsx7hhd.js → chunk-erdq0rn8.js} +8 -8
  15. package/dist/src/{chunk-wdr3sdsm.js → chunk-fnakrk0a.js} +42 -11
  16. package/dist/src/{chunk-bjdqj43d.js → chunk-hpzr94hm.js} +23 -6
  17. package/dist/src/{chunk-fd9n51mc.js → chunk-n073xnr1.js} +51 -22
  18. package/dist/src/{chunk-xmkgq3nh.js → chunk-r0nfthsf.js} +2 -2
  19. package/dist/src/{chunk-z1vhdr3c.js → chunk-rwpynx2j.js} +10 -10
  20. package/dist/src/{chunk-8x6ygvhh.js → chunk-sj24fpz3.js} +4 -4
  21. package/dist/src/{chunk-5vx1b9z8.js → chunk-xhq21g24.js} +3 -3
  22. package/dist/src/{chunk-4af38z2b.js → chunk-ybte82d3.js} +1 -1
  23. package/dist/src/{chunk-khmgp03q.js → chunk-ympzv86c.js} +65 -13
  24. package/dist/src/{chunk-se5daacy.js → chunk-z7kkfrgz.js} +1 -1
  25. package/dist/src/cli/index.js +12 -12
  26. package/dist/src/cli/main.js +9 -9
  27. package/dist/src/mcp/index.js +2 -2
  28. package/dist/src/webui/index.js +13 -3
  29. package/package.json +1 -1
@@ -6,13 +6,13 @@ import"./chunk-9tt13dm0.js";
6
6
  import"./chunk-g7pnjzkk.js";
7
7
  import {
8
8
  readOrCreateRoleConfig
9
- } from "./chunk-v1httsp6.js";
9
+ } from "./chunk-64ftwe9b.js";
10
10
  import {
11
11
  resolveRoleConfigPath2
12
- } from "./chunk-qfyefed3.js";
12
+ } from "./chunk-1bf0wmgk.js";
13
13
  import {
14
14
  CliError2
15
- } from "./chunk-bjdqj43d.js";
15
+ } from "./chunk-hpzr94hm.js";
16
16
  import"./chunk-3nnahj0j.js";
17
17
  import"./chunk-0y5542k8.js";
18
18
 
@@ -3,7 +3,7 @@ import {
3
3
  HTTP_BODY_BYTES2,
4
4
  createHttpFacade2,
5
5
  startHttpFacade2
6
- } from "./chunk-76wgt2g5.js";
6
+ } from "./chunk-9y36gntb.js";
7
7
  import"./chunk-smpevv7n.js";
8
8
  import"./chunk-7crhmqn2.js";
9
9
  import"./chunk-d71r315c.js";
@@ -14,6 +14,7 @@ import {
14
14
  parseManagementReadPath
15
15
  } from "./chunk-gav2y5y9.js";
16
16
  import {
17
+ isWildcardHostname,
17
18
  canonicalLoopbackHost
18
19
  } from "./chunk-6n9s7nfe.js";
19
20
 
@@ -37,6 +38,30 @@ var statuses = {
37
38
  invalid_response: 502,
38
39
  timeout: 504
39
40
  };
41
+ function lanAwareOrigin(request, loopback, lan) {
42
+ const raw = request.headers.get("host");
43
+ if (!raw || Buffer.byteLength(raw) > 2048) {
44
+ return null;
45
+ }
46
+ const expected = new URL(loopback);
47
+ const host = raw.toLowerCase();
48
+ if (host === expected.host.toLowerCase()) {
49
+ return expected.origin;
50
+ }
51
+ if (!lan) {
52
+ return null;
53
+ }
54
+ try {
55
+ const url = new URL(request.url);
56
+ const candidate = "http://" + host;
57
+ if (new URL(candidate).origin !== candidate) {
58
+ return null;
59
+ }
60
+ return url.host.toLowerCase() === host && url.protocol === "http:" ? candidate : null;
61
+ } catch {
62
+ return null;
63
+ }
64
+ }
40
65
  function failure(code, status) {
41
66
  return new Response(JSON.stringify({ error: code }), {
42
67
  status,
@@ -77,6 +102,9 @@ function assets(input) {
77
102
  return result;
78
103
  }
79
104
  function allowed(request, expected) {
105
+ if (expected === null) {
106
+ return null;
107
+ }
80
108
  if (new TextEncoder().encode(request.url).byteLength > MANAGEMENT_URL_BYTES) {
81
109
  return null;
82
110
  }
@@ -118,7 +146,7 @@ function context(identity, signal) {
118
146
  async function initialize(implementation, request, body, signal) {
119
147
  return implementation(request, new Response(body.slice().buffer, { headers: { ...headers, "content-type": managementAssetType("/") } }), signal);
120
148
  }
121
- function prepare(options, origin) {
149
+ function prepare(options, origin, lan = () => false) {
122
150
  if (!options || typeof options.authenticate !== "function") {
123
151
  throw new Error("management_authentication_required");
124
152
  }
@@ -174,7 +202,7 @@ function prepare(options, origin) {
174
202
  }
175
203
  let url;
176
204
  try {
177
- url = allowed(request, origin());
205
+ url = allowed(request, lanAwareOrigin(request, origin(), lan()));
178
206
  } catch {
179
207
  url = null;
180
208
  }
@@ -264,24 +292,27 @@ function prepare(options, origin) {
264
292
  }
265
293
  function createManagementReadHandler2(options) {
266
294
  const url = new URL(options.origin);
267
- if (url.origin !== options.origin || url.protocol !== "http:" || url.hostname !== "127.0.0.1" || url.username || url.password) {
295
+ if (url.origin !== options.origin || url.protocol !== "http:" || !["127.0.0.1", "[::1]"].includes(url.hostname) || url.username || url.password) {
268
296
  throw new Error("management_listener_invalid");
269
297
  }
270
- return prepare(options, () => options.origin);
298
+ return prepare(options, () => options.origin, () => options.lan === true);
271
299
  }
272
300
  function startManagementReadListener2(options) {
273
301
  if (!options) {
274
302
  throw new Error("management_listener_invalid");
275
303
  }
276
304
  let origin = "";
277
- const handler = prepare(options, () => origin);
305
+ let lan = false;
306
+ const handler = prepare(options, () => origin, () => lan);
278
307
  try {
279
308
  return startManagementListener2({
280
309
  port: options.port,
281
310
  hostname: options.hostname,
311
+ lan: options.lan === true,
282
312
  maxRequestBodySize: 1,
283
- handler: (actualOrigin) => {
313
+ handler: (actualOrigin, actualLan) => {
284
314
  origin = actualOrigin;
315
+ lan = actualLan;
285
316
  return handler;
286
317
  }
287
318
  });
@@ -307,7 +338,7 @@ function startManagementListener2(options) {
307
338
  });
308
339
  const url = new URL(`http://${canonicalLoopbackHost(options.hostname)}:${server.port}`).origin;
309
340
  try {
310
- handler = options.handler(url);
341
+ handler = options.handler(url, options.lan === true && isWildcardHostname(options.hostname));
311
342
  if (typeof handler?.fetch !== "function" || typeof handler.stop !== "function") {
312
343
  throw new Error("management_listener_invalid");
313
344
  }
@@ -844,7 +875,7 @@ function createManagementHandler2(options) {
844
875
  throw new Error("management_csrf_required");
845
876
  }
846
877
  const reads = createManagementReadHandler2(options);
847
- const origin = new URL(options.origin);
878
+ const expected = (request) => lanAwareOrigin(request, options.origin, options.lan === true);
848
879
  const pending = new Set;
849
880
  let stopped = false;
850
881
  let tokens = 16;
@@ -930,7 +961,7 @@ function createManagementHandler2(options) {
930
961
  size += Buffer.byteLength(name + value);
931
962
  count++;
932
963
  }
933
- if (request.url.length > 2048 || size > 16384 || count > 48 || url.origin !== options.origin || request.headers.get("host") !== origin.host || request.headers.get("origin") !== options.origin || url.username || url.password || url.search || url.hash || request.headers.has("sec-fetch-site") && request.headers.get("sec-fetch-site") !== "same-origin") {
964
+ if (request.url.length > 2048 || size > 16384 || count > 48 || url.origin !== expected(request) || request.headers.get("origin") !== url.origin || url.username || url.password || url.search || url.hash || request.headers.has("sec-fetch-site") && request.headers.get("sec-fetch-site") !== "same-origin") {
934
965
  return failure2("forbidden", 403);
935
966
  }
936
967
  if (request.method !== "POST") {
@@ -1025,16 +1056,37 @@ function createManagementSessionAdapter2(options) {
1025
1056
  throw new Error("management_cookie_name_invalid");
1026
1057
  }
1027
1058
  const origin = new URL(options.origin);
1028
- if (origin.origin !== options.origin || origin.protocol !== "http:" || origin.hostname !== "127.0.0.1" || origin.username || origin.password) {
1059
+ if (origin.origin !== options.origin || origin.protocol !== "http:" || !["127.0.0.1", "[::1]"].includes(origin.hostname) || origin.username || origin.password) {
1029
1060
  throw new Error("management_listener_invalid");
1030
1061
  }
1031
1062
  const identities = options.identities;
1032
1063
  const sessions = options.sessions;
1033
1064
  const now = options.now ?? Date.now;
1034
1065
  let observed = 0;
1066
+ function expected(request) {
1067
+ const raw = request.headers.get("host");
1068
+ if (!raw || Buffer.byteLength(raw) > 2048) {
1069
+ return null;
1070
+ }
1071
+ const host = raw.toLowerCase();
1072
+ if (host === origin.host.toLowerCase()) {
1073
+ return origin.origin;
1074
+ }
1075
+ if (!options.lan) {
1076
+ return null;
1077
+ }
1078
+ try {
1079
+ const url = new URL(request.url);
1080
+ const candidate = "http://" + host;
1081
+ return new URL(candidate).origin === candidate && url.host.toLowerCase() === host && url.protocol === "http:" ? candidate : null;
1082
+ } catch {
1083
+ return null;
1084
+ }
1085
+ }
1035
1086
  function cookie(request) {
1036
1087
  const url = new URL(request.url);
1037
- if (url.origin !== origin.origin || request.headers.get("host") !== origin.host || request.headers.has("origin") && request.headers.get("origin") !== origin.origin) {
1088
+ const trusted = expected(request);
1089
+ if (trusted === null || url.origin !== trusted || request.headers.has("origin") && request.headers.get("origin") !== trusted) {
1038
1090
  return null;
1039
1091
  }
1040
1092
  const site = request.headers.get("sec-fetch-site");
@@ -1115,7 +1167,7 @@ function createManagementSessionAdapter2(options) {
1115
1167
  if (request.method !== "POST") {
1116
1168
  return false;
1117
1169
  }
1118
- if (request.headers.get("origin") !== origin.origin || request.headers.has("sec-fetch-site") && request.headers.get("sec-fetch-site") !== "same-origin") {
1170
+ if (request.headers.get("origin") !== expected(request) || request.headers.has("sec-fetch-site") && request.headers.get("sec-fetch-site") !== "same-origin") {
1119
1171
  return false;
1120
1172
  }
1121
1173
  const candidate = request.headers.get("x-rovloom-csrf");
@@ -1132,4 +1184,4 @@ function createManagementSessionAdapter2(options) {
1132
1184
  }
1133
1185
  export { createManagementReadHandler2, startManagementReadListener2, startManagementListener2, loadManagementAssets2, ManagementServiceError2, StoreManagementWriteService2, createManagementHandler2, createManagementSessionAdapter2 };
1134
1186
 
1135
- //# debugId=FD715A6C580CBDB864756E2164756E21
1187
+ //# debugId=5F343A955701396E64756E2164756E21
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-7crhmqn2.js";
5
5
  import {
6
6
  CliError2
7
- } from "./chunk-bjdqj43d.js";
7
+ } from "./chunk-hpzr94hm.js";
8
8
  import {
9
9
  readPrivateBytes
10
10
  } from "./chunk-0y5542k8.js";
@@ -8,7 +8,7 @@ import {
8
8
  HELP2,
9
9
  parseCommand2,
10
10
  runCli2
11
- } from "../chunk-keg92d31.js";
11
+ } from "../chunk-abd4envz.js";
12
12
  import {
13
13
  Store2
14
14
  } from "../chunk-nyn75b8v.js";
@@ -16,7 +16,7 @@ import"../chunk-09f9q26d.js";
16
16
  import {
17
17
  FacadeServiceError2
18
18
  } from "../chunk-smpevv7n.js";
19
- import"../chunk-76wgt2g5.js";
19
+ import"../chunk-9y36gntb.js";
20
20
  import {
21
21
  Router2
22
22
  } from "../chunk-y4hksha9.js";
@@ -39,38 +39,38 @@ import {
39
39
  import"../chunk-d4ejrtjq.js";
40
40
  import"../chunk-5s2emvww.js";
41
41
  import"../chunk-4etdq0cp.js";
42
- import"../chunk-khmgp03q.js";
42
+ import"../chunk-ympzv86c.js";
43
43
  import"../chunk-5h82060k.js";
44
44
  import"../chunk-863tk45b.js";
45
45
  import"../chunk-zb641qa3.js";
46
46
  import"../chunk-ttsrctxg.js";
47
47
  import"../chunk-5svt6rwr.js";
48
48
  import"../chunk-2tn0r64b.js";
49
- import"../chunk-wdr3sdsm.js";
50
- import"../chunk-fd9n51mc.js";
49
+ import"../chunk-fnakrk0a.js";
50
+ import"../chunk-n073xnr1.js";
51
51
  import {
52
52
  createRuntimeCliRuntime2,
53
53
  MANAGEMENT_COOKIE_NAME2,
54
54
  MANAGEMENT_BOOTSTRAP_META2,
55
55
  createManagementPageInitializer2,
56
56
  createProductionCliRuntime2
57
- } from "../chunk-dtj9y82v.js";
58
- import"../chunk-qab3m6nh.js";
57
+ } from "../chunk-5n8csngz.js";
58
+ import"../chunk-ebm3kvnq.js";
59
59
  import {
60
60
  readRuntimeConfig2
61
- } from "../chunk-6hxy1fcg.js";
62
- import"../chunk-v1httsp6.js";
61
+ } from "../chunk-bspzg8er.js";
62
+ import"../chunk-64ftwe9b.js";
63
63
  import {
64
64
  resolveRoleConfigPath2
65
- } from "../chunk-qfyefed3.js";
66
- import"../chunk-se5daacy.js";
65
+ } from "../chunk-1bf0wmgk.js";
66
+ import"../chunk-z7kkfrgz.js";
67
67
  import {
68
68
  CliError2,
69
69
  parseConfig2,
70
70
  configDocument2,
71
71
  configTemplate2,
72
72
  readConfig2
73
- } from "../chunk-bjdqj43d.js";
73
+ } from "../chunk-hpzr94hm.js";
74
74
  import"../chunk-vwcntax3.js";
75
75
  import"../chunk-gbsbwssz.js";
76
76
  import"../chunk-3nnahj0j.js";
@@ -10,20 +10,20 @@ import"../chunk-g7pnjzkk.js";
10
10
  import {
11
11
  parseCommand2,
12
12
  runCli2
13
- } from "../chunk-keg92d31.js";
13
+ } from "../chunk-abd4envz.js";
14
14
  import {
15
15
  createNativeServiceBackend2,
16
16
  ServiceManager2
17
17
  } from "../chunk-ttm3c0jh.js";
18
- import"../chunk-6hxy1fcg.js";
19
- import"../chunk-v1httsp6.js";
18
+ import"../chunk-bspzg8er.js";
19
+ import"../chunk-64ftwe9b.js";
20
20
  import {
21
21
  resolveRoleConfigPath2
22
- } from "../chunk-qfyefed3.js";
23
- import"../chunk-se5daacy.js";
22
+ } from "../chunk-1bf0wmgk.js";
23
+ import"../chunk-z7kkfrgz.js";
24
24
  import {
25
25
  parseConfig2
26
- } from "../chunk-bjdqj43d.js";
26
+ } from "../chunk-hpzr94hm.js";
27
27
  import {
28
28
  manifest,
29
29
  serviceControlId
@@ -300,10 +300,10 @@ async function control(role) {
300
300
  }
301
301
  async function product() {
302
302
  if (!runtime) {
303
- const { createProductSources } = await import("../chunk-t3pn1435.js");
304
- const { CliSetup } = await import("../chunk-ymsx7hhd.js");
303
+ const { createProductSources } = await import("../chunk-e7x51y0t.js");
304
+ const { CliSetup } = await import("../chunk-erdq0rn8.js");
305
305
  setup = new CliSetup;
306
- runtime = (await import("../chunk-z1vhdr3c.js")).createProductionCliRuntime(createProductSources(), setup);
306
+ runtime = (await import("../chunk-rwpynx2j.js")).createProductionCliRuntime(createProductSources(), setup);
307
307
  }
308
308
  return runtime;
309
309
  }
@@ -5,7 +5,7 @@ import {
5
5
  HTTP_BODY_BYTES2,
6
6
  createHttpFacade2,
7
7
  startHttpFacade2
8
- } from "../chunk-76wgt2g5.js";
8
+ } from "../chunk-9y36gntb.js";
9
9
  import {
10
10
  StoreGatewayService2,
11
11
  RuntimeGatewayService2
@@ -22,7 +22,7 @@ import {
22
22
  import {
23
23
  MCP_REVISION2,
24
24
  PRODUCT_VERSION2
25
- } from "../chunk-xmkgq3nh.js";
25
+ } from "../chunk-r0nfthsf.js";
26
26
  import"../chunk-zj48jvfe.js";
27
27
  import"../chunk-0xgpxdgc.js";
28
28
  import"../chunk-gbsbwssz.js";
@@ -1,4 +1,7 @@
1
1
  // @bun
2
+ import {
3
+ DEFAULT_PAIRING_POLICY_REF
4
+ } from "../chunk-5j0gj6w2.js";
2
5
  import {
3
6
  ReadError2,
4
7
  createSnapshotReader2,
@@ -1192,6 +1195,12 @@ function createPreferenceControl(kind, choices, onChoose) {
1192
1195
  return { root, update, close, dispose };
1193
1196
  }
1194
1197
 
1198
+ // src/webui/request-id.ts
1199
+ function managementRequestId() {
1200
+ const bytes = globalThis.crypto.getRandomValues(new Uint8Array(16));
1201
+ return "request_" + Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
1202
+ }
1203
+
1195
1204
  // src/webui/write-contract.ts
1196
1205
  class ManagementClientError extends Error {
1197
1206
  problem;
@@ -1695,7 +1704,7 @@ function createDeviceManagementFlow(options) {
1695
1704
  let active;
1696
1705
  let generation = 0;
1697
1706
  let disposed = false;
1698
- const requestId = options.requestId ?? (() => "request_" + globalThis.crypto.randomUUID());
1707
+ const requestId = options.requestId ?? managementRequestId;
1699
1708
  async function execute(operation, args, signal) {
1700
1709
  if (signal.aborted) {
1701
1710
  throw new ManagementClientError("aborted");
@@ -2320,7 +2329,7 @@ function createPairingManagementFlow(options) {
2320
2329
  let active;
2321
2330
  let generation = 0;
2322
2331
  let disposed = false;
2323
- const requestId = options.requestId ?? (() => "request_" + globalThis.crypto.randomUUID());
2332
+ const requestId = options.requestId ?? managementRequestId;
2324
2333
  async function execute(operation, args, signal) {
2325
2334
  if (signal.aborted) {
2326
2335
  throw new ManagementClientError("aborted");
@@ -2569,6 +2578,7 @@ function createPairingActions(options) {
2569
2578
  policyInput.required = true;
2570
2579
  policyInput.maxLength = 128;
2571
2580
  policyInput.autocomplete = "off";
2581
+ policyInput.value = DEFAULT_PAIRING_POLICY_REF;
2572
2582
  policyLabel.append(policyCaption, policyInput);
2573
2583
  const create = node3("button", "pairing-confirm");
2574
2584
  create.type = "submit";
@@ -3507,4 +3517,4 @@ export {
3507
3517
  unavailableRead
3508
3518
  };
3509
3519
 
3510
- //# debugId=8E3F9EB456F6148764756E2164756E21
3520
+ //# debugId=D52975500C6ECA9664756E2164756E21
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rovloom",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Rovloom: multi-machine MCP gateway and connector for Luvus/Herdr runtimes",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",