dexie-cloud-addon 4.3.5 → 4.3.6

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.
@@ -8,7 +8,7 @@
8
8
  *
9
9
  * ==========================================================================
10
10
  *
11
- * Version 4.3.5, Fri Jan 23 2026
11
+ * Version 4.3.6, Wed Jan 28 2026
12
12
  *
13
13
  * https://dexie.org
14
14
  *
@@ -2445,73 +2445,19 @@
2445
2445
  }
2446
2446
  }
2447
2447
 
2448
- /** Cache for fetched SVG content to avoid re-fetching */
2449
- const svgCache = {};
2450
- /** Default SVG icons for built-in OAuth providers */
2451
- const ProviderIcons = {
2452
- google: `<svg viewBox="0 0 24 24" width="20" height="20"><path fill="#4285F4" d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"/><path fill="#34A853" d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"/><path fill="#FBBC05" d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"/><path fill="#EA4335" d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"/></svg>`,
2453
- github: `<svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor"><path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z"/></svg>`,
2454
- microsoft: `<svg viewBox="0 0 24 24" width="20" height="20"><rect fill="#F25022" x="1" y="1" width="10" height="10"/><rect fill="#00A4EF" x="1" y="13" width="10" height="10"/><rect fill="#7FBA00" x="13" y="1" width="10" height="10"/><rect fill="#FFB900" x="13" y="13" width="10" height="10"/></svg>`,
2455
- apple: `<svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor"><path d="M18.71 19.5c-.83 1.24-1.71 2.45-3.05 2.47-1.34.03-1.77-.79-3.29-.79-1.53 0-2 .77-3.27.82-1.31.05-2.3-1.32-3.14-2.53C4.25 17 2.94 12.45 4.7 9.39c.87-1.52 2.43-2.48 4.12-2.51 1.28-.02 2.5.87 3.29.87.78 0 2.26-1.07 3.81-.91.65.03 2.47.26 3.64 1.98-.09.06-2.17 1.28-2.15 3.81.03 3.02 2.65 4.03 2.68 4.04-.03.07-.42 1.44-1.38 2.83M13 3.5c.73-.83 1.94-1.46 2.94-1.5.13 1.17-.34 2.35-1.04 3.19-.69.85-1.83 1.51-2.95 1.42-.15-1.15.41-2.35 1.05-3.11z"/></svg>`,
2456
- };
2457
- /** Email/envelope icon for OTP option */
2458
- const EmailIcon = `<svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="M22 6L12 13 2 6"/></svg>`;
2459
- /**
2460
- * Fetches SVG content from a URL and caches it.
2461
- * Returns the SVG string or null if fetch fails.
2462
- */
2463
- function fetchSvgIcon(url) {
2464
- return __awaiter(this, void 0, void 0, function* () {
2465
- if (svgCache[url]) {
2466
- return svgCache[url];
2467
- }
2468
- try {
2469
- const res = yield fetch(url);
2470
- if (res.ok) {
2471
- const svg = yield res.text();
2472
- // Validate it looks like SVG
2473
- if (svg.includes('<svg')) {
2474
- svgCache[url] = svg;
2475
- return svg;
2476
- }
2477
- }
2478
- }
2479
- catch (_a) {
2480
- // Silently fail - will show no icon
2481
- }
2482
- return null;
2483
- });
2484
- }
2448
+ /** Email/envelope icon data URL for OTP option */
2449
+ const EmailIcon = `data:image/svg+xml;base64,${btoa('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="#666666" stroke-width="2"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="M22 6L12 13 2 6"/></svg>')}`;
2485
2450
  /**
2486
2451
  * Converts an OAuthProviderInfo to a generic DXCOption.
2487
- * Fetches SVG icons from URLs if needed.
2488
2452
  */
