Skip to content

fix(dexie-cloud): allow anonymous blob download + fix SW Dexie.ignoreTransaction crash#2287

Merged
dfahlander merged 3 commits intomasterfrom
liz/fix-blob-download-anonymous-and-sw-crash
Mar 31, 2026
Merged

fix(dexie-cloud): allow anonymous blob download + fix SW Dexie.ignoreTransaction crash#2287
dfahlander merged 3 commits intomasterfrom
liz/fix-blob-download-anonymous-and-sw-crash

Conversation

@liz709
Copy link
Copy Markdown
Contributor

@liz709 liz709 commented Mar 31, 2026

Problem

Two bugs preventing blob resolution for rlm-public roles (and other public realm data), plus a defensive fix in Dexie core.

Bug 1: Dexie.ignoreTransaction() crashes in service worker context

loadCachedAccessToken fell through to Dexie.ignoreTransaction() even for unauthenticated users. In service worker context, this crashes with:

TypeError: Cannot read properties of undefined (reading 'global')
  at switchToZone (promise.js:675)
  at usePSD (promise.js:713)
  at Dexie.ignoreTransaction (dexie-static-props.ts:111)

Root cause: PSD.transless can be undefined even when PSD.trans is truthy (e.g. in service worker context). Dexie.ignoreTransaction() called usePSD(PSD.transless, ...) without checking.

Bug 2: Anonymous users can't download blobs from public realms

BlobDownloadTracker.download() threw Error: No access token available for blob download for unauthenticated users. But the server already supports anonymous access for rlm-public blobs — authenticateUser() returns an anonymous user with ACCESS_DB scope and public realm access when no Bearer token is provided.

Fixes (3 files)

src/classes/dexie/dexie-static-props.ts — Dexie core

Guard Dexie.ignoreTransaction(): check both PSD.trans && PSD.transless before calling usePSD. If transless is undefined, fall through to calling scopeFunc() directly (same as no-transaction case).

addons/dexie-cloud/src/sync/loadCachedAccessToken.ts

If currentUser.isLoggedIn is falsy, return null immediately — no need to attempt a DB lookup via Dexie.ignoreTransaction() when we know there's no token.

addons/dexie-cloud/src/sync/BlobDownloadTracker.ts

  • Remove hard requirement for access token
  • downloadBlob() accepts string | null for accessToken
  • Omit Authorization header when token is null — server handles anonymous access for public realm blobs

Verified

  • Server's authenticateUser() already handles anonymous requests correctly (ACCESS_DB scope + rlm-public realm)
  • Server's blob endpoint realm check (blob_refs.realm_id) will pass for rlm-public blobs
  • No prettier-related logic changes in promise.js — confirmed by whitespace-stripped diff
  • Build passes, unit tests pass, CodeRabbit clean

Summary by CodeRabbit

  • New Features

    • Support downloading blobs from public realms without authentication.
  • Bug Fixes

    • Improved handling of unauthenticated blob access requests; no error if no cached token.
    • Avoid unnecessary cached-token DB lookups when a user is not logged in, reducing work and latency.
  • Refactor

    • Refined non-transactional execution selection to better respect transaction context.

…reTransaction crash

Two bugs fixed:

1. BlobDownloadTracker: Remove hard requirement for access token.
   Public realm (rlm-public) blobs must be downloadable without auth.
   downloadBlob() now omits the Authorization header when token is null,
   letting the server decide whether to allow anonymous access.

2. loadCachedAccessToken: Skip Dexie.ignoreTransaction() when user is
   not logged in. Previously this always fell through to a DB lookup via
   Dexie.ignoreTransaction() even for unauthenticated users who clearly
   have no token to find. This caused a crash in service worker context
   where PSD.transless.env is undefined when called from within an active
   rw transaction (e.g. during applyServerChanges after sync).

   The fix: if currentUser.isLoggedIn is falsy, return null immediately
   without touching Dexie.ignoreTransaction.
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 31, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d6578fdc-a101-4345-bc27-af29ce9c1a1d

📥 Commits

Reviewing files that changed from the base of the PR and between 5fe38bc and 1780073.

📒 Files selected for processing (1)
  • src/classes/dexie/dexie-static-props.ts

📝 Walkthrough

Walkthrough

Blob download now accepts nullable access tokens and skips Authorization when token is null; cached access token loader returns null immediately if user is not logged in; Dexie.ignoreTransaction() guards use of PSD.transless before switching PSD scope.

Changes

Cohort / File(s) Summary
Public Blob Download Support
addons/dexie-cloud/src/sync/BlobDownloadTracker.ts
downloadBlob(...) signature changed to accept `accessToken: string
Login Status Validation
addons/dexie-cloud/src/sync/loadCachedAccessToken.ts
Added early currentUser?.isLoggedIn check; returns null immediately when not logged in, avoiding Dexie.ignoreTransaction and DB access for unauthenticated users.
PSD Transaction Guard
src/classes/dexie/dexie-static-props.ts
Dexie.ignoreTransaction() now only calls usePSD(PSD.transless, scopeFunc) when both PSD.trans and PSD.transless are truthy; otherwise directly executes scopeFunc().

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 I hopped through headers, token light in paw,
If public fields beckon, I fetch without law.
Logged-out I wait, no DB to press,
PSD steps in to keep my rest.
A joyful nibble — patch and applause!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the two main bugs fixed: anonymous blob download support and the Dexie.ignoreTransaction crash in service workers. It is concise and directly matches the primary changes in the changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch liz/fix-blob-download-anonymous-and-sw-crash

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
addons/dexie-cloud/src/sync/loadCachedAccessToken.ts (1)

13-16: ⚠️ Potential issue | 🟠 Major

Guard order allows stale token reuse after logout.

At Line 14, cached tokens are returned before the new logged-out guard at Line 35 runs. If a token is already in wm, logged-out users may still send Authorization, which can break the anonymous/public-blob path and keep old auth context alive.

💡 Proposed fix
 export function loadCachedAccessToken(
   db: DexieCloudDB
 ): Promise<string | null> {
+  const currentUser = db.cloud.currentUser.value;
+  if (!currentUser?.isLoggedIn) {
+    wm.delete(db); // prevent stale token reuse after logout
+    return Promise.resolve(null);
+  }
+
   let cached = wm.get(db);
   if (cached && cached.expiration > Date.now() + 5 * MINUTES) {
     return Promise.resolve(cached.accessToken);
   }
-  const currentUser = db.cloud.currentUser.value;
+
   if (
     currentUser &&
     currentUser.accessToken &&

Also applies to: 35-37

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@addons/dexie-cloud/src/sync/loadCachedAccessToken.ts` around lines 13 - 16,
The current guard order returns a cached token from wm.get(db) using
cached.expiration before the "logged-out" check runs, allowing stale tokens
after logout; move the logged-out check (the guard that detects a
recently-logged-out DB/user) to run before consulting wm.get(db) so you
refuse/clear tokens for logged-out sessions first, and only then read cached =
wm.get(db) and validate cached.expiration > Date.now() + 5 * MINUTES; also
ensure any cached token is removed/ignored when the logged-out condition is true
so loadCachedAccessToken (and its use of wm.get/db/cached/accessToken) cannot
return an auth token for a logged-out user.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@addons/dexie-cloud/src/sync/loadCachedAccessToken.ts`:
- Around line 13-16: The current guard order returns a cached token from
wm.get(db) using cached.expiration before the "logged-out" check runs, allowing
stale tokens after logout; move the logged-out check (the guard that detects a
recently-logged-out DB/user) to run before consulting wm.get(db) so you
refuse/clear tokens for logged-out sessions first, and only then read cached =
wm.get(db) and validate cached.expiration > Date.now() + 5 * MINUTES; also
ensure any cached token is removed/ignored when the logged-out condition is true
so loadCachedAccessToken (and its use of wm.get/db/cached/accessToken) cannot
return an auth token for a logged-out user.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 74dda9ce-6235-4bb7-a4d4-85cead7137fb

📥 Commits

Reviewing files that changed from the base of the PR and between 39b99a3 and 9ae8d1c.

📒 Files selected for processing (2)
  • addons/dexie-cloud/src/sync/BlobDownloadTracker.ts
  • addons/dexie-cloud/src/sync/loadCachedAccessToken.ts

liz709 added 2 commits March 31, 2026 12:05
…less

PSD.transless can be undefined even when PSD.trans is truthy (e.g. in
service worker context). This caused a crash in switchToZone when
accessing targetZone.env on the undefined transless PSD.

Fix: check both PSD.trans AND PSD.transless before calling usePSD.
If transless is undefined, fall through to calling scopeFunc() directly
(same as no-transaction case).
Better approach: instead of skipping usePSD when transless is undefined,
fall back to globalPSD. This ensures the zone switch always happens with
a valid PSD that has proper env properties for promise patching.
@dfahlander dfahlander merged commit 0b7bbad into master Mar 31, 2026
7 checks passed
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