@nimbus-sh/worker 0.8.0 → 0.10.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 (124) hide show
  1. package/dist/esbuild-wasm-bundle.generated.d.ts +24 -24
  2. package/dist/esbuild-wasm-bundle.generated.d.ts.map +1 -1
  3. package/dist/esbuild-wasm-bundle.generated.js +24 -24
  4. package/dist/facets/cirrus-real.js +3 -3
  5. package/dist/facets/compose.d.ts +3 -0
  6. package/dist/facets/compose.d.ts.map +1 -1
  7. package/dist/facets/compose.js +10 -3
  8. package/dist/facets/esbuild-bundle-pool.d.ts +1 -1
  9. package/dist/facets/esbuild-bundle-pool.js +3 -3
  10. package/dist/facets/esbuild-transform.d.ts +6 -2
  11. package/dist/facets/esbuild-transform.d.ts.map +1 -1
  12. package/dist/facets/esbuild-transform.js +8 -4
  13. package/dist/facets/manager.d.ts +54 -15
  14. package/dist/facets/manager.d.ts.map +1 -1
  15. package/dist/facets/manager.js +227 -144
  16. package/dist/facets/real-vite-hmr.d.ts +2 -0
  17. package/dist/facets/real-vite-hmr.d.ts.map +1 -1
  18. package/dist/facets/real-vite-hmr.js +3 -2
  19. package/dist/git/commands.d.ts +17 -1
  20. package/dist/git/commands.d.ts.map +1 -1
  21. package/dist/git/commands.js +73 -9
  22. package/dist/git/network-facet.d.ts +2 -0
  23. package/dist/git/network-facet.d.ts.map +1 -1
  24. package/dist/git/network-facet.js +10 -5
  25. package/dist/hosted/commands.d.ts.map +1 -1
  26. package/dist/hosted/commands.js +28 -39
  27. package/dist/hosted/runtime.d.ts +24 -2
  28. package/dist/hosted/runtime.d.ts.map +1 -1
  29. package/dist/hosted/runtime.js +70 -13
  30. package/dist/hosted/services.d.ts +14 -2
  31. package/dist/hosted/services.d.ts.map +1 -1
  32. package/dist/hosted/services.js +15 -2
  33. package/dist/loaders/generated-workers.d.ts +2 -2
  34. package/dist/loaders/generated-workers.d.ts.map +1 -1
  35. package/dist/loaders/generated-workers.js +4 -4
  36. package/dist/loaders/pre-bundle-preamble.d.ts +6 -3
  37. package/dist/loaders/pre-bundle-preamble.d.ts.map +1 -1
  38. package/dist/loaders/pre-bundle-preamble.js +13 -8
  39. package/dist/node-shims-artifact.generated.js +3 -3
  40. package/dist/npm/cache.d.ts +6 -1
  41. package/dist/npm/cache.d.ts.map +1 -1
  42. package/dist/npm/cache.js +8 -6
  43. package/dist/npm/install-batch-facet.d.ts +2 -0
  44. package/dist/npm/install-batch-facet.d.ts.map +1 -1
  45. package/dist/npm/install-batch-facet.js +29 -15
  46. package/dist/npm/installer.d.ts +8 -4
  47. package/dist/npm/installer.d.ts.map +1 -1
  48. package/dist/npm/installer.js +173 -113
  49. package/dist/npm/npx-install.d.ts +3 -1
  50. package/dist/npm/npx-install.d.ts.map +1 -1
  51. package/dist/npm/npx-install.js +4 -1
  52. package/dist/npm/placement.d.ts +16 -0
  53. package/dist/npm/placement.d.ts.map +1 -0
  54. package/dist/npm/placement.js +33 -0
  55. package/dist/npm/r2-cache.d.ts +10 -6
  56. package/dist/npm/r2-cache.d.ts.map +1 -1
  57. package/dist/npm/r2-cache.js +32 -16
  58. package/dist/npm/resolve-one-facet.d.ts +3 -0
  59. package/dist/npm/resolve-one-facet.d.ts.map +1 -1
  60. package/dist/npm/resolve-one-facet.js +1 -0
  61. package/dist/npm/resolver.d.ts +11 -6
  62. package/dist/npm/resolver.d.ts.map +1 -1
  63. package/dist/npm/resolver.js +12 -3
  64. package/dist/runtime/bash-repl.d.ts +5 -3
  65. package/dist/runtime/bash-repl.d.ts.map +1 -1
  66. package/dist/runtime/bash-repl.js +8 -3
  67. package/dist/runtime/cpython-resident.d.ts.map +1 -1
  68. package/dist/runtime/cpython-resident.js +2 -10
  69. package/dist/runtime/esbuild-wasm-bytes.d.ts +25 -18
  70. package/dist/runtime/esbuild-wasm-bytes.d.ts.map +1 -1
  71. package/dist/runtime/esbuild-wasm-bytes.js +55 -30
  72. package/dist/runtime/facet-loader-host.d.ts.map +1 -1
  73. package/dist/runtime/facet-loader-host.js +0 -9
  74. package/dist/runtime/node-shims.d.ts.map +1 -1
  75. package/dist/runtime/node-shims.js +853 -181
  76. package/dist/runtime/python-repl.d.ts +4 -3
  77. package/dist/runtime/python-repl.d.ts.map +1 -1
  78. package/dist/runtime/python-repl.js +10 -39
  79. package/dist/runtime/ruby-repl.d.ts +3 -2
  80. package/dist/runtime/ruby-repl.d.ts.map +1 -1
  81. package/dist/runtime/ruby-repl.js +7 -6
  82. package/dist/runtime/ruby-resident.d.ts.map +1 -1
  83. package/dist/runtime/ruby-resident.js +5 -16
  84. package/dist/runtime/runtime-catalog.js +1 -1
  85. package/dist/runtime/wasi/preamble.d.ts +0 -22
  86. package/dist/runtime/wasi/preamble.d.ts.map +1 -1
  87. package/dist/runtime/wasi/preamble.js +160 -1445
  88. package/dist/runtime-catalog.generated.js +1 -1
  89. package/dist/session/hibernation.d.ts +45 -2
  90. package/dist/session/hibernation.d.ts.map +1 -1
  91. package/dist/session/hibernation.js +78 -1
  92. package/dist/session/init.d.ts.map +1 -1
  93. package/dist/session/init.js +1 -0
  94. package/dist/session/nimbus-session.d.ts +16 -23
  95. package/dist/session/nimbus-session.d.ts.map +1 -1
  96. package/dist/session/nimbus-session.js +25 -36
  97. package/dist/session/npm-install-port.d.ts.map +1 -1
  98. package/dist/session/npm-install-port.js +1 -0
  99. package/dist/session/port-capability.d.ts.map +1 -1
  100. package/dist/session/port-capability.js +11 -1
  101. package/dist/session/programmatic.js +2 -2
  102. package/dist/session/routes.d.ts.map +1 -1
  103. package/dist/session/routes.js +4 -2
  104. package/dist/session/rpc.d.ts +7 -44
  105. package/dist/session/rpc.d.ts.map +1 -1
  106. package/dist/session/rpc.js +17 -67
  107. package/dist/session/supervisor-op.d.ts +8 -3
  108. package/dist/session/supervisor-op.d.ts.map +1 -1
  109. package/dist/session/supervisor-op.js +10 -45
  110. package/dist/session/supervisor-rpc.d.ts +47 -22
  111. package/dist/session/supervisor-rpc.d.ts.map +1 -1
  112. package/dist/session/supervisor-rpc.js +64 -26
  113. package/dist/vfs/facet-resident-store.d.ts.map +1 -1
  114. package/dist/vfs/facet-resident-store.js +4 -2
  115. package/dist/workspace-host.d.ts +2 -1
  116. package/dist/workspace-host.d.ts.map +1 -1
  117. package/dist/wrangler/nimbus-wrangler.d.ts.map +1 -1
  118. package/dist/wrangler/nimbus-wrangler.js +3 -0
  119. package/package.json +30 -4
  120. package/public/_assets/esbuild-0.24.2.js +2380 -0
  121. package/public/_assets/runtime/{node-shims-8f8c64edd2a1f0f5.js → node-shims-7b4dd7a76d95d21e.js} +852 -180
  122. package/scripts/bundle-esbuild-wasm.mjs +55 -39
  123. package/scripts/bundle-facet-workers.mjs +45 -7
  124. package/scripts/bundle-runtime.mjs +35 -8
@@ -569,6 +569,43 @@ function __residentAnyUnder(prefix) {
569
569
  return false;
570
570
  }
571
571
 
572
+ // ═══════════════════════════════════════════════════════════════════════
573
+ // ── fs.constants (linux x64) ───────────────────────────────────────
574
+ // ═══════════════════════════════════════════════════════════════════════
575
+ //
576
+ // The ONE table behind fs.constants, fs.promises.constants, and the fs slice
577
+ // of node:constants / process.binding('fs'). Values are real Node on Linux
578
+ // x64 (node -p 'require("fs").constants'). Packages compose open flags from
579
+ // this table at module init — modern-tar (create-astro via @bluwy/giget-core)
580
+ // computes O_WRONLY|O_CREAT|O_TRUNC|O_NOFOLLOW|O_EXCL and passes the number
581
+ // to fs.open — so a partial table silently degrades every such open to
582
+ // O_RDONLY (0) and every extraction fails ENOENT. Frozen, as Node's is.
583
+ const __fsConstants = Object.freeze({
584
+ // ── libuv fs flags ────────────────────────────────────────────────
585
+ UV_FS_SYMLINK_DIR: 1, UV_FS_SYMLINK_JUNCTION: 2,
586
+ // ── open(2) flags ─────────────────────────────────────────────────
587
+ O_RDONLY: 0, O_WRONLY: 1, O_RDWR: 2,
588
+ UV_DIRENT_UNKNOWN: 0, UV_DIRENT_FILE: 1, UV_DIRENT_DIR: 2, UV_DIRENT_LINK: 3,
589
+ UV_DIRENT_FIFO: 4, UV_DIRENT_SOCKET: 5, UV_DIRENT_CHAR: 6, UV_DIRENT_BLOCK: 7,
590
+ EXTENSIONLESS_FORMAT_JAVASCRIPT: 0, EXTENSIONLESS_FORMAT_WASM: 1,
591
+ // ── stat.mode file-type bits ──────────────────────────────────────
592
+ S_IFMT: 61440, S_IFREG: 32768, S_IFDIR: 16384, S_IFCHR: 8192,
593
+ S_IFBLK: 24576, S_IFIFO: 4096, S_IFLNK: 40960, S_IFSOCK: 49152,
594
+ O_CREAT: 64, O_EXCL: 128, UV_FS_O_FILEMAP: 0, O_NOCTTY: 256, O_TRUNC: 512,
595
+ O_APPEND: 1024, O_DIRECTORY: 65536, O_NOATIME: 262144, O_NOFOLLOW: 131072,
596
+ O_SYNC: 1052672, O_DSYNC: 4096, O_DIRECT: 16384, O_NONBLOCK: 2048,
597
+ // ── stat.mode permission bits ─────────────────────────────────────
598
+ S_IRWXU: 448, S_IRUSR: 256, S_IWUSR: 128, S_IXUSR: 64,
599
+ S_IRWXG: 56, S_IRGRP: 32, S_IWGRP: 16, S_IXGRP: 8,
600
+ S_IRWXO: 7, S_IROTH: 4, S_IWOTH: 2, S_IXOTH: 1,
601
+ // ── fs.access modes ───────────────────────────────────────────────
602
+ F_OK: 0, R_OK: 4, W_OK: 2, X_OK: 1,
603
+ // ── fs.copyFile modes (libuv shape + Node alias) ──────────────────
604
+ UV_FS_COPYFILE_EXCL: 1, COPYFILE_EXCL: 1,
605
+ UV_FS_COPYFILE_FICLONE: 2, COPYFILE_FICLONE: 2,
606
+ UV_FS_COPYFILE_FICLONE_FORCE: 4, COPYFILE_FICLONE_FORCE: 4,
607
+ });
608
+
572
609
  // ═══════════════════════════════════════════════════════════════════════