2489
2453
  function providerToOption(provider) {
2490
- return __awaiter(this, void 0, void 0, function* () {
2491
- var _a;
2492
- let iconSvg;
2493
- // First check for built-in icons
2494
- if (ProviderIcons[provider.type]) {
2495
- iconSvg = ProviderIcons[provider.type];
2496
- }
2497
- // If provider has iconUrl pointing to SVG, fetch and inline it
2498
- else if ((_a = provider.iconUrl) === null || _a === void 0 ? void 0 : _a.toLowerCase().endsWith('.svg')) {
2499
- const fetched = yield fetchSvgIcon(provider.iconUrl);
2500
- if (fetched) {
2501
- iconSvg = fetched;
2502
- }
2503
- }
2504
- return {
2505
- name: 'provider',
2506
- value: provider.name,
2507
- displayName: `Continue with ${provider.displayName}`,
2508
- iconSvg,
2509
- // If iconUrl is not SVG, pass it through for img tag rendering
2510
- iconUrl: (!iconSvg && provider.iconUrl) ? provider.iconUrl : undefined,
2511
- // Use provider type as style hint for branding
2512
- styleHint: provider.type,
2513
- };
2514
- });
2454
+ return {
2455
+ name: 'provider',
2456
+ value: provider.name,
2457
+ displayName: `Continue with ${provider.displayName}`,
2458
+ iconUrl: provider.iconUrl,
2459
+ styleHint: provider.type,
2460
+ };
2515
2461
  }
