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.
- package/TODO-SOCIALAUTH.md +1 -1
- package/dist/modern/authentication/handleOAuthCallback.d.ts +0 -4
- package/dist/modern/default-ui/OptionButton.d.ts +0 -4
- package/dist/modern/dexie-cloud-addon.js +50 -119
- package/dist/modern/dexie-cloud-addon.js.map +1 -1
- package/dist/modern/dexie-cloud-addon.min.js +1 -1
- package/dist/modern/dexie-cloud-addon.min.js.map +1 -1
- package/dist/modern/service-worker.js +50 -119
- package/dist/modern/service-worker.js.map +1 -1
- package/dist/modern/service-worker.min.js +1 -1
- package/dist/modern/service-worker.min.js.map +1 -1
- package/dist/modern/types/DXCUserInteraction.d.ts +1 -3
- package/dist/umd/dexie-cloud-addon.js +51 -120
- package/dist/umd/dexie-cloud-addon.js.map +1 -1
- package/dist/umd/dexie-cloud-addon.min.js +1 -1
- package/dist/umd/dexie-cloud-addon.min.js.map +1 -1
- package/dist/umd/service-worker.js +51 -120
- package/dist/umd/service-worker.js.map +1 -1
- package/dist/umd/service-worker.min.js +1 -1
- package/dist/umd/service-worker.min.js.map +1 -1
- package/package.json +1 -1
|
@@ -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 (
|
|
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.
|
|
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
|
-
/**
|
|
2065
|
-
const
|
|
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
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
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
|
|
2282
|
-
const providerOptions =
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
2847
|
-
|
|
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'
|
|
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
|
|
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,
|
|
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: "#
|
|
17070
|
-
border: "1px solid #
|
|
17071
|
-
color: "#
|
|
17020
|
+
backgroundColor: "#ffffff",
|
|
17021
|
+
border: "1px solid #dadce0",
|
|
17022
|
+
color: "#181717"
|
|
17072
17023
|
},
|
|
17073
17024
|
ProviderMicrosoft: {
|
|
17074
17025
|
backgroundColor: "#ffffff",
|
|
17075
|
-
border: "1px solid #
|
|
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: "#
|
|
17085
|
-
border: "1px solid #
|
|
17086
|
-
color: "#
|
|
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,
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
18438
|
-
|
|
18439
|
-
|
|
18440
|
-
|
|
18441
|
-
|
|
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.
|
|
18477
|
+
dexieCloud.version = "4.3.6";
|
|
18547
18478
|
Dexie.Cloud = dexieCloud;
|
|
18548
18479
|
|
|
18549
18480
|
exports.default = dexieCloud;
|