Initial Commit
This commit is contained in:
@@ -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"`
|
||||
|
||||
---
|
||||
Reference in New Issue
Block a user