2516
2462
  function interactWithUser(userInteraction, req) {
2517
2463
  return new Promise((resolve, reject) => {
@@ -2662,8 +2608,8 @@
2662
2608
  */
2663
2609
  function promptForProvider(userInteraction_1, providers_1, otpEnabled_1) {
2664
2610
  return __awaiter(this, arguments, void 0, function* (userInteraction, providers, otpEnabled, title = 'Choose login method', alerts = []) {
2665
- // Convert providers to generic options (with icon fetching)
2666
- const providerOptions = yield Promise.all(providers.map(providerToOption));
2611
+ // Convert providers to generic options
2612
+ const providerOptions = providers.map(providerToOption);
2667
2613
  // Build the options array
2668
2614
  const options = [...providerOptions];
2669
2615
  // Add OTP option if enabled
@@ -2672,7 +2618,7 @@
2672
2618
  name: 'otp',
2673
2619
  value: 'email',
2674
2620
  displayName: 'Continue with email',
2675
- iconSvg: EmailIcon,
2621
+ iconUrl: EmailIcon,
2676
2622
  styleHint: 'otp',
2677
2623
  });
2678
2624
  }
@@ -13261,7 +13207,7 @@
13261
13207
  *
13262
13208
  * ==========================================================================
13263
13209
  *
13264
- * Version 4.2.2, Fri Jan 23 2026
13210
+ * Version 4.2.2, Wed Jan 28 2026
13265
13211
  *
13266
13212
  * https://dexie.org
13267
13213
  *
@@ -14708,10 +14654,12 @@
14708
14654
  mode: 'cors',
14709
14655
  });
14710
14656
  if (!res.ok) {
14657
+ // Read body once as text to avoid stream consumption issues
14658
+ const bodyText = yield res.text().catch(() => res.statusText);
14711
14659
  if (res.status === 400 || res.status === 401) {
14712
- // Try to parse error response
14660
+ // Try to parse error response as JSON
14713
14661
  try {
14714
- const errorResponse = yield res.json();
14662
+ const errorResponse = JSON.parse(bodyText);
14715
14663
  if (errorResponse.type === 'error') {
14716
14664
  // Check for specific error codes
14717
14665
  if (errorResponse.messageCode === 'INVALID_OTP') {
@@ -14728,8 +14676,7 @@
14728
14676
  // Fall through to generic error
14729
14677
  }
14730
14678
  }
14731
- const errorText = yield res.text().catch(() => res.statusText);
14732
- throw new OAuthError('provider_error', undefined, `Token exchange failed: ${res.status} ${errorText}`);
14679
+ throw new OAuthError('provider_error', undefined, `Token exchange failed: ${res.status} ${bodyText}`);
14733
14680
  }
14734
14681
  const response = yield res.json();
14735
14682
  if (response.type === 'error') {
@@ -14835,9 +14782,8 @@
14835
14782
  * ```
14836
14783
  */
14837
14784
  function startOAuthRedirect(options) {
14838
- // Store provider in sessionStorage for reference on callback
14839
- if (typeof sessionStorage !== 'undefined') {
14840
- sessionStorage.setItem('dexie-cloud-oauth-provider', options.provider);
14785
+ if (typeof window === 'undefined') {
14786
+ throw new Error('OAuth redirect requires a browser environment');
14841
14787
  }
14842
14788
  const loginUrl = buildOAuthLoginUrl(options);
14843
14789
  window.location.href = loginUrl;
@@ -14943,7 +14889,8 @@
14943
14889
  const res1 = yield fetch(`${url}/token`, {
14944
14890
  body: JSON.stringify(tokenRequest),
14945
14891
  method: 'post',
14946
- headers: { 'Content-Type': 'application/json', mode: 'cors' },
14892
+ headers: { 'Content-Type': 'application/json' },
14893
+ mode: 'cors',
14947
14894
  });
14948
14895
  if (res1.status !== 200) {
14949
14896
  const errMsg = yield res1.text();
@@ -15013,7 +14960,11 @@
15013
14960
  if (!url)
15014
14961
  throw new Error(`No database URL given.`);
15015
14962
  const redirectUri = ((_b = db.cloud.options) === null || _b === void 0 ? void 0 : _b.oauthRedirectUri) ||
15016
- (typeof window !== 'undefined' ? window.location.href : undefined);
14963
+ (typeof location !== 'undefined' ? location.href : undefined);
14964
+ // CodeRabbit suggested to fail fast here, but the only situation where
14965
+ // redirectUri would be undefined is in non-browser environments, and
14966
+ // in those environments OAuth redirect does not make sense anyway
14967
+ // and will fail fast in startOAuthRedirect().
15017
14968
  // Start OAuth redirect flow - page navigates away
15018
14969
  startOAuthRedirect({
15019
14970
  databaseUrl: url,
@@ -17066,13 +17017,13 @@
17066
17017
  color: "#3c4043"
17067
17018
  },
17068
17019
  ProviderGitHub: {
17069
- backgroundColor: "#24292e",
17070
- border: "1px solid #24292e",
17071
- color: "#ffffff"
17020
+ backgroundColor: "#ffffff",
17021
+ border: "1px solid #dadce0",
17022
+ color: "#181717"
17072
17023
  },
17073
17024
  ProviderMicrosoft: {
17074
17025
  backgroundColor: "#ffffff",
17075
- border: "1px solid #8c8c8c",
17026
+ border: "1px solid #dadce0",
17076
17027
  color: "#5e5e5e"
17077
17028
  },
17078
17029
  ProviderApple: {
@@ -17081,9 +17032,9 @@
17081
17032
  color: "#ffffff"
17082
17033
  },
17083
17034
  ProviderCustom: {
17084
- backgroundColor: "#4f46e5",
17085
- border: "1px solid #4f46e5",
17086
- color: "#ffffff"
17035
+ backgroundColor: "#ffffff",
17036
+ border: "1px solid #dadce0",
17037
+ color: "#181717"
17087
17038
  },
17088
17039
  // Divider styles
17089
17040
  Divider: {
@@ -17174,39 +17125,13 @@
17174
17125
  * Generic button component for selectable options.
17175
17126
  * Displays the option's icon and display name.
17176
17127
  *
17177
- * The icon can be:
17178
- * - Inline SVG (iconSvg) - rendered directly with dangerouslySetInnerHTML
17179
- * - Image URL (iconUrl) - rendered as an img tag
17180
- *
17181
17128
  * Style is determined by the styleHint property for branding purposes.
17182
17129
  */
17183
17130
  function OptionButton({ option, onClick }) {
17184
- const { displayName, iconUrl, iconSvg, styleHint, value } = option;
17131
+ const { displayName, iconUrl, styleHint } = option;
17185
17132
  const style = getOptionStyle(styleHint);
17186
- // Get the text color from the button style for SVG fill processing
17187
- const textColor = style.color || '#000000';
17188
- // Process SVG to replace currentColor with actual text color
17189
- const processedSvg = iconSvg
17190
- ? iconSvg
17191
- .replace(/fill="currentColor"/gi, `fill="${textColor}"`)
17192
- .replace(/fill='currentColor'/gi, `fill='${textColor}'`)
17193
- .replace(/stroke="currentColor"/gi, `stroke="${textColor}"`)
17194
- .replace(/stroke='currentColor'/gi, `stroke='${textColor}'`)
17195
- : null;
17196
- // Render the appropriate icon
17197
- const renderIcon = () => {
17198
- // Inline SVG
17199
- if (processedSvg) {
17200
- return (_$1("span", { style: Styles.ProviderButtonIcon, "aria-hidden": "true", dangerouslySetInnerHTML: { __html: processedSvg } }));
17201
- }
17202
- // Image URL
17203
- if (iconUrl) {
17204
- return (_$1("img", { src: iconUrl, alt: "", style: Styles.ProviderButtonIcon, "aria-hidden": "true" }));
17205
- }
17206
- return null;
17207
- };
17208
17133
  return (_$1("button", { type: "button", style: style, onClick: onClick, class: `dxc-option-btn${styleHint ? ` dxc-option-${styleHint}` : ''}`, "aria-label": displayName },
17209
- renderIcon(),
17134
+ iconUrl && (_$1("img", { src: iconUrl, alt: "", style: Styles.ProviderButtonIcon, "aria-hidden": "true" })),
17210
17135
  _$1("span", { style: Styles.ProviderButtonText }, displayName)));
17211
17136
  }
17212
17137
  /**
@@ -17993,7 +17918,7 @@
17993
17918
  const syncComplete = new rxjs.Subject();
17994
17919
  dexie.cloud = {
17995
17920
  // @ts-ignore
17996
- version: "4.3.5",
17921
+ version: "4.3.6",
17997
17922
  options: Object.assign({}, DEFAULT_OPTIONS),
17998
17923
  schema: null,
17999
17924
  get currentUserId() {
@@ -18263,12 +18188,18 @@
18263
18188
  pendingOAuthError = null; // Clear pending error
18264
18189
  console.debug('[dexie-cloud] Showing OAuth error:', error.message);
18265
18190
  // Show alert to user about the OAuth error
18266
- yield alertUser(db.cloud.userInteraction, 'Authentication Error', {
18267
- type: 'error',
18268
- messageCode: 'GENERIC_ERROR',
18269
- message: error.message,
18270
- messageParams: { provider: error.provider || 'unknown' }
18271
- });
18191
+ // Guard so UI errors don't abort initialization
18192
+ try {
18193
+ yield alertUser(db.cloud.userInteraction, 'Authentication Error', {
18194
+ type: 'error',
18195
+ messageCode: 'GENERIC_ERROR',
18196
+ message: error.message,
18197
+ messageParams: { provider: error.provider || 'unknown' }
18198
+ });
18199
+ }
18200
+ catch (uiError) {
18201
+ console.error('[dexie-cloud] Failed to show OAuth error alert:', uiError);
18202
+ }
18272
18203
  }
18273
18204
  // Process pending OAuth callback if present (from dxc-auth redirect)
18274
18205
  if (pendingOAuthCode && !db.cloud.isServiceWorkerDB) {
@@ -18372,7 +18303,7 @@
18372
18303
  }
18373
18304
  }
18374
18305
  // @ts-ignore
18375
- dexieCloud.version = "4.3.5";
18306
+ dexieCloud.version = "4.3.6";
18376
18307
  Dexie.Cloud = dexieCloud;
18377
18308
 
18378
18309
  // In case the SW lives for a while, let it reuse already opened connections: