dexie-cloud-addon 4.4.3 → 4.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -32,6 +32,19 @@ export interface LoginHints {
32
32
  oauthCode?: string;
33
33
  /** Optional redirect path (relative or absolute) to use for OAuth redirect URI. */
34
34
  redirectPath?: string;
35
+ /**
36
+ * Optional login intent hint.
37
+ *
38
+ * - `"login"`: Only existing users are accepted. Unknown users always get
39
+ * USER_NOT_REGISTERED regardless of the database user policy.
40
+ * - `"register"`: New-user registration is intended. Unknown users that would
41
+ * normally get USER_NOT_REGISTERED will instead get
42
+ * USER_NOT_ACCEPTED (i.e. the policy blocked them, not the
43
+ * fact that registration isn't supported here).
44
+ * - `undefined`: Default behaviour — the server returns whatever code the
45
+ * user policy dictates.
46
+ */
47
+ intent?: 'login' | 'register';
35
48
  }
36
49
  export interface DexieCloudAPI {
37
50
  version: string;
@@ -9,6 +9,8 @@ export interface ExchangeOAuthCodeOptions {
9
9
  publicKey: string;
10
10
  /** Requested scopes (defaults to ['ACCESS_DB']) */
11
11
  scopes?: string[];
12
+ /** Optional login intent — see LoginHints.intent for semantics. */
13
+ intent?: 'login' | 'register';
12
14
  }
13
15
  /**
14
16
  * Exchanges a Dexie Cloud authorization code for access and refresh tokens.
@@ -17,7 +17,7 @@ export declare function interactWithUser<T extends DXCUserInteractionRequest>(us
17
17
  [P in keyof T['fields']]: string;
18
18
  }>;
19
19
  export declare function alertUser(userInteraction: BehaviorSubject<DXCUserInteraction | undefined>, title: string, ...alerts: DXCAlert[]): Promise<{}>;
20
- export declare function promptForEmail(userInteraction: BehaviorSubject<DXCUserInteraction | undefined>, title: string, emailHint?: string): Promise<string>;
20
+ export declare function promptForEmail(userInteraction: BehaviorSubject<DXCUserInteraction | undefined>, title: string, emailHint?: string, initialAlert?: DXCAlert): Promise<string>;
21
21
  export declare function promptForOTP(userInteraction: BehaviorSubject<DXCUserInteraction | undefined>, email: string, alert?: DXCAlert): Promise<string>;
22
22
  export declare function confirmLogout(userInteraction: BehaviorSubject<DXCUserInteraction | undefined>, currentUserId: string, numUnsyncedChanges: number): Promise<boolean>;
23
23
  /** Result from provider selection prompt */
@@ -8,7 +8,7 @@
8
8
  *
9
9
  * ==========================================================================
10
10
  *
11
- * Version 4.4.3, Sat Mar 21 2026
11
+ * Version 4.4.4, Wed Mar 25 2026
12
12
  *
13
13
  * https://dexie.org
14
14
  *
@@ -1858,9 +1858,10 @@ function alertUser(userInteraction, title, ...alerts) {
1858
1858
  cancelLabel: null,
1859
1859
  });
1860
1860
  }
