@nimbus-sh/worker 0.10.0 → 0.11.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 (260) hide show
  1. package/NOTICE.md +5 -0
  2. package/README.md +10 -0
  3. package/dist/_shared/session-router.d.ts +7 -0
  4. package/dist/_shared/session-router.d.ts.map +1 -1
  5. package/dist/_shared/session-router.js +7 -0
  6. package/dist/bindings/body.d.ts +6 -0
  7. package/dist/bindings/body.d.ts.map +1 -0
  8. package/dist/bindings/body.js +37 -0
  9. package/dist/bindings/kv.d.ts +0 -2
  10. package/dist/bindings/kv.d.ts.map +1 -1
  11. package/dist/bindings/kv.js +3 -42
  12. package/dist/bindings/r2.d.ts +0 -2
  13. package/dist/bindings/r2.d.ts.map +1 -1
  14. package/dist/bindings/r2.js +4 -44
  15. package/dist/esbuild-cli-artifact.generated.d.ts +18 -0
  16. package/dist/esbuild-cli-artifact.generated.d.ts.map +1 -0
  17. package/dist/esbuild-cli-artifact.generated.js +17 -0
  18. package/dist/facets/cirrus-real.d.ts.map +1 -1
  19. package/dist/facets/cirrus-real.js +9 -4
  20. package/dist/facets/compose.d.ts +11 -7
  21. package/dist/facets/compose.d.ts.map +1 -1
  22. package/dist/facets/compose.js +8 -38
  23. package/dist/facets/data-plan.d.ts +79 -0
  24. package/dist/facets/data-plan.d.ts.map +1 -0
  25. package/dist/facets/data-plan.js +477 -0
  26. package/dist/facets/esbuild-transform.d.ts +36 -10
  27. package/dist/facets/esbuild-transform.d.ts.map +1 -1
  28. package/dist/facets/esbuild-transform.js +216 -20
  29. package/dist/facets/exec-telemetry.d.ts +7 -3
  30. package/dist/facets/exec-telemetry.d.ts.map +1 -1
  31. package/dist/facets/manager.d.ts +179 -78
  32. package/dist/facets/manager.d.ts.map +1 -1
  33. package/dist/facets/manager.js +1221 -649
  34. package/dist/facets/opencode-staging.d.ts +0 -2
  35. package/dist/facets/opencode-staging.d.ts.map +1 -1
  36. package/dist/facets/opencode-staging.js +5 -11
  37. package/dist/facets/process.d.ts +4 -0
  38. package/dist/facets/process.d.ts.map +1 -1
  39. package/dist/facets/process.js +3 -0
  40. package/dist/facets/read-profile.d.ts +149 -0
  41. package/dist/facets/read-profile.d.ts.map +1 -0
  42. package/dist/facets/read-profile.js +483 -0
  43. package/dist/facets/resident-identity.d.ts +0 -1
  44. package/dist/facets/resident-identity.d.ts.map +1 -1
  45. package/dist/facets/resident-identity.js +0 -3
  46. package/dist/facets/wasm-swap-registry.d.ts +34 -25
  47. package/dist/facets/wasm-swap-registry.d.ts.map +1 -1
  48. package/dist/facets/wasm-swap-registry.js +62 -56
  49. package/dist/facets/ws-terminal.d.ts +4 -4
  50. package/dist/facets/ws-terminal.d.ts.map +1 -1
  51. package/dist/facets/ws-terminal.js +4 -5
  52. package/dist/git/commands.d.ts +16 -9
  53. package/dist/git/commands.d.ts.map +1 -1
  54. package/dist/git/commands.js +1818 -188
  55. package/dist/git/network-facet.d.ts +10 -2
  56. package/dist/git/network-facet.d.ts.map +1 -1
  57. package/dist/git/network-facet.js +62 -16
  58. package/dist/git/unified-diff.d.ts +74 -0
  59. package/dist/git/unified-diff.d.ts.map +1 -0
  60. package/dist/git/unified-diff.js +676 -0
  61. package/dist/git-bundle.generated.d.ts +7 -11
  62. package/dist/git-bundle.generated.d.ts.map +1 -1
  63. package/dist/git-bundle.generated.js +7 -11
  64. package/dist/hosted/commands.d.ts.map +1 -1
  65. package/dist/hosted/commands.js +62 -243
  66. package/dist/hosted/runtime.d.ts +19 -13
  67. package/dist/hosted/runtime.d.ts.map +1 -1
  68. package/dist/hosted/runtime.js +71 -14
  69. package/dist/hosted/services.d.ts +6 -7
  70. package/dist/hosted/services.d.ts.map +1 -1
  71. package/dist/hosted/services.js +10 -14
  72. package/dist/hosted/session.d.ts +165 -0
  73. package/dist/hosted/session.d.ts.map +1 -0
  74. package/dist/hosted/session.js +132 -0
  75. package/dist/loaders/generated-workers.d.ts +5 -2
  76. package/dist/loaders/generated-workers.d.ts.map +1 -1
  77. package/dist/loaders/generated-workers.js +6 -3
  78. package/dist/loaders/npm-resolve-preamble.d.ts.map +1 -1
  79. package/dist/loaders/npm-resolve-preamble.js +0 -27
  80. package/dist/node-shims-artifact.generated.d.ts +13 -4
  81. package/dist/node-shims-artifact.generated.d.ts.map +1 -1
  82. package/dist/node-shims-artifact.generated.js +16 -7
  83. package/dist/npm/bin-links.d.ts +3 -1
  84. package/dist/npm/bin-links.d.ts.map +1 -1
  85. package/dist/npm/bin-links.js +32 -8
  86. package/dist/npm/cache.d.ts +5 -0
  87. package/dist/npm/cache.d.ts.map +1 -1
  88. package/dist/npm/cache.js +13 -1
  89. package/dist/npm/install-batch-facet.d.ts +2 -2
  90. package/dist/npm/install-batch-facet.js +3 -3
  91. package/dist/npm/installer.d.ts +17 -1
  92. package/dist/npm/installer.d.ts.map +1 -1
  93. package/dist/npm/installer.js +159 -20
  94. package/dist/npm/package-lock.d.ts +32 -0
  95. package/dist/npm/package-lock.d.ts.map +1 -0
  96. package/dist/npm/package-lock.js +65 -0
  97. package/dist/npm/pre-bundle-facet.d.ts +1 -30
  98. package/dist/npm/pre-bundle-facet.d.ts.map +1 -1
  99. package/dist/npm/pre-bundle-facet.js +3 -5
  100. package/dist/npm/r2-cache.d.ts +2 -0
  101. package/dist/npm/r2-cache.d.ts.map +1 -1
  102. package/dist/npm/r2-cache.js +2 -0
  103. package/dist/npm/resolve-one-facet.d.ts.map +1 -1
  104. package/dist/npm/resolve-one-facet.js +14 -3
  105. package/dist/npm/resolver.d.ts +0 -7
  106. package/dist/npm/resolver.d.ts.map +1 -1
  107. package/dist/npm/resolver.js +0 -22
  108. package/dist/opencode-artifact.generated.js +2 -2
  109. package/dist/replica/routing.d.ts +2 -38
  110. package/dist/replica/routing.d.ts.map +1 -1
  111. package/dist/replica/routing.js +3 -55
  112. package/dist/router/index.d.ts.map +1 -1
  113. package/dist/router/index.js +15 -2
  114. package/dist/router/public-directory.d.ts +18 -0
  115. package/dist/router/public-directory.d.ts.map +1 -1
  116. package/dist/router/public-directory.js +1 -1
  117. package/dist/router/remote-api.d.ts +3 -1
  118. package/dist/router/remote-api.d.ts.map +1 -1
  119. package/dist/router/remote-api.js +42 -79
  120. package/dist/runtime/bash-repl.js +2 -2
  121. package/dist/runtime/bun-repl.d.ts.map +1 -1
  122. package/dist/runtime/bun-repl.js +2 -13
  123. package/dist/runtime/esbuild-wasm-bytes.d.ts +17 -5
  124. package/dist/runtime/esbuild-wasm-bytes.d.ts.map +1 -1
  125. package/dist/runtime/esbuild-wasm-bytes.js +43 -94
  126. package/dist/runtime/git-bundle-artifact.d.ts +17 -0
  127. package/dist/runtime/git-bundle-artifact.d.ts.map +1 -0
  128. package/dist/runtime/git-bundle-artifact.js +25 -0
  129. package/dist/runtime/node-repl.d.ts.map +1 -1
  130. package/dist/runtime/node-repl.js +2 -13
  131. package/dist/runtime/node-shims-artifact.d.ts +22 -23
  132. package/dist/runtime/node-shims-artifact.d.ts.map +1 -1
  133. package/dist/runtime/node-shims-artifact.js +48 -78
  134. package/dist/runtime/node-shims.d.ts.map +1 -1
  135. package/dist/runtime/node-shims.js +1567 -864
  136. package/dist/runtime/opencode-artifact.d.ts.map +1 -1
  137. package/dist/runtime/opencode-artifact.js +17 -53
  138. package/dist/runtime/opencode-facet-runner.d.ts +3 -6
  139. package/dist/runtime/opencode-facet-runner.d.ts.map +1 -1
  140. package/dist/runtime/opencode-facet-runner.js +45 -10
  141. package/dist/runtime/opentui-wasm-bytes.d.ts.map +1 -1
  142. package/dist/runtime/opentui-wasm-bytes.js +16 -49
  143. package/dist/runtime/package-manager.d.ts +0 -2
  144. package/dist/runtime/package-manager.d.ts.map +1 -1
  145. package/dist/runtime/package-manager.js +0 -3
  146. package/dist/runtime/python-repl.d.ts.map +1 -1
  147. package/dist/runtime/python-repl.js +2 -2
  148. package/dist/runtime/repl-session.d.ts +10 -0
  149. package/dist/runtime/repl-session.d.ts.map +1 -1
  150. package/dist/runtime/repl-session.js +7 -0
  151. package/dist/runtime/ruby-repl.d.ts.map +1 -1
  152. package/dist/runtime/ruby-repl.js +2 -2
  153. package/dist/runtime/ruby-resident.d.ts.map +1 -1
  154. package/dist/runtime/ruby-resident.js +36 -35
  155. package/dist/runtime/runtime-catalog.d.ts +10 -3
  156. package/dist/runtime/runtime-catalog.d.ts.map +1 -1
  157. package/dist/runtime/runtime-catalog.js +125 -15
  158. package/dist/runtime/sqlite-wasm-bytes.d.ts +4 -4
  159. package/dist/runtime/sqlite-wasm-bytes.d.ts.map +1 -1
  160. package/dist/runtime/sqlite-wasm-bytes.js +21 -57
  161. package/dist/runtime/staged-source.d.ts +67 -0
  162. package/dist/runtime/staged-source.d.ts.map +1 -0
  163. package/dist/runtime/staged-source.js +113 -0
  164. package/dist/runtime/wasi/preamble.d.ts.map +1 -1
  165. package/dist/runtime/wasi/preamble.js +0 -24
  166. package/dist/runtime-catalog.generated.js +1 -1
  167. package/dist/session/agent.d.ts +14 -2
  168. package/dist/session/agent.d.ts.map +1 -1
  169. package/dist/session/agent.js +57 -19
  170. package/dist/session/ai.d.ts +0 -11
  171. package/dist/session/ai.d.ts.map +1 -1
  172. package/dist/session/ai.js +0 -4
  173. package/dist/session/fs-watch.d.ts +0 -11
  174. package/dist/session/fs-watch.d.ts.map +1 -1
  175. package/dist/session/fs-watch.js +0 -21
  176. package/dist/session/hibernation.d.ts +34 -11
  177. package/dist/session/hibernation.d.ts.map +1 -1
  178. package/dist/session/hibernation.js +46 -29
  179. package/dist/session/init-phases.d.ts +1 -2
  180. package/dist/session/init-phases.d.ts.map +1 -1
  181. package/dist/session/init-phases.js +1 -2
  182. package/dist/session/init.d.ts.map +1 -1
  183. package/dist/session/init.js +7 -20
  184. package/dist/session/keys.d.ts +0 -3
  185. package/dist/session/keys.d.ts.map +1 -1
  186. package/dist/session/keys.js +0 -3
  187. package/dist/session/legacy-reset.d.ts +11 -0
  188. package/dist/session/legacy-reset.d.ts.map +1 -0
  189. package/dist/session/legacy-reset.js +16 -0
  190. package/dist/session/nimbus-session.d.ts +41 -15
  191. package/dist/session/nimbus-session.d.ts.map +1 -1
  192. package/dist/session/nimbus-session.js +64 -70
  193. package/dist/session/npm-install-port.d.ts.map +1 -1
  194. package/dist/session/npm-install-port.js +1 -0
  195. package/dist/session/programmatic.d.ts +13 -18
  196. package/dist/session/programmatic.d.ts.map +1 -1
  197. package/dist/session/programmatic.js +53 -39
  198. package/dist/session/replica-routes.d.ts +2 -3
  199. package/dist/session/replica-routes.d.ts.map +1 -1
  200. package/dist/session/replica-routes.js +3 -10
  201. package/dist/session/routes.d.ts.map +1 -1
  202. package/dist/session/routes.js +7 -10
  203. package/dist/session/rpc.d.ts +104 -20
  204. package/dist/session/rpc.d.ts.map +1 -1
  205. package/dist/session/rpc.js +184 -37
  206. package/dist/session/start-real-vite.js +2 -2
  207. package/dist/session/state-store.d.ts +1 -17
  208. package/dist/session/state-store.d.ts.map +1 -1
  209. package/dist/session/state-store.js +3 -53
  210. package/dist/session/supervisor-op.d.ts +7 -0
  211. package/dist/session/supervisor-op.d.ts.map +1 -1
  212. package/dist/session/supervisor-op.js +6 -1
  213. package/dist/session/supervisor-rpc.d.ts +104 -15
  214. package/dist/session/supervisor-rpc.d.ts.map +1 -1
  215. package/dist/session/supervisor-rpc.js +188 -71
  216. package/dist/session/vite-command.d.ts.map +1 -1
  217. package/dist/session/vite-command.js +17 -14
  218. package/dist/session/ws.d.ts.map +1 -1
  219. package/dist/session/ws.js +20 -8
  220. package/dist/shell/npm-bin-entrypoints.d.ts.map +1 -1
  221. package/dist/shell/npm-bin-entrypoints.js +30 -5
  222. package/dist/vfs/facet-resident-limits.d.ts +33 -0
  223. package/dist/vfs/facet-resident-limits.d.ts.map +1 -0
  224. package/dist/vfs/facet-resident-limits.js +33 -0
  225. package/dist/vfs/facet-resident-store.d.ts +2 -10
  226. package/dist/vfs/facet-resident-store.d.ts.map +1 -1
  227. package/dist/vfs/facet-resident-store.js +1594 -219
  228. package/dist/workspace-host.d.ts +2 -0
  229. package/dist/workspace-host.d.ts.map +1 -1
  230. package/dist/workspace-host.js +2 -0
  231. package/dist/wrangler/nimbus-wrangler.d.ts +0 -2
  232. package/dist/wrangler/nimbus-wrangler.d.ts.map +1 -1
  233. package/dist/wrangler/nimbus-wrangler.js +5 -22
  234. package/package.json +8 -7
  235. package/public/_assets/opencode/1.16.2/index-attach.js +2 -2
  236. package/public/_assets/runtime/esbuild-cli-c4fda380d52befc1.js +6892 -0
  237. package/public/_assets/runtime/git-de3e60c9f3ff006a.js +103 -0
  238. package/public/_assets/runtime/{node-shims-7b4dd7a76d95d21e.js → node-shims-06565b121555c194.js} +2089 -861
  239. package/public/_assets/runtime/resident-store-6ffb1939c53d982f.js +2264 -0
  240. package/public/_assets/runtime/vfs-write-ledger-e501e8fc793bc2c1.js +889 -0
  241. package/scripts/build-opencode-attach-entry.mjs +51 -1
  242. package/scripts/bundle-facet-workers.mjs +114 -3
  243. package/scripts/bundle-git.mjs +88 -27
  244. package/scripts/bundle-node-shims.mjs +72 -46
  245. package/scripts/bundle-runtime.mjs +18 -421
  246. package/scripts/cf-git-patch.mjs +137 -0
  247. package/scripts/patch-install-deps.mjs +49 -96
  248. package/scripts/runtime-specs.mjs +435 -0
  249. package/vendor/git-http.generated.d.ts +82 -0
  250. package/vendor/git-upstream.generated.d.ts +4378 -0
  251. package/vendor/git.LICENSE +7 -0
  252. package/vendor/git.generated.d.mts +21 -0
  253. package/vendor/git.generated.mjs +103 -0
  254. package/dist/replica/suspension.d.ts +0 -36
  255. package/dist/replica/suspension.d.ts.map +0 -1
  256. package/dist/replica/suspension.js +0 -49
  257. package/dist/runtime/static-server.d.ts +0 -3
  258. package/dist/runtime/static-server.d.ts.map +0 -1
  259. package/dist/runtime/static-server.js +0 -133
  260. package/scripts/clean-dist.mjs +0 -7
@@ -2,10 +2,37 @@
2
2
  // ═══════════════════════════════════════════════════════════════════════
3
3
  // ── Format helper ──────────────────────────────────────────────────
4
4
  // ═══════════════════════════════════════════════════════════════════════
5
+ function __isErrorValue(v) {
6
+ return v instanceof Error || Object.prototype.toString.call(v) === "[object Error]";
7
+ }
8
+ // Node's util.inspect(err); JSON.stringify drops non-enumerable name/message/stack.
9
+ function __fmtError(e, seen) {
10
+ if (seen.has(e)) return "[Circular *]";
11
+ seen.add(e);
12
+ let text;
13
+ try { text = typeof e.stack === "string" && e.stack ? e.stack : Error.prototype.toString.call(e); }
14
+ catch { text = String(e); }
15
+ const fields = [];
16
+ for (const key of Object.keys(e)) {
17
+ if (key === "cause") continue;
18
+ let value;
19
+ try { value = e[key]; } catch { continue; }
20
+ fields.push(key + ": " + __fmtField(value, seen));
21
+ }
22
+ if (Object.prototype.hasOwnProperty.call(e, "cause")) fields.push("[cause]: " + __fmtField(e.cause, seen));
23
+ if (fields.length === 0) return text;
24
+ return text + " {\n" + fields.map((f) => " " + f.split("\n").join("\n ")).join(",\n") + "\n}";
25
+ }
26
+ function __fmtField(v, seen) {
27
+ if (typeof v === "string") return JSON.stringify(v);
28
+ if (v !== null && typeof v === "object" && __isErrorValue(v)) return __fmtError(v, seen);
29
+ return __fmt(v);
30
+ }
5
31
  function __fmt(v) {
6
32
  if (v === null) return "null";
7
33
  if (v === undefined) return "undefined";
8
34
  if (typeof v === "object") {
35
+ if (__isErrorValue(v)) return __fmtError(v, new Set());
9
36
  try { return JSON.stringify(v); } catch { return String(v); }
10
37
  }
11
38
  return String(v);
@@ -58,6 +85,41 @@ async function __nimbusUseRpcResultUnref(promise, use) {
58
85
  finally { __nimbusDisposeRpcResult(value); }
59
86
  }
60
87
 
88
+ /**
89
+ * The ACQUIRE barrier, taken before the program sees anything that arrived
90
+ * from outside it: a response or body from the network, a relayed socket
91
+ * frame, a request routed to one of its ports, a stdin packet or signal, a
92
+ * child's output or exit. Each of those can be the second half of a causal
93
+ * chain that began with a write somewhere else — `echo v2 > f; curl :3000`,
94
+ * a child that writes a file and then exits — and the handler's synchronous
95
+ * reads must see that write. Nothing but this barrier carries it.
96
+ *
97
+ * What the supervisor delivers — a request, a stdin packet, a child's output
98
+ * or exit — carries the answer to this barrier with it (`delivered`,
99
+ * session/rpc.ts _acquireOnDelivery), computed after the thing delivered was
100
+ * queued, so the barrier applies that answer instead of asking, and the
101
+ * program resumes with no round trip of its own. It asks when there is none
102
+ * or it cannot use the one delivered. A resumption the supervisor does not
103
+ * deliver — a timer, the network — always asks.
104
+ *
105
+ * The barrier is installed by the fs module, which is evaluated after this
106
+ * point; a facet with no supervisor has none and nothing to be coherent with.
107
+ */
108
+ async function __nimbusInboundBarrier(delivered) {
109
+ const acquire = globalThis.__nimbusVfsAcquireBarrier;
110
+ if (typeof acquire === "function") await acquire(delivered);
111
+ }
112
+
113
+ /**
114
+ * The arguments this process asks its ACQUIRE with (the fs module's
115
+ * _acquireArgs), for a delivery to be answered from: a long poll sends them,
116
+ * and what it delivers comes back carrying fsAcquire's answer to them.
117
+ */
118
+ function __nimbusVfsAcquireArgs() {
119
+ const args = globalThis.__nimbusVfsAcquireArgs;
120
+ return typeof args === "function" ? args() : undefined;
121
+ }
122
+
61
123
  // ═══════════════════════════════════════════════════════════════════════
62
124
  // ── Precompiled wasm ───────────────────────────────────────────────
63
125
  // A wasm image can only become a WebAssembly.Module through the Worker
@@ -287,13 +349,11 @@ function __nimbusWasmDigest(bytes) {
287
349
  // supervisor round trip per outbound request, not a hidden one. It is the
288
350
  // price of the guarantee.
289
351
  //
290
- // The barriers live on globalThis because the fs module installs them and
291
- // is evaluated after this one; a facet with no supervisor bound has none,
292
- // and there is nothing to be coherent with.
352
+ // The RELEASE barrier lives on globalThis because the fs module installs it
353
+ // and is evaluated after this one; the ACQUIRE is __nimbusInboundBarrier.
293
354
  const __resumeCoherent = async (pending) => {
294
355
  const value = await pending;
295
- const acquire = globalThis.__nimbusVfsAcquireBarrier;
296
- if (typeof acquire === "function") await acquire();
356
+ await __nimbusInboundBarrier();
297
357
  return value;
298
358
  };
299
359
  const __barriered = async (input, init) => {
@@ -323,6 +383,15 @@ function __nimbusWasmDigest(bytes) {
323
383
 
324
384
  let __nimbusLiveStdinPump = null;
325
385
  let __nimbusProcessExitReported = false;
386
+ // Set when the program has exited: its timers are cleared and its writes refused.
387
+ let __nimbusProgramStopped = false;
388
+ let __nimbusExitEmitted = false;
389
+ // 'exit' listeners run once, synchronously, before the program is stopped.
390
+ function __nimbusEmitExit(code) {
391
+ if (__nimbusExitEmitted) return;
392
+ __nimbusExitEmitted = true;
393
+ try { __processEvents.emit("exit", code); } catch {}
394
+ }
326
395
  let __nimbusProcessExitResolve = null;
327
396
  let __nimbusProcessExitCode = null;
328
397
  const __nimbusProcessExitPromise = new Promise((resolve) => {
@@ -673,29 +742,205 @@ const __fsMod = (() => {
673
742
  // ── VFS bundle lookup (fast path — in-memory) ──
674
743
  function _bundleLookup(absPath) {
675
744
  const k = _strip(absPath);
676
- if (__vfsBundle && k in __vfsBundle) return __vfsBundle[k];
677
- // Also check writes
745
+ if (globalThis.__nimbusProfileStaged) globalThis.__nimbusProfileStaged.delete(k);
746
+ // The parked write first, as _writtenCell reads: it is this process's own,
747
+ // newer than anything the store holds, and it is the live cell (a store
748
+ // read reassembles a copy, which a write loop would pay for per write).
678
749
  if (__vfsWrites && k in __vfsWrites) return __vfsWrites[k];
750
+ if (__vfsBundle && k in __vfsBundle) return __vfsBundle[k];
751
+ // The same bytes under the name they are held by: through a symlink, or
752
+ // under the old name of a rename this process has not seen land yet.
753
+ if (__vfsBundle && _nsActive()) {
754
+ const real = _nsRealKey(k);
755
+ if (real !== null && real !== k && real in __vfsBundle) return __vfsBundle[real];
756
+ }
679
757
  return undefined;
680
758
  }
681
759
 
682
- // __vfsMetadata is not declared in every embedding of these shims, so the
683
- // one guarded reference lives here and every other reader goes through it.
684
- function _metadataTable() {
685
- return (typeof __vfsMetadata !== "undefined" && __vfsMetadata) ? __vfsMetadata : null;
686
- }
687
-
688
- // Same guard, same reason: the SQLite resident store is spliced into the
689
- // resident-process body only. The one-shot exec path runs in a stateless
690
- // loaded worker with no facet storage at all, so these shims must still work
691
- // with the resident set on the heap and this is the single place that asks.
760
+ // Whether the store is bound: every embedding of these shims boots one (a
761
+ // facet's SQLite, or a one-shot's heap), and this is the single place that asks.
692
762
  function _residentStorePresent() {
693
763
  return typeof __residentAdmit === "function" && typeof __residentReady !== "undefined" && __residentReady;
694
764
  }
695
765
 
766
+ // ── The namespace (resident facets) ──
767
+ //
768
+ // A resident facet's store holds every name the credential can see, with
769
+ // its stat, exact at the cursor (vfs/facet-resident-store.ts). While it
770
+ // does, it answers every synchronous metadata question — stat, exists,
771
+ // readdir, realpath, access — and an absent name is known absent, so none
772
+ // of them records a miss or refuses. While it does not (a relist failed,
773
+ // until the next barrier repairs it), each of them is refused by name
774
+ // (_nsRequire).
775
+ //
776
+ // What the table cannot know is this process's own structural effects that
777
+ // the authority has not reported back yet, so those sit in an overlay, one
778
+ // entry per path: "absent" / "absentTree" (unlink, rmdir, rm), "dir"
779
+ // (mkdir; `hide` when nothing was there, so no stale child shows through)
780
+ // and "alias" (a rename: the new name denotes what the old one did). An
781
+ // entry retires once its mutation has settled AND a barrier begun after
782
+ // that has applied, because such a barrier's delta is answered after the
783
+ // mutation committed, so the table then shows it or anything later.
784
+ function _nsActive() {
785
+ return typeof __nsReady === "function" && __nsReady();
786
+ }
787
+ // The namespace answers every synchronous metadata question, or none. While
788
+ // it is not ready (a relist failed, until the next barrier repairs it) a
789
+ // synchronous call is refused, naming why and the asynchronous form that
790
+ // answers now. A launch never runs user code before it is ready.
791
+ function _nsRequire(syscall, displayPath, asyncForm) {
792
+ if (_nsActive()) return;
793
+ _stats.namespaceRefusals++;
794
+ const why = typeof __nsNotReadyCause === "function" ? __nsNotReadyCause() : "the process was started without one";
795
+ const err = _fsErr("EAGAIN", syscall, displayPath);
796
+ err.message = "EAGAIN: " + syscall + " '" + String(displayPath) + "': the namespace is being rebuilt after " + why
797
+ + (_supervisor() ? "; use " + asyncForm : "");
798
+ throw err;
799
+ }
800
+ const _nsOwn = new Map();
801
+ let _nsFresh = [];
802
+ let _barrierBegins = 0;
803
+ function _nsOwnSet(k, state, extra) {
804
+ const before = _nsOwn.get(k);
805
+ const entry = { state, from: extra?.from, hide: !!extra?.hide, settled: null };
806
+ try { __residentNamespaceOverlayDelta(_nsOwnCost(k, entry) - (before ? _nsOwnCost(k, before) : 0)); }
807
+ catch (error) {
808
+ // The view is sealed by the store. Let the already-projected structural
809
+ // operation reach its authority/ack; aborting midway would strand
810
+ // earlier overlays with no owning mutation to retire them.
811
+ if (__residentInHeap && error?.code === "ENOSPC") return;
812
+ throw error;
813
+ }
814
+ _nsOwn.set(k, entry);
815
+ _nsFresh.push(entry);
816
+ }
817
+ function _nsOwnCost(k, entry) { return __namespaceRowBytes("", k, entry.from); }
818
+ /** Hand the overlay entries made since the last mutation to the one being queued. */
819
+ function _nsTakeFresh() {
820
+ const mine = _nsFresh;
821
+ _nsFresh = [];
822
+ return () => { for (const entry of mine) if (entry.settled === null) entry.settled = _barrierBegins; };
823
+ }
824
+ function _nsRetire(begin) {
825
+ for (const [k, entry] of _nsOwn) if (entry.settled !== null && entry.settled < begin) {
826
+ _nsOwn.delete(k);
827
+ __residentNamespaceOverlayDelta(-_nsOwnCost(k, entry));
828
+ }
829
+ }
830
+
831
+ /**
832
+ * The overlay's word on `k`: "absent", { alias } (look the table up at
833
+ * this key instead), { dir } (own directory), { hide } (the table knows
834
+ * nothing under an own fresh directory), or null (ask the table).
835
+ */
836
+ function _nsOwnView(k) {
837
+ if (_nsOwn.size === 0) return null;
838
+ const own = _nsOwn.get(k);
839
+ if (own) {
840
+ if (own.state === "absent" || own.state === "absentTree") return "absent";
841
+ if (own.state === "alias") return { alias: own.from };
842
+ return { dir: true };
843
+ }
844
+ for (let i = k.lastIndexOf("/"); i > 0; i = k.lastIndexOf("/", i - 1)) {
845
+ const above = _nsOwn.get(k.slice(0, i));
846
+ if (!above) continue;
847
+ if (above.state === "absent" || above.state === "absentTree") return "absent";
848
+ if (above.state === "alias") return { alias: above.from + k.slice(i) };
849
+ if (above.hide) return { hide: true };
850
+ }
851
+ return null;
852
+ }
853
+
854
+ /** The table key `k` denotes (overlay and symlinks applied), or null. */
855
+ function _nsRealKey(k) {
856
+ const own = _nsOwnView(k);
857
+ if (own === "absent" || (own && (own.dir || own.hide))) return null;
858
+ const found = __nsResolve(own && own.alias !== undefined ? own.alias : k, true);
859
+ return found && found !== "ELOOP" ? found.path : null;
860
+ }
861
+
862
+ function _nsRowMeta(row) {
863
+ const kind = Number(row.kind);
864
+ return {
865
+ type: kind === 1 ? "directory" : kind === 2 ? "symlink" : "file",
866
+ size: Number(row.size), mode: Number(row.mode), uid: Number(row.uid), gid: Number(row.gid),
867
+ atime: Number(row.atime), mtime: Number(row.mtime), ctime: Number(row.ctime),
868
+ };
869
+ }
870
+
871
+ /**
872
+ * Everything the namespace says about `k`: a stat record, "absent", or
873
+ * "ELOOP". Own pending writes and directories first, then the overlay,
874
+ * then the table, then content this process wrote that the table has not
875
+ * caught up with.
876
+ */
877
+ function _nsMeta(k, follow) {
878
+ if (k === "") return _nsRowMeta(__nsResolve("", true).row);
879
+ if (__vfsWrites && k in __vfsWrites && _denialCode(__vfsWrites[k]) === null) {
880
+ const size = _byteLen(__vfsWrites[k]);
881
+ if (_createdHere.has(k)) {
882
+ return { type: "file", size, mode: 0o100666 & ~__processUmask, uid: cred.uid, gid: cred.gid, own: true };
883
+ }
884
+ // A rewrite of a file that was there: its owner and mode stay what the
885
+ // authority says they are.
886
+ const found = __nsResolve(k, follow);
887
+ if (found && found !== "ELOOP" && Number(found.row.kind) === 0) return { ..._nsRowMeta(found.row), size };
888
+ }
889
+ const own = _nsOwnView(k);
890
+ if (own === "absent") return "absent";
891
+ if (own && own.dir) return { type: "directory", size: 0, mode: 0o40777 & ~__processUmask, uid: cred.uid, gid: cred.gid, own: true };
892
+ // A directory this process made hides what the namespace held under its
893
+ // name before, but not what this process has put there since: those rows
894
+ // are its own writes, recorded when the authority accepted them.
895
+ if (!own || own.alias !== undefined || (own.hide && _createdHere.has(k))) {
896
+ const found = __nsResolve(own && own.alias !== undefined ? own.alias : k, follow);
897
+ if (found === "ELOOP") return "ELOOP";
898
+ if (found) return _nsRowMeta(found.row);
899
+ }
900
+ // The namespace is exact, so a name it lacks is not there, whatever bytes
901
+ // the module map carries under it (a file removed since the map was
902
+ // built). Content never stands in for metadata.
903
+ return "absent";
904
+ }
905
+
906
+ /** Names directly under directory `k`: Map name → type. */
907
+ function _nsList(k) {
908
+ const names = new Map();
909
+ const own = _nsOwnView(k);
910
+ if (own !== "absent" && !(own && own.hide) && !(own && own.dir && _nsOwn.get(k)?.hide)) {
911
+ const real = __nsResolve(own && own.alias !== undefined ? own.alias : k, true);
912
+ if (real && real !== "ELOOP") {
913
+ for (const child of __nsChildren(real.path)) {
914
+ names.set(child.name, child.kind === 1 ? "directory" : child.kind === 2 ? "symlink" : "file");
915
+ }
916
+ }
917
+ }
918
+ const prefix = k ? k + "/" : "";
919
+ if (__vfsWrites) {
920
+ for (const wk in __vfsWrites) {
921
+ if (!wk.startsWith(prefix)) continue;
922
+ const rest = wk.slice(prefix.length);
923
+ const slash = rest.indexOf("/");
924
+ if (rest) names.set(slash < 0 ? rest : rest.slice(0, slash), slash < 0 ? "file" : "directory");
925
+ }
926
+ }
927
+ for (const [ok, entry] of _nsOwn) {
928
+ if (!ok.startsWith(prefix) || ok.slice(prefix.length).includes("/")) continue;
929
+ const name = ok.slice(prefix.length);
930
+ if (entry.state === "absent" || entry.state === "absentTree") { if (!(__vfsWrites && ok in __vfsWrites)) names.delete(name); }
931
+ else if (entry.state === "dir") names.set(name, "directory");
932
+ else {
933
+ const meta = _nsMeta(ok, false);
934
+ if (meta !== "absent" && meta !== "ELOOP") names.set(name, meta.type);
935
+ }
936
+ }
937
+ return names;
938
+ }
939
+
696
940
  function _metadata(absPath) {
697
- const table = _metadataTable();
698
- return table ? table[_strip(absPath)] : undefined;
941
+ _nsRequire("stat", absPath, "fs.promises.stat");
942
+ const meta = _nsMeta(_strip(absPath), true);
943
+ return meta === "absent" || meta === "ELOOP" ? undefined : meta;
699
944
  }
700
945
 
701
946
  function _denialCode(cell) {
@@ -703,52 +948,13 @@ const __fsMod = (() => {
703
948
  typeof cell.error === "string" ? cell.error : null;
704
949
  }
705
950
 
706
- // Removal retracts the path from the sync existence view — __vfsMetadata
707
- // (spawn-time stat records) and __vfsManifest (directory shape). Without
708
- // it, existsSync keeps reporting a file this process already deleted and
709
- // the sync read path reports that file as merely non-resident.
951
+ // Removal retracts the path from the sync existence view: the namespace's
952
+ // overlay of this process's own effects says it is gone until a barrier's
953
+ // delta does.
710
954
  function _forgetSyncPath(k) {
955
+ _createdHere.delete(k);
711
956
  _announcedDirs.delete(k);
712
- const metadata = _metadataTable();
713
- if (metadata) delete metadata[k];
714
- if (!__vfsManifest) return;
715
- delete __vfsManifest[k];
716
- const slash = k.lastIndexOf("/");
717
- const parent = slash >= 0 ? k.slice(0, slash) : "";
718
- const name = slash >= 0 ? k.slice(slash + 1) : k;
719
- const siblings = __vfsManifest[parent];
720
- if (!siblings) return;
721
- const at = siblings.indexOf(name);
722
- if (at !== -1) siblings.splice(at, 1);
723
- }
724
-
725
- /**
726
- * Put a path into the sync EXISTENCE view — the inverse of _forgetSyncPath.
727
- *
728
- * A content cell is not existence. An invalidation drops content and is
729
- * documented to leave the name behind so existsSync cannot fabricate an
730
- * ENOENT for a file that was merely rewritten — but a file this process just
731
- * created has no manifest entry and no spawn-time stat record, so its cell
732
- * WAS the name, and evicting it retracted a file the program had written
733
- * itself. Recording the name where every other name lives is what makes that
734
- * documented asymmetry true.
735
- *
736
- * The parent's listing is the right home for it. Where the parent has no
737
- * listing the entry is created only for a directory this process made, since
738
- * that is the only case in which it knows the whole contents and calling the
739
- * directory enumerated is honest.
740
- */
741
- function _announceSyncPath(k) {
742
- if (!__vfsManifest || k === "") return;
743
- const slash = k.lastIndexOf("/");
744
- const parent = slash >= 0 ? k.slice(0, slash) : "";
745
- const name = slash >= 0 ? k.slice(slash + 1) : k;
746
- let siblings = __vfsManifest[parent];
747
- if (!Array.isArray(siblings)) {
748
- if (!__vfsDirs || !(parent in __vfsDirs)) return;
749
- siblings = __vfsManifest[parent] = [];
750
- }
751
- if (siblings.indexOf(name) === -1) siblings.push(name);
957
+ _nsOwnSet(k, "absent");
752
958
  }
753
959
 
754
960
  /**
@@ -757,41 +963,67 @@ const __fsMod = (() => {
757
963
  * content carried. One place, because every sync mutation owes all three.
758
964
  */
759
965
  function _parkWrite(k, cell) {
966
+ _noteCreation(k);
760
967
  __vfsWrites[k] = cell;
761
968
  if (__vfsBundle) __vfsBundle[k] = cell;
762
969
  delete __vfsBundleRevisions[k];
763
- _announceSyncPath(k);
970
+ }
971
+
972
+ /**
973
+ * The paths this process itself created, whose owner and mode are its own:
974
+ * its uid and gid, and what its umask leaves. Every other stat answer comes
975
+ * from the authority's metadata, and a path the authority never described
976
+ * is not given one. A stat invented from the reader's own credential made a
977
+ * root-owned file read as the reader's own and writable.
978
+ *
979
+ * A path counts as created when nothing was there before the write and the
980
+ * view KNOWS nothing was there. Unknown is not created: a file the process
981
+ * never staged may exist at the authority, owned by someone else.
982
+ */
983
+ const _createdHere = new Set();
984
+ function _noteCreation(k) {
985
+ if (_createdHere.has(k)) return;
986
+ const absPath = "/" + k;
987
+ // Known absent: the namespace names everything this credential can see.
988
+ if (_statLadder(absPath) !== undefined) return;
989
+ _createdHere.add(k);
990
+ }
991
+ function _forgetCreation(k) {
992
+ const prefix = k + "/";
993
+ for (const key of [..._createdHere]) if (key === k || key.startsWith(prefix)) _createdHere.delete(key);
764
994
  }
765
995
 
766
996
  function _forgetSyncTree(k) {
767
997
  const prefix = k + "/";
998
+ _forgetCreation(k);
999
+ _nsOwnSet(k, "absentTree");
768
1000
  for (const dir of _announcedDirs) if (dir.startsWith(prefix)) _announcedDirs.delete(dir);
769
- const metadata = _metadataTable();
770
- if (metadata) {
771
- for (const mk of Object.keys(metadata)) if (mk.startsWith(prefix)) delete metadata[mk];
772
- }
773
- if (__vfsManifest) {
774
- for (const dk of Object.keys(__vfsManifest)) if (dk.startsWith(prefix)) delete __vfsManifest[dk];
775
- }
776
1001
  _forgetSyncPath(k);
777
1002
  }
778
1003
 
779
1004
  /**
780
1005
  * The honest error for a sync read the resident view cannot serve. A facet
781
1006
  * has no synchronous I/O primitive, so a sync read is limited to content
782
- * staged into this process — but the sync existence view (__vfsMetadata +
783
- * __vfsManifest) knows far more paths than the content bundle carries.
784
- * ENOENT is only correct when the path is unknown there too; for a path
785
- * that demonstrably exists it sends the caller hunting for a missing file
786
- * instead of awaiting the read that would return it.
1007
+ * staged into this process, but the namespace names every path the
1008
+ * credential can see. ENOENT is correct only when it names none; for a path
1009
+ * that exists it would send the caller hunting for a missing file instead
1010
+ * of awaiting the read that would return it.
787
1011
  */
788
1012
  function _notResidentError(absPath, displayPath, syscall, asyncForm) {
789
1013
  const st = _statLadder(absPath);
790
- if (st === undefined) {
791
- if (!_absenceIsKnown(absPath)) _recordUnmapped(absPath, syscall);
792
- return _fsErr("ENOENT", syscall, displayPath);
793
- }
1014
+ if (st === undefined) return _fsErr("ENOENT", syscall, displayPath);
794
1015
  if (st.isDirectory()) return _fsErr("EISDIR", syscall, displayPath);
1016
+ // Unreadable to this credential: the namespace's mode says so, and no
1017
+ // bytes could have been staged for it.
1018
+ if (!_modeAllows(st, 4)) return _fsErr("EACCES", syscall, displayPath);
1019
+ if (typeof __residentStorageMiss === "function" && __residentStorageMiss(_strip(absPath))) {
1020
+ // The process's own write, which neither its store nor its heap budget
1021
+ // could hold: the workspace's storage is full.
1022
+ const full = _fsErr("ENOSPC", syscall, displayPath);
1023
+ full.message = "ENOSPC: workspace storage is full; '" + String(displayPath) + "' is readable asynchronously"
1024
+ + (_supervisor() ? " (" + asyncForm + ")" : "");
1025
+ return full;
1026
+ }
795
1027
  _recordResidencyMiss(absPath);
796
1028
  const err = _fsErr("EAGAIN", syscall, displayPath);
797
1029
  err.message += " — '" + String(displayPath) + "' exists but its content is not " +
@@ -925,7 +1157,9 @@ const __fsMod = (() => {
925
1157
  let meta;
926
1158
  // A thrown stat is the authority failing to answer, not an answer:
927
1159
  // nothing is learned, and the miss stands.
928
- try { meta = await __nimbusUseRpcResult(supervisor.stat(absPath), (r) => r); }
1160
+ // Queued on the path: the program's own later mutations of it must not overtake the stat.
1161
+ const observe = () => __nimbusUseRpcResult(supervisor.stat(absPath), (r) => r);
1162
+ try { meta = await (_hasVfsMutationQueue() ? __nimbusQueueVfsMutation(absPath, observe, false) : observe()); }
929
1163
  catch { return; }
930
1164
  if (meta === null || meta === undefined) { _observedAbsent.add(k); return; }
931
1165
  if (meta.type === "directory") return;
@@ -963,193 +1197,46 @@ const __fsMod = (() => {
963
1197
  }
964
1198
  };
965
1199
 
966
- /**
967
- * Has this directory's content been enumerated, or merely mentioned?
968
- *
969
- * __vfsManifest is a walk of SELECTED roots — the cwd subtree, its
970
- * node_modules, the entry script's own package — not of the filesystem. A
971
- * directory with an entry there was listed by that walk, so its child list
972
- * is complete and a name that is not in it is genuinely not there. A
973
- * directory with no entry was never opened, and knows nothing. __vfsDirs
974
- * holds the directories this process created itself, which it therefore
975
- * knows the contents of by construction.
976
- *
977
- * Conflating the two is what let a synchronous readdir of a real directory
978
- * outside the walk answer with an empty array — not an error, not a refusal,
979
- * a positive assertion that a populated directory is empty. Every caller
980
- * that used to end in "not found, so absent" goes through here first.
981
- */
982
- function _dirEnumerated(k) {
983
- return (!!__vfsManifest && k in __vfsManifest) || (!!__vfsDirs && k in __vfsDirs);
984
- }
985
1200
 
986
- /** Does the content bundle itself describe children under this directory? */
987
- function _bundleHasChildren(k) {
988
- if (!__vfsBundle) return false;
989
- return __residentAnyUnder(k ? k + "/" : "");
990
- }
991
1201
 
992
- /**
993
- * Can the view say this path is ABSENT, as opposed to say nothing at all?
994
- *
995
- * With no supervisor bound there is no authority to be ignorant of: the
996
- * staged tables ARE the filesystem, the async form reads out of those same
997
- * tables, and a name that is not in them is not anywhere. Ignorance is a
998
- * property of the gap between a process and an authority it cannot reach
999
- * synchronously, so where there is no authority there is no gap.
1000
- */
1001
- function _absenceIsKnown(absPath) {
1002
- if (!_supervisor()) return true;
1003
- const k = _strip(absPath);
1004
- if (k === "") return true;
1005
- const segments = k.split("/");
1006
- // Deepest enumerated ancestor, because that is the only one that can
1007
- // testify. Walking up rather than looking only at the immediate parent is
1008
- // what makes a whole missing subtree answerable from one listing: if
1009
- // $HOME was enumerated and holds no .config, then nothing under .config
1010
- // is there either, and a program probing three levels down deserves that
1011
- // answer rather than three refusals.
1012
- for (let i = segments.length - 1; i >= 0; i--) {
1013
- const dir = segments.slice(0, i).join("/");
1014
- if (!_dirEnumerated(dir)) continue;
1015
- const child = segments.slice(0, i + 1).join("/");
1016
- const children = (__vfsManifest && __vfsManifest[dir]) || [];
1017
- const present = children.indexOf(segments[i]) !== -1
1018
- || (!!__vfsDirs && child in __vfsDirs)
1019
- || (!!__vfsBundle && child in __vfsBundle);
1020
- // The component is not in a directory that was listed: absent, and so is
1021
- // everything below it. If it IS there, only its own enumeration settles
1022
- // what it contains, so nothing short of the immediate parent will do.
1023
- if (!present) return true;
1024
- return i === segments.length - 1;
1025
- }
1026
- return false;
1027
- }
1028
1202
 
1029
- /**
1030
- * A path the sync view never mapped: record the ignorance, and repair it.
1031
- *
1032
- * Sibling of _notResidentError and the same bargain — the file may well be
1033
- * there, the process simply cannot look without blocking. The callers answer
1034
- * ENOENT, which is provisional rather than fabricated: this records the miss
1035
- * and pulls in the listing that settles the question, and the exit report
1036
- * reads the ledger. If the path was genuinely absent the repair proves it
1037
- * and the entry retires — the program's not-found branch was the right
1038
- * branch and it reached it through the right errno. If the path WAS there,
1039
- * the entry survives and the run is failed by name.
1040
- *
1041
- * EAGAIN was tried here and is the wrong answer to hand a program even
1042
- * though it is the honest description of the situation. It cannot arise from
1043
- * a real POSIX filesystem, so nothing branches on it, and the catch block
1044
- * that receives it was written for a missing file and rethrows instead:
1045
- * measured, create-next-app reads $HOME/.config/<tool>/config.json through
1046
- * the conf package, is handed EAGAIN for a file that was never there, and
1047
- * dies before writing one template file. Read a config, treat ENOENT as "no
1048
- * config yet", rethrow anything else is the near-universal shape. Refusing
1049
- * bought nothing the ledger was not already delivering, and cost every
1050
- * program that idiom.
1051
- *
1052
- * A LISTING is the exception and still refuses — see readdirSync. An array is
1053
- * a complete enumeration by definition, so there is no provisional form of
1054
- * it: an empty one asserts that a directory nothing ever opened is empty,
1055
- * which is how a scaffolder was told its template directory held nothing,
1056
- * wrote nothing, and exited 0.
1057
- */
1058
- function _recordUnmapped(absPath, syscall) {
1059
- const k = _strip(absPath);
1060
- _recordMiss(k);
1061
- // A listing wants the path's own contents; a read wants its bytes. Both
1062
- // also want the boundary listing, which is the only thing that can prove
1063
- // the path was not there — and fetching one repair and then the other
1064
- // would refuse the same access twice, once for being unmapped and once for
1065
- // having no resident content. _faultOnce collapses them where they meet.
1066
- _faultInBoundary(k);
1067
- if (syscall === "scandir") { _faultInDirectory(k); return; }
1068
- _faultIn(k);
1069
- }
1070
1203
 
1071
- /**
1072
- * The shallowest directory on this path whose contents the view does not
1073
- * know: the child of the deepest ancestor that WAS enumerated.
1074
- *
1075
- * That, not the immediate parent, is the listing a refusal has to pull in.
1076
- * For a path that is not there the parent is usually not there either, so
1077
- * its readdir fails, the view learns nothing, and the ledger keeps an entry
1078
- * no repair can ever retire — the run is failed over a file that was simply
1079
- * absent. The boundary directory is different: the enumerated ancestor's own
1080
- * listing already proved it is present, so it can be read, and reading it
1081
- * either names the next component or proves the whole subtree absent.
1082
- *
1083
- * With nothing enumerated at all the boundary is the root, which is one
1084
- * listing away from making the next level answerable.
1085
- */
1086
- function _unknownBoundary(k) {
1087
- const segments = k.split("/");
1088
- for (let i = segments.length - 1; i >= 0; i--) {
1089
- if (_dirEnumerated(segments.slice(0, i).join("/"))) {
1090
- return segments.slice(0, i + 1).join("/");
1091
- }
1092
- }
1093
- return "";
1094
- }
1095
1204
 
1096
- function _faultInBoundary(k) {
1097
- _faultInDirectory(_unknownBoundary(k));
1098
- }
1099
1205
 
1100
- /**
1101
- * The refusal, for the two callers that have no provisional answer to give.
1102
- *
1103
- * A listing cannot say "not found" usefully, and neither can a write that
1104
- * needs the prior content it is splicing onto. Everywhere else the sync view
1105
- * answers ENOENT and lets the exit report settle whether that was true; here
1106
- * there is no branch the program could take that would be right, so the
1107
- * honest EAGAIN is also the useful one.
1108
- */
1109
- function _refuseUnmapped(absPath, displayPath, syscall, asyncForm) {
1110
- _recordUnmapped(absPath, syscall);
1111
- const err = _fsErr("EAGAIN", syscall, displayPath);
1112
- err.message += " — '" + String(displayPath) + "' lies outside the filesystem view "
1113
- + "staged into the process, so a synchronous call cannot tell what is there, "
1114
- + "and synchronous I/O cannot block to find out"
1115
- + (_supervisor() ? "; " + asyncForm + " answers from the live filesystem" : "");
1116
- return err;
1117
- }
1118
1206
 
1119
- /**
1120
- * Pull a directory listing in. _readdirAsync already records what it learns
1121
- * into __vfsManifest, so one call both answers the fault and converges the
1122
- * sync view on the async one — there is no second merge path to keep honest.
1123
- */
1124
- function _faultInDirectory(k) {
1125
- if (!_supervisor() || _dirEnumerated(k) || !_faultOnce("listing", k)) return;
1126
- try { _repairs.push(_readdirAsync("/" + k, undefined).catch(() => {})); }
1127
- catch { /* speculative */ }
1207
+
1208
+
1209
+ // What the authority says of a path after this process's own async request
1210
+ // (a stat, read or accepted write) is what the sync view answers for it
1211
+ // from then on, as it would after the delta that reports it
1212
+ // (facet-resident-store's __nsNoteLiveStat).
1213
+ //
1214
+ // The lstat rides the read batch (_queueBatchRequest) rather than a call
1215
+ // of its own: a resumption refetches every path it owes at once
1216
+ // (_acquireAndRefetch), and a learn per path made that one lstat call per
1217
+ // path — 1,601 in flight from one facet after a program wrote 1,600 files,
1218
+ // some of which stayed pending and never reached the session
1219
+ // (preview/new/lucide-barrel-cache-widens, measured 2026-09-28). Batched,
1220
+ // the learns cost a round trip per batch, as the reads before them do.
1221
+ async function _learnLive(absPath, supervisor) {
1222
+ if (!supervisor || typeof supervisor.fsReadBatch !== "function") return;
1223
+ let stat;
1224
+ try { stat = await _queueBatchRequest(supervisor, { path: absPath, lstat: true }, 0); } catch { return; }
1225
+ __nsNoteLiveStat(_strip(absPath), stat ?? null);
1128
1226
  }
1129
1227
 
1130
1228
  /**
1131
- * Retire the refusals a repair turned into honest absence.
1132
- *
1133
- * A refusal is only a wrong answer when the path was THERE and the process
1134
- * was denied it. Where the listing comes back and shows the name is simply
1135
- * not present, the program's not-found branch was the right branch all
1136
- * along — it merely reached it through the wrong errno — and failing the run
1137
- * over that would fail every module resolver, which probes dozens of paths
1138
- * that do not exist by design. So what stays in the ledger is exactly the
1139
- * harmful set: content that exists and was not served.
1229
+ * Retire the misses a repair turned into honest absence. A miss is a wrong
1230
+ * answer only when the path was THERE and the process was denied it: one on
1231
+ * a name the namespace does not have (or the authority did not have when it
1232
+ * was asked) was the program's not-found branch, taken for the right
1233
+ * reason. Failing the run over those would fail every module resolver,
1234
+ * which probes dozens of paths that do not exist by design.
1140
1235
  */
1141
1236
  function _settleProvenAbsences() {
1142
1237
  if (_residencyMisses.size === 0) return;
1143
1238
  for (const k of [..._residencyMisses]) {
1144
- const absPath = "/" + k;
1145
- // The authority did not have it when we asked, so nothing was withheld —
1146
- // whatever is at the path now, this process put there.
1147
- if (_observedAbsent.has(k)) { _residencyMisses.delete(k); continue; }
1148
- if (_statLadder(absPath) !== undefined) continue;
1149
- if (_absenceIsKnown(absPath)) { _residencyMisses.delete(k); continue; }
1150
- // Still unprovable, because the listing that would settle it lies below
1151
- // the one already fetched. Ask for the next one; the settle loop waits.
1152
- _faultInBoundary(k);
1239
+ if (_observedAbsent.has(k) || (_nsActive() && _statLadder("/" + k) === undefined)) _residencyMisses.delete(k);
1153
1240
  }
1154
1241
  }
1155
1242
 
@@ -1218,6 +1305,10 @@ const __fsMod = (() => {
1218
1305
 
1219
1306
  const _localTimes = globalThis.__nimbusVfsTimes || (globalThis.__nimbusVfsTimes = Object.create(null));
1220
1307
  const _localModes = globalThis.__nimbusVfsModes || (globalThis.__nimbusVfsModes = Object.create(null));
1308
+ // Modes set locally that the authority has not received yet. Delivered once:
1309
+ // re-sending on every flush made each read of the path a chmod, which bumped
1310
+ // its revision and evicted the process's own cell (create-astro EAGAIN).
1311
+ const _pendingModes = globalThis.__nimbusVfsPendingModes || (globalThis.__nimbusVfsPendingModes = new Set());
1221
1312
 
1222
1313
  function _coerceMode(value, syscall, p) {
1223
1314
  const n = typeof value === "string" ? parseInt(value, 8) : Number(value);
@@ -1242,11 +1333,9 @@ const __fsMod = (() => {
1242
1333
  atimeMs: _coerceTimeMs(atime, syscall, p),
1243
1334
  mtimeMs: _coerceTimeMs(mtime, syscall, p),
1244
1335
  };
1336
+ // The sync view answers these times ahead of the namespace's (_statObject)
1337
+ // until the utimes is reported back, as a write's own bytes are.
1245
1338
  _localTimes[k] = time;
1246
- // A spawn-time stat record answers statSync ahead of _localTimes, so it
1247
- // must carry the new times too or the sync view keeps the old mtime.
1248
- const meta = _metadata(absPath);
1249
- if (meta) { meta.atime = time.atimeMs; meta.mtime = time.mtimeMs; }
1250
1339
  return time;
1251
1340
  }
1252
1341
 
@@ -1300,7 +1389,7 @@ const __fsMod = (() => {
1300
1389
  // ══ Cache coherence: ACQUIRE + read-through fill ═════════════════════
1301
1390
  //
1302
1391
  // The supervisor's SQLite VFS is the only authority. Everything in this
1303
- // facet — __vfsBundle, __vfsMetadata, __vfsManifest, __vfsDirs — is a
1392
+ // facet — the resident store, __vfsBundle, __vfsDirs — is a
1304
1393
  // cache of it, and __vfsWrites is this process's own not-yet-flushed
1305
1394
  // mutations.
1306
1395
  //
@@ -1328,6 +1417,24 @@ const __fsMod = (() => {
1328
1417
  // a frame arrives as a supervisor reply the same barrier
1329
1418
  // rides on (see the relayed WebSocket below).
1330
1419
  //
1420
+ // The supervisor's own deliveries are resumptions too. Each takes
1421
+ // __nimbusInboundBarrier before the program sees it, and each carries the
1422
+ // barrier's answer, computed by the supervisor after the thing delivered
1423
+ // was queued (protocol §3's piggybacked inv), so the barrier applies it
1424
+ // instead of asking and the delivery costs no round trip of its own:
1425
+ // - request: a request routed to one of the process's ports, in the
1426
+ // dispatch every resident's server shares (__nimbusServeHttp).
1427
+ // The supervisor starts it, so it holds no cursor of this
1428
+ // process's and answers "nothing since now", which stands in
1429
+ // only when no write preceded the request since this process
1430
+ // last caught up (protocol §9.2); otherwise the barrier asks.
1431
+ // - stdin: a stdin packet — input, its end, a signal, a resize — for an
1432
+ // attached process (__makeProcessStdin's pump).
1433
+ // - child: a spawned child's output and its exit (_runReadLoop,
1434
+ // _runWaitLoop).
1435
+ // Stdin and child output are long polls, so they send this process's
1436
+ // ACQUIRE arguments (_acquireArgs) and are answered from exactly those.
1437
+ //
1331
1438
  // Keep this list empty. An entry here is a documented hole in the owner's
1332
1439
  // invariant, not a TODO: it means some process can be woken by something
1333
1440
  // this system does not mediate, and its next synchronous read can serve
@@ -1349,8 +1456,18 @@ const __fsMod = (() => {
1349
1456
  // envelope — there is no reason to invent a second surface for it.
1350
1457
  const _stats = globalThis.__nimbusVfsCoherence
1351
1458
  || (globalThis.__nimbusVfsCoherence = {
1352
- fills: 0, filledBytes: 0, invalidations: 0, poisons: 0,
1459
+ fills: 0, filledBytes: 0, invalidations: 0, poisons: 0, pushes: 0,
1353
1460
  reconciles: 0, selfWrites: 0, misses: 0,
1461
+ // ACQUIREs that got no answer (see _acquireBarrier), and the last reason.
1462
+ barrierFailures: 0, lastBarrierFailure: "",
1463
+ // Barriers that held their resumption on an own write's acknowledgement
1464
+ // (_awaitReportedOwnWrites).
1465
+ ownWriteWaits: 0,
1466
+ // The namespace's failure state (a relist failed): synchronous calls
1467
+ // refused with its cause (_nsRequire), and barriers that repaired it.
1468
+ namespaceRefusals: 0, namespaceRepairs: 0,
1469
+ // Repairs a delta from the store's durable floor answered, with no listing.
1470
+ floorRepairs: 0,
1354
1471
  });
1355
1472
 
1356
1473
  /**
@@ -1383,8 +1500,6 @@ const __fsMod = (() => {
1383
1500
  let evicted = false;
1384
1501
  delete __vfsBundleRevisions[k];
1385
1502
  if (__vfsBundle && k in __vfsBundle) { delete __vfsBundle[k]; evicted = true; }
1386
- const metadata = _metadataTable();
1387
- if (metadata && k in metadata) { delete metadata[k]; evicted = true; }
1388
1503
  return evicted;
1389
1504
  }
1390
1505
 
@@ -1399,15 +1514,107 @@ const __fsMod = (() => {
1399
1514
  const _owedRefetch = new Set();
1400
1515
 
1401
1516
  // An own-mutation lease can end in an eviction (a peer wrote inside the
1402
- // window). The ledger owning that decision is spliced AHEAD of this
1403
- // closure, so it is handed the one eviction path rather than keeping a
1404
- // second copy of it: content view, stat view, the invalidation count and
1405
- // the refetch debt move together here or not at all.
1406
- globalThis.__nimbusEvictResidentCell = (k) => {
1517
+ // window), and so can a flush whose revision a barrier's report outran.
1518
+ // The ledger owning those decisions is spliced AHEAD of this closure, so it
1519
+ // is handed the one eviction path rather than keeping a second copy of it:
1520
+ // content view, stat view, the invalidation count and the refetch debt
1521
+ // move together here or not at all.
1522
+ function _evictOwed(k) {
1407
1523
  if (!_evictResident(k)) return;
1408
1524
  _stats.invalidations++;
1409
1525
  _owedRefetch.add(k);
1410
- };
1526
+ }
1527
+ globalThis.__nimbusEvictResidentCell = _evictOwed;
1528
+
1529
+ /**
1530
+ * Live reads in flight, per path: each one's fill ticket, which carries
1531
+ * the highest revision a barrier reported for the path while that read was
1532
+ * outstanding.
1533
+ *
1534
+ * A barrier that reports a path nobody holds has nothing to evict and
1535
+ * CONSUMES the report: the cursor moves past it and no later delta names it
1536
+ * again. A read of that path already in flight may have been served before
1537
+ * the mutation the report describes, and its bytes would then be installed
1538
+ * behind the only message that could have evicted them. So the report is
1539
+ * kept on the read until it lands, and the read installs only if nothing
1540
+ * newer than its cursor was reported under it (_installResident).
1541
+ *
1542
+ * One ticket per read, not one per path: a read that begins after a report
1543
+ * or a poison is judged only by what is reported after it began. Sharing the
1544
+ * earlier read's record condemned the read issued to replace it.
1545
+ */
1546
+ const _fillReports = new Map();
1547
+
1548
+ /**
1549
+ * Begin a live read of `k`: the cursor it is issued under — every mutation
1550
+ * at or below it is already in the bytes it returns — and what has been
1551
+ * reported against it since, nothing yet. Called after the read's barrier
1552
+ * and before its RPC.
1553
+ */
1554
+ function _beginFill(k) {
1555
+ const fill = { k, rev: _cursor.rev, reported: -1 };
1556
+ let live = _fillReports.get(k);
1557
+ if (!live) {
1558
+ live = new Set();
1559
+ _fillReports.set(k, live);
1560
+ }
1561
+ live.add(fill);
1562
+ return fill;
1563
+ }
1564
+
1565
+ function _endFill(fill) {
1566
+ const live = _fillReports.get(fill.k);
1567
+ if (!live) return;
1568
+ live.delete(fill);
1569
+ if (live.size === 0) _fillReports.delete(fill.k);
1570
+ }
1571
+
1572
+ /** A barrier reported `k` at `rev`: remember it on every read of it in flight. */
1573
+ function _noteFillReport(k, rev) {
1574
+ const live = _fillReports.get(k);
1575
+ if (live) for (const fill of live) if (rev > fill.reported) fill.reported = rev;
1576
+ }
1577
+
1578
+ /**
1579
+ * Note one delta entry on everything in flight that it covers: its path,
1580
+ * or, for a subtree-scoped or structural entry, every path at or under it.
1581
+ * The ledger does the same for this facet's own writes and mutations.
1582
+ */
1583
+ function _noteReport(entry) {
1584
+ if (!entry.subtree && !entry.structural) {
1585
+ __nimbusNoteVfsReport(entry.path, entry.rev);
1586
+ _noteFillReport(entry.path, entry.rev);
1587
+ return;
1588
+ }
1589
+ __nimbusNoteVfsReportUnder(entry.path, entry.rev);
1590
+ const under = entry.path + "/";
1591
+ for (const k of [..._fillReports.keys()]) {
1592
+ if (k === entry.path || k.startsWith(under)) _noteFillReport(k, entry.rev);
1593
+ }
1594
+ }
1595
+
1596
+ /**
1597
+ * The resident cells a delta entry covers: its path, or, for a
1598
+ * subtree-scoped or structural entry, every cell at or under it. Such an
1599
+ * entry stands for changes it does not name (a directory that went, one
1600
+ * whose mode, owner or group changed, or something beneath it this facet
1601
+ * may not see), so each cell there is judged as a named one would be.
1602
+ */
1603
+ function _coveredCells(entry) {
1604
+ if (!entry.subtree && !entry.structural) return [entry.path];
1605
+ const under = entry.path + "/";
1606
+ const cells = new Set();
1607
+ for (const table of [__vfsBundle, __vfsBundleRevisions]) {
1608
+ if (!table) continue;
1609
+ for (const k of Object.keys(table)) if (k === entry.path || k.startsWith(under)) cells.add(k);
1610
+ }
1611
+ return [...cells];
1612
+ }
1613
+
1614
+ /** The cursor moved without a delta (a poison), so no read in flight can be dated. */
1615
+ function _spoilFills() {
1616
+ for (const live of _fillReports.values()) for (const fill of live) fill.reported = Infinity;
1617
+ }
1411
1618
 
1412
1619
  /**
1413
1620
  * Install bytes the supervisor just served as the resident cell for a
@@ -1421,42 +1628,30 @@ const __fsMod = (() => {
1421
1628
  * returned, so it has nothing to invalidate. The bytes are already paid
1422
1629
  * for; caching them costs one map insert.
1423
1630
  *
1631
+ * `fill` (_beginFill) dates them, and it is also the reason an install can
1632
+ * be declined: a barrier that reported the path above the read's cursor
1633
+ * while the read was in flight may describe a mutation the bytes predate,
1634
+ * and that report is gone once consumed. Declining costs the next sync
1635
+ * read a miss; installing would cost a stale byte nothing ever evicts.
1636
+ *
1424
1637
  * The parent's manifest entry gains the name too, so the existence view
1425
1638
  * cannot go on denying a file whose bytes this process is holding.
1426
1639
  */
1427
- function _installResident(absPath, bytes) {
1640
+ function _installResident(absPath, bytes, fill) {
1428
1641
  if (!__vfsBundle) return;
1429
1642
  const k = _strip(absPath);
1430
1643
  if (k === "") return;
1644
+ if (fill.reported > fill.rev) return;
1431
1645
  // Never over a cell this facet owns.
1432
1646
  //
1433
1647
  // A pending write is strictly newer than anything the authority can
1434
1648
  // report, and __vfsBundle is what sync reads consult first, so installing
1435
1649
  // over it would serve the program bytes older than its own write.
1436
- //
1437
- // A STAMPED cell is this facet's own flushed write, and the barrier this
1438
- // read passed on the way in reported nobody else has touched the path
1439
- // since — so the bytes are already what is being installed, and the only
1440
- // thing the install would change is to drop the stamp. It did: a
1441
- // speculative repair issued by an earlier refused read landed after the
1442
- // flush, unstamped the cell, and the next ACQUIRE evicted the facet's own
1443
- // output. Measured at selfWrites 0 / invalidations 1 / fills 2 for one
1444
- // written file, against 1 / 0 / 0 with the repair absent.
1445
1650
  if (__vfsWrites && k in __vfsWrites) return;
1446
- if (__vfsBundleRevisions[k] !== undefined) return;
1447
- __vfsBundle[k] = bytes;
1448
- // Keep the stat view consistent with the bytes now held. Without this
1449
- // the content view is fresh while statSync still reports the
1450
- // spawn-time length, so a program can read N bytes and be told the
1451
- // file is M — an inconsistency introduced BY the fill. Only the size
1452
- // is corrected: type, mode, ownership and timestamps stay as the
1453
- // authority last reported them, so mtime-based change detection
1454
- // (make, tsc --build, watchers) does not see every read as a change.
1455
- const metadata = _metadataTable();
1456
- if (metadata && k in metadata) {
1457
- metadata[k] = { ...metadata[k], size: _byteLen(bytes) };
1458
- }
1459
- _announceSyncPath(k);
1651
+ // The store dates the row at the read's cursor, so the next delta that
1652
+ // names the path above it evicts it. It declines, itself, to replace own
1653
+ // bytes or a row dated later than this read can vouch for.
1654
+ if (!__residentFill(k, bytes, fill.rev)) return;
1460
1655
  _stats.fills++;
1461
1656
  _stats.filledBytes += _byteLen(bytes);
1462
1657
  }
@@ -1492,25 +1687,86 @@ const __fsMod = (() => {
1492
1687
  return _residentRepair;
1493
1688
  }
1494
1689
 
1690
+ /**
1691
+ * Set while the store holds only what a repair could NOT vouch for: rows it
1692
+ * had to drop rather than prove current. Nothing but another repair brings
1693
+ * those back — a delta names what changed, not what this facet lost — so
1694
+ * every barrier repairs until one vouches, however the ACQUIRE is answered.
1695
+ */
1696
+ let _storeRepairOwed = false;
1697
+
1698
+ /**
1699
+ * The repair's first try: the delta from the store's durable floor
1700
+ * (__residentCursor), asked as every barrier asks it. True when it applied
1701
+ * (the repair is done); false when a listing is needed after all.
1702
+ */
1703
+ async function _repairFromFloor(supervisor, result) {
1704
+ if (!supervisor || typeof supervisor.fsAcquire !== "function" || !_nsActive()) return false;
1705
+ if (result !== null && result.poison === true) return false;
1706
+ const floor = __residentCursor();
1707
+ if (floor === null || (result !== null && result.epoch !== floor.epoch)) return false;
1708
+ let delta;
1709
+ try {
1710
+ delta = await __nimbusUseRpcResult(supervisor.fsAcquire(floor.epoch, floor.rev, { namespace: true }), (r) => r);
1711
+ } catch { return false; }
1712
+ if (!delta || delta.poison === true || typeof delta.rev !== "number" || delta.epoch !== floor.epoch) return false;
1713
+ if (Array.isArray(delta.paths)) for (const entry of delta.paths) _noteReport(entry);
1714
+ await __residentRoomForPushed(delta);
1715
+ const applied = __residentAdmit(delta);
1716
+ for (const dir of applied.relist) await __nsRelist(supervisor, dir);
1717
+ if (!_nsActive()) return false;
1718
+ _cursor.epoch = applied.cursor.epoch;
1719
+ _cursor.rev = applied.cursor.rev;
1720
+ _stats.invalidations += applied.dropped.length;
1721
+ // What it should hold and lost (dropped by this delta, or by the barrier
1722
+ // that could not vouch for its rows), refetched by the namespace's stats.
1723
+ const refilled = await __residentRefillFromNamespace(supervisor, applied.dropped);
1724
+ _stats.fills += refilled.filled;
1725
+ _stats.filledBytes += refilled.bytes;
1726
+ _stats.floorRepairs++;
1727
+ _storeRepairOwed = false;
1728
+ return true;
1729
+ }
1730
+
1731
+ /**
1732
+ * `result` is the ACQUIRE answer that asked for the repair: a poison, a
1733
+ * delta arriving while a repair is owed, or null for a barrier that got no
1734
+ * answer at all.
1735
+ */
1495
1736
  async function _runResidentRepair(supervisor, result) {
1737
+ // Within one epoch, with the change log intact and the namespace
1738
+ // answering, the store's rows are dated through its own durable cursor, so
1739
+ // the delta from there names everything that moved since. Only an epoch
1740
+ // change, a poison (the log truncated past the cursor), or a namespace
1741
+ // that stopped answering needs the listing.
1742
+ if (await _repairFromFloor(supervisor, result)) return;
1743
+ const ownAtStart = __residentOwnPaths();
1496
1744
  let repaired;
1497
1745
  try { repaired = await __residentSynchronizeFromSupervisor(supervisor); }
1498
1746
  catch { repaired = null; }
1499
1747
  if (!repaired || !repaired.cursor) {
1500
1748
  // The pass could not vouch for a single row — a supervisor replaced
1501
- // mid-enumeration, an enumeration that came back short. A row that
1502
- // cannot be dated must not be served, so the cold cache the poison asked
1503
- // for is taken after all, and the pass runs once more to repopulate what
1504
- // it just dropped.
1505
- __residentAdmit(result);
1506
- _cursor.epoch = result.epoch;
1507
- _cursor.rev = result.rev;
1749
+ // mid-enumeration, an enumeration that came back short, an authority it
1750
+ // could not reach. A row that cannot be dated must not be served, so the
1751
+ // cold cache is taken after all, and the pass runs once more to
1752
+ // repopulate what it just dropped. An answer with a cursor is admitted as
1753
+ // it would have been; a barrier with no answer drops every dated row and
1754
+ // keeps the cursor it had, which the next delta is still owed from.
1755
+ if (result) {
1756
+ __residentAdmit(result);
1757
+ _cursor.epoch = result.epoch;
1758
+ _cursor.rev = result.rev;
1759
+ } else {
1760
+ __residentDropDated();
1761
+ }
1508
1762
  try { repaired = await __residentSynchronizeFromSupervisor(supervisor); }
1509
1763
  catch { repaired = null; }
1510
1764
  } else if (repaired.reconciled) {
1511
1765
  _stats.reconciles++;
1512
1766
  }
1513
- if (!repaired || !repaired.cursor) return;
1767
+ _settleSkippedReports(ownAtStart, repaired);
1768
+ _storeRepairOwed = !(repaired && repaired.cursor);
1769
+ if (_storeRepairOwed) return;
1514
1770
  _cursor.epoch = repaired.cursor.epoch;
1515
1771
  _cursor.rev = repaired.cursor.rev;
1516
1772
  _stats.invalidations += repaired.dropped;
@@ -1518,6 +1774,41 @@ const __fsMod = (() => {
1518
1774
  _stats.filledBytes += repaired.bytes;
1519
1775
  }
1520
1776
 
1777
+ /**
1778
+ * Deliver the reports a repair moved the cursor over.
1779
+ *
1780
+ * A repair moves the cursor without a delta, so what a delta would have
1781
+ * reported reaches nothing on its own. A dated row the pass kept is proven
1782
+ * current by its listed revision and needs nothing more. A row of this
1783
+ * facet's own bytes is kept whatever the listing says — and its report is
1784
+ * exactly what the write or mutation that owns it needs, to judge its own
1785
+ * acknowledgement against. The pass hands those back (`own`), and they are
1786
+ * noted here as a delta's would have been; one acknowledged since the pass
1787
+ * looked was dated by a receipt that could not see the report, so it is
1788
+ * judged here directly.
1789
+ *
1790
+ * With nothing datable — across incarnations, against a short listing, or
1791
+ * a pass that failed outright — every own row, and every row that was own
1792
+ * when the repair began, is judged as though a peer wrote it last: an
1793
+ * eviction and a refetch, never a stale byte.
1794
+ */
1795
+ function _settleSkippedReports(ownAtStart, repaired) {
1796
+ const reports = new Map();
1797
+ if (repaired && repaired.cursor && repaired.reconciled && Array.isArray(repaired.own)) {
1798
+ for (const entry of repaired.own) reports.set(entry.path, entry.rev);
1799
+ } else {
1800
+ for (const k of ownAtStart) reports.set(k, Infinity);
1801
+ if (repaired && Array.isArray(repaired.own)) for (const entry of repaired.own) reports.set(entry.path, Infinity);
1802
+ for (const k of Object.keys(__vfsOwnLeases)) reports.set(k, Infinity);
1803
+ for (const k of Object.keys(__vfsWrites)) reports.set(k, Infinity);
1804
+ }
1805
+ for (const [k, rev] of reports) {
1806
+ __nimbusNoteVfsReport(k, rev);
1807
+ const provenance = __residentProvenance(k);
1808
+ if (provenance !== undefined && provenance !== -1 && provenance < rev) _evictOwed(k);
1809
+ }
1810
+ }
1811
+
1521
1812
  /**
1522
1813
  * ACQUIRE. Apply every invalidation the supervisor has for this facet,
1523
1814
  * then re-stamp the cursor.
@@ -1543,65 +1834,247 @@ const __fsMod = (() => {
1543
1834
  * left. Comparing revisions rather than names keeps the peer case intact:
1544
1835
  * a peer writing the same path afterwards reports a HIGHER revision than
1545
1836
  * our stamp, so that invalidation still lands.
1837
+ *
1838
+ * An ACQUIRE that gets no answer is a poison too, never an empty delta. It
1839
+ * has learned nothing about what changed, and the resumption behind it is
1840
+ * about to serve every row it holds. The call is a pure read, so a dropped
1841
+ * one is already retried where the supervisor makes it (SupervisorRPC,
1842
+ * fabric's idempotent), and what arrives here failed those retries, came
1843
+ * from a host that could not serve it, or answered without a cursor. The
1844
+ * rows are repaired against the listing exactly as for a poison; with no
1845
+ * cursor to adopt, the one held is kept and still owed every change since.
1846
+ * The barrier itself never throws: the operation or callback behind it
1847
+ * runs either way, against rows that were vouched for or a colder cache.
1848
+ *
1849
+ * A repair is single-flight, and while one runs no delta may be admitted
1850
+ * at all: the repair has already dropped the rows it could not vouch for,
1851
+ * so a report of one of them finds nothing to evict and is consumed, and
1852
+ * the repair then installs it at its listing's revision and publishes the
1853
+ * listing's cursor over the one the delta advanced. So any barrier answered
1854
+ * while a repair runs joins it, whether its own answer needed a repair or
1855
+ * was an ordinary delta, and the listing may predate that answer — the rows
1856
+ * it vouches for are another barrier's answer, not this one's — so a joiner
1857
+ * waits for it and then asks again: a delta from the repaired cursor names
1858
+ * everything since. Only the barrier that started a repair resumes on it
1859
+ * alone.
1860
+ *
1861
+ * `delivered` is an answer the supervisor delivered with the resumption
1862
+ * this barrier is taken for; it stands in for the first ACQUIRE when it can
1863
+ * (_deliveredAnswer). Everything after is the same for an answer delivered
1864
+ * and one asked for, so a repair, a join or a poison follows exactly the
1865
+ * path it always has.
1866
+ *
1867
+ * Last, the barrier waits out every own write or mutation that a report —
1868
+ * this answer's or an earlier one's — is outstanding against, until its
1869
+ * acknowledgement says which came first (__nimbusReportedOwnAcknowledgements).
1870
+ * Until then the resumption could run on own bytes the authority applied
1871
+ * before a peer overwrote them. Nothing is waited on unless such a report
1872
+ * exists.
1546
1873
  */
1547
- async function _acquireBarrier(supervisor) {
1874
+ async function _acquireBarrier(supervisor, delivered) {
1548
1875
  if (!supervisor || typeof supervisor.fsAcquire !== "function") return [];
1549
- let result;
1550
- // Through the RPC helper like every other supervisor call, because it IS
1551
- // one: the barrier is the first thing an async read issues, and while it
1552
- // was uncounted __nimbusPendingOps read zero for a whole round trip. A
1553
- // one-shot facet's event loop, which exits when no handle is live, then
1554
- // ended the program mid-read — measured as an fs.promises.readFile whose
1555
- // .then never ran, no error, no output, intermittently, and never when a
1556
- // pending timer happened to hold the program open.
1557
- try { result = await __nimbusUseRpcResult(supervisor.fsAcquire(_cursor.epoch, _cursor.rev), (r) => r); }
1558
- catch { return []; }
1559
- if (!result || typeof result.rev !== "number") return [];
1560
- // Paths that held content before this eviction are the ones worth
1561
- // refetching at a resumption boundary — a later sync read of any of them
1562
- // would otherwise miss. Collected before the delete so the membership
1563
- // test is against the pre-eviction bundle.
1564
- const wereResident = [];
1876
+ const fromDelivery = _deliveredAnswer(delivered);
1877
+ // The overlay of this facet's own structural effects retires what settled
1878
+ // before the answer was asked for: a delivered answer was asked for when
1879
+ // its arguments were built, a fetched one now.
1880
+ const begin = fromDelivery ? _argsBegin(delivered.args) : ++_barrierBegins;
1881
+ let result = fromDelivery || await _acquire(supervisor);
1565
1882
  // When the resident set lives in the facet's own SQLite, the STORE applies
1566
1883
  // the delta. That is not an optimisation, it is where provenance has to
1567
1884
  // live: a facet's SQLite outlives its module scope, so a new incarnation
1568
1885
  // opens onto rows a previous one wrote while every heap-side stamp that
1569
1886
  // described them is gone. Rows carry their own revision, __vfsBundleRevisions
1570
1887
  // cannot follow them there, and two provenance stores would be one too many.
1571
- if (_residentStorePresent()) {
1572
- if (result.poison) {
1573
- _stats.poisons++;
1574
- await _repairPoisonedStore(supervisor, result);
1575
- // Nothing is returned because a dropped cell is either refetched by
1576
- // the repair or gone from the authority too.
1577
- return [];
1888
+ {
1889
+ // A namespace that stopped answering (a relist failed) is a failure
1890
+ // state, not a mode: every barrier the process reaches repairs it, once,
1891
+ // until a listing restores it.
1892
+ let namespaceAsked = false;
1893
+ for (let joins = 0; ; joins++) {
1894
+ const joining = _residentRepair !== null;
1895
+ const namespaceOwed = !namespaceAsked && !_nsActive();
1896
+ // A sealed heap view can release acknowledged overlays before its
1897
+ // listing; otherwise the old overlay and replacement rows would
1898
+ // consume the same scarce allowance while preventing each other's
1899
+ // repair. Nothing synchronous may consult the sealed view here.
1900
+ if (namespaceOwed && __residentInHeap) _nsRetire(begin);
1901
+ const needsRepair = result === null || result.poison === true || _storeRepairOwed || namespaceOwed;
1902
+ if (!joining && !needsRepair) break;
1903
+ if (namespaceOwed) { namespaceAsked = true; _stats.namespaceRepairs++; }
1904
+ if (needsRepair) {
1905
+ if (result !== null && result.poison === true) _stats.poisons++;
1906
+ _spoilFills();
1907
+ }
1908
+ await (joining ? _residentRepair : _repairPoisonedStore(supervisor, result));
1909
+ // A repair's listing is walked page by page at successive revisions,
1910
+ // so even the barrier that started it asks once more: the delta from
1911
+ // the listing's cursor leaves the namespace exact. Unanswered, it
1912
+ // resumes on the repair's rows as they are, which the listing vouched
1913
+ // for; the namespace then waits for the next barrier.
1914
+ if (!joining) {
1915
+ if (_storeRepairOwed) return [];
1916
+ result = await _acquire(supervisor);
1917
+ if (result === null || result.poison === true) { _nsRetire(begin); return []; }
1918
+ continue;
1919
+ }
1920
+ if (joins + 1 >= _REPAIR_JOINS_MAX) {
1921
+ // Every repair this barrier waited on was someone else's. Rather
1922
+ // than resume on rows none of them vouched for as of its own
1923
+ // answer, it drops them and leaves the repair owed: a colder cache,
1924
+ // never a stale byte. Any repair still to finish lists after this.
1925
+ __residentDropDated();
1926
+ _storeRepairOwed = true;
1927
+ __nimbusNoteUnnamedReports();
1928
+ await _awaitReportedOwnWrites();
1929
+ return [];
1930
+ }
1931
+ result = await _acquire(supervisor);
1932
+ }
1933
+ // The store keeps a row of this facet's own bytes over any report, so
1934
+ // the report is noted first: the write or mutation that owns the row
1935
+ // judges it against its own revision when that arrives, as it does for
1936
+ // a heap cell. A read in flight gets the same note.
1937
+ if (Array.isArray(result.paths)) {
1938
+ for (const entry of result.paths) _noteReport(entry);
1578
1939
  }
1940
+ // N18: room for what it pushes, before it is held.
1941
+ await __residentRoomForPushed(result);
1579
1942
  const applied = __residentAdmit(result);
1580
- _cursor.epoch = result.epoch;
1581
- _cursor.rev = result.rev;
1943
+ _cursor.epoch = applied.cursor.epoch;
1944
+ _cursor.rev = applied.cursor.rev;
1945
+ // A directory that became searchable has descendants no delta names.
1946
+ for (const dir of applied.relist) await __nsRelist(supervisor, dir);
1947
+ _nsRetire(begin);
1582
1948
  _stats.invalidations += applied.dropped.length;
1949
+ _stats.selfWrites += applied.kept;
1950
+ _stats.pushes += applied.pushed || 0;
1951
+ await _awaitReportedOwnWrites();
1583
1952
  return applied.dropped;
1584
1953
  }
1585
- if (result.poison) {
1586
- if (__vfsBundle) for (const k of Object.keys(__vfsBundle)) { wereResident.push(k); _evictResident(k); }
1587
- _stats.poisons++;
1588
- } else if (Array.isArray(result.paths)) {
1589
- for (const entry of result.paths) {
1590
- const k = entry.path;
1591
- // This cursor is about to advance past the report, so a path with
1592
- // one of this facet's own writes in flight keeps the number: only
1593
- // that write's own revision, when it arrives, can say whether the
1594
- // report was itself or a peer. Everything else ignores it.
1595
- __nimbusNoteVfsReport(k, entry.rev);
1596
- if (__vfsBundleRevisions[k] >= entry.rev) { _stats.selfWrites++; continue; }
1597
- const held = !!(__vfsBundle && k in __vfsBundle);
1598
- if (_evictResident(k)) _stats.invalidations++;
1599
- if (held) wereResident.push(k);
1954
+ }
1955
+
1956
+ /**
1957
+ * Hold the resumption behind a barrier on every own write or mutation a
1958
+ * report is outstanding against, until its acknowledgement says which came
1959
+ * first (__nimbusReportedOwnAcknowledgements). Counted, because the wait is
1960
+ * also paid when the report was the write itself coming back, which the
1961
+ * facet cannot tell apart until the acknowledgement lands.
1962
+ */
1963
+ async function _awaitReportedOwnWrites() {
1964
+ const acks = __nimbusReportedOwnAcknowledgements();
1965
+ if (acks === null) return;
1966
+ _stats.ownWriteWaits++;
1967
+ await acks;
1968
+ }
1969
+
1970
+ /**
1971
+ * Repairs someone else started that one barrier waits on, in a row, before
1972
+ * it stops asking again and drops what it cannot vouch for. A bound on the
1973
+ * barrier's own liveness, not a tuning knob: each join waits a whole repair,
1974
+ * so the fourth means repairs keep being started under it.
1975
+ */
1976
+ const _REPAIR_JOINS_MAX = 4;
1977
+
1978
+ /**
1979
+ * What this facet asks its ACQUIRE with: its cursor. Built in one place, so
1980
+ * what a delivery is answered from (a long poll sends these,
1981
+ * `__nimbusVfsAcquireArgs`) is exactly what fsAcquire would be asked.
1982
+ */
1983
+ function _acquireArgs() {
1984
+ // Every build is the start of an answer the overlay may retire against.
1985
+ const begin = ++_barrierBegins;
1986
+ const key = _cursor.epoch + "@" + _cursor.rev;
1987
+ if (!_argsBegins.has(key)) _argsBegins.set(key, begin);
1988
+ const options = _residentStorePresent() && typeof __residentAcquireOptions === "function"
1989
+ ? __residentAcquireOptions() : undefined;
1990
+ return options
1991
+ ? { epoch: _cursor.epoch, cursor: _cursor.rev, options }
1992
+ : { epoch: _cursor.epoch, cursor: _cursor.rev };
1993
+ }
1994
+ /**
1995
+ * The earliest begin of any arguments built at a cursor: a delivered answer
1996
+ * may answer any of them, and retiring against the earliest is the one
1997
+ * that is never too late. Cursors left behind are forgotten.
1998
+ */
1999
+ const _argsBegins = new Map();
2000
+ function _argsBegin(args) {
2001
+ const key = args.epoch + "@" + args.cursor;
2002
+ const begin = _argsBegins.get(key) ?? 0;
2003
+ for (const k of [..._argsBegins.keys()]) {
2004
+ const [epoch, rev] = [k.slice(0, k.lastIndexOf("@")), Number(k.slice(k.lastIndexOf("@") + 1))];
2005
+ if (epoch !== _cursor.epoch || rev < _cursor.rev) _argsBegins.delete(k);
2006
+ }
2007
+ return begin;
2008
+ }
2009
+
2010
+ /**
2011
+ * One ACQUIRE: the authority's answer, or null when there is none — the
2012
+ * call failed past the supervisor's own retries, the host could not serve
2013
+ * it, or the answer carried no cursor. A null is counted where the
2014
+ * coherence stats are read, and is never an empty delta (_acquireBarrier).
2015
+ */
2016
+ async function _acquire(supervisor) {
2017
+ // Through the RPC helper like every other supervisor call, because it IS
2018
+ // one: the barrier is the first thing an async read issues, and while it
2019
+ // was uncounted __nimbusPendingOps read zero for a whole round trip. A
2020
+ // one-shot facet's event loop, which exits when no handle is live, then
2021
+ // ended the program mid-read — measured as an fs.promises.readFile whose
2022
+ // .then never ran, no error, no output, intermittently, and never when a
2023
+ // pending timer happened to hold the program open.
2024
+ try {
2025
+ const args = _acquireArgs();
2026
+ const result = await __nimbusUseRpcResult(
2027
+ args.options ? supervisor.fsAcquire(args.epoch, args.cursor, args.options) : supervisor.fsAcquire(args.epoch, args.cursor),
2028
+ (r) => r,
2029
+ );
2030
+ if (!result || typeof result.rev !== "number" || typeof result.epoch !== "string") {
2031
+ throw new Error("fsAcquire answered without a cursor");
1600
2032
  }
2033
+ return _currentAnswer(result);
2034
+ } catch (error) {
2035
+ _stats.barrierFailures++;
2036
+ _stats.lastBarrierFailure = (error && error.message) || String(error);
2037
+ return null;
1601
2038
  }
1602
- _cursor.epoch = result.epoch;
1603
- _cursor.rev = result.rev;
1604
- return wereResident;
2039
+ }
2040
+
2041
+ /**
2042
+ * An answer as it stands against this facet's cursor now.
2043
+ *
2044
+ * Answers can be admitted in another order than they were given: an
2045
+ * answer a long poll delivers was asked for before the barrier that
2046
+ * overtook it. Everything at or below the cursor is admitted already, by
2047
+ * whichever answer took the cursor past it — an answer is complete from
2048
+ * the cursor it was asked from, which is never ahead of the cursor now, and
2049
+ * names each path at its newest revision in its range. So only the entries
2050
+ * above the cursor are news, and the cursor never moves back. An answer in
2051
+ * another epoch, or a poison, is left as it is.
2052
+ */
2053
+ function _currentAnswer(result) {
2054
+ if (result.poison === true || result.epoch !== _cursor.epoch) return result;
2055
+ if (result.rev <= _cursor.rev) return { ...result, rev: _cursor.rev, paths: [] };
2056
+ const paths = result.paths.filter((entry) => entry.rev > _cursor.rev);
2057
+ return paths.length === result.paths.length ? result : { ...result, paths };
2058
+ }
2059
+
2060
+ /**
2061
+ * The answer a delivery carried (session/rpc.ts _acquireOnDelivery), as it
2062
+ * stands against the cursor now, or null when it cannot stand in for
2063
+ * asking. It can when it answers from a cursor this facet has reached, in
2064
+ * this epoch: everything at or below that cursor is admitted, and the
2065
+ * answer names everything after it up to the moment of delivery. The
2066
+ * barrier asks, as it always has, when there is no answer or it is a
2067
+ * poison, in another epoch, or from a cursor this facet has not reached — a
2068
+ * routed request is answered from the supervisor's own cursor, "nothing
2069
+ * since now", which stands in only for a facet that is already there.
2070
+ */
2071
+ function _deliveredAnswer(delivered) {
2072
+ if (!delivered || typeof delivered !== "object") return null;
2073
+ const { args, answer } = delivered;
2074
+ if (!args || !answer || answer.poison === true || !Array.isArray(answer.paths)) return null;
2075
+ if (typeof answer.rev !== "number" || answer.epoch !== _cursor.epoch || args.epoch !== _cursor.epoch) return null;
2076
+ if (!(args.cursor <= _cursor.rev)) return null;
2077
+ return _currentAnswer(answer);
1605
2078
  }
1606
2079
 
1607
2080
  /**
@@ -1623,9 +2096,22 @@ const __fsMod = (() => {
1623
2096
  * This closes staleness of RESIDENT cells across an untrusted resumption.
1624
2097
  * A first synchronous touch of a NON-resident path is the separate
1625
2098
  * residency floor and is unaffected — it still raises EAGAIN, correctly.
2099
+ *
2100
+ * Two resumptions can barrier at once — a child's output and its exit
2101
+ * arrive together — and both deltas name the same changed path. The first
2102
+ * to land evicts it and starts the refetch; the second finds no row and
2103
+ * would release its callback while that refetch is still in flight, onto
2104
+ * a miss. So a barrier also waits for every refetch still in flight.
2105
+ * It does not read those paths again. A refetch in flight installs its
2106
+ * bytes unless a barrier has since reported the path above the cursor it
2107
+ * was issued under, or a poison spoiled it (_installResident). Only then
2108
+ * does a later barrier read the path itself, and only if nothing holds it
2109
+ * by now. Re-reading every in-flight path at every resumption cost a dev
2110
+ * server 50 reads per request while a peer's refetch of 50 files ran: 500
2111
+ * reads over ten resumptions, and under steady load the set never drained.
1626
2112
  */
1627
- async function _acquireAndRefetch(supervisor) {
1628
- const stale = await _acquireBarrier(supervisor);
2113
+ async function _acquireAndRefetch(supervisor, delivered) {
2114
+ const stale = await _acquireBarrier(supervisor, delivered);
1629
2115
  // Plus what an own-mutation lease dropped since the last resumption:
1630
2116
  // the same debt this function exists to settle, owed by an eviction
1631
2117
  // that had no barrier to report it (see _owedRefetch).
@@ -1633,8 +2119,58 @@ const __fsMod = (() => {
1633
2119
  for (const k of _owedRefetch) if (stale.indexOf(k) === -1) stale.push(k);
1634
2120
  _owedRefetch.clear();
1635
2121
  }
1636
- if (stale.length === 0) return;
1637
- await Promise.all(stale.map((k) => _liveReadFile("/" + k, undefined, true).catch(() => {})));
2122
+ // Taken before this barrier's own refetches join the map.
2123
+ const inFlight = [..._refetching];
2124
+ const reads = stale.map(_refetch);
2125
+ for (const [k, refetch] of inFlight) {
2126
+ if (stale.indexOf(k) !== -1) continue;
2127
+ if (!(refetch.fill.reported > refetch.fill.rev)) reads.push(refetch.done);
2128
+ else if (!(__vfsBundle && k in __vfsBundle)) reads.push(_refetch(k));
2129
+ }
2130
+ if (reads.length > 0) await Promise.all(reads);
2131
+ }
2132
+
2133
+ /**
2134
+ * Refetches in flight, per path: the newest read of it, and the fill
2135
+ * ticket that read installs under — the cursor it was issued at, and the
2136
+ * reports noted against it since.
2137
+ */
2138
+ const _refetching = new Map();
2139
+
2140
+ /**
2141
+ * Read `k` live and install it, behind the barrier just taken. Settles
2142
+ * either way: a refetch that fails leaves the path missing, which the next
2143
+ * read of it answers.
2144
+ *
2145
+ * `read` settles once this read has landed and its install was made or
2146
+ * declined. `done`, which the resumptions wait on, may wait once more. An
2147
+ * install is declined when a barrier reported the path above this read's
2148
+ * cursor, or a poison spoiled it, and settling there would release every
2149
+ * waiter onto the miss it left while something else is already filling
2150
+ * the path: the newer refetch a barrier issued to replace this one, or the
2151
+ * repair that poison started. So `done` waits on what is in flight at the
2152
+ * moment this read settles, that refetch's own read and install and that
2153
+ * repair, and then settles whether or not the path is held. It never
2154
+ * follows a refetch issued after that. A peer that rewrites the path
2155
+ * faster than one read round trip outdates every refetch with the next
2156
+ * resumption's report, and following them held every resumption, including
2157
+ * those that never read the path, until the writer stopped (1528 ms against
2158
+ * 33 ms). A path left unheld is read live by its next read.
2159
+ */
2160
+ function _refetch(k) {
2161
+ const fill = _beginFill(k);
2162
+ const refetch = { fill, read: null, done: null };
2163
+ refetch.read = _liveReadFile("/" + k, undefined, fill).then(() => {}, () => {}).then(() => {
2164
+ _endFill(fill);
2165
+ if (_refetching.get(k) === refetch) _refetching.delete(k);
2166
+ });
2167
+ refetch.done = refetch.read.then(() => {
2168
+ if (__vfsBundle && k in __vfsBundle) return undefined;
2169
+ const newer = _refetching.get(k);
2170
+ return Promise.all([newer && newer.read, _residentRepair]);
2171
+ });
2172
+ _refetching.set(k, refetch);
2173
+ return refetch.done;
1638
2174
  }
1639
2175
 
1640
2176
  /**
@@ -1646,14 +2182,15 @@ const __fsMod = (() => {
1646
2182
  * its fetch handler; binding the supervisor when the wrappers are
1647
2183
  * installed would silently leave every resident-TUI timer unbarriered.
1648
2184
  *
1649
- * Published on globalThis because the two other untrusted resumptions —
1650
- * an outbound fetch response and a relayed socket frame — are delivered
1651
- * by code outside this closure. One barrier, three boundaries.
2185
+ * Published on globalThis because the other resumptions — an outbound
2186
+ * fetch response, a relayed socket frame, and everything the supervisor
2187
+ * delivers (`__nimbusInboundBarrier`, with the answer it delivered) — are
2188
+ * handed to the program by code outside this closure.
1652
2189
  */
1653
- async function _resumptionAcquire() {
2190
+ async function _resumptionAcquire(delivered) {
1654
2191
  const supervisor = _supervisor();
1655
2192
  if (!supervisor || typeof supervisor.fsAcquire !== "function") return;
1656
- await _acquireAndRefetch(supervisor);
2193
+ await _acquireAndRefetch(supervisor, delivered);
1657
2194
  }
1658
2195
 
1659
2196
  /**
@@ -1687,6 +2224,7 @@ const __fsMod = (() => {
1687
2224
  if (globalThis.__nimbusResumptionBarriersInstalled) return;
1688
2225
  globalThis.__nimbusResumptionBarriersInstalled = true;
1689
2226
  globalThis.__nimbusVfsAcquireBarrier = _resumptionAcquire;
2227
+ globalThis.__nimbusVfsAcquireArgs = _acquireArgs;
1690
2228
  globalThis.__nimbusVfsReleaseBarrier = _resumptionRelease;
1691
2229
  const _setTimeout = globalThis.setTimeout;
1692
2230
  const _setInterval = globalThis.setInterval;
@@ -1794,8 +2332,9 @@ const __fsMod = (() => {
1794
2332
  // `method` names the supervisor RPC when it differs from the syscall the
1795
2333
  // caller reports (lchown rides `chown`, rm rides `fsRemove`).
1796
2334
  function _queueStructuralMutation(absPath, syscall, displayPath, rpc, after, method) {
2335
+ const settle = _nsTakeFresh();
1797
2336
  const supervisor = _supervisor();
1798
- if (!supervisor || typeof supervisor[method || syscall] !== "function") return null;
2337
+ if (!supervisor || typeof supervisor[method || syscall] !== "function") { settle(); return null; }
1799
2338
  const queued = _hasVfsMutationQueue();
1800
2339
  const before = queued && after ? after() : null;
1801
2340
  const run = async () => {
@@ -1811,7 +2350,11 @@ const __fsMod = (() => {
1811
2350
  );
1812
2351
  _markVfsStale();
1813
2352
  };
1814
- return queued ? __nimbusQueueVfsMutation(absPath, run) : run();
2353
+ const out = queued ? __nimbusQueueVfsMutation(absPath, run) : run();
2354
+ // Settled either way: a failed mutation leaves the authority as it was,
2355
+ // which the next barrier's table shows.
2356
+ Promise.resolve(out).then(settle, settle);
2357
+ return out;
1815
2358
  }
1816
2359
 
1817
2360
  /**
@@ -1824,25 +2367,33 @@ const __fsMod = (() => {
1824
2367
  * effect while the lease still holds the cell, so the stamp the end
1825
2368
  * settles describes a cell that already carries the mutation.
1826
2369
  *
1827
- * Heap-side stamps do not describe rows in the resident store, so store
1828
- * mode has no lease to take and is left to the store's own provenance.
2370
+ * The ledger takes the lease on whichever holds the stamp: a heap stamp,
2371
+ * or the resident store's row. Without it a store row the mutation
2372
+ * overlaid would be left as own bytes nobody ever dates, which the barrier
2373
+ * keeps against every later write by anyone.
2374
+ *
2375
+ * From lease to receipt it is an acknowledgement in flight
2376
+ * (__nimbusOwnAcknowledgement): a barrier that reports the path waits for
2377
+ * it, rather than resume on bytes the receipt may yet show a peer outran.
1829
2378
  */
1830
- async function _ownMutation(absPath, rpc, apply) {
2379
+ function _ownMutation(absPath, rpc, apply) {
1831
2380
  const key = _strip(absPath);
1832
- const held = !_residentStorePresent() && __nimbusBeginOwnMutation(key);
1833
- let receipt;
1834
- let landed = false;
1835
- try { receipt = await rpc(); landed = true; }
1836
- finally {
1837
- // The local effect follows the mutation landing, not the receipt: the
1838
- // receipt only settles the stamp, and a supervisor that answers
1839
- // without one still applied the bytes. The end runs even if applying
1840
- // throws: a lease left open pins its cell at Infinity, which is the one
1841
- // state in this protocol that can serve a stale byte forever.
1842
- try { if (landed && apply) apply(receipt); }
1843
- finally { __nimbusEndOwnMutation(key, held, receipt); }
1844
- }
1845
- return receipt;
2381
+ return __nimbusOwnAcknowledgement(key, async () => {
2382
+ const held = __nimbusBeginOwnMutation(key);
2383
+ let receipt;
2384
+ let landed = false;
2385
+ try { receipt = await rpc(); landed = true; }
2386
+ finally {
2387
+ // The local effect follows the mutation landing, not the receipt: the
2388
+ // receipt only settles the stamp, and a supervisor that answers
2389
+ // without one still applied the bytes. The end runs even if applying
2390
+ // throws: a lease left open pins its cell at Infinity, which is the one
2391
+ // state in this protocol that can serve a stale byte forever.
2392
+ try { if (landed && apply) apply(receipt); }
2393
+ finally { __nimbusEndOwnMutation(key, held, receipt); }
2394
+ }
2395
+ return receipt;
2396
+ });
1846
2397
  }
1847
2398
 
1848
2399
  // A sync caller has no frame to receive the outcome. The ledger already
@@ -1877,6 +2428,8 @@ const __fsMod = (() => {
1877
2428
  "write", absPath,
1878
2429
  (result) => result,
1879
2430
  ),
2431
+ true,
2432
+ true,
1880
2433
  );
1881
2434
  }
1882
2435
 
@@ -1887,13 +2440,18 @@ const __fsMod = (() => {
1887
2440
  await _flushParkedWrite(absPath, supervisor);
1888
2441
  _markVfsStale();
1889
2442
  }
1890
- // Pending sync chmod rides along with any flush of the same path
1891
- // (idempotent — the entry stays so local statSync remains coherent).
1892
- if (k in _localModes && typeof supervisor.chmod === "function") {
1893
- await _ownMutation(
1894
- absPath,
1895
- () => _fsRpc(supervisor.chmod(absPath, _localModes[k]), "chmod", absPath, (result) => result),
1896
- );
2443
+ // A pending sync chmod rides along with the next flush of the same path.
2444
+ if (_pendingModes.has(k) && typeof supervisor.chmod === "function") {
2445
+ _pendingModes.delete(k);
2446
+ try {
2447
+ await _ownMutation(
2448
+ absPath,
2449
+ () => _fsRpc(supervisor.chmod(absPath, _localModes[k]), "chmod", absPath, (result) => result),
2450
+ );
2451
+ } catch (error) {
2452
+ _pendingModes.add(k);
2453
+ throw error;
2454
+ }
1897
2455
  _markVfsStale();
1898
2456
  }
1899
2457
  }
@@ -1981,8 +2539,11 @@ const __fsMod = (() => {
1981
2539
  const atime = new Date(Number(meta?.atime || meta?.mtime || Date.now()));
1982
2540
  const mode = Number(meta?.mode ?? (isDir ? 0o755 : 0o644));
1983
2541
  const stat = _localStatObject(key, isDir, isSymlink, size, mode, meta?.uid, meta?.gid);
1984
- stat.atime = atime;
1985
- stat.mtime = mtime;
2542
+ // This process's own utimes, until it is reported back, ahead of the
2543
+ // namespace's (_recordLocalTimes).
2544
+ const own = key === undefined ? undefined : _localTimes[key];
2545
+ stat.atime = own && Number.isFinite(own.atimeMs) ? new Date(own.atimeMs) : atime;
2546
+ stat.mtime = own && Number.isFinite(own.mtimeMs) ? new Date(own.mtimeMs) : mtime;
1986
2547
  stat.ctime = new Date(Number(meta?.ctime ?? meta?.mtime ?? Date.now()));
1987
2548
  stat.birthtime = stat.ctime;
1988
2549
  return stat;
@@ -2015,24 +2576,32 @@ const __fsMod = (() => {
2015
2576
  // multi-MB file for one RPC frame.
2016
2577
  const READ_STREAM_CHUNK_BYTES = 65536;
2017
2578
 
2018
- // Ranged reads issued in the same microtask turn travel as ONE batch.
2579
+ // Ranged reads issued in the same microtask turn travel as ONE batch, and
2580
+ // so do lstats (_learnLive): one request kind each, one round trip.
2019
2581
  //
2020
2582
  // A round trip costs an order of magnitude more than the read behind it,
2021
2583
  // so a program awaiting reads one at a time pays for round trips and
2022
2584
  // nothing else. Nothing here changes what a read sees: every request is
2023
- // the same live ranged read, executed in order, in the caller's turn. The
2024
- // gather window is one microtask, so it can only capture reads the program
2025
- // had already issued concurrently — a sequential loop batches nothing
2026
- // because it has issued nothing else to batch.
2585
+ // the same live ranged read or lstat, executed in order, in the caller's
2586
+ // turn. The gather window is one microtask, so it can only capture
2587
+ // requests the program had already issued concurrently — a sequential
2588
+ // loop batches nothing because it has issued nothing else to batch.
2027
2589
  const READ_BATCH_PATH_LIMIT = 1024;
2028
2590
  const READ_BATCH_REQUEST_BYTES = 4194304;
2029
2591
  let _openReadBatch = null;
2030
2592
 
2031
2593
  function _queueRangeRead(supervisor, absPath, pos, want) {
2594
+ return _queueBatchRequest(supervisor, { path: absPath, offset: pos, length: want }, want);
2595
+ }
2596
+
2597
+ // `request` in the open batch, `bytes` of file content counted against the
2598
+ // batch's bound. Settles with the entry's bytes for a range, its stat for
2599
+ // an lstat.
2600
+ function _queueBatchRequest(supervisor, request, bytes) {
2032
2601
  let batch = _openReadBatch;
2033
2602
  if (batch && (
2034
2603
  batch.requests.length >= READ_BATCH_PATH_LIMIT
2035
- || batch.bytes + want > READ_BATCH_REQUEST_BYTES
2604
+ || batch.bytes + bytes > READ_BATCH_REQUEST_BYTES
2036
2605
  )) {
2037
2606
  _openReadBatch = null;
2038
2607
  _flushReadBatch(batch);
@@ -2042,17 +2611,24 @@ const __fsMod = (() => {
2042
2611
  batch = { supervisor, requests: [], settlers: [], bytes: 0 };
2043
2612
  _openReadBatch = batch;
2044
2613
  queueMicrotask(() => {
2045
- if (_openReadBatch === batch) _openReadBatch = null;
2614
+ // A batch a bound closed was flushed then; sending it here too would
2615
+ // read every entry of it twice.
2616
+ if (_openReadBatch !== batch) return;
2617
+ _openReadBatch = null;
2046
2618
  _flushReadBatch(batch);
2047
2619
  });
2048
2620
  }
2049
- batch.bytes += want;
2050
- batch.requests.push({ path: absPath, offset: pos, length: want });
2051
- return new Promise((resolve, reject) => { batch.settlers.push({ resolve, reject }); });
2621
+ batch.bytes += bytes;
2622
+ batch.requests.push(request);
2623
+ const settler = Promise.withResolvers();
2624
+ batch.settlers.push(settler);
2625
+ return settler.promise;
2052
2626
  }
2053
2627
 
2054
2628
  async function _flushReadBatch(batch) {
2055
- globalThis.__nimbusFsRpcReads++;
2629
+ // A read round trip is one that carries a range; a batch of learns
2630
+ // (lstat requests) is metadata, which the read count leaves out.
2631
+ if (batch.requests.some((request) => request.lstat !== true)) globalThis.__nimbusFsRpcReads++;
2056
2632
  try {
2057
2633
  const entries = await __nimbusUseRpcResult(
2058
2634
  batch.supervisor.fsReadBatch(batch.requests), (r) => r,
@@ -2063,6 +2639,8 @@ const __fsMod = (() => {
2063
2639
  const err = new Error(entry.error.message);
2064
2640
  if (entry.error.code) err.code = entry.error.code;
2065
2641
  batch.settlers[i].reject(err);
2642
+ } else if (batch.requests[i].lstat === true) {
2643
+ batch.settlers[i].resolve(entry ? entry.stat : null);
2066
2644
  } else {
2067
2645
  batch.settlers[i].resolve(entry ? entry.bytes : null);
2068
2646
  }
@@ -2127,59 +2705,83 @@ const __fsMod = (() => {
2127
2705
  return parts;
2128
2706
  }
2129
2707
 
2130
- async function _liveReadFile(p, opts, skipAcquire) {
2708
+ async function _liveReadFile(p, opts, refetch) {
2131
2709
  const absPath = _resolve(p);
2132
2710
  const encoding = typeof opts === "string" ? opts : opts?.encoding;
2133
2711
  const supervisor = _supervisor();
2134
2712
  if (!supervisor) throw _fsErr("ENOENT", "open", p);
2135
- // The refetch step of _acquireAndRefetch has already acquired against a
2136
- // fresh cursor, so re-acquiring here would be a redundant round trip
2137
- // that always returns "still R". Every other caller acquires.
2138
- if (!skipAcquire) await _acquireBarrier(supervisor);
2139
-
2140
- if (typeof supervisor.fsReadRange === "function") {
2141
- // Chunked: the caller wants the whole file, but nothing upstream has
2142
- // to hold it all at once to produce it.
2143
- //
2144
- // A short chunk is the only signal the file ended, so this walk could
2145
- // only ever have one chunk in flight — 65 sequential round trips for a
2146
- // 4 MiB file, each costing far more than the read behind it. The FIRST
2147
- // chunk still costs exactly one trip and settles it for every file
2148
- // that fits in one. When it comes back full there is demonstrably
2149
- // more, and a stat says how much, so the remainder is issued together
2150
- // and the read batch carries it in a single trip.
2151
- const parts = [];
2152
- let total = 0;
2153
- for (;;) {
2154
- const chunk = await _readRangeAt(absPath, p, total, READ_STREAM_CHUNK_BYTES);
2155
- if (chunk === null) break;
2156
- parts.push(chunk);
2157
- total += chunk.byteLength;
2158
- if (chunk.byteLength < READ_STREAM_CHUNK_BYTES) break;
2159
- if (typeof supervisor.stat !== "function") continue;
2160
- for (const rest of await _readChunksFrom(absPath, p, supervisor, total)) {
2161
- parts.push(rest);
2162
- total += rest.byteLength;
2713
+ // A refetch (_refetch) has already acquired against a fresh cursor and
2714
+ // holds the fill ticket issued under it, so re-acquiring here would be a
2715
+ // redundant round trip that always returns "still R". Every other caller
2716
+ // acquires, and its fill ticket is its own.
2717
+ if (!refetch) await _acquireBarrier(supervisor);
2718
+ const fill = refetch || _beginFill(_strip(absPath));
2719
+ try {
2720
+ if (typeof supervisor.fsReadRange === "function") {
2721
+ // Chunked: the caller wants the whole file, but nothing upstream has
2722
+ // to hold it all at once to produce it.
2723
+ //
2724
+ // A short chunk is the only signal the file ended, so this walk could
2725
+ // only ever have one chunk in flight — 65 sequential round trips for a
2726
+ // 4 MiB file, each costing far more than the read behind it. The FIRST
2727
+ // chunk still costs exactly one trip and settles it for every file
2728
+ // that fits in one. When it comes back full there is demonstrably
2729
+ // more, and a stat says how much, so the remainder is issued together
2730
+ // and the read batch carries it in a single trip.
2731
+ const parts = [];
2732
+ let total = 0;
2733
+ for (;;) {
2734
+ const chunk = await _readRangeAt(absPath, p, total, READ_STREAM_CHUNK_BYTES);
2735
+ if (chunk === null) break;
2736
+ parts.push(chunk);
2737
+ total += chunk.byteLength;
2738
+ if (chunk.byteLength < READ_STREAM_CHUNK_BYTES) break;
2739
+ if (typeof supervisor.stat !== "function") continue;
2740
+ for (const rest of await _readChunksFrom(absPath, p, supervisor, total)) {
2741
+ parts.push(rest);
2742
+ total += rest.byteLength;
2743
+ }
2744
+ break;
2163
2745
  }
2164
- break;
2746
+ const bytes = parts.length === 1 ? parts[0] : _concatBytes(parts, total);
2747
+ _installResident(absPath, bytes, fill);
2748
+ await _learnLive(absPath, supervisor);
2749
+ return encoding ? _asString(bytes) : __BufferMod.from(bytes);
2165
2750
  }
2166
- const bytes = parts.length === 1 ? parts[0] : _concatBytes(parts, total);
2167
- _installResident(absPath, bytes);
2168
- return encoding ? _asString(bytes) : __BufferMod.from(bytes);
2169
- }
2170
2751
 
2171
- if (typeof supervisor.readFile === "function") {
2172
- await _flushLocalPathToSupervisor(absPath, supervisor);
2173
- const text = await _fsReadRpc(supervisor.readFile(absPath), "open", p, (result) => result);
2174
- if (text !== null && text !== undefined) {
2175
- _installResident(absPath, text);
2176
- return encoding ? _asString(text) : __BufferMod.from(text);
2752
+ if (typeof supervisor.readFile === "function") {
2753
+ await _flushLocalPathToSupervisor(absPath, supervisor);
2754
+ const text = await _fsReadRpc(supervisor.readFile(absPath), "open", p, (result) => result);
2755
+ if (text !== null && text !== undefined) {
2756
+ _installResident(absPath, text, fill);
2757
+ await _learnLive(absPath, supervisor);
2758
+ return encoding ? _asString(text) : __BufferMod.from(text);
2759
+ }
2177
2760
  }
2761
+ } finally {
2762
+ if (!refetch) _endFill(fill);
2178
2763
  }
2179
2764
 
2180
2765
  throw _fsErr("ENOENT", "open", p);
2181
2766
  }
2182
2767
 
2768
+
2769
+
2770
+ /** Paths whose write-back this process issued and the authority accepted. */
2771
+ const _acceptedHere = new Set();
2772
+ globalThis.__nimbusVfsWriteLanded = (key) => {
2773
+ const k = String(key).replace(/^\/+/, "");
2774
+ _acceptedHere.add(k);
2775
+ };
2776
+
2777
+ // The authority refused a parked write (vfs-write-ledger): the record may
2778
+ // be that write's, so it is forgotten and the next access asks the authority.
2779
+ globalThis.__nimbusVfsWriteRefused = (key) => {
2780
+ const k = String(key).replace(/^\/+/, "");
2781
+ _createdHere.delete(k);
2782
+ _acceptedHere.delete(k);
2783
+ };
2784
+
2183
2785
  function _concatBytes(parts, total) {
2184
2786
  const out = new Uint8Array(total);
2185
2787
  let off = 0;
@@ -2251,24 +2853,11 @@ const __fsMod = (() => {
2251
2853
  // its shape: the sync existence view must not go on contradicting a
2252
2854
  // directory this very process has enumerated. Names only — size, mode
2253
2855
  // and ownership are not observable here and are never invented.
2254
- if (__vfsManifest) __vfsManifest[key] = entries.map((entry) => entry.name);
2255
- // Which of the children are directories IS observable here, and it is
2256
- // the one fact a later synchronous listing cannot recover on its own —
2257
- // an unwalked subdirectory has no manifest entry, so without this it
2258
- // reads back as a file. A directory's size is 0 in this filesystem, so
2259
- // recording it invents nothing; file children are left alone, because
2260
- // their size is not knowable from a listing and must not be guessed.
2261
- const metadataTable = _metadataTable();
2262
- if (metadataTable) {
2263
- for (const entry of entries) {
2264
- if (entry.type !== "directory") continue;
2265
- const child = prefix + entry.name;
2266
- if (child in metadataTable) continue;
2267
- metadataTable[child] = {
2268
- type: "directory", size: 0, mode: 0o755, uid: cred.uid, gid: cred.gid,
2269
- };
2270
- }
2271
- }
2856
+ // The listed directory and its child directories get the authority's
2857
+ // own stat: a later synchronous stat or listing of them needs a record
2858
+ // saying what they are, and a record says who owns them, which a
2859
+ // listing does not. So it is asked for, never assumed (one lstat per
2860
+ // child directory, concurrently).
2272
2861
  if (opts?.withFileTypes) {
2273
2862
  return entries
2274
2863
  .map((entry) => _direntObject(entry.name, entry.type, absPath))
@@ -2326,6 +2915,8 @@ const __fsMod = (() => {
2326
2915
  _fsRpc(supervisor.writeFile(absPath, content), "write", p, (result) => result)
2327
2916
  );
2328
2917
  _markVfsStale();
2918
+ // Accepted: the authority's stat is what the sync view keeps for it.
2919
+ await _learnLive(absPath, supervisor);
2329
2920
  }
2330
2921
  }
2331
2922
 
@@ -2344,6 +2935,7 @@ const __fsMod = (() => {
2344
2935
  ),
2345
2936
  );
2346
2937
  _markVfsStale();
2938
+ await _learnLive(absPath, supervisor);
2347
2939
  }
2348
2940
 
2349
2941
  // The async structural calls ARE the sync ones, awaited: the same local
@@ -2451,11 +3043,27 @@ const __fsMod = (() => {
2451
3043
  if (!supervisor && !existsSync(p)) throw _fsErr("ENOENT", syscall, p);
2452
3044
  }
2453
3045
 
3046
+ /**
3047
+ * chmod(2): only the owner or root changes a mode (EPERM). The local
3048
+ * overlay is what statSync reports and what the local permission checks
3049
+ * read, so a mode set here without that check made a root-owned file
3050
+ * writable in the process's own view.
3051
+ */
3052
+ function _ensureModeOwner(absPath, syscall, p) {
3053
+ if (Number(cred.uid) === 0) return;
3054
+ const stat = _statLadder(absPath);
3055
+ if (stat === undefined) throw _fsErr("ENOENT", syscall, p);
3056
+ if (Number(stat.uid) !== Number(cred.uid)) throw _fsErr("EPERM", syscall, p);
3057
+ }
3058
+
2454
3059
  function chmodSync(p, mode) {
2455
3060
  if (!existsSync(p)) throw _fsErr("ENOENT", "chmod", p);
3061
+ _ensureModeOwner(_resolve(p), "chmod", p);
2456
3062
  // Local-visible immediately (statSync overlay); the live write-through
2457
3063
  // rides the next flush of the same path — same fidelity as utimesSync.
2458
- _localModes[_strip(_resolve(p))] = _coerceMode(mode, "chmod", p);
3064
+ const k = _strip(_resolve(p));
3065
+ _localModes[k] = _coerceMode(mode, "chmod", p);
3066
+ _pendingModes.add(k);
2459
3067
  }
2460
3068
 
2461
3069
  async function _chmodAsync(p, mode) {
@@ -2467,7 +3075,9 @@ const __fsMod = (() => {
2467
3075
  throw _fsErr("ENOENT", "chmod", p);
2468
3076
  }
2469
3077
  const m = _coerceMode(mode, "chmod", p);
3078
+ if (localExists) _ensureModeOwner(absPath, "chmod", p);
2470
3079
  _localModes[_strip(absPath)] = m;
3080
+ _pendingModes.add(_strip(absPath));
2471
3081
  if (supervisor && typeof supervisor.chmod === "function") {
2472
3082
  await _flushLocalPathToSupervisor(absPath, supervisor);
2473
3083
  _markVfsStale();
@@ -2519,6 +3129,18 @@ const __fsMod = (() => {
2519
3129
  }
2520
3130
  const nextUid = _coerceId(uid, syscall, p);
2521
3131
  const nextGid = _coerceId(gid, syscall, p);
3132
+ // chown(2): root changes anything; the owner may only set the group to
3133
+ // one of its own groups, and never the owner. Checked before the local
3134
+ // row changes: that row is what the local permission checks read.
3135
+ if (Number(cred.uid) !== 0) {
3136
+ const stat = _statLadder(absPath);
3137
+ if (stat === undefined) throw _fsErr("ENOENT", syscall, p);
3138
+ const groups = [Number(cred.gid), ...cred.groups.map(Number)];
3139
+ if (Number(stat.uid) !== Number(cred.uid) || nextUid !== Number(stat.uid)
3140
+ || (nextGid !== Number(stat.gid) && !groups.includes(nextGid))) {
3141
+ throw _fsErr("EPERM", syscall, p);
3142
+ }
3143
+ }
2522
3144
  const meta = _metadata(absPath);
2523
3145
  if (meta) { meta.uid = nextUid; meta.gid = nextGid; }
2524
3146
  // The parked write must be registered on the tail BEFORE the chown is
@@ -2535,21 +3157,25 @@ const __fsMod = (() => {
2535
3157
  function lchownSync(p, uid, gid) { _detachStructuralMutation(_chownQueued(p, uid, gid, { followSymlinks: false }, "lchown")); }
2536
3158
  function lchmodSync(p, mode) { chmodSync(p, mode); }
2537
3159
 
3160
+ /**
3161
+ * Whether this process may WANT (r=4, w=2, x=1) a path whose stat is
3162
+ * META, by POSIX's owner/group/other rule. Only a stat that states the
3163
+ * owner, group and mode can be judged; one that does not is not judged in
3164
+ * the process's favour: absent fields used to default to mode 0644 and
3165
+ * owner 1000, which made any undescribed file the reader's own.
3166
+ */
2538
3167
  function _modeAllows(meta, want) {
2539
3168
  if (want === 0) return true;
2540
- const mode = Number(meta?.mode ?? 0o644) & 0o777;
3169
+ const mode = Number(meta?.mode);
3170
+ const uid = Number(meta?.uid);
3171
+ const gid = Number(meta?.gid);
3172
+ if (!Number.isInteger(mode) || !Number.isInteger(uid) || !Number.isInteger(gid)) return false;
3173
+ const bits = mode & 0o777;
2541
3174
  const currentUid = Number(cred.uid);
2542
- const currentGid = Number(cred.gid);
3175
+ if (currentUid === 0) return (want & 1) === 0 || (bits & 0o111) !== 0;
2543
3176
  const groups = cred.groups.map(Number);
2544
- if (currentUid === 0) {
2545
- if ((want & 1) !== 0 && (mode & 0o111) === 0) return false;
2546
- return true;
2547
- }
2548
- const shift = currentUid === Number(meta?.uid ?? 1000)
2549
- ? 6
2550
- : (currentGid === Number(meta?.gid ?? 1000) || groups.includes(Number(meta?.gid ?? 1000))) ? 3 : 0;
2551
- const available = (mode >> shift) & 7;
2552
- return (available & want) === want;
3177
+ const shift = currentUid === uid ? 6 : (Number(cred.gid) === gid || groups.includes(gid)) ? 3 : 0;
3178
+ return (((bits >> shift) & 7) & want) === want;
2553
3179
  }
2554
3180
 
2555
3181
  function _ensureAncestorsTraversable(absPath, syscall, p) {
@@ -2563,34 +3189,31 @@ const __fsMod = (() => {
2563
3189
  function _ensureWritable(absPath, syscall, p) {
2564
3190
  _ensureAncestorsTraversable(absPath, syscall, p);
2565
3191
  const cell = _bundleLookup(absPath);
2566
- const meta = _metadata(absPath);
2567
- // The ladder rather than existsSync: a write to a path outside the staged
2568
- // view is a legitimate create, and must not be turned into a refusal by
2569
- // the check that guards it.
2570
- if (meta !== undefined || cell !== undefined || _statLadder(absPath) !== undefined) {
2571
- const denial = _denialCode(cell);
2572
- if (denial || !_modeAllows(meta, 2)) throw _fsErr(denial || "EACCES", syscall, p);
3192
+ const denial = _denialCode(cell);
3193
+ if (denial) throw _fsErr(denial, syscall, p);
3194
+ // Judged on what the authority says of the path (or of a file this
3195
+ // process made), never on the bytes held under its name.
3196
+ const stat = _statLadder(absPath);
3197
+ if (stat !== undefined) {
3198
+ if (!_modeAllows(stat, 2)) throw _fsErr("EACCES", syscall, p);
2573
3199
  return;
2574
3200
  }
3201
+ // Nothing there: a create, judged by the parent the namespace describes.
2575
3202
 
2576
3203
  const parent = __pathMod.dirname(absPath);
2577
- const parentMeta = _metadata(parent);
2578
- if (parentMeta) {
2579
- if (parentMeta.type && parentMeta.type !== "directory") throw _fsErr("ENOTDIR", syscall, p);
2580
- if (!_modeAllows(parentMeta, 3)) throw _fsErr("EACCES", syscall, p);
3204
+ const parentStat = _statLadder(parent);
3205
+ if (parentStat !== undefined) {
3206
+ if (!parentStat.isDirectory()) throw _fsErr("ENOTDIR", syscall, p);
3207
+ if (!_modeAllows(parentStat, 3)) throw _fsErr("EACCES", syscall, p);
2581
3208
  return;
2582
3209
  }
2583
3210
 
2584
- const parentKey = _strip(parent);
2585
- const parentIsLocal = parent === cwd || parent === "/" ||
2586
- (!!__vfsDirs && parentKey in __vfsDirs) ||
2587
- (!!__vfsManifest && parentKey in __vfsManifest);
2588
- if (parentIsLocal || _supervisor()) return;
2589
3211
  throw _fsErr("ENOENT", syscall, p);
2590
3212
  }
2591
3213
 
2592
3214
  function accessSync(p, mode) {
2593
3215
  const absPath = _resolve(p);
3216
+ _nsRequire("access", p, "fs.promises.access");
2594
3217
  const cell = _bundleLookup(absPath);
2595
3218
  const meta = _metadata(absPath);
2596
3219
  if (cell === undefined && meta === undefined && !existsSync(p)) throw _fsErr("ENOENT", "access", p);
@@ -2601,7 +3224,10 @@ const __fsMod = (() => {
2601
3224
  _ensureAncestorsTraversable(absPath, "access", p);
2602
3225
  const denial = _denialCode(cell);
2603
3226
  if ((requested & 4) !== 0 && denial) throw _fsErr(denial, "access", p);
2604
- if (!_modeAllows(meta, requested)) throw _fsErr("EACCES", "access", p);
3227
+ if (requested === 0) return;
3228
+ const stat = _statLadder(absPath);
3229
+ if (stat === undefined) throw _fsErr("ENOENT", "access", p);
3230
+ if (!_modeAllows(stat, requested)) throw _fsErr("EACCES", "access", p);
2605
3231
  }
2606
3232
 
2607
3233
  async function _accessAsync(p, mode) {
@@ -2712,42 +3338,12 @@ const __fsMod = (() => {
2712
3338
  // ── existsSync ──
2713
3339
  function existsSync(p) {
2714
3340
  const absPath = _resolve(p);
2715
- const k = _strip(absPath);
2716
- if (_metadata(absPath) !== undefined) { _residencySatisfied(absPath); return true; }
2717
- if (__vfsBundle && k in __vfsBundle) { _residencySatisfied(absPath); return true; }
2718
- if (__vfsWrites && k in __vfsWrites) { _residencySatisfied(absPath); return true; }
2719
- if (__vfsDirs && k in __vfsDirs) { _residencySatisfied(absPath); return true; }
2720
- // W2.5b root-cause fix: consult the manifest BEFORE falling back to
2721
- // the O(N) bundle-prefix scan. The manifest is uncapped and always
2722
- // reflects the real directory shape, even when the file content for
2723
- // a directory's contents was excluded by the 4 MiB / 500-file content
2724
- if (__vfsManifest) {
2725
- if (k in __vfsManifest) { _residencySatisfied(absPath); return true; }
2726
- // Path may be a file listed by its parent's manifest entry.
2727
- const slash = k.lastIndexOf("/");
2728
- const parent = slash >= 0 ? k.slice(0, slash) : "";
2729
- const name = slash >= 0 ? k.slice(slash + 1) : k;
2730
- const sib = __vfsManifest[parent];
2731
- if (sib && sib.indexOf(name) !== -1) { _residencySatisfied(absPath); return true; }
2732
- }
2733
- // Last-resort: bundle dir entries
2734
- if (__vfsBundle && (k in __vfsBundle || __residentAnyUnder(k + "/"))) {
2735
- _residencySatisfied(absPath);
2736
- return true;
2737
- }
2738
- // Nothing found — which is only an answer if the enclosing directory was
2739
- // enumerated. Node's existsSync never throws, so the false below is
2740
- // provisional: the miss is recorded, the listing that settles it is pulled
2741
- // in, and the exit report fails the run if the path turns out to have been
2742
- // there all along.
2743
- if (!_absenceIsKnown(absPath)) {
2744
- _recordUnmapped(absPath, "access");
2745
- return false;
2746
- }
3341
+ _nsRequire("access", p, "fs.promises.access");
2747
3342
  _residencySatisfied(absPath);
2748
- return false;
3343
+ return _statLadder(absPath) !== undefined;
2749
3344
  }
2750
3345
 
3346
+
2751
3347
  // ── statSync ──
2752
3348
  function statSync(p, opts) {
2753
3349
  const absPath = _resolve(p);
@@ -2760,16 +3356,12 @@ const __fsMod = (() => {
2760
3356
  // classify a miss without redoing the resolve and ancestor walk it just
2761
3357
  // performed — that path runs on every module-resolution probe.
2762
3358
  function _statResolved(absPath, p, opts) {
3359
+ _nsRequire("stat", p, "fs.promises.stat");
2763
3360
  const stat = _statLadder(absPath);
2764
- // An answer settles the path, including the honest "not there" below —
2765
- // what the ledger is for is reads that went unanswered, not reads that came
2766
- // back with news the caller did not want. A PROVISIONAL not-there is not an
2767
- // answer, so the unmapped branch deliberately leaves the record standing.
2768
- if (stat !== undefined) { _residencySatisfied(absPath); return stat; }
2769
- // Nothing in the view describes the path, and there are two very different
2770
- // reasons for that. Only one of them means the file is not there.
2771
- if (_absenceIsKnown(absPath)) _residencySatisfied(absPath);
2772
- else _recordUnmapped(absPath, "stat");
3361
+ // An answer settles the path, including the honest "not there": the
3362
+ // namespace names every path this credential can see.
3363
+ _residencySatisfied(absPath);
3364
+ if (stat !== undefined) return stat;
2773
3365
  // Node's statSync honors { throwIfNoEntry: false } by returning undefined
2774
3366
  // for a missing path instead of throwing.
2775
3367
  if (opts && opts.throwIfNoEntry === false) return undefined;
@@ -2782,154 +3374,45 @@ const __fsMod = (() => {
2782
3374
  * MEANS — absence and ignorance are different answers and only one of them
2783
3375
  * is a condition a program can act on, so the callers classify.
2784
3376
  */
2785
- function _statLadder(absPath) {
3377
+ function _statLadder(absPath, noFollow) {
2786
3378
  const k = _strip(absPath);
2787
- // Content written this exec session is newer than the spawn-time
2788
- // metadata snapshot, so it — not __vfsMetadata — is authoritative for
2789
- // size. Without this, fstatSync/statSync on a file we just wrote report
2790
- // the pre-write length.
2791
- if (__vfsWrites && k in __vfsWrites && _denialCode(__vfsWrites[k]) === null) {
2792
- const meta = _metadata(absPath);
2793
- const size = _byteLen(__vfsWrites[k]);
2794
- // Correct only the size — reusing the metadata record keeps the type
2795
- // and the recorded timestamps stable, so mtime-based change detection
2796
- // (make, tsc --build, watchers) does not see every call as a change.
2797
- if (meta) return _statObject({ ...meta, size }, k);
2798
- return _localStatObject(
2799
- k, false, false, size, 0o666 & ~__processUmask, cred.uid, cred.gid,
2800
- );
2801
- }
2802
- const metadata = _metadata(absPath);
2803
- if (metadata) return _statObject(metadata, k);
2804
- // Check if it's a known directory written this exec session
2805
- if (__vfsDirs && k in __vfsDirs) {
2806
- return _localStatObject(k, true, false, 0, 0o777 & ~__processUmask, cred.uid, cred.gid);
2807
- }
2808
- // W2.5b: consult uncapped manifest first for directory shape.
2809
- if (__vfsManifest && k in __vfsManifest) {
2810
- return _localStatObject(k, true, false, 0, 0o755, cred.uid, cred.gid);
2811
- }
2812
- // File with content embedded?
2813
- const content = _bundleLookup(absPath);
2814
- if (content !== undefined) {
2815
- // _byteLen handles both string (UTF-8 encode) and Uint8Array
2816
- // (byteLength) — fixes binary writes from reporting the
2817
- // post-corruption byte count.
2818
- const size = _byteLen(content);
2819
- return _localStatObject(k, false, false, size, 0o666 & ~__processUmask, cred.uid, cred.gid);
2820
- }
2821
- // File listed in parent's manifest but content was capped out — return
2822
- // a zero-size file stat so callers like fs.stat / fs.statSync see the
2823
- // file as present (downstream readFileSync will surface ENOENT if it
2824
- // actually tries to read content; many consumers only need stat).
2825
- if (__vfsManifest) {
2826
- const slash = k.lastIndexOf("/");
2827
- const parent = slash >= 0 ? k.slice(0, slash) : "";
2828
- const name = slash >= 0 ? k.slice(slash + 1) : k;
2829
- const sib = __vfsManifest[parent];
2830
- if (sib && sib.indexOf(name) !== -1) {
2831
- return _localStatObject(k, false, false, 0, 0o644, cred.uid, cred.gid);
2832
- }
2833
- }
2834
- // Last-resort: bundle prefix scan (legacy path).
2835
- if (__vfsBundle && __residentAnyUnder(k + "/")) {
2836
- return _localStatObject(k, true, false, 0, 0o755, cred.uid, cred.gid);
2837
- }
2838
- return undefined;
3379
+ _nsRequire("stat", absPath, "fs.promises.stat");
3380
+ const meta = _nsMeta(k, !noFollow);
3381
+ if (meta === "absent" || meta === "ELOOP") return undefined;
3382
+ return meta.own
3383
+ ? _localStatObject(k, meta.type === "directory", false, meta.size, meta.mode & 0o7777, meta.uid, meta.gid)
3384
+ : _statObject(meta, k);
2839
3385
  }
2840
3386
 
2841
3387
  // ── lstatSync (alias for statSync in our VFS — no symlinks) ──
2842
- function lstatSync(p, opts) { return statSync(p, opts); }
3388
+ function lstatSync(p, opts) {
3389
+ const absPath = _resolve(p);
3390
+ _nsRequire("lstat", p, "fs.promises.lstat");
3391
+ _ensureAncestorsTraversable(absPath, "lstat", p);
3392
+ const stat = _statLadder(absPath, true);
3393
+ if (stat !== undefined) return stat;
3394
+ if (opts && opts.throwIfNoEntry === false) return undefined;
3395
+ throw _fsErr("ENOENT", "lstat", p);
3396
+ }
2843
3397
 
2844
3398
  // ── readdirSync ──
2845
- // W2.5b root-cause fix: prefer the uncapped __vfsManifest for directory
2846
- // listings. The legacy bundle-prefix scan is kept as a fallback for paths
2847
- // not in the manifest (e.g. dirs created at exec time via mkdirSync) and
2848
- // is unioned with __vfsWrites so newly-written files become visible.
3399
+ // The namespace's listing of the directory, with this process's own
3400
+ // structural effects over it (_nsList).
2849
3401
  function readdirSync(p, opts) {
2850
3402
  const absPath = _resolve(p);
3403
+ _nsRequire("scandir", p, "fs.promises.readdir");
2851
3404
  _ensureAncestorsTraversable(absPath, "scandir", p);
2852
3405
  const metadata = _metadata(absPath);
2853
3406
  if (metadata && !_modeAllows(metadata, 4)) throw _fsErr("EACCES", "scandir", p);
2854
3407
  const k = _strip(absPath);
2855
- // A listing is the one answer with no way to express doubt: an array is a
2856
- // complete enumeration by definition, so returning what happens to be
2857
- // known asserts that nothing else is there. Only a directory the walk
2858
- // enumerated, or one this process created, can honestly be listed.
2859
- if (!_dirEnumerated(k) && !_bundleHasChildren(k)) {
2860
- // An authority exists that this call cannot reach, so an empty array
2861
- // would be a claim about a directory nothing ever opened. Refuse, and
2862
- // pull the listing in for the next one.
2863
- //
2864
- // This is the one caller that keeps refusing. Everywhere else the sync
2865
- // view answers a path it cannot map with the not-found the program was
2866
- // written to handle, provisionally, and lets the exit report settle
2867
- // whether that answer was true. A listing has no such answer to give:
2868
- // "no config yet, write one" is an idiom every program implements, and
2869
- // there is no counterpart for a directory — a caller handed ENOENT for a
2870
- // template tree has nowhere to go but the same wrong branch an empty
2871
- // array sent it down, and the array at least it could not detect.
2872
- if (_supervisor()) {
2873
- throw _refuseUnmapped(absPath, p, "scandir", "fs.promises.readdir");
2874
- }
2875
- // No authority: the staged tables are the whole filesystem. A path they
2876
- // do not describe is missing, and one they describe with no children is
2877
- // genuinely empty.
2878
- if (_statLadder(absPath) === undefined) throw _fsErr("ENOENT", "scandir", p);
2879
- }
2880
- const prefix = k ? k + "/" : "";
2881
- const names = new Set();
2882
- // 1. Manifest-supplied children (the authoritative source for installed pkgs).
2883
- if (__vfsManifest && k in __vfsManifest) {
2884
- for (const n of __vfsManifest[k]) names.add(n);
2885
- }
2886
- // 2. Bundle-prefix fallback (covers older paths or runtime-mkdir'd ones
2887
- // that aren't in the manifest yet).
2888
- if (__vfsBundle) {
2889
- for (const bk of __residentUnder(prefix)) {
2890
- const seg = bk.substring(prefix.length).split("/")[0];
2891
- if (seg) names.add(seg);
2892
- }
2893
- }
2894
- // 3. Files written during this exec session.
2895
- if (__vfsWrites) {
2896
- for (const wk in __vfsWrites) {
2897
- if (wk.startsWith(prefix)) {
2898
- const rest = wk.substring(prefix.length);
2899
- const seg = rest.split("/")[0];
2900
- if (seg) names.add(seg);
2901
- }
2902
- }
2903
- }
2904
- // 4. Dirs created during this exec session.
2905
- if (__vfsDirs) {
2906
- for (const dk in __vfsDirs) {
2907
- if (dk.startsWith(prefix)) {
2908
- const rest = dk.substring(prefix.length);
2909
- const seg = rest.split("/")[0];
2910
- if (seg) names.add(seg);
2911
- }
2912
- }
2913
- }
3408
+ const st = _statLadder(absPath);
3409
+ if (st === undefined) throw _fsErr("ENOENT", "scandir", p);
3410
+ if (!st.isDirectory()) throw _fsErr("ENOTDIR", "scandir", p);
2914
3411
  _residencySatisfied(absPath);
2915
- const arr = [...names].sort();
2916
- if (opts?.withFileTypes) {
2917
- return arr.map(n => {
2918
- const fp = prefix + n;
2919
- // Manifest is the definitive isDir source; fall back to bundle scan.
2920
- // The metadata record sits between them: a directory that was listed
2921
- // but never walked has no manifest entry of its own, and calling it a
2922
- // file is how a template tree full of subdirectories reads back as a
2923
- // tree full of nothing.
2924
- const isDir =
2925
- (!!__vfsManifest && fp in __vfsManifest) ||
2926
- (!!__vfsDirs && fp in __vfsDirs) ||
2927
- _metadata(fp)?.type === "directory" ||
2928
- (!!__vfsBundle && __residentAnyUnder(fp + "/"));
2929
- return _direntObject(n, isDir ? "directory" : "file", absPath);
2930
- });
2931
- }
2932
- return arr;
3412
+ const listed = _nsList(k);
3413
+ const sorted = [...listed.keys()].sort();
3414
+ if (!opts?.withFileTypes) return sorted;
3415
+ return sorted.map((n) => _direntObject(n, listed.get(n), absPath));
2933
3416
  }
2934
3417
 
2935
3418
  // ── mkdirSync ──
@@ -2943,11 +3426,16 @@ const __fsMod = (() => {
2943
3426
  if (opts?.recursive) {
2944
3427
  const parts = k.split("/").filter(Boolean);
2945
3428
  let cur = "";
2946
- for (const part of parts) { cur = cur ? cur + "/" + part : part; __vfsDirs[cur] = true; created.push(cur); }
3429
+ for (const part of parts) { cur = cur ? cur + "/" + part : part; _noteCreation(cur); __vfsDirs[cur] = true; created.push(cur); }
2947
3430
  } else {
3431
+ _noteCreation(k);
2948
3432
  __vfsDirs[k] = true;
2949
3433
  created.push(k);
2950
3434
  }
3435
+ for (const dir of created) {
3436
+ const was = _nsMeta(dir, true);
3437
+ if (was === "absent") _nsOwnSet(dir, "dir", { hide: true });
3438
+ }
2951
3439
  const queued = _queueStructuralMutation(absPath, "mkdir", p, (supervisor) => supervisor.mkdir(absPath));
2952
3440
  // Told, not merely known locally: _announceLocalDirs must not issue a
2953
3441
  // second mkdir for a directory whose own RPC is already in the queue.
@@ -2957,9 +3445,30 @@ const __fsMod = (() => {
2957
3445
  function mkdirSync(p, opts) { _detachStructuralMutation(_mkdirQueued(p, opts)); }
2958
3446
 
2959
3447
  // ── unlinkSync ──
3448
+ /**
3449
+ * unlink(2)/rmdir(2)/rename(2) of an existing name: the parent must be
3450
+ * writable and searchable, and in a sticky directory (/tmp, 1777) only the
3451
+ * file's owner, the directory's owner or root may remove it. Checked before
3452
+ * the local view changes, so a refusal leaves the process's view intact. A
3453
+ * name whose owner this view does not know is refused as a miss.
3454
+ */
3455
+ function _ensureRemovable(absPath, syscall, p) {
3456
+ _ensureAncestorsTraversable(absPath, syscall, p);
3457
+ const k = _strip(absPath);
3458
+ const parent = _statLadder(__pathMod.dirname(absPath));
3459
+ if (parent === undefined) return;
3460
+ if (!_modeAllows(parent, 3)) throw _fsErr("EACCES", syscall, p);
3461
+ if ((Number(parent.mode) & 0o1000) === 0 || Number(cred.uid) === 0 || Number(parent.uid) === Number(cred.uid)) return;
3462
+ if (_createdHere.has(k)) return;
3463
+ const target = _statLadder(absPath, true);
3464
+ if (target === undefined) return;
3465
+ if (Number(target.uid) !== Number(cred.uid)) throw _fsErr("EPERM", syscall, p);
3466
+ }
3467
+
2960
3468
  function _unlinkQueued(p) {
2961
3469
  const absPath = _resolve(p);
2962
3470
  const k = _strip(absPath);
3471
+ _ensureRemovable(absPath, "unlink", p);
2963
3472
  if (__vfsBundle) delete __vfsBundle[k];
2964
3473
  if (__vfsWrites) delete __vfsWrites[k];
2965
3474
  _forgetSyncPath(k);
@@ -2971,6 +3480,7 @@ const __fsMod = (() => {
2971
3480
  function _rmdirQueued(p) {
2972
3481
  const absPath = _resolve(p);
2973
3482
  const k = _strip(absPath);
3483
+ _ensureRemovable(absPath, "rmdir", p);
2974
3484
  if (__vfsDirs) delete __vfsDirs[k];
2975
3485
  _forgetSyncPath(k);
2976
3486
  return _queueStructuralMutation(
@@ -2985,21 +3495,29 @@ const __fsMod = (() => {
2985
3495
  function _renameQueued(oldP, newP) {
2986
3496
  const oldAbs = _resolve(oldP);
2987
3497
  const newAbs = _resolve(newP);
3498
+ // The name leaves its directory and lands in another (replacing what is
3499
+ // there): both are removals by POSIX's rule.
3500
+ _ensureRemovable(oldAbs, "rename", oldP);
3501
+ if (_statLadder(newAbs, true) !== undefined) _ensureRemovable(newAbs, "rename", newP);
3502
+ else _ensureWritable(newAbs, "rename", newP);
2988
3503
  const oldK = _strip(oldAbs);
2989
3504
  const newK = _strip(newAbs);
3505
+ // The table still holds the old name until the rename is reported, so the
3506
+ // new name reads through to it and the old one reads as gone.
3507
+ const nsFrom = _nsRealKey(oldK);
3508
+ // What this process created travels with the name; what it did not stays
3509
+ // the authority's, whatever the move does to the local tables.
3510
+ const oldPrefix = oldK + "/";
3511
+ const createdMoved = [..._createdHere]
3512
+ .filter((key) => key === oldK || key.startsWith(oldPrefix))
3513
+ .map((key) => newK + key.slice(oldK.length));
2990
3514
  const content = __vfsBundle?.[oldK] ?? __vfsWrites?.[oldK];
2991
3515
  if (content !== undefined) {
2992
3516
  _parkWrite(newK, content);
2993
3517
  if (__vfsBundle) delete __vfsBundle[oldK];
2994
3518
  delete __vfsBundleRevisions[oldK];
2995
3519
  delete __vfsWrites[oldK];
2996
- // The stat record travels with the content: dropping it would lose the
2997
- // mode/ownership, and leaving it behind would keep the source path
2998
- // reporting as an existing file this rename already moved away.
2999
- const metadata = _metadataTable();
3000
- const moved = metadata ? metadata[oldK] : undefined;
3001
3520
  _forgetSyncPath(oldK);
3002
- if (moved) metadata[newK] = moved;
3003
3521
  } else if (__vfsDirs && oldK in __vfsDirs) {
3004
3522
  // A directory this process made travels under its new name, so the
3005
3523
  // sync view stops listing the old one and _announceLocalDirs cannot
@@ -3014,6 +3532,16 @@ const __fsMod = (() => {
3014
3532
  }
3015
3533
  _forgetSyncTree(oldK);
3016
3534
  }
3535
+ _forgetCreation(oldK);
3536
+ _forgetCreation(newK);
3537
+ for (const key of createdMoved) _createdHere.add(key);
3538
+ for (const [ok, entry] of [..._nsOwn]) {
3539
+ if ((ok === oldK || ok.startsWith(oldPrefix)) && entry.state === "dir") {
3540
+ _nsOwnSet(newK + ok.slice(oldK.length), "dir", { hide: entry.hide });
3541
+ }
3542
+ }
3543
+ if (nsFrom !== null && !_nsOwn.has(newK)) _nsOwnSet(newK, "alias", { from: nsFrom });
3544
+ _nsOwnSet(oldK, "absentTree");
3017
3545
  const queued = _queueStructuralMutation(
3018
3546
  oldAbs, "rename", oldP,
3019
3547
  (supervisor) => supervisor.rename(oldAbs, newAbs),
@@ -3180,7 +3708,16 @@ const __fsMod = (() => {
3180
3708
  // Sync realpath stays local and identity-resolves. Async symlink
3181
3709
  // operations use the live supervisor bridge below.
3182
3710
  // .native static is required by TypeScript's getNodeSystem at
3183
- function realpathSync(p, opts) { return _resolve(String(p)); }
3711
+ function realpathSync(p, opts) {
3712
+ const absPath = _resolve(String(p));
3713
+ _nsRequire("realpath", p, "fs.promises.realpath");
3714
+ const k = _strip(absPath);
3715
+ const meta = _nsMeta(k, true);
3716
+ if (meta === "ELOOP") throw _fsErr("ELOOP", "realpath", p);
3717
+ if (meta === "absent") throw _fsErr("ENOENT", "realpath", p);
3718
+ const real = _nsRealKey(k);
3719
+ return real === null ? absPath : "/" + real;
3720
+ }
3184
3721
  realpathSync.native = realpathSync;
3185
3722
 
3186
3723
  // ── Async variants (thin wrappers returning via callback) ──
@@ -3208,6 +3745,11 @@ const __fsMod = (() => {
3208
3745
  _mkdirAsync(p, opts).then(() => { if (cb) cb(null); }).catch((e) => { if (cb) cb(e); });
3209
3746
  }
3210
3747
  function unlink(p, cb) { _unlinkAsync(p).then(() => { if (cb) cb(null); }).catch((e) => { if (cb) cb(e); }); }
3748
+ // The callback form proper-lockfile (via graceful-fs) releases its lock directory with.
3749
+ function rmdir(p, opts, cb) {
3750
+ if (typeof opts === "function") { cb = opts; opts = undefined; }
3751
+ _rmdirAsync(p).then(() => { if (cb) cb(null); }).catch((e) => { if (cb) cb(e); });
3752
+ }
3211
3753
  function rename(oldP, newP, cb) { _renameAsync(oldP, newP).then(() => { if (cb) cb(null); }).catch((e) => { if (cb) cb(e); }); }
3212
3754
  function utimes(p, atime, mtime, cb) { _utimesAsync(p, atime, mtime).then(() => { if (cb) cb(null); }).catch((e) => { if (cb) cb(e); }); }
3213
3755
  function lutimes(p, atime, mtime, cb) { _utimesAsync(p, atime, mtime, { followSymlinks: false }).then(() => { if (cb) cb(null); }).catch((e) => { if (cb) cb(e); }); }
@@ -3264,11 +3806,8 @@ const __fsMod = (() => {
3264
3806
  // Non-resident and non-empty: writing onto a zero-filled base would
3265
3807
  // silently destroy the bytes we cannot see. Refuse instead.
3266
3808
  if (st !== undefined && st.size !== 0) throw _notResidentError(absPath, p, syscall, asyncForm);
3267
- // Absent or empty — an empty base IS the true prior content, but only
3268
- // where absence is knowledge. A path the view never mapped may hold bytes
3269
- // this process cannot see, and an O_APPEND descriptor onto a zero-filled
3270
- // base would overwrite the file with the fragment it meant to add.
3271
- if (st === undefined && !_absenceIsKnown(absPath)) throw _refuseUnmapped(absPath, p, syscall, asyncForm);
3809
+ // Absent or empty: an empty base is the true prior content (the namespace
3810
+ // names every path this credential can see).
3272
3811
  return new Uint8Array(0);
3273
3812
  }
3274
3813
 
@@ -3531,6 +4070,10 @@ const __fsMod = (() => {
3531
4070
  if (!exists && !fl.create) throw _fsErr("ENOENT", "open", path);
3532
4071
  if (exists && fl.create && fl.exclusive) throw _fsErr("EEXIST", "open", path);
3533
4072
  let size = liveMeta ? (Number(liveMeta.size) || 0) : (localStat ? localStat.size : 0);
4073
+ // The authority answered, so what it said is what the sync view keeps:
4074
+ // its stat when something is there, and when nothing is, the file this
4075
+ // open creates is the process's own.
4076
+ if (!liveMeta && supervisor && !localStat) _createdHere.add(_strip(absPath));
3534
4077
  if (!exists) {
3535
4078
  await _writeFileAsync(path, new Uint8Array(0));
3536
4079
  if (mode !== undefined && mode !== null) {
@@ -3555,6 +4098,7 @@ const __fsMod = (() => {
3555
4098
  if (!exists && !fl.create) throw _fsErr("ENOENT", "open", path);
3556
4099
  if (exists && fl.create && fl.exclusive) throw _fsErr("EEXIST", "open", path);
3557
4100
  if (fl.write || !exists) _ensureWritable(absPath, "open", path);
4101
+ if (!exists) _noteCreation(_strip(absPath));
3558
4102
  let size = exists ? st.size : 0;
3559
4103
  // O_TRUNC means "make it empty", so zeroing is the requested semantic,
3560
4104
  // and creating a genuinely absent file is too. O_APPEND must NEVER
@@ -3683,7 +4227,10 @@ const __fsMod = (() => {
3683
4227
  function fchmodSync(fd, mode) {
3684
4228
  if (_isStdioFd(fd)) throw _fsErr("EINVAL", "fchmod", fd);
3685
4229
  const handle = _fdHandle(fd, "fchmod");
3686
- _localModes[_strip(handle._abs)] = _coerceMode(mode, "fchmod", handle._path);
4230
+ const k = _strip(handle._abs);
4231
+ _ensureModeOwner(handle._abs, "fchmod", handle._path);
4232
+ _localModes[k] = _coerceMode(mode, "fchmod", handle._path);
4233
+ _pendingModes.add(k);
3687
4234
  }
3688
4235
  function fchownSync(fd, uid, gid) {
3689
4236
  if (_isStdioFd(fd)) throw _fsErr("EINVAL", "fchown", fd);
@@ -4023,15 +4570,16 @@ const __fsMod = (() => {
4023
4570
  // not just the local cache — is required so a subsequent async fs op
4024
4571
  // (e.g. fs.promises.rename of a copied file, as create-cloudflare
4025
4572
  // does for __dot__gitignore) sees the copy in the VFS instead of
4026
- // ENOENT.
4027
- __vfsDirs[destK] = true;
4573
+ // ENOENT. Each directory is made as mkdir makes it, so the namespace's
4574
+ // overlay lists it for the writes beneath it.
4575
+ await _mkdirAsync("/" + destK, { recursive: true });
4028
4576
  const walk = async (relDir) => {
4029
4577
  const absDir = relDir ? srcAbs + "/" + relDir : srcAbs;
4030
4578
  const ents = await _readdirAsync(absDir, { withFileTypes: true });
4031
4579
  for (const ent of ents) {
4032
4580
  const rel = relDir ? relDir + "/" + ent.name : ent.name;
4033
4581
  if (ent.isDirectory && ent.isDirectory()) {
4034
- __vfsDirs[destK + "/" + rel] = true;
4582
+ await _mkdirAsync("/" + destK + "/" + rel, { recursive: true });
4035
4583
  await walk(rel);
4036
4584
  } else {
4037
4585
  await _writeFileAsync("/" + destK + "/" + rel, await _readFileAsync(srcAbs + "/" + rel));
@@ -4204,7 +4752,7 @@ const __fsMod = (() => {
4204
4752
  openSync, closeSync, readSync, writeSync, fstatSync, ftruncateSync, fsyncSync, fdatasyncSync,
4205
4753
  futimesSync, fchmodSync, fchownSync, readvSync, writevSync,
4206
4754
  open, close, read, write, fstat, ftruncate, fsync, fdatasync, fchmod, futimes, readv, writev,
4207
- readFile, writeFile, appendFile, stat, lstat, readdir, exists, mkdir, unlink, rename, utimes, lutimes, chmod, lchmod, chown, lchown, fchown, access,
4755
+ readFile, writeFile, appendFile, stat, lstat, readdir, exists, mkdir, unlink, rmdir, rename, utimes, lutimes, chmod, lchmod, chown, lchown, fchown, access,
4208
4756
  rm, cp, truncate, copyFile, mkdtemp, link, symlink, readlink, realpath, opendir, statfs,
4209
4757
  Dirent: __Dirent,
4210
4758
  Dir: __Dir,
@@ -4381,8 +4929,7 @@ const __NimbusRelayedWebSocket = (() => {
4381
4929
  // The barrier the whole relay exists for. Every frame is now a
4382
4930
  // supervisor reply, so it can carry the invalidation delta, and
4383
4931
  // user code runs only after the resident set has caught up.
4384
- const acquire = globalThis.__nimbusVfsAcquireBarrier;
4385
- if (typeof acquire === "function") await acquire();
4932
+ await __nimbusInboundBarrier();
4386
4933
  this._deliver(event);
4387
4934
  }
4388
4935
  }
@@ -6138,9 +6685,14 @@ const __undiciMod = (() => {
6138
6685
  // ── util module ────────────────────────────────────────────────────
6139
6686
  // ═══════════════════════════════════════════════════════════════════════
6140
6687
  const __utilMod = {
6141
- inspect: (o, opts) => { try { return JSON.stringify(o, null, 2); } catch { return String(o); } },
6142
- format: (fmt, ...a) => {
6143
- if (typeof fmt !== "string") return [fmt, ...a].map(__fmt).join(" ");
6688
+ inspect: (o, opts) => {
6689
+ if (o !== null && typeof o === "object" && __isErrorValue(o)) return __fmtError(o, new Set());
6690
+ try { return JSON.stringify(o, null, 2); } catch { return String(o); }
6691
+ },
6692
+ format: (...args) => {
6693
+ if (args.length === 0) return "";
6694
+ const [fmt, ...a] = args;
6695
+ if (typeof fmt !== "string") return args.map(__fmt).join(" ");
6144
6696
  let i = 0;
6145
6697
  return fmt.replace(/%[sdifjoO%]/g, (m) => {
6146
6698
  if (m === "%%") return "%";
@@ -6149,7 +6701,7 @@ const __utilMod = {
6149
6701
  if (m === "%s") return String(v);
6150
6702
  if (m === "%d" || m === "%i" || m === "%f") return Number(v).toString();
6151
6703
  if (m === "%j") { try { return JSON.stringify(v); } catch { return "[Circular]"; } }
6152
- if (m === "%o" || m === "%O") { try { return JSON.stringify(v, null, 2); } catch { return String(v); } }
6704
+ if (m === "%o" || m === "%O") return __utilMod.inspect(v);
6153
6705
  return String(v);
6154
6706
  }) + (i < a.length ? " " + a.slice(i).map(__fmt).join(" ") : "");
6155
6707
  },
@@ -6416,11 +6968,31 @@ const __utilMod = {
6416
6968
  // (set+restored by __loadModule per call). When set, the fallback becomes
6417
6969
  // "file:///" + __currentModulePath so relative URLs resolve against
6418
6970
  // the real on-VFS module location — restoring proper import.meta.url
6971
+ //
6972
+ // The leniency is scoped to calls that PASSED a base. `new URL(x)` with one
6973
+ // argument is Node's strict absolute-URL parse: it throws
6974
+ // TypeError [ERR_INVALID_URL] for anything that is not already a URL, and
6975
+ // that throw is load-bearing rather than incidental. Node's own ESM
6976
+ // resolver — and every vendored copy of it, including exsolve, which is what
6977
+ // `nuxt dev` resolves `@nuxt/kit` and `nuxt` with — spells the
6978
+ // bare-specifier test as
6979
+ // try { resolved = new URL(specifier); } catch { packageResolve(…); }
6980
+ // Swallowing the throw made `new URL("@nuxt/kit")` answer
6981
+ // file:///@nuxt/kit, so moduleResolve never reached packageResolve and
6982
+ // finalizeResolution stat'd /@nuxt/kit — the FILESYSTEM ROOT — instead of
6983
+ // walking <from>/node_modules. Two syscalls and every bare import in the
6984
+ // project was unresolvable. The bundler breakage this wrapper exists for
6985
+ // (`new URL(rel, import.meta.url)` where the rolldown/esbuild polyfill
6986
+ // reduced import.meta.url to null/undefined) is always a two-argument call,
6987
+ // so requiring the base argument keeps that fix and restores Node's
6988
+ // contract for the one-argument form. URL.canParse, which is bound
6989
+ // straight off the native constructor below, already answered false for
6990
+ // these strings; the constructor now agrees with it.
6419
6991
  (() => {
6420
6992
  const _Orig = globalThis.URL;
6421
6993
  class _Shim extends _Orig {
6422
6994
  constructor(input, base) {
6423
- if (base == null && typeof input === "string") {
6995
+ if (arguments.length >= 2 && base == null && typeof input === "string") {
6424
6996
  try { super(input); return; }
6425
6997
  catch {
6426
6998
  // X.5-M3: prefer current module path when known, so
@@ -7002,6 +7574,13 @@ const __childProcessMod = (() => {
7002
7574
  /**
7003
7575
  * Read-loop for a single fd. Long-polls cpReadOutput, pushes chunks
7004
7576
  * into the Readable via .push, handles closure.
7577
+ *
7578
+ * What the child printed, and that it closed the stream, is news from
7579
+ * another process, which may have written files before it printed. So a
7580
+ * reply that delivers anything takes the barrier first, and a 'data'
7581
+ * handler that reads what the child wrote reads it current. The poll sends
7582
+ * this process's ACQUIRE arguments and the reply carries the answer, so the
7583
+ * barrier costs no round trip of its own.
7005
7584
  */
7006
7585
  async function _runReadLoop(child, fd, stream, sinceSeqRef) {
7007
7586
  // Exponential backoff for idle children: start at 100ms, double up
@@ -7014,12 +7593,14 @@ const __childProcessMod = (() => {
7014
7593
  while (HAS_SUPERVISOR && child.pid && !child._streamsClosed) {
7015
7594
  try {
7016
7595
  const r = await __nimbusUseRpcResult(
7017
- __supervisor.cpReadOutput(child.pid, fd, sinceSeqRef.value, backoff),
7596
+ __supervisor.cpReadOutput(child.pid, fd, sinceSeqRef.value, backoff, __nimbusVfsAcquireArgs()),
7018
7597
  (result) => result,
7019
7598
  );
7020
- if (r && Array.isArray(r.chunks) && r.chunks.length > 0) {
7599
+ const chunks = r && Array.isArray(r.chunks) ? r.chunks : [];
7600
+ if (chunks.length > 0 || (r && r.closed)) await __nimbusInboundBarrier(r.acquired);
7601
+ if (chunks.length > 0) {
7021
7602
  backoff = 100; // reset — child is producing
7022
- for (const c of r.chunks) {
7603
+ for (const c of chunks) {
7023
7604
  // The queue hands back bytes; a Readable given a string would
7024
7605
  // encode it again.
7025
7606
  stream.write(__BufferMod.from(c.data));
@@ -7047,16 +7628,19 @@ const __childProcessMod = (() => {
7047
7628
 
7048
7629
  /**
7049
7630
  * Wait-loop: long-poll cpWait until the child reports exit. Emits
7050
- * 'exit' once stamped.
7631
+ * 'exit' once stamped, behind the barrier: a child's exit is how a parent
7632
+ * learns the files it wrote are there. Answered on the reply, as for the
7633
+ * child's output.
7051
7634
  */
7052
7635
  async function _runWaitLoop(child) {
7053
7636
  while (HAS_SUPERVISOR && child.pid && !child._exitFired) {
7054
7637
  try {
7055
7638
  const r = await __nimbusUseRpcResult(
7056
- __supervisor.cpWait(child.pid, 1000),
7639
+ __supervisor.cpWait(child.pid, 1000, __nimbusVfsAcquireArgs()),
7057
7640
  (result) => result,
7058
7641
  );
7059
7642
  if (r && r.done) {
7643
+ await __nimbusInboundBarrier(r.acquired);
7060
7644
  child.exitCode = r.exitCode;
7061
7645
  child.signalCode = r.signal;
7062
7646
  child._exitFired = true;
@@ -7237,7 +7821,7 @@ const __childProcessMod = (() => {
7237
7821
  * stdout/stderr/exit events fire. Callers like cross-spawn.sync
7238
7822
  * that read result.status get null until the spawn settles.
7239
7823
  * 3. When the parent facet's main drain settles __pendingIO before
7240
- * reportExit (facet-manager.ts), the result object's fields are
7824
+ * reportExit (facets/manager.ts), the result object's fields are
7241
7825
  * filled in by the time the supervisor sees the parent exit.
7242
7826
  *
7243
7827
  * Cross-spawn.sync's typical pattern is "const r = spawnSync(...);
@@ -7580,7 +8164,7 @@ function __makeProcessStdin() {
7580
8164
  // facet, so counting it as in-flight work would mean the entry drain
7581
8165
  // never sees the program finish.
7582
8166
  packet = await __nimbusUseRpcResultUnref(
7583
- __supervisor.cpReadStdin(liveChildPid, 1000),
8167
+ __supervisor.cpReadStdin(liveChildPid, 1000, __nimbusVfsAcquireArgs()),
7584
8168
  (result) => result,
7585
8169
  );
7586
8170
  readFailures = 0;
@@ -7597,6 +8181,18 @@ function __makeProcessStdin() {
7597
8181
  await new Promise((resolve) => setTimeout(resolve, 500));
7598
8182
  continue;
7599
8183
  }
8184
+ // A packet that delivers anything — input, its end, a signal, a resize
8185
+ // — hands the program news from outside it, and whatever sent the news
8186
+ // may have written files first (a shell's `echo v2 > f` before the
8187
+ // keystroke, the editor's save before the signal). So it takes the
8188
+ // barrier before any handler sees it. The poll sent this process's
8189
+ // ACQUIRE arguments and the packet carries the answer, so a keystroke
8190
+ // costs no round trip of its own. An empty poll delivers nothing and
8191
+ // costs nothing.
8192
+ if (packet && (packet.resize || packet.signal || packet.ended
8193
+ || (packet.data && packet.data.byteLength > 0))) {
8194
+ await __nimbusInboundBarrier(packet.acquired);
8195
+ }
7600
8196
  if (packet && packet.resize) {
7601
8197
  __nimbusTtyColumns = Number(packet.resize.columns) || __nimbusTtyColumns;
7602
8198
  __nimbusTtyRows = Number(packet.resize.rows) || __nimbusTtyRows;
@@ -7713,6 +8309,7 @@ function __makeProcessOutputStream(streamName) {
7713
8309
  errored: null,
7714
8310
  write(d, enc, cb) {
7715
8311
  if (typeof enc === "function") cb = enc;
8312
+ if (__nimbusProgramStopped) return true;
7716
8313
  // The reported result is text; decode the bytes at this edge only.
7717
8314
  const s = __nimbusOutText(streamName, __nimbusOutBytes(d, enc));
7718
8315
  if (streamName === "stderr") stderr += s;
@@ -7758,6 +8355,8 @@ function __makeProcessOutputStream(streamName) {
7758
8355
  function __nimbusReportProcessExit(code, reason) {
7759
8356
  if (__nimbusProcessExitReported) return;
7760
8357
  __nimbusProcessExitCode = Number(code ?? 0);
8358
+ __nimbusProgramStopped = true;
8359
+ try { if (typeof globalThis.__nimbusStopProgramTimers === "function") globalThis.__nimbusStopProgramTimers(); } catch {}
7761
8360
  try { if (__nimbusProcessExitResolve) __nimbusProcessExitResolve(__nimbusProcessExitCode); } catch {}
7762
8361
  // Generated lifecycle owners defer the terminal supervisor report until
7763
8362
  // their durability boundary has drained. Reporting here would retire the
@@ -7797,7 +8396,7 @@ const __processMod = {
7797
8396
  chdir: (d) => { cwd = __pathMod.resolve(cwd || "/home/user", d); },
7798
8397
  exit: (code) => {
7799
8398
  exitCode = code ?? 0;
7800
- try { __processEvents.emit("exit", exitCode); } catch {}
8399
+ __nimbusEmitExit(exitCode);
7801
8400
  __nimbusReportProcessExit(exitCode, "");
7802
8401
  throw new __ProcessExit(exitCode);
7803
8402
  },
@@ -8211,14 +8810,27 @@ builtins.http = (() => {
8211
8810
  return new __hostResponse("Nimbus: no HTTP server is listening in this process", { status: 502 });
8212
8811
  }
8213
8812
  const url = new URL(request.url);
8813
+ // The request carries the answer to its own barrier (below). It is
8814
+ // Nimbus's, not the program's, so the program does not see it.
8815
+ let delivered;
8816
+ try { delivered = JSON.parse(request.headers.get("X-Nimbus-Vfs-Acquired") || "null"); } catch {}
8214
8817
  const headers = {};
8215
- request.headers.forEach((v, k) => { headers[k] = v; });
8818
+ request.headers.forEach((v, k) => { if (k !== "x-nimbus-vfs-acquired") headers[k] = v; });
8216
8819
  // Bytes, not text: a UTF-8 decode corrupts every binary upload, and the
8217
8820
  // decoded string is not the TypedArray receiver Buffer methods require.
8218
8821
  let body = null;
8219
8822
  if (request.method !== "GET" && request.method !== "HEAD") {
8220
8823
  body = new Uint8Array(await request.arrayBuffer());
8221
8824
  }
8825
+ // A request is a resumption like any other, and often the second half of
8826
+ // a causal chain — `echo v2 > f; curl :3000` — so the handler runs behind
8827
+ // the barrier, after the body has arrived. Sited here, in the dispatch
8828
+ // every resident's server shares, not in a caller that happens to yield
8829
+ // through a barriered timer on the way. The supervisor routed it, so it
8830
+ // arrives with an answer, which is enough when no write preceded the
8831
+ // request since this process last caught up (session/rpc.ts
8832
+ // _acquireForRoutedRequest); otherwise the barrier asks.
8833
+ await __nimbusInboundBarrier(delivered);
8222
8834
  const res = server._handleRequest(url.pathname + url.search, request.method, headers, body);
8223
8835
  // Return once headers are known. A handler that never sends headers is
8224
8836
  // bounded by a header timeout (NOT a body-finish cap) so a hung handler
@@ -9053,38 +9665,12 @@ builtins["node:util/types"] = builtins["util/types"];
9053
9665
  // skips it via the same FACET_PROVIDED_PACKAGES list.
9054
9666
  builtins.undici = __undiciMod;
9055
9667
 
9056
- /**
9057
- * A cell's dynamic import() call.
9058
- *
9059
- * A cell is compiled with new Function, so an import() left in its body
9060
- * is the RUNTIME's: it resolves against the module map and hands back the
9061
- * platform's own builtins, not this process's. Real Vite reaches
9062
- * node:http that way (config.js:14968), got a server whose listen bound no
9063
- * port here, and the facet exited with no handles the moment boot returned.
9064
- *
9065
- * The ESM→CJS rewriter routes those calls here with the cell's own
9066
- * require, so resolution is the one the process already has. The result is
9067
- * shaped as a module namespace, since import() resolves to one and callers
9068
- * destructure named exports off it.
9069
- */
9070
- globalThis.__nimbusCellImport = (req, id) => Promise.resolve().then(() => {
9071
- const loaded = req(id);
9072
- if (loaded && (loaded.__esModule || loaded[Symbol.toStringTag] === "Module")) return loaded;
9073
- // A CJS module's exports ARE the namespace's named exports, with the whole
9074
- // object as the default export — what an ESM importer of a CJS module sees.
9075
- if (loaded && (typeof loaded === "object" || typeof loaded === "function")) {
9076
- const ns = Object.create(null);
9077
- for (const key of Object.keys(loaded)) ns[key] = loaded[key];
9078
- if (!("default" in ns)) ns.default = loaded;
9079
- Object.defineProperty(ns, Symbol.toStringTag, { value: "Module" });
9080
- return ns;
9081
- }
9082
- return { default: loaded };
9083
- });
9084
9668
  // ═══════════════════════════════════════════════════════════════════════
9085
9669
  // ── require() — full Node.js module resolution ─────────────────────
9086
9670
  // ═══════════════════════════════════════════════════════════════════════
9087
9671
  const __moduleCache = new Map();
9672
+ // package → why the package ABI policy says it cannot run here (wasm-swap-registry.ts).
9673
+ const __nimbusAbiAdvisories = new Map([["sharp","Native libvips bindings; not portable to Workers. … try: no Workers-compatible target — render server-side or use Cloudflare Images. For the wasm32 build see @img/sharp-wasm32 entry below."],["sqlite3","Native sqlite3 .node binding. … try: better-sqlite3-wasm (untested by Nimbus) or sql.js once wasm asset loading is available."],["better-sqlite3","Native sqlite .node binding. … try: better-sqlite3-wasm (untested by Nimbus) or @libsql/client if its subpath exports resolve in your project."],["canvas","Native Cairo bindings. … try: canvaskit-wasm (Skia -> WASM, canvas-API-compatible, ~7MB; untested by Nimbus) or @resvg/resvg-wasm for SVG."],["sodium-native","Native libsodium. … try: tweetnacl (pure JS, untested by Nimbus) or libsodium-wrappers (WASM, untested by Nimbus)."],["node-pty","PTY syscalls unavailable in workerd. … try: no Workers-compatible target — use the Nimbus built-in shell."],["robotjs","Desktop automation; sandboxed Workers cannot access OS UI. … try: no Workers-compatible target."],["electron","Embedded Chromium runtime; not applicable to Workers. … try: no Workers-compatible target."],["bcrypt","Native bcrypt; pure-JS bcryptjs has an equivalent sync API but the require() name differs and Nimbus does not yet support npm aliases. … try: change `require(\"bcrypt\")` to `require(\"bcryptjs\")`, then `npm install bcryptjs`. APIs are sync-compatible."],["argon2","Native Argon2 C bindings. … try: hash-wasm for argon2d, argon2i, and argon2id."],["node-sass","Native libsass; deprecated upstream. … try: sass (dart-sass, pure JS)."],["grpc","Deprecated native gRPC. … try: @grpc/grpc-js (pure JS, untested end-to-end in Nimbus)."],["@swc/core","Native Rust SWC. … try: @swc/wasm-web for transform/parse only; it does not provide the native Plugin API."],["prisma","Native query engine; not portable to Workers in this configuration. … try: @prisma/adapter-d1 (Prisma official Workers adapter, untested by Nimbus), or migrate to drizzle-orm + @libsql/client (untested by Nimbus)."],["@prisma/client","Same as `prisma` (native query engine). … try: @prisma/adapter-d1 (untested by Nimbus), or drizzle-orm + @libsql/client (untested)."],["puppeteer","Bundled Chromium binary (~150 MB). … try: no Workers-compatible target for the bundled binary — use puppeteer-core + Cloudflare Browser Rendering (untested by Nimbus)."],["playwright","Bundled browsers (~300 MB). … try: no Workers-compatible target for bundled browsers — use @playwright/test against a remote browser endpoint (untested by Nimbus)."],["sql.js","Installs but fails at runtime because dist/sql-wasm.wasm is not available to the runtime loader. … try: For SQL in Workers, consider Cloudflare D1 or @libsql/client."],["@swc/wasm-web","Installs but fails at runtime because its generated code path depends on workerd-blocked dynamic code generation. … try: For ESM transforms consider esbuild-wasm."],["@img/sharp-wasm32","WASM build of sharp; package is wasm32-cpu-only and libvips initThreads() requires pthread support unavailable in Workers. … try: wasm-vips may work for simple pipelines; for complex pipelines, render server-side and ship pixels."],["@napi-rs/canvas","Native bindings only (linux-x64-gnu/musl, darwin-arm64/x64, android-arm64, linux-arm64-gnu/musl, win32-x64-msvc, linux-arm-gnueabihf). No WASM build published. … try: canvaskit-wasm (Skia -> WASM, canvas-API-compatible, ~7MB; untested by Nimbus) or @resvg/resvg-wasm for SVG."],["@napi-rs/canvas-wasm32-wasi","@napi-rs/canvas does not publish a wasm32-wasi variant on npm (404). The @napi-rs/canvas project ships only native bindings. No WASM/WASI build exists. … try: canvaskit-wasm (Skia -> WASM, canvas-API-compatible; untested by Nimbus) or @resvg/resvg-wasm for SVG."],["@tailwindcss/oxide","Native Rust Tailwind v4 oxide engine; ships only platform-specific .node bindings plus a wasm32-wasi shard. workerd has no node:wasi, and bare native bindings cannot dlopen. … try: no Workers-compatible target — Tailwind v3 (`tailwindcss@^3`) is pure JS and works in Workers (untested by Nimbus). Tailwind v4 inherently requires the Rust oxide engine."],["lightningcss","Native Rust CSS parser; ships platform-specific .node bindings plus a wasm32-wasi-only `lightningcss-wasm` package. workerd has no node:wasi, and the package probes libc through child_process.execSync. … try: no Workers-compatible target today — postcss + cssnano (pure JS, untested by Nimbus) cover most lightningcss use cases. For CSS minification only: clean-css (pure JS, untested by Nimbus)."],["rolldown","Native Rust bundler that Vite 8 loads at startup. Its only non-native build, @rolldown/binding-wasm32-wasi, is a wasm32-wasip1-threads binary, and Workers run one thread per isolate with Atomics.wait disabled. … try: no Workers-compatible target — rolldown publishes no single-threaded build, so tools that load Vite 8 themselves (Astro 7) cannot start here."],["@rolldown/binding-wasm32-wasi","wasm32-wasip1-threads build of rolldown: it imports a shared memory and wasi thread-spawn, its Rust locks and thread parking execute memory.atomic.wait32, and its loader needs node:wasi and worker_threads. Workers run one thread per isolate with Atomics.wait disabled. … try: no Workers-compatible target — rolldown publishes no single-threaded build."]]);
9088
9674
 
9089
9675
  /**
9090
9676
  * Direct VFS bundle access for module resolution.
@@ -9110,24 +9696,8 @@ function __readFileOr(path, fallback) {
9110
9696
  }
9111
9697
  function __fileExists(path) {
9112
9698
  const k = path.replace(/^\/+/, "");
9113
- if (__vfsBundle && k in __vfsBundle) return true;
9114
- if (__vfsWrites && k in __vfsWrites) return true;
9115
- if (__vfsDirs && k in __vfsDirs) return true;
9116
- // Consult the uncapped manifest (directory shape) so resolution sees
9117
- // installed files whose content was excluded from the bounded snapshot
9118
- // (e.g. web-streams-polyfill's ponyfill/package.json, reached via a
9119
- // parent-relative main). Mirrors existsSync's manifest probe.
9120
- if (__vfsManifest) {
9121
- if (k in __vfsManifest) return true;
9122
- const slash = k.lastIndexOf("/");
9123
- const parent = slash >= 0 ? k.slice(0, slash) : "";
9124
- const name = slash >= 0 ? k.slice(slash + 1) : k;
9125
- const sib = __vfsManifest[parent];
9126
- if (sib && sib.indexOf(name) !== -1) return true;
9127
- }
9128
- // Check for directory by looking for any key with this prefix
9129
- if (__vfsBundle && __residentAnyUnder(k + "/")) return true;
9130
- return false;
9699
+ // The namespace answers exactly (vfs/facet-resident-store.ts).
9700
+ return __fsMod.existsSync("/" + k);
9131
9701
  }
9132
9702
  // W3.5 Fix A: strict-file membership probe. __fileExists also returns true for
9133
9703
  // directories (it has to — __resolveNodeModule and __resolveImportsField call
@@ -9139,26 +9709,8 @@ function __fileExists(path) {
9139
9709
  // the fastify ret/dist/types failure.
9140
9710
  function __pathIsFile(path) {
9141
9711
  const k = path.replace(/^\/+/, "");
9142
- if (__vfsBundle && k in __vfsBundle) return true;
9143
- if (__vfsWrites && k in __vfsWrites) return true;
9144
- // Consult the manifest as a strict-file probe: a name listed in its
9145
- // parent's manifest entry is a file (directories are manifest KEYS).
9146
- // This lets resolution find files whose content was excluded from the
9147
- // bounded snapshot without re-introducing the directory short-circuit
9148
- // (__vfsManifest[k] being a directory key is deliberately NOT matched).
9149
- if (__vfsManifest) {
9150
- const slash = k.lastIndexOf("/");
9151
- const parent = slash >= 0 ? k.slice(0, slash) : "";
9152
- const name = slash >= 0 ? k.slice(slash + 1) : k;
9153
- const sib = __vfsManifest[parent];
9154
- if (sib && sib.indexOf(name) !== -1 && !(k in __vfsManifest)) return true;
9155
- }
9156
- // Last resort: the full fs view (live SQLite VFS) for paths outside the
9157
- // bounded snapshot/manifest entirely — e.g. the /tmp/.npx-cache tree,
9158
- // which the project snapshot never covers. stat-as-file only.
9159
- try { const st = __fsMod.statSync("/" + k); if (st && st.isFile && st.isFile()) return true; } catch {}
9160
- // Deliberately does NOT consult __vfsDirs nor do the prefix scan.
9161
- return false;
9712
+ const st = __fsMod.statSync("/" + k, { throwIfNoEntry: false });
9713
+ return !!st && st.isFile();
9162
9714
  }
9163
9715
  function __resolveFile(base) {
9164
9716
  // Mirrors Node's LOAD_AS_FILE + LOAD_AS_DIRECTORY (require_2 spec):
@@ -9231,15 +9783,12 @@ function __resolveFile(base) {
9231
9783
  }
9232
9784
 
9233
9785
  // __compiledModules is defined at MODULE TOP LEVEL in the generator code
9234
- // (facet-manager.ts) so new Function() runs during module evaluation.
9786
+ // (facets/manager.ts) so new Function() runs during module evaluation.
9235
9787
 
9236
9788
  // ── Single-source-of-truth exports/imports resolver (W2) ───────────────
9237
9789
  // Emitted from src/_shared/exports-resolver.ts via getExportsResolverJS().
9238
9790
  // Declares: resolveExports, resolveConditionValue, resolvePackageEntry,
9239
9791
  // DEFAULT_ESM_CONDITIONS, DEFAULT_CJS_CONDITIONS.
9240
- // the prior hand-rolled __resolvePkgEntry only honoured top-level
9241
- // require|default|import and dropped subpath maps, wildcards, nested
9242
- // conditions, the imports field, and null-target enforcement.
9243
9792
 
9244
9793
  // ── exports-resolver.js (auto-generated; keep in sync with src/_shared/exports-resolver.ts) ──
9245
9794
  const DEFAULT_ESM_CONDITIONS = ['import', 'module', 'browser', 'default'];
@@ -9335,6 +9884,14 @@ function resolvePackageEntry(pkg, subpath, conditions) {
9335
9884
  }
9336
9885
  return subpath;
9337
9886
  }
9887
+
9888
+ function packageSelfReferenceSubpath(pkg, specifier) {
9889
+ if (!pkg || typeof pkg.name !== 'string' || pkg.name.length === 0) return null;
9890
+ if (pkg.exports === undefined || pkg.exports === null) return null;
9891
+ if (specifier === pkg.name) return '.';
9892
+ if (!specifier.startsWith(pkg.name + '/')) return null;
9893
+ return '.' + specifier.slice(pkg.name.length);
9894
+ }
9338
9895
  // ── end exports-resolver.js ────────────────────────────────────────────
9339
9896
 
9340
9897
 
@@ -9386,8 +9943,8 @@ function __resolvePkgSubpath(pkgDir, pkg, subpath) {
9386
9943
  }
9387
9944
  let entry = resolvePackageEntry(pkg, subpath, __NIMBUS_CJS_CONDITIONS);
9388
9945
  // X.5-F R3: ESM-condition fallback for pure-ESM packages whose
9389
- // dist/.mjs files were transformed to CJS by transformEsmInBundle
9390
- // at install time (facet-manager.ts:842, W3.5 Fix B). Without this,
9946
+ // dist/.mjs files were transformed to CJS
9947
+ // by transformEsmInBundle (facets/manager.ts). Without this,
9391
9948
  // packages like nuxt — whose exports map only contains
9392
9949
  // {types, import} for the root subpath — return null from the CJS
9393
9950
  // walk and dead-end with "Cannot find module 'nuxt'" even though
@@ -9430,10 +9987,6 @@ function __resolvePkgSubpath(pkgDir, pkg, subpath) {
9430
9987
  return __resolveFile(pkgDir + "/" + rel);
9431
9988
  }
9432
9989
 
9433
- /** Back-compat name used elsewhere in this file. */
9434
- function __resolvePkgEntry(pkgDir) {
9435
- return __resolvePkgSubpath(pkgDir, null, ".");
9436
- }
9437
9990
 
9438
9991
  /**
9439
9992
  * Resolve a bare specifier (e.g. "react", "@scope/pkg", "pkg/sub/path")
@@ -9482,32 +10035,23 @@ function __resolveNodeModule(name, fromDir) {
9482
10035
  }
9483
10036
 
9484
10037
  /**
9485
- * Resolve a #name imports-field specifier from the nearest enclosing
9486
- * package.json. Returns the resolved file or null.
10038
+ * Node's "package scope" of a directory (readPackageScope): the nearest
10039
+ * enclosing package.json, walking up from fromDir. The FIRST package.json
10040
+ * found is the scope, even when it lacks the field the caller wants — the
10041
+ * imports field and the self-reference rule both belong to the importing
10042
+ * module's own package, never to an ancestor past it. The walk never
10043
+ * crosses a node_modules directory: a file that sits directly under one
10044
+ * belongs to no package, not to the project above it. Returns { dir, pkg }
10045
+ * (pkg null when the file is unparseable) or null when no package.json
10046
+ * encloses fromDir.
9487
10047
  */
9488
- function __resolveImportsField(name, fromDir) {
9489
- // Walk up looking for the nearest package.json. Stop at the first one
9490
- // (Node spec: imports field of the importing module's package).
10048
+ function __nearestPackageScope(fromDir) {
9491
10049
  let dir = (fromDir || "").replace(/^\/+/, "");
9492
10050
  while (true) {
10051
+ if (dir === "node_modules" || dir.endsWith("/node_modules")) return null;
9493
10052
  const pkgJsonPath = (dir ? dir + "/" : "") + "package.json";
9494
10053
  if (__fileExists(pkgJsonPath)) {
9495
- const pkg = __readPkgJson(dir);
9496
- if (pkg && pkg.imports) {
9497
- const target = resolveExports(pkg.imports, name, __NIMBUS_CJS_CONDITIONS);
9498
- if (target) {
9499
- // Imports targets are relative to the package root (dir)
9500
- if (target.startsWith("./")) {
9501
- return __resolveFile((dir ? dir + "/" : "") + target.slice(2));
9502
- }
9503
- if (target.startsWith("/")) {
9504
- return __resolveFile(target.slice(1));
9505
- }
9506
- // Bare specifier — re-resolve as a node_module from this dir
9507
- return __resolveNodeModule(target, dir);
9508
- }
9509
- }
9510
- return null; // first package.json wins, even if no imports field
10054
+ return { dir, pkg: __readPkgJson(dir) };
9511
10055
  }
9512
10056
  if (!dir) return null;
9513
10057
  const lastSlash = dir.lastIndexOf("/");
@@ -9515,38 +10059,96 @@ function __resolveImportsField(name, fromDir) {
9515
10059
  }
9516
10060
  }
9517
10061
 
10062
+ /**
10063
+ * Resolve a #name imports-field specifier from the nearest enclosing
10064
+ * package.json. Returns the resolved file or null.
10065
+ */
10066
+ function __resolveImportsField(name, fromDir) {
10067
+ // First package.json wins, even if no imports field (Node spec: imports
10068
+ // field of the importing module's package).
10069
+ const scope = __nearestPackageScope(fromDir);
10070
+ if (!scope || !scope.pkg || !scope.pkg.imports) return null;
10071
+ const dir = scope.dir;
10072
+ const target = resolveExports(scope.pkg.imports, name, __NIMBUS_CJS_CONDITIONS);
10073
+ if (!target) return null;
10074
+ // Imports targets are relative to the package root (dir)
10075
+ if (target.startsWith("./")) {
10076
+ return __resolveFile((dir ? dir + "/" : "") + target.slice(2));
10077
+ }
10078
+ if (target.startsWith("/")) {
10079
+ return __resolveFile(target.slice(1));
10080
+ }
10081
+ // Bare specifier — re-resolve as a node_module from this dir
10082
+ return __resolveNodeModule(target, dir);
10083
+ }
10084
+
10085
+ /**
10086
+ * Node's LOAD_PACKAGE_SELF: a bare specifier naming the enclosing package
10087
+ * itself (`require('<its-name>')`, `require('<its-name>/sub')`) resolves
10088
+ * through that package's own `exports` map — only when the nearest
10089
+ * package.json has `exports` AND its `name` matches, and only through
10090
+ * `exports` (no main/index probing: a subpath the map does not expose is
10091
+ * not exported). Sits between the imports-field branch and the
10092
+ * node_modules walk, where Node puts it. Returns the resolved file or null.
10093
+ *
10094
+ * Conditions are the ones the node_modules walk uses for the same
10095
+ * require: the runtime's CJS set first, the ESM set when the map exposes
10096
+ * the subpath only under `import` (dynamic import() is lowered onto this
10097
+ * require chain, see __resolvePkgSubpath).
10098
+ *
10099
+ * Tri-state, as in Node: null when the rule does not apply (the caller
10100
+ * walks node_modules); { resolved: null } when the enclosing package claims
10101
+ * the name but its map does not expose the subpath or the target is
10102
+ * missing — Node throws ERR_PACKAGE_PATH_NOT_EXPORTED / MODULE_NOT_FOUND
10103
+ * there and never consults node_modules, so neither does the caller.
10104
+ */
10105
+ function __resolvePackageSelf(name, fromDir) {
10106
+ const scope = __nearestPackageScope(fromDir);
10107
+ if (!scope || !scope.pkg) return null;
10108
+ const subpath = packageSelfReferenceSubpath(scope.pkg, name);
10109
+ if (subpath === null) return null;
10110
+ let entry = resolveExports(scope.pkg.exports, subpath, __NIMBUS_CJS_CONDITIONS);
10111
+ if (entry == null) entry = resolveExports(scope.pkg.exports, subpath, DEFAULT_ESM_CONDITIONS);
10112
+ if (entry == null) return { resolved: null };
10113
+ return { resolved: __resolveFile((scope.dir ? scope.dir + "/" : "") + entry.replace(/^\.\/+/, "")) };
10114
+ }
10115
+
9518
10116
  // ═══════════════════════════════════════════════════════════════════════
9519
- // ── X.5-S: __mkCompiledFn — conditional-param-rename wrap for new Function
10117
+ // ── __mkCompiledFn — the request-time fallback compile ──────────────
9520
10118
  // ═══════════════════════════════════════════════════════════════════════
9521
- //
9522
- // vite's chunks/node.js (transitive bundle of open@10.2.0) contains the
9523
- // ESM idiom `const __dirname = path.dirname(fileURLToPath(import.meta.url))`.
9524
- // W3.5 Fix B's esbuild ESM→CJS transform preserves that line verbatim
9525
- // while substituting `import.meta` with `const import_meta = {}`. Wrapping
9526
- // the body in `new Function("exports","require","module","__filename","__dirname", code)`
9527
- // then collides at parse time:
9528
- //
9529
- // SyntaxError: Identifier '__dirname' has already been declared
9530
- //
9531
- // (VERIFY-23417C5 §4 #1 / X5M3-retro §"Next bucket".) The helper RENAMES
9532
- // the conflicting param to a placeholder name so the body's own
9533
- // `const __dirname` becomes the single declarer. We rename rather than
9534
- // drop because callers pass 5 positional arguments and dropping a slot
9535
- // would mis-align downstream slots (e.g. the USER_CODE wrap appends
9536
- // `console` / `process` / etc. after `__dirname`). Renaming preserves
9537
- // slot alignment while letting the body's binding win.
9538
- //
9539
- // Symmetric for `__filename` because open@10's idiom often emits both.
10119
+ // One definition, from core/_shared/compiled-fn.ts (interpolated above as
10120
+ // MK_COMPILED_FN_SOURCE); here it serves a cell the startup precompile set
10121
+ // did not include, where the runtime permits it. See that file for why the
10122
+ // collision is detected by compiling rather than by scanning the source.
10123
+
9540
10124
  function __mkCompiledFn(code) {
9541
- const reFn = /(?:^|\n|;)\s*(?:const|let|var)\s+__filename\s*=/m;
9542
- const reDn = /(?:^|\n|;)\s*(?:const|let|var)\s+__dirname\s*=/m;
9543
- const reRequire = /(?:^|\n|;)\s*(?:const|let|var)\s+require\s*=/m;
9544
- const fnName = reFn.test(code) ? "__filename__nimbus_unused" : "__filename";
9545
- const dnName = reDn.test(code) ? "__dirname__nimbus_unused" : "__dirname";
9546
- const requireName = reRequire.test(code) ? "require__nimbus_unused" : "require";
9547
- return new Function("exports", requireName, "module", fnName, dnName, code);
10125
+ // Node strips a leading shebang from every module before evaluation;
10126
+ // bin scripts are commonly bundled verbatim with their
10127
+ // "#!/usr/bin/env node" line, which is a SyntaxError under new Function.
10128
+ if (typeof code === "string" && code.charCodeAt(0) === 35 && code.charCodeAt(1) === 33) {
10129
+ const __nl = code.indexOf("\n");
10130
+ code = __nl >= 0 ? code.slice(__nl + 1) : "";
10131
+ }
10132
+ const __base = ["exports", "require", "module", "__filename", "__dirname"];
10133
+ const __params = __base.slice();
10134
+ let __error;
10135
+ // Each pass renames exactly the parameter the parser reported; a module
10136
+ // may declare more than one, so the loop runs once per slot at most.
10137
+ for (let __attempt = 0; __attempt <= __base.length; __attempt++) {
10138
+ try { return new Function(...__params, code); }
10139
+ catch (e) {
10140
+ __error = e;
10141
+ // V8 (workerd) and JavaScriptCore (bun, the unit tests) word it differently.
10142
+ const __m = /Identifier '([$\w]+)' has already been declared|Cannot declare a \w+ variable twice: '([$\w]+)'/.exec((e && e.message) || "");
10143
+ const __slot = __m ? __base.indexOf(__m[1] || __m[2]) : -1;
10144
+ if (__slot < 0 || __params[__slot] !== __base[__slot]) throw e;
10145
+ __params[__slot] = __base[__slot] + "__nimbus_unused";
10146
+ }
10147
+ }
10148
+ throw __error;
9548
10149
  }
9549
10150
 
10151
+
9550
10152
  function __exportsTarget(mod) {
9551
10153
  const value = mod.exports;
9552
10154
  if (value && (typeof value === "object" || typeof value === "function")) return value;
@@ -9597,11 +10199,12 @@ function __makeLoadingExports(mod) {
9597
10199
  * Load and execute a JS/JSON module from VFS.
9598
10200
  * Returns the module.exports value.
9599
10201
  */
9600
- function __loadModule(resolvedPath) {
9601
- if (__moduleCache.has(resolvedPath)) return __moduleCache.get(resolvedPath);
10202
+ function __loadModule(resolvedPath, evaluationKey = resolvedPath) {
10203
+ if (globalThis.__nimbusProfileStaged) globalThis.__nimbusProfileStaged.delete(String(resolvedPath).replace(/^\/+/, ""));
10204
+ if (__moduleCache.has(evaluationKey)) return __moduleCache.get(evaluationKey);
9602
10205
 
9603
10206
  const mod = { exports: {} };
9604
- __moduleCache.set(resolvedPath, __makeLoadingExports(mod));
10207
+ __moduleCache.set(evaluationKey, __makeLoadingExports(mod));
9605
10208
 
9606
10209
  const code = __readFileOr(resolvedPath, null);
9607
10210
  if (code === null) throw new Error("Cannot read module: " + resolvedPath);
@@ -9609,7 +10212,7 @@ function __loadModule(resolvedPath) {
9609
10212
  // JSON
9610
10213
  if (resolvedPath.endsWith(".json")) {
9611
10214
  mod.exports = JSON.parse(code);
9612
- __moduleCache.set(resolvedPath, mod.exports);
10215
+ __moduleCache.set(evaluationKey, mod.exports);
9613
10216
  return mod.exports;
9614
10217
  }
9615
10218
 
@@ -9632,6 +10235,16 @@ function __loadModule(resolvedPath) {
9632
10235
  // const import_meta = {}. Save+restore for recursive __loadModule.
9633
10236
  const __prevModulePath = globalThis.__currentModulePath;
9634
10237
  globalThis.__currentModulePath = resolvedPath;
10238
+ const moduleUrl = evaluationKey.startsWith("file:")
10239
+ ? evaluationKey : builtins.url.pathToFileURL("/" + resolvedPath).href;
10240
+ // Evaluation metadata lives on the module, not in source text. Keeping
10241
+ // it here preserves the five CommonJS arguments and captures the parent
10242
+ // even when import.meta.resolve is extracted and called later.
10243
+ const importMeta = Object.assign(Object.create(null), {
10244
+ url: moduleUrl,
10245
+ resolve: (specifier) => globalThis.__nimbusImportMetaResolve(specifier, moduleUrl),
10246
+ });
10247
+ Object.defineProperty(mod, "__nimbusImportMeta", { value: importMeta });
9635
10248
  try {
9636
10249
  // Use pre-compiled function from startup (new Function allowed at module eval time)
9637
10250
  // Normalize path to match VFS bundle key format (no leading /)
@@ -9656,7 +10269,7 @@ function __loadModule(resolvedPath) {
9656
10269
  } catch (evalErr) {
9657
10270
  // W3.5 Fix C: if the file was in the bundle but its pre-compile
9658
10271
  // failed at facet startup, surface the original SyntaxError
9659
- // instead of the misleading "file was not pre-bundled" text.
10272
+ // instead of the misleading "not in this launch's module map" text.
9660
10273
  const normalizedPath2 = resolvedPath.replace(/^\/+/, "");
9661
10274
  const compileErr =
9662
10275
  (typeof __compileFailures !== "undefined" && __compileFailures &&
@@ -9668,22 +10281,27 @@ function __loadModule(resolvedPath) {
9668
10281
  );
9669
10282
  }
9670
10283
  if (evalErr.message && evalErr.message.includes("Code generation from strings disallowed")) {
9671
- throw new Error("Cannot load module '" + resolvedPath + "': file was not pre-bundled. Add it to the VFS bundle.");
10284
+ // Not a read miss (the text is here) and nothing in the process can
10285
+ // answer it, so it is kept apart from the read ledger that settles those.
10286
+ (globalThis.__nimbusModuleMisses ??= new Set()).add(normalizedPath2);
10287
+ throw new Error("Cannot load module '" + resolvedPath + "': it was not in this launch's module map; the next launch of the same command stages it.");
9672
10288
  }
9673
10289
  throw evalErr;
9674
10290
  }
9675
10291
  }
9676
10292
  } catch (e) {
9677
- __moduleCache.delete(resolvedPath);
10293
+ __moduleCache.delete(evaluationKey);
9678
10294
  if (e && typeof e === "object" && !e.__nimbusModulePath) {
9679
10295
  try {
9680
- e.__nimbusModulePath = resolvedPath;
9681
- if (typeof e.message === "string") {
9682
- e.message += "\nNimbus module: " + resolvedPath;
9683
- }
9684
- if (typeof e.stack === "string" && !e.stack.includes("Nimbus module:")) {
9685
- e.stack += "\nNimbus module: " + resolvedPath;
9686
- }
10296
+ Object.defineProperty(e, "__nimbusModulePath", { value: resolvedPath, configurable: true, writable: true });
10297
+ const at = resolvedPath.lastIndexOf("node_modules/");
10298
+ const parts = at < 0 ? [] : resolvedPath.slice(at + 13).split("/");
10299
+ const pkg = parts[0] && parts[0].startsWith("@") ? parts[0] + "/" + parts[1] : parts[0];
10300
+ const advisory = pkg ? __nimbusAbiAdvisories.get(pkg) : undefined;
10301
+ const note = "\nNimbus module: " + resolvedPath
10302
+ + (advisory ? "\nNimbus: " + pkg + " has no Workers-compatible build: " + advisory : "");
10303
+ if (typeof e.message === "string") e.message += note;
10304
+ if (typeof e.stack === "string" && !e.stack.includes("Nimbus module:")) e.stack += note;
9687
10305
  } catch {}
9688
10306
  }
9689
10307
  throw e;
@@ -9692,7 +10310,7 @@ function __loadModule(resolvedPath) {
9692
10310
  }
9693
10311
 
9694
10312
  // Update cache with final exports (module.exports may have been reassigned)
9695
- __moduleCache.set(resolvedPath, mod.exports);
10313
+ __moduleCache.set(evaluationKey, mod.exports);
9696
10314
  return mod.exports;
9697
10315
  }
9698
10316
 
@@ -9701,6 +10319,25 @@ function __loadModule(resolvedPath) {
9701
10319
  * Returns the resolved VFS path, or null.
9702
10320
  */
9703
10321
  function __resolveFrom(id, fromDir) {
10322
+ // An absolute file: URL is a specifier Node accepts: `import(href)` is the
10323
+ // portable way to load a path a resolver just handed back, and it is what
10324
+ // every package that resolves before it imports emits — @nuxt/cli's
10325
+ // loadKit does `import(pathToFileURL(resolveModulePath('@nuxt/kit', …)).href)`.
10326
+ // The ESM→CJS transform funnels those imports through this one resolver, so
10327
+ // the scheme has to come off before the specifier is classified: with it on,
10328
+ // the file: URL misses the absolute-path branch below and gets looked up as
10329
+ // if it were the name of a package.
10330
+ if (typeof id === "string" && id.startsWith("file:")) {
10331
+ let filePath;
10332
+ try {
10333
+ const u = new URL(id);
10334
+ // .pathname drops the query a cache-busting importer appends
10335
+ // (`import(href + "?t=" + Date.now())` is the standard HMR spelling),
10336
+ // and the decode is what node:url's fileURLToPath does with it.
10337
+ filePath = decodeURIComponent(u.pathname);
10338
+ } catch { filePath = id.replace(/^file:\/\//, ""); }
10339
+ id = filePath;
10340
+ }
9704
10341
  // X.5-P: literal "." / ".." are CommonJS aliases for "./" / "../".
9705
10342
  // Pre-fix they slipped past the startsWith("./")/("../") guards (which
9706
10343
  // require >= 3 / >= 4 chars respectively) and fell into the bare-spec
@@ -9730,43 +10367,634 @@ function __resolveFrom(id, fromDir) {
9730
10367
  if (id.startsWith("#")) {
9731
10368
  return __resolveImportsField(id, fromDir);
9732
10369
  }
9733
- // Bare specifier → node_modules resolution
10370
+ // Bare specifier: the enclosing package's own name resolves through its
10371
+ // exports map (Node's LOAD_PACKAGE_SELF), then node_modules resolution.
10372
+ // Once the enclosing package claims the name, its map is the whole
10373
+ // answer: a subpath it does not expose is not found, never a
10374
+ // node_modules copy's.
10375
+ const self = __resolvePackageSelf(id, fromDir);
10376
+ if (self) return self.resolved;
9734
10377
  return __resolveNodeModule(id, fromDir);
9735
10378
  }
9736
10379
 
9737
- globalThis.__nimbusImportMetaResolve = function __nimbusImportMetaResolve(specifier, parentUrl) {
9738
- const currentFromParent = typeof parentUrl === "string" && parentUrl.startsWith("file:")
9739
- ? parentUrl.replace(/^file:\/\/\/+/, "")
9740
- : "";
9741
- const current = currentFromParent || (
9742
- typeof globalThis.__currentModulePath === "string"
9743
- ? globalThis.__currentModulePath.replace(/^\/+/, "")
9744
- : ""
9745
- );
9746
- const fromDir = current.includes("/") ? current.substring(0, current.lastIndexOf("/")) : "";
9747
- const text = String(specifier);
9748
- if (text.startsWith("file:")) return text;
9749
- if (text.startsWith("./") || text.startsWith("../") || text.startsWith("/")) {
9750
- return new URL(text, current ? "file:///" + current : "file:///").href;
9751
- }
9752
- const resolved = __resolveFrom(text, fromDir);
9753
- // Node throws ERR_MODULE_NOT_FOUND rather than answering with the specifier
9754
- // it could not resolve, and packages are written against that: the standard
9755
- // shape is a try/catch that reports something the user can act on. Handing
9756
- // back the bare specifier passes the "unresolved" case off as a URL, so
9757
- // fileURLToPath downstream yields a path that was never on disk and the
9758
- // eventual error names a phantom file instead of the missing package.
9759
- // typescript@7 does exactly this: with the specifier echoed back it reports
9760
- // "Executable not found: @typescript/typescript-linux-x64/lib/tsc", where
9761
- // its own catch would have said the platform package is missing.
9762
- if (!resolved) {
9763
- const err = new Error(
9764
- "Cannot find package '" + text + "' imported from " + (current || fromDir || "<unknown>"),
10380
+ // ═══════════════════════════════════════════════════════════════════════
10381
+ // ── import() — Node's ESM loader ────────────────────────────────────
10382
+ // ═══════════════════════════════════════════════════════════════════════
10383
+ // A cell's dynamic import() reaches here with its module's URL
10384
+ // (core/runtime/dynamic-import-rewrite.ts). Resolution is Node's ESM
10385
+ // algorithm (core/_shared/esm-resolver.ts, interpolated below): the "import"
10386
+ // conditions, no extension probing, a directory refused by name, file: URLs,
10387
+ // Node's error codes and messages. What resolves loads through the same
10388
+ // module cache require uses, shaped as the namespace Node would give.
10389
+ // Node's builtins that exist only with the scheme; the rest of the table is
10390
+ // the process's own builtins, undici among them, which the process provides
10391
+ // in place of any installed copy (see builtins.undici above).
10392
+ const __ESM_SCHEME_ONLY_BUILTINS = new Set(["test", "test/reporters", "sqlite", "sea"]);
10393
+ // Node's ESM resolver (core/_shared/esm-resolver.ts, compiled once by
10394
+ // scripts/bundle-facet-workers.mjs): declares createEsmResolver.
10395
+ function createEsmResolver(host) {
10396
+ const conditions = new Set(["node", "import", "module-sync"]);
10397
+ const ask = {
10398
+ *kind(path) {
10399
+ const kind = yield host.kind(path);
10400
+ return kind === "file" || kind === "directory" ? kind : null;
10401
+ },
10402
+ *readText(path) {
10403
+ const text = yield host.readText(path);
10404
+ return typeof text === "string" ? text : null;
10405
+ },
10406
+ *realpath(path) {
10407
+ const real = yield host.realpath(path);
10408
+ return typeof real === "string" ? real : path;
10409
+ },
10410
+ *cjsResolve(specifier, parentPath) {
10411
+ const found = yield host.cjsResolve(specifier, parentPath);
10412
+ return typeof found === "string" ? found : null;
10413
+ }
10414
+ };
10415
+ function codedError(Ctor, code, message) {
10416
+ return Object.assign(new Ctor(message), { code });
10417
+ }
10418
+ const codeOf = (error) => error !== null && typeof error === "object" && "code" in error ? error.code : void 0;
10419
+ const filePath = (url) => decodeURIComponent(new URL(String(url)).pathname);
10420
+ const fileUrl = (path) => {
10421
+ const url = new URL("file://");
10422
+ url.pathname = path;
10423
+ return url;
10424
+ };
10425
+ function isRelativeSpecifier(specifier) {
10426
+ if (specifier[0] !== ".") return false;
10427
+ if (specifier.length === 1 || specifier[1] === "/") return true;
10428
+ return specifier[1] === "." && (specifier.length === 2 || specifier[2] === "/");
10429
+ }
10430
+ const isRelativeOrAbsolute = (specifier) => specifier !== "" && (specifier[0] === "/" || isRelativeSpecifier(specifier));
10431
+ function* readPackageConfig(pjsonPath, specifier, base) {
10432
+ const text = (yield* ask.kind(pjsonPath)) === "file" ? yield* ask.readText(pjsonPath) : null;
10433
+ if (text === null) return { exists: false, pjsonPath, type: "none" };
10434
+ let parsed;
10435
+ try {
10436
+ parsed = JSON.parse(text);
10437
+ } catch {
10438
+ throw codedError(
10439
+ Error,
10440
+ "ERR_INVALID_PACKAGE_CONFIG",
10441
+ `Invalid package config ${pjsonPath}` + (base ? ` while importing ${JSON.stringify(specifier)} from ${base}` : "") + "."
10442
+ );
10443
+ }
10444
+ const config = { exists: true, pjsonPath, type: "none" };
10445
+ if (parsed === null || typeof parsed !== "object") return config;
10446
+ if (typeof parsed.name === "string") config.name = parsed.name;
10447
+ if (typeof parsed.main === "string") config.main = parsed.main;
10448
+ if ("exports" in parsed) config.exports = parsed.exports;
10449
+ if (parsed.imports !== null && typeof parsed.imports === "object") config.imports = parsed.imports;
10450
+ if (parsed.type === "module" || parsed.type === "commonjs") config.type = parsed.type;
10451
+ return config;
10452
+ }
10453
+ function* packageScopeConfig(resolved) {
10454
+ let pjsonUrl = new URL("./package.json", resolved);
10455
+ while (true) {
10456
+ if (pjsonUrl.pathname.endsWith("node_modules/package.json")) break;
10457
+ const config = yield* readPackageConfig(filePath(pjsonUrl), resolved.href, void 0);
10458
+ if (config.exists) return config;
10459
+ const last = pjsonUrl;
10460
+ pjsonUrl = new URL("../package.json", pjsonUrl);
10461
+ if (pjsonUrl.pathname === last.pathname) break;
10462
+ }
10463
+ return { exists: false, pjsonPath: filePath(pjsonUrl), type: "none" };
10464
+ }
10465
+ function invalidPackageTarget(key, target, pjsonUrl, internal, base) {
10466
+ const text = typeof target === "object" && target !== null ? JSON.stringify(target, null, "") : `${target}`;
10467
+ const pkgPath = filePath(new URL(".", pjsonUrl));
10468
+ const related = !internal && text.length > 0 && !text.startsWith("./");
10469
+ const tail = `in the package config ${pkgPath}package.json imported from ${base}${related ? '; targets must start with "./"' : ""}`;
10470
+ return codedError(
10471
+ Error,
10472
+ "ERR_INVALID_PACKAGE_TARGET",
10473
+ key === "." ? `Invalid "exports" main target ${JSON.stringify(text)} defined ${tail}` : `Invalid "${internal ? "imports" : "exports"}" target ${JSON.stringify(text)} defined for '${key}' ${tail}`
9765
10474
  );
9766
- err.code = "ERR_MODULE_NOT_FOUND";
9767
- throw err;
9768
10475
  }
9769
- return "file:///" + resolved.replace(/^\/+/, "");
10476
+ const invalidSegment = /(^|\\|\/)((\.|%2e)(\.|%2e)?|(n|%6e|%4e)(o|%6f|%4f)(d|%64|%44)(e|%65|%45)(_|%5f)(m|%6d|%4d)(o|%6f|%4f)(d|%64|%44)(u|%75|%55)(l|%6c|%4c)(e|%65|%45)(s|%73|%53))?(\\|\/|$)/i;
10477
+ const deprecatedInvalidSegment = /(^|\\|\/)((\.|%2e)(\.|%2e)?|(n|%6e|%4e)(o|%6f|%4f)(d|%64|%44)(e|%65|%45)(_|%5f)(m|%6d|%4d)(o|%6f|%4f)(d|%64|%44)(u|%75|%55)(l|%6c|%4c)(e|%65|%45)(s|%73|%53))(\\|\/|$)/i;
10478
+ function* resolveTargetString(target, subpath, match, pjsonUrl, base, pattern, internal, isPathMap) {
10479
+ if (subpath !== "" && !pattern && target[target.length - 1] !== "/") {
10480
+ throw invalidPackageTarget(match, target, pjsonUrl, internal, base);
10481
+ }
10482
+ if (!target.startsWith("./")) {
10483
+ if (internal && !target.startsWith("../") && !target.startsWith("/")) {
10484
+ let isUrl = false;
10485
+ try {
10486
+ new URL(target);
10487
+ isUrl = true;
10488
+ } catch {
10489
+ }
10490
+ if (!isUrl) {
10491
+ const exportTarget = pattern ? target.replace(/\*/g, () => subpath) : target + subpath;
10492
+ return yield* packageResolve(exportTarget, pjsonUrl.href);
10493
+ }
10494
+ }
10495
+ throw invalidPackageTarget(match, target, pjsonUrl, internal, base);
10496
+ }
10497
+ if (invalidSegment.test(target.slice(2)) && deprecatedInvalidSegment.test(target.slice(2))) {
10498
+ throw invalidPackageTarget(match, target, pjsonUrl, internal, base);
10499
+ }
10500
+ const resolved = new URL(target, pjsonUrl);
10501
+ if (!resolved.pathname.startsWith(new URL(".", pjsonUrl).pathname)) {
10502
+ throw invalidPackageTarget(match, target, pjsonUrl, internal, base);
10503
+ }
10504
+ if (subpath === "") return resolved;
10505
+ if (invalidSegment.test(subpath) && deprecatedInvalidSegment.test(subpath) && !isPathMap) {
10506
+ const request = pattern ? match.replace("*", () => subpath) : match + subpath;
10507
+ throw codedError(
10508
+ TypeError,
10509
+ "ERR_INVALID_MODULE_SPECIFIER",
10510
+ `Invalid module "${request}" request is not a valid match in pattern "${match}" for the "${internal ? "imports" : "exports"}" resolution of ${filePath(pjsonUrl)} imported from ${base}`
10511
+ );
10512
+ }
10513
+ if (pattern) return new URL(resolved.href.replace(/\*/g, () => subpath));
10514
+ return new URL(subpath, resolved);
10515
+ }
10516
+ function* resolveTarget(pjsonUrl, target, subpath, key, base, pattern, internal, isPathMap) {
10517
+ if (typeof target === "string") {
10518
+ return yield* resolveTargetString(target, subpath, key, pjsonUrl, base, pattern, internal, isPathMap);
10519
+ }
10520
+ if (Array.isArray(target)) {
10521
+ if (target.length === 0) return null;
10522
+ let lastException;
10523
+ for (const item of target) {
10524
+ let result;
10525
+ try {
10526
+ result = yield* resolveTarget(pjsonUrl, item, subpath, key, base, pattern, internal, isPathMap);
10527
+ } catch (error) {
10528
+ lastException = error;
10529
+ if (codeOf(error) === "ERR_INVALID_PACKAGE_TARGET") continue;
10530
+ throw error;
10531
+ }
10532
+ if (result === void 0) continue;
10533
+ if (result === null) {
10534
+ lastException = null;
10535
+ continue;
10536
+ }
10537
+ return result;
10538
+ }
10539
+ if (lastException === void 0 || lastException === null) return lastException;
10540
+ throw lastException;
10541
+ }
10542
+ if (typeof target === "object" && target !== null) {
10543
+ const keys = Object.getOwnPropertyNames(target);
10544
+ for (const condition of keys) {
10545
+ if (/^\d+$/.test(condition) && String(Number(condition)) === condition && Number(condition) < 4294967295) {
10546
+ throw codedError(
10547
+ Error,
10548
+ "ERR_INVALID_PACKAGE_CONFIG",
10549
+ `Invalid package config ${filePath(pjsonUrl)} while importing ${fileUrl(base).href}. "exports" cannot contain numeric property keys.`
10550
+ );
10551
+ }
10552
+ }
10553
+ for (const condition of keys) {
10554
+ if (condition !== "default" && !conditions.has(condition)) continue;
10555
+ const result = yield* resolveTarget(
10556
+ pjsonUrl,
10557
+ Reflect.get(target, condition),
10558
+ subpath,
10559
+ key,
10560
+ base,
10561
+ pattern,
10562
+ internal,
10563
+ isPathMap
10564
+ );
10565
+ if (result === void 0) continue;
10566
+ return result;
10567
+ }
10568
+ return void 0;
10569
+ }
10570
+ if (target === null) return null;
10571
+ throw invalidPackageTarget(key, target, pjsonUrl, internal, base);
10572
+ }
10573
+ function patternKeyCompare(a, b) {
10574
+ const aStar = a.indexOf("*");
10575
+ const bStar = b.indexOf("*");
10576
+ const baseA = aStar === -1 ? a.length : aStar + 1;
10577
+ const baseB = bStar === -1 ? b.length : bStar + 1;
10578
+ if (baseA > baseB) return -1;
10579
+ if (baseB > baseA) return 1;
10580
+ if (aStar === -1) return 1;
10581
+ if (bStar === -1) return -1;
10582
+ if (a.length > b.length) return -1;
10583
+ if (b.length > a.length) return 1;
10584
+ return 0;
10585
+ }
10586
+ function bestPattern(map, name) {
10587
+ let best = "";
10588
+ let bestSubpath = "";
10589
+ for (const key of Object.getOwnPropertyNames(map)) {
10590
+ const star = key.indexOf("*");
10591
+ if (star === -1 || !name.startsWith(key.slice(0, star))) continue;
10592
+ const trailer = key.slice(star + 1);
10593
+ if (name.length >= key.length && name.endsWith(trailer) && patternKeyCompare(best, key) === 1 && key.lastIndexOf("*") === star) {
10594
+ best = key;
10595
+ bestSubpath = name.slice(star, name.length - trailer.length);
10596
+ }
10597
+ }
10598
+ return best ? { key: best, subpath: bestSubpath } : null;
10599
+ }
10600
+ function exportsNotFound(subpath, pjsonUrl, base) {
10601
+ const pkgPath = filePath(new URL(".", pjsonUrl));
10602
+ return codedError(
10603
+ Error,
10604
+ "ERR_PACKAGE_PATH_NOT_EXPORTED",
10605
+ subpath === "." ? `No "exports" main defined in ${pkgPath}package.json imported from ${base}` : `Package subpath '${subpath}' is not defined by "exports" in ${pkgPath}package.json imported from ${base}`
10606
+ );
10607
+ }
10608
+ function* packageExportsResolve(pjsonUrl, subpath, config, base) {
10609
+ let exports = config.exports;
10610
+ const isSugar = (() => {
10611
+ if (typeof exports === "string" || Array.isArray(exports)) return true;
10612
+ if (typeof exports !== "object" || exports === null) return false;
10613
+ let sugar = false;
10614
+ let i = 0;
10615
+ for (const key of Object.getOwnPropertyNames(exports)) {
10616
+ const current = key === "" || key[0] !== ".";
10617
+ if (i++ === 0) sugar = current;
10618
+ else if (sugar !== current) {
10619
+ throw codedError(
10620
+ Error,
10621
+ "ERR_INVALID_PACKAGE_CONFIG",
10622
+ `Invalid package config ${filePath(pjsonUrl)} while importing ${fileUrl(base).href}. "exports" cannot contain some keys starting with '.' and some not. The exports object must either be an object of package subpath keys or an object of main entry condition name keys only.`
10623
+ );
10624
+ }
10625
+ }
10626
+ return sugar;
10627
+ })();
10628
+ if (isSugar) exports = { ".": exports };
10629
+ const map = exports;
10630
+ if (Object.prototype.hasOwnProperty.call(map, subpath) && !subpath.includes("*") && !subpath.endsWith("/")) {
10631
+ const result = yield* resolveTarget(pjsonUrl, map[subpath], "", subpath, base, false, false, false);
10632
+ if (result == null) throw exportsNotFound(subpath, pjsonUrl, base);
10633
+ return result;
10634
+ }
10635
+ const best = bestPattern(map, subpath);
10636
+ if (best) {
10637
+ const result = yield* resolveTarget(pjsonUrl, map[best.key], best.subpath, best.key, base, true, false, subpath.endsWith("/"));
10638
+ if (result == null) throw exportsNotFound(subpath, pjsonUrl, base);
10639
+ return result;
10640
+ }
10641
+ throw exportsNotFound(subpath, pjsonUrl, base);
10642
+ }
10643
+ function* packageImportsResolve(name, baseUrl) {
10644
+ const base = filePath(baseUrl);
10645
+ if (name === "#" || name.startsWith("#/") || name.endsWith("/")) {
10646
+ throw codedError(TypeError, "ERR_INVALID_MODULE_SPECIFIER", `Invalid module "${name}" is not a valid internal imports specifier name imported from ${base}`);
10647
+ }
10648
+ const config = yield* packageScopeConfig(new URL(baseUrl));
10649
+ let pjsonUrl;
10650
+ if (config.exists) {
10651
+ pjsonUrl = fileUrl(config.pjsonPath);
10652
+ const imports = config.imports;
10653
+ if (imports) {
10654
+ if (Object.prototype.hasOwnProperty.call(imports, name) && !name.includes("*")) {
10655
+ const result = yield* resolveTarget(pjsonUrl, imports[name], "", name, base, false, true, false);
10656
+ if (result != null) return result;
10657
+ } else {
10658
+ const best = bestPattern(imports, name);
10659
+ if (best) {
10660
+ const result = yield* resolveTarget(pjsonUrl, imports[best.key], best.subpath, best.key, base, true, true, false);
10661
+ if (result != null) return result;
10662
+ }
10663
+ }
10664
+ }
10665
+ }
10666
+ const where = pjsonUrl ? ` in package ${filePath(new URL(".", pjsonUrl))}package.json` : "";
10667
+ throw codedError(TypeError, "ERR_PACKAGE_IMPORT_NOT_DEFINED", `Package import specifier "${name}" is not defined${where} imported from ${base}`);
10668
+ }
10669
+ function* legacyMainResolve(pjsonUrl, config, base) {
10670
+ const tries = [];
10671
+ if (config.main !== void 0) {
10672
+ for (const suffix of ["", ".js", ".json", ".node", "/index.js", "/index.json", "/index.node"]) tries.push(`./${config.main}${suffix}`);
10673
+ }
10674
+ tries.push("./index.js", "./index.json", "./index.node");
10675
+ for (const candidate of tries) {
10676
+ const url = new URL(candidate, pjsonUrl);
10677
+ if ((yield* ask.kind(filePath(url))) === "file") return url;
10678
+ }
10679
+ const dir = fileUrl(filePath(new URL(".", pjsonUrl)).replace(/\/+/g, "/"));
10680
+ const missing = filePath(new URL(config.main ?? "index.js", dir));
10681
+ throw codedError(Error, "ERR_MODULE_NOT_FOUND", `Cannot find package '${missing}' imported from ${base}`);
10682
+ }
10683
+ function* packageResolve(specifier, baseUrl) {
10684
+ if (host.isBuiltin(specifier)) return new URL("node:" + specifier);
10685
+ const base = filePath(baseUrl);
10686
+ let separator = specifier.indexOf("/");
10687
+ let valid = true;
10688
+ let scoped = false;
10689
+ if (specifier[0] === "@") {
10690
+ scoped = true;
10691
+ if (separator === -1 || specifier.length === 0) valid = false;
10692
+ else separator = specifier.indexOf("/", separator + 1);
10693
+ }
10694
+ const name = separator === -1 ? specifier : specifier.slice(0, separator);
10695
+ if (/^\.|%|\\/.test(name)) valid = false;
10696
+ if (!valid) {
10697
+ throw codedError(TypeError, "ERR_INVALID_MODULE_SPECIFIER", `Invalid module "${specifier}" is not a valid package name imported from ${base}`);
10698
+ }
10699
+ const subpath = "." + (separator === -1 ? "" : specifier.slice(separator));
10700
+ const self = yield* packageScopeConfig(new URL(baseUrl));
10701
+ if (self.exists && self.exports != null && self.name === name) {
10702
+ return yield* packageExportsResolve(fileUrl(self.pjsonPath), subpath, self, base);
10703
+ }
10704
+ let pjsonUrl = new URL("./node_modules/" + name + "/package.json", baseUrl);
10705
+ let pjsonPath = filePath(pjsonUrl);
10706
+ let lastPath;
10707
+ do {
10708
+ if ((yield* ask.kind(pjsonPath.slice(0, pjsonPath.length - 13))) !== "directory") {
10709
+ lastPath = pjsonPath;
10710
+ pjsonUrl = new URL((scoped ? "../../../../node_modules/" : "../../../node_modules/") + name + "/package.json", pjsonUrl);
10711
+ pjsonPath = filePath(pjsonUrl);
10712
+ continue;
10713
+ }
10714
+ const config = yield* readPackageConfig(pjsonPath, specifier, base);
10715
+ if (config.exports != null) return yield* packageExportsResolve(pjsonUrl, subpath, config, base);
10716
+ if (subpath === ".") return yield* legacyMainResolve(pjsonUrl, config, base);
10717
+ return new URL(subpath, pjsonUrl);
10718
+ } while (pjsonPath.length !== lastPath.length);
10719
+ throw codedError(Error, "ERR_MODULE_NOT_FOUND", `Cannot find package '${name}' imported from ${base}`);
10720
+ }
10721
+ function* formatOf(url, path) {
10722
+ const base = path.slice(path.lastIndexOf("/") + 1);
10723
+ const dot = base.lastIndexOf(".");
10724
+ const ext = dot > 0 ? base.slice(dot) : "";
10725
+ if (ext === ".mjs" || ext === ".mts") return "module";
10726
+ if (ext === ".cjs" || ext === ".cts") return "commonjs";
10727
+ if (ext === ".json") return "json";
10728
+ if (ext === ".js" || ext === ".ts" || ext === "") {
10729
+ const type = (yield* packageScopeConfig(url)).type;
10730
+ if (type === "module") return "module";
10731
+ if (type === "commonjs") return "commonjs";
10732
+ return "detect";
10733
+ }
10734
+ throw codedError(TypeError, "ERR_UNKNOWN_FILE_EXTENSION", `Unknown file extension "${ext}" for ${path}`);
10735
+ }
10736
+ function* finalizeResolution(resolved, baseUrl) {
10737
+ const base = filePath(baseUrl);
10738
+ if (/%2f|%5c/i.test(resolved.pathname)) {
10739
+ throw codedError(
10740
+ TypeError,
10741
+ "ERR_INVALID_MODULE_SPECIFIER",
10742
+ `Invalid module "${resolved.pathname}" must not include encoded "/" or "\\" characters imported from ${base}`
10743
+ );
10744
+ }
10745
+ const path = filePath(resolved);
10746
+ const kind = path.endsWith("/") ? "directory" : yield* ask.kind(path);
10747
+ if (kind === "directory") {
10748
+ throw Object.assign(
10749
+ codedError(Error, "ERR_UNSUPPORTED_DIR_IMPORT", `Directory import '${path}' is not supported resolving ES modules imported from ${base}`),
10750
+ { url: resolved.href }
10751
+ );
10752
+ }
10753
+ if (kind !== "file") {
10754
+ throw Object.assign(
10755
+ codedError(Error, "ERR_MODULE_NOT_FOUND", `Cannot find module '${path}' imported from ${base}`),
10756
+ { url: resolved.href }
10757
+ );
10758
+ }
10759
+ const real = yield* ask.realpath(path);
10760
+ const url = fileUrl(real);
10761
+ url.search = resolved.search;
10762
+ url.hash = resolved.hash;
10763
+ return { url: url.href, path: real };
10764
+ }
10765
+ function* moduleResolve(specifier, parentUrl) {
10766
+ let resolved;
10767
+ if (isRelativeOrAbsolute(specifier)) resolved = new URL(specifier, parentUrl);
10768
+ else if (specifier[0] === "#") resolved = yield* packageImportsResolve(specifier, parentUrl);
10769
+ else {
10770
+ try {
10771
+ resolved = new URL(specifier);
10772
+ } catch {
10773
+ resolved = yield* packageResolve(specifier, parentUrl);
10774
+ }
10775
+ }
10776
+ if (resolved.protocol === "node:") return { url: "node:" + resolved.pathname, builtin: resolved.pathname };
10777
+ if (resolved.protocol !== "file:") return { url: resolved.href };
10778
+ return yield* finalizeResolution(resolved, parentUrl);
10779
+ }
10780
+ function* loadable(resolved) {
10781
+ if (resolved.builtin !== void 0) {
10782
+ if (!host.isBuiltin("node:" + resolved.builtin)) {
10783
+ throw codedError(Error, "ERR_UNKNOWN_BUILTIN_MODULE", `No such built-in module: node:${resolved.builtin}`);
10784
+ }
10785
+ return { url: resolved.url, builtin: resolved.builtin, format: "builtin" };
10786
+ }
10787
+ if (resolved.url.startsWith("data:")) return { url: resolved.url, format: "data" };
10788
+ if (resolved.path === void 0) {
10789
+ throw codedError(
10790
+ Error,
10791
+ "ERR_UNSUPPORTED_ESM_URL_SCHEME",
10792
+ `Only URLs with a scheme in: file and data are supported by the default ESM loader. Received protocol '${new URL(resolved.url).protocol}'`
10793
+ );
10794
+ }
10795
+ return { url: resolved.url, path: resolved.path, format: yield* formatOf(new URL(resolved.url), resolved.path) };
10796
+ }
10797
+ function* commonJsHint(specifier, parentUrl) {
10798
+ let found = yield* ask.cjsResolve(specifier, filePath(parentUrl));
10799
+ if (found === null) return null;
10800
+ if (isRelativeSpecifier(specifier)) {
10801
+ const from = parentUrl.slice("file://".length, parentUrl.lastIndexOf("/")).split("/").filter(Boolean);
10802
+ const to = fileUrl(found).pathname.split("/").filter(Boolean);
10803
+ let common = 0;
10804
+ while (common < from.length && common < to.length && from[common] === to[common]) common++;
10805
+ found = [...from.slice(common).map(() => ".."), ...to.slice(common)].join("/");
10806
+ if (!found.startsWith("../")) found = `./${found}`;
10807
+ } else if (specifier[0] && specifier[0] !== "/" && specifier[0] !== ".") {
10808
+ const slash = specifier.indexOf("/");
10809
+ const pkg = slash === -1 ? specifier : specifier.slice(0, slash);
10810
+ const needle = `/node_modules/${pkg}/`;
10811
+ const at = found.lastIndexOf(needle);
10812
+ found = at !== -1 ? pkg + "/" + found.slice(at + needle.length).split("/").map(encodeURIComponent).join("/") : fileUrl(found).href;
10813
+ }
10814
+ return found;
10815
+ }
10816
+ function* resolveWithHint(specifier, parentUrl) {
10817
+ try {
10818
+ return yield* moduleResolve(specifier, parentUrl);
10819
+ } catch (error) {
10820
+ const code = codeOf(error);
10821
+ if (error instanceof Error && (code === "ERR_MODULE_NOT_FOUND" || code === "ERR_UNSUPPORTED_DIR_IMPORT")) {
10822
+ const asGiven = specifier.startsWith("file://") ? filePath(specifier) : specifier;
10823
+ const found = yield* commonJsHint(asGiven, parentUrl);
10824
+ if (found && found !== asGiven) error.message += `
10825
+ Did you mean to import ${JSON.stringify(found)}?`;
10826
+ }
10827
+ throw error;
10828
+ }
10829
+ }
10830
+ function* importTarget(specifier, parentUrl) {
10831
+ return yield* loadable(yield* resolveWithHint(specifier, parentUrl));
10832
+ }
10833
+ function* metaResolve(specifier, parentUrl) {
10834
+ try {
10835
+ return (yield* moduleResolve(specifier, parentUrl)).url;
10836
+ } catch (error) {
10837
+ const code = codeOf(error);
10838
+ if ((code === "ERR_MODULE_NOT_FOUND" || code === "ERR_UNSUPPORTED_DIR_IMPORT") && error !== null && typeof error === "object" && "url" in error && typeof error.url === "string") return error.url;
10839
+ throw error;
10840
+ }
10841
+ }
10842
+ function runSync(steps) {
10843
+ let next = steps.next();
10844
+ while (!next.done) {
10845
+ if (next.value instanceof Promise) throw new Error("resolveSync: the host answered asynchronously");
10846
+ next = steps.next(next.value);
10847
+ }
10848
+ return next.value;
10849
+ }
10850
+ return {
10851
+ async resolve(specifier, parentUrl) {
10852
+ const steps = importTarget(specifier, parentUrl);
10853
+ let next = steps.next();
10854
+ while (!next.done) {
10855
+ let answer;
10856
+ try {
10857
+ answer = await next.value;
10858
+ } catch (error) {
10859
+ next = steps.throw(error);
10860
+ continue;
10861
+ }
10862
+ next = steps.next(answer);
10863
+ }
10864
+ return next.value;
10865
+ },
10866
+ resolveSync: (specifier, parentUrl) => runSync(importTarget(specifier, parentUrl)),
10867
+ metaResolveSync: (specifier, parentUrl) => runSync(metaResolve(specifier, parentUrl)),
10868
+ validateAttributes(url, format, attributes) {
10869
+ for (const key of Object.keys(attributes)) {
10870
+ if (key !== "type") {
10871
+ throw codedError(TypeError, "ERR_IMPORT_ATTRIBUTE_UNSUPPORTED", `Import attribute "${key}" with value "${attributes[key]}" is not supported in ${url}`);
10872
+ }
10873
+ }
10874
+ const type = attributes.type;
10875
+ if (format === "json" || format === "data" && /^data:application\/json(?:;[^,]*)?,/.test(url)) {
10876
+ if (type === "json") return;
10877
+ if (!("type" in attributes)) {
10878
+ throw codedError(TypeError, "ERR_IMPORT_ATTRIBUTE_MISSING", `Module "${url}" needs an import attribute of "type: json"`);
10879
+ }
10880
+ } else if (type == null) {
10881
+ return;
10882
+ }
10883
+ if (typeof type !== "string") {
10884
+ throw codedError(TypeError, "ERR_INVALID_ARG_TYPE", `The "type" argument must be of type string. Received ${typeof type}`);
10885
+ }
10886
+ if (type !== "json") {
10887
+ throw codedError(TypeError, "ERR_IMPORT_ATTRIBUTE_UNSUPPORTED", `Import attribute "type" with value "${type}" is not supported in ${url}`);
10888
+ }
10889
+ throw codedError(TypeError, "ERR_IMPORT_ATTRIBUTE_TYPE_INCOMPATIBLE", `Module "${url}" is not of type "json"`);
10890
+ }
10891
+ };
10892
+ }
10893
+ const __esmResolver = createEsmResolver({
10894
+ kind(path) {
10895
+ const st = __fsMod.statSync(path, { throwIfNoEntry: false });
10896
+ return !st ? null : st.isDirectory() ? "directory" : st.isFile() ? "file" : null;
10897
+ },
10898
+ realpath(path) {
10899
+ try { return __fsMod.realpathSync(path); } catch { return path; }
10900
+ },
10901
+ readText(path) { return __readFileOr(path, null); },
10902
+ isBuiltin(specifier) {
10903
+ const scheme = specifier.startsWith("node:");
10904
+ const name = scheme ? specifier.slice(5) : specifier;
10905
+ if (!scheme && __ESM_SCHEME_ONLY_BUILTINS.has(name)) return false;
10906
+ return Object.prototype.hasOwnProperty.call(builtins, name);
10907
+ },
10908
+ cjsResolve(specifier, parentPath) {
10909
+ try {
10910
+ const dir = parentPath.slice(0, parentPath.lastIndexOf("/")).replace(/^\/+/, "");
10911
+ const found = __resolveFrom(specifier, dir);
10912
+ return found ? "/" + String(found).replace(/^\/+/, "") : null;
10913
+ } catch { return null; }
10914
+ },
10915
+ });
10916
+ const __esmNamespaces = new Map();
10917
+ /** A module namespace: its names sorted, read through to the exports. */
10918
+ function __esmNamespaceOf(names, read) {
10919
+ const ns = Object.create(null);
10920
+ for (const name of [...names].sort()) {
10921
+ Object.defineProperty(ns, name, { enumerable: true, get: () => read(name) });
10922
+ }
10923
+ Object.defineProperty(ns, Symbol.toStringTag, { value: "Module" });
10924
+ return Object.preventExtensions(ns);
10925
+ }
10926
+ function __esmLoad(resolution) {
10927
+ const cached = __esmNamespaces.get(resolution.url);
10928
+ if (cached) return cached;
10929
+ let ns;
10930
+ if (resolution.format === "builtin") {
10931
+ const mod = __requireFrom("node:" + resolution.builtin, "");
10932
+ const names = new Set(mod && (typeof mod === "object" || typeof mod === "function") ? Object.keys(mod) : []);
10933
+ names.add("default");
10934
+ ns = __esmNamespaceOf(names, (name) => name === "default" ? mod : mod[name]);
10935
+ } else if (resolution.format === "data") {
10936
+ const match = /^data:application\/json(;[^,]*)?,/.exec(resolution.url);
10937
+ if (!match) {
10938
+ throw Object.assign(new Error("Nimbus: a data: URL module can only be JSON here; code cannot be compiled after the process starts: " + resolution.url.slice(0, 64)), { code: "ERR_NIMBUS_DATA_MODULE" });
10939
+ }
10940
+ const body = resolution.url.slice(match[0].length);
10941
+ const value = JSON.parse(match[1] && match[1].includes(";base64") ? atob(body) : decodeURIComponent(body));
10942
+ ns = __esmNamespaceOf(["default"], () => value);
10943
+ } else {
10944
+ const key = resolution.path.replace(/^\/+/, "");
10945
+ const esm = resolution.format === "module"
10946
+ || (resolution.format === "detect" && globalThis.__nimbusEsmModules && globalThis.__nimbusEsmModules.has(key));
10947
+ // Canonical queryless ESM shares evaluation with require() and static
10948
+ // imports lowered to require(). Queries/fragments are distinct jobs.
10949
+ const variant = esm && (resolution.url.includes("?") || resolution.url.includes("#"));
10950
+ const exports = __loadModule(key, variant ? resolution.url : key);
10951
+ if (resolution.format === "json") {
10952
+ ns = __esmNamespaceOf(["default"], () => exports);
10953
+ } else if (esm) {
10954
+ // The ESM→CJS transform's exports: the module's own names, live.
10955
+ const names = exports && typeof exports === "object" ? Object.keys(exports).filter((name) => name !== "__esModule") : [];
10956
+ ns = __esmNamespaceOf(names, (name) => exports[name]);
10957
+ } else {
10958
+ // CommonJS: module.exports is the default, its names the named exports.
10959
+ const mod = exports;
10960
+ const names = new Set(mod && (typeof mod === "object" || typeof mod === "function") ? Object.keys(mod) : []);
10961
+ names.delete("default");
10962
+ names.add("default");
10963
+ ns = __esmNamespaceOf(names, (name) => name === "default" ? mod : mod[name]);
10964
+ }
10965
+ }
10966
+ __esmNamespaces.set(resolution.url, ns);
10967
+ return ns;
10968
+ }
10969
+ globalThis.__nimbusDynamicImport = function __nimbusDynamicImport(parentUrl, specifier, options) {
10970
+ return Promise.resolve().then(() => {
10971
+ const text = String(specifier);
10972
+ const attributes = {};
10973
+ // V8's own checks and messages (node 22), which run before resolution.
10974
+ if (options !== undefined) {
10975
+ if (options === null || typeof options !== "object") throw new TypeError("The second argument to import() must be an object");
10976
+ const withAttributes = options.with;
10977
+ if (withAttributes !== undefined) {
10978
+ if (withAttributes === null || typeof withAttributes !== "object") throw new TypeError("The 'assert' option must be an object");
10979
+ for (const key of Object.keys(withAttributes)) {
10980
+ if (typeof withAttributes[key] !== "string") throw new TypeError("Import assertion value must be a string");
10981
+ attributes[key] = withAttributes[key];
10982
+ }
10983
+ }
10984
+ }
10985
+ const resolution = __esmResolver.resolveSync(text, parentUrl);
10986
+ __esmResolver.validateAttributes(resolution.url, resolution.format, attributes);
10987
+ return __esmLoad(resolution);
10988
+ });
10989
+ };
10990
+
10991
+ // Node's import.meta.resolve, synchronous as in Node: the URL a specifier
10992
+ // names, even for a file or directory that will not load.
10993
+ globalThis.__nimbusImportMetaResolve = function __nimbusImportMetaResolve(specifier, parentUrl) {
10994
+ const parent = typeof parentUrl === "string" && parentUrl.startsWith("file:")
10995
+ ? parentUrl
10996
+ : "file:///" + String(globalThis.__currentModulePath || "[eval]").replace(/^\/+/, "");
10997
+ return __esmResolver.metaResolveSync(String(specifier), parent);
9770
10998
  };
9771
10999
 
9772
11000
  /**