@ai-ecoverse/slicc-kernel 1.89.0 → 1.90.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/index.js CHANGED
@@ -326,6 +326,56 @@ function clipboardAnswerer(port, hook) {
326
326
  };
327
327
  }
328
328
 
329
+ // src/facade/port.ts
330
+ function serveFacadePort(port, hook, { name, stamp }, onDone) {
331
+ let conn;
332
+ let done = false;
333
+ const end = () => {
334
+ done = true;
335
+ port.close();
336
+ onDone?.();
337
+ };
338
+ const finish = () => {
339
+ if (done) return;
340
+ port.postMessage({ close: true });
341
+ end();
342
+ };
343
+ port.addEventListener(
344
+ "message",
345
+ ({ data }) => {
346
+ if (data.b !== void 0) conn?.send(data.b);
347
+ else if (data.close && !done) {
348
+ end();
349
+ conn?.close(typeof data.close === "string" ? data.close : void 0);
350
+ }
351
+ }
352
+ );
353
+ port.start?.();
354
+ new Promise((resolve) => resolve(hook(stamp, { name }))).then(
355
+ (opened) => {
356
+ conn = opened;
357
+ if (done) return opened.close();
358
+ opened.onmessage = (bytes) => {
359
+ if (done) return;
360
+ const copy = bytes.slice();
361
+ port.postMessage({ b: copy }, [copy.buffer]);
362
+ };
363
+ opened.onclose = () => finish();
364
+ port.postMessage({ open: true });
365
+ },
366
+ (e) => {
367
+ if (done) return;
368
+ port.postMessage({ error: e instanceof Error ? e.message : String(e) });
369
+ end();
370
+ }
371
+ );
372
+ return () => {
373
+ if (done) return;
374
+ conn?.close();
375
+ finish();
376
+ };
377
+ }
378
+
329
379
  // src/fs/types.ts
330
380
  var DEFAULT_USERS = "enforce";
331
381
 
@@ -1286,7 +1336,7 @@ var RemoteTransport = class {
1286
1336
  };
1287
1337
 
1288
1338
  // src/client/protocol.ts
