@ai-ecoverse/slicc-kernel 1.54.7 → 1.54.9

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/node.js CHANGED
@@ -947,9 +947,9 @@ var KernelSocket = class _KernelSocket {
947
947
  case SO_TYPE:
948
948
  return SOCK_STREAM;
949
949
  case SO_ERROR: {
950
- const failed = this.failed;
950
+ const failed2 = this.failed;
951
951
  this.failed = void 0;
952
- return failed ? wasiErrno(failed) : 0;
952
+ return failed2 ? wasiErrno(failed2) : 0;
953
953
  }
954
954
  case SO_ACCEPTCONN:
955
955
  return this.state === "listening" ? 1 : 0;
@@ -2813,7 +2813,7 @@ var OpfsFs = class {
2813
2813
  const swap = targetStat?.isDirectory === true;
2814
2814
  const staging = swap ? `.${name2}.${crypto.randomUUID()}` : name2;
2815
2815
  this.forget(destination);
2816
- const timed = await this.explicitTimes(source.path);
2816
+ const timed2 = await this.explicitTimes(source.path);
2817
2817
  const moved2 = await this.place(source.handle, dir, staging);
2818
2818
  if (swap) await this.rm(destination, { recursive: true });
2819
2819
  await this.meta.move(source.path, destination, carry);
@@ -2825,7 +2825,7 @@ var OpfsFs = class {
2825
2825
  if (!placed) await dir.removeEntry(staging, { recursive: true });
2826
2826
  copied ||= !placed;
2827
2827
  }
2828
- if (copied) await this.restamp(destination, timed);
2828
+ if (copied) await this.restamp(destination, timed2);
2829
2829
  this.changed(source.path, destination);
2830
2830
  this.touch(parentOf2(source.path), parent.path);
2831
2831
  }
@@ -2834,16 +2834,16 @@ var OpfsFs = class {
2834
2834
  return handle.kind === "file" ? (await handle.getFile()).lastModified : 0;
2835
2835
  }
2836
2836
  async explicitTimes(path) {
2837
- const timed = [];
2837
+ const timed2 = [];
2838
2838
  for (const entry of await this.meta.under(path)) {
2839
2839
  if (entry.mtimeFor === void 0 || entry.link !== void 0) continue;
2840
2840
  const current = await this.modified(entry.path).catch(() => void 0);
2841
- if (current === entry.mtimeFor) timed.push(entry.path.slice(path.length));
2841
+ if (current === entry.mtimeFor) timed2.push(entry.path.slice(path.length));
2842
2842
  }
2843
- return timed;
2843
+ return timed2;
2844
2844
  }
2845
- async restamp(path, timed) {
2846
- for (const rest2 of timed) {
2845
+ async restamp(path, timed2) {
2846
+ for (const rest2 of timed2) {
2847
2847
  const mtimeFor = await this.modified(path + rest2);
2848
2848
  await this.meta.update(path + rest2, (entry) => entry && { ...entry, mtimeFor });
2849
2849
  }
@@ -6456,6 +6456,7 @@ function* procWalk(path, follow2) {
6456
6456
  let done4 = [];
6457
6457
  let todo = path.split("/").filter((part) => part !== "");
6458
6458
  let hops = 0;
6459
+ let broken;
6459
6460
  while (todo.length > 0) {
6460
6461
  const part = todo.shift();
6461
6462
  if (part === ".") continue;
@@ -6465,19 +6466,31 @@ function* procWalk(path, follow2) {
6465
6466
  }
6466
6467
  const at = `/${[...done4, part].join("/")}`;
6467
6468
  const whole = normalize(`/${[...done4, part, ...todo].join("/")}`);
6468
- if (inProc(at) && inProc(whole)) return whole;
6469
+ if (inProc(at) && inProc(whole)) return broken ?? whole;
6469
6470
  if (!follow2 && todo.length === 0) return void 0;
6470
- const target = yield at;
6471
- if (target === null) return void 0;
6472
- if (target === void 0) done4.push(part);
6473
- else {
6471
+ const target = yield { at, check: todo.find((next2) => next2 !== ".") === ".." };
6472
+ if (typeof target === "string") {
6474
6473
  if (++hops > MAX_HOPS2) return void 0;
6475
- if (target.startsWith("/")) done4 = [];
6476
- todo = [...target.split("/").filter((part2) => part2 !== ""), ...todo];
6474
+ [done4, todo] = throughLink(target, done4, todo);
6475
+ } else {
6476
+ broken ??= refusalOf(target);
6477
+ done4.push(part);
6477
6478
  }
6478
6479
  }
6479
6480
  return void 0;
6480
6481
  }
6482
+ function failed(err) {
6483
+ const code = err?.code;
6484
+ return { refused: typeof code === "string" ? code : "ENOENT" };
6485
+ }
6486
+ function refusalOf(found) {
6487
+ if (found === true) return void 0;
6488
+ return found === false ? { refused: "ENOTDIR" } : found;
6489
+ }
6490
+ function throughLink(target, done4, todo) {
6491
+ const parts = target.split("/").filter((part) => part !== "");
6492
+ return [target.startsWith("/") ? [] : done4, [...parts, ...todo]];
6493
+ }
6481
6494
  async function procAlias(fs, path, follow2) {
6482
6495
  const { readlink, lstat } = fs;
6483
6496
  if (!readlink || !lstat) return void 0;
@@ -6489,7 +6502,10 @@ async function procAlias(fs, path, follow2) {
6489
6502
  const walk = procWalk(path, follow2);
6490
6503
  let step = walk.next();
6491
6504
  while (!step.done) {
6492
- const target = await readlink.call(fs, step.value).catch(() => void 0);
6505
+ const { at, check } = step.value;
6506
+ const link2 = await readlink.call(fs, at).catch(() => void 0);
6507
+ const isDir = (st) => st.isDirectory === true;
6508
+ const target = link2 ?? (check ? await lstat.call(fs, at).then(isDir, failed) : true);
6493
6509
  step = walk.next(target);
6494
6510
  }
6495
6511
  return step.value;
@@ -9856,6 +9872,8 @@ var WasmProcess = class {
9856
9872
  async openVfs(req) {
9857
9873
  if (inProc(req.path)) return this.openProc(req, req.path);
9858
9874
  const alias = req.orphan ? void 0 : await procAlias(this.options.fs, req.path, !req.exclusive);
9875
+ if (typeof alias === "object")
9876
+ throw Object.assign(new Error(alias.refused), { code: alias.refused });
9859
9877
  if (alias !== void 0) return this.openProc(req, alias);
9860
9878
  await refuseReadonly(this.options.fs, req.path, req.flags, req);
9861
9879
  const fd = this.fds.install(heldFile(), 3);
@@ -11512,22 +11530,22 @@ async function mountFstab(lines2, mount, signal, retries = FSTAB_RETRIES, discar
11512
11530
  );
11513
11531
  }
11514
11532
  async function mountLine({ line, spec, invalid }, mount, signal, retries, discard) {
11515
- let failed = invalid;
11533
+ let failed2 = invalid;
11516
11534
  for (let attempt = 0; !invalid && attempt <= retries.length && !signal.aborted; attempt++) {
11517
11535
  try {
11518
11536
  const entry = await mount(spec);
11519
11537
  if (!signal.aborted) return { line, target: spec.target, entry };
11520
11538
  discard(entry);
11521
- failed = Object.assign(new Error("the kernel stopped"), { code: "ECANCELED" });
11539
+ failed2 = Object.assign(new Error("the kernel stopped"), { code: "ECANCELED" });
11522
11540
  break;
11523
11541
  } catch (err) {
11524
- failed = err;
11542
+ failed2 = err;
11525
11543
  if (FINAL.has(codeOf3(err)) || attempt === retries.length) break;
11526
11544
  await wait(retries[attempt], signal);
11527
11545
  }
11528
11546
  }
11529
- const code = codeOf3(failed);
11530
- return { line, target: spec.target, code, error: String(failed?.message ?? code) };
11547
+ const code = codeOf3(failed2);
11548
+ return { line, target: spec.target, code, error: String(failed2?.message ?? code) };
11531
11549
  }
11532
11550
 
11533
11551
  // src/mount/hostfs.ts
@@ -11555,11 +11573,24 @@ var HostfsClient = class {
11555
11573
  get maxIo() {
11556
11574
  return this.capabilities.maxIo ?? HOSTFS_IO;
11557
11575
  }
11558
- async send(path, init, handle = false, retried = false) {
11576
+ retired;
11577
+ stop = new AbortController();
11578
+ get gone() {
11579
+ return this.retired !== void 0;
11580
+ }
11581
+ retire(why) {
11582
+ this.retired ??= why;
11583
+ this.stop.abort();
11584
+ }
11585
+ async send(path, init, handle = false, retried = false, cleanup = false) {
11586
+ if (this.retired && !cleanup) throw fsError2("ENOTCONN", this.retired);
11587
+ const stop = cleanup ? void 0 : this.stop.signal;
11588
+ const signal = init.signal && stop ? AbortSignal.any([init.signal, stop]) : init.signal ?? stop;
11559
11589
  let response;
11560
11590
  try {
11561
11591
  response = await this.fetch(`${this.grant.url}${path}`, {
11562
11592
  ...init,
11593
+ ...signal ? { signal } : {},
11563
11594
  credentials: "omit",
11564
11595
  headers: {
11565
11596
  ...init.headers,
@@ -11596,6 +11627,20 @@ var HostfsClient = class {
11596
11627
  );
11597
11628
  return await response.json();
11598
11629
  }
11630
+ async cleanup(op, body) {
11631
+ const response = await this.send(
11632
+ "/api/hostfs",
11633
+ {
11634
+ method: "POST",
11635
+ headers: { "Content-Type": "application/json" },
11636
+ body: JSON.stringify({ op, ...body })
11637
+ },
11638
+ true,
11639
+ false,
11640
+ true
11641
+ );
11642
+ await response.body?.cancel();
11643
+ }
11599
11644
  async read(fh, offset, size, ifMatch) {
11600
11645
  const response = await this.send(
11601
11646
  "/api/hostfs",
@@ -11663,6 +11708,11 @@ function hostfsHandlers(current) {
11663
11708
  return fresh(remote);
11664
11709
  };
11665
11710
  const call = (op, body = {}) => current().call(op, body);
11711
+ const settle = (client, restore) => client.call("setattr", restore).catch((err) => {
11712
+ if (!client.gone || !client.cleanup) throw err;
11713
+ void client.cleanup("setattr", restore).catch(() => {
11714
+ });
11715
+ });
11666
11716
  async function writable(client, path, flags) {
11667
11717
  const { ifMatch: _, ...asked } = flags;
11668
11718
  const opening = () => client.call("open", { path: rel(path), ...asked });
@@ -11673,9 +11723,9 @@ function hostfsHandlers(current) {
11673
11723
  const mode = (await client.call("stat", { path: rel(path) })).mode ?? 0;
11674
11724
  if (mode & 128) throw err;
11675
11725
  const restore = { path: rel(path), mode };
11676
- await client.call("setattr", { path: rel(path), mode: mode | 128 });
11677
- const opened2 = await opening().catch(async (again) => {
11678
- await client.call("setattr", restore);
11726
+ const opened2 = await client.call("setattr", { path: rel(path), mode: mode | 128 }).then(opening).catch(async (again) => {
11727
+ await settle(client, restore).catch(() => {
11728
+ });
11679
11729
  throw again;
11680
11730
  });
11681
11731
  return { opened: opened2, restore };
@@ -11730,7 +11780,7 @@ function hostfsHandlers(current) {
11730
11780
  try {
11731
11781
  await fresh(remote).client.call("release", { fh: remote.fh }, true);
11732
11782
  } finally {
11733
- if (remote.restore) await current().call("setattr", remote.restore);
11783
+ if (remote.restore) await settle(current(), remote.restore);
11734
11784
  }
11735
11785
  },
11736
11786
  mkdir: async (path) => void await call("mkdir", { path: rel(path) }),
@@ -11860,6 +11910,73 @@ function invalidation(event) {
11860
11910
  return event.paths ?? true;
11861
11911
  }
11862
11912
  var PORT_REQUEST_MS = 6e4;
11913
+ var HOSTFS_CALL_MS = 2e4;
11914
+ var PORT_BEAT_MS = 1e3;
11915
+ var PORT_DEAD_MS = 1e4;
11916
+ var PORT_LINGER_MS = 1e3;
11917
+ function timed(transport, ms) {
11918
+ const inflight = /* @__PURE__ */ new Set();
11919
+ const guard = (name2, run2, late, expire) => new Promise((resolve, reject) => {
11920
+ let expired = false;
11921
+ const running = run2();
11922
+ inflight.add(running);
11923
+ const done4 = () => inflight.delete(running);
11924
+ running.then(done4, done4);
11925
+ const timer = setTimeout(() => {
11926
+ expired = true;
11927
+ const why = `the host folder did not answer ${name2} within ${ms} ms`;
11928
+ transport.retire?.(why);
11929
+ expire?.(running);
11930
+ reject(fsError2("ENOTCONN", why));
11931
+ }, ms);
11932
+ running.then(
11933
+ (value) => {
11934
+ clearTimeout(timer);
11935
+ if (expired) late?.(value);
11936
+ resolve(value);
11937
+ },
11938
+ (err) => {
11939
+ clearTimeout(timer);
11940
+ reject(err);
11941
+ }
11942
+ );
11943
+ });
11944
+ const cleanup = async (op, body, skip) => {
11945
+ await Promise.allSettled([...inflight].filter((work) => work !== skip));
11946
+ await transport.cleanup?.(op, body);
11947
+ };
11948
+ const release = (opened2) => {
11949
+ const fh = opened2?.fh;
11950
+ if (typeof fh === "number") void cleanup("release", { fh }).catch(() => {
11951
+ });
11952
+ };
11953
+ return {
11954
+ get capabilities() {
11955
+ return transport.capabilities;
11956
+ },
11957
+ get token() {
11958
+ return transport.token;
11959
+ },
11960
+ get maxIo() {
11961
+ return transport.maxIo;
11962
+ },
11963
+ get gone() {
11964
+ return transport.gone;
11965
+ },
11966
+ retire: (why) => transport.retire?.(why),
11967
+ ...transport.cleanup ? { cleanup } : {},
11968
+ call: (op, body, handle) => guard(
11969
+ op,
11970
+ () => transport.call(op, body, handle),
11971
+ op === "open" ? release : void 0,
11972
+ op === "release" ? (running) => void cleanup("release", body ?? {}, running).catch(() => {
11973
+ }) : void 0
11974
+ ),
11975
+ read: (fh, offset, size, ifMatch) => guard("read", () => transport.read(fh, offset, size, ifMatch)),
11976
+ write: (fh, offset, bytes) => guard("write", () => transport.write(fh, offset, bytes)),
11977
+ watch: (signal, onEvent, onOpen) => transport.watch(signal, onEvent, onOpen)
11978
+ };
11979
+ }
11863
11980
  var PORT_MS_PER_MIB = 1e3;
11864
11981
  var nextPortToken = 0;
11865
11982
  var PortTransport = class {
@@ -11870,13 +11987,25 @@ var PortTransport = class {
11870
11987
  waiting = /* @__PURE__ */ new Map();
11871
11988
  next = 0;
11872
11989
  dead;
11873
- constructor(grant, requestMs = PORT_REQUEST_MS) {
11990
+ beatMs;
11991
+ deadMs;
11992
+ lingerMs;
11993
+ beat;
11994
+ answers = false;
11995
+ pinged;
11996
+ constructor(grant, liveness = {}) {
11874
11997
  this.port = grant.port;
11875
- this.requestMs = requestMs;
11998
+ this.requestMs = liveness.requestMs ?? PORT_REQUEST_MS;
11999
+ this.beatMs = liveness.beatMs ?? PORT_BEAT_MS;
12000
+ this.deadMs = liveness.deadMs ?? PORT_DEAD_MS;
12001
+ this.lingerMs = liveness.lingerMs ?? PORT_LINGER_MS;
11876
12002
  this.capabilities = grant.capabilities ?? {};
11877
12003
  this.token = grant.token ?? `port-${++nextPortToken}`;
11878
12004
  this.port.addEventListener("message", (event) => {
11879
- this.waiting.get(event.data?.id)?.(event.data);
12005
+ if (event.data?.pong) {
12006
+ this.answers = true;
12007
+ this.pinged = void 0;
12008
+ } else this.waiting.get(event.data?.id)?.(event.data);
11880
12009
  });
11881
12010
  this.port.addEventListener("close", () => this.fail("the folder's port closed"));
11882
12011
  this.port.start();
@@ -11887,8 +12016,51 @@ var PortTransport = class {
11887
12016
  get gone() {
11888
12017
  return this.dead !== void 0;
11889
12018
  }
12019
+ retire(why) {
12020
+ this.fail(why);
12021
+ }
12022
+ ping() {
12023
+ if (this.pinged !== void 0) return;
12024
+ this.pinged = Date.now();
12025
+ try {
12026
+ this.port.postMessage({ id: 0, op: "ping" });
12027
+ } catch {
12028
+ }
12029
+ }
12030
+ watchBeat() {
12031
+ if (this.beat || this.dead) return;
12032
+ this.ping();
12033
+ this.beat = setInterval(() => {
12034
+ if (this.waiting.size === 0) {
12035
+ clearInterval(this.beat);
12036
+ this.beat = void 0;
12037
+ return;
12038
+ }
12039
+ if (this.answers && this.pinged !== void 0 && Date.now() - this.pinged > this.deadMs) {
12040
+ this.fail("the folder's port stopped answering");
12041
+ return;
12042
+ }
12043
+ this.ping();
12044
+ }, this.beatMs);
12045
+ }
12046
+ async cleanup(op, body) {
12047
+ if (this.closed) throw fsError2("ENOTCONN", "the folder's port is closed");
12048
+ this.port.postMessage({ id: 0, op: "cleanup", name: op, body });
12049
+ }
12050
+ closed = false;
11890
12051
  fail(why) {
11891
- if (this.dead === void 0) this.port.close();
12052
+ if (this.dead === void 0) {
12053
+ setTimeout(() => {
12054
+ try {
12055
+ this.port.postMessage({ id: 0, op: "bye" });
12056
+ } catch {
12057
+ }
12058
+ this.closed = true;
12059
+ this.port.close();
12060
+ }, this.lingerMs);
12061
+ }
12062
+ clearInterval(this.beat);
12063
+ this.beat = void 0;
11892
12064
  this.dead ??= why;
11893
12065
  for (const settle of [...this.waiting.values()])
11894
12066
  settle({ id: 0, error: { code: "ENOTCONN", message: why } });
@@ -11905,6 +12077,7 @@ var PortTransport = class {
11905
12077
  },
11906
12078
  this.requestMs + Math.ceil(bytes / 1048576) * PORT_MS_PER_MIB
11907
12079
  );
12080
+ this.watchBeat();
11908
12081
  this.waiting.set(id2, (reply) => {
11909
12082
  clearTimeout(timer);
11910
12083
  this.waiting.delete(id2);
@@ -11951,6 +12124,7 @@ var PortTransport = class {
11951
12124
  }
11952
12125
  resolve();
11953
12126
  };
12127
+ this.watchBeat();
11954
12128
  this.waiting.set(id2, (reply) => {
11955
12129
  if (reply.open) return onOpen();
11956
12130
  if (reply.event) return onEvent(reply.event);
@@ -11974,11 +12148,38 @@ var errorOf = (err) => ({
11974
12148
  });
11975
12149
  function serveHostfsPort(port, transport) {
11976
12150
  const watches = /* @__PURE__ */ new Map();
12151
+ const handles = /* @__PURE__ */ new Set();
12152
+ let stopped = false;
12153
+ const closeHandles = () => {
12154
+ for (const fh of handles) void transport.call("release", { fh }, true).catch(() => {
12155
+ });
12156
+ handles.clear();
12157
+ };
11977
12158
  const send = (reply, transfer = []) => port.postMessage(reply, transfer);
12159
+ const pending = /* @__PURE__ */ new Set();
12160
+ const track = (work) => {
12161
+ pending.add(work);
12162
+ const done4 = () => pending.delete(work);
12163
+ work.then(done4, done4);
12164
+ return work;
12165
+ };
12166
+ const answer = async (name2, body) => {
12167
+ const result = await track(transport.call(name2, body));
12168
+ const opened2 = result?.fh;
12169
+ if (name2 === "open" && typeof opened2 === "number") handles.add(opened2);
12170
+ if (name2 === "release") handles.delete(body?.fh);
12171
+ if (stopped) closeHandles();
12172
+ return result;
12173
+ };
11978
12174
  const listener = async ({
11979
12175
  data
11980
12176
  }) => {
11981
12177
  const { id: id2, op } = data;
12178
+ if (op === "ping") return send({ id: id2, pong: true });
12179
+ if (op === "bye") return stop();
12180
+ if (op === "cleanup")
12181
+ return void Promise.allSettled([...pending]).then(() => answer(data.name, data.body)).catch(() => {
12182
+ });
11982
12183
  if (op === "unwatch") return watches.get(id2)?.abort();
11983
12184
  if (op === "watch") {
11984
12185
  const stop2 = new AbortController();
@@ -11999,32 +12200,35 @@ function serveHostfsPort(port, transport) {
11999
12200
  }
12000
12201
  try {
12001
12202
  if (op === "read") {
12002
- const read = await transport.read(
12003
- data.fh,
12004
- data.offset,
12005
- data.size,
12006
- data.ifMatch
12203
+ const read = await track(
12204
+ transport.read(
12205
+ data.fh,
12206
+ data.offset,
12207
+ data.size,
12208
+ data.ifMatch
12209
+ )
12007
12210
  );
12008
12211
  const bytes = read.slice();
12009
12212
  return send({ id: id2, bytes }, [bytes.buffer]);
12010
12213
  }
12011
12214
  if (op === "write") {
12012
- await transport.write(data.fh, data.offset, data.bytes);
12215
+ await track(
12216
+ transport.write(data.fh, data.offset, data.bytes)
12217
+ );
12013
12218
  return send({ id: id2 });
12014
12219
  }
12015
12220
  if (op !== "call") throw fsError2("EINVAL", `unknown hostfs port op ${op}`);
12016
- send({
12017
- id: id2,
12018
- result: await transport.call(data.name, data.body)
12019
- });
12221
+ send({ id: id2, result: await answer(data.name, data.body) });
12020
12222
  } catch (err) {
12021
12223
  send({ id: id2, error: errorOf(err) });
12022
12224
  }
12023
12225
  };
12024
12226
  const stop = () => {
12227
+ stopped = true;
12025
12228
  port.removeEventListener("message", listener);
12026
12229
  port.removeEventListener("close", stop);
12027
12230
  for (const watch of watches.values()) watch.abort();
12231
+ closeHandles();
12028
12232
  port.close();
12029
12233
  };
12030
12234
  port.addEventListener("message", listener);
@@ -12032,10 +12236,10 @@ function serveHostfsPort(port, transport) {
12032
12236
  port.start();
12033
12237
  return stop;
12034
12238
  }
12035
- function grantConnect(hook, fetch2, requestMs) {
12239
+ function grantConnect(hook, fetch2, liveness = {}) {
12036
12240
  return async (source, options) => {
12037
12241
  const first = await hook(source, options);
12038
- if ("port" in first) return new PortTransport(first, requestMs);
12242
+ if ("port" in first) return new PortTransport(first, liveness);
12039
12243
  const grant = async () => {
12040
12244
  const again = await hook(source, options);
12041
12245
  if ("port" in again)
@@ -12055,7 +12259,10 @@ async function openHostfs(spec, connect, timing = {}) {
12055
12259
  const stop = new AbortController();
12056
12260
  let active;
12057
12261
  const handlers = hostfsHandlers(() => active);
12058
- const ranged2 = () => active?.capabilities.ranges === true ? { ranges: true } : {};
12262
+ const ranged2 = () => ({
12263
+ ...active?.capabilities.ranges === true ? { ranges: true } : {},
12264
+ ...active ? { maxIo: Math.min(active.maxIo, HOSTFS_IO) } : {}
12265
+ });
12059
12266
  const served = serveFilesystem(
12060
12267
  port2,
12061
12268
  { ...slot.handlers, mount: ranged2 },
@@ -12071,7 +12278,7 @@ async function openHostfs(spec, connect, timing = {}) {
12071
12278
  {
12072
12279
  connect: () => connect(spec.source, { readonly: readonly2 }),
12073
12280
  up(client) {
12074
- active = client;
12281
+ active = timed(client, timing.callMs ?? HOSTFS_CALL_MS);
12075
12282
  slot.insert(client, handlers);
12076
12283
  served.invalidate(true);
12077
12284
  },
@@ -13100,11 +13307,7 @@ var Launcher = class {
13100
13307
  throw fsError("ENODEV", "this kernel has no hostfs hook (createKernel({ hostfs }))");
13101
13308
  return openHostfs(
13102
13309
  spec,
13103
- grantConnect(
13104
- hostfs,
13105
- hostfsFetch ?? ((url, init) => fetch(url, init)),
13106
- hostfsTiming?.requestMs
13107
- ),
13310
+ grantConnect(hostfs, hostfsFetch ?? ((url, init) => fetch(url, init)), hostfsTiming),
13108
13311
  hostfsTiming
13109
13312
  );
13110
13313
  }