Skip to content

Bypass rexie, surface real DOM errors and harden commit batching#10

Open
ssttuu wants to merge 2 commits into
surrealdb:mainfrom
ssttuu:fix-idb-error-and-harden-commit
Open

Bypass rexie, surface real DOM errors and harden commit batching#10
ssttuu wants to merge 2 commits into
surrealdb:mainfrom
ssttuu:fix-idb-error-and-harden-commit

Conversation

@ssttuu
Copy link
Copy Markdown

@ssttuu ssttuu commented Apr 27, 2026

What is the motivation?

End users (surrealdb/surrealdb.js#571, surrealdb/surrealist#1155, #9) hit a generic
InternalError: An IndexedDB error occured: idb error
the first time they call db.use(ns, db) after
db.connect('indxdb://...') on @surrealdb/wasm 3.0.x. The actual
DOMException name and message never reach the user, making the
failure undebuggable. Investigating it surfaced a related concern
about how the commit() flush dispatches mixed put + delete batches.

What does this change do?

  1. Bypass rexie, talk to idb directly. rexie::Error::IdbError's
    Display impl is "idb error" with no {0} placeholder, so the
    wrapped idb::Error (and the DOMException it carries) was always
    discarded by the time it reached From<rexie::Error> for indxdb::Error. Replacing the rexie indirection with a direct
    idb integration lets format_idb_error extract the
    DOMException's name and message so callers now see
    InvalidStateError: A request was placed against a transaction which is currently not active and similar -- the actual reason
    the IDB call failed.

  2. Harden Transaction::commit()'s flush phase. Every buffered
    put and delete is now dispatched on a single fresh read-write
    IDB transaction, synchronously, keeping only the last request
    handle. Only that last request is awaited (mirroring the pattern
    idb::ObjectStore::put_all uses internally). Because no .await
    is interleaved with the issuing loop, the IDB transaction's
    pending-request queue is never empty during dispatch and the
    transaction cannot auto-commit prematurely. The previous code
    awaited each delete() sequentially after put_all, which the
    IDB spec does not guarantee keeps the transaction active across
    the wake-up microtask boundary.

  3. Browser regression tests + CI. A new tests/web.rs
    wasm-bindgen-test suite covers put/get round-trips, mixed
    put+delete commits, multi-transaction sequences (the shape of
    db.use()), savepoint rollback, read-your-own-writes and
    conditional writes. Each test opens a freshly-named IDB database
    so the suite is parallel-safe. CI runs the suite headless under
    both Chrome and Firefox via wasm-pack test. `cargo clippy` is
    also extended to `--all-targets` so test code is held to the
    same standard as the library.

The public API is unchanged. The `rexie` dependency is dropped in
favour of `idb` directly. The crate version is bumped to `0.13.0`.

What is your testing strategy?

GitHub Actions testing -- the new `browser-test` matrix job runs the
`wasm-bindgen-test` suite headless under Chrome and Firefox. The
`mixed_put_delete_in_single_commit` and
`multi_transaction_use_simulation` cases are direct regressions for
the user-reported scenarios. Local `cargo check`,
`cargo clippy --all-targets --target wasm32-unknown-unknown` and
`cargo fmt --check` all pass.

Security Considerations

No security implications. The change is internal to the WASM-only
storage backend; no new untrusted inputs are accepted, and the error
formatting path only stringifies a `web_sys::DomException`'s
`name` and `message` properties (always-safe, browser-supplied
strings). The `rexie` dependency is dropped, reducing the
dependency surface.

Is this related to any issues?

Have you read the Contributing Guidelines?

  • Yes

Copy link
Copy Markdown

@claude claude Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

This release does three independent things, all motivated by the
user-visible "An IndexedDB error occured: idb error" failure reported
in surrealdb.js#571 / surrealist#1155 / indxdb#9 when calling
`db.use()` shortly after `db.connect('indxdb://...')`.

1. Wrap the underlying `idb` crate directly instead of going through
   `rexie`. The `From<rexie::Error>` conversion only ever printed
   "idb error" because `rexie::Error::IdbError` has no `{0}`
   placeholder in its `Display` impl, so the inner DOMException name
   and message were silently dropped before reaching the client. The
   new `From<idb::Error>` impl pulls the `name`/`message` out of any
   wrapped DOMException so callers see e.g. `InvalidStateError: A
   request was placed against a transaction which is currently not
   active` instead of the cryptic generic message.

2. Refactor `Transaction::commit()` to fire every buffered put and
   delete through a single read-write IDB transaction, synchronously,
   keeping only the most recently issued request handle. Only the last
   request is awaited (the same pattern `idb::ObjectStore::put_all`
   uses internally). Because no `.await` is interleaved with the
   issuing loop, the IDB transaction's pending-request queue is never
   empty during dispatch, so it cannot auto-commit prematurely. The
   previous implementation awaited each `delete()` sequentially after
   `put_all`, which the IDB spec does not guarantee will keep the
   transaction active across the wake-up microtask boundary.

3. Add a `tests/web.rs` `wasm-bindgen-test` suite covering put/get
   round-trips, mixed put+delete commits, multi-transaction sequences
   (the shape of `db.use()`), savepoint rollback, read-your-own-writes
   and conditional writes. Each test opens a freshly-named IDB
   database so the suite is parallel-safe. CI runs the suite headless
   under both Chrome and Firefox via `wasm-pack test`.

The public API is unchanged; the `rexie` dependency is dropped in
favour of `idb` directly.

Bumps the crate version to 0.13.0.

Made-with: Cursor
@ssttuu ssttuu force-pushed the fix-idb-error-and-harden-commit branch from aa2841c to 2f45107 Compare April 27, 2026 19:57
CI's stable rustfmt produces different output to my local environment
because rustfmt.toml contains nightly-only options that get silently
ignored on stable. Apply the stable formatter's output.

Made-with: Cursor
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: IndexedDB not working in @surrealdb/wasm 3.x

1 participant