first commit
This commit is contained in:
60
docs/persistence/storage/storage-file/src/node-fs/node-fs.md
Normal file
60
docs/persistence/storage/storage-file/src/node-fs/node-fs.md
Normal file
@@ -0,0 +1,60 @@
|
||||
# `node-fs`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
Provides the default `NodeFsLike` implementation backed by `node:fs/promises` and the two stream constructors from `node:fs`. The factory is the single binding point between this package and Node's filesystem APIs — every other module talks to the structural `NodeFsLike` interface so tests can substitute real in-memory or hooked adapters without `vi.mock`.
|
||||
|
||||
## Features
|
||||
|
||||
- Returns a fresh `NodeFsLike` object per call so callers can spread-and-override individual methods without mutating shared state.
|
||||
- Forwards `readFile` results through `new Uint8Array(buffer, byteOffset, byteLength)` so consumers get a stable `Uint8Array` view regardless of the underlying Buffer subclass.
|
||||
- Wraps `node:fs/promises.open` so the returned handle matches the structural `NodeFsFileHandleLike` interface (only `read` + `close`).
|
||||
- Translates `readdir(path, { recursive: true, withFileTypes: true })` Dirent entries into the lighter `NodeFsReaddirEntry` shape exposed to the rest of the package.
|
||||
- Translates `stat` into the lighter `NodeFsStatLike` shape exposing only the four fields the adapter reads.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { defaultNodeFs } from "@suaveplan/storage-file";
|
||||
|
||||
const fs = defaultNodeFs();
|
||||
await fs.mkdir("/tmp/store", { recursive: true });
|
||||
await fs.writeFile("/tmp/store/hello.data", new TextEncoder().encode("hi"));
|
||||
const data = await fs.readFile("/tmp/store/hello.data");
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { defaultNodeFs, NodeFsStorage } from "@suaveplan/storage-file";
|
||||
import type { NodeFsLike } from "@suaveplan/storage-file/types";
|
||||
|
||||
const base = defaultNodeFs();
|
||||
|
||||
// Wrap stat to ensure mtimes never go backwards under wall-clock skew.
|
||||
const monotonicStat: NodeFsLike = {
|
||||
...base,
|
||||
async stat(path) {
|
||||
const s = await base.stat(path);
|
||||
return { ...s, mtimeMs: Math.max(s.mtimeMs, Date.now()) };
|
||||
},
|
||||
};
|
||||
|
||||
const storage = new NodeFsStorage({ rootDir: "/tmp/store", fs: monotonicStat });
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `defaultNodeFs(): NodeFsLike` — returns a fresh adapter object.
|
||||
|
||||
Every method on the returned object forwards to its `node:fs/promises` counterpart with minimal shape translation. See `fs-adapter.types.md` for the full method list.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- The factory pattern (vs a module-level singleton) is deliberate: returning a fresh object lets tests construct independent adapters per `it(...)` block and verify ownership semantics.
|
||||
- The factory is dependency-free at module evaluation time — every Node import is at the top of the file, but `defaultNodeFs()` itself doesn't reach into globals or open any handles. Callers can build the storage adapter at import time without paying any filesystem cost.
|
||||
- The lazy buffer-view translation in `readFile` avoids a copy when callers operate on the result via DataView or pass it back into a hash function.
|
||||
Reference in New Issue
Block a user