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.
@@ -17,10 +17,8 @@ export interface DXCOption {
17
17
  value: string;
18
18
  /** Human-readable display label */
19
19
  displayName: string;
20
- /** URL to an icon image (mutually exclusive with iconSvg) */
20
+ /** URL to an icon image (can be a regular URL or a data: URL for inline images) */
21
21
  iconUrl?: string;
22
- /** Inline SVG markup for the icon (mutually exclusive with iconUrl) */
23
- iconSvg?: string;
24
22
  /** Optional style hint for the UI (e.g., 'google', 'github', 'microsoft', 'apple', 'otp') */
25
23
  styleHint?: string;
26
24
  }
@@ -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
  *
@@ -2061,73 +2061,19 @@
2061
2061
  }
2062
2062
  }
2063
2063
 
2064
- /** Cache for fetched SVG content to avoid re-fetching */
2065
- const svgCache = {};
2066
- /** Default SVG icons for built-in OAuth providers */
2067
- const ProviderIcons = {
2068
- 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>`,
2069
- 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>`,
2070
- 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>`,
2071
- 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>`,
2072
- };
2073
- /** Email/envelope icon for OTP option */
2074
- 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>`;
2075
- /**
2076
- * Fetches SVG content from a URL and caches it.
2077
- * Returns the SVG string or null if fetch fails.
2078
- */
2079
- function fetchSvgIcon(url) {
2080
- return __awaiter(this, void 0, void 0, function* () {
2081
- if (svgCache[url]) {
2082
- return svgCache[url];
2083
- }
2084
- try {
2085
- const res = yield fetch(url);
2086
- if (res.ok) {
2087
- const svg = yield res.text();
2088
- // Validate it looks like SVG
2089
- if (svg.includes('<svg')) {
2090
- svgCache[url] = svg;
2091
- return svg;
2092
- }
2093
- }
2094
- }
2095
- catch (_a) {
2096
- // Silently fail - will show no icon
2097
- }
2098
- return null;
2099
- });
2100
- }
2064
+ /** Email/envelope icon data URL for OTP option */
2065
+ 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>')}`;
2101
2066
  /**
2102
2067
  * Converts an OAuthProviderInfo to a generic DXCOption.
2103
- * Fetches SVG icons from URLs if needed.
2104
2068
  */
2105
2069
  function providerToOption(provider) {
2106
- return __awaiter(this, void 0, void 0, function* () {
2107
- var _a;
2108
- let iconSvg;
2109
- // First check for built-in icons
2110
- if (ProviderIcons[provider.type]) {
2111
- iconSvg = ProviderIcons[provider.type];
2112
- }
2113
- // If provider has iconUrl pointing to SVG, fetch and inline it
2114
- else if ((_a = provider.iconUrl) === null || _a === void 0 ? void 0 : _a.toLowerCase().endsWith('.svg')) {
2115
- const fetched = yield fetchSvgIcon(provider.iconUrl);
2116
- if (fetched) {
2117
- iconSvg = fetched;
2118
- }
2119
- }
2120
- return {
2121
- name: 'provider',
2122
- value: provider.name,
2123
- displayName: `Continue with ${provider.displayName}`,
2124
- iconSvg,
2125
- // If iconUrl is not SVG, pass it through for img tag rendering
2126
- iconUrl: (!iconSvg && provider.iconUrl) ? provider.iconUrl : undefined,
2127
- // Use provider type as style hint for branding
2128
- styleHint: provider.type,
2129
- };
2130
- });
2070
+ return {
2071
+ name: 'provider',
2072
+ value: provider.name,
2073
+ displayName: `Continue with ${provider.displayName}`,
2074
+ iconUrl: provider.iconUrl,
2075
+ styleHint: provider.type,
2076
+ };
2131
2077
  }
