@suaveplan/storage-browser-opfs - Browser OPFS AbstractStorage adapter for @suaveplan/storage: origin-scoped persistent file storage via navigator.storage.getDirectory(), AbortSignal everywhere, strict key sanitisation, native Web Streams, native partial reads + partial writes, DOMException → typed OpfsError mapping, full OTel surface.
Browser-tier AbstractStorage adapter backed by the Origin Private File System (OPFS). Provides persistent, origin-scoped key-value storage for browser consumers (vault snapshots, drive chunk caches, in-app i18n catalogues, SQLite-WASM backing files), with full AbstractStorage conformance, native Web Streams, native partial reads + partial writes, AbortSignal threading, Zod-validated options, structured OpfsError boundary, and a complete OpenTelemetry surface.
Documentation tree
- filename-codec — (no submodules)
- filename-codec — (no submodules)
- in-memory-opfs — (no submodules)
- in-memory-opfs — (no submodules)
- key-sanitizer — (no submodules)
- key-sanitizer — (no submodules)
- opfs-adapter — (no submodules)
- opfs-adapter — (no submodules)
- opfs-storage — (no submodules) - opfs-storage.ops — Hosts pure / nearly-pure helpers…
- opfs-storage.errors — Encapsulates the mapping between WHATWG
DOMExceptionshapes thrown by the OPFS API and the typedOpfsErrorcodes th… - opfs-storage — (no submodules) - opfs-storage.ops — Hosts pure / nearly-pure helpers…
- opfs-storage.ops — Hosts pure / nearly-pure helpers that
OpfsStoragecalls but that would push the class file over the 300-line hard bud… - opfs-storage.streams — Factors the
createReadStream/createWriteStreambuilders out of the mainOpfsStorageclass so the class stays un…
- opfs-storage.errors — Encapsulates the mapping between WHATWG
- otel — (no submodules)
- otel — (no submodules)
- registry — (no submodules)
- registry — (no submodules)
- error-codes — Single source of truth for every error code the
@suaveplan/storage-browser-opfspackage can throw. The registry uses…
- filename-codec — (no submodules)- in-memory-opfs — (no submodules) - in-memory-opfs — (no submodules)- key-sanitizer — (no submodules) - key-sanitizer — (no submodules)- opfs-adapter — (no submodules) - opfs-adapter — (no submodules)- opfs-storage — (no submodules) - opfs-storage.errors — Encapsulates the mapping between WHATWG
DOMExceptionshapes thrown by the OPFS API and the typedOpfsErrorcodes th… - opfs-storage — (no submodules) - opfs-storage.ops — Hosts pure / nearly-pure helpers that
OpfsStoragecalls but that would push the class file over the 300-line hard bud… - opfs-storage.streams — Factors the
createReadStream/createWriteStreambuilders out of the mainOpfsStorageclass so the class stays un… - otel — (no submodules) - otel — (no submodules)- registry — (no submodules) - registry — (no submodules)- error-codes — Single source of truth for every error code the
@suaveplan/storage-browser-opfspackage can throw. The registry uses…
Install
bun add @suaveplan/storage-browser-opfs
Quick start
import {
createOpfsStorage,
isOpfsAvailable,
} from "@suaveplan/storage-browser-opfs";
if (!isOpfsAvailable()) {
throw new Error("This browser does not support OPFS");
}
const storage = createOpfsStorage({ directory: "myapp" });
await storage.set("user/42", new TextEncoder().encode("hello"));
const back = await storage.get("user/42");
Factory integration
import { registerOpfsProvider } from "@suaveplan/storage-browser-opfs/registry";
import { createStorage } from "@suaveplan/storage/factory";
registerOpfsProvider();
const storage = createStorage({ type: "opfs", config: { directory: "myapp" } });
The package does NOT self-register at module-evaluation time — call registerOpfsProvider() explicitly so sideEffects: false bundlers can tree-shake the factory path when not used.
Capabilities
| Capability | Value | Notes |
|---|---|---|
partialReads |
true |
Via File.slice(...).arrayBuffer(). |
partialWrites |
true |
Via FileSystemWritableFileStream.seek(). |
nativeStreams |
true |
File.stream() for read; buffered close-on-commit for write. |
atomicWrites |
false |
Close-as-commit semantics within a single realm; no cross-realm locking. |
contentAddressable |
false |
Keys are caller-supplied strings. |
Modules
src/error-codes.ts—OPFS_CODESregistry +OpfsError.src/key-sanitizer/key-sanitizer.ts— strict key boundary.src/filename-codec/filename-codec.ts— caller-key ↔ OPFS-filename round-trip.src/opfs-adapter/opfs-adapter.ts—defaultOpfs()+isOpfsAvailable().src/opfs-storage/opfs-storage.ts— theOpfsStorageclass.src/opfs-storage/opfs-storage.errors.ts— DOMException mapping.src/opfs-storage/opfs-storage.ops.ts— internal helpers.src/opfs-storage/opfs-storage.streams.ts—ReadableStream/WritableStreambuilders.src/otel/otel.ts— OpenTelemetry instrument set.src/registry/registry.ts—registerOpfsProvider().src/in-memory-opfs/in-memory-opfs.ts— real-implementation test double, exposed under./in-memory-opfsfor downstream test packages.src/types/opfs-like.types.ts— structural OPFS surface.src/types/opfs-storage.types.ts— option boundary.
License
MIT.