a02b236e97
* fix(sentry): drop more benign View Transition rejections Broaden is_ignored_browser_error to also drop "Transition was skipped" (navigation superseded, READEST-F) and "aborted because of invalid state" (READEST-G), matched case-insensitively alongside the existing hidden-tab case. These are expected browser behavior — the navigation completes, only the animation is skipped/aborted. A transition timeout stays visible (real perf signal, handled separately). Fixes READEST-F Fixes READEST-G Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(library): create the book directory idempotently Importing a book did a check-then-create with a non-recursive createDir. Two concurrent imports of the same book both pass the exists check, then the second create fails — on Windows with "Cannot create a file when that file already exists" (Sentry READEST-H). Use a recursive create (create_dir_all), a no-op when the directory already exists. Fixes READEST-H Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(stats): serialize applyRemoteEvents to avoid nested transactions The statistics connection is shared across ReadingStatsTracker instances (split view). applyRemoteEvents runs a manual BEGIN/COMMIT that the per-op native connection lock does not make atomic, so two concurrent pulls opened a BEGIN inside a BEGIN ("cannot start a transaction within a transaction", Sentry READEST-N). Serialize applyRemoteEvents against itself with a small promise mutex. Adds a regression test that fails without the guard. Fixes READEST-N Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>