1861
- function promptForEmail(userInteraction, title, emailHint) {
1861
+ function promptForEmail(userInteraction, title, emailHint, initialAlert) {
1862
1862
  return __awaiter(this, void 0, void 0, function* () {
1863
1863
  let email = emailHint || '';
1864
+ let firstPrompt = true;
1864
1865
  // Regular expression for email validation
1865
1866
  // ^[\w-+.]+@([\w-]+\.)+[\w-]{2,10}(\sas\s[\w-+.]+@([\w-]+\.)+[\w-]{2,10})?$
1866
1867
  //
@@ -1883,19 +1884,21 @@ function promptForEmail(userInteraction, title, emailHint) {
1883
1884
  // and GLOBAL_WRITE permissions on the database. The email will be checked on the server before
1884
1885
  // allowing it and giving out a token for email2, using the OTP sent to email1.
1885
1886
  while (!email || !/^[\w-+.]+@([\w-]+\.)+[\w-]{2,10}(\sas\s[\w-+.]+@([\w-]+\.)+[\w-]{2,10})?$/.test(email)) {
1887
+ const alerts = [];
1888
+ if (firstPrompt && initialAlert)
1889
+ alerts.push(initialAlert);
1890
+ if (email)
1891
+ alerts.push({
1892
+ type: 'error',
1893
+ messageCode: 'INVALID_EMAIL',
1894
+ message: 'Please enter a valid email address',
1895
+ messageParams: {},
1896
+ });
1897
+ firstPrompt = false;
1886
1898
  email = (yield interactWithUser(userInteraction, {
1887
1899
  type: 'email',
1888
1900
  title,
1889
- alerts: email
1890
- ? [
1891
- {
1892
- type: 'error',
1893
- messageCode: 'INVALID_EMAIL',
1894
- message: 'Please enter a valid email address',
1895
- messageParams: {},
1896
- },
1897
- ]
1898
- : [],
1901
+ alerts,
1899
1902
  fields: {
1900
1903
  email: {
1901
1904
  type: 'email',
@@ -2038,6 +2041,29 @@ class OAuthRedirectError extends Error {
2038
2041
  }
2039
2042
  }
2040
2043
 
2044
+ /** Thrown when the server rejects a user due to a policy rule.
2045
+ *
2046
+ * Unlike a generic 403, this error carries a machine-readable `code` so that
2047
+ * the addon can convert it into a DXCUserInteraction challenge rather than
2048
+ * simply throwing.
2049
+ */
2050
+ class PolicyRejectionError extends Error {
2051
+ constructor(body) {
2052
+ super(body.message);
2053
+ this.code = body.code;
2054
+ }
2055
+ get name() {
2056
+ return 'PolicyRejectionError';
2057
+ }
2058
+ }
2059
+ /** Returns true when a plain fetch Response contains a structured PolicyError body. */
2060
+ function isPolicyErrorBody(value) {
2061
+ return (typeof value === 'object' &&
2062
+ value !== null &&
2063
+ typeof value.code === 'string' &&
2064
+ typeof value.message === 'string');
2065
+ }
2066
+
2041
2067
  const SECONDS = 1000;
2042
2068
  const MINUTES = 60 * SECONDS;
2043
2069
 
@@ -2212,6 +2238,10 @@ function userAuthenticate(context, fetchToken, userInteraction, hints) {
2212
2238
  if (error instanceof OAuthRedirectError || (error === null || error === void 0 ? void 0 : error.name) === 'OAuthRedirectError') {
2213
2239
  throw error; // Re-throw without logging
2214
2240
  }
2241
+ // Policy rejections have already been shown to the user as a challenge
2242
+ if (error instanceof PolicyRejectionError || (error === null || error === void 0 ? void 0 : error.name) === 'PolicyRejectionError') {
2243
+ throw error;
2244
+ }
2215
2245
  if (error instanceof TokenErrorResponseError) {
2216
2246
  yield alertUser(userInteraction, error.title, {
2217
2247
  type: 'error',
@@ -2410,13 +2440,8 @@ class OAuthError extends Error {
2410
2440
  */
2411
2441
  function exchangeOAuthCode(options) {
2412
2442
  return __awaiter(this, void 0, void 0, function* () {
2413
- const { databaseUrl, code, publicKey, scopes = ['ACCESS_DB'] } = options;
2414
- const tokenRequest = {
2415
- grant_type: 'authorization_code',
2416
- code,
2417
- public_key: publicKey,
2418
- scopes,
2419
- };
2443
+ const { databaseUrl, code, publicKey, scopes = ['ACCESS_DB'], intent } = options;
2444
+ const tokenRequest = Object.assign({ grant_type: 'authorization_code', code, public_key: publicKey, scopes }, (intent !== undefined ? { intent } : {}));
2420
2445
  try {
2421
2446
  const res = yield fetch(`${databaseUrl}/token`, {
2422
2447
  method: 'POST',
@@ -2427,6 +2452,20 @@ function exchangeOAuthCode(options) {
2427
2452
  if (!res.ok) {
2428
2453
  // Read body once as text to avoid stream consumption issues
2429
2454
  const bodyText = yield res.text().catch(() => res.statusText);
2455
+ // Check for structured policy rejection (403 with JSON body)
2456
+ if (res.status === 403) {
2457
+ try {
2458
+ const body = JSON.parse(bodyText);
2459
+ if (isPolicyErrorBody(body)) {
2460
+ throw new PolicyRejectionError(body);
2461
+ }
2462
+ }
2463
+ catch (e) {
2464
+ if (e instanceof PolicyRejectionError)
2465
+ throw e;
2466
+ // Fall through to generic error
2467
+ }
2468
+ }
2430
2469
  if (res.status === 400 || res.status === 401) {
2431
2470
  // Try to parse error response as JSON
2432
2471
  try {
@@ -2562,32 +2601,59 @@ function startOAuthRedirect(options) {
2562
2601
 
2563
2602
  function otpFetchTokenCallback(db) {
2564
2603
  const { userInteraction } = db.cloud;
2565
- return function otpAuthenticate(_a) {
2566
- return __awaiter(this, arguments, void 0, function* ({ public_key, hints }) {
2604
+ /**
2605
+ * Core authentication function.
2606
+ *
2607
+ * @param public_key - RSA public key PEM for the session
2608
+ * @param hints - Optional login hints from the caller
2609
+ * @param policyAlert - When set, a previous attempt was rejected by a server
2610
+ * policy rule. The alert is injected into the first
2611
+ * interactive prompt so the user sees why they were
2612
+ * rejected without changing any other flow logic.
2613
+ */
2614
+ function otpAuthenticate(_a, policyAlert_1) {
2615
+ return __awaiter(this, arguments, void 0, function* ({ public_key, hints }, policyAlert) {
2567
2616
  var _b, _c;
2568
2617
  let tokenRequest;
2569
2618
  const url = (_b = db.cloud.options) === null || _b === void 0 ? void 0 : _b.databaseUrl;
2570
2619
  if (!url)
2571
2620
  throw new Error(`No database URL given.`);
2621
+ const intent = hints === null || hints === void 0 ? void 0 : hints.intent;
2622
+ // ── Non-interactive paths ──────────────────────────────────────────────
2623
+ // These paths POST directly without prompting the user. If a policyAlert
2624
+ // exists (from a previous rejected attempt), show it with a message-alert
2625
+ // before proceeding so the user understands what happened.
2572
2626
  // Handle OAuth code exchange (from redirect/deep link flows)
2573
2627
  if ((hints === null || hints === void 0 ? void 0 : hints.oauthCode) && hints.provider) {
2574
- return yield exchangeOAuthCode({
2575
- databaseUrl: url,
2576
- code: hints.oauthCode,
2577
- publicKey: public_key,
2578
- scopes: ['ACCESS_DB'],
2579
- });
2628
+ try {
2629
+ return yield exchangeOAuthCode({
2630
+ databaseUrl: url,
2631
+ code: hints.oauthCode,
2632
+ publicKey: public_key,
2633
+ scopes: ['ACCESS_DB'],
2634
+ intent,
2635
+ });
2636
+ }
2637
+ catch (err) {
2638
+ if (err instanceof PolicyRejectionError) {
2639
+ return yield otpAuthenticate({ public_key, hints: undefined }, toPolicyAlert(err));
2640
+ }
2641
+ throw err;
2642
+ }
2580
2643
  }
2581
- // Handle OAuth provider login via redirect
2644
+ // Handle OAuth provider login via redirect (programmatic, no interaction)
2582
2645
  if (hints === null || hints === void 0 ? void 0 : hints.provider) {
2646
+ if (policyAlert) {
2647
+ // A previous OAuth attempt was rejected. Fall through to the
2648
+ // interactive flow — policyAlert will be shown inside the prompt.
2649
+ return yield otpAuthenticate({ public_key, hints: undefined }, policyAlert);
2650
+ }
2583
2651
  let resolvedRedirectUri = undefined;
2584
2652
  if (hints.redirectPath) {
2585
- // If redirectPath is absolute, use as is. If relative, resolve against current location
2586
2653
  if (/^https?:\/\//i.test(hints.redirectPath)) {
2587
2654
  resolvedRedirectUri = hints.redirectPath;
2588
2655
  }
2589
2656
  else if (typeof window !== 'undefined' && window.location) {
2590
- // Use URL constructor to resolve relative path
2591
2657
  resolvedRedirectUri = new URL(hints.redirectPath, window.location.href).toString();
2592
2658
  }
2593
2659
  else if (typeof location !== 'undefined' && location.href) {
@@ -2595,23 +2661,27 @@ function otpFetchTokenCallback(db) {
2595
2661
  }
2596
2662
  }
2597
2663
  initiateOAuthRedirect(db, hints.provider, resolvedRedirectUri);
2598
- // This function never returns - page navigates away
2599
2664
  throw new OAuthRedirectError(hints.provider);
2600
2665
  }
2666
+ // ── Interactive paths ──────────────────────────────────────────────────
2667
+ // policyAlert (if set) is injected into the first prompt so the user sees
2668
+ // it alongside the normal auth UI — no separate error screen needed.
2601
2669
  if ((hints === null || hints === void 0 ? void 0 : hints.grant_type) === 'demo') {
2602
- const demo_user = yield promptForEmail(userInteraction, 'Enter a demo user email', (hints === null || hints === void 0 ? void 0 : hints.email) || (hints === null || hints === void 0 ? void 0 : hints.userId));
2670
+ const demo_user = yield promptForEmail(userInteraction, 'Enter a demo user email', (hints === null || hints === void 0 ? void 0 : hints.email) || (hints === null || hints === void 0 ? void 0 : hints.userId), policyAlert);
2603
2671
  tokenRequest = {
2604
2672
  demo_user,
2605
2673
  grant_type: 'demo',
2606
2674
  scopes: ['ACCESS_DB'],
2607
- public_key
2675
+ public_key,
2608
2676
  };
2609
2677
  }
2610
2678
  else if ((hints === null || hints === void 0 ? void 0 : hints.otpId) && hints.otp) {
2611
- // User provided OTP ID and OTP code. This means that the OTP email
2612
- // has already gone out and the user may have clicked a magic link
2613
- // in the email with otp and otpId in query and the app has picked
2614
- // up those values and passed them to db.cloud.login().
2679
+ // Magic-link flow: OTP already supplied by the caller (e.g. from email).
2680
+ // No interaction show alert as a plain message if there is one.
2681
+ if (policyAlert) {
2682
+ yield alertUser(userInteraction, 'Access Denied', policyAlert);
2683
+ return yield otpAuthenticate({ public_key, hints: undefined }, policyAlert);
2684
+ }
2615
2685
  tokenRequest = {
2616
2686
  grant_type: 'otp',
2617
2687
  otp_id: hints.otpId,
@@ -2621,56 +2691,52 @@ function otpFetchTokenCallback(db) {
2621
2691
  };
2622
2692
  }
2623
2693
  else if ((hints === null || hints === void 0 ? void 0 : hints.grant_type) === 'otp' || (hints === null || hints === void 0 ? void 0 : hints.email)) {
2624
- // User explicitly requested OTP flow - skip provider selection
2625
- const email = (hints === null || hints === void 0 ? void 0 : hints.email) || (yield promptForEmail(userInteraction, 'Enter email address'));
2694
+ // Caller explicitly requested OTP skip provider selection.
2695
+ const email = (hints === null || hints === void 0 ? void 0 : hints.email) ||
2696
+ (yield promptForEmail(userInteraction, 'Enter email address', undefined, policyAlert));
2626
2697
  if (/@demo.local$/.test(email)) {
2627
2698
  tokenRequest = {
2628
2699
  demo_user: email,
2629
2700
  grant_type: 'demo',
2630
2701
  scopes: ['ACCESS_DB'],
2631
- public_key
2702
+ public_key,
2632
2703
  };
2633
2704
  }
2634
2705
  else {
2635
- tokenRequest = {
2636
- email,
2637
- grant_type: 'otp',
2638
- scopes: ['ACCESS_DB'],
2639
- };
2706
+ tokenRequest = Object.assign({ email, grant_type: 'otp', scopes: ['ACCESS_DB'] }, (intent !== undefined ? { intent } : {}));
2640
2707
  }
2641
2708
  }
2642
2709
  else {
2643
- // Check for available auth providers (OAuth + OTP)
2710
+ // Default path: check for OAuth providers, then fall back to OTP.
2644
2711
  const socialAuthEnabled = ((_c = db.cloud.options) === null || _c === void 0 ? void 0 : _c.socialAuth) !== false;
2645
2712
  const authProviders = yield fetchAuthProviders(url, socialAuthEnabled);
2646
- // If we have OAuth providers available, prompt for selection
2647
2713
  if (authProviders.providers.length > 0) {
2648
- const selection = yield promptForProvider(userInteraction, authProviders.providers, authProviders.otpEnabled, 'Sign in');
2714
+ const providerAlerts = policyAlert ? [policyAlert] : [];
2715
+ const selection = yield promptForProvider(userInteraction, authProviders.providers, authProviders.otpEnabled, 'Sign in', providerAlerts);
2649
2716
  if (selection.type === 'provider') {
2650
- // User selected an OAuth provider - initiate redirect
2651
2717
  initiateOAuthRedirect(db, selection.provider);
2652
- // This function never returns - page navigates away
2653
2718
  throw new OAuthRedirectError(selection.provider);
2654
2719
  }
2655
- // User chose OTP - continue with email prompt below
2720
+ // User chose OTP fall through to email prompt (no policyAlert here;
2721
+ // it was already shown in the provider prompt above).
2656
2722
  }
2657
- const email = yield promptForEmail(userInteraction, 'Enter email address', hints === null || hints === void 0 ? void 0 : hints.email);
2723
+ const email = yield promptForEmail(userInteraction, 'Enter email address', hints === null || hints === void 0 ? void 0 : hints.email,
2724
+ // Show policyAlert in email prompt only if there were no providers
2725
+ // (otherwise it was already shown in the provider selection above).
2726
+ authProviders.providers.length === 0 ? policyAlert : undefined);
2658
2727
  if (/@demo.local$/.test(email)) {
2659
2728
  tokenRequest = {
2660
2729
  demo_user: email,
2661
2730
  grant_type: 'demo',
2662
2731
  scopes: ['ACCESS_DB'],
2663
- public_key
2732
+ public_key,
2664
2733
  };
2665
2734
  }
2666
2735
  else {
2667
- tokenRequest = {
2668
- email,
2669
- grant_type: 'otp',
2670
- scopes: ['ACCESS_DB'],
2671
- };
2736
+ tokenRequest = Object.assign({ email, grant_type: 'otp', scopes: ['ACCESS_DB'] }, (intent !== undefined ? { intent } : {}));
2672
2737
  }
2673
2738
  }
2739
+ // ── POST /token (step 1) ───────────────────────────────────────────────
2674
2740
  const res1 = yield fetch(`${url}/token`, {
2675
2741
  body: JSON.stringify(tokenRequest),
2676
2742
  method: 'post',
@@ -2678,19 +2744,22 @@ function otpFetchTokenCallback(db) {
2678
2744
  mode: 'cors',
2679
2745
  });
2680
2746
  if (res1.status !== 200) {
2747
+ const alert = yield tryParsePolicyAlert(res1);
2748
+ if (alert) {
2749
+ // Policy rejection — restart the flow with the error injected.
2750
+ return yield otpAuthenticate({ public_key, hints: undefined }, alert);
2751
+ }
2681
2752
  const errMsg = yield res1.text();
2682
- yield alertUser(userInteraction, "Token request failed", {
2753
+ yield alertUser(userInteraction, 'Token request failed', {
2683
2754
  type: 'error',
2684
2755
  messageCode: 'GENERIC_ERROR',
2685
2756
  message: errMsg,
2686
- messageParams: {}
2757
+ messageParams: {},
2687
2758
  }).catch(() => { });
2688
2759
  throw new HttpError(res1, errMsg);
2689
2760
  }
2690
2761
  const response = yield res1.json();
2691
2762
  if (response.type === 'tokens' || response.type === 'error') {
2692
- // Demo user request can get a "tokens" response right away
2693
- // Error can also be returned right away.
2694
2763
  return response;
2695
2764
  }
2696
2765
  else if (tokenRequest.grant_type === 'otp' && 'email' in tokenRequest) {
@@ -2698,6 +2767,7 @@ function otpFetchTokenCallback(db) {
2698
2767
  throw new Error(`Unexpected response from ${url}/token`);
2699
2768
  const otp = yield promptForOTP(userInteraction, tokenRequest.email);
2700
2769
  const tokenRequest2 = Object.assign(Object.assign({}, tokenRequest), { otp: otp || '', otp_id: response.otp_id, public_key });
2770
+ // ── POST /token (step 2: OTP verification) ─────────────────────────
2701
2771
  let res2 = yield fetch(`${url}/token`, {
2702
2772
  body: JSON.stringify(tokenRequest2),
2703
2773
  method: 'post',
@@ -2710,7 +2780,7 @@ function otpFetchTokenCallback(db) {
2710
2780
  type: 'error',
2711
2781
  messageCode: 'INVALID_OTP',
2712
2782
  message: errorText,
2713
- messageParams: {}
2783
+ messageParams: {},
2714
2784
  });
2715
2785
  res2 = yield fetch(`${url}/token`, {
2716
2786
  body: JSON.stringify(tokenRequest2),
@@ -2720,6 +2790,10 @@ function otpFetchTokenCallback(db) {
2720
2790
  });
2721
2791
  }
2722
2792
  if (res2.status !== 200) {
2793
+ const alert = yield tryParsePolicyAlert(res2);
2794
+ if (alert) {
2795
+ return yield otpAuthenticate({ public_key, hints: undefined }, alert);
2796
+ }
2723
2797
  const errMsg = yield res2.text();
2724
2798
  throw new HttpError(res2, errMsg);
2725
2799
  }
@@ -2730,14 +2804,11 @@ function otpFetchTokenCallback(db) {
2730
2804
  throw new Error(`Unexpected response from ${url}/token`);
2731
2805
  }
2732
2806
  });
2733
- };
2807
+ }
2808
+ return ({ public_key, hints }) => otpAuthenticate({ public_key, hints });
2734
2809
  }
2735
2810
  /**
2736
2811
  * Initiates OAuth login via full page redirect.
2737
- *
2738
- * The page will navigate away to the OAuth provider. After authentication,
2739
- * the user is redirected back with a dxc-auth query parameter that is
2740
- * automatically detected by db.cloud.configure().
2741
2812
  */
2742
2813
  function initiateOAuthRedirect(db, provider, redirectUriOverride) {
2743
2814
  var _a, _b;
@@ -2747,17 +2818,44 @@ function initiateOAuthRedirect(db, provider, redirectUriOverride) {
2747
2818
  const redirectUri = redirectUriOverride ||
2748
2819
  ((_b = db.cloud.options) === null || _b === void 0 ? void 0 : _b.oauthRedirectUri) ||
2749
2820
  (typeof location !== 'undefined' ? location.href : undefined);
2750
- // CodeRabbit suggested to fail fast here, but the only situation where
2751
- // redirectUri would be undefined is in non-browser environments, and
2752
- // in those environments OAuth redirect does not make sense anyway
2753
- // and will fail fast in startOAuthRedirect().
2754
- // Start OAuth redirect flow - page navigates away
2755
2821
  startOAuthRedirect({
2756
2822
  databaseUrl: url,
2757
2823
  provider,
2758
2824
  redirectUri,
2759
2825
  });
2760
2826
  }
2827
+ /**
2828
+ * Converts a PolicyRejectionError to a DXCAlert for injection into prompts.
2829
+ */
2830
+ function toPolicyAlert(err) {
2831
+ return {
2832
+ type: 'error',
2833
+ messageCode: err.code,
2834
+ message: err.message,
2835
+ messageParams: {},
2836
+ };
2837
+ }
2838
+ /**
2839
+ * Tries to parse a failed Response as a structured PolicyError body.
2840
+ * Returns a DXCAlert if it is one, otherwise returns null.
2841
+ * Safe to call: reads body via clone() so the original Response is untouched.
2842
+ */
2843
+ function tryParsePolicyAlert(res) {
2844
+ return __awaiter(this, void 0, void 0, function* () {
2845
+ if (res.status !== 403)
2846
+ return null;
2847
+ try {
2848
+ const body = yield res.clone().json();
2849
+ if (isPolicyErrorBody(body)) {
2850
+ return toPolicyAlert(new PolicyRejectionError(body));
2851
+ }
2852
+ }
2853
+ catch (_a) {
2854
+ // Not JSON
2855
+ }
2856
+ return null;
2857
+ });
2858
+ }
2761
2859
 
2762
2860
  /** A way to log to console in production without terser stripping out
2763
2861
  * it from the release bundle.
@@ -6038,6 +6136,7 @@ function createBlobResolvingCursor(cursor, table, blobSavingQueue, db) {
6038
6136
  return cursor.start(() => {
6039
6137
  const rawValue = cursor.value;
6040
6138
  if (!rawValue || !hasUnresolvedBlobRefs(rawValue)) {
6139
+ wrappedCursor.value = rawValue;
6041
6140
  onNext();
6042
6141
  return;
6043
6142
  }
@@ -6046,6 +6145,7 @@ function createBlobResolvingCursor(cursor, table, blobSavingQueue, db) {
6046
6145
  onNext();
6047
6146
  }, err => {
6048
6147
  console.error('Failed to resolve BlobRefs for cursor value:', err);
6148
+ wrappedCursor.value = rawValue;
6049
6149
  onNext();
6050
6150
  });
6051
6151
  });
@@ -8273,7 +8373,7 @@ function dexieCloud(dexie) {
8273
8373
  const downloading$ = createDownloadingState();
8274
8374
  dexie.cloud = {
8275
8375
  // @ts-ignore
8276
- version: "4.4.3",
8376
+ version: "4.4.4",
8277
8377
  options: Object.assign({}, DEFAULT_OPTIONS),
8278
8378
  schema: null,
8279
8379
  get currentUserId() {
@@ -8700,7 +8800,7 @@ function dexieCloud(dexie) {
8700
8800
  }
8701
8801
  }
8702
8802
  // @ts-ignore
8703
- dexieCloud.version = "4.4.3";
8803
+ dexieCloud.version = "4.4.4";
8704
8804
  Dexie.Cloud = dexieCloud;
8705
8805
 
8706
8806
  export { dexieCloud as default, defineYDocTrigger, dexieCloud, getTiedObjectId, getTiedRealmId, resolveText };