From 11be3bd3e3d817925f8d9436219a96ffff875ca0 Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Wed, 23 Sep 2026 12:06:53 +0200 Subject: [PATCH] vfs: add ComposableProvider for layered mounts Allow providers to be layered at one mount point. Reads search layers in priority order, while writes copy lower-layer files to the first provider and deletions hide lower copies without changing them. Assisted-by: pi Signed-off-by: Matteo Collina --- doc/api/vfs.md | 51 +++ lib/internal/vfs/providers/composable.js | 416 ++++++++++++++++++ lib/vfs.js | 2 + test/parallel/test-vfs-composable-provider.js | 117 +++++ 4 files changed, 586 insertions(+) create mode 100644 lib/internal/vfs/providers/composable.js create mode 100644 test/parallel/test-vfs-composable-provider.js diff --git a/doc/api/vfs.md b/doc/api/vfs.md index edbb1c306dff..ee73092f4f8e 100644 --- a/doc/api/vfs.md +++ b/doc/api/vfs.md @@ -594,6 +594,56 @@ provider.setReadOnly(); myVfs.writeFileSync('/x.txt', 'fail'); // throws EROFS ``` +## Class: `ComposableProvider` + + + +[`ComposableProvider`][] combines one or more providers in priority order. The first +provider is the writable layer; reads search from first to last. Directories +are merged, with entries in higher-priority layers shadowing entries with the +same name in lower layers. Writes to a lower file copy it to the first provider +before changing it. Removing a file hides lower copies without deleting them. +The first provider must be writable to change the composed file system. + +### `new ComposableProvider(providers)` + + + +* `providers` {VirtualProvider\[]} Non-empty array of providers, ordered from + highest to lowest priority. + +```cjs +const vfs = require('node:vfs'); + +const memory = new vfs.MemoryProvider(); +const disk = new vfs.RealFSProvider('/tmp/vfs-root'); +const combined = vfs.create(new vfs.ComposableProvider([memory, disk])); +combined.writeFileSync('/config.json', '{"debug":true}'); +// The file in memory shadows /tmp/vfs-root/config.json. +``` + +### `composableProvider.providers` + + + +* {VirtualProvider\[]} + +A copy of the ordered provider list. Changes to this array do not affect the +composition. File handles opened before a write continue to refer to the layer +on which they were opened. Watching a path watches only its currently selected +provider, not changes across the entire composition. Symbolic links are +resolved by the provider containing them, not across providers. Traversal +through a symbolic-link directory is not supported by the composition. Renaming +a directory over a directory that exists only in a lower layer is not supported. +Layer selection and copy-up use synchronous provider operations, including +when invoked through the asynchronous VFS API. + ## Class: `RealFSProvider`