@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.
- package/dist/esbuild-wasm-bundle.generated.d.ts +24 -24
- package/dist/esbuild-wasm-bundle.generated.d.ts.map +1 -1
- package/dist/esbuild-wasm-bundle.generated.js +24 -24
- package/dist/facets/cirrus-real.js +3 -3
- package/dist/facets/compose.d.ts +3 -0
- package/dist/facets/compose.d.ts.map +1 -1
- package/dist/facets/compose.js +10 -3
- package/dist/facets/esbuild-bundle-pool.d.ts +1 -1
- package/dist/facets/esbuild-bundle-pool.js +3 -3
- package/dist/facets/esbuild-transform.d.ts +6 -2
- package/dist/facets/esbuild-transform.d.ts.map +1 -1
- package/dist/facets/esbuild-transform.js +8 -4
- package/dist/facets/manager.d.ts +54 -15
- package/dist/facets/manager.d.ts.map +1 -1
- package/dist/facets/manager.js +227 -144
- package/dist/facets/real-vite-hmr.d.ts +2 -0
- package/dist/facets/real-vite-hmr.d.ts.map +1 -1
- package/dist/facets/real-vite-hmr.js +3 -2
- package/dist/git/commands.d.ts +17 -1
- package/dist/git/commands.d.ts.map +1 -1
- package/dist/git/commands.js +73 -9
- package/dist/git/network-facet.d.ts +2 -0
- package/dist/git/network-facet.d.ts.map +1 -1
- package/dist/git/network-facet.js +10 -5
- package/dist/hosted/commands.d.ts.map +1 -1
- package/dist/hosted/commands.js +28 -39
- package/dist/hosted/runtime.d.ts +24 -2
- package/dist/hosted/runtime.d.ts.map +1 -1
- package/dist/hosted/runtime.js +70 -13
- package/dist/hosted/services.d.ts +14 -2
- package/dist/hosted/services.d.ts.map +1 -1
- package/dist/hosted/services.js +15 -2
- package/dist/loaders/generated-workers.d.ts +2 -2
- package/dist/loaders/generated-workers.d.ts.map +1 -1
- package/dist/loaders/generated-workers.js +4 -4
- package/dist/loaders/pre-bundle-preamble.d.ts +6 -3
- package/dist/loaders/pre-bundle-preamble.d.ts.map +1 -1
- package/dist/loaders/pre-bundle-preamble.js +13 -8
- package/dist/node-shims-artifact.generated.js +3 -3
- package/dist/npm/cache.d.ts +6 -1
- package/dist/npm/cache.d.ts.map +1 -1
- package/dist/npm/cache.js +8 -6
- package/dist/npm/install-batch-facet.d.ts +2 -0
- package/dist/npm/install-batch-facet.d.ts.map +1 -1
- package/dist/npm/install-batch-facet.js +29 -15
- package/dist/npm/installer.d.ts +8 -4
- package/dist/npm/installer.d.ts.map +1 -1
- package/dist/npm/installer.js +173 -113
- package/dist/npm/npx-install.d.ts +3 -1
- package/dist/npm/npx-install.d.ts.map +1 -1
- package/dist/npm/npx-install.js +4 -1
- package/dist/npm/placement.d.ts +16 -0
- package/dist/npm/placement.d.ts.map +1 -0
- package/dist/npm/placement.js +33 -0
- package/dist/npm/r2-cache.d.ts +10 -6
- package/dist/npm/r2-cache.d.ts.map +1 -1
- package/dist/npm/r2-cache.js +32 -16
- package/dist/npm/resolve-one-facet.d.ts +3 -0
- package/dist/npm/resolve-one-facet.d.ts.map +1 -1
- package/dist/npm/resolve-one-facet.js +1 -0
- package/dist/npm/resolver.d.ts +11 -6
- package/dist/npm/resolver.d.ts.map +1 -1
- package/dist/npm/resolver.js +12 -3
- package/dist/runtime/bash-repl.d.ts +5 -3
- package/dist/runtime/bash-repl.d.ts.map +1 -1
- package/dist/runtime/bash-repl.js +8 -3
- package/dist/runtime/cpython-resident.d.ts.map +1 -1
- package/dist/runtime/cpython-resident.js +2 -10
- package/dist/runtime/esbuild-wasm-bytes.d.ts +25 -18
- package/dist/runtime/esbuild-wasm-bytes.d.ts.map +1 -1
- package/dist/runtime/esbuild-wasm-bytes.js +55 -30
- package/dist/runtime/facet-loader-host.d.ts.map +1 -1
- package/dist/runtime/facet-loader-host.js +0 -9
- package/dist/runtime/node-shims.d.ts.map +1 -1
- package/dist/runtime/node-shims.js +853 -181
- package/dist/runtime/python-repl.d.ts +4 -3
- package/dist/runtime/python-repl.d.ts.map +1 -1
- package/dist/runtime/python-repl.js +10 -39
- package/dist/runtime/ruby-repl.d.ts +3 -2
- package/dist/runtime/ruby-repl.d.ts.map +1 -1
- package/dist/runtime/ruby-repl.js +7 -6
- package/dist/runtime/ruby-resident.d.ts.map +1 -1
- package/dist/runtime/ruby-resident.js +5 -16
- package/dist/runtime/runtime-catalog.js +1 -1
- package/dist/runtime/wasi/preamble.d.ts +0 -22
- package/dist/runtime/wasi/preamble.d.ts.map +1 -1
- package/dist/runtime/wasi/preamble.js +160 -1445
- package/dist/runtime-catalog.generated.js +1 -1
- package/dist/session/hibernation.d.ts +45 -2
- package/dist/session/hibernation.d.ts.map +1 -1
- package/dist/session/hibernation.js +78 -1
- package/dist/session/init.d.ts.map +1 -1
- package/dist/session/init.js +1 -0
- package/dist/session/nimbus-session.d.ts +16 -23
- package/dist/session/nimbus-session.d.ts.map +1 -1
- package/dist/session/nimbus-session.js +25 -36
- package/dist/session/npm-install-port.d.ts.map +1 -1
- package/dist/session/npm-install-port.js +1 -0
- package/dist/session/port-capability.d.ts.map +1 -1
- package/dist/session/port-capability.js +11 -1
- package/dist/session/programmatic.js +2 -2
- package/dist/session/routes.d.ts.map +1 -1
- package/dist/session/routes.js +4 -2
- package/dist/session/rpc.d.ts +7 -44
- package/dist/session/rpc.d.ts.map +1 -1
- package/dist/session/rpc.js +17 -67
- package/dist/session/supervisor-op.d.ts +8 -3
- package/dist/session/supervisor-op.d.ts.map +1 -1
- package/dist/session/supervisor-op.js +10 -45
- package/dist/session/supervisor-rpc.d.ts +47 -22
- package/dist/session/supervisor-rpc.d.ts.map +1 -1
- package/dist/session/supervisor-rpc.js +64 -26
- package/dist/vfs/facet-resident-store.d.ts.map +1 -1
- package/dist/vfs/facet-resident-store.js +4 -2
- package/dist/workspace-host.d.ts +2 -1
- package/dist/workspace-host.d.ts.map +1 -1
- package/dist/wrangler/nimbus-wrangler.d.ts.map +1 -1
- package/dist/wrangler/nimbus-wrangler.js +3 -0
- package/package.json +30 -4
- package/public/_assets/esbuild-0.24.2.js +2380 -0
- package/public/_assets/runtime/{node-shims-8f8c64edd2a1f0f5.js → node-shims-7b4dd7a76d95d21e.js} +852 -180
- package/scripts/bundle-esbuild-wasm.mjs +55 -39
- package/scripts/bundle-facet-workers.mjs +45 -7
- package/scripts/bundle-runtime.mjs +35 -8
package/public/_assets/runtime/{node-shims-8f8c64edd2a1f0f5.js → node-shims-7b4dd7a76d95d21e.js}
RENAMED
|
@@ -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
|
|
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
|
|
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
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
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
|
|
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
|
-
|
|
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, () =>
|
|
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
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
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
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
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
|
-
|
|
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
|
-
() =>
|
|
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
|
|
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
|
-
|
|
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
|
|
2929
|
+
return _direntObject(n, isDir ? "directory" : "file", absPath);
|
|
2695
2930
|
});
|
|
2696
2931
|
}
|
|
2697
2932
|
return arr;
|
|
2698
2933
|
}
|
|
2699
2934
|
|
|
2700
2935
|
// ── mkdirSync ──
|
|
2701
|
-
|
|
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
|
|
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
|
|
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
|
|
2732
|
-
const
|
|
2733
|
-
const
|
|
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
|
-
|
|
2752
|
-
|
|
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
|
|
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
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
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
|
-
|
|
3035
|
-
|
|
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
|
-
|
|
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 {
|
|
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
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
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
|
-
|
|
3324
|
-
|
|
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) => {
|
|
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 =
|
|
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
|
-
|
|
3532
|
-
|
|
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;
|
|
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
|
-
// ──
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
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 = {
|
|
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
|