dexie-cloud-addon 4.3.4 → 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 +69 -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 +69 -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 +70 -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 +70 -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;
|
|
@@ -2897,6 +2843,25 @@
|
|
|
2897
2843
|
public_key,
|
|
2898
2844
|
};
|
|
2899
2845
|
}
|
|
2846
|
+
else if ((hints === null || hints === void 0 ? void 0 : hints.grant_type) === 'otp' || (hints === null || hints === void 0 ? void 0 : hints.email)) {
|
|
2847
|
+
// User explicitly requested OTP flow - skip provider selection
|
|
2848
|
+
const email = (hints === null || hints === void 0 ? void 0 : hints.email) || (yield promptForEmail(userInteraction, 'Enter email address'));
|
|
2849
|
+
if (/@demo.local$/.test(email)) {
|
|
2850
|
+
tokenRequest = {
|
|
2851
|
+
demo_user: email,
|
|
2852
|
+
grant_type: 'demo',
|
|
2853
|
+
scopes: ['ACCESS_DB'],
|
|
2854
|
+
public_key
|
|
2855
|
+
};
|
|
2856
|
+
}
|
|
2857
|
+
else {
|
|
2858
|
+
tokenRequest = {
|
|
2859
|
+
email,
|
|
2860
|
+
grant_type: 'otp',
|
|
2861
|
+
scopes: ['ACCESS_DB'],
|
|
2862
|
+
};
|
|
2863
|
+
}
|
|
2864
|
+
}
|
|
2900
2865
|
else {
|
|
2901
2866
|
// Check for available auth providers (OAuth + OTP)
|
|
2902
2867
|
const socialAuthEnabled = ((_c = db.cloud.options) === null || _c === void 0 ? void 0 : _c.socialAuth) !== false;
|
|
@@ -2932,7 +2897,8 @@
|
|
|
2932
2897
|
const res1 = yield fetch(`${url}/token`, {
|
|
2933
2898
|
body: JSON.stringify(tokenRequest),
|
|
2934
2899
|
method: 'post',
|
|
2935
|
-
headers: { 'Content-Type': 'application/json'
|
|
2900
|
+
headers: { 'Content-Type': 'application/json' },
|
|
2901
|
+
mode: 'cors',
|
|
2936
2902
|
});
|
|
2937
2903
|
if (res1.status !== 200) {
|
|
2938
2904
|
const errMsg = yield res1.text();
|
|
@@ -3002,7 +2968,11 @@
|
|
|
3002
2968
|
if (!url)
|
|
3003
2969
|
throw new Error(`No database URL given.`);
|
|
3004
2970
|
const redirectUri = ((_b = db.cloud.options) === null || _b === void 0 ? void 0 : _b.oauthRedirectUri) ||
|
|
3005
|
-
(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().
|
|
3006
2976
|
// Start OAuth redirect flow - page navigates away
|
|
3007
2977
|
startOAuthRedirect({
|
|
3008
2978
|
databaseUrl: url,
|
|
@@ -13808,7 +13778,7 @@
|
|
|
13808
13778
|
*
|
|
13809
13779
|
* ==========================================================================
|
|
13810
13780
|
*
|
|
13811
|
-
* Version 4.2.2,
|
|
13781
|
+
* Version 4.2.2, Wed Jan 28 2026
|
|
13812
13782
|
*
|
|
13813
13783
|
* https://dexie.org
|
|
13814
13784
|
*
|
|
@@ -17047,13 +17017,13 @@
|
|
|
17047
17017
|
color: "#3c4043"
|
|
17048
17018
|
},
|
|
17049
17019
|
ProviderGitHub: {
|
|
17050
|
-
backgroundColor: "#
|
|
17051
|
-
border: "1px solid #
|
|
17052
|
-
color: "#
|
|
17020
|
+
backgroundColor: "#ffffff",
|
|
17021
|
+
border: "1px solid #dadce0",
|
|
17022
|
+
color: "#181717"
|
|
17053
17023
|
},
|
|
17054
17024
|
ProviderMicrosoft: {
|
|
17055
17025
|
backgroundColor: "#ffffff",
|
|
17056
|
-
border: "1px solid #
|
|
17026
|
+
border: "1px solid #dadce0",
|
|
17057
17027
|
color: "#5e5e5e"
|
|
17058
17028
|
},
|
|
17059
17029
|
ProviderApple: {
|
|
@@ -17062,9 +17032,9 @@
|
|
|
17062
17032
|
color: "#ffffff"
|
|
17063
17033
|
},
|
|
17064
17034
|
ProviderCustom: {
|
|
17065
|
-
backgroundColor: "#
|
|
17066
|
-
border: "1px solid #
|
|
17067
|
-
color: "#
|
|
17035
|
+
backgroundColor: "#ffffff",
|
|
17036
|
+
border: "1px solid #dadce0",
|
|
17037
|
+
color: "#181717"
|
|
17068
17038
|
},
|
|
17069
17039
|
// Divider styles
|
|
17070
17040
|
Divider: {
|
|
@@ -17155,39 +17125,13 @@
|
|
|
17155
17125
|
* Generic button component for selectable options.
|
|
17156
17126
|
* Displays the option's icon and display name.
|
|
17157
17127
|
*
|
|
17158
|
-
* The icon can be:
|
|
17159
|
-
* - Inline SVG (iconSvg) - rendered directly with dangerouslySetInnerHTML
|
|
17160
|
-
* - Image URL (iconUrl) - rendered as an img tag
|
|
17161
|
-
*
|
|
17162
17128
|
* Style is determined by the styleHint property for branding purposes.
|
|
17163
17129
|
*/
|
|
17164
17130
|
function OptionButton({ option, onClick }) {
|
|
17165
|
-
const { displayName, iconUrl,
|
|
17131
|
+
const { displayName, iconUrl, styleHint } = option;
|
|
17166
17132
|
const style = getOptionStyle(styleHint);
|
|
17167
|
-
// Get the text color from the button style for SVG fill processing
|
|
17168
|
-
const textColor = style.color || '#000000';
|
|
17169
|
-
// Process SVG to replace currentColor with actual text color
|
|
17170
|
-
const processedSvg = iconSvg
|
|
17171
|
-
? iconSvg
|
|
17172
|
-
.replace(/fill="currentColor"/gi, `fill="${textColor}"`)
|
|
17173
|
-
.replace(/fill='currentColor'/gi, `fill='${textColor}'`)
|
|
17174
|
-
.replace(/stroke="currentColor"/gi, `stroke="${textColor}"`)
|
|
17175
|
-
.replace(/stroke='currentColor'/gi, `stroke='${textColor}'`)
|
|
17176
|
-
: null;
|
|
17177
|
-
// Render the appropriate icon
|
|
17178
|
-
const renderIcon = () => {
|
|
17179
|
-
// Inline SVG
|
|
17180
|
-
if (processedSvg) {
|
|
17181
|
-
return (_$1("span", { style: Styles.ProviderButtonIcon, "aria-hidden": "true", dangerouslySetInnerHTML: { __html: processedSvg } }));
|
|
17182
|
-
}
|
|
17183
|
-
// Image URL
|
|
17184
|
-
if (iconUrl) {
|
|
17185
|
-
return (_$1("img", { src: iconUrl, alt: "", style: Styles.ProviderButtonIcon, "aria-hidden": "true" }));
|
|
17186
|
-
}
|
|
17187
|
-
return null;
|
|
17188
|
-
};
|
|
17189
17133
|
return (_$1("button", { type: "button", style: style, onClick: onClick, class: `dxc-option-btn${styleHint ? ` dxc-option-${styleHint}` : ''}`, "aria-label": displayName },
|
|
17190
|
-
|
|
17134
|
+
iconUrl && (_$1("img", { src: iconUrl, alt: "", style: Styles.ProviderButtonIcon, "aria-hidden": "true" })),
|
|
17191
17135
|
_$1("span", { style: Styles.ProviderButtonText }, displayName)));
|
|
17192
17136
|
}
|
|
17193
17137
|
/**
|
|
@@ -18145,7 +18089,7 @@
|
|
|
18145
18089
|
const syncComplete = new rxjs.Subject();
|
|
18146
18090
|
dexie.cloud = {
|
|
18147
18091
|
// @ts-ignore
|
|
18148
|
-
version: "4.3.
|
|
18092
|
+
version: "4.3.6",
|
|
18149
18093
|
options: Object.assign({}, DEFAULT_OPTIONS),
|
|
18150
18094
|
schema: null,
|
|
18151
18095
|
get currentUserId() {
|
|
@@ -18415,12 +18359,18 @@
|
|
|
18415
18359
|
pendingOAuthError = null; // Clear pending error
|
|
18416
18360
|
console.debug('[dexie-cloud] Showing OAuth error:', error.message);
|
|
18417
18361
|
// Show alert to user about the OAuth error
|
|
18418
|
-
|
|
18419
|
-
|
|
18420
|
-
|
|
18421
|
-
|
|
18422
|
-
|
|
18423
|
-
|
|
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
|
+
}
|
|
18424
18374
|
}
|
|
18425
18375
|
// Process pending OAuth callback if present (from dxc-auth redirect)
|
|
18426
18376
|
if (pendingOAuthCode && !db.cloud.isServiceWorkerDB) {
|
|
@@ -18524,7 +18474,7 @@
|
|
|
18524
18474
|
}
|
|
18525
18475
|
}
|
|
18526
18476
|
// @ts-ignore
|
|
18527
|
-
dexieCloud.version = "4.3.
|
|
18477
|
+
dexieCloud.version = "4.3.6";
|
|
18528
18478
|
Dexie.Cloud = dexieCloud;
|
|
18529
18479
|
|
|
18530
18480
|
exports.default = dexieCloud;
|