573
610
  // ── fs shim (VFS-backed) ───────────────────────────────────────────
574
611
  // ═══════════════════════════════════════════════════════════════════════
@@ -1206,6 +1243,10 @@ const __fsMod = (() => {
1206
1243
  mtimeMs: _coerceTimeMs(mtime, syscall, p),
1207
1244
  };
1208
1245
  _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; }
1209
1250
  return time;
1210
1251
  }
1211
1252
 
@@ -1347,6 +1388,27 @@ const __fsMod = (() => {
1347
1388
  return evicted;
1348
1389
  }
1349
1390
 
1391
+ // Cells an own-mutation lease evicted with no barrier in hand.
1392
+ //
1393
+ // A barrier hands _acquireAndRefetch every path it dropped, which is what
1394
+ // keeps a sync read inside a timer callback reading the peer's new bytes
1395
+ // instead of EAGAIN. A lease's end drops a cell on its own account — the
1396
+ // barrier that would have reported it was suppressed by the lease itself
1397
+ // — so the same debt is recorded here and settled by the next untrusted
1398
+ // resumption.
1399
+ const _owedRefetch = new Set();
1400
+
1401
+ // 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) => {
1407
+ if (!_evictResident(k)) return;
1408
+ _stats.invalidations++;
1409
+ _owedRefetch.add(k);
1410
+ };
1411
+
1350
1412
  /**
1351
1413
  * Install bytes the supervisor just served as the resident cell for a
1352
1414
  * path, at the cursor they were served under.
@@ -1526,6 +1588,11 @@ const __fsMod = (() => {
1526
1588
  } else if (Array.isArray(result.paths)) {
1527
1589
  for (const entry of result.paths) {
1528
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);
1529
1596
  if (__vfsBundleRevisions[k] >= entry.rev) { _stats.selfWrites++; continue; }
1530
1597
  const held = !!(__vfsBundle && k in __vfsBundle);
1531
1598
  if (_evictResident(k)) _stats.invalidations++;
@@ -1559,6 +1626,13 @@ const __fsMod = (() => {
1559
1626
  */
1560
1627
  async function _acquireAndRefetch(supervisor) {
1561
1628
  const stale = await _acquireBarrier(supervisor);
1629
+ // Plus what an own-mutation lease dropped since the last resumption:
1630
+ // the same debt this function exists to settle, owed by an eviction
1631
+ // that had no barrier to report it (see _owedRefetch).
1632
+ if (_owedRefetch.size > 0) {
1633
+ for (const k of _owedRefetch) if (stale.indexOf(k) === -1) stale.push(k);
1634
+ _owedRefetch.clear();
1635
+ }
1562
1636
  if (stale.length === 0) return;
1563
1637
  await Promise.all(stale.map((k) => _liveReadFile("/" + k, undefined, true).catch(() => {})));
1564
1638
  }