1289
- var PROTOCOL = [1, 10];
1339
+ var PROTOCOL = [1, 11];
1290
1340
  function locksOf(scope = globalThis) {
1291
1341
  const locks = scope.navigator?.locks;
1292
1342
  return typeof locks?.request === "function" ? locks : void 0;
@@ -1353,6 +1403,8 @@ var Channel = class {
1353
1403
  watching = /* @__PURE__ */ new Map();
1354
1404
  cdpHooks = /* @__PURE__ */ new Map();
1355
1405
  cdpOpen = /* @__PURE__ */ new Set();
1406
+ facadeHooks = /* @__PURE__ */ new Map();
1407
+ facadeOpen = /* @__PURE__ */ new Set();
1356
1408
  protocol = PROTOCOL;
1357
1409
  nextId = 0;
1358
1410
  port;
@@ -1375,6 +1427,8 @@ var Channel = class {
1375
1427
  this.remote?.fail(error);
1376
1428
  for (const close of [...this.cdpOpen]) close();
1377
1429
  this.cdpOpen.clear();
1430
+ for (const close of [...this.facadeOpen]) close();
1431
+ this.facadeOpen.clear();
1378
1432
  for (const call of this.pending.values()) call.reject(error);
1379
1433
  this.pending.clear();
1380
1434
  this.release();
@@ -1404,6 +1458,10 @@ var Channel = class {
1404
1458
  this.openCdp(data);
1405
1459
  return;
1406
1460
  }
1461
+ if (data.facadeOpen && data.port) {
1462
+ this.openFacade(data);
1463
+ return;
1464
+ }
1407
1465
  if (data.watch !== void 0) {
1408
1466
  this.watching.get(data.watch)?.(data.change);
1409
1467
  return;
@@ -1446,7 +1504,36 @@ var Channel = class {
1446
1504
  const close = serveCdpPort(port, hook, request, () => this.cdpOpen.delete(close));
1447
1505
  this.cdpOpen.add(close);
1448
1506
  }
1507
+ openFacade({ facadeOpen: { registration, ...request }, port }) {
1508
+ const hook = registration === void 0 ? void 0 : this.facadeHooks.get(registration);
1509
+ if (!hook || this.failure) {
1510
+ port.postMessage({ error: "this client no longer serves the facade" });
1511
+ port.close();
1512
+ return;
1513
+ }
1514
+ const close = serveFacadePort(port, hook, request, () => this.facadeOpen.delete(close));
1515
+ this.facadeOpen.add(close);
1516
+ }
1449
1517
  };
1518
+ async function serveFacadeOn(channel, name, hook) {
1519
+ if (typeof hook !== "function") throw new TypeError("serveFacade: hook must be a function");
1520
+ await since(channel, 11, "facade serving", async () => {
1521
+ });
1522
+ const { id, done } = channel.request({ op: "serve-facade", name });
1523
+ channel.facadeHooks.set(id, hook);
1524
+ try {
1525
+ await done;
1526
+ } catch (error) {
1527
+ channel.facadeHooks.delete(id);
1528
+ throw error;
1529
+ }
1530
+ return {
1531
+ close: () => {
1532
+ if (!channel.facadeHooks.delete(id)) return;
1533
+ void channel.call({ op: "unserve-facade", registration: id }).catch(() => void 0);
1534
+ }
1535
+ };
1536
+ }
1450
1537
  async function serveCdpOn(channel, hook, options) {
1451
1538
  await since(channel, 5, "CDP serving", async () => {
1452
1539
  });
@@ -1680,6 +1767,7 @@ async function attachKernel(port, options = {}) {
1680
1767
  loopbackFetch: (input, options2) => loopbackFetch((o) => dialOn(channel, o), input, options2),
1681
1768
  fs: fsOn(channel),
1682
1769
  serveCdp: (hook, options2 = {}) => serveCdpOn(channel, hook, options2),
1770
+ serveFacade: (name, hook) => serveFacadeOn(channel, name, hook),
1683
1771
  onTraits(listener) {
1684
1772
  channel.traitsListeners.add(listener);
1685
1773
  return () => channel.traitsListeners.delete(listener);
@@ -2019,6 +2107,7 @@ function initCall(options, transport) {
2019
2107
  ...uplinkInit(options.network?.uplink),
2020
2108
  ...options.hostfs ? { hostfs: true } : {},
2021
2109
  ...options.cdp ? { cdp: true } : {},
2110
+ ...facadesInit(options.facades),
2022
2111
  ...options.hostname !== void 0 ? { hostname: options.hostname } : {},
2023
2112
  users: options.users === void 0 ? DEFAULT_USERS : options.users,
2024
2113
  ...options.onDenial ? { denials: true } : {},
@@ -2031,6 +2120,46 @@ function initCall(options, transport) {
2031
2120
  } : {}
2032
2121
  };
2033
2122
  }
2123
+ function hostedMessage(data, on) {
2124
+ if ("cdpOpen" in data) on.cdp.open(data);
2125
+ else if ("facadeOpen" in data) on.facades.open(data);
2126
+ else if ("mountPolicy" in data) void on.policy(data.mountPolicy);
2127
+ else if ("medium" in data) on.medium(data.medium);
2128
+ else if ("hostfs" in data) void on.hostfs(data.hostfs);
2129
+ else return false;
2130
+ return true;
2131
+ }
2132
+ function facadesInit(specs) {
2133
+ if (!specs) return {};
2134
+ const facades = {};
2135
+ for (const [name, spec] of Object.entries(specs)) {
2136
+ if (spec?.hook !== void 0 && typeof spec.hook !== "function") {
2137
+ throw new TypeError(`facades.${name}: hook must be a function`);
2138
+ }
2139
+ facades[name] = { port: spec?.port, ...spec?.hook ? { hook: true } : {} };
2140
+ }
2141
+ return { facades };
2142
+ }
2143
+ function facadeBridge(specs) {
2144
+ const open = /* @__PURE__ */ new Set();
2145
+ let closed = false;
2146
+ return {
2147
+ open({ facadeOpen, port }) {
2148
+ const hook = specs?.[facadeOpen.name]?.hook;
2149
+ if (!hook || closed) {
2150
+ port.postMessage({ error: "no facade host" });
2151
+ port.close();
2152
+ return;
2153
+ }
2154
+ const close = serveFacadePort(port, hook, facadeOpen, () => open.delete(close));
2155
+ open.add(close);
2156
+ },
2157
+ close() {
2158
+ closed = true;
2159
+ for (const close of [...open]) close();
2160
+ }
2161
+ };
2162
+ }
2034
2163
  function cdpBridge(hook) {
2035
2164
  const open = /* @__PURE__ */ new Set();
2036
2165
  let closed = false;
@@ -2141,6 +2270,7 @@ function checkOptions(options) {
2141
2270
  }
2142
2271
  if (options.protect) protectInit(options.protect);
2143
2272
  integrityOptions(options.protect?.integrity);
2273
+ facadesInit(options.facades);
2144
2274
  }
2145
2275
  function hookRelays(worker, options) {
2146
2276
  const sealed = sealedAnswerer(worker, options.sealed);
@@ -2187,11 +2317,13 @@ async function createKernel(options = {}) {
2187
2317
  (req) => call(req)
2188
2318
  );
2189
2319
  const cdp = cdpBridge(options.cdp);
2320
+ const facades = facadeBridge(options.facades);
2190
2321
  const sealed = hookRelays(worker, options);
2191
2322
  const approvals = approver(options.approve, worker);
2192
2323
  const fail = (error) => {
2193
2324
  dials.reset();
2194
2325
  cdp.close();
2326
+ facades.close();
2195
2327
  sealed.close();
2196
2328
  approvals.close();
2197
2329
  failure3 = error;
@@ -2233,15 +2365,13 @@ async function createKernel(options = {}) {
2233
2365
  options.onDenial?.(data.denial);
2234
2366
  return true;
2235
2367
  };
2368
+ const hosts = { cdp, facades, policy, medium: pendingMedium, hostfs: grantHostfs };
2236
2369
  worker.addEventListener("message", ({ data }) => {
2237
2370
  if (aside(data)) return;
2238
2371
  if (approvals.handle(data)) return;
2239
2372
  if ("net" in data) return bridge?.answer(data);
2240
2373
  if ("uplink" in data) return uplinks?.answer(data);
2241
- if ("cdpOpen" in data) return cdp.open(data);
2242
- if ("mountPolicy" in data) return void policy(data.mountPolicy);
2243
- if ("medium" in data) return pendingMedium(data.medium);
2244
- if ("hostfs" in data) return void grantHostfs(data.hostfs);
2374
+ if (hostedMessage(data, hosts)) return;
2245
2375
  const call2 = pending.get(data.id);
2246
2376
  if (!call2) return;
2247
2377
  if (data.fd !== void 0) return call2.output?.(data.fd, data.bytes);