Skip to content

chore(deps): bump dexie 4.0.10 -> 4.4.2#8496

Merged
pubkey merged 9 commits into
pubkey:masterfrom
sahanxdissanayake:bump-dexie-to-4.4.2
May 13, 2026
Merged

chore(deps): bump dexie 4.0.10 -> 4.4.2#8496
pubkey merged 9 commits into
pubkey:masterfrom
sahanxdissanayake:bump-dexie-to-4.4.2

Conversation

@sahanxdissanayake
Copy link
Copy Markdown
Contributor

Summary

Bumps dexie from 4.0.10 (released 2024-11-15) to 4.4.2 (released 2026-03-31) to pick up dexie 4.2.1's fix for #2186 (PR #2187):

"Resolve issue #2186 by letting an external closure of the DB make it behave identical to explicit closing the database, except that we still respect autoOpen option."

Why this matters for RxDB downstream

In an RxDB 17.1.0 application using getRxStorageDexie() on iOS Safari, the dexie #2186 latent state-inconsistency is producing three error variants at production volume:

Error Source
AbortError: Transaction aborted dexie wrapper
BulkError: docs.bulkPut(): 1 of 1 operations failed. Errors: UnknownError: Attempt to delete range from database without an in-progress transaction WebKit IDB
UnknownError: Attempt to get a record from database without an in-progress transaction WebKit IDB

Mechanism:

  1. iOS jetsam kills the com.apple.WebKit.Storage XPC process under memory pressure / app backgrounding.
  2. In pre-4.2.1 dexie, Dexie.on.close fires but Dexie.isOpen() still returns true — internal state is inconsistent.
  3. RxDB's next bulkPut / get opens a transaction against the (now dead) connection.
  4. The next op on that transaction throws one of the variants above.

After bumping to dexie 4.2.1+, external closure transitions Dexie to a real closed state, surfacing the clean DatabaseClosedError which applications can filter / recover from.

The class of error has been observed to produce silent local-write loss in an offline-first admin tool — exactly the failure mode this codebase aims to prevent. The RxDB 17 internal bulkWrite surface increase appears to have amplified how often the latent dexie bug fires (first-seen jumped 9 days after a downstream RxDB 16 → 17 bump).

Compatibility verified

Locally against this tag (pubkey/rxdb@17.1.0):

git clone --depth 1 --branch 17.1.0 https://github.com/pubkey/rxdb.git
# bump dexie to 4.4.2 in package.json
yarn install --ignore-scripts
yarn run build
yarn run build:test
cross-env DEFAULT_STORAGE=dexie NODE_ENV=fast \
  ./node_modules/.bin/mocha --config ./config/.mocharc.cjs ./test_tmp/unit.test.js