2132
2078
  function interactWithUser(userInteraction, req) {
2133
2079
  return new Promise((resolve, reject) => {
@@ -2278,8 +2224,8 @@
2278
2224
  */
2279
2225
  function promptForProvider(userInteraction_1, providers_1, otpEnabled_1) {
2280
2226
  return __awaiter(this, arguments, void 0, function* (userInteraction, providers, otpEnabled, title = 'Choose login method', alerts = []) {
2281
- // Convert providers to generic options (with icon fetching)
2282
- const providerOptions = yield Promise.all(providers.map(providerToOption));
2227
+ // Convert providers to generic options
2228
+ const providerOptions = providers.map(providerToOption);
2283
2229
  // Build the options array
2284
2230
  const options = [...providerOptions];
2285
2231
  // Add OTP option if enabled
@@ -2288,7 +2234,7 @@
2288
2234
  name: 'otp',
2289
2235
  value: 'email',
2290
2236
  displayName: 'Continue with email',
2291
- iconSvg: EmailIcon,
2237
+ iconUrl: EmailIcon,
2292
2238
  styleHint: 'otp',
2293
2239
  });
2294
2240
  }
@@ -2716,10 +2662,12 @@
2716
2662
  mode: 'cors',
2717
2663
  });
2718
2664
  if (!res.ok) {
2665
+ // Read body once as text to avoid stream consumption issues
2666
+ const bodyText = yield res.text().catch(() => res.statusText);
2719
2667
  if (res.status === 400 || res.status === 401) {
2720
- // Try to parse error response
2668
+ // Try to parse error response as JSON
2721
2669
  try {
2722
- const errorResponse = yield res.json();
2670
+ const errorResponse = JSON.parse(bodyText);
2723
2671
  if (errorResponse.type === 'error') {
2724
2672
  // Check for specific error codes
2725
2673
  if (errorResponse.messageCode === 'INVALID_OTP') {
@@ -2736,8 +2684,7 @@
2736
2684
  // Fall through to generic error
2737
2685
  }
2738
2686
  }
2739
- const errorText = yield res.text().catch(() => res.statusText);
2740
- throw new OAuthError('provider_error', undefined, `Token exchange failed: ${res.status} ${errorText}`);
2687
+ throw new OAuthError('provider_error', undefined, `Token exchange failed: ${res.status} ${bodyText}`);
2741
2688
  }
2742
2689
  const response = yield res.json();
2743
2690
  if (response.type === 'error') {
@@ -2843,9 +2790,8 @@
2843
2790
  * ```
2844
2791
  */
2845
2792
  function startOAuthRedirect(options) {
2846
- // Store provider in sessionStorage for reference on callback
2847
- if (typeof sessionStorage !== 'undefined') {
2848
- sessionStorage.setItem('dexie-cloud-oauth-provider', options.provider);
2793
+ if (typeof window === 'undefined') {
2794
+ throw new Error('OAuth redirect requires a browser environment');
2849
2795
  }
2850
2796
  const loginUrl = buildOAuthLoginUrl(options);
2851
2797
  window.location.href = loginUrl;
@@ -2951,7 +2897,8 @@
2951
2897
  const res1 = yield fetch(`${url}/token`, {
2952
2898
  body: JSON.stringify(tokenRequest),
2953
2899
  method: 'post',
2954
- headers: { 'Content-Type': 'application/json', mode: 'cors' },
2900
+ headers: { 'Content-Type': 'application/json' },
2901
+ mode: 'cors',
2955
2902
  });
2956
2903
  if (res1.status !== 200) {
2957
2904
  const errMsg = yield res1.text();
@@ -3021,7 +2968,11 @@
3021
2968
  if (!url)
3022
2969
  throw new Error(`No database URL given.`);
3023
2970
  const redirectUri = ((_b = db.cloud.options) === null || _b === void 0 ? void 0 : _b.oauthRedirectUri) ||
3024
- (typeof window !== 'undefined' ? window.location.href : undefined);
2971
+ (typeof location !== 'undefined' ? location.href : undefined);
2972
+ // CodeRabbit suggested to fail fast here, but the only situation where
2973
+ // redirectUri would be undefined is in non-browser environments, and
2974
+ // in those environments OAuth redirect does not make sense anyway
2975
+ // and will fail fast in startOAuthRedirect().
3025
2976
  // Start OAuth redirect flow - page navigates away
3026
2977
  startOAuthRedirect({
3027
2978
  databaseUrl: url,
@@ -13827,7 +13778,7 @@
13827
13778
  *
13828
13779
  * ==========================================================================
13829
13780
  *
13830
- * Version 4.2.2, Fri Jan 23 2026
13781
+ * Version 4.2.2, Wed Jan 28 2026
13831
13782
  *
13832
13783
  * https://dexie.org
13833
13784
  *
@@ -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
  /**
@@ -18164,7 +18089,7 @@
18164
18089
  const syncComplete = new rxjs.Subject();
18165
18090
  dexie.cloud = {
18166
18091
  // @ts-ignore
18167
- version: "4.3.5",
18092
+ version: "4.3.6",
18168
18093
  options: Object.assign({}, DEFAULT_OPTIONS),
18169
18094
  schema: null,
18170
18095
  get currentUserId() {
@@ -18434,12 +18359,18 @@
18434
18359
  pendingOAuthError = null; // Clear pending error
18435
18360
  console.debug('[dexie-cloud] Showing OAuth error:', error.message);
18436
18361
  // Show alert to user about the OAuth error
18437
- yield alertUser(db.cloud.userInteraction, 'Authentication Error', {
18438
- type: 'error',
18439
- messageCode: 'GENERIC_ERROR',
18440
- message: error.message,
18441
- messageParams: { provider: error.provider || 'unknown' }
18442
- });
18362
+ // Guard so UI errors don't abort initialization
18363
+ try {
18364
+ yield alertUser(db.cloud.userInteraction, 'Authentication Error', {
18365
+ type: 'error',
18366
+ messageCode: 'GENERIC_ERROR',
18367
+ message: error.message,
18368
+ messageParams: { provider: error.provider || 'unknown' }
18369
+ });
18370
+ }
18371
+ catch (uiError) {
18372
+ console.error('[dexie-cloud] Failed to show OAuth error alert:', uiError);
18373
+ }
18443
18374
  }
18444
18375
  // Process pending OAuth callback if present (from dxc-auth redirect)
18445
18376
  if (pendingOAuthCode && !db.cloud.isServiceWorkerDB) {
@@ -18543,7 +18474,7 @@
18543
18474
  }
18544
18475
  }
18545
18476
  // @ts-ignore
18546
- dexieCloud.version = "4.3.5";
18477
+ dexieCloud.version = "4.3.6";
18547
18478
  Dexie.Cloud = dexieCloud;
18548
18479
 
18549
18480
  exports.default = dexieCloud;