Files
2026-05-27 23:29:53 +01:00

4.3 KiB

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"