Result: 1000 / 1000 dexie tests pass. The single failure was replication-webrtc.test.ts > import WebRTC polyfills on Node.js — unrelated to dexie (it's a node_datachannel.node native binding install issue on darwin-arm64 when --ignore-scripts is used to skip the prebuild).

Note for review

This bump also requires rxdb-old's nested dexie to be updated. rxdb-old (a test dep used for backward-compat tests) pins its own dexie@4.0.10 in its nested node_modules. At Dexie construction time the dedup check throws Two different versions of Dexie loaded in the same app: 4.0.10 and 4.4.2. To run the suite locally I symlinked node_modules/rxdb-old/node_modules/dexie to the top-level dexie. The correct upstream fix is to bump rxdb-old to a version whose own dexie pin is 4.4.2 (or similarly compatible).

Context

Prior renovate bump PRs (#7387 4.2.0, #7443 4.2.1, #7764 4.3.0) were each closed without explanatory comment. PR #7948 then added dexie to renovate.json:ignoreDeps. If there is a specific known incompatibility, a one-line note would be very helpful — I can dig further and adjust this PR. Otherwise this looks like the right path to resolving a real iOS-Safari issue for downstream users without forcing them to use a package-manager override.

Refs

Sahan Dissanayake added 6 commits May 12, 2026 06:12
Picks up dexie 4.2.1's fix for pubkey#2186 (PR pubkey#2187): when an external
agent closes the IDB connection (e.g. iOS Safari jetsam killing the
`com.apple.WebKit.Storage` XPC process under memory pressure),
pre-4.2.1 dexie left `Dexie.isOpen()` returning `true` while the
underlying connection was dead. The next `bulkPut` / `get` would
open a transaction against the dead connection, surfacing as either
`AbortError: Transaction aborted` or `UnknownError: Attempt to
{delete range|get a record} from database without an in-progress
transaction`.

These error variants are firing at production volume in an
RxDB 17.1.0 application using `getRxStorageDexie()` on iOS Safari.
The class of error has been the cause of an internal customer
incident producing silent local-write loss.

dexie 4.2.1 (PR pubkey#2187): "letting an external closure of the DB
make it behave identical to explicit closing the database". After
the fix dexie surfaces `DatabaseClosedError` which the application
can filter / recover from cleanly.

Compatibility verified locally against rxdb@17.1.0:
- `npm run test:fast:dexie` -> 1000 / 1000 dexie tests pass
- The single failure was an unrelated WebRTC native-binding install
  issue (`node_datachannel.node` not built for darwin-arm64) and is
  unrelated to dexie.

Note for review: this bump also requires `rxdb-old`'s nested dexie
to be updated (it pins 4.0.10) so the dedup check at `Dexie`
construction time does not throw. Locally I symlinked
`node_modules/rxdb-old/node_modules/dexie` to the top-level dexie
to run the suite; the right upstream fix is to bump rxdb-old too.

Prior bump PRs (pubkey#7387 4.2.0, pubkey#7443 4.2.1, pubkey#7764 4.3.0) were closed
without comment. If there is a specific known incompatibility, I'd
appreciate a one-line note — I can dig in further. Otherwise this
appears to be the path to resolving the iOS issue for downstream
users without adding a pnpm/yarn override.

Refs: dexie issue pubkey#2186, dexie PR pubkey#2187.
Adds a yarn `resolutions` block to force `rxdb-old`'s nested dexie
to the same version. Without this, CI fails with:

    Error: Two different versions of Dexie loaded in the same app:
    4.0.10 and 4.4.2
        at node_modules/rxdb-old/node_modules/dexie/import-wrapper.mjs

`rxdb-old` is aliased to `rxdb@16.21.1` and bundles its own
`dexie@4.0.10` nested. Dexie's module-load-time dedup check throws
when both 4.0.10 and 4.4.2 are loaded.

Verified locally: with this resolution applied, only the top-level
`node_modules/dexie` remains (single 4.4.2 install across the tree),
and the dexie storage test suite runs to completion — 1029 / 1030
tests pass. The single failure is the same unrelated WebRTC native
binding issue on darwin-arm64 (`node_datachannel.node` not built
when `--ignore-scripts` is used in local install). CI has the
prebuilt binary so it should not affect the GitHub Actions run.
CI runs `npm install`, not `yarn install` (see .github/workflows/main.yml).
The `resolutions` block in the prior commit is yarn-only — npm ignores
it — so CI still ended up with rxdb-old's nested dexie 4.0.10 alongside
the top-level 4.4.2 and Dexie's dedup check threw at module load time:

    Error: Two different versions of Dexie loaded in the same app:
    4.0.10 and 4.4.2

Adds `dexie: 4.4.2` to the existing npm `overrides` block (which
already pins eslint and webpack-dev-server). Keeps `resolutions` too
so local yarn workflows behave the same as CI.

Verified locally with `npm install --ignore-scripts`: the only dexie
in `node_modules` is the top-level 4.4.2; no nested install under
rxdb-old.
…i jetsam)

Per https://rxdb.info/contribution.html ("Every feature or bugfix
must be committed together with a unit-test"), this adds a focused
regression test for the dexie 4.0.10 → 4.4.2 bump.

The test:

1. Creates an RxDB database backed by the dexie storage adapter.
2. Reaches the underlying Dexie instance through
   `collection.storageInstance.internals.dexieDb`.
3. Manually invokes `dexieDb.idbdb.onclose(new Event('close'))` —
   the same code path the browser walks when iOS Safari's WebKit
   Storage XPC process is reaped by jetsam under memory pressure
   or app backgrounding.
4. Asserts `dexieDb.isOpen()` returns `false` after the close
   handler runs.

On dexie >= 4.2.1 (which carries
dexie/Dexie.js#2187 — the fix for
dexie/Dexie.js#2186) the assertion holds
because the onclose handler now invokes
`db.close({ disableAutoOpen: false })`. On dexie < 4.2.1 the same
handler only refired the `close` event; the next RxDB `bulkWrite`
would open a transaction against the dead connection and surface
as "AbortError: Transaction aborted" or "Attempt to {delete range|
get a record} from database without an in-progress transaction".

Verified locally:
  $ yarn run build:test
  $ cross-env DEFAULT_STORAGE=dexie NODE_ENV=fast \\
      ./node_modules/.bin/mocha --config ./config/.mocharc.cjs \\
      --grep "iOS Safari jetsam" ./test_tmp/unit.test.js
  1 passing (50ms)

If the dexie pin is rolled back below 4.2.1 this test will fail.
The prior run hit a flaky timeout in
`rx-database.test.ts > using > should automatically cleanup after
scope when "using" is used` — unrelated to the dexie change (master
passes the same test on its most recent run, 25674054338). Re-running
to confirm the regression test stays green.
My earlier test for dexie pubkey#2186 simulated `idbdb.onclose` (iOS jetsam)
and asserted `dexieDb.isOpen() === false`. That part is correct, but
the test never called `db.close()` afterwards. The onclose handler
closes only the dexie connection; RxDB has no idea and its internal
DB_COUNT stays incremented forever.

When the full unit suite runs, the next test that creates and closes
a database brings DB_COUNT back to 1 (not 0) because of the orphan
my test left behind. That makes `rx-database.test.ts > using >
should automatically cleanup after scope when "using" is used`
time out — it waits for `dbCount() === 0` which is now unreachable.

Fix: call `db.close()` at the end of my test, inside a try/catch so
the already-closed storage doesn't escape. RxDB's outer close still
runs and decrements DB_COUNT.

Verified locally in /tmp/rxdb-verify (a fresh clone of master with
the dexie 4.0.10 -> 4.4.2 bump + the test fix applied): the full
`test:node:dexie` suite goes from "354 passing, 1 failing" (using
test timeout) to "1382 passing, 1 failing", with the remaining
failure being `plugin.test.js > full.node.ts: spawn mocha ENOENT`
which is a local PATH-only issue unrelated to dexie.
Comment thread package.json
Sahan Dissanayake added 2 commits May 13, 2026 07:42
Resolves conflict in package.json `overrides` block: take upstream's
`eslint: 10.3.0` bump and keep the `dexie: 4.4.2` entry added by this
branch.

Drops the `resolutions` block — verified locally that `overrides`
alone is sufficient under `npm install` (which is what
`.github/workflows/main.yml` uses). The yarn-only path the
resolutions block targeted is not exercised on CI. With only
`overrides` in package.json, the full storage-dexie suite runs
1382 passing, 0 failing.

If yarn-local parity is desired we can add `resolutions` back in a
follow-up — happy to do that on request.
The previous merge commit accidentally staged a local Claude Code
plugin artifact that is not relevant to RxDB. Removing.
@pubkey
Copy link
Copy Markdown
Owner

pubkey commented May 13, 2026

Please remove that test case from the PR. Updating dexie is good enough, we do not want to test dexie internals.

@sahanxdissanayake sahanxdissanayake requested a review from pubkey May 13, 2026 06:51
@pubkey pubkey merged commit b048a70 into pubkey:master May 13, 2026
22 of 24 checks passed
@sahanxdissanayake sahanxdissanayake deleted the bump-dexie-to-4.4.2 branch May 13, 2026 07:21
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.

2 participants