Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,90 @@
<!-- markdownlint-disable MD024 -->
# Capability Spec Delta: storage-file (bun-fs adapter)
**Package**: `@suaveplan/storage-file`
**Status**: PROPOSED
> Every requirement below carries a `**Verified by:**` line at authoring time. No exceptions.
## ADDED Requirements
### Requirement: defaultBunFs satisfies NodeFsLike via Bun-native read/write
The package SHALL export a `defaultBunFs(): NodeFsLike` factory from
`src/bun-fs/bun-fs.ts`. The returned object's `readFile(path)` SHALL be
implemented in terms of `Bun.file(path).bytes()` and its `writeFile(path, data)`
SHALL be implemented in terms of `Bun.write(path, data)`. Every other method
on the returned `NodeFsLike` (`mkdir`, `readdir`, `rename`, `unlink`, `stat`,
`access`, `open`, `createReadStream`, `createWriteStream`) SHALL delegate to
the same `node:fs/promises` / `node:fs` calls used by `defaultNodeFs()`. The
factory SHALL return a fresh object per call so callers can selectively
override individual methods without mutating shared state.
#### Scenario: readFile round-trips Bun.write output
- **WHEN** a caller calls `defaultBunFs().writeFile(path, bytes)` followed by
`defaultBunFs().readFile(path)` against a real temp dir
- **THEN** the returned `Uint8Array` is byte-equal to `bytes`
#### Scenario: every other method forwards to node:fs/promises behaviour
- **WHEN** a caller exercises `mkdir`, `readdir`, `stat`, `access`, `rename`,
`unlink`, `open`, `createReadStream`, and `createWriteStream` on a
`defaultBunFs()` instance against a real temp dir
- **THEN** every call returns the same shape and side effects as the
matching method on `defaultNodeFs()` (`stat.isFile()/isDirectory()` work,
`readdir` entries expose `isFile`/`isDirectory`/`parentPath`, the file
handle from `open` supports positioned `read` and `close`, the streams
flow bytes end-to-end)
**Verified by:** `src/bun-fs/bun-fs.test.ts::"round-trips bytes through Bun.write and Bun.file"` AND `src/bun-fs/bun-fs.test.ts::"forwards mkdir, readdir, stat, access, rename, unlink, open, and the stream constructors"`
---
### Requirement: pickDefaultFs selects the Bun adapter at runtime
The package SHALL export a `pickDefaultFs(): NodeFsLike` factory from
`src/bun-fs/bun-fs.ts` that returns `defaultBunFs()` when `globalThis.Bun`
is defined and `defaultNodeFs()` otherwise. The probe SHALL be performed on
each call (never cached at module scope) so test harnesses can deterministically
switch adapters by injecting an explicit `fs` option to `NodeFsStorage`.
#### Scenario: probe selects the Bun adapter under Bun
- **WHEN** the test runs under Bun (the `bun` condition in
`@suaveplan/testing/runner`) and the caller invokes `pickDefaultFs()`
- **THEN** the returned `NodeFsLike` `readFile` and `writeFile` are sourced
from `defaultBunFs()`, observable by performing a round-trip and confirming
the byte contents are preserved against a real temp file
**Verified by:** `src/bun-fs/bun-fs.test.ts::"pickDefaultFs returns a working NodeFsLike under Bun"`
---
### Requirement: NodeFsStorage default fs honours runtime probe
`resolveConfig` in `src/node-fs-storage/node-fs-storage.helpers.ts` SHALL
resolve a missing `options.fs` by calling `pickDefaultFs()` rather than
`defaultNodeFs()`. The behaviour SHALL be backwards compatible: when the
caller passes `options.fs` explicitly, the injected adapter is used
unchanged. No existing scenario in the canonical `storage-file` spec is
modified — every assertion against `NodeFsStorage`'s public surface
continues to hold.
#### Scenario: explicit fs option overrides the runtime probe
- **WHEN** a caller constructs `new NodeFsStorage({ rootDir, fs: customFs })`
- **THEN** every filesystem call routes through `customFs` and
`pickDefaultFs()` is not consulted
#### Scenario: missing fs option under Bun uses defaultBunFs
- **WHEN** a caller constructs `new NodeFsStorage({ rootDir })` under Bun and
performs `await storage.set("k", bytes)` followed by `await storage.get("k")`
- **THEN** the returned `Uint8Array` is byte-equal to `bytes` and the
spec-conformance suite for `NodeFsStorage` continues to pass
**Verified by:** `src/bun-fs/bun-fs.test.ts::"NodeFsStorage round-trips through the auto-picked Bun fs"` AND `src/node-fs-storage/node-fs-storage.spec-conformance.test.ts::"declares the documented capabilities matrix"`
---