@@ -1659,7 +1733,16 @@ const __fsMod = (() => {
1659
1733
  // supervisor.mkdir is recursive, so the deepest unannounced one creates all
1660
1734
  // of them in a single round trip; a path whose directories are already live
1661
1735
  // (the common case) costs none at all.
1736
+ //
1737
+ // This is also the one seam every asynchronous fs entry point crosses on
1738
+ // its way to the authority — directly, or through
1739
+ // _flushLocalPathToSupervisor — so it is where a live call waits for the
1740
+ // structural mutations the program issued synchronously before it:
1741
+ // mkdirSync, rmdirSync, unlinkSync, renameSync queue their authority RPC
1742
+ // (below) rather than land it, and an open/stat/readdir that overtook that
1743
+ // queue would be answered for a tree the program has already changed.
1662
1744
  async function _announceLocalDirs(absPath, supervisor) {
1745
+ await _awaitStructuralOrder(absPath);
1663
1746
  if (!__vfsDirs || typeof supervisor.mkdir !== "function") return;
1664
1747
  const pending = [];
1665
1748
  let key = "";
@@ -1675,24 +1758,142 @@ const __fsMod = (() => {
1675
1758
  _markVfsStale();
1676
1759
  }
1677
1760
 
1761
+ // The write ledger is spliced ahead of the shims in every runner
1762
+ // (facets/manager.ts, opencode-facet-runner.ts). A harness that evaluates
1763
+ // the shims alone has no mutation queue and therefore nothing to wait for;
1764
+ // an absent ledger must not be an error on a read path that never needed
1765
+ // one before.
1766
+ function _hasVfsMutationQueue() {
1767
+ return typeof __nimbusQueueVfsMutation === "function";
1768
+ }
1769
+ function _awaitStructuralOrder(absPath) {
1770
+ return _hasVfsMutationQueue() ? __nimbusAwaitAncestorMutations(absPath) : Promise.resolve();
1771
+ }
1772
+
1773
+ /**
1774
+ * Carry a synchronous structural mutation to the authority.
1775
+ *
1776
+ * mkdirSync, rmdirSync, unlinkSync and renameSync used to edit the local
1777
+ * tables and stop: a sync syscall cannot make an RPC, and unlike a sync
1778
+ * write they parked nothing the write-back could later flush. Measured
1779
+ * live: node-tar's `mkdirSync(dir)` then `fs.promises.open(dir/file,
1780
+ * "w")` — once per extracted entry — was answered ENOENT by an authority
1781
+ * that had never heard of `dir`; that is create-astro's template copy.
1782
+ *
1783
+ * The sync effect stays exactly as it was. What is added is the same RPC
1784
+ * the asynchronous form of the call issues, queued through the write
1785
+ * ledger so it registers with the exit drain, is ordered behind pending
1786
+ * mutations of its ancestors (the ledger does that for every queued
1787
+ * mutation), and — for the two that act on a subtree — behind pending
1788
+ * mutations beneath it. The async forms are that same queued call, awaited.
1789
+ *
1790
+ * `null` when there is no authority to tell: standalone and unit contexts
1791
+ * keep today's local-only behaviour. Without a ledger the RPC is issued
1792
+ * directly, which is what the async forms did before they were queued.
1793
+ */
1794
+ // `method` names the supervisor RPC when it differs from the syscall the
1795
+ // caller reports (lchown rides `chown`, rm rides `fsRemove`).
1796
+ function _queueStructuralMutation(absPath, syscall, displayPath, rpc, after, method) {
1797
+ const supervisor = _supervisor();
1798
+ if (!supervisor || typeof supervisor[method || syscall] !== "function") return null;
1799
+ const queued = _hasVfsMutationQueue();
1800
+ const before = queued && after ? after() : null;
1801
+ const run = async () => {
1802
+ if (before) await before;
1803
+ // Only chown answers with a receipt. The rest (mkdir, unlink, rmdir,
1804
+ // rename, rm) have already dropped the path's cell and stamp in their
1805
+ // synchronous half, so no lease is taken at all; where one is — the
1806
+ // stamp unlink leaves behind — an absent receipt retires it, which is
1807
+ // what an unstamped cell already costs.
1808
+ await _ownMutation(
1809
+ absPath,
1810
+ () => _fsRpc(rpc(supervisor), syscall, displayPath, (result) => result),
1811
+ );
1812
+ _markVfsStale();
1813
+ };
1814
+ return queued ? __nimbusQueueVfsMutation(absPath, run) : run();
1815
+ }
1816
+
1817
+ /**
1818
+ * Run one of this facet's own partial mutations under a lease.
1819
+ *
1820
+ * See __nimbusBeginOwnMutation: the barrier KEEPS the cell while the RPC
1821
+ * is in flight — a barrier issued after this mutation can be answered
1822
+ * ahead of it, and an eviction there loses bytes no later stamp can
1823
+ * recover — and the receipt decides at the end. `apply` lands the local
1824
+ * effect while the lease still holds the cell, so the stamp the end
1825
+ * settles describes a cell that already carries the mutation.
1826
+ *
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.
1829
+ */
1830
+ async function _ownMutation(absPath, rpc, apply) {
1831
+ 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;
1846
+ }
1847
+
1848
+ // A sync caller has no frame to receive the outcome. The ledger already
1849
+ // marks a queued result handled and retains what the exit drain must
1850
+ // report; this only keeps a ledger-less embedding from raising an
1851
+ // unhandled rejection for a verdict nobody could catch.
1852
+ function _detachStructuralMutation(mutation) {
1853
+ if (mutation) mutation.then(undefined, () => undefined);
1854
+ }
1855
+
1856
+ // A rename lives at two names. Its mutation is queued under the source;
1857
+ // this parks a fence under the destination so that anything queued for the
1858
+ // destination, or an ancestor wait that passes through it, is ordered
1859
+ // behind the move as well. The fence never fails on its own account.
1860
+ function _fenceVfsMutation(absPath, mutation) {
1861
+ if (!mutation || !_hasVfsMutationQueue()) return;
1862
+ __nimbusQueueVfsMutation(absPath, () => mutation.then(() => undefined, () => undefined), false);
1863
+ }
1864
+
1865
+ // Queue the parked write for `absPath`, if any, on the path's mutation
1866
+ // tail. Registration is synchronous: a caller that queues its own mutation
1867
+ // on the same tail right after this call is ordered behind the flush.
1868
+ function _flushParkedWrite(absPath, supervisor) {
1869
+ const k = _strip(absPath);
1870
+ if (!__vfsWrites || !(k in __vfsWrites) || typeof supervisor.writeFile !== "function") {
1871
+ return Promise.resolve(undefined);
1872
+ }
1873
+ return __nimbusFlushVfsWrite(
1874
+ absPath,
1875
+ (content, snapshot) => _fsRpc(
1876
+ __nimbusPersistVfsWrite(supervisor, absPath, content, snapshot),
1877
+ "write", absPath,
1878
+ (result) => result,
1879
+ ),
1880
+ );
1881
+ }
1882
+
1678
1883
  async function _flushLocalPathToSupervisor(absPath, supervisor) {
1679
1884
  const k = _strip(absPath);
1680
1885
  await _announceLocalDirs(absPath, supervisor);
1681
1886
  if (__vfsWrites && k in __vfsWrites && typeof supervisor.writeFile === "function") {
1682
- await __nimbusFlushVfsWrite(
1683
- absPath,
1684
- (content, snapshot) => _fsRpc(
1685
- __nimbusPersistVfsWrite(supervisor, absPath, content, snapshot),
1686
- "write", absPath,
1687
- (result) => result,
1688
- ),
1689
- );
1887
+ await _flushParkedWrite(absPath, supervisor);
1690
1888
  _markVfsStale();
1691
1889
  }
1692
1890
  // Pending sync chmod rides along with any flush of the same path
1693
1891
  // (idempotent — the entry stays so local statSync remains coherent).
1694
1892
  if (k in _localModes && typeof supervisor.chmod === "function") {
1695
- await _fsRpc(supervisor.chmod(absPath, _localModes[k]), "chmod", absPath, () => undefined);
1893
+ await _ownMutation(
1894
+ absPath,
1895
+ () => _fsRpc(supervisor.chmod(absPath, _localModes[k]), "chmod", absPath, (result) => result),
1896
+ );
1696
1897
  _markVfsStale();
1697
1898
  }
1698
1899
  }
@@ -1787,16 +1988,26 @@ const __fsMod = (() => {
1787
1988
  return stat;
1788
1989
  }
1789
1990
 
1790
- function _direntObject(name, type) {
1791
- const isDir = type === "directory" || type === "dir";
1792
- const isSymlink = type === "symlink";
1793
- return {
1794
- name,
1795
- isFile: () => !isDir && !isSymlink,
1796
- isDirectory: () => isDir,
1797
- isSymbolicLink: () => isSymlink,
1798
- };
1991
+ // The one Dirent shape: readdir({ withFileTypes }) sync and async, and
1992
+ // every Dir.read(). `parentPath` is Node's field; `path` its deprecated
1993
+ // alias that older callers still read.
1994
+ class __Dirent {
1995
+ constructor(name, type, parentPath) {
1996
+ this.name = name;
1997
+ this.parentPath = parentPath === undefined ? "" : String(parentPath);
1998
+ this.path = this.parentPath;
1999
+ this._isDir = type === "directory" || type === "dir";
2000
+ this._isSymlink = type === "symlink";
2001
+ }
2002
+ isFile() { return !this._isDir && !this._isSymlink; }
2003
+ isDirectory() { return this._isDir; }
2004
+ isSymbolicLink() { return this._isSymlink; }
2005
+ isBlockDevice() { return false; }
2006
+ isCharacterDevice() { return false; }
2007
+ isFIFO() { return false; }
2008
+ isSocket() { return false; }
1799
2009
  }
2010
+ function _direntObject(name, type, parentPath) { return new __Dirent(name, type, parentPath); }
1800
2011
 
1801
2012
  // Largest single ranged read issued against the supervisor. Every live
1802
2013
  // read path (read streams, whole-file async reads) is expressed as a
@@ -2060,7 +2271,7 @@ const __fsMod = (() => {
2060
2271
  }
2061
2272
  if (opts?.withFileTypes) {
2062
2273
  return entries
2063
- .map((entry) => _direntObject(entry.name, entry.type))
2274
+ .map((entry) => _direntObject(entry.name, entry.type, absPath))
2064
2275
  .sort((a, b) => a.name.localeCompare(b.name));
2065
2276
  }
2066
2277
  return entries.map((entry) => entry.name).sort();
@@ -2083,7 +2294,9 @@ const __fsMod = (() => {
2083
2294
  async function _readlinkAsync(p) {
2084
2295
  const supervisor = _supervisor();
2085
2296
  if (supervisor && typeof supervisor.readlink === "function") {
2086
- const target = await _fsRpc(supervisor.readlink(_resolve(p)), "readlink", p, (result) => result);
2297
+ const absPath = _resolve(p);
2298
+ await _awaitStructuralOrder(absPath);
2299
+ const target = await _fsRpc(supervisor.readlink(absPath), "readlink", p, (result) => result);
2087
2300
  if (target !== null && target !== undefined) return target;
2088
2301
  }
2089
2302
  throw _fsErr("EINVAL", "readlink", p);
@@ -2092,7 +2305,9 @@ const __fsMod = (() => {
2092
2305
  async function _symlinkAsync(target, path) {
2093
2306
  const supervisor = _supervisor();
2094
2307
  if (supervisor && typeof supervisor.symlink === "function") {
2095
- await _fsRpc(supervisor.symlink(String(target), _resolve(path)), "symlink", path, () => undefined);
2308
+ const absPath = _resolve(path);
2309
+ await _awaitStructuralOrder(absPath);
2310
+ await _fsRpc(supervisor.symlink(String(target), absPath), "symlink", path, () => undefined);
2096
2311
  _markVfsStale();
2097
2312
  return;
2098
2313
  }
@@ -2105,8 +2320,10 @@ const __fsMod = (() => {
2105
2320
  const supervisor = _supervisor();
2106
2321
  if (supervisor && typeof supervisor.writeFile === "function") {
2107
2322
  await _announceLocalDirs(absPath, supervisor);
2323
+ // The revision comes back so the ledger can stamp the cell: an async
2324
+ // whole write is the facet's own as much as a parked sync one is.
2108
2325
  await __nimbusFlushVfsWrite(absPath, (content) =>
2109
- _fsRpc(supervisor.writeFile(absPath, content), "write", p, () => undefined)
2326
+ _fsRpc(supervisor.writeFile(absPath, content), "write", p, (result) => result)
2110
2327
  );
2111
2328
  _markVfsStale();
2112
2329
  }
@@ -2129,41 +2346,13 @@ const __fsMod = (() => {
2129
2346
  _markVfsStale();
2130
2347
  }
2131
2348
 
2132
- async function _mkdirAsync(p, opts) {
2133
- mkdirSync(p, opts);
2134
- const supervisor = _supervisor();
2135
- if (supervisor && typeof supervisor.mkdir === "function") {
2136
- await _fsRpc(supervisor.mkdir(_resolve(p)), "mkdir", p, () => undefined);
2137
- _markVfsStale();
2138
- }
2139
- }
2140
-
2141
- async function _unlinkAsync(p) {
2142
- unlinkSync(p);
2143
- const supervisor = _supervisor();
2144
- if (supervisor && typeof supervisor.unlink === "function") {
2145
- await _fsRpc(supervisor.unlink(_resolve(p)), "unlink", p, () => undefined);
2146
- _markVfsStale();
2147
- }
2148
- }
2149
-
2150
- async function _rmdirAsync(p) {
2151
- rmdirSync(p);
2152
- const supervisor = _supervisor();
2153
- if (supervisor && typeof supervisor.rmdir === "function") {
2154
- await _fsRpc(supervisor.rmdir(_resolve(p)), "rmdir", p, () => undefined);
2155
- _markVfsStale();
2156
- }
2157
- }
2158
-
2159
- async function _renameAsync(oldP, newP) {
2160
- renameSync(oldP, newP);
2161
- const supervisor = _supervisor();
2162
- if (supervisor && typeof supervisor.rename === "function") {
2163
- await _fsRpc(supervisor.rename(_resolve(oldP), _resolve(newP)), "rename", oldP, () => undefined);
2164
- _markVfsStale();
2165
- }
2166
- }
2349
+ // The async structural calls ARE the sync ones, awaited: the same local
2350
+ // effect and the same queued authority RPC, so the two forms cannot
2351
+ // disagree about order, and a program mixing them sees one sequence.
2352
+ async function _mkdirAsync(p, opts) { await _mkdirQueued(p, opts); }
2353
+ async function _unlinkAsync(p) { await _unlinkQueued(p); }
2354
+ async function _rmdirAsync(p) { await _rmdirQueued(p); }
2355
+ async function _renameAsync(oldP, newP) { await _renameQueued(oldP, newP); }
2167
2356
 
2168
2357
  async function _truncateAsync(p, len) {
2169
2358
  const absPath = _resolve(p);
@@ -2181,6 +2370,9 @@ const __fsMod = (() => {
2181
2370
  (content, snapshot) =>
2182
2371
  __nimbusPersistVfsWrite(supervisor, absPath, content, snapshot),
2183
2372
  );
2373
+ // Persisting the append drops the resident cell (the ledger
2374
+ // refetches it on the next live read), so there is no cell to
2375
+ // trim or stamp behind this truncate.
2184
2376
  await __nimbusQueueVfsMutation(absPath, async () => {
2185
2377
  await flush;
2186
2378
  await _fsRpc(
@@ -2202,12 +2394,15 @@ const __fsMod = (() => {
2202
2394
  // Live file is the source of truth — supervisor trims only the
2203
2395
  // boundary chunk; ENOENT propagates when it does not exist.
2204
2396
  const generation = __vfsWriteGenerations[k];
2205
- await __nimbusQueueVfsMutation(absPath, () =>
2206
- _fsRpc(supervisor.fsTruncate(absPath, size), "truncate", p, () => undefined)
2207
- );
2208
- if (__vfsWriteGenerations[k] === generation && localCell !== undefined) {
2209
- _truncateLocalCell(absPath, size);
2210
- }
2397
+ await __nimbusQueueVfsMutation(absPath, () => _ownMutation(
2398
+ absPath,
2399
+ () => _fsRpc(supervisor.fsTruncate(absPath, size), "truncate", p, (result) => result),
2400
+ () => {
2401
+ if (__vfsWriteGenerations[k] === generation && localCell !== undefined) {
2402
+ _truncateLocalCell(absPath, size);
2403
+ }
2404
+ },
2405
+ ));
2211
2406
  _markVfsStale();
2212
2407
  return;
2213
2408
  }
@@ -2227,9 +2422,9 @@ const __fsMod = (() => {
2227
2422
  _recordLocalTimes(absPath, atime, mtime, "lutimes", p);
2228
2423
  }
2229
2424
 
2230
- async function _utimesAsync(p, atime, mtime, opts) {
2425
+ async function _utimesAsync(p, atime, mtime, opts, syscallOverride) {
2231
2426
  const followSymlinks = !(opts && opts.followSymlinks === false);
2232
- const syscall = followSymlinks ? "utimes" : "lutimes";
2427
+ const syscall = syscallOverride || (followSymlinks ? "utimes" : "lutimes");
2233
2428
  const absPath = _resolve(p);
2234
2429
  const supervisor = _supervisor();
2235
2430
  let localExists = false;
@@ -2240,11 +2435,16 @@ const __fsMod = (() => {
2240
2435
  const time = _recordLocalTimes(absPath, atime, mtime, syscall, p);
2241
2436
  if (supervisor && typeof supervisor.utimes === "function") {
2242
2437
  await _flushLocalPathToSupervisor(absPath, supervisor);
2243
- await _fsRpc(
2438
+ // Ordered behind the path's pending mutations: an fd write queued a
2439
+ // moment ago (modern-tar writes, then futimes, then closes) would
2440
+ // otherwise land AFTER the timestamp and reset it to "now".
2441
+ const leased = () => _ownMutation(absPath, () => _fsRpc(
2244
2442
  supervisor.utimes(absPath, time.atimeMs, time.mtimeMs),
2245
2443
  syscall, p,
2246
- () => undefined,
2247
- );
2444
+ (result) => result,
2445
+ ));
2446
+ if (_hasVfsMutationQueue()) await __nimbusQueueVfsMutation(absPath, leased);
2447
+ else await leased();
2248
2448
  _markVfsStale();
2249
2449
  return;
2250
2450
  }
@@ -2294,11 +2494,46 @@ const __fsMod = (() => {
2294
2494
  const nextUid = _coerceId(uid, syscall, p);
2295
2495
  const nextGid = _coerceId(gid, syscall, p);
2296
2496
  await _flushLocalPathToSupervisor(absPath, supervisor);
2297
- await _fsRpc(supervisor.chown(absPath, nextUid, nextGid, opts), syscall, p, () => undefined);
2497
+ await _ownMutation(
2498
+ absPath,
2499
+ () => _fsRpc(supervisor.chown(absPath, nextUid, nextGid, opts), syscall, p, (result) => result),
2500
+ () => {
2501
+ const meta = _metadata(absPath);
2502
+ if (meta) { meta.uid = nextUid; meta.gid = nextGid; }
2503
+ },
2504
+ );
2505
+ _markVfsStale();
2506
+ }
2507
+
2508
+ // Sync ownership change: the stat record is updated locally at once and
2509
+ // the authority RPC is queued behind the path's pending flush, the same
2510
+ // parked model mkdirSync/unlinkSync use. Without an authority there is no
2511
+ // owner table to change, so the answer is the same ENOSYS as the async form.
2512
+ function _chownQueued(p, uid, gid, opts, syscall) {
2513
+ const followSymlinks = !(opts && opts.followSymlinks === false);
2514
+ const absPath = _resolve(p);
2515
+ const supervisor = _supervisor();
2516
+ if (!supervisor || typeof supervisor.chown !== "function") {
2517
+ if (!existsSync(p)) throw _fsErr("ENOENT", syscall, p);
2518
+ throw _fsErr("ENOSYS", syscall, p);
2519
+ }
2520
+ const nextUid = _coerceId(uid, syscall, p);
2521
+ const nextGid = _coerceId(gid, syscall, p);
2298
2522
  const meta = _metadata(absPath);
2299
2523
  if (meta) { meta.uid = nextUid; meta.gid = nextGid; }
2300
- _markVfsStale();
2524
+ // The parked write must be registered on the tail BEFORE the chown is
2525
+ // (a flush awaited from inside the queued step would queue behind it
2526
+ // and wait on itself), so it is the synchronous-registering flush.
2527
+ return _queueStructuralMutation(
2528
+ absPath, syscall, p,
2529
+ (s) => s.chown(absPath, nextUid, nextGid, followSymlinks ? undefined : { followSymlinks: false }),
2530
+ () => _flushParkedWrite(absPath, supervisor),
2531
+ "chown",
2532
+ );
2301
2533
  }
2534
+ function chownSync(p, uid, gid) { _detachStructuralMutation(_chownQueued(p, uid, gid, undefined, "chown")); }
2535
+ function lchownSync(p, uid, gid) { _detachStructuralMutation(_chownQueued(p, uid, gid, { followSymlinks: false }, "lchown")); }
2536
+ function lchmodSync(p, mode) { chmodSync(p, mode); }
2302
2537
 
2303
2538
  function _modeAllows(meta, want) {
2304
2539
  if (want === 0) return true;
@@ -2691,46 +2926,67 @@ const __fsMod = (() => {
2691
2926
  (!!__vfsDirs && fp in __vfsDirs) ||
2692
2927
  _metadata(fp)?.type === "directory" ||
2693
2928
  (!!__vfsBundle && __residentAnyUnder(fp + "/"));
2694
- return { name: n, isFile: () => !isDir, isDirectory: () => isDir, isSymbolicLink: () => false };
2929
+ return _direntObject(n, isDir ? "directory" : "file", absPath);
2695
2930
  });
2696
2931
  }
2697
2932
  return arr;
2698
2933
  }
2699
2934
 
2700
2935
  // ── mkdirSync ──
2701
- function mkdirSync(p, opts) {
2936
+ // The sync effect, then the authority mutation queued behind it (see
2937
+ // _queueStructuralMutation). One RPC whatever the depth: the async form
2938
+ // sends the path alone and the authority's mkdir creates the ancestors.
2939
+ function _mkdirQueued(p, opts) {
2702
2940
  const absPath = _resolve(p);
2703
2941
  const k = _strip(absPath);
2942
+ const created = [];
2704
2943
  if (opts?.recursive) {
2705
2944
  const parts = k.split("/").filter(Boolean);
2706
2945
  let cur = "";
2707
- for (const part of parts) { cur = cur ? cur + "/" + part : part; __vfsDirs[cur] = true; }
2946
+ for (const part of parts) { cur = cur ? cur + "/" + part : part; __vfsDirs[cur] = true; created.push(cur); }
2708
2947
  } else {
2709
2948
  __vfsDirs[k] = true;
2949
+ created.push(k);
2710
2950
  }
2951
+ const queued = _queueStructuralMutation(absPath, "mkdir", p, (supervisor) => supervisor.mkdir(absPath));
2952
+ // Told, not merely known locally: _announceLocalDirs must not issue a
2953
+ // second mkdir for a directory whose own RPC is already in the queue.
2954
+ if (queued) for (const dir of created) _announcedDirs.add(dir);
2955
+ return queued;
2711
2956
  }
2957
+ function mkdirSync(p, opts) { _detachStructuralMutation(_mkdirQueued(p, opts)); }
2712
2958
 
2713
2959
  // ── unlinkSync ──
2714
- function unlinkSync(p) {
2960
+ function _unlinkQueued(p) {
2715
2961
  const absPath = _resolve(p);
2716
2962
  const k = _strip(absPath);
2717
2963
  if (__vfsBundle) delete __vfsBundle[k];
2718
2964
  if (__vfsWrites) delete __vfsWrites[k];
2719
2965
  _forgetSyncPath(k);
2966
+ return _queueStructuralMutation(absPath, "unlink", p, (supervisor) => supervisor.unlink(absPath));
2720
2967
  }
2968
+ function unlinkSync(p) { _detachStructuralMutation(_unlinkQueued(p)); }
2721
2969
 
2722
2970
  // ── rmdirSync ──
2723
- function rmdirSync(p) {
2971
+ function _rmdirQueued(p) {
2724
2972
  const absPath = _resolve(p);
2725
2973
  const k = _strip(absPath);
2726
2974
  if (__vfsDirs) delete __vfsDirs[k];
2727
2975
  _forgetSyncPath(k);
2976
+ return _queueStructuralMutation(
2977
+ absPath, "rmdir", p,
2978
+ (supervisor) => supervisor.rmdir(absPath),
2979
+ () => __nimbusAwaitSubtreeMutations(absPath),
2980
+ );
2728
2981
  }
2982
+ function rmdirSync(p) { _detachStructuralMutation(_rmdirQueued(p)); }
2729
2983
 
2730
2984
  // ── renameSync ──
2731
- function renameSync(oldP, newP) {
2732
- const oldK = _strip(_resolve(oldP));
2733
- const newK = _strip(_resolve(newP));
2985
+ function _renameQueued(oldP, newP) {
2986
+ const oldAbs = _resolve(oldP);
2987
+ const newAbs = _resolve(newP);
2988
+ const oldK = _strip(oldAbs);
2989
+ const newK = _strip(newAbs);
2734
2990
  const content = __vfsBundle?.[oldK] ?? __vfsWrites?.[oldK];
2735
2991
  if (content !== undefined) {
2736
2992
  _parkWrite(newK, content);
@@ -2744,14 +3000,182 @@ const __fsMod = (() => {
2744
3000
  const moved = metadata ? metadata[oldK] : undefined;
2745
3001
  _forgetSyncPath(oldK);
2746
3002
  if (moved) metadata[newK] = moved;
2747
- }
3003
+ } else if (__vfsDirs && oldK in __vfsDirs) {
3004
+ // A directory this process made travels under its new name, so the
3005
+ // sync view stops listing the old one and _announceLocalDirs cannot
3006
+ // re-create it at the authority behind the rename.
3007
+ const prefix = oldK + "/";
3008
+ for (const dk of Object.keys(__vfsDirs)) {
3009
+ if (dk !== oldK && !dk.startsWith(prefix)) continue;
3010
+ const moved = newK + dk.slice(oldK.length);
3011
+ __vfsDirs[moved] = true;
3012
+ delete __vfsDirs[dk];
3013
+ if (_announcedDirs.has(dk)) _announcedDirs.add(moved);
3014
+ }
3015
+ _forgetSyncTree(oldK);
3016
+ }
3017
+ const queued = _queueStructuralMutation(
3018
+ oldAbs, "rename", oldP,
3019
+ (supervisor) => supervisor.rename(oldAbs, newAbs),
3020
+ // The queue orders the move behind the source's ancestors; the move
3021
+ // also needs the destination's ancestors to exist and every pending
3022
+ // mutation beneath the source to have landed under the old name.
3023
+ () => Promise.all([__nimbusAwaitAncestorMutations(newAbs), __nimbusAwaitSubtreeMutations(oldAbs)]),
3024
+ );
3025
+ _fenceVfsMutation(newAbs, queued);
3026
+ return queued;
2748
3027
  }
3028
+ function renameSync(oldP, newP) { _detachStructuralMutation(_renameQueued(oldP, newP)); }
2749
3029
 
2750
3030
  // ── copyFileSync ──
2751
- function copyFileSync(src, dest) {
2752
- writeFileSync(dest, readFileSync(src, "utf8"));
3031
+ // Bytes, not utf8: a utf8 round trip replaces every byte ≥ 0x80 with
3032
+ // U+FFFD, which is how a copied .png or .woff2 arrived corrupted.
3033
+ function copyFileSync(src, dest, mode) {
3034
+ if ((Number(mode) & __fsConstants.COPYFILE_EXCL) !== 0 && existsSync(dest)) {
3035
+ throw _fsErr("EEXIST", "copyfile", dest);
3036
+ }
3037
+ writeFileSync(dest, readFileSync(src));
3038
+ }
3039
+
3040
+ // ── rmSync / rm ──
3041
+ // The local tables are edited at once (the same retraction unlinkSync and
3042
+ // rmdirSync perform, over the whole subtree when recursive) and ONE
3043
+ // authority RPC — fsRemove, which the bridge serves as unlink or a bounded
3044
+ // recursive removal — is queued behind every pending mutation beneath the
3045
+ // path. ENOENT under `force` is the authority's to swallow; locally an
3046
+ // unknown path may still exist live, so it is asked rather than answered.
3047
+ function _rmQueued(p, opts, sync) {
3048
+ const o = opts || {};
3049
+ const absPath = _resolve(p);
3050
+ const k = _strip(absPath);
3051
+ const st = statSync(p, { throwIfNoEntry: false });
3052
+ const supervisor = _supervisor();
3053
+ const canRemove = !!supervisor && typeof supervisor.fsRemove === "function";
3054
+ if (st === undefined) {
3055
+ if (!canRemove) {
3056
+ if (o.force) return null;
3057
+ throw _fsErr("ENOENT", "rm", p);
3058
+ }
3059
+ // A path the sync view cannot map may still exist live (born after
3060
+ // boot). The async form asks the authority, whose ENOENT is the real
3061
+ // one; the sync form has no frame to receive that answer, so it gives
3062
+ // statSync's own provisional not-found unless `force` makes the
3063
+ // verdict irrelevant.
3064
+ if (sync && !o.force) throw _fsErr("ENOENT", "rm", p);
3065
+ }
3066
+ if (st !== undefined && st.isDirectory() && !o.recursive) {
3067
+ throw _fsErr("ERR_FS_EISDIR", "rm", p);
3068
+ }
3069
+ const prefix = k + "/";
3070
+ // A parked write is content the authority may never have seen: the
3071
+ // caller's file demonstrably existed here, so the removal succeeds, and
3072
+ // the authority is told "if present" rather than made to fail on a file
3073
+ // that was only ever local.
3074
+ let parked = false;
3075
+ if (__vfsBundle) {
3076
+ if (k in __vfsBundle) delete __vfsBundle[k];
3077
+ if (o.recursive) for (const bk of __residentUnder(prefix)) delete __vfsBundle[bk];
3078
+ }
3079
+ delete __vfsBundleRevisions[k];
3080
+ if (__vfsWrites) {
3081
+ for (const wk of Object.keys(__vfsWrites)) {
3082
+ if (wk === k || (o.recursive && wk.startsWith(prefix))) { delete __vfsWrites[wk]; parked = true; }
3083
+ }
3084
+ }
3085
+ if (__vfsDirs) {
3086
+ for (const dk of Object.keys(__vfsDirs)) {
3087
+ if (dk === k || (o.recursive && dk.startsWith(prefix))) delete __vfsDirs[dk];
3088
+ }
3089
+ }
3090
+ if (o.recursive) _forgetSyncTree(k); else _forgetSyncPath(k);
3091
+ if (!canRemove) {
3092
+ // No fsRemove: a plain file still has the unlink RPC.
3093
+ if (st !== undefined && !st.isDirectory()) {
3094
+ return _queueStructuralMutation(absPath, "rm", p, (s) => s.unlink(absPath), undefined, "unlink");
3095
+ }
3096
+ return null;
3097
+ }
3098
+ return _queueStructuralMutation(
3099
+ absPath, "rm", p,
3100
+ (s) => s.fsRemove(absPath, { recursive: !!o.recursive, force: !!o.force || parked }),
3101
+ () => __nimbusAwaitSubtreeMutations(absPath),
3102
+ "fsRemove",
3103
+ );
3104
+ }
3105
+ function rmSync(p, opts) { _detachStructuralMutation(_rmQueued(p, opts, true)); }
3106
+ async function _rmAsync(p, opts) { await _rmQueued(p, opts, false); }
3107
+
3108
+ // ── cpSync ──
3109
+ // A walk of the resident view; every file copy is a parked sync write that
3110
+ // the existing write-back drains, and every directory a queued mkdir.
3111
+ function cpSync(src, dest, opts) {
3112
+ const o = opts || {};
3113
+ const st = statSync(src, { throwIfNoEntry: false });
3114
+ if (st === undefined) throw _fsErr("ENOENT", "cp", src);
3115
+ if (typeof o.filter === "function" && !o.filter(String(src), String(dest))) return;
3116
+ if (!st.isDirectory()) {
3117
+ const destSt = statSync(dest, { throwIfNoEntry: false });
3118
+ if (destSt !== undefined) {
3119
+ if (destSt.isDirectory()) throw _fsErr("EISDIR", "cp", dest);
3120
+ if (o.errorOnExist) throw _fsErr("ERR_FS_CP_EEXIST", "cp", dest);
3121
+ if (o.force === false) return;
3122
+ }
3123
+ copyFileSync(src, dest);
3124
+ return;
3125
+ }
3126
+ if (!o.recursive) throw _fsErr("ERR_FS_EISDIR", "cp", src);
3127
+ mkdirSync(dest, { recursive: true });
3128
+ for (const ent of readdirSync(src, { withFileTypes: true })) {
3129
+ cpSync(__pathMod.join(String(src), ent.name), __pathMod.join(String(dest), ent.name), o);
3130
+ }
3131
+ }
3132
+
3133
+ // ── mkdtemp ──
3134
+ // Node appends six characters from [a-zA-Z0-9]; a collision with a name
3135
+ // the sync view already knows is retried rather than reused.
3136
+ const _MKDTEMP_ALPHABET = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
3137
+ function _mkdtempName(prefix) {
3138
+ for (let attempt = 0; attempt < 64; attempt++) {
3139
+ let suffix = "";
3140
+ for (let i = 0; i < 6; i++) suffix += _MKDTEMP_ALPHABET[Math.floor(Math.random() * _MKDTEMP_ALPHABET.length)];
3141
+ const name = String(prefix) + suffix;
3142
+ if (!existsSync(name)) return name;
3143
+ }
3144
+ throw _fsErr("EEXIST", "mkdtemp", String(prefix) + "XXXXXX");
3145
+ }
3146
+ function mkdtempSync(prefix) {
3147
+ const name = _mkdtempName(prefix);
3148
+ mkdirSync(name);
3149
+ return name;
3150
+ }
3151
+ async function _mkdtempAsync(prefix) {
3152
+ const name = _mkdtempName(prefix);
3153
+ await _mkdirAsync(name);
3154
+ return name;
3155
+ }
3156
+
3157
+ // ── truncateSync ──
3158
+ // The resident-view rule of ftruncateSync applied to a path: trim the
3159
+ // resident cell and park it, refuse EAGAIN when the bytes are not here.
3160
+ function truncateSync(p, len) {
3161
+ const absPath = _resolve(p);
3162
+ const st = statSync(p, { throwIfNoEntry: false });
3163
+ if (st === undefined) throw _fsErr("ENOENT", "truncate", p);
3164
+ if (st.isDirectory()) throw _fsErr("EISDIR", "truncate", p);
3165
+ const size = Math.max(0, Math.trunc(Number(len) || 0));
3166
+ _ensureWritable(absPath, "truncate", p);
3167
+ const base = _residentWriteBase(absPath, p, "truncate");
3168
+ const next = new Uint8Array(size);
3169
+ next.set(base.subarray(0, Math.min(size, base.byteLength)), 0);
3170
+ _parkWrite(_strip(absPath), next);
3171
+ _markVfsStale();
2753
3172
  }
2754
3173
 
3174
+ // ── link / linkSync ──
3175
+ // The VFS has no hard links and a copy would lie about sharing an inode,
3176
+ // so both forms answer ENOSYS like fs.promises.link always has.
3177
+ function linkSync(existingPath, newPath) { throw _fsErr("ENOSYS", "link", newPath); }
3178
+
2755
3179
  // ── realpathSync (X.5-T per X5Z5-plan §4.3 + X526b-retro §3.1) ──
2756
3180
  // Sync realpath stays local and identity-resolves. Async symlink
2757
3181
  // operations use the live supervisor bridge below.
@@ -2798,7 +3222,7 @@ const __fsMod = (() => {
2798
3222
  // ── open-flag parsing for fs.promises.open ──
2799
3223
  function _parseOpenFlags(flags) {
2800
3224
  if (typeof flags === "number") {
2801
- const O_WRONLY = 1, O_RDWR = 2, O_CREAT = 64, O_EXCL = 128, O_TRUNC = 512, O_APPEND = 1024;
3225
+ const { O_WRONLY, O_RDWR, O_CREAT, O_EXCL, O_TRUNC, O_APPEND, O_DIRECTORY } = __fsConstants;
2802
3226
  return {
2803
3227
  read: (flags & O_WRONLY) === 0,
2804
3228
  write: (flags & (O_WRONLY | O_RDWR)) !== 0,
@@ -2806,15 +3230,16 @@ const __fsMod = (() => {
2806
3230
  create: (flags & O_CREAT) !== 0,
2807
3231
  truncate: (flags & O_TRUNC) !== 0,
2808
3232
  exclusive: (flags & O_EXCL) !== 0,
3233
+ directory: (flags & O_DIRECTORY) !== 0,
2809
3234
  };
2810
3235
  }
2811
3236
  const s = String(flags === undefined || flags === null ? "r" : flags);
2812
3237
  const plus = s.indexOf("+") !== -1;
2813
3238
  const exclusive = s.indexOf("x") !== -1;
2814
3239
  const base = s.charAt(0);
2815
- if (base === "w") return { read: plus, write: true, append: false, create: true, truncate: true, exclusive };
2816
- if (base === "a") return { read: plus, write: true, append: true, create: true, truncate: false, exclusive };
2817
- return { read: true, write: plus, append: false, create: false, truncate: false, exclusive };
3240
+ if (base === "w") return { read: plus, write: true, append: false, create: true, truncate: true, exclusive, directory: false };
3241
+ if (base === "a") return { read: plus, write: true, append: true, create: true, truncate: false, exclusive, directory: false };
3242
+ return { read: true, write: plus, append: false, create: false, truncate: false, exclusive, directory: false };
2818
3243
  }
2819
3244
 
2820
3245
  // ── FileHandle — returned from fs.promises.open ──
@@ -2824,6 +3249,38 @@ const __fsMod = (() => {
2824
3249
  // hibernation and partial reads/writes never move whole files. Unflushed
2825
3250
  // sync writes (__vfsWrites) take read precedence; the local sync view is
2826
3251
  // overlaid on writes so readFileSync stays coherent.
3252
+ // The prior content a sync positional write or truncate lays its bytes
3253
+ // over. Shared by the descriptor forms and truncateSync.
3254
+ function _residentWriteBase(absPath, p, syscall) {
3255
+ const cell = _writtenCell(absPath);
3256
+ if (cell !== undefined) {
3257
+ const denial = _denialCode(cell);
3258
+ if (denial) throw _fsErr(denial, syscall, p);
3259
+ _residencySatisfied(absPath);
3260
+ return _asBytes(cell);
3261
+ }
3262
+ const asyncForm = "the async fs." + syscall + "/fs.promises form";
3263
+ const st = statSync(p, { throwIfNoEntry: false });
3264
+ // Non-resident and non-empty: writing onto a zero-filled base would
3265
+ // silently destroy the bytes we cannot see. Refuse instead.
3266
+ 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);
3272
+ return new Uint8Array(0);
3273
+ }
3274
+
3275
+ async function _fsyncAsync(absPath, p) {
3276
+ const supervisor = _supervisor();
3277
+ if (supervisor) {
3278
+ await _flushLocalPathToSupervisor(absPath, supervisor);
3279
+ await _awaitStructuralOrder(absPath);
3280
+ }
3281
+ _markVfsStale();
3282
+ }
3283
+
2827
3284
  let __nextFileHandleFd = 3;
2828
3285
  const __fileHandles = new Map();
2829
3286
  class __FileHandle {
@@ -2898,16 +3355,21 @@ const __fsMod = (() => {
2898
3355
  );
2899
3356
  if (meta && meta.type === "file") writeAt = Number(meta.size) || 0;
2900
3357
  }
2901
- await _fsRpc(
2902
- supervisor.fsWriteRange(this._abs, writeAt, bytes),
2903
- "write", this._path,
2904
- () => undefined,
3358
+ await _ownMutation(
3359
+ this._abs,
3360
+ () => _fsRpc(
3361
+ supervisor.fsWriteRange(this._abs, writeAt, bytes),
3362
+ "write", this._path,
3363
+ (result) => result,
3364
+ ),
3365
+ () => {
3366
+ const key = _strip(this._abs);
3367
+ if (!Object.prototype.hasOwnProperty.call(__vfsWrites, key) &&
3368
+ __vfsWriteGenerations[key] === overlayGeneration) {
3369
+ _overlayLocalCell(this._abs, writeAt, bytes);
3370
+ }
3371
+ },
2905
3372
  );
2906
- const key = _strip(this._abs);
2907
- if (!Object.prototype.hasOwnProperty.call(__vfsWrites, key) &&
2908
- __vfsWriteGenerations[key] === overlayGeneration) {
2909
- _overlayLocalCell(this._abs, writeAt, bytes);
2910
- }
2911
3373
  });
2912
3374
  _markVfsStale();
2913
3375
  } else {
@@ -2963,24 +3425,7 @@ const __fsMod = (() => {
2963
3425
  if (bytes === undefined) throw this._notResident(syscall);
2964
3426
  return bytes;
2965
3427
  }
2966
- _writeBase(syscall) {
2967
- const bytes = this._residentBytes(syscall);
2968
- if (bytes !== undefined) return bytes;
2969
- const st = statSync(this._path, { throwIfNoEntry: false });
2970
- // Non-resident and non-empty: writing onto a zero-filled base would
2971
- // silently destroy the bytes we cannot see. Refuse instead.
2972
- if (st !== undefined && st.size !== 0) throw this._notResident(syscall);
2973
- // Absent or empty — an empty base IS the true prior content, but only
2974
- // where absence is knowledge. A path the view never mapped may hold bytes
2975
- // this process cannot see, and an O_APPEND descriptor onto a zero-filled
2976
- // base would overwrite the file with the fragment it meant to add.
2977
- if (st === undefined && !_absenceIsKnown(this._abs)) {
2978
- throw _refuseUnmapped(
2979
- this._abs, this._path, syscall, "the async fs." + syscall + "/fs.promises form",
2980
- );
2981
- }
2982
- return new Uint8Array(0);
2983
- }
3428
+ _writeBase(syscall) { return _residentWriteBase(this._abs, this._path, syscall); }
2984
3429
  _commit(next) {
2985
3430
  _parkWrite(_strip(this._abs), next);
2986
3431
  _markVfsStale();
@@ -3030,9 +3475,38 @@ const __fsMod = (() => {
3030
3475
  }
3031
3476
  async chmod(mode) { this._assertOpen("fchmod"); await _chmodAsync(this._path, mode); }
3032
3477
  async chown(uid, gid) { this._assertOpen("fchown"); await _chownAsync(this._path, uid, gid, undefined, "fchown"); }
3033
- async utimes(atime, mtime) { this._assertOpen("futimes"); await _utimesAsync(this._path, atime, mtime); }
3034
- async sync() {}
3035
- async datasync() {}
3478
+ async utimes(atime, mtime) { this._assertOpen("futimes"); await _utimesAsync(this._path, atime, mtime, undefined, "futimes"); }
3479
+ // Durability here means: every byte parked for this path has reached
3480
+ // the authority and every mutation queued for it has landed. The bridge
3481
+ // itself is synchronously durable, so no further RPC is owed.
3482
+ async sync() { this._assertOpen("fsync"); await _fsyncAsync(this._abs, this._path); }
3483
+ async datasync() { this._assertOpen("fdatasync"); await _fsyncAsync(this._abs, this._path); }
3484
+ // Scatter/gather over the ranged read/write: one sequential pass per
3485
+ // buffer, stopping at the first short read, positions advanced by hand
3486
+ // when an explicit one was given so the file position stays untouched.
3487
+ async readv(buffers, position) {
3488
+ this._assertOpen("read");
3489
+ let bytesRead = 0;
3490
+ let pos = _isCurrentPos(position) ? null : Number(position);
3491
+ for (const buffer of buffers) {
3492
+ const r = await this.read(buffer, 0, buffer.byteLength, pos);
3493
+ bytesRead += r.bytesRead;
3494
+ if (pos !== null) pos += r.bytesRead;
3495
+ if (r.bytesRead < buffer.byteLength) break;
3496
+ }
3497
+ return { bytesRead, buffers };
3498
+ }
3499
+ async writev(buffers, position) {
3500
+ this._assertOpen("write");
3501
+ let bytesWritten = 0;
3502
+ let pos = _isCurrentPos(position) ? null : Number(position);
3503
+ for (const buffer of buffers) {
3504
+ const r = await this.write(buffer, 0, buffer.byteLength, pos);
3505
+ bytesWritten += r.bytesWritten;
3506
+ if (pos !== null) pos += r.bytesWritten;
3507
+ }
3508
+ return { bytesWritten, buffers };
3509
+ }
3036
3510
  async close() { this._assertOpen("close"); this._closed = true; __fileHandles.delete(this.fd); }
3037
3511
  [Symbol.asyncDispose]() { return this.close(); }
3038
3512
  }
@@ -3053,6 +3527,7 @@ const __fsMod = (() => {
3053
3527
  if (localStat && localStat.isDirectory()) throw _fsErr("EISDIR", "open", path);
3054
3528
  }
3055
3529
  const exists = !!liveMeta || !!localStat;
3530
+ if (exists && fl.directory) throw _fsErr("ENOTDIR", "open", path);
3056
3531
  if (!exists && !fl.create) throw _fsErr("ENOENT", "open", path);
3057
3532
  if (exists && fl.create && fl.exclusive) throw _fsErr("EEXIST", "open", path);
3058
3533
  let size = liveMeta ? (Number(liveMeta.size) || 0) : (localStat ? localStat.size : 0);
@@ -3076,6 +3551,7 @@ const __fsMod = (() => {
3076
3551
  const st = statSync(path, { throwIfNoEntry: false });
3077
3552
  if (st && st.isDirectory()) throw _fsErr("EISDIR", "open", path);
3078
3553
  const exists = st !== undefined;
3554
+ if (exists && fl.directory) throw _fsErr("ENOTDIR", "open", path);
3079
3555
  if (!exists && !fl.create) throw _fsErr("ENOENT", "open", path);
3080
3556
  if (exists && fl.create && fl.exclusive) throw _fsErr("EEXIST", "open", path);
3081
3557
  if (fl.write || !exists) _ensureWritable(absPath, "open", path);
@@ -3196,6 +3672,49 @@ const __fsMod = (() => {
3196
3672
  function fsyncSync(fd) { if (!_isStdioFd(fd)) _fdHandle(fd, "fsync"); _markVfsStale(); }
3197
3673
  function fdatasyncSync(fd) { if (!_isStdioFd(fd)) _fdHandle(fd, "fdatasync"); _markVfsStale(); }
3198
3674
 
3675
+ // Descriptor metadata, sync: the path forms on the handle's path, so the
3676
+ // local overlay (times, modes, ownership) and the parked write-through are
3677
+ // exactly what utimesSync/chmodSync/chownSync give.
3678
+ function futimesSync(fd, atime, mtime) {
3679
+ if (_isStdioFd(fd)) throw _fsErr("EINVAL", "futimes", fd);
3680
+ const handle = _fdHandle(fd, "futimes");
3681
+ _recordLocalTimes(handle._abs, atime, mtime, "futimes", handle._path);
3682
+ }
3683
+ function fchmodSync(fd, mode) {
3684
+ if (_isStdioFd(fd)) throw _fsErr("EINVAL", "fchmod", fd);
3685
+ const handle = _fdHandle(fd, "fchmod");
3686
+ _localModes[_strip(handle._abs)] = _coerceMode(mode, "fchmod", handle._path);
3687
+ }
3688
+ function fchownSync(fd, uid, gid) {
3689
+ if (_isStdioFd(fd)) throw _fsErr("EINVAL", "fchown", fd);
3690
+ const handle = _fdHandle(fd, "fchown");
3691
+ _detachStructuralMutation(_chownQueued(handle._path, uid, gid, undefined, "fchown"));
3692
+ }
3693
+
3694
+ // Scatter/gather, sync: readSync/writeSync per buffer; stdio fds keep the
3695
+ // stream behaviour those two already give them.
3696
+ function readvSync(fd, buffers, position) {
3697
+ let bytesRead = 0;
3698
+ let pos = _isCurrentPos(position) ? null : Number(position);
3699
+ for (const buffer of buffers) {
3700
+ const n = readSync(fd, buffer, 0, buffer.byteLength, pos);
3701
+ bytesRead += n;
3702
+ if (pos !== null) pos += n;
3703
+ if (n < buffer.byteLength) break;
3704
+ }
3705
+ return bytesRead;
3706
+ }
3707
+ function writevSync(fd, buffers, position) {
3708
+ let bytesWritten = 0;
3709
+ let pos = _isCurrentPos(position) ? null : Number(position);
3710
+ for (const buffer of buffers) {
3711
+ const n = writeSync(fd, buffer, 0, buffer.byteLength, pos);
3712
+ bytesWritten += n;
3713
+ if (pos !== null) pos += n;
3714
+ }
3715
+ return bytesWritten;
3716
+ }
3717
+
3199
3718
  // ── callback forms (live I/O — these CAN reach the supervisor) ──
3200
3719
  function open(path, flags, mode, cb) {
3201
3720
  if (typeof flags === "function") { cb = flags; flags = undefined; mode = undefined; }
@@ -3276,21 +3795,56 @@ const __fsMod = (() => {
3276
3795
  if (!handle) return;
3277
3796
  handle.truncate(len).then(() => cb(null)).catch((e) => cb(e));
3278
3797
  }
3279
- function fsync(fd, cb) {
3798
+ // The async forms CAN wait for durability: the parked bytes are flushed
3799
+ // and the path's queued mutations awaited before the callback fires.
3800
+ function _fsyncCb(fd, syscall, cb) {
3801
+ let handle = null;
3280
3802
  let err = null;
3281
- try { fsyncSync(fd); } catch (e) { err = e; }
3803
+ try { if (!_isStdioFd(fd)) handle = _fdHandle(fd, syscall); } catch (e) { err = e; }
3282
3804
  // Without a callback there is nowhere to deliver the failure, so raise
3283
3805
  // it here rather than let an EBADF vanish.
3284
- if (typeof cb !== "function") { if (err) throw err; return; }
3285
- queueMicrotask(() => cb(err));
3286
- }
3287
- function fdatasync(fd, cb) {
3288
- let err = null;
3289
- try { fdatasyncSync(fd); } catch (e) { err = e; }
3290
- // Without a callback there is nowhere to deliver the failure, so raise
3291
- // it here rather than let an EBADF vanish.
3292
- if (typeof cb !== "function") { if (err) throw err; return; }
3293
- queueMicrotask(() => cb(err));
3806
+ if (typeof cb !== "function") { if (err) throw err; _markVfsStale(); return; }
3807
+ if (err || !handle) { _markVfsStale(); queueMicrotask(() => cb(err)); return; }
3808
+ _fsyncAsync(handle._abs, handle._path).then(() => cb(null)).catch((e) => cb(e));
3809
+ }
3810
+ function fsync(fd, cb) { _fsyncCb(fd, "fsync", cb); }
3811
+ function fdatasync(fd, cb) { _fsyncCb(fd, "fdatasync", cb); }
3812
+ function futimes(fd, atime, mtime, cb) {
3813
+ if (_isStdioFd(fd)) { queueMicrotask(() => cb(_fsErr("EINVAL", "futimes", fd))); return; }
3814
+ const handle = _fdFor(fd, "futimes", cb);
3815
+ if (!handle) return;
3816
+ handle.utimes(atime, mtime).then(() => cb(null)).catch((e) => cb(e));
3817
+ }
3818
+ function readv(fd, buffers, position, cb) {
3819
+ if (typeof position === "function") { cb = position; position = null; }
3820
+ const run = async () => {
3821
+ let bytesRead = 0;
3822
+ let pos = _isCurrentPos(position) ? null : Number(position);
3823
+ for (const buffer of buffers) {
3824
+ const n = await new Promise((res, rej) =>
3825
+ read(fd, buffer, 0, buffer.byteLength, pos, (e, count) => (e ? rej(e) : res(count))));
3826
+ bytesRead += n;
3827
+ if (pos !== null) pos += n;
3828
+ if (n < buffer.byteLength) break;
3829
+ }
3830
+ return bytesRead;
3831
+ };
3832
+ run().then((n) => cb(null, n, buffers)).catch((e) => cb(e));
3833
+ }
3834
+ function writev(fd, buffers, position, cb) {
3835
+ if (typeof position === "function") { cb = position; position = null; }
3836
+ const run = async () => {
3837
+ let bytesWritten = 0;
3838
+ let pos = _isCurrentPos(position) ? null : Number(position);
3839
+ for (const buffer of buffers) {
3840
+ const n = await new Promise((res, rej) =>
3841
+ write(fd, buffer, 0, buffer.byteLength, pos, (e, count) => (e ? rej(e) : res(count))));
3842
+ bytesWritten += n;
3843
+ if (pos !== null) pos += n;
3844
+ }
3845
+ return bytesWritten;
3846
+ };
3847
+ run().then((n) => cb(null, n, buffers)).catch((e) => cb(e));
3294
3848
  }
3295
3849
  function fchmod(fd, mode, cb) {
3296
3850
  const handle = _fdFor(fd, "fchmod", cb);
@@ -3303,6 +3857,135 @@ const __fsMod = (() => {
3303
3857
  handle.chown(uid, gid).then(() => cb(null)).catch((error) => cb(error));
3304
3858
  }
3305
3859
 
3860
+ // ── Dir — fs.opendir / opendirSync / fs.promises.opendir ──
3861
+ // The listing is taken whole at open (both readdir forms already return
3862
+ // one) and handed out one Dirent per read(); closing a closed Dir is
3863
+ // ERR_DIR_CLOSED as in Node.
3864
+ class __Dir {
3865
+ constructor(path, entries) {
3866
+ this.path = path;
3867
+ this._entries = entries;
3868
+ this._at = 0;
3869
+ this._closed = false;
3870
+ }
3871
+ _assertOpen() {
3872
+ if (this._closed) {
3873
+ const err = new Error("Directory handle was closed");
3874
+ err.code = "ERR_DIR_CLOSED";
3875
+ throw err;
3876
+ }
3877
+ }
3878
+ readSync() {
3879
+ this._assertOpen();
3880
+ return this._at < this._entries.length ? this._entries[this._at++] : null;
3881
+ }
3882
+ read(cb) {
3883
+ const result = new Promise((res, rej) => { try { res(this.readSync()); } catch (e) { rej(e); } });
3884
+ if (typeof cb !== "function") return result;
3885
+ result.then((entry) => cb(null, entry), (e) => cb(e));
3886
+ }
3887
+ closeSync() { this._assertOpen(); this._closed = true; }
3888
+ close(cb) {
3889
+ const result = new Promise((res, rej) => { try { this.closeSync(); res(); } catch (e) { rej(e); } });
3890
+ if (typeof cb !== "function") return result;
3891
+ result.then(() => cb(null), (e) => cb(e));
3892
+ }
3893
+ async *[Symbol.asyncIterator]() {
3894
+ try {
3895
+ for (;;) {
3896
+ const entry = this.readSync();
3897
+ if (entry === null) break;
3898
+ yield entry;
3899
+ }
3900
+ } finally {
3901
+ if (!this._closed) this._closed = true;
3902
+ }
3903
+ }
3904
+ [Symbol.asyncDispose]() { return this._closed ? Promise.resolve() : this.close(); }
3905
+ [Symbol.dispose]() { if (!this._closed) this.closeSync(); }
3906
+ }
3907
+ function opendirSync(p, opts) {
3908
+ return new __Dir(String(p), readdirSync(p, { withFileTypes: true }));
3909
+ }
3910
+ async function _opendirAsync(p, opts) {
3911
+ return new __Dir(String(p), await _readdirAsync(p, { withFileTypes: true }));
3912
+ }
3913
+ function opendir(p, opts, cb) {
3914
+ if (typeof opts === "function") { cb = opts; opts = undefined; }
3915
+ _opendirAsync(p, opts).then((dir) => cb(null, dir)).catch((e) => cb(e));
3916
+ }
3917
+
3918
+ // ── statfs ──
3919
+ // Honest constants for the VFS: the block size is the SQLite chunk unit's
3920
+ // page size, and blocks is the configured VFS capacity in those blocks.
3921
+ // The supervisor surface exposes no usage counter, so bfree/bavail report
3922
+ // the whole capacity; the VFS has no inode table, so files/ffree are 0
3923
+ // (unknown, not "none"). `type` is 0: this is no kernel filesystem and
3924
+ // no magic number would be true of it.
3925
+ const _STATFS_BSIZE = 4096;
3926
+ const _STATFS_BLOCKS = Math.floor(10737418240 / 4096);
3927
+ function _statfsObject(opts) {
3928
+ const wrap = opts && opts.bigint ? BigInt : Number;
3929
+ return {
3930
+ type: wrap(0),
3931
+ bsize: wrap(_STATFS_BSIZE),
3932
+ blocks: wrap(_STATFS_BLOCKS),
3933
+ bfree: wrap(_STATFS_BLOCKS),
3934
+ bavail: wrap(_STATFS_BLOCKS),
3935
+ files: wrap(0),
3936
+ ffree: wrap(0),
3937
+ };
3938
+ }
3939
+ function statfsSync(p, opts) {
3940
+ if (statSync(p, { throwIfNoEntry: false }) === undefined) throw _fsErr("ENOENT", "statfs", p);
3941
+ return _statfsObject(opts);
3942
+ }
3943
+ async function _statfsAsync(p, opts) {
3944
+ await _statAsync(p);
3945
+ return _statfsObject(opts);
3946
+ }
3947
+ function statfs(p, opts, cb) {
3948
+ if (typeof opts === "function") { cb = opts; opts = undefined; }
3949
+ _statfsAsync(p, opts).then((s) => cb(null, s)).catch((e) => cb(e));
3950
+ }
3951
+
3952
+ // ── remaining callback forms of the path operations ──
3953
+ function rm(p, opts, cb) {
3954
+ if (typeof opts === "function") { cb = opts; opts = undefined; }
3955
+ _rmAsync(p, opts).then(() => cb(null)).catch((e) => cb(e));
3956
+ }
3957
+ function cp(src, dest, opts, cb) {
3958
+ if (typeof opts === "function") { cb = opts; opts = undefined; }
3959
+ promises.cp(src, dest, opts).then(() => cb(null)).catch((e) => cb(e));
3960
+ }
3961
+ function truncate(p, len, cb) {
3962
+ if (typeof len === "function") { cb = len; len = 0; }
3963
+ _truncateAsync(p, len || 0).then(() => cb(null)).catch((e) => cb(e));
3964
+ }
3965
+ function copyFile(src, dest, mode, cb) {
3966
+ if (typeof mode === "function") { cb = mode; mode = 0; }
3967
+ promises.copyFile(src, dest, mode).then(() => cb(null)).catch((e) => cb(e));
3968
+ }
3969
+ function mkdtemp(prefix, opts, cb) {
3970
+ if (typeof opts === "function") { cb = opts; opts = undefined; }
3971
+ _mkdtempAsync(prefix).then((name) => cb(null, name)).catch((e) => cb(e));
3972
+ }
3973
+ function link(existingPath, newPath, cb) { queueMicrotask(() => cb(_fsErr("ENOSYS", "link", newPath))); }
3974
+ function symlink(target, path, type, cb) {
3975
+ if (typeof type === "function") { cb = type; type = undefined; }
3976
+ _symlinkAsync(target, path).then(() => cb(null)).catch((e) => cb(e));
3977
+ }
3978
+ function readlink(p, opts, cb) {
3979
+ if (typeof opts === "function") { cb = opts; opts = undefined; }
3980
+ _readlinkAsync(p).then((target) => cb(null, target)).catch((e) => cb(e));
3981
+ }
3982
+ function realpath(p, opts, cb) {
3983
+ if (typeof opts === "function") { cb = opts; opts = undefined; }
3984
+ promises.realpath(p, opts).then((r) => cb(null, r)).catch((e) => cb(e));
3985
+ }
3986
+ realpath.native = realpath;
3987
+ function lchmod(p, mode, cb) { chmod(p, mode, cb); }
3988
+
3306
3989
  // ── promises namespace (W3: full surface, VFS-backed) ──
3307
3990
  // We can't forward to workerd's node:fs/promises because that operates
3308
3991
  // on a real-host filesystem, not our VFS. So every method is shim'd
@@ -3320,22 +4003,8 @@ const __fsMod = (() => {
3320
4003
  // W3 additions:
3321
4004
  appendFile: async (p, d, o) => { await _appendFileAsync(p, d, o); },
3322
4005
  lstat: (p) => new Promise((res, rej) => lstat(p, (e, s) => e ? rej(e) : res(s))),
3323
- rm: async (p, opts) => {
3324
- const o = opts || {};
3325
- const k = _strip(_resolve(p));
3326
- const prefix = k + "/";
3327
- if (o.recursive) {
3328
- if (__vfsBundle) {
3329
- if (k in __vfsBundle) delete __vfsBundle[k];
3330
- for (const bk of __residentUnder(prefix)) delete __vfsBundle[bk];
3331
- }
3332
- if (__vfsWrites) for (const wk of Object.keys(__vfsWrites)) if (wk === k || wk.startsWith(prefix)) delete __vfsWrites[wk];
3333
- if (__vfsDirs) for (const dk of Object.keys(__vfsDirs)) if (dk === k || dk.startsWith(prefix)) delete __vfsDirs[dk];
3334
- _forgetSyncTree(k);
3335
- } else {
3336
- try { await _unlinkAsync(p); } catch (e) { if (!o.force) throw e; }
3337
- }
3338
- },
4006
+ // The same local retraction and queued authority removal rmSync does.
4007
+ rm: async (p, opts) => { await _rmAsync(p, opts); },
3339
4008
  cp: async (src, dest, opts) => {
3340
4009
  const o = opts || {};
3341
4010
  const srcAbs = _resolve(src);
@@ -3371,7 +4040,12 @@ const __fsMod = (() => {
3371
4040
  };
3372
4041
  await walk("");
3373
4042
  },
3374
- copyFile: async (src, dest) => { await _writeFileAsync(dest, await _readFileAsync(src)); },
4043
+ copyFile: async (src, dest, mode) => {
4044
+ if ((Number(mode) & __fsConstants.COPYFILE_EXCL) !== 0 && await _existsAsync(dest)) {
4045
+ throw _fsErr("EEXIST", "copyfile", dest);
4046
+ }
4047
+ await _writeFileAsync(dest, await _readFileAsync(src));
4048
+ },
3375
4049
  rename: async (oldP, newP) => { await _renameAsync(oldP, newP); },
3376
4050
  rmdir: async (p) => { await _rmdirAsync(p); },
3377
4051
  realpath: async (p) => __pathMod.resolve(String(p)),
@@ -3385,12 +4059,10 @@ const __fsMod = (() => {
3385
4059
  symlink: async (target, path) => { await _symlinkAsync(target, path); },
3386
4060
  link: async () => { throw _fsErr("ENOSYS", "link", ""); },
3387
4061
  readlink: async (p) => _readlinkAsync(p),
3388
- mkdtemp: async (prefix) => {
3389
- const name = String(prefix) + Math.random().toString(36).slice(2, 10);
3390
- mkdirSync(name, { recursive: true });
3391
- return name;
3392
- },
4062
+ mkdtemp: async (prefix) => _mkdtempAsync(prefix),
3393
4063
  open: async (path, flags, mode) => _openAsync(path, flags, mode),
4064
+ opendir: async (p, opts) => _opendirAsync(p, opts),
4065
+ statfs: async (p, opts) => _statfsAsync(p, opts),
3394
4066
  watch: async function* (filename, opts) {
3395
4067
  // Minimal async iter — polls _bundleLookup every 500ms and yields
3396
4068
  // a single `change` event when content differs. Adequate for
@@ -3435,8 +4107,9 @@ const __fsMod = (() => {
3435
4107
  },
3436
4108
  };
3437
4109
 
3438
- // ── constants ──
3439
- const constants = { F_OK: 0, R_OK: 4, W_OK: 2, X_OK: 1 };
4110
+ // ── constants ── the shared linux x64 table (see __fsConstants).
4111
+ const constants = __fsConstants;
4112
+ promises.constants = constants;
3440
4113
 
3441
4114
  // fs.ReadStream / fs.WriteStream classes. Real Node exposes these as
3442
4115
  // constructors; graceful-fs (bundled by degit → create-cloudflare)
@@ -3526,10 +4199,15 @@ const __fsMod = (() => {
3526
4199
  const __fsExports = {
3527
4200
  readFileSync, writeFileSync, appendFileSync, existsSync, statSync, lstatSync,
3528
4201
  readdirSync, mkdirSync, unlinkSync, rmdirSync, renameSync, copyFileSync,
3529
- realpathSync, utimesSync, lutimesSync, chmodSync, accessSync,
4202
+ realpathSync, utimesSync, lutimesSync, chmodSync, lchmodSync, chownSync, lchownSync, accessSync,
4203
+ rmSync, cpSync, mkdtempSync, truncateSync, linkSync, opendirSync, statfsSync,
3530
4204
  openSync, closeSync, readSync, writeSync, fstatSync, ftruncateSync, fsyncSync, fdatasyncSync,
3531
- open, close, read, write, fstat, ftruncate, fsync, fdatasync, fchmod,
3532
- readFile, writeFile, appendFile, stat, lstat, readdir, exists, mkdir, unlink, rename, utimes, lutimes, chmod, chown, lchown, fchown, access,
4205
+ futimesSync, fchmodSync, fchownSync, readvSync, writevSync,
4206
+ 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,
4208
+ rm, cp, truncate, copyFile, mkdtemp, link, symlink, readlink, realpath, opendir, statfs,
4209
+ Dirent: __Dirent,
4210
+ Dir: __Dir,
3533
4211
  promises, constants,
3534
4212
  createReadStream: (p, opts) => new (__getReadStream())(p, opts),
3535
4213
  createWriteStream: (p, opts) => {
@@ -3871,13 +4549,10 @@ globalThis.WebSocket = __NimbusRelayedWebSocket;
3871
4549
  //
3872
4550
  // require('node:constants') (and the legacy bare require('constants'))
3873
4551
  // expose a FLAT object of POSIX/Linux/OpenSSL constants. Real Node ships
3874
- // ~234 constants; we ship the ones that actually get touched by:
4552
+ // ~234 constants; the full fs slice comes from __fsConstants, and the rest
4553
+ // is what actually gets touched by:
3875
4554
  // - create-next-app (touches UV_FS_O_FILEMAP — verified via grep on
3876
4555
  // unpkg.com/create-next-app@latest/dist/index.js)
3877
- // - typical fs.openSync flag composition (O_RDONLY, O_WRONLY, O_RDWR,
3878
- // O_CREAT, O_EXCL, O_TRUNC, O_APPEND, O_DIRECTORY, etc.)
3879
- // - typical fs.access mode composition (F_OK, R_OK, W_OK, X_OK)
3880
- // - typical fs.copyFile mode composition (COPYFILE_EXCL etc.)
3881
4556
  // - signal/errno tables (shared shape with __osMod.constants.signals
3882
4557
  // etc. — flat here, nested there; both shapes are real-Node-accurate
3883
4558
  // and we expose both via the right module).
@@ -3922,26 +4597,10 @@ const __constantsMod = {
3922
4597
  SIGTSTP: 20, SIGTTIN: 21, SIGTTOU: 22, SIGURG: 23, SIGXCPU: 24,
3923
4598
  SIGXFSZ: 25, SIGVTALRM: 26, SIGPROF: 27, SIGWINCH: 28, SIGIO: 29,
3924
4599
  SIGPOLL: 29, SIGPWR: 30, SIGSYS: 31,
3925
- // ── File-type bits (stat.mode masks) ──────────────────────────────
3926
- S_IFMT: 61440, S_IFREG: 32768, S_IFDIR: 16384, S_IFCHR: 8192,
3927
- S_IFBLK: 24576, S_IFIFO: 4096, S_IFLNK: 40960, S_IFSOCK: 49152,
3928
- // ── File-open flags (fs.openSync / fs.constants.O_*) ──────────────
3929
- O_RDONLY: 0, O_WRONLY: 1, O_RDWR: 2,
3930
- O_CREAT: 64, O_EXCL: 128, O_NOCTTY: 256, O_TRUNC: 512, O_APPEND: 1024,
3931
- O_DIRECTORY: 65536, O_NOATIME: 262144, O_NOFOLLOW: 131072,
3932
- O_SYNC: 1052672, O_DSYNC: 4096, O_DIRECT: 16384, O_NONBLOCK: 2048,
3933
- // libuv-specific fs flag — create-next-app touches this directly.
3934
- UV_FS_O_FILEMAP: 0,
3935
- // ── File-permission bits (chmod / stat.mode user/group/other) ─────
3936
- S_IRWXU: 448, S_IRUSR: 256, S_IWUSR: 128, S_IXUSR: 64,
3937
- S_IRWXG: 56, S_IRGRP: 32, S_IWGRP: 16, S_IXGRP: 8,
3938
- S_IRWXO: 7, S_IROTH: 4, S_IWOTH: 2, S_IXOTH: 1,
3939
- // ── fs.access mode constants ──────────────────────────────────────
3940
- F_OK: 0, R_OK: 4, W_OK: 2, X_OK: 1,
3941
- // ── fs.copyFile mode constants (libuv shape + Node alias) ─────────
3942
- UV_FS_COPYFILE_EXCL: 1, COPYFILE_EXCL: 1,
3943
- UV_FS_COPYFILE_FICLONE: 2, COPYFILE_FICLONE: 2,
3944
- UV_FS_COPYFILE_FICLONE_FORCE: 4, COPYFILE_FICLONE_FORCE: 4,
4600
+ // ── fs constants (O_*, S_IF*, S_I*, F_OK.., COPYFILE_*, UV_*) ────
4601
+ // Node's constants module is the union of os, fs and crypto constants;
4602
+ // the fs slice is __fsConstants, the same object fs.constants exposes.
4603
+ ...__fsConstants,
3945
4604
  // ── OpenSSL / TLS option flags ────────────────────────────────────
3946
4605
  // Numeric values from real Node v20. Libraries probe defined-ness;
3947
4606
  // we ship the surface so constants.SSL_OP_* doesn't undefined-throw.
@@ -7712,7 +8371,20 @@ builtins.tty = {
7712
8371
  // core and must not be reported as such — a package that sniffs this list
7713
8372
  // would otherwise conclude e.g. undici ships with node.
7714
8373
  const __nimbusFacetProvidedPackages = new Set(["undici"]);
7715
- builtins.module = { get builtinModules() { return Object.keys(builtins).filter((n) => !__nimbusFacetProvidedPackages.has(n)); }, createRequire: (specifier) => __makeRequire(__requireBaseDir(specifier)), _resolveFilename: (id) => id, _cache: {} };
8374
+ builtins.module = {
8375
+ get builtinModules() { return Object.keys(builtins).filter((n) => !__nimbusFacetProvidedPackages.has(n)); },
8376
+ createRequire: (specifier) => __makeRequire(__requireBaseDir(specifier)),
8377
+ isBuiltin: (specifier) => Object.hasOwn(builtins, String(specifier).replace(/^node:/, '')) && !__nimbusFacetProvidedPackages.has(String(specifier).replace(/^node:/, '')),
8378
+ // Node 22.1's on-disk compile cache. There is no disk to cache into and
8379
+ // nothing to compile ahead: callers (pi's CLI entry calls it
8380
+ // unconditionally) get Node's own answer for a cache that is off.
8381
+ enableCompileCache: () => ({ status: 3, message: 'compile cache is not available in this runtime' }),
8382
+ getCompileCacheDir: () => undefined,
8383
+ flushCompileCache: () => {},
8384
+ constants: { compileCacheStatus: { FAILED: 0, ENABLED: 1, ALREADY_ENABLED: 2, DISABLED: 3 } },
8385
+ _resolveFilename: (id) => id,
8386
+ _cache: {},
8387
+ };
7716
8388
  // Bind to globalThis: workerd's timer globals throw "Illegal invocation"
7717
8389
  // when called with a receiver other than globalThis (i.e. as
7718
8390
  // timers.setInterval(...)), which clack's spinner — used by