You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
OPFS-backed persistence for the browser entry (@libredb/libredb/browser) shipped
in #8. The adapter — src/adapter/opfs.ts, opfsFileSystem(handle) — wraps a FileSystemSyncAccessHandle so the synchronous kernel can be durable in a browser
with no async core. Its behaviour is 100% covered, but only against an in-memory
fake (src/adapter/opfs.test.ts). We have proven the adapter logic; we have not proven it works end-to-end against a real browser OPFS, inside a real
Web Worker, on the engines our users actually run.
This issue tracks adding a real-browser end-to-end verification across Chrome,
Firefox, and Safari. It is a verification task — no change to the adapter is
expected unless a browser surfaces a real defect.
Why this is needed
Sync access handles only exist inside a Web Worker and are obtained
asynchronously (navigator.storage.getDirectory -> getFileHandle -> createSyncAccessHandle). None of that path is touched by the current unit
test.
The three engines differ in OPFS history and semantics (version floors, createSyncAccessHandle modes, flush/truncate behaviour, eviction). A fake
cannot reveal engine-specific surprises.
The distribution-channels design spec
(docs/superpowers/specs/2026-06-29-distribution-channels-design.md) lists OPFS
persistence (Phase 5) with "Sync access handles are Worker-only; browser matrix"
as the standing risk. This closes it.
Scope / what to build
A minimal browser E2E harness, kept separate from the unit-test gate
(real-browser tests cannot run under bun test; they must not count toward or
break the 100% line/function/statement coverage held by bunfig.toml).
A tiny Worker fixture that does the real OPFS acquisition and opens a
path-backed database via open({ path, fs: opfsFileSystem(handle) }).
A page/driver that drives the Worker and asserts the scenarios below.
A CI job (separate from gate) that runs the matrix on each browser, with
honest reporting of any engine that is skipped (e.g. if Safari/WebKit cannot be
run in CI, say so rather than silently dropping it).
Test scenarios (per browser)
Roundtrip: open path-backed DB in a Worker, write via each lens (kv, doc, table), read back in the same session.
Durability across reopen: write, close(), re-acquire the handle, reopen the
same path, and assert the committed state is reconstructed exactly (the core
durability guarantee).
WAL replay / partial-write safety: exercise enough writes to confirm the append short-write loop (opfs.ts) behaves on a real handle; confirm no torn
record after reopen.
In-memory parity: the pathless open() path works on the main thread (no
Worker, no OPFS) on every browser.
Negative: a path-backed open with no fs fails as designed.
Browser matrix
Engine
Min target
Notes
Chromium (Chrome/Edge)
OPFS sync access handle since Chrome 102
baseline
Firefox
sync access handle since Firefox 111
verify flush/truncate semantics
Safari / WebKit
OPFS since 16.4
most likely to differ; document any CI limitation
Run over a secure context (https / localhost) since navigator.storage
requires it.
Constraints
Do not pull real-browser tests into the bun run gate coverage gate; wire
them as a separate script + CI job. Document clearly that adapter unit coverage
stays at 100% and the E2E job is additive.
Keep the runtime library zero-dependency; any browser-driver tooling
(e.g. Playwright) is a devDependency / CI-only concern, never shipped.
English-only, no emoji, conventional commits. A test-only/CI-only change does not require a changeset (it never reaches the published package).
Acceptance criteria
A documented, repeatable command runs the OPFS E2E suite locally against at
least one real browser.
CI runs the suite on Chromium and Firefox and is green; Safari/WebKit is either
covered or its omission is documented with rationale.
All scenarios above pass, or any real defect they surface is filed/fixed.
README's browser/OPFS section links to how to run the E2E suite.
Non-goals
No change to the synchronous kernel contract or the embedded, single-process
model.
No Worker/bridge helper shipped in the package — acquiring the handle and wiring
the Worker remains the consumer's responsibility by design.
No IndexedDB / async-face adapter (separate discussion if ever desired).
Summary
OPFS-backed persistence for the browser entry (
@libredb/libredb/browser) shippedin #8. The adapter —
src/adapter/opfs.ts,opfsFileSystem(handle)— wraps aFileSystemSyncAccessHandleso the synchronous kernel can be durable in a browserwith no async core. Its behaviour is 100% covered, but only against an in-memory
fake (
src/adapter/opfs.test.ts). We have proven the adapter logic; we havenot proven it works end-to-end against a real browser OPFS, inside a real
Web Worker, on the engines our users actually run.
This issue tracks adding a real-browser end-to-end verification across Chrome,
Firefox, and Safari. It is a verification task — no change to the adapter is
expected unless a browser surfaces a real defect.
Why this is needed
asynchronously (
navigator.storage.getDirectory->getFileHandle->createSyncAccessHandle). None of that path is touched by the current unittest.
createSyncAccessHandlemodes, flush/truncate behaviour, eviction). A fakecannot reveal engine-specific surprises.
(
docs/superpowers/specs/2026-06-29-distribution-channels-design.md) lists OPFSpersistence (Phase 5) with "Sync access handles are Worker-only; browser matrix"
as the standing risk. This closes it.
Scope / what to build
(real-browser tests cannot run under
bun test; they must not count toward orbreak the 100% line/function/statement coverage held by
bunfig.toml).path-backed database via
open({ path, fs: opfsFileSystem(handle) }).gate) that runs the matrix on each browser, withhonest reporting of any engine that is skipped (e.g. if Safari/WebKit cannot be
run in CI, say so rather than silently dropping it).
Test scenarios (per browser)
kv,doc,table), read back in the same session.close(), re-acquire the handle, reopen thesame path, and assert the committed state is reconstructed exactly (the core
durability guarantee).
appendshort-write loop (opfs.ts) behaves on a real handle; confirm no tornrecord after reopen.
catalog+ reserved-key guard behaveidentically to Node.
open()path works on the main thread (noWorker, no OPFS) on every browser.
openwith nofsfails as designed.Browser matrix
Run over a secure context (https / localhost) since
navigator.storagerequires it.
Constraints
bun run gatecoverage gate; wirethem as a separate script + CI job. Document clearly that adapter unit coverage
stays at 100% and the E2E job is additive.
(e.g. Playwright) is a devDependency / CI-only concern, never shipped.
not require a changeset (it never reaches the published package).
Acceptance criteria
least one real browser.
covered or its omission is documented with rationale.
Non-goals
model.
the Worker remains the consumer's responsibility by design.
References
src/adapter/opfs.ts,src/adapter/opfs.test.ts(in-memory fake).src/browser.ts(browser entry,opfsFileSystemexport).docs/superpowers/specs/2026-06-29-distribution-channels-design.md(Phase 5,browser-matrix risk).
README.md(Worker + OPFS usage note).