@ai-ecoverse/slicc-kernel 1.83.0 → 1.84.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/node.js CHANGED
@@ -448,8 +448,8 @@ async function inParent(g, op, path, old = false) {
448
448
  if (!old) return void await need(g, op, parentOf(path), W_OK | X_OK, DIR, path);
449
449
  const dir = await access(g.fs, g.cred, parentOf(path), W_OK | X_OK, DIR);
450
450
  if (dir.denied === void 0) return stickyEntry(g, op, path, dir);
451
- const lookup2 = dir.denied === dir.path && dir.perm && permits(g.cred, dir.perm, X_OK);
452
- if (!lookup2 || await present(g.fs, entryIn(dir, path), false)) deny(g, op, path);
451
+ const lookup3 = dir.denied === dir.path && dir.perm && permits(g.cred, dir.perm, X_OK);
452
+ if (!lookup3 || await present(g.fs, entryIn(dir, path), false)) deny(g, op, path);
453
453
  }
454
454
  async function makeIn(g, op, path) {
455
455
  for (let dir = parentOf(path); ; dir = parentOf(dir)) {
@@ -3467,10 +3467,10 @@ function translate(err, path, op = "lookup", mapped = true) {
3467
3467
  var META_OPS = ["get", "update", "move", "remove", "links", "under", "all"];
3468
3468
  function sidecar(meta) {
3469
3469
  const pathOf = ([first]) => [first, "/"].flat().find((p) => typeof p === "string");
3470
- const guarded2 = (op) => (...args) => meta[op].apply(meta, args).catch((err) => {
3470
+ const guarded3 = (op) => (...args) => meta[op].apply(meta, args).catch((err) => {
3471
3471
  throw translate(err, pathOf(args), "sidecar", false);
3472
3472
  });
3473
- return Object.fromEntries(META_OPS.map((op) => [op, guarded2(op)]));
3473
+ return Object.fromEntries(META_OPS.map((op) => [op, guarded3(op)]));
3474
3474
  }
3475
3475
  function missing2(err) {
3476
3476
  const code = err?.code;
@@ -5907,9 +5907,13 @@ function withCommandDirs(fs, names, userDir = async () => void 0, owners = false
5907
5907
  // src/fs/fresh-modules.ts
5908
5908
  var MAGIC = [0, 97, 115, 109];
5909
5909
  var MAX_FRESH = 65536;
5910
+ var DEFAULT_UMASK = 18;
5910
5911
  function isModule(bytes) {
5911
5912
  return MAGIC.every((b, i) => bytes[i] === b);
5912
5913
  }
5914
+ function within4(path, dir) {
5915
+ return path.startsWith(dir === "/" ? "/" : `${dir}/`);
5916
+ }
5913
5917
  var FreshModules = class {
5914
5918
  fresh = /* @__PURE__ */ new Map();
5915
5919
  add(path, umask, pid) {
@@ -5917,17 +5921,40 @@ var FreshModules = class {
5917
5921
  this.fresh.delete(key);
5918
5922
  const oldest = this.fresh.size >= MAX_FRESH ? this.fresh.keys().next().value : void 0;
5919
5923
  if (oldest !== void 0) this.fresh.delete(oldest);
5920
- this.fresh.set(key, { umask: umask & 511, pid, added: 0 });
5924
+ const mask = umask & 511;
5925
+ this.fresh.set(key, { umask: mask, pid, added: 0, setup: mask !== DEFAULT_UMASK });
5921
5926
  }
5922
5927
  forget(pid) {
5923
5928
  for (const [path, fresh2] of this.fresh) if (fresh2.pid === pid) this.fresh.delete(path);
5924
5929
  }
5930
+ drop(fresh2) {
5931
+ for (const [key, note] of [...this.fresh]) if (note === fresh2) this.fresh.delete(key);
5932
+ }
5933
+ moved(from, to) {
5934
+ const source = normalizePath(from);
5935
+ const target = normalizePath(to);
5936
+ if (source === target) return;
5937
+ for (const key of [...this.fresh.keys()]) {
5938
+ if (key === target || within4(key, target)) this.fresh.delete(key);
5939
+ }
5940
+ for (const [key, fresh2] of [...this.fresh]) {
5941
+ if (key !== source && !within4(key, source)) continue;
5942
+ this.fresh.delete(key);
5943
+ this.fresh.set(target + key.slice(source.length), fresh2);
5944
+ }
5945
+ }
5925
5946
  wrap(fs) {
5926
- const decide = async (given, bytes) => {
5947
+ const head = async (path) => {
5948
+ if (fs.pread) return fs.pread(path, 0, MAGIC.length);
5949
+ return (await fs.readFileBuffer(path)).subarray(0, MAGIC.length);
5950
+ };
5951
+ const decide = async (given, known) => {
5927
5952
  const path = normalizePath(given);
5928
5953
  const fresh2 = this.fresh.get(path);
5929
- if (!fresh2 || typeof bytes === "string" || bytes.length < MAGIC.length) return;
5954
+ if (!fresh2) return;
5955
+ const bytes = known && known.length >= MAGIC.length ? known : await head(path);
5930
5956
  const want = isModule(bytes) ? 73 & ~fresh2.umask : 0;
5957
+ fresh2.setup = false;
5931
5958
  if (want === fresh2.added) return;
5932
5959
  const mode = (await fs.stat(path)).mode & 4095;
5933
5960
  await fs.chmod(path, mode & ~fresh2.added | want);
@@ -5936,32 +5963,47 @@ var FreshModules = class {
5936
5963
  const overrides = {
5937
5964
  writeFile: async (path, content, owner) => {
5938
5965
  await fs.writeFile(path, content, owner);
5939
- await decide(path, content);
5966
+ if (this.fresh.has(normalizePath(path))) {
5967
+ await decide(
5968
+ path,
5969
+ typeof content === "string" ? new TextEncoder().encode(content) : content
5970
+ );
5971
+ }
5940
5972
  },
5941
5973
  chmod: async (path, mode) => {
5942
5974
  const fresh2 = this.fresh.get(normalizePath(path));
5943
- const creating = fresh2?.added === 0 && (mode & 4095) === (438 & ~fresh2.umask);
5944
- if (!creating) this.fresh.delete(normalizePath(path));
5975
+ if (fresh2?.setup && (mode & 4095) === (438 & ~fresh2.umask)) fresh2.setup = false;
5976
+ else if (fresh2) this.drop(fresh2);
5945
5977
  await fs.chmod(path, mode);
5946
5978
  },
5947
5979
  rm: async (path, options) => {
5948
- this.fresh.delete(normalizePath(path));
5949
5980
  await fs.rm(path, options);
5981
+ const at = normalizePath(path);
5982
+ for (const key of [...this.fresh.keys()]) {
5983
+ if (key === at || within4(key, at)) this.fresh.delete(key);
5984
+ }
5950
5985
  },
5951
5986
  rename: async (from, to) => {
5952
5987
  await fs.rename(from, to);
5953
- const fresh2 = this.fresh.get(normalizePath(from));
5954
- this.fresh.delete(normalizePath(from));
5955
- this.fresh.delete(normalizePath(to));
5988
+ this.moved(from, to);
5989
+ },
5990
+ link: async (from, to, follow2) => {
5991
+ await fs.link(from, to, follow2);
5992
+ const source = follow2 && fs.realpath ? await fs.realpath(from, true) : from;
5993
+ const fresh2 = this.fresh.get(normalizePath(source));
5956
5994
  if (fresh2) this.fresh.set(normalizePath(to), fresh2);
5957
5995
  }
5958
5996
  };
5959
5997
  const ranged2 = rangedOps(fs);
5960
5998
  if (ranged2) {
5961
5999
  overrides.pwrite = async (path, at, bytes, transfer) => {
5962
- const head = at === 0 && this.fresh.has(normalizePath(path)) ? bytes.slice(0, 4) : void 0;
6000
+ const touches2 = at < MAGIC.length && this.fresh.has(normalizePath(path));
5963
6001
  await ranged2.pwrite(path, at, bytes, transfer);
5964
- if (head) await decide(path, head);
6002
+ if (touches2) await decide(path);
6003
+ };
6004
+ overrides.truncate = async (path, size) => {
6005
+ await ranged2.truncate(path, size);
6006
+ if (size < MAGIC.length && this.fresh.has(normalizePath(path))) await decide(path);
5965
6007
  };
5966
6008
  }
5967
6009
  const bound2 = /* @__PURE__ */ new WeakMap();
@@ -6701,7 +6743,7 @@ function parseSize(text) {
6701
6743
  if (!match) throw errnoError("EINVAL", `not a size: ${text}`);
6702
6744
  return Math.floor(Number(match[1]) * UNITS[match[2].toLowerCase()]);
6703
6745
  }
6704
- var within4 = (path, target) => path === target || target === "/" || path.startsWith(`${target}/`);
6746
+ var within5 = (path, target) => path === target || target === "/" || path.startsWith(`${target}/`);
6705
6747
  var HeldSet = class extends Set {
6706
6748
  idle;
6707
6749
  constructor(idle) {
@@ -6720,7 +6762,7 @@ var HeldSet = class extends Set {
6720
6762
  }
6721
6763
  };
6722
6764
  function heldUnder(held, target) {
6723
- for (const paths of held) for (const path of paths.keys()) if (within4(path, target)) return true;
6765
+ for (const paths of held) for (const path of paths.keys()) if (within5(path, target)) return true;
6724
6766
  return false;
6725
6767
  }
6726
6768
  var HeldPaths = class extends Map {
@@ -6836,24 +6878,24 @@ var HeldPaths = class extends Map {
6836
6878
  return this.owning === path;
6837
6879
  }
6838
6880
  revoke(prefix) {
6839
- for (const path of this.keys()) if (within4(path, prefix)) this.revoked.add(path);
6881
+ for (const path of this.keys()) if (within5(path, prefix)) this.revoked.add(path);
6840
6882
  }
6841
6883
  renamed(from, to) {
6842
6884
  for (const [path, count2] of [...this]) {
6843
- if (!within4(path, from)) continue;
6885
+ if (!within5(path, from)) continue;
6844
6886
  const moved2 = to + path.slice(from.length);
6845
6887
  this.delete(path);
6846
6888
  this.set(moved2, (this.get(moved2) ?? 0) + count2);
6847
6889
  if (this.revoked.delete(path)) this.revoked.add(moved2);
6848
6890
  }
6849
6891
  for (const [path, count2] of [...this.opens]) {
6850
- if (!within4(path, from)) continue;
6892
+ if (!within5(path, from)) continue;
6851
6893
  const moved2 = to + path.slice(from.length);
6852
6894
  this.opens.delete(path);
6853
6895
  this.opens.set(moved2, (this.opens.get(moved2) ?? 0) + count2);
6854
6896
  }
6855
6897
  for (const [id2, key] of this.handles) {
6856
- if (within4(key, from)) this.handles.set(id2, to + key.slice(from.length));
6898
+ if (within5(key, from)) this.handles.set(id2, to + key.slice(from.length));
6857
6899
  }
6858
6900
  }
6859
6901
  isRevoked(path) {
@@ -6960,7 +7002,7 @@ var MountTable = class {
6960
7002
  locate(path) {
6961
7003
  let best;
6962
7004
  for (const mount of this.mounts.values()) {
6963
- if (within4(path, mount.target) && (!best || mount.target.length > best.target.length))
7005
+ if (within5(path, mount.target) && (!best || mount.target.length > best.target.length))
6964
7006
  best = mount;
6965
7007
  }
6966
7008
  if (!best) return void 0;
@@ -7103,7 +7145,7 @@ var MountTable = class {
7103
7145
  async commitUnder(prefix) {
7104
7146
  const at = normalizePath(prefix);
7105
7147
  await Promise.all(
7106
- [...this.sessions.keys()].filter((p) => within4(p, at)).map((p) => this.commit(p))
7148
+ [...this.sessions.keys()].filter((p) => within5(p, at)).map((p) => this.commit(p))
7107
7149
  );
7108
7150
  }
7109
7151
  async commitOverlapping(real, offset, length2) {
@@ -7138,10 +7180,10 @@ var MountTable = class {
7138
7180
  }
7139
7181
  forget(mount, path) {
7140
7182
  mount.epoch++;
7141
- for (const key of [...mount.attrs.keys()]) if (within4(key, path)) mount.attrs.delete(key);
7183
+ for (const key of [...mount.attrs.keys()]) if (within5(key, path)) mount.attrs.delete(key);
7142
7184
  mount.lists.delete(path);
7143
7185
  mount.lists.delete(parentOf7(path));
7144
- for (const key of [...mount.lists.keys()]) if (within4(key, path)) mount.lists.delete(key);
7186
+ for (const key of [...mount.lists.keys()]) if (within5(key, path)) mount.lists.delete(key);
7145
7187
  }
7146
7188
  async getattr(mount, path, rel2, settled = false) {
7147
7189
  for (let round = 1; ; round++) {
@@ -7776,6 +7818,11 @@ function statJson(s) {
7776
7818
  async function readdirStat(fs, dir) {
7777
7819
  return (await fs.readdirStat(dir)).map(([name2, stat]) => [name2, stat && statJson(stat)]);
7778
7820
  }
7821
+ async function usageAt(entry, path) {
7822
+ if (!entry.statfs) return void 0;
7823
+ const real = await realTarget(entry.fs, path).catch(() => path);
7824
+ return entry.statfs(real);
7825
+ }
7779
7826
  async function storageUsage() {
7780
7827
  const estimate = await globalThis.navigator?.storage?.estimate?.();
7781
7828
  if (typeof estimate?.quota !== "number") return null;
@@ -7996,8 +8043,8 @@ async function guarded(entry, path, req) {
7996
8043
  await guard(g, path, req, entry.cwd);
7997
8044
  return void 0;
7998
8045
  } catch (err) {
7999
- const refusal = err.code === "EACCES";
8000
- return req.op === "exists" && refusal ? json2(false) : toErrno(err);
8046
+ const refusal2 = err.code === "EACCES";
8047
+ return req.op === "exists" && refusal2 ? json2(false) : toErrno(err);
8001
8048
  }
8002
8049
  }
8003
8050
  async function createExclusive(fs, path, owner) {
@@ -8092,7 +8139,7 @@ async function dispatchOne(entry, req) {
8092
8139
  if (req.op === "hold") return await holdOp(entry, path, req);
8093
8140
  const refused2 = await guarded(entry, path, req);
8094
8141
  if (refused2) return refused2;
8095
- if (req.op === "statfs") return json2(await entry.statfs?.(path) ?? await storageUsage());
8142
+ if (req.op === "statfs") return json2(await usageAt(entry, path) ?? await storageUsage());
8096
8143
  if (entry.revoked?.(path)) return { ok: false, errno: "EIO", message: `${path} was unmounted` };
8097
8144
  if (req.op === "write" && req.mode === 1 || UNLINKED_OPS.has(req.op)) {
8098
8145
  const serve = async () => run(entry, await keptOr(entry, path, req.handle), req);
@@ -10776,7 +10823,7 @@ function parsePrefix(text) {
10776
10823
  if (length2 < 0 || length2 > max) return void 0;
10777
10824
  return { ...parsed2, length: length2 };
10778
10825
  }
10779
- function within5(prefix, addr) {
10826
+ function within6(prefix, addr) {
10780
10827
  if (prefix.v6 !== addr.v6) return false;
10781
10828
  const shift = BigInt((prefix.v6 ? 128 : 32) - prefix.length);
10782
10829
  return addr.bits >> shift === prefix.bits >> shift;
@@ -10816,9 +10863,9 @@ var Routes = class {
10816
10863
  if (!addr) return "unreachable";
10817
10864
  if (addr.v6 && addr.bits === 1n) return "loopback";
10818
10865
  if (!addr.v6 && addr.bits >> 24n === 127n) return "loopback";
10819
- if (RESERVED.some((p) => within5(p, addr))) return "reserved";
10866
+ if (RESERVED.some((p) => within6(p, addr))) return "reserved";
10820
10867
  if (addr.v6 && !this.ipv6) return "unreachable";
10821
- if (this.exit || this.table.some((p) => within5(p, addr))) return "uplink";
10868
+ if (this.exit || this.table.some((p) => within6(p, addr))) return "uplink";
10822
10869
  return "unreachable";
10823
10870
  }
10824
10871
  };
@@ -10884,14 +10931,14 @@ var Resolver = class {
10884
10931
  if (hit && hit.expires > this.now()) return hit.addresses;
10885
10932
  const signal = blocking?.();
10886
10933
  if (signal?.aborted) throw new KernelError("EINTR");
10887
- let lookup2 = this.pending.get(id2);
10888
- if (!lookup2) {
10934
+ let lookup3 = this.pending.get(id2);
10935
+ if (!lookup3) {
10889
10936
  const abort = new AbortController();
10890
- lookup2 = { work: this.lookup(key, asked, id2, abort.signal), abort, waiters: 0 };
10891
- this.pending.set(id2, lookup2);
10892
- void lookup2.work.then(() => this.pending.delete(id2));
10937
+ lookup3 = { work: this.lookup(key, asked, id2, abort.signal), abort, waiters: 0 };
10938
+ this.pending.set(id2, lookup3);
10939
+ void lookup3.work.then(() => this.pending.delete(id2));
10893
10940
  }
10894
- return waitFor(lookup2, signal);
10941
+ return waitFor(lookup3, signal);
10895
10942
  }
10896
10943
  async lookup(name2, family, id2, abandoned) {
10897
10944
  const uplink = this.uplink;
@@ -10932,17 +10979,17 @@ var Resolver = class {
10932
10979
  }
10933
10980
  }
10934
10981
  };
10935
- function waitFor(lookup2, signal) {
10936
- lookup2.waiters++;
10982
+ function waitFor(lookup3, signal) {
10983
+ lookup3.waiters++;
10937
10984
  return new Promise((resolve2, reject) => {
10938
10985
  const abort = () => {
10939
- if (--lookup2.waiters === 0) lookup2.abort.abort(new KernelError("EINTR"));
10986
+ if (--lookup3.waiters === 0) lookup3.abort.abort(new KernelError("EINTR"));
10940
10987
  reject(new KernelError("EINTR"));
10941
10988
  };
10942
10989
  signal?.addEventListener("abort", abort, { once: true });
10943
- void lookup2.work.then((value) => {
10990
+ void lookup3.work.then((value) => {
10944
10991
  if (signal?.aborted) return;
10945
- lookup2.waiters--;
10992
+ lookup3.waiters--;
10946
10993
  signal?.removeEventListener("abort", abort);
10947
10994
  resolve2(value);
10948
10995
  });
@@ -11674,7 +11721,7 @@ function isMissing(err) {
11674
11721
  if (err?.code === "ENOENT") return true;
11675
11722
  return err instanceof Error && err.message.startsWith("ENOENT");
11676
11723
  }
11677
- function within6(path, root) {
11724
+ function within7(path, root) {
11678
11725
  return path === root || path.startsWith(root.endsWith("/") ? root : `${root}/`);
11679
11726
  }
11680
11727
  var VfsNode = class {
@@ -11995,12 +12042,12 @@ var VfsNodes = class {
11995
12042
  return node;
11996
12043
  }
11997
12044
  holds(prefix) {
11998
- for (const path of this.byPath.keys()) if (within6(path, prefix)) return true;
12045
+ for (const path of this.byPath.keys()) if (within7(path, prefix)) return true;
11999
12046
  return false;
12000
12047
  }
12001
12048
  writes(prefix) {
12002
12049
  for (const [path, node] of this.byPath)
12003
- if (node.writers > 0 && within6(path, prefix)) return true;
12050
+ if (node.writers > 0 && within7(path, prefix)) return true;
12004
12051
  return false;
12005
12052
  }
12006
12053
  closed(node, writable2 = false) {
@@ -12044,11 +12091,11 @@ var VfsNodes = class {
12044
12091
  this.kept.delete(node);
12045
12092
  }
12046
12093
  async flush(path) {
12047
- for (const [p, node] of this.byPath) if (within6(p, path)) await node.serial(() => node.flush());
12094
+ for (const [p, node] of this.byPath) if (within7(p, path)) await node.serial(() => node.flush());
12048
12095
  }
12049
12096
  async unlinking(path) {
12050
12097
  for (const [held, node] of [...this.byPath]) {
12051
- if (!within6(held, path)) continue;
12098
+ if (!within7(held, path)) continue;
12052
12099
  await node.serial(async () => {
12053
12100
  await Promise.all([this.keepsOnDisk || node.keep(), node.limit()]);
12054
12101
  });
@@ -12056,14 +12103,14 @@ var VfsNodes = class {
12056
12103
  }
12057
12104
  revoke(prefix) {
12058
12105
  for (const [path, node] of [...this.byPath]) {
12059
- if (!within6(path, prefix)) continue;
12106
+ if (!within7(path, prefix)) continue;
12060
12107
  node.revoke();
12061
12108
  this.forget(node);
12062
12109
  }
12063
12110
  }
12064
12111
  unlinked(path) {
12065
12112
  for (const [held, node] of [...this.byPath]) {
12066
- if (!within6(held, path) || this.byPath.get(held) !== node) continue;
12113
+ if (!within7(held, path) || this.byPath.get(held) !== node) continue;
12067
12114
  if (!this.dropName(held, node)) this.orphan(node);
12068
12115
  }
12069
12116
  }
@@ -12071,8 +12118,8 @@ var VfsNodes = class {
12071
12118
  if (from === to) return;
12072
12119
  const moved2 = [];
12073
12120
  for (const [p, node] of [...this.byPath]) {
12074
- if (within6(p, from)) moved2.push([p, node]);
12075
- else if (within6(p, to) && this.byPath.get(p) === node && !this.dropName(p, node)) {
12121
+ if (within7(p, from)) moved2.push([p, node]);
12122
+ else if (within7(p, to) && this.byPath.get(p) === node && !this.dropName(p, node)) {
12076
12123
  this.orphan(node);
12077
12124
  }
12078
12125
  }
@@ -12351,7 +12398,7 @@ function isWasmSyscall(req) {
12351
12398
  var MAX_READ = 1024 * 1024;
12352
12399
  var WRITE_ACCESS = 3;
12353
12400
  var KEYBOARD = /* @__PURE__ */ new Set([SIG.INT, SIG.QUIT, SIG.TSTP]);
12354
- var DEFAULT_UMASK = 18;
12401
+ var DEFAULT_UMASK2 = 18;
12355
12402
  function words(value) {
12356
12403
  if (!Array.isArray(value) || !value.every((w) => typeof w === "string")) {
12357
12404
  throw new KernelError("EINVAL");
@@ -12379,7 +12426,7 @@ var WasmProcess = class {
12379
12426
  interrupt = new AbortController();
12380
12427
  gone = new AbortController();
12381
12428
  dying = false;
12382
- umask = DEFAULT_UMASK;
12429
+ umask = DEFAULT_UMASK2;
12383
12430
  cred;
12384
12431
  execChild;
12385
12432
  killed = false;
@@ -12401,7 +12448,7 @@ var WasmProcess = class {
12401
12448
  this.fds = fds;
12402
12449
  this.options = options;
12403
12450
  this.inherited = options.ignored ?? 0;
12404
- this.umask = options.umask ?? DEFAULT_UMASK;
12451
+ this.umask = options.umask ?? DEFAULT_UMASK2;
12405
12452
  this.cred = copyCred(options.cred ?? ROOT);
12406
12453
  this.children = new ChildTable(fds, options.spawner, options.forker);
12407
12454
  this.nodes = options.nodes ?? new VfsNodes(options.fs);
@@ -18087,7 +18134,7 @@ var Launcher = class {
18087
18134
  }
18088
18135
  }
18089
18136
  umaskOf(pid) {
18090
- return this.processes.get(pid)?.umask?.() ?? DEFAULT_UMASK;
18137
+ return this.processes.get(pid)?.umask?.() ?? DEFAULT_UMASK2;
18091
18138
  }
18092
18139
  imageOf(pid) {
18093
18140
  const members = this.jobs.list();
@@ -18597,6 +18644,111 @@ var Launcher = class {
18597
18644
  }
18598
18645
  };
18599
18646
 
18647
+ // src/node/loopback.ts
18648
+ import { lookup } from "node:dns/promises";
18649
+ import { isIP } from "node:net";
18650
+ var DEVTOOLS_PORTS = [9222, 9223, 9224, 9225, 9226, 9227, 9228, 9229];
18651
+ var METADATA_V6 = [64768, 3778, 0, 0, 0, 0, 0, 596].join(":");
18652
+ var resolveHost = async (host) => (await lookup(host, { all: true, verbatim: true })).map((a) => a.address);
18653
+ function ipv4Place(address) {
18654
+ const [a, b] = address.split(".").map(Number);
18655
+ if (a === 127 || a === 0) return "loopback";
18656
+ if (a === 169 && b === 254) return "link-local";
18657
+ return void 0;
18658
+ }
18659
+ function placeOf(address) {
18660
+ const plain = address.replace(/^\[(.*)\]$/, "$1").toLowerCase();
18661
+ const kind = isIP(plain);
18662
+ if (kind === 4) return ipv4Place(plain);
18663
+ if (kind !== 6) return void 0;
18664
+ const words2 = hextets2(plain);
18665
+ const embedded2 = words2.slice(0, 5).every((w) => w === 0) && (words2[5] === 65535 || words2[5] === 0);
18666
+ if (embedded2 && (words2[5] === 65535 || words2[6] !== 0)) return ipv4Place(ipv4Of(words2));
18667
+ if (words2.slice(0, 7).every((w) => w === 0) && (words2[7] ?? 0) <= 1) return "loopback";
18668
+ if (((words2[0] ?? 0) & 65472) === 65152) return "link-local";
18669
+ if (words2.join(":") === METADATA_V6) return "link-local";
18670
+ return void 0;
18671
+ }
18672
+ function ipv4Of(words2) {
18673
+ const [high = 0, low = 0] = words2.slice(6);
18674
+ return [high >> 8, high & 255, low >> 8, low & 255].join(".");
18675
+ }
18676
+ function hextets2(address) {
18677
+ const dotted = /(\d+\.\d+\.\d+\.\d+)$/.exec(address)?.[1];
18678
+ let text = address;
18679
+ if (dotted) {
18680
+ const [a, b, c, d] = dotted.split(".").map(Number);
18681
+ text = `${address.slice(0, -dotted.length)}${(a << 8 | b).toString(16)}:${(c << 8 | d).toString(16)}`;
18682
+ }
18683
+ const [head = "", tail] = text.split("::");
18684
+ const part = (side) => side ? side.split(":").map((w) => Number.parseInt(w, 16)) : [];
18685
+ const left = part(head);
18686
+ const right = tail === void 0 ? [] : part(tail);
18687
+ const gap = Array(8 - left.length - right.length).fill(0);
18688
+ return [...left, ...gap, ...right];
18689
+ }
18690
+ function loopbackName2(host) {
18691
+ const name2 = host.toLowerCase().replace(/\.$/, "");
18692
+ return name2 === "localhost" || name2.endsWith(".localhost");
18693
+ }
18694
+ function portOf(url) {
18695
+ if (url.port) return Number(url.port);
18696
+ return url.protocol === "https:" || url.protocol === "wss:" ? 443 : 80;
18697
+ }
18698
+ function allows(policy, port) {
18699
+ if (Array.isArray(policy)) return policy.includes(port);
18700
+ return policy === true && !DEVTOOLS_PORTS.includes(port);
18701
+ }
18702
+ function refusal(url, address, place) {
18703
+ const where = `${address}:${portOf(url)}`;
18704
+ const why = place === "link-local" ? `nodeTransport refuses link-local ${where}` : `nodeTransport refuses the host's loopback ${where} (see nodeTransport({ hostLoopback }))`;
18705
+ return Object.assign(new Error(why), { status: 403, code: "EACCES" });
18706
+ }
18707
+ async function addressesOf(host, resolve2) {
18708
+ const plain = host.replace(/^\[(.*)\]$/, "$1");
18709
+ if (isIP(plain)) return [plain];
18710
+ if (loopbackName2(plain)) return ["127.0.0.1"];
18711
+ return resolve2(plain).catch(() => []);
18712
+ }
18713
+ async function checkDestination(target, policy, resolve2 = resolveHost) {
18714
+ const url = new URL(target);
18715
+ for (const address of await addressesOf(url.hostname, resolve2)) {
18716
+ const place = placeOf(address);
18717
+ if (!place) continue;
18718
+ if (place === "loopback" && allows(policy, portOf(url))) continue;
18719
+ throw refusal(url, address, place);
18720
+ }
18721
+ }
18722
+ function guarded2(check, signal) {
18723
+ if (!signal) return check;
18724
+ signal.throwIfAborted();
18725
+ let stop = () => {
18726
+ };
18727
+ const aborted2 = new Promise((_, reject) => {
18728
+ stop = () => reject(signal.reason);
18729
+ signal.addEventListener("abort", stop, { once: true });
18730
+ });
18731
+ return Promise.race([check, aborted2]).finally(() => signal.removeEventListener("abort", stop));
18732
+ }
18733
+ function guardedLoopback(transport, policy, resolve2) {
18734
+ const open = transport.websocket?.bind(transport);
18735
+ return {
18736
+ get traits() {
18737
+ return transport.traits;
18738
+ },
18739
+ fetch: async (request, owner) => {
18740
+ await guarded2(checkDestination(request.url, policy, resolve2), request.signal);
18741
+ return transport.fetch(request, owner);
18742
+ },
18743
+ ...open ? {
18744
+ websocket: async (request) => {
18745
+ await guarded2(checkDestination(request.url, policy, resolve2), request.signal);
18746
+ return open(request);
18747
+ }
18748
+ } : {}
18749
+ };
18750
+ }
18751
+
18600
18752
  // src/node/memory-root.ts
18601
18753
  var fail2 = (name2) => {
18602
18754
  throw new DOMException(name2, name2);
@@ -18803,8 +18955,8 @@ function isMemoryRoot(handle) {
18803
18955
  }
18804
18956
 
18805
18957
  // src/node/ws-diagnose.ts
18806
- import { lookup } from "node:dns/promises";
18807
- import { isIP, connect as tcp } from "node:net";
18958
+ import { lookup as lookup2 } from "node:dns/promises";
18959
+ import { isIP as isIP2, connect as tcp } from "node:net";
18808
18960
  import { connect as tls } from "node:tls";
18809
18961
  var PROBE_MS = 3e3;
18810
18962
  var PASSED = /* @__PURE__ */ new Set(["ECONNREFUSED", "EHOSTUNREACH", "ENETUNREACH", "ETIMEDOUT", "ECONNRESET"]);
@@ -18815,7 +18967,7 @@ function codeOf5(e) {
18815
18967
  }
18816
18968
  function probe(secure, host, port, ms) {
18817
18969
  return new Promise((resolve2) => {
18818
- const socket = secure ? tls({ host, port, ...isIP(host) ? {} : { servername: host } }) : tcp({ host, port });
18970
+ const socket = secure ? tls({ host, port, ...isIP2(host) ? {} : { servername: host } }) : tcp({ host, port });
18819
18971
  const done4 = (code) => {
18820
18972
  clearTimeout(timer);
18821
18973
  socket.destroy();
@@ -18835,7 +18987,7 @@ async function diagnose(url, ms = PROBE_MS) {
18835
18987
  const secure = at.protocol === "wss:";
18836
18988
  const port = Number(at.port) || (secure ? 443 : 80);
18837
18989
  try {
18838
- await lookup(host);
18990
+ await lookup2(host);
18839
18991
  } catch (e) {
18840
18992
  return NO_NAME.has(codeOf5(e) ?? "") ? "EAI_NONAME" : void 0;
18841
18993
  }
@@ -19684,9 +19836,10 @@ function hostfsFetchOf(options) {
19684
19836
  }
19685
19837
  };
19686
19838
  }
19687
- function nodeTransport() {
19839
+ function nodeTransport(options = {}) {
19688
19840
  const transport = fetchTransport({ webSocket: true, webSocketHeaders: true, redirect: "manual" });
19689
- return diagnosing({ ...transport, traits: { ...transport.traits, crossOrigin: "any" } });
19841
+ const open = { ...transport, traits: { ...transport.traits, crossOrigin: "any" } };
19842
+ return diagnosing(guardedLoopback(open, options.hostLoopback ?? false));
19690
19843
  }
19691
19844
  var TERMINATED = "the kernel is terminated";
19692
19845
  var EXIT_GRACE_MS = 50;