Skip to content

Verify OPFS browser persistence end-to-end on Chrome, Firefox, and Safari #10

Description

@cevheri

Summary

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

  1. 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).
  2. A tiny Worker fixture that does the real OPFS acquisition and opens a
    path-backed database via open({ path, fs: opfsFileSystem(handle) }).
  3. A page/driver that drives the Worker and asserts the scenarios below.
  4. 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.
  • Reserved-key / catalog integrity: catalog + reserved-key guard behave
    identically to Node.
  • 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).

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No fields configured for Task.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions