dexie-cloud-addon 4.4.5 → 4.4.7
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/dist/modern/DXCWebSocketStatus.d.ts +1 -1
- package/dist/modern/DexieCloudAPI.d.ts +1 -1
- package/dist/modern/authentication/AuthPersistedContext.d.ts +2 -2
- package/dist/modern/currentUserEmitter.d.ts +3 -3
- package/dist/modern/db/entities/Member.d.ts +3 -3
- package/dist/modern/db/entities/PersistedSyncState.d.ts +1 -1
- package/dist/modern/db/entities/Role.d.ts +3 -3
- package/dist/modern/default-ui/Dialog.d.ts +1 -1
- package/dist/modern/default-ui/index.d.ts +5 -5
- package/dist/modern/dexie-cloud-addon.js +646 -526
- 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/dexie-cloud-client.d.ts +1 -1
- package/dist/modern/helpers/BroadcastedAndLocalEvent.d.ts +2 -2
- package/dist/modern/helpers/getSyncableTables.d.ts +3 -3
- package/dist/modern/helpers/resolveText.d.ts +1 -1
- package/dist/modern/middleware-helpers/guardedTable.d.ts +1 -1
- package/dist/modern/service-worker.js +648 -528
- 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/sync/BlobDownloadTracker.d.ts +2 -2
- package/dist/modern/sync/extractRealm.d.ts +1 -1
- package/dist/modern/sync/getTablesToSyncify.d.ts +2 -2
- package/dist/modern/sync/isSyncNeeded.d.ts +1 -1
- package/dist/modern/sync/messageConsumerIsReady.d.ts +1 -1
- package/dist/modern/sync/modifyLocalObjectsWithNewUserId.d.ts +3 -3
- package/dist/modern/sync/numUnsyncedMutations.d.ts +1 -1
- package/dist/modern/sync/performGuardedJob.d.ts +1 -1
- package/dist/modern/sync/registerSyncEvent.d.ts +1 -1
- package/dist/modern/sync/triggerSync.d.ts +2 -2
- package/dist/modern/types/DXCUserInteraction.d.ts +2 -2
- package/dist/modern/types/SyncState.d.ts +2 -2
- package/dist/modern/types/TXExpandos.d.ts +1 -1
- package/dist/modern/updateSchemaFromOptions.d.ts +2 -2
- package/dist/modern/verifyConfig.d.ts +1 -1
- package/dist/modern/verifySchema.d.ts +1 -1
- package/dist/modern/yjs/YTable.d.ts +3 -3
- package/dist/modern/yjs/getUpdatesTable.d.ts +2 -2
- package/dist/modern/yjs/reopenDocSignal.d.ts +2 -2
- package/dist/umd/dexie-cloud-addon.js +654 -534
- 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 +656 -536
- 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 +3 -3
- package/dist/modern/default-ui/AuthProviderButton.d.ts +0 -21
- package/dist/modern/default-ui/ProviderSelectionDialog.d.ts +0 -7
- package/dist/modern/default-ui/SelectDialog.d.ts +0 -10
- package/dist/modern/dexie-cloud-addon.min.js.gz +0 -0
- package/dist/umd/DISABLE_SERVICEWORKER_STRATEGY.d.ts +0 -1
- package/dist/umd/DXCWebSocketStatus.d.ts +0 -1
- package/dist/umd/DexieCloudAPI.d.ts +0 -75
- package/dist/umd/DexieCloudOptions.d.ts +0 -27
- package/dist/umd/DexieCloudSyncOptions.d.ts +0 -4
- package/dist/umd/DexieCloudTable.d.ts +0 -18
- package/dist/umd/InvalidLicenseError.d.ts +0 -5
- package/dist/umd/Invite.d.ts +0 -8
- package/dist/umd/PermissionChecker.d.ts +0 -15
- package/dist/umd/TSON.d.ts +0 -17
- package/dist/umd/WSObservable.d.ts +0 -72
- package/dist/umd/associate.d.ts +0 -1
- package/dist/umd/authentication/AuthPersistedContext.d.ts +0 -9
- package/dist/umd/authentication/TokenErrorResponseError.d.ts +0 -10
- package/dist/umd/authentication/TokenExpiredError.d.ts +0 -3
- package/dist/umd/authentication/UNAUTHORIZED_USER.d.ts +0 -2
- package/dist/umd/authentication/authenticate.d.ts +0 -13
- package/dist/umd/authentication/currentUserObservable.d.ts +0 -1
- package/dist/umd/authentication/interactWithUser.d.ts +0 -21
- package/dist/umd/authentication/login.d.ts +0 -3
- package/dist/umd/authentication/logout.d.ts +0 -5
- package/dist/umd/authentication/otpFetchTokenCallback.d.ts +0 -3
- package/dist/umd/authentication/setCurrentUser.d.ts +0 -14
- package/dist/umd/authentication/waitUntil.d.ts +0 -3
- package/dist/umd/computeSyncState.d.ts +0 -4
- package/dist/umd/createSharedValueObservable.d.ts +0 -3
- package/dist/umd/currentUserEmitter.d.ts +0 -3
- package/dist/umd/db/DexieCloudDB.d.ts +0 -61
- package/dist/umd/db/entities/BaseRevisionMapEntry.d.ts +0 -5
- package/dist/umd/db/entities/EntityCommon.d.ts +0 -5
- package/dist/umd/db/entities/GuardedJob.d.ts +0 -5
- package/dist/umd/db/entities/Member.d.ts +0 -19
- package/dist/umd/db/entities/PersistedSyncState.d.ts +0 -22
- package/dist/umd/db/entities/Realm.d.ts +0 -14
- package/dist/umd/db/entities/Role.d.ts +0 -11
- package/dist/umd/db/entities/UserLogin.d.ts +0 -23
- package/dist/umd/default-ui/Dialog.d.ts +0 -5
- package/dist/umd/default-ui/LoginDialog.d.ts +0 -3
- package/dist/umd/default-ui/Styles.d.ts +0 -3
- package/dist/umd/default-ui/index.d.ts +0 -24
- package/dist/umd/define-ydoc-trigger.d.ts +0 -3
- package/dist/umd/dexie-cloud-addon.d.ts +0 -3
- package/dist/umd/dexie-cloud-addon.js.gz +0 -0
- package/dist/umd/dexie-cloud-addon.min.js.gz +0 -0
- package/dist/umd/dexie-cloud-client.d.ts +0 -23
- package/dist/umd/errors/HttpError.d.ts +0 -5
- package/dist/umd/extend-dexie-interface.d.ts +0 -23
- package/dist/umd/getGlobalRolesObservable.d.ts +0 -5
- package/dist/umd/getInternalAccessControlObservable.d.ts +0 -12
- package/dist/umd/getInvitesObservable.d.ts +0 -23
- package/dist/umd/getPermissionsLookupObservable.d.ts +0 -16
- package/dist/umd/getTiedRealmId.d.ts +0 -2
- package/dist/umd/helpers/BroadcastedAndLocalEvent.d.ts +0 -8
- package/dist/umd/helpers/CancelToken.d.ts +0 -4
- package/dist/umd/helpers/IS_SERVICE_WORKER.d.ts +0 -1
- package/dist/umd/helpers/SWBroadcastChannel.d.ts +0 -12
- package/dist/umd/helpers/allSettled.d.ts +0 -1
- package/dist/umd/helpers/bulkUpdate.d.ts +0 -4
- package/dist/umd/helpers/computeRealmSetHash.d.ts +0 -2
- package/dist/umd/helpers/date-constants.d.ts +0 -5
- package/dist/umd/helpers/flatten.d.ts +0 -1
- package/dist/umd/helpers/getMutationTable.d.ts +0 -1
- package/dist/umd/helpers/getSyncableTables.d.ts +0 -4
- package/dist/umd/helpers/getTableFromMutationTable.d.ts +0 -1
- package/dist/umd/helpers/makeArray.d.ts +0 -1
- package/dist/umd/helpers/randomString.d.ts +0 -1
- package/dist/umd/helpers/resolveText.d.ts +0 -16
- package/dist/umd/helpers/throwVersionIncrementNeeded.d.ts +0 -1
- package/dist/umd/helpers/visibilityState.d.ts +0 -1
- package/dist/umd/isEagerSyncDisabled.d.ts +0 -2
- package/dist/umd/isFirefox.d.ts +0 -1
- package/dist/umd/isSafari.d.ts +0 -2
- package/dist/umd/mapValueObservable.d.ts +0 -5
- package/dist/umd/mergePermissions.d.ts +0 -2
- package/dist/umd/middleware-helpers/guardedTable.d.ts +0 -11
- package/dist/umd/middleware-helpers/idGenerationHelpers.d.ts +0 -18
- package/dist/umd/middlewares/createIdGenerationMiddleware.d.ts +0 -3
- package/dist/umd/middlewares/createImplicitPropSetterMiddleware.d.ts +0 -3
- package/dist/umd/middlewares/createMutationTrackingMiddleware.d.ts +0 -17
- package/dist/umd/middlewares/outstandingTransaction.d.ts +0 -4
- package/dist/umd/overrideParseStoresSpec.d.ts +0 -4
- package/dist/umd/performInitialSync.d.ts +0 -4
- package/dist/umd/permissions.d.ts +0 -9
- package/dist/umd/prodLog.d.ts +0 -9
- package/dist/umd/service-worker.d.ts +0 -1
- package/dist/umd/sync/DEXIE_CLOUD_SYNCER_ID.d.ts +0 -1
- package/dist/umd/sync/LocalSyncWorker.d.ts +0 -7
- package/dist/umd/sync/SyncRequiredError.d.ts +0 -3
- package/dist/umd/sync/applyServerChanges.d.ts +0 -3
- package/dist/umd/sync/connectWebSocket.d.ts +0 -2
- package/dist/umd/sync/encodeIdsForServer.d.ts +0 -4
- package/dist/umd/sync/extractRealm.d.ts +0 -2
- package/dist/umd/sync/getLatestRevisionsPerTable.d.ts +0 -6
- package/dist/umd/sync/getTablesToSyncify.d.ts +0 -3
- package/dist/umd/sync/isOnline.d.ts +0 -1
- package/dist/umd/sync/isSyncNeeded.d.ts +0 -2
- package/dist/umd/sync/listClientChanges.d.ts +0 -9
- package/dist/umd/sync/listSyncifiedChanges.d.ts +0 -5
- package/dist/umd/sync/messageConsumerIsReady.d.ts +0 -2
- package/dist/umd/sync/messagesFromServerQueue.d.ts +0 -8
- package/dist/umd/sync/modifyLocalObjectsWithNewUserId.d.ts +0 -4
- package/dist/umd/sync/myId.d.ts +0 -1
- package/dist/umd/sync/numUnsyncedMutations.d.ts +0 -2
- package/dist/umd/sync/old_startSyncingClientChanges.d.ts +0 -39
- package/dist/umd/sync/performGuardedJob.d.ts +0 -2
- package/dist/umd/sync/ratelimit.d.ts +0 -3
- package/dist/umd/sync/registerSyncEvent.d.ts +0 -3
- package/dist/umd/sync/sync.d.ts +0 -15
- package/dist/umd/sync/syncIfPossible.d.ts +0 -5
- package/dist/umd/sync/syncWithServer.d.ts +0 -6
- package/dist/umd/sync/triggerSync.d.ts +0 -2
- package/dist/umd/sync/updateBaseRevs.d.ts +0 -5
- package/dist/umd/types/DXCAlert.d.ts +0 -25
- package/dist/umd/types/DXCInputField.d.ts +0 -11
- package/dist/umd/types/DXCUserInteraction.d.ts +0 -93
- package/dist/umd/types/NewIdOptions.d.ts +0 -3
- package/dist/umd/types/SWMessageEvent.d.ts +0 -3
- package/dist/umd/types/SWSyncEvent.d.ts +0 -4
- package/dist/umd/types/SyncState.d.ts +0 -9
- package/dist/umd/types/TXExpandos.d.ts +0 -11
- package/dist/umd/updateSchemaFromOptions.d.ts +0 -3
- package/dist/umd/userIsActive.d.ts +0 -7
- package/dist/umd/verifyConfig.d.ts +0 -2
- package/dist/umd/verifySchema.d.ts +0 -2
- package/dist/umd/yjs/YDexieCloudSyncState.d.ts +0 -3
- package/dist/umd/yjs/YTable.d.ts +0 -3
- package/dist/umd/yjs/applyYMessages.d.ts +0 -9
- package/dist/umd/yjs/awareness.d.ts +0 -3
- package/dist/umd/yjs/createYClientUpdateObservable.d.ts +0 -4
- package/dist/umd/yjs/createYHandler.d.ts +0 -2
- package/dist/umd/yjs/downloadYDocsFromServer.d.ts +0 -3
- package/dist/umd/yjs/getUpdatesTable.d.ts +0 -3
- package/dist/umd/yjs/listUpdatesSince.d.ts +0 -3
- package/dist/umd/yjs/listYClientMessagesAndStateVector.d.ts +0 -26
- package/dist/umd/yjs/reopenDocSignal.d.ts +0 -10
- package/dist/umd/yjs/updateYSyncStates.d.ts +0 -6
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*
|
|
9
9
|
* ==========================================================================
|
|
10
10
|
*
|
|
11
|
-
* Version 4.4.
|
|
11
|
+
* Version 4.4.7, Fri Mar 27 2026
|
|
12
12
|
*
|
|
13
13
|
* https://dexie.org
|
|
14
14
|
*
|
|
@@ -107,12 +107,12 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
|
|
|
107
107
|
};
|
|
108
108
|
|
|
109
109
|
const UNAUTHORIZED_USER = {
|
|
110
|
-
userId:
|
|
111
|
-
name:
|
|
110
|
+
userId: 'unauthorized',
|
|
111
|
+
name: 'Unauthorized',
|
|
112
112
|
claims: {
|
|
113
|
-
sub:
|
|
113
|
+
sub: 'unauthorized',
|
|
114
114
|
},
|
|
115
|
-
lastLogin: new Date(0)
|
|
115
|
+
lastLogin: new Date(0),
|
|
116
116
|
};
|
|
117
117
|
try {
|
|
118
118
|
Object.freeze(UNAUTHORIZED_USER);
|
|
@@ -121,8 +121,10 @@ try {
|
|
|
121
121
|
catch (_a) { }
|
|
122
122
|
|
|
123
123
|
const swHolder = {};
|
|
124
|
-
const swContainer = typeof self !== 'undefined' &&
|
|
125
|
-
|
|
124
|
+
const swContainer = typeof self !== 'undefined' &&
|
|
125
|
+
self.document && // self.document is to verify we're not the SW ourself
|
|
126
|
+
typeof navigator !== 'undefined' &&
|
|
127
|
+
navigator.serviceWorker;
|
|
126
128
|
if (swContainer)
|
|
127
129
|
swContainer.ready.then((registration) => (swHolder.registration = registration));
|
|
128
130
|
if (typeof self !== 'undefined' && 'clients' in self && !self.document) {
|
|
@@ -176,7 +178,8 @@ class SWBroadcastChannel {
|
|
|
176
178
|
}
|
|
177
179
|
}
|
|
178
180
|
|
|
179
|
-
const events = globalThis['lbc-events'] ||
|
|
181
|
+
const events = globalThis['lbc-events'] ||
|
|
182
|
+
(globalThis['lbc-events'] = new Map());
|
|
180
183
|
function addListener(name, listener) {
|
|
181
184
|
if (events.has(name)) {
|
|
182
185
|
events.get(name).push(listener);
|
|
@@ -197,25 +200,25 @@ function removeListener(name, listener) {
|
|
|
197
200
|
function dispatch(ev) {
|
|
198
201
|
const listeners = events.get(ev.type);
|
|
199
202
|
if (listeners) {
|
|
200
|
-
listeners.forEach(listener => {
|
|
203
|
+
listeners.forEach((listener) => {
|
|
201
204
|
try {
|
|
202
205
|
listener(ev);
|
|
203
206
|
}
|
|
204
|
-
catch (_a) {
|
|
205
|
-
}
|
|
207
|
+
catch (_a) { }
|
|
206
208
|
});
|
|
207
209
|
}
|
|
208
210
|
}
|
|
209
211
|
class BroadcastedAndLocalEvent extends Observable {
|
|
210
212
|
constructor(name) {
|
|
211
|
-
const bc = typeof BroadcastChannel ===
|
|
212
|
-
? new SWBroadcastChannel(name)
|
|
213
|
-
|
|
213
|
+
const bc = typeof BroadcastChannel === 'undefined'
|
|
214
|
+
? new SWBroadcastChannel(name)
|
|
215
|
+
: new BroadcastChannel(name);
|
|
216
|
+
super((subscriber) => {
|
|
214
217
|
function onCustomEvent(ev) {
|
|
215
218
|
subscriber.next(ev.detail);
|
|
216
219
|
}
|
|
217
220
|
function onMessageEvent(ev) {
|
|
218
|
-
console.debug(
|
|
221
|
+
console.debug('BroadcastedAndLocalEvent: onMessageEvent', ev);
|
|
219
222
|
subscriber.next(ev.data);
|
|
220
223
|
}
|
|
221
224
|
let unsubscribe;
|
|
@@ -223,11 +226,11 @@ class BroadcastedAndLocalEvent extends Observable {
|
|
|
223
226
|
addListener(`lbc-${name}`, onCustomEvent); // Works better in service worker
|
|
224
227
|
try {
|
|
225
228
|
if (bc instanceof SWBroadcastChannel) {
|
|
226
|
-
unsubscribe = bc.subscribe(message => subscriber.next(message));
|
|
229
|
+
unsubscribe = bc.subscribe((message) => subscriber.next(message));
|
|
227
230
|
}
|
|
228
231
|
else {
|
|
229
|
-
console.debug(
|
|
230
|
-
bc.addEventListener(
|
|
232
|
+
console.debug('BroadcastedAndLocalEvent: bc.addEventListener()', name, 'bc is a', bc);
|
|
233
|
+
bc.addEventListener('message', onMessageEvent);
|
|
231
234
|
}
|
|
232
235
|
}
|
|
233
236
|
catch (err) {
|
|
@@ -241,7 +244,7 @@ class BroadcastedAndLocalEvent extends Observable {
|
|
|
241
244
|
unsubscribe();
|
|
242
245
|
}
|
|
243
246
|
else {
|
|
244
|
-
bc.removeEventListener(
|
|
247
|
+
bc.removeEventListener('message', onMessageEvent);
|
|
245
248
|
}
|
|
246
249
|
};
|
|
247
250
|
});
|
|
@@ -249,7 +252,7 @@ class BroadcastedAndLocalEvent extends Observable {
|
|
|
249
252
|
this.bc = bc;
|
|
250
253
|
}
|
|
251
254
|
next(message) {
|
|
252
|
-
console.debug(
|
|
255
|
+
console.debug('BroadcastedAndLocalEvent: bc.postMessage()', Object.assign({}, message), 'bc is a', this.bc);
|
|
253
256
|
this.bc.postMessage(message);
|
|
254
257
|
const ev = new CustomEvent(`lbc-${this.name}`, { detail: message });
|
|
255
258
|
//self.dispatchEvent(ev);
|
|
@@ -264,7 +267,7 @@ function registerSyncEvent(db, purpose) {
|
|
|
264
267
|
try {
|
|
265
268
|
// Send sync event to SW:
|
|
266
269
|
const sw = yield navigator.serviceWorker.ready;
|
|
267
|
-
if (purpose ===
|
|
270
|
+
if (purpose === 'push' && sw.sync) {
|
|
268
271
|
yield sw.sync.register(`dexie-cloud:${db.name}`);
|
|
269
272
|
}
|
|
270
273
|
if (sw.active) {
|
|
@@ -273,7 +276,7 @@ function registerSyncEvent(db, purpose) {
|
|
|
273
276
|
sw.active.postMessage({
|
|
274
277
|
type: 'dexie-cloud-sync',
|
|
275
278
|
dbName: db.name,
|
|
276
|
-
purpose
|
|
279
|
+
purpose,
|
|
277
280
|
});
|
|
278
281
|
}
|
|
279
282
|
else {
|
|
@@ -333,7 +336,7 @@ function escapeDollarProps(value) {
|
|
|
333
336
|
const keys = Object.keys(value);
|
|
334
337
|
let dollarKeys = null;
|
|
335
338
|
for (let i = 0, l = keys.length; i < l; ++i) {
|
|
336
|
-
if (keys[i][0] ===
|
|
339
|
+
if (keys[i][0] === '$') {
|
|
337
340
|
dollarKeys = dollarKeys || [];
|
|
338
341
|
dollarKeys.push(keys[i]);
|
|
339
342
|
}
|
|
@@ -345,7 +348,7 @@ function escapeDollarProps(value) {
|
|
|
345
348
|
delete clone[k];
|
|
346
349
|
}
|
|
347
350
|
for (const k of dollarKeys) {
|
|
348
|
-
clone[
|
|
351
|
+
clone['$' + k] = value[k];
|
|
349
352
|
}
|
|
350
353
|
return clone;
|
|
351
354
|
}
|
|
@@ -396,7 +399,7 @@ function TypesonSimplified(...typeDefsInputs) {
|
|
|
396
399
|
//
|
|
397
400
|
// Child part
|
|
398
401
|
//
|
|
399
|
-
if (value === undefined || (key[0] ===
|
|
402
|
+
if (value === undefined || (key[0] === '$' && key !== '$t')) {
|
|
400
403
|
top = stack[stack.length - 1];
|
|
401
404
|
let deletes;
|
|
402
405
|
let mods;
|
|
@@ -407,7 +410,7 @@ function TypesonSimplified(...typeDefsInputs) {
|
|
|
407
410
|
else {
|
|
408
411
|
stack.push([this, (deletes = []), (mods = {})]);
|
|
409
412
|
}
|
|
410
|
-
if (key[0] ===
|
|
413
|
+
if (key[0] === '$' && key !== '$t') {
|
|
411
414
|
// Unescape props (also preserves undefined if this is a combo)
|
|
412
415
|
deletes.push(key);
|
|
413
416
|
mods[key.substr(1)] = value;
|
|
@@ -424,8 +427,8 @@ function TypesonSimplified(...typeDefsInputs) {
|
|
|
424
427
|
function getTypeDef(realVal) {
|
|
425
428
|
const type = typeof realVal;
|
|
426
429
|
switch (typeof realVal) {
|
|
427
|
-
case
|
|
428
|
-
case
|
|
430
|
+
case 'object':
|
|
431
|
+
case 'function': {
|
|
429
432
|
// "object", "function", null
|
|
430
433
|
if (realVal === null)
|
|
431
434
|
return null;
|
|
@@ -441,7 +444,7 @@ function TypesonSimplified(...typeDefsInputs) {
|
|
|
441
444
|
if (!typeDef) {
|
|
442
445
|
typeDef = Array.isArray(realVal)
|
|
443
446
|
? null
|
|
444
|
-
: typeof realVal ===
|
|
447
|
+
: typeof realVal === 'function'
|
|
445
448
|
? typeDefs.function || null
|
|
446
449
|
: ObjectDef;
|
|
447
450
|
}
|
|
@@ -617,13 +620,13 @@ TSONRef.resolver = null;
|
|
|
617
620
|
|
|
618
621
|
function readBlobSync(b) {
|
|
619
622
|
const req = new XMLHttpRequest();
|
|
620
|
-
req.overrideMimeType(
|
|
623
|
+
req.overrideMimeType('text/plain; charset=x-user-defined');
|
|
621
624
|
const url = URL.createObjectURL(b);
|
|
622
625
|
try {
|
|
623
|
-
req.open(
|
|
626
|
+
req.open('GET', url, false); // Sync
|
|
624
627
|
req.send();
|
|
625
628
|
if (req.status !== 200 && req.status !== 0) {
|
|
626
|
-
throw new Error(
|
|
629
|
+
throw new Error('Bad Blob access: ' + req.status);
|
|
627
630
|
}
|
|
628
631
|
return req.responseText;
|
|
629
632
|
}
|
|
@@ -637,11 +640,11 @@ const numberTypeDef = {
|
|
|
637
640
|
replace: (num) => {
|
|
638
641
|
switch (true) {
|
|
639
642
|
case isNaN(num):
|
|
640
|
-
return { $t:
|
|
643
|
+
return { $t: 'number', v: 'NaN' };
|
|
641
644
|
case num === Infinity:
|
|
642
|
-
return { $t:
|
|
645
|
+
return { $t: 'number', v: 'Infinity' };
|
|
643
646
|
case num === -Infinity:
|
|
644
|
-
return { $t:
|
|
647
|
+
return { $t: 'number', v: '-Infinity' };
|
|
645
648
|
default:
|
|
646
649
|
return num;
|
|
647
650
|
}
|
|
@@ -653,17 +656,17 @@ const numberTypeDef = {
|
|
|
653
656
|
const dateTypeDef = {
|
|
654
657
|
Date: {
|
|
655
658
|
replace: (date) => ({
|
|
656
|
-
$t:
|
|
657
|
-
v: isNaN(date.getTime()) ?
|
|
659
|
+
$t: 'Date',
|
|
660
|
+
v: isNaN(date.getTime()) ? 'NaN' : date.toISOString(),
|
|
658
661
|
}),
|
|
659
|
-
revive: ({ v }) => new Date(v ===
|
|
662
|
+
revive: ({ v }) => new Date(v === 'NaN' ? NaN : Date.parse(v)),
|
|
660
663
|
},
|
|
661
664
|
};
|
|
662
665
|
|
|
663
666
|
const setTypeDef = {
|
|
664
667
|
Set: {
|
|
665
668
|
replace: (set) => ({
|
|
666
|
-
$t:
|
|
669
|
+
$t: 'Set',
|
|
667
670
|
v: Array.from(set),
|
|
668
671
|
}),
|
|
669
672
|
revive: ({ v }) => new Set(v),
|
|
@@ -673,34 +676,34 @@ const setTypeDef = {
|
|
|
673
676
|
const mapTypeDef = {
|
|
674
677
|
Map: {
|
|
675
678
|
replace: (map) => ({
|
|
676
|
-
$t:
|
|
679
|
+
$t: 'Map',
|
|
677
680
|
v: Array.from(map.entries()),
|
|
678
681
|
}),
|
|
679
682
|
revive: ({ v }) => new Map(v),
|
|
680
683
|
},
|
|
681
684
|
};
|
|
682
685
|
|
|
683
|
-
const _global = typeof globalThis !==
|
|
686
|
+
const _global = typeof globalThis !== 'undefined' // All modern environments (node, bun, deno, browser, workers, webview etc)
|
|
684
687
|
? globalThis
|
|
685
|
-
: typeof self !==
|
|
688
|
+
: typeof self !== 'undefined' // Older browsers, workers, webview, window etc
|
|
686
689
|
? self
|
|
687
|
-
: typeof global !==
|
|
690
|
+
: typeof global !== 'undefined' // Older versions of node
|
|
688
691
|
? global
|
|
689
692
|
: undefined; // Unsupported environment. No idea to return 'this' since we are in a module or a function scope anyway.
|
|
690
693
|
|
|
691
694
|
const typedArrayTypeDefs = [
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
695
|
+
'Int8Array',
|
|
696
|
+
'Uint8Array',
|
|
697
|
+
'Uint8ClampedArray',
|
|
698
|
+
'Int16Array',
|
|
699
|
+
'Uint16Array',
|
|
700
|
+
'Int32Array',
|
|
701
|
+
'Uint32Array',
|
|
702
|
+
'Float32Array',
|
|
703
|
+
'Float64Array',
|
|
704
|
+
'DataView',
|
|
705
|
+
'BigInt64Array',
|
|
706
|
+
'BigUint64Array',
|
|
704
707
|
].reduce((specs, typeName) => ({
|
|
705
708
|
...specs,
|
|
706
709
|
[typeName]: {
|
|
@@ -728,10 +731,10 @@ const typedArrayTypeDefs = [
|
|
|
728
731
|
},
|
|
729
732
|
}), {});
|
|
730
733
|
|
|
731
|
-
const hasArrayBufferFromBase64 =
|
|
732
|
-
const hasArrayBufferToBase64 =
|
|
733
|
-
const b64decode = typeof Buffer !==
|
|
734
|
-
? (base64) => Buffer.from(base64,
|
|
734
|
+
const hasArrayBufferFromBase64 = 'fromBase64' in Uint8Array; // https://github.com/tc39/proposal-arraybuffer-base64;
|
|
735
|
+
const hasArrayBufferToBase64 = 'toBase64' in Uint8Array.prototype; // https://github.com/tc39/proposal-arraybuffer-base64;
|
|
736
|
+
const b64decode = typeof Buffer !== 'undefined'
|
|
737
|
+
? (base64) => Buffer.from(base64, 'base64') // Node
|
|
735
738
|
: hasArrayBufferFromBase64
|
|
736
739
|
? // @ts-ignore: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array/fromBase64
|
|
737
740
|
(base64) => Uint8Array.fromBase64(base64) // Modern javascript standard
|
|
@@ -745,14 +748,14 @@ const b64decode = typeof Buffer !== "undefined"
|
|
|
745
748
|
}
|
|
746
749
|
return bytes;
|
|
747
750
|
};
|
|
748
|
-
const b64encode = typeof Buffer !==
|
|
751
|
+
const b64encode = typeof Buffer !== 'undefined'
|
|
749
752
|
? (b) => {
|
|
750
753
|
// Node
|
|
751
754
|
if (ArrayBuffer.isView(b)) {
|
|
752
|
-
return Buffer.from(b.buffer, b.byteOffset, b.byteLength).toString(
|
|
755
|
+
return Buffer.from(b.buffer, b.byteOffset, b.byteLength).toString('base64');
|
|
753
756
|
}
|
|
754
757
|
else {
|
|
755
|
-
return Buffer.from(b).toString(
|
|
758
|
+
return Buffer.from(b).toString('base64');
|
|
756
759
|
}
|
|
757
760
|
}
|
|
758
761
|
: hasArrayBufferToBase64
|
|
@@ -771,7 +774,7 @@ const b64encode = typeof Buffer !== "undefined"
|
|
|
771
774
|
const chunk = u8a.subarray(i, i + CHUNK_SIZE);
|
|
772
775
|
strs.push(String.fromCharCode.apply(null, Array.from(chunk)));
|
|
773
776
|
}
|
|
774
|
-
return btoa(strs.join(
|
|
777
|
+
return btoa(strs.join(''));
|
|
775
778
|
};
|
|
776
779
|
|
|
777
780
|
function b64LexEncode(b) {
|
|
@@ -781,7 +784,7 @@ function b64LexDecode(b64Lex) {
|
|
|
781
784
|
return b64decode(lexToB64(b64Lex));
|
|
782
785
|
}
|
|
783
786
|
function b64ToLex(base64) {
|
|
784
|
-
var encoded =
|
|
787
|
+
var encoded = '';
|
|
785
788
|
for (var i = 0, length = base64.length; i < length; i++) {
|
|
786
789
|
encoded += ENCODE_TABLE[base64[i]];
|
|
787
790
|
}
|
|
@@ -789,81 +792,81 @@ function b64ToLex(base64) {
|
|
|
789
792
|
}
|
|
790
793
|
function lexToB64(base64lex) {
|
|
791
794
|
// only accept string input
|
|
792
|
-
if (typeof base64lex !==
|
|
793
|
-
throw new Error(
|
|
795
|
+
if (typeof base64lex !== 'string') {
|
|
796
|
+
throw new Error('invalid decoder input: ' + base64lex);
|
|
794
797
|
}
|
|
795
|
-
var base64 =
|
|
798
|
+
var base64 = '';
|
|
796
799
|
for (var i = 0, length = base64lex.length; i < length; i++) {
|
|
797
800
|
base64 += DECODE_TABLE[base64lex[i]];
|
|
798
801
|
}
|
|
799
802
|
return base64;
|
|
800
803
|
}
|
|
801
804
|
const DECODE_TABLE = {
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
A:
|
|
814
|
-
B:
|
|
815
|
-
C:
|
|
816
|
-
D:
|
|
817
|
-
E:
|
|
818
|
-
F:
|
|
819
|
-
G:
|
|
820
|
-
H:
|
|
821
|
-
I:
|
|
822
|
-
J:
|
|
823
|
-
K:
|
|
824
|
-
L:
|
|
825
|
-
M:
|
|
826
|
-
N:
|
|
827
|
-
O:
|
|
828
|
-
P:
|
|
829
|
-
Q:
|
|
830
|
-
R:
|
|
831
|
-
S:
|
|
832
|
-
T:
|
|
833
|
-
U:
|
|
834
|
-
V:
|
|
835
|
-
W:
|
|
836
|
-
X:
|
|
837
|
-
Y:
|
|
838
|
-
Z:
|
|
839
|
-
_:
|
|
840
|
-
a:
|
|
841
|
-
b:
|
|
842
|
-
c:
|
|
843
|
-
d:
|
|
844
|
-
e:
|
|
845
|
-
f:
|
|
846
|
-
g:
|
|
847
|
-
h:
|
|
848
|
-
i:
|
|
849
|
-
j:
|
|
850
|
-
k:
|
|
851
|
-
l:
|
|
852
|
-
m:
|
|
853
|
-
n:
|
|
854
|
-
o:
|
|
855
|
-
p:
|
|
856
|
-
q:
|
|
857
|
-
r:
|
|
858
|
-
s:
|
|
859
|
-
t:
|
|
860
|
-
u:
|
|
861
|
-
v:
|
|
862
|
-
w:
|
|
863
|
-
x:
|
|
864
|
-
y:
|
|
865
|
-
z:
|
|
866
|
-
|
|
805
|
+
'-': '=',
|
|
806
|
+
'0': 'A',
|
|
807
|
+
'1': 'B',
|
|
808
|
+
'2': 'C',
|
|
809
|
+
'3': 'D',
|
|
810
|
+
'4': 'E',
|
|
811
|
+
'5': 'F',
|
|
812
|
+
'6': 'G',
|
|
813
|
+
'7': 'H',
|
|
814
|
+
'8': 'I',
|
|
815
|
+
'9': 'J',
|
|
816
|
+
A: 'K',
|
|
817
|
+
B: 'L',
|
|
818
|
+
C: 'M',
|
|
819
|
+
D: 'N',
|
|
820
|
+
E: 'O',
|
|
821
|
+
F: 'P',
|
|
822
|
+
G: 'Q',
|
|
823
|
+
H: 'R',
|
|
824
|
+
I: 'S',
|
|
825
|
+
J: 'T',
|
|
826
|
+
K: 'U',
|
|
827
|
+
L: 'V',
|
|
828
|
+
M: 'W',
|
|
829
|
+
N: 'X',
|
|
830
|
+
O: 'Y',
|
|
831
|
+
P: 'Z',
|
|
832
|
+
Q: 'a',
|
|
833
|
+
R: 'b',
|
|
834
|
+
S: 'c',
|
|
835
|
+
T: 'd',
|
|
836
|
+
U: 'e',
|
|
837
|
+
V: 'f',
|
|
838
|
+
W: 'g',
|
|
839
|
+
X: 'h',
|
|
840
|
+
Y: 'i',
|
|
841
|
+
Z: 'j',
|
|
842
|
+
_: 'k',
|
|
843
|
+
a: 'l',
|
|
844
|
+
b: 'm',
|
|
845
|
+
c: 'n',
|
|
846
|
+
d: 'o',
|
|
847
|
+
e: 'p',
|
|
848
|
+
f: 'q',
|
|
849
|
+
g: 'r',
|
|
850
|
+
h: 's',
|
|
851
|
+
i: 't',
|
|
852
|
+
j: 'u',
|
|
853
|
+
k: 'v',
|
|
854
|
+
l: 'w',
|
|
855
|
+
m: 'x',
|
|
856
|
+
n: 'y',
|
|
857
|
+
o: 'z',
|
|
858
|
+
p: '0',
|
|
859
|
+
q: '1',
|
|
860
|
+
r: '2',
|
|
861
|
+
s: '3',
|
|
862
|
+
t: '4',
|
|
863
|
+
u: '5',
|
|
864
|
+
v: '6',
|
|
865
|
+
w: '7',
|
|
866
|
+
x: '8',
|
|
867
|
+
y: '9',
|
|
868
|
+
z: '+',
|
|
869
|
+
'|': '/',
|
|
867
870
|
};
|
|
868
871
|
const ENCODE_TABLE = {};
|
|
869
872
|
for (const c of Object.keys(DECODE_TABLE)) {
|
|
@@ -873,7 +876,7 @@ for (const c of Object.keys(DECODE_TABLE)) {
|
|
|
873
876
|
const arrayBufferTypeDef = {
|
|
874
877
|
ArrayBuffer: {
|
|
875
878
|
replace: (ab) => ({
|
|
876
|
-
$t:
|
|
879
|
+
$t: 'ArrayBuffer',
|
|
877
880
|
v: b64LexEncode(ab),
|
|
878
881
|
}),
|
|
879
882
|
revive: ({ v }) => {
|
|
@@ -896,9 +899,9 @@ function string2ArrayBuffer(str) {
|
|
|
896
899
|
|
|
897
900
|
const blobTypeDef = {
|
|
898
901
|
Blob: {
|
|
899
|
-
test: (blob, toStringTag) => toStringTag ===
|
|
902
|
+
test: (blob, toStringTag) => toStringTag === 'Blob' || blob instanceof FakeBlob,
|
|
900
903
|
replace: (blob) => ({
|
|
901
|
-
$t:
|
|
904
|
+
$t: 'Blob',
|
|
902
905
|
v: blob instanceof FakeBlob
|
|
903
906
|
? b64encode(blob.buf)
|
|
904
907
|
: b64encode(string2ArrayBuffer(readBlobSync(blob))),
|
|
@@ -909,7 +912,7 @@ const blobTypeDef = {
|
|
|
909
912
|
const buf = ab.buffer.byteLength === ab.byteLength
|
|
910
913
|
? ab.buffer
|
|
911
914
|
: ab.buffer.slice(ab.byteOffset, ab.byteOffset + ab.byteLength);
|
|
912
|
-
return typeof Blob !==
|
|
915
|
+
return typeof Blob !== 'undefined'
|
|
913
916
|
? new Blob([new Uint8Array(buf)], { type })
|
|
914
917
|
: new FakeBlob(buf, type);
|
|
915
918
|
},
|
|
@@ -928,15 +931,15 @@ const blobTypeDef = {
|
|
|
928
931
|
|
|
929
932
|
const fileTypeDef = {
|
|
930
933
|
File: {
|
|
931
|
-
test: (file, toStringTag) => toStringTag ===
|
|
934
|
+
test: (file, toStringTag) => toStringTag === 'File',
|
|
932
935
|
replace: (file) => ({
|
|
933
|
-
$t:
|
|
936
|
+
$t: 'File',
|
|
934
937
|
v: b64encode(string2ArrayBuffer(readBlobSync(file))),
|
|
935
938
|
type: file.type,
|
|
936
939
|
name: file.name,
|
|
937
940
|
lastModified: new Date(file.lastModified).toISOString(),
|
|
938
941
|
}),
|
|
939
|
-
revive: ({ type, v, name, lastModified }) => {
|
|
942
|
+
revive: ({ type, v, name, lastModified, }) => {
|
|
940
943
|
const ab = b64decode(v);
|
|
941
944
|
const buf = ab.buffer.byteLength === ab.byteLength
|
|
942
945
|
? ab.buffer
|
|
@@ -960,13 +963,13 @@ const fileTypeDef = {
|
|
|
960
963
|
const undefinedTypeDef = {
|
|
961
964
|
undefined: {
|
|
962
965
|
replace: () => ({
|
|
963
|
-
$t:
|
|
966
|
+
$t: 'undefined',
|
|
964
967
|
}),
|
|
965
968
|
revive: () => undefined,
|
|
966
969
|
},
|
|
967
970
|
};
|
|
968
971
|
|
|
969
|
-
const getRandomValues = typeof crypto !==
|
|
972
|
+
const getRandomValues = typeof crypto !== 'undefined'
|
|
970
973
|
? crypto.getRandomValues.bind(crypto)
|
|
971
974
|
: (buf) => {
|
|
972
975
|
for (let i = 0; i < buf.length; ++i) {
|
|
@@ -1067,7 +1070,7 @@ function setByKeyPath(obj, keyPath, value) {
|
|
|
1067
1070
|
var innerObj = obj[currentKeyPath];
|
|
1068
1071
|
//@ts-ignore: even if currentKeyPath would be numeric string and obj would be array - it works.
|
|
1069
1072
|
if (!innerObj || !hasOwn(obj, currentKeyPath))
|
|
1070
|
-
innerObj =
|
|
1073
|
+
innerObj = obj[currentKeyPath] = {};
|
|
1071
1074
|
setByKeyPath(innerObj, remainingKeyPath, value);
|
|
1072
1075
|
}
|
|
1073
1076
|
}
|
|
@@ -1086,17 +1089,23 @@ function setByKeyPath(obj, keyPath, value) {
|
|
|
1086
1089
|
}
|
|
1087
1090
|
}
|
|
1088
1091
|
}
|
|
1089
|
-
const randomString$1 = typeof self !== 'undefined' && typeof crypto !== 'undefined'
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1092
|
+
const randomString$1 = typeof self !== 'undefined' && typeof crypto !== 'undefined'
|
|
1093
|
+
? (bytes, randomFill = crypto.getRandomValues.bind(crypto)) => {
|
|
1094
|
+
// Web
|
|
1095
|
+
const buf = new Uint8Array(bytes);
|
|
1096
|
+
randomFill(buf);
|
|
1097
|
+
return self.btoa(String.fromCharCode.apply(null, buf));
|
|
1098
|
+
}
|
|
1099
|
+
: typeof Buffer !== 'undefined'
|
|
1100
|
+
? (bytes, randomFill = simpleRandomFill) => {
|
|
1101
|
+
// Node
|
|
1102
|
+
const buf = Buffer.alloc(bytes);
|
|
1103
|
+
randomFill(buf);
|
|
1104
|
+
return buf.toString('base64');
|
|
1105
|
+
}
|
|
1106
|
+
: () => {
|
|
1107
|
+
throw new Error('No implementation of randomString was found');
|
|
1108
|
+
};
|
|
1100
1109
|
function simpleRandomFill(buf) {
|
|
1101
1110
|
for (let i = 0; i < buf.length; ++i) {
|
|
1102
1111
|
buf[i] = Math.floor(Math.random() * 256);
|
|
@@ -1115,11 +1124,13 @@ function simpleRandomFill(buf) {
|
|
|
1115
1124
|
* @returns
|
|
1116
1125
|
*/
|
|
1117
1126
|
function isValidSyncableID(id) {
|
|
1118
|
-
if (typeof id ===
|
|
1127
|
+
if (typeof id === 'string')
|
|
1119
1128
|
return true;
|
|
1120
1129
|
//if (validIDTypes[toStringTag(id)]) return true;
|
|
1121
1130
|
//if (Array.isArray(id)) return id.every((part) => isValidSyncableID(part));
|
|
1122
|
-
if (Array.isArray(id) &&
|
|
1131
|
+
if (Array.isArray(id) &&
|
|
1132
|
+
id.some((key) => isValidSyncableID(key)) &&
|
|
1133
|
+
id.every(isValidSyncableIDPart))
|
|
1123
1134
|
return true;
|
|
1124
1135
|
return false;
|
|
1125
1136
|
}
|
|
@@ -1128,53 +1139,53 @@ function isValidSyncableID(id) {
|
|
|
1128
1139
|
* For example, ArrayBuffer cannot be used (gives "object ArrayBuffer") but Uint8Array can be
|
|
1129
1140
|
* used (gives comma-delimited list of included bytes).
|
|
1130
1141
|
* 2: Since we store the key as a VARCHAR server side in current version, try not promote types that stringifies to become very long server side.
|
|
1131
|
-
*/
|
|
1142
|
+
*/
|
|
1132
1143
|
function isValidSyncableIDPart(part) {
|
|
1133
|
-
return typeof part ===
|
|
1144
|
+
return (typeof part === 'string' ||
|
|
1145
|
+
typeof part === 'number' ||
|
|
1146
|
+
(Array.isArray(part) && part.every(isValidSyncableIDPart)));
|
|
1134
1147
|
}
|
|
1135
1148
|
function isValidAtID(id, idPrefix) {
|
|
1136
|
-
return !idPrefix || (typeof id ===
|
|
1149
|
+
return !idPrefix || (typeof id === 'string' && id.startsWith(idPrefix));
|
|
1137
1150
|
}
|
|
1138
1151
|
|
|
1139
1152
|
function applyOperation(target, table, op) {
|
|
1140
1153
|
const tbl = target[table] || (target[table] = {});
|
|
1141
|
-
const keys = op.keys.map(key => typeof key === 'string' ? key : JSON.stringify(key));
|
|
1154
|
+
const keys = op.keys.map((key) => typeof key === 'string' ? key : JSON.stringify(key));
|
|
1142
1155
|
switch (op.type) {
|
|
1143
|
-
case
|
|
1156
|
+
case 'insert':
|
|
1144
1157
|
// TODO: Don't treat insert and upsert the same?
|
|
1145
|
-
case
|
|
1158
|
+
case 'upsert':
|
|
1146
1159
|
keys.forEach((key, idx) => {
|
|
1147
1160
|
tbl[key] = {
|
|
1148
|
-
type:
|
|
1161
|
+
type: 'ups',
|
|
1149
1162
|
val: op.values[idx],
|
|
1150
1163
|
};
|
|
1151
1164
|
});
|
|
1152
1165
|
break;
|
|
1153
|
-
case
|
|
1154
|
-
case
|
|
1166
|
+
case 'update':
|
|
1167
|
+
case 'modify': {
|
|
1155
1168
|
keys.forEach((key, idx) => {
|
|
1156
|
-
const changeSpec = op.type ===
|
|
1157
|
-
? op.changeSpecs[idx]
|
|
1158
|
-
: op.changeSpec;
|
|
1169
|
+
const changeSpec = op.type === 'update' ? op.changeSpecs[idx] : op.changeSpec;
|
|
1159
1170
|
const entry = tbl[key];
|
|
1160
1171
|
if (!entry) {
|
|
1161
1172
|
tbl[key] = {
|
|
1162
|
-
type:
|
|
1173
|
+
type: 'upd',
|
|
1163
1174
|
mod: changeSpec,
|
|
1164
1175
|
};
|
|
1165
1176
|
}
|
|
1166
1177
|
else {
|
|
1167
1178
|
switch (entry.type) {
|
|
1168
|
-
case
|
|
1179
|
+
case 'ups':
|
|
1169
1180
|
// Adjust the existing upsert with additional updates
|
|
1170
1181
|
for (const [propPath, value] of Object.entries(changeSpec)) {
|
|
1171
1182
|
setByKeyPath(entry.val, propPath, value);
|
|
1172
1183
|
}
|
|
1173
1184
|
break;
|
|
1174
|
-
case
|
|
1185
|
+
case 'del':
|
|
1175
1186
|
// No action.
|
|
1176
1187
|
break;
|
|
1177
|
-
case
|
|
1188
|
+
case 'upd':
|
|
1178
1189
|
// Adjust existing update with additional updates
|
|
1179
1190
|
Object.assign(entry.mod, changeSpec); // May work for deep props as well - new keys is added later, right? Does the prop order persist along TSON and all? But it will not be 100% when combined with some server code (seach for "address.city": "Stockholm" comment)
|
|
1180
1191
|
break;
|
|
@@ -1183,10 +1194,10 @@ function applyOperation(target, table, op) {
|
|
|
1183
1194
|
});
|
|
1184
1195
|
break;
|
|
1185
1196
|
}
|
|
1186
|
-
case
|
|
1197
|
+
case 'delete':
|
|
1187
1198
|
keys.forEach((key) => {
|
|
1188
1199
|
tbl[key] = {
|
|
1189
|
-
type:
|
|
1200
|
+
type: 'del',
|
|
1190
1201
|
};
|
|
1191
1202
|
});
|
|
1192
1203
|
break;
|
|
@@ -1283,30 +1294,30 @@ function toDBOperationSet(inSet, txid) {
|
|
|
1283
1294
|
};
|
|
1284
1295
|
for (const [optype, muts] of Object.entries(ops)) {
|
|
1285
1296
|
switch (optype) {
|
|
1286
|
-
case
|
|
1297
|
+
case 'ups': {
|
|
1287
1298
|
const op = {
|
|
1288
|
-
type:
|
|
1289
|
-
keys: muts.map(mut => mut.key),
|
|
1290
|
-
values: muts.map(mut => mut.val),
|
|
1291
|
-
txid
|
|
1299
|
+
type: 'upsert',
|
|
1300
|
+
keys: muts.map((mut) => mut.key),
|
|
1301
|
+
values: muts.map((mut) => mut.val),
|
|
1302
|
+
txid,
|
|
1292
1303
|
};
|
|
1293
1304
|
resultEntry.muts.push(op);
|
|
1294
1305
|
break;
|
|
1295
1306
|
}
|
|
1296
|
-
case
|
|
1307
|
+
case 'upd': {
|
|
1297
1308
|
const op = {
|
|
1298
|
-
type:
|
|
1299
|
-
keys: muts.map(mut => mut.key),
|
|
1300
|
-
changeSpecs: muts.map(mut => mut.mod),
|
|
1301
|
-
txid
|
|
1309
|
+
type: 'update',
|
|
1310
|
+
keys: muts.map((mut) => mut.key),
|
|
1311
|
+
changeSpecs: muts.map((mut) => mut.mod),
|
|
1312
|
+
txid,
|
|
1302
1313
|
};
|
|
1303
1314
|
resultEntry.muts.push(op);
|
|
1304
1315
|
break;
|
|
1305
1316
|
}
|
|
1306
|
-
case
|
|
1317
|
+
case 'del': {
|
|
1307
1318
|
const op = {
|
|
1308
|
-
type:
|
|
1309
|
-
keys: muts.map(mut => mut.key),
|
|
1319
|
+
type: 'delete',
|
|
1320
|
+
keys: muts.map((mut) => mut.key),
|
|
1310
1321
|
txid,
|
|
1311
1322
|
};
|
|
1312
1323
|
resultEntry.muts.push(op);
|
|
@@ -1321,7 +1332,7 @@ function toDBOperationSet(inSet, txid) {
|
|
|
1321
1332
|
|
|
1322
1333
|
function getDbNameFromDbUrl(dbUrl) {
|
|
1323
1334
|
const url = new URL(dbUrl);
|
|
1324
|
-
return url.pathname ===
|
|
1335
|
+
return url.pathname === '/'
|
|
1325
1336
|
? url.hostname.split('.')[0]
|
|
1326
1337
|
: url.pathname.split('/')[1];
|
|
1327
1338
|
}
|
|
@@ -1439,7 +1450,8 @@ function decodeYMessage(a) {
|
|
|
1439
1450
|
prop,
|
|
1440
1451
|
k,
|
|
1441
1452
|
u: readVarUint8Array(decoder),
|
|
1442
|
-
r: (decoder.pos < decoder.arr.length && readVarString(decoder)) ||
|
|
1453
|
+
r: (decoder.pos < decoder.arr.length && readVarString(decoder)) ||
|
|
1454
|
+
undefined,
|
|
1443
1455
|
};
|
|
1444
1456
|
default:
|
|
1445
1457
|
throw new TypeError(`Unknown message type: ${type}`);
|
|
@@ -1456,7 +1468,8 @@ async function asyncIterablePipeline(source, ...stages) {
|
|
|
1456
1468
|
}
|
|
1457
1469
|
// Start running the machine. If the last stage is a sink, it will consume the data and never emit anything
|
|
1458
1470
|
// to us here...
|
|
1459
|
-
for await (const chunk of result) {
|
|
1471
|
+
for await (const chunk of result) {
|
|
1472
|
+
}
|
|
1460
1473
|
}
|
|
1461
1474
|
|
|
1462
1475
|
async function* consumeChunkedBinaryStream(source) {
|
|
@@ -1510,7 +1523,7 @@ async function* consumeChunkedBinaryStream(source) {
|
|
|
1510
1523
|
}
|
|
1511
1524
|
if (pos + len > chunk.byteLength) {
|
|
1512
1525
|
bufs.push(chunk.slice(pos));
|
|
1513
|
-
len -=
|
|
1526
|
+
len -= chunk.byteLength - pos;
|
|
1514
1527
|
state = 2;
|
|
1515
1528
|
pos = chunk.byteLength; // will break while loop.
|
|
1516
1529
|
}
|
|
@@ -1541,7 +1554,7 @@ async function* consumeChunkedBinaryStream(source) {
|
|
|
1541
1554
|
function getFetchResponseBodyGenerator(res) {
|
|
1542
1555
|
return async function* () {
|
|
1543
1556
|
if (!res.body)
|
|
1544
|
-
throw new Error(
|
|
1557
|
+
throw new Error('Response body is not readable');
|
|
1545
1558
|
const reader = res.body.getReader();
|
|
1546
1559
|
try {
|
|
1547
1560
|
while (true) {
|
|
@@ -1649,7 +1662,7 @@ function removeRedundantUpdateOps(muts) {
|
|
|
1649
1662
|
}
|
|
1650
1663
|
const strKey = '' + mut.keys[0];
|
|
1651
1664
|
const changeSpecs = mut.changeSpecs[0];
|
|
1652
|
-
if (Object.values(changeSpecs).some(v => typeof v ===
|
|
1665
|
+
if (Object.values(changeSpecs).some((v) => typeof v === 'object' && v && '@@propmod' in v)) {
|
|
1653
1666
|
continue; // Cannot optimize if any PropModification is present
|
|
1654
1667
|
}
|
|
1655
1668
|
let keyCoverage = updateCoverage.get(strKey);
|
|
@@ -1657,11 +1670,13 @@ function removeRedundantUpdateOps(muts) {
|
|
|
1657
1670
|
keyCoverage.push({ txid: mut.txid, updateSpec: changeSpecs });
|
|
1658
1671
|
}
|
|
1659
1672
|
else {
|
|
1660
|
-
updateCoverage.set(strKey, [
|
|
1673
|
+
updateCoverage.set(strKey, [
|
|
1674
|
+
{ txid: mut.txid, updateSpec: changeSpecs },
|
|
1675
|
+
]);
|
|
1661
1676
|
}
|
|
1662
1677
|
}
|
|
1663
1678
|
}
|
|
1664
|
-
muts = muts.filter(mut => {
|
|
1679
|
+
muts = muts.filter((mut) => {
|
|
1665
1680
|
// Only apply optimization to update mutations that are single-key
|
|
1666
1681
|
if (mut.type !== 'update')
|
|
1667
1682
|
return true;
|
|
@@ -1669,7 +1684,7 @@ function removeRedundantUpdateOps(muts) {
|
|
|
1669
1684
|
return true;
|
|
1670
1685
|
// Check if this has PropModifications - if so, skip optimization
|
|
1671
1686
|
const changeSpecs = mut.changeSpecs[0];
|
|
1672
|
-
if (Object.values(changeSpecs).some(v => typeof v ===
|
|
1687
|
+
if (Object.values(changeSpecs).some((v) => typeof v === 'object' && v && '@@propmod' in v)) {
|
|
1673
1688
|
return true; // Cannot optimize if any PropModification is present
|
|
1674
1689
|
}
|
|
1675
1690
|
// Keep track of properties that aren't overlapped by later transactions
|
|
@@ -1697,7 +1712,7 @@ function removeRedundantUpdateOps(muts) {
|
|
|
1697
1712
|
return muts;
|
|
1698
1713
|
}
|
|
1699
1714
|
function canonicalizeToUpdateOps(muts) {
|
|
1700
|
-
muts = muts.map(mut => {
|
|
1715
|
+
muts = muts.map((mut) => {
|
|
1701
1716
|
if (mut.type === 'modify' && mut.criteria.index === null) {
|
|
1702
1717
|
// The criteria is on primary key. Convert to an update operation instead.
|
|
1703
1718
|
// It is simpler for the server to handle and also more efficient.
|
|
@@ -1863,14 +1878,15 @@ function promptForEmail(userInteraction, title, emailHint, initialAlert) {
|
|
|
1863
1878
|
// the domain extension like .com, .net, etc.
|
|
1864
1879
|
// (\sas\s[\w-+.]+@([\w-]+\.)+[\w-]{2,10})?$ : This part is optional (due to the ? at the end).
|
|
1865
1880
|
// If present, it matches " as " followed by another valid email address. This allows for the
|
|
1866
|
-
// input to be either a single email address or two email addresses separated by " as ".
|
|
1881
|
+
// input to be either a single email address or two email addresses separated by " as ".
|
|
1867
1882
|
//
|
|
1868
1883
|
// The use case for "<email1> as <email2>"" is for when a database owner with full access to the
|
|
1869
1884
|
// database needs to impersonate another user in the database in order to troubleshoot. This
|
|
1870
1885
|
// format will only be possible to use when email1 is the owner of an API client with GLOBAL_READ
|
|
1871
1886
|
// and GLOBAL_WRITE permissions on the database. The email will be checked on the server before
|
|
1872
1887
|
// allowing it and giving out a token for email2, using the OTP sent to email1.
|
|
1873
|
-
while (!email ||
|
|
1888
|
+
while (!email ||
|
|
1889
|
+
!/^[\w-+.]+@([\w-]+\.)+[\w-]{2,10}(\sas\s[\w-+.]+@([\w-]+\.)+[\w-]{2,10})?$/.test(email)) {
|
|
1874
1890
|
const alerts = [];
|
|
1875
1891
|
if (firstPrompt && initialAlert)
|
|
1876
1892
|
alerts.push(initialAlert);
|
|
@@ -1936,7 +1952,7 @@ function confirmLogout(userInteraction, currentUserId, numUnsyncedChanges) {
|
|
|
1936
1952
|
messageParams: {
|
|
1937
1953
|
currentUserId,
|
|
1938
1954
|
numUnsyncedChanges: numUnsyncedChanges.toString(),
|
|
1939
|
-
}
|
|
1955
|
+
},
|
|
1940
1956
|
},
|
|
1941
1957
|
];
|
|
1942
1958
|
return yield interactWithUser(userInteraction, {
|
|
@@ -1945,7 +1961,7 @@ function confirmLogout(userInteraction, currentUserId, numUnsyncedChanges) {
|
|
|
1945
1961
|
alerts,
|
|
1946
1962
|
fields: {},
|
|
1947
1963
|
submitLabel: 'Confirm logout',
|
|
1948
|
-
cancelLabel: 'Cancel'
|
|
1964
|
+
cancelLabel: 'Cancel',
|
|
1949
1965
|
})
|
|
1950
1966
|
.then(() => true)
|
|
1951
1967
|
.catch(() => false);
|
|
@@ -2062,7 +2078,8 @@ function loadAccessToken(db) {
|
|
|
2062
2078
|
if (!accessToken)
|
|
2063
2079
|
return null;
|
|
2064
2080
|
const expTime = (_a = accessTokenExpiration === null || accessTokenExpiration === void 0 ? void 0 : accessTokenExpiration.getTime()) !== null && _a !== void 0 ? _a : Infinity;
|
|
2065
|
-
if (expTime >
|
|
2081
|
+
if (expTime > Date.now() + 5 * MINUTES &&
|
|
2082
|
+
(((_b = currentUser.license) === null || _b === void 0 ? void 0 : _b.status) || 'ok') === 'ok') {
|
|
2066
2083
|
return currentUser;
|
|
2067
2084
|
}
|
|
2068
2085
|
if (!refreshToken) {
|
|
@@ -2222,11 +2239,13 @@ function userAuthenticate(context, fetchToken, userInteraction, hints) {
|
|
|
2222
2239
|
}
|
|
2223
2240
|
catch (error) {
|
|
2224
2241
|
// OAuth redirect is not an error - page is navigating away
|
|
2225
|
-
if (error instanceof OAuthRedirectError ||
|
|
2242
|
+
if (error instanceof OAuthRedirectError ||
|
|
2243
|
+
(error === null || error === void 0 ? void 0 : error.name) === 'OAuthRedirectError') {
|
|
2226
2244
|
throw error; // Re-throw without logging
|
|
2227
2245
|
}
|
|
2228
2246
|
// Policy rejections have already been shown to the user as a challenge
|
|
2229
|
-
if (error instanceof PolicyRejectionError ||
|
|
2247
|
+
if (error instanceof PolicyRejectionError ||
|
|
2248
|
+
(error === null || error === void 0 ? void 0 : error.name) === 'PolicyRejectionError') {
|
|
2230
2249
|
throw error;
|
|
2231
2250
|
}
|
|
2232
2251
|
if (error instanceof TokenErrorResponseError) {
|
|
@@ -2245,7 +2264,10 @@ function userAuthenticate(context, fetchToken, userInteraction, hints) {
|
|
|
2245
2264
|
if (isOffline) {
|
|
2246
2265
|
message = `You seem to be offline. Please connect to the internet and try again.`;
|
|
2247
2266
|
}
|
|
2248
|
-
else if (typeof location !== 'undefined' &&
|
|
2267
|
+
else if (typeof location !== 'undefined' &&
|
|
2268
|
+
(Dexie.debug ||
|
|
2269
|
+
location.hostname === 'localhost' ||
|
|
2270
|
+
location.hostname === '127.0.0.1')) {
|
|
2249
2271
|
// The audience is most likely the developer. Suggest to whitelist the localhost origin:
|
|
2250
2272
|
const whitelistCommand = `npx dexie-cloud whitelist ${location.origin}`;
|
|
2251
2273
|
message = `Could not connect to server. Please verify that your origin '${location.origin}' is whitelisted using \`npx dexie-cloud whitelist\``;
|
|
@@ -2348,7 +2370,7 @@ class HttpError extends Error {
|
|
|
2348
2370
|
this.httpStatus = res.status;
|
|
2349
2371
|
}
|
|
2350
2372
|
get name() {
|
|
2351
|
-
return
|
|
2373
|
+
return 'HttpError';
|
|
2352
2374
|
}
|
|
2353
2375
|
}
|
|
2354
2376
|
|
|
@@ -2425,7 +2447,7 @@ function checkSyncRateLimitDelay(db) {
|
|
|
2425
2447
|
const delatMilliseconds = ((_b = (_a = syncRatelimitDelays.get(db)) === null || _a === void 0 ? void 0 : _a.getTime()) !== null && _b !== void 0 ? _b : 0) - Date.now();
|
|
2426
2448
|
if (delatMilliseconds > 0) {
|
|
2427
2449
|
console.debug(`Stalling sync request ${delatMilliseconds} ms to spare ratelimits`);
|
|
2428
|
-
yield new Promise(resolve => setTimeout(resolve, delatMilliseconds));
|
|
2450
|
+
yield new Promise((resolve) => setTimeout(resolve, delatMilliseconds));
|
|
2429
2451
|
}
|
|
2430
2452
|
});
|
|
2431
2453
|
}
|
|
@@ -2490,7 +2512,7 @@ function syncWithServer(changes, y, syncState, baseRevs, db, databaseUrl, schema
|
|
|
2490
2512
|
baseRevs,
|
|
2491
2513
|
changes: encodeIdsForServer(db.dx.core.schema, currentUser, changes),
|
|
2492
2514
|
y,
|
|
2493
|
-
dxcv: db.cloud.version
|
|
2515
|
+
dxcv: db.cloud.version,
|
|
2494
2516
|
};
|
|
2495
2517
|
console.debug('Sync request', syncRequest);
|
|
2496
2518
|
db.syncStateChangedEvent.next({
|
|
@@ -2530,19 +2552,22 @@ function modifyLocalObjectsWithNewUserId(syncifiedTables, currentUser, alreadySy
|
|
|
2530
2552
|
return __awaiter(this, void 0, void 0, function* () {
|
|
2531
2553
|
const ignoredRealms = new Set(alreadySyncedRealms || []);
|
|
2532
2554
|
for (const table of syncifiedTables) {
|
|
2533
|
-
if (table.name ===
|
|
2555
|
+
if (table.name === 'members') {
|
|
2534
2556
|
// members
|
|
2535
2557
|
yield table.toCollection().modify((member) => {
|
|
2536
|
-
if (!ignoredRealms.has(member.realmId) &&
|
|
2558
|
+
if (!ignoredRealms.has(member.realmId) &&
|
|
2559
|
+
(!member.userId || member.userId === UNAUTHORIZED_USER.userId)) {
|
|
2537
2560
|
member.userId = currentUser.userId;
|
|
2538
2561
|
}
|
|
2539
2562
|
});
|
|
2540
2563
|
}
|
|
2541
|
-
else if (table.name ===
|
|
2542
|
-
else if (table.name ===
|
|
2564
|
+
else if (table.name === 'roles') ;
|
|
2565
|
+
else if (table.name === 'realms') {
|
|
2543
2566
|
// realms
|
|
2544
2567
|
yield table.toCollection().modify((realm) => {
|
|
2545
|
-
if (!ignoredRealms.has(realm.realmId) &&
|
|
2568
|
+
if (!ignoredRealms.has(realm.realmId) &&
|
|
2569
|
+
(realm.owner === undefined ||
|
|
2570
|
+
realm.owner === UNAUTHORIZED_USER.userId)) {
|
|
2546
2571
|
realm.owner = currentUser.userId;
|
|
2547
2572
|
}
|
|
2548
2573
|
});
|
|
@@ -2575,8 +2600,8 @@ function throwIfCancelled(cancelToken) {
|
|
|
2575
2600
|
let isOnline = false;
|
|
2576
2601
|
if (typeof self !== 'undefined' && typeof navigator !== 'undefined') {
|
|
2577
2602
|
isOnline = navigator.onLine;
|
|
2578
|
-
self.addEventListener('online', () => isOnline = true);
|
|
2579
|
-
self.addEventListener('offline', () => isOnline = false);
|
|
2603
|
+
self.addEventListener('online', () => (isOnline = true));
|
|
2604
|
+
self.addEventListener('offline', () => (isOnline = false));
|
|
2580
2605
|
}
|
|
2581
2606
|
|
|
2582
2607
|
function updateBaseRevs(db, schema, latestRevisions, serverRev) {
|
|
@@ -2593,7 +2618,10 @@ function updateBaseRevs(db, schema, latestRevisions, serverRev) {
|
|
|
2593
2618
|
}));
|
|
2594
2619
|
// Clean up baseRevs for tables that do not exist anymore or are no longer marked for sync
|
|
2595
2620
|
// Resolve #2168 by also cleaning up baseRevs for tables that are not marked for sync
|
|
2596
|
-
yield db.$baseRevs
|
|
2621
|
+
yield db.$baseRevs
|
|
2622
|
+
.where('tableName')
|
|
2623
|
+
.noneOf(Object.keys(schema).filter((table) => schema[table].markedForSync))
|
|
2624
|
+
.delete();
|
|
2597
2625
|
});
|
|
2598
2626
|
}
|
|
2599
2627
|
|
|
@@ -2686,11 +2714,11 @@ function hasBlobRefs(obj, visited = new WeakSet()) {
|
|
|
2686
2714
|
return false;
|
|
2687
2715
|
}
|
|
2688
2716
|
if (Array.isArray(obj)) {
|
|
2689
|
-
return obj.some(item => hasBlobRefs(item, visited));
|
|
2717
|
+
return obj.some((item) => hasBlobRefs(item, visited));
|
|
2690
2718
|
}
|
|
2691
2719
|
// Only traverse POJOs
|
|
2692
2720
|
if (obj.constructor === Object) {
|
|
2693
|
-
return Object.values(obj).some(value => hasBlobRefs(value, visited));
|
|
2721
|
+
return Object.values(obj).some((value) => hasBlobRefs(value, visited));
|
|
2694
2722
|
}
|
|
2695
2723
|
return false;
|
|
2696
2724
|
}
|
|
@@ -2754,7 +2782,8 @@ function convertToOriginalType(data, ref) {
|
|
|
2754
2782
|
*/
|
|
2755
2783
|
function resolveAllBlobRefs(obj_1, dbUrl_1) {
|
|
2756
2784
|
return __awaiter(this, arguments, void 0, function* (obj, dbUrl, resolvedBlobs = [], currentPath = '', visited = new WeakMap(), tracker) {
|
|
2757
|
-
if (obj == null) {
|
|
2785
|
+
if (obj == null) {
|
|
2786
|
+
// null or undefined
|
|
2758
2787
|
return obj;
|
|
2759
2788
|
}
|
|
2760
2789
|
// Check if this is a BlobRef - resolve it and track it
|
|
@@ -2803,9 +2832,7 @@ function resolveAllBlobRefs(obj_1, dbUrl_1) {
|
|
|
2803
2832
|
* Check if an object has unresolved BlobRefs
|
|
2804
2833
|
*/
|
|
2805
2834
|
function hasUnresolvedBlobRefs(obj) {
|
|
2806
|
-
return (typeof obj === 'object' &&
|
|
2807
|
-
obj !== null &&
|
|
2808
|
-
obj._hasBlobRefs === 1);
|
|
2835
|
+
return (typeof obj === 'object' && obj !== null && obj._hasBlobRefs === 1);
|
|
2809
2836
|
}
|
|
2810
2837
|
|
|
2811
2838
|
/**
|
|
@@ -2890,6 +2917,16 @@ function applyServerChanges(changes, db) {
|
|
|
2890
2917
|
}
|
|
2891
2918
|
break;
|
|
2892
2919
|
case 'update':
|
|
2920
|
+
if (!primaryKey.outbound && primaryKey.keyPath) {
|
|
2921
|
+
// The primary key should never be part of an updateSpec — it cannot change
|
|
2922
|
+
// and is already communicated via the operation's keys array.
|
|
2923
|
+
// For private singleton IDs (e.g. "#key:userId" on server, "#key" on client),
|
|
2924
|
+
// the encoded server-side key may leak into the changeSpec via getObjectDiff().
|
|
2925
|
+
// Strip it here unconditionally as a defensive measure.
|
|
2926
|
+
for (const changeSpec of mut.changeSpecs) {
|
|
2927
|
+
Dexie.delByKeyPath(changeSpec, primaryKey.keyPath);
|
|
2928
|
+
}
|
|
2929
|
+
}
|
|
2893
2930
|
yield bulkUpdate(table, keys, mut.changeSpecs);
|
|
2894
2931
|
break;
|
|
2895
2932
|
case 'delete':
|
|
@@ -2904,10 +2941,7 @@ function applyServerChanges(changes, db) {
|
|
|
2904
2941
|
const DEXIE_CLOUD_SYNCER_ID = 'dexie-cloud-syncer';
|
|
2905
2942
|
|
|
2906
2943
|
function listUpdatesSince(yTable, sinceIncluding) {
|
|
2907
|
-
return yTable
|
|
2908
|
-
.where('i')
|
|
2909
|
-
.between(sinceIncluding, Infinity, true)
|
|
2910
|
-
.toArray();
|
|
2944
|
+
return yTable.where('i').between(sinceIncluding, Infinity, true).toArray();
|
|
2911
2945
|
}
|
|
2912
2946
|
|
|
2913
2947
|
/** Queries the local database for YMessages to send to server.
|
|
@@ -3002,7 +3036,7 @@ function listYClientMessagesAndStateVector(db, tablesToSync) {
|
|
|
3002
3036
|
}
|
|
3003
3037
|
return {
|
|
3004
3038
|
yMessages: result,
|
|
3005
|
-
lastUpdateIds
|
|
3039
|
+
lastUpdateIds,
|
|
3006
3040
|
};
|
|
3007
3041
|
});
|
|
3008
3042
|
}
|
|
@@ -3011,7 +3045,8 @@ function getUpdatesTable(db, table, ydocProp) {
|
|
|
3011
3045
|
var _a, _b, _c;
|
|
3012
3046
|
if (!db.dx._allTables[table])
|
|
3013
3047
|
return undefined;
|
|
3014
|
-
const utbl = (_c = (_b = (_a = db
|
|
3048
|
+
const utbl = (_c = (_b = (_a = db
|
|
3049
|
+
.table(table)) === null || _a === void 0 ? void 0 : _a.schema.yProps) === null || _b === void 0 ? void 0 : _b.find((p) => p.prop === ydocProp)) === null || _c === void 0 ? void 0 : _c.updatesTable;
|
|
3015
3050
|
if (!utbl) {
|
|
3016
3051
|
console.debug(`No updatesTable found for ${table}.${ydocProp}`);
|
|
3017
3052
|
return undefined;
|
|
@@ -3144,10 +3179,18 @@ const blobEndpointSupported = new Map();
|
|
|
3144
3179
|
*/
|
|
3145
3180
|
// TypedArray/DataView tags for size check
|
|
3146
3181
|
const ARRAYBUFFER_VIEW_TAGS = new Set([
|
|
3147
|
-
'Int8Array',
|
|
3148
|
-
'
|
|
3149
|
-
'
|
|
3150
|
-
'
|
|
3182
|
+
'Int8Array',
|
|
3183
|
+
'Uint8Array',
|
|
3184
|
+
'Uint8ClampedArray',
|
|
3185
|
+
'Int16Array',
|
|
3186
|
+
'Uint16Array',
|
|
3187
|
+
'Int32Array',
|
|
3188
|
+
'Uint32Array',
|
|
3189
|
+
'Float32Array',
|
|
3190
|
+
'Float64Array',
|
|
3191
|
+
'BigInt64Array',
|
|
3192
|
+
'BigUint64Array',
|
|
3193
|
+
'DataView',
|
|
3151
3194
|
]);
|
|
3152
3195
|
// Static Set for O(1) lookup of binary type tags
|
|
3153
3196
|
const BINARY_TYPE_TAGS = new Set([
|
|
@@ -3247,7 +3290,7 @@ function uploadBlob(databaseUrl, getCachedAccessToken, blob) {
|
|
|
3247
3290
|
const response = yield fetch(uploadUrl, {
|
|
3248
3291
|
method: 'PUT',
|
|
3249
3292
|
headers: {
|
|
3250
|
-
|
|
3293
|
+
Authorization: `Bearer ${accessToken}`,
|
|
3251
3294
|
'Content-Type': contentType,
|
|
3252
3295
|
},
|
|
3253
3296
|
body,
|
|
@@ -3263,8 +3306,7 @@ function uploadBlob(databaseUrl, getCachedAccessToken, blob) {
|
|
|
3263
3306
|
// The server returns the ref with version prefix (e.g., "1:blobId")
|
|
3264
3307
|
const result = yield response.json();
|
|
3265
3308
|
// Return BlobRef with server's ref (includes version) and original type preserved in _bt
|
|
3266
|
-
return Object.assign({ _bt: origType, ref: result.ref, size: size }, (origType === 'Blob' ? { ct: contentType } : {})
|
|
3267
|
-
);
|
|
3309
|
+
return Object.assign({ _bt: origType, ref: result.ref, size: size }, (origType === 'Blob' ? { ct: contentType } : {}));
|
|
3268
3310
|
});
|
|
3269
3311
|
}
|
|
3270
3312
|
function offloadBlobsAndMarkDirty(obj_1, databaseUrl_1, getCachedAccessToken_1) {
|
|
@@ -3272,7 +3314,10 @@ function offloadBlobsAndMarkDirty(obj_1, databaseUrl_1, getCachedAccessToken_1)
|
|
|
3272
3314
|
const dirtyFlag = { dirty: false };
|
|
3273
3315
|
const result = yield offloadBlobs(obj, databaseUrl, getCachedAccessToken, maxStringLength, dirtyFlag);
|
|
3274
3316
|
// Mark the object as dirty for sync if any blobs were offloaded
|
|
3275
|
-
if (dirtyFlag.dirty &&
|
|
3317
|
+
if (dirtyFlag.dirty &&
|
|
3318
|
+
typeof result === 'object' &&
|
|
3319
|
+
result !== null &&
|
|
3320
|
+
result.constructor === Object) {
|
|
3276
3321
|
result._hasBlobRefs = 1;
|
|
3277
3322
|
}
|
|
3278
3323
|
return result;
|
|
@@ -3288,7 +3333,9 @@ function offloadBlobs(obj_1, databaseUrl_1, getCachedAccessToken_1) {
|
|
|
3288
3333
|
return obj;
|
|
3289
3334
|
}
|
|
3290
3335
|
// Check if this is a long string that should be offloaded
|
|
3291
|
-
if (typeof obj === 'string' &&
|
|
3336
|
+
if (typeof obj === 'string' &&
|
|
3337
|
+
obj.length > maxStringLength &&
|
|
3338
|
+
maxStringLength !== Infinity) {
|
|
3292
3339
|
if (blobEndpointSupported.get(databaseUrl) === false) {
|
|
3293
3340
|
return obj;
|
|
3294
3341
|
}
|
|
@@ -3374,11 +3421,11 @@ function offloadBlobsInOperation(op_1, databaseUrl_1, getCachedAccessToken_1) {
|
|
|
3374
3421
|
switch (op.type) {
|
|
3375
3422
|
case 'insert':
|
|
3376
3423
|
case 'upsert': {
|
|
3377
|
-
const processedValues = yield Promise.all(op.values.map(value => offloadBlobsAndMarkDirty(value, databaseUrl, getCachedAccessToken, maxStringLength)));
|
|
3424
|
+
const processedValues = yield Promise.all(op.values.map((value) => offloadBlobsAndMarkDirty(value, databaseUrl, getCachedAccessToken, maxStringLength)));
|
|
3378
3425
|
return Object.assign(Object.assign({}, op), { values: processedValues });
|
|
3379
3426
|
}
|
|
3380
3427
|
case 'update': {
|
|
3381
|
-
const processedChangeSpecs = yield Promise.all(op.changeSpecs.map(spec => offloadBlobsAndMarkDirty(spec, databaseUrl, getCachedAccessToken, maxStringLength)));
|
|
3428
|
+
const processedChangeSpecs = yield Promise.all(op.changeSpecs.map((spec) => offloadBlobsAndMarkDirty(spec, databaseUrl, getCachedAccessToken, maxStringLength)));
|
|
3382
3429
|
return Object.assign(Object.assign({}, op), { changeSpecs: processedChangeSpecs });
|
|
3383
3430
|
}
|
|
3384
3431
|
case 'modify': {
|
|
@@ -3411,9 +3458,9 @@ function hasLargeBlobsInOperation(op, maxStringLength) {
|
|
|
3411
3458
|
switch (op.type) {
|
|
3412
3459
|
case 'insert':
|
|
3413
3460
|
case 'upsert':
|
|
3414
|
-
return op.values.some(value => hasLargeBlobs(value, maxStringLength));
|
|
3461
|
+
return op.values.some((value) => hasLargeBlobs(value, maxStringLength));
|
|
3415
3462
|
case 'update':
|
|
3416
|
-
return op.changeSpecs.some(spec => hasLargeBlobs(spec, maxStringLength));
|
|
3463
|
+
return op.changeSpecs.some((spec) => hasLargeBlobs(spec, maxStringLength));
|
|
3417
3464
|
case 'modify':
|
|
3418
3465
|
return hasLargeBlobs(op.changeSpec, maxStringLength);
|
|
3419
3466
|
default:
|
|
@@ -3425,7 +3472,9 @@ function hasLargeBlobs(obj, maxStringLength, visited = new WeakSet()) {
|
|
|
3425
3472
|
return false;
|
|
3426
3473
|
}
|
|
3427
3474
|
// Check long strings
|
|
3428
|
-
if (typeof obj === 'string' &&
|
|
3475
|
+
if (typeof obj === 'string' &&
|
|
3476
|
+
obj.length > maxStringLength &&
|
|
3477
|
+
maxStringLength !== Infinity) {
|
|
3429
3478
|
return true;
|
|
3430
3479
|
}
|
|
3431
3480
|
if (shouldOffloadBlob(obj)) {
|
|
@@ -3440,13 +3489,13 @@ function hasLargeBlobs(obj, maxStringLength, visited = new WeakSet()) {
|
|
|
3440
3489
|
}
|
|
3441
3490
|
visited.add(obj);
|
|
3442
3491
|
if (Array.isArray(obj)) {
|
|
3443
|
-
return obj.some(item => hasLargeBlobs(item, maxStringLength, visited));
|
|
3492
|
+
return obj.some((item) => hasLargeBlobs(item, maxStringLength, visited));
|
|
3444
3493
|
}
|
|
3445
3494
|
// Traverse plain objects (POJO-like) - use duck typing since IndexedDB
|
|
3446
3495
|
// may return objects where constructor !== Object
|
|
3447
3496
|
const proto = Object.getPrototypeOf(obj);
|
|
3448
3497
|
if (proto === Object.prototype || proto === null) {
|
|
3449
|
-
return Object.values(obj).some(value => hasLargeBlobs(value, maxStringLength, visited));
|
|
3498
|
+
return Object.values(obj).some((value) => hasLargeBlobs(value, maxStringLength, visited));
|
|
3450
3499
|
}
|
|
3451
3500
|
return false;
|
|
3452
3501
|
}
|
|
@@ -3500,7 +3549,7 @@ function updateYSyncStates(lastUpdateIdsBeforeSync, receivedUntilsAfterSync, db)
|
|
|
3500
3549
|
yield db.table(yTable).add({
|
|
3501
3550
|
i: DEXIE_CLOUD_SYNCER_ID,
|
|
3502
3551
|
unsentFrom,
|
|
3503
|
-
receivedUntil
|
|
3552
|
+
receivedUntil,
|
|
3504
3553
|
});
|
|
3505
3554
|
}
|
|
3506
3555
|
else {
|
|
@@ -3640,19 +3689,22 @@ function loadCachedAccessToken(db) {
|
|
|
3640
3689
|
return Promise.resolve(cached.accessToken);
|
|
3641
3690
|
}
|
|
3642
3691
|
const currentUser = db.cloud.currentUser.value;
|
|
3643
|
-
if (currentUser &&
|
|
3692
|
+
if (currentUser &&
|
|
3693
|
+
currentUser.accessToken &&
|
|
3694
|
+
((_b = (_a = currentUser.accessTokenExpiration) === null || _a === void 0 ? void 0 : _a.getTime()) !== null && _b !== void 0 ? _b : Infinity) >
|
|
3695
|
+
Date.now() + 5 * MINUTES) {
|
|
3644
3696
|
wm$3.set(db, {
|
|
3645
3697
|
accessToken: currentUser.accessToken,
|
|
3646
|
-
expiration: (_d = (_c = currentUser.accessTokenExpiration) === null || _c === void 0 ? void 0 : _c.getTime()) !== null && _d !== void 0 ? _d : Infinity
|
|
3698
|
+
expiration: (_d = (_c = currentUser.accessTokenExpiration) === null || _c === void 0 ? void 0 : _c.getTime()) !== null && _d !== void 0 ? _d : Infinity,
|
|
3647
3699
|
});
|
|
3648
3700
|
return Promise.resolve(currentUser.accessToken);
|
|
3649
3701
|
}
|
|
3650
|
-
return Dexie.ignoreTransaction(() => loadAccessToken(db).then(user => {
|
|
3702
|
+
return Dexie.ignoreTransaction(() => loadAccessToken(db).then((user) => {
|
|
3651
3703
|
var _a, _b;
|
|
3652
3704
|
if (user === null || user === void 0 ? void 0 : user.accessToken) {
|
|
3653
3705
|
wm$3.set(db, {
|
|
3654
3706
|
accessToken: user.accessToken,
|
|
3655
|
-
expiration: (_b = (_a = user.accessTokenExpiration) === null || _a === void 0 ? void 0 : _a.getTime()) !== null && _b !== void 0 ? _b : Infinity
|
|
3707
|
+
expiration: (_b = (_a = user.accessTokenExpiration) === null || _a === void 0 ? void 0 : _a.getTime()) !== null && _b !== void 0 ? _b : Infinity,
|
|
3656
3708
|
});
|
|
3657
3709
|
}
|
|
3658
3710
|
return (user === null || user === void 0 ? void 0 : user.accessToken) || null;
|
|
@@ -3663,7 +3715,8 @@ const CURRENT_SYNC_WORKER = 'currentSyncWorker';
|
|
|
3663
3715
|
function sync(db, options, schema, syncOptions) {
|
|
3664
3716
|
return _sync(db, options, schema, syncOptions)
|
|
3665
3717
|
.then((result) => {
|
|
3666
|
-
if (!(syncOptions === null || syncOptions === void 0 ? void 0 : syncOptions.justCheckIfNeeded)) {
|
|
3718
|
+
if (!(syncOptions === null || syncOptions === void 0 ? void 0 : syncOptions.justCheckIfNeeded)) {
|
|
3719
|
+
// && syncOptions?.purpose !== 'push') {
|
|
3667
3720
|
db.syncStateChangedEvent.next({
|
|
3668
3721
|
phase: 'in-sync',
|
|
3669
3722
|
});
|
|
@@ -3750,7 +3803,7 @@ function _sync(db_1, options_1, schema_1) {
|
|
|
3750
3803
|
const syncState = yield db.getPersistedSyncState();
|
|
3751
3804
|
let baseRevs = yield db.$baseRevs.toArray();
|
|
3752
3805
|
// Resolve #2168
|
|
3753
|
-
baseRevs = baseRevs.filter(br => tablesToSync.some(tbl => tbl.name === br.tableName));
|
|
3806
|
+
baseRevs = baseRevs.filter((br) => tablesToSync.some((tbl) => tbl.name === br.tableName));
|
|
3754
3807
|
let clientChanges = yield listClientChanges(mutationTables, db);
|
|
3755
3808
|
const yResults = yield listYClientMessagesAndStateVector(db, tablesToSync);
|
|
3756
3809
|
throwIfCancelled(cancelToken);
|
|
@@ -3766,7 +3819,7 @@ function _sync(db_1, options_1, schema_1) {
|
|
|
3766
3819
|
}
|
|
3767
3820
|
return [clientChanges, syncState, baseRevs, yResults];
|
|
3768
3821
|
}));
|
|
3769
|
-
const pushSyncIsNeeded = clientChangeSet.some((set) => set.muts.some((mut) => mut.keys.length > 0)) || yMessages.some(m => m.type === 'u-c');
|
|
3822
|
+
const pushSyncIsNeeded = clientChangeSet.some((set) => set.muts.some((mut) => mut.keys.length > 0)) || yMessages.some((m) => m.type === 'u-c');
|
|
3770
3823
|
if (justCheckIfNeeded) {
|
|
3771
3824
|
console.debug('Sync is needed:', pushSyncIsNeeded);
|
|
3772
3825
|
return pushSyncIsNeeded;
|
|
@@ -3910,7 +3963,7 @@ function _sync(db_1, options_1, schema_1) {
|
|
|
3910
3963
|
db.$syncState.put(newSyncState, 'syncState');
|
|
3911
3964
|
return {
|
|
3912
3965
|
done: addedClientChanges.length === 0,
|
|
3913
|
-
newSyncState
|
|
3966
|
+
newSyncState,
|
|
3914
3967
|
};
|
|
3915
3968
|
}));
|
|
3916
3969
|
if (!done) {
|
|
@@ -3918,7 +3971,7 @@ function _sync(db_1, options_1, schema_1) {
|
|
|
3918
3971
|
yield checkSyncRateLimitDelay(db);
|
|
3919
3972
|
return yield _sync(db, options, schema, { isInitialSync, cancelToken });
|
|
3920
3973
|
}
|
|
3921
|
-
const usingYProps = Object.values(schema).some(tbl => { var _a; return (_a = tbl.yProps) === null || _a === void 0 ? void 0 : _a.length; });
|
|
3974
|
+
const usingYProps = Object.values(schema).some((tbl) => { var _a; return (_a = tbl.yProps) === null || _a === void 0 ? void 0 : _a.length; });
|
|
3922
3975
|
const serverSupportsYprops = !!res.yMessages;
|
|
3923
3976
|
if (usingYProps && serverSupportsYprops) {
|
|
3924
3977
|
try {
|
|
@@ -4225,11 +4278,13 @@ class BlobDownloadTracker {
|
|
|
4225
4278
|
download(blobRef, dbUrl) {
|
|
4226
4279
|
let promise = this.inFlight.get(blobRef.ref);
|
|
4227
4280
|
if (!promise) {
|
|
4228
|
-
promise = loadCachedAccessToken(this.db)
|
|
4281
|
+
promise = loadCachedAccessToken(this.db)
|
|
4282
|
+
.then((accessToken) => {
|
|
4229
4283
|
if (!accessToken)
|
|
4230
|
-
throw new Error(
|
|
4284
|
+
throw new Error('No access token available for blob download');
|
|
4231
4285
|
return downloadBlob(blobRef, dbUrl, accessToken);
|
|
4232
|
-
})
|
|
4286
|
+
})
|
|
4287
|
+
.finally(() => this.inFlight.delete(blobRef.ref));
|
|
4233
4288
|
// When the promise settles (either fulfilled or rejected), remove it from the in-flight map
|
|
4234
4289
|
this.inFlight.set(blobRef.ref, promise);
|
|
4235
4290
|
}
|
|
@@ -4249,8 +4304,8 @@ function downloadBlob(blobRef, dbUrl, accessToken) {
|
|
|
4249
4304
|
const downloadUrl = `${dbUrl}/blob/${blobRef.ref}`;
|
|
4250
4305
|
const response = yield fetch(downloadUrl, {
|
|
4251
4306
|
headers: {
|
|
4252
|
-
|
|
4253
|
-
}
|
|
4307
|
+
Authorization: `Bearer ${accessToken}`,
|
|
4308
|
+
},
|
|
4254
4309
|
});
|
|
4255
4310
|
if (!response.ok) {
|
|
4256
4311
|
throw new Error(`Failed to download blob ${blobRef.ref}: ${response.status} ${response.statusText}`);
|
|
@@ -4342,7 +4397,9 @@ function DexieCloudDB(dx) {
|
|
|
4342
4397
|
return db.$syncState.get('schema').then((schema) => {
|
|
4343
4398
|
if (schema) {
|
|
4344
4399
|
for (const table of db.tables) {
|
|
4345
|
-
if (table.schema.primKey &&
|
|
4400
|
+
if (table.schema.primKey &&
|
|
4401
|
+
table.schema.primKey.keyPath &&
|
|
4402
|
+
schema[table.name]) {
|
|
4346
4403
|
schema[table.name].primaryKey = nameFromKeyPath(table.schema.primKey.keyPath);
|
|
4347
4404
|
}
|
|
4348
4405
|
}
|
|
@@ -4370,9 +4427,11 @@ function DexieCloudDB(dx) {
|
|
|
4370
4427
|
return db;
|
|
4371
4428
|
}
|
|
4372
4429
|
function nameFromKeyPath(keyPath) {
|
|
4373
|
-
return typeof keyPath === 'string'
|
|
4374
|
-
keyPath
|
|
4375
|
-
|
|
4430
|
+
return typeof keyPath === 'string'
|
|
4431
|
+
? keyPath
|
|
4432
|
+
: keyPath
|
|
4433
|
+
? '[' + [].join.call(keyPath, '+') + ']'
|
|
4434
|
+
: '';
|
|
4376
4435
|
}
|
|
4377
4436
|
|
|
4378
4437
|
/**
|
|
@@ -4430,7 +4489,7 @@ function observeBlobProgress(db, downloading$) {
|
|
|
4430
4489
|
isDownloading: isDownloading && stats.blobsRemaining > 0,
|
|
4431
4490
|
blobsRemaining: stats.blobsRemaining,
|
|
4432
4491
|
bytesRemaining: stats.bytesRemaining,
|
|
4433
|
-
})), share({ resetOnRefCountZero: () => timer(2000) }) // Keep alive for 2s after last unsubscription to avoid rapid re-subscriptions during UI updates
|
|
4492
|
+
})), share({ resetOnRefCountZero: () => timer(2000) }) // Keep alive for 2s after last unsubscription to avoid rapid re-subscriptions during UI updates
|
|
4434
4493
|
);
|
|
4435
4494
|
}
|
|
4436
4495
|
/**
|
|
@@ -4514,13 +4573,13 @@ function downloadUnresolvedBlobs(db, downloading$, signal) {
|
|
|
4514
4573
|
}
|
|
4515
4574
|
setDownloadingState(downloading$, true);
|
|
4516
4575
|
try {
|
|
4517
|
-
debugLog(`Eager download: Found ${syncedTables.length} syncable tables: ${syncedTables.map(t => t.name).join(', ')}`);
|
|
4576
|
+
debugLog(`Eager download: Found ${syncedTables.length} syncable tables: ${syncedTables.map((t) => t.name).join(', ')}`);
|
|
4518
4577
|
for (const table of syncedTables) {
|
|
4519
4578
|
if (signal === null || signal === void 0 ? void 0 : signal.aborted)
|
|
4520
4579
|
;
|
|
4521
4580
|
try {
|
|
4522
4581
|
// Check if table has _hasBlobRefs index
|
|
4523
|
-
const hasIndex = table.schema.indexes.some(idx => idx.name === '_hasBlobRefs');
|
|
4582
|
+
const hasIndex = table.schema.indexes.some((idx) => idx.name === '_hasBlobRefs');
|
|
4524
4583
|
if (!hasIndex)
|
|
4525
4584
|
continue;
|
|
4526
4585
|
// Query objects with _hasBlobRefs marker
|
|
@@ -4536,7 +4595,7 @@ function downloadUnresolvedBlobs(db, downloading$, signal) {
|
|
|
4536
4595
|
const MAX_CONCURRENT = 6;
|
|
4537
4596
|
const primaryKey = table.schema.primKey;
|
|
4538
4597
|
// Filter to actionable objects first
|
|
4539
|
-
const pending = unresolvedObjects.filter(obj => {
|
|
4598
|
+
const pending = unresolvedObjects.filter((obj) => {
|
|
4540
4599
|
if (!hasUnresolvedBlobRefs(obj))
|
|
4541
4600
|
return false;
|
|
4542
4601
|
const key = primaryKey.keyPath
|
|
@@ -4599,20 +4658,20 @@ class AuthPersistedContext {
|
|
|
4599
4658
|
}
|
|
4600
4659
|
static load(db, userId) {
|
|
4601
4660
|
return db
|
|
4602
|
-
.table(
|
|
4661
|
+
.table('$logins')
|
|
4603
4662
|
.get(userId)
|
|
4604
4663
|
.then((userLogin) => new AuthPersistedContext(db, userLogin || {
|
|
4605
4664
|
userId,
|
|
4606
4665
|
claims: {
|
|
4607
|
-
sub: userId
|
|
4666
|
+
sub: userId,
|
|
4608
4667
|
},
|
|
4609
|
-
lastLogin: new Date(0)
|
|
4668
|
+
lastLogin: new Date(0),
|
|
4610
4669
|
}));
|
|
4611
4670
|
}
|
|
4612
4671
|
save() {
|
|
4613
4672
|
return __awaiter(this, void 0, void 0, function* () {
|
|
4614
4673
|
const db = wm$1.get(this);
|
|
4615
|
-
db.table(
|
|
4674
|
+
db.table('$logins').put(this);
|
|
4616
4675
|
});
|
|
4617
4676
|
}
|
|
4618
4677
|
}
|
|
@@ -4707,7 +4766,7 @@ class OAuthError extends Error {
|
|
|
4707
4766
|
*/
|
|
4708
4767
|
function exchangeOAuthCode(options) {
|
|
4709
4768
|
return __awaiter(this, void 0, void 0, function* () {
|
|
4710
|
-
const { databaseUrl, code, publicKey, scopes = ['ACCESS_DB'], intent } = options;
|
|
4769
|
+
const { databaseUrl, code, publicKey, scopes = ['ACCESS_DB'], intent, } = options;
|
|
4711
4770
|
const tokenRequest = Object.assign({ grant_type: 'authorization_code', code, public_key: publicKey, scopes }, (intent !== undefined ? { intent } : {}));
|
|
4712
4771
|
try {
|
|
4713
4772
|
const res = yield fetch(`${databaseUrl}/token`, {
|
|
@@ -4765,7 +4824,8 @@ function exchangeOAuthCode(options) {
|
|
|
4765
4824
|
return response;
|
|
4766
4825
|
}
|
|
4767
4826
|
catch (error) {
|
|
4768
|
-
if (error instanceof OAuthError ||
|
|
4827
|
+
if (error instanceof OAuthError ||
|
|
4828
|
+
error instanceof TokenErrorResponseError) {
|
|
4769
4829
|
throw error;
|
|
4770
4830
|
}
|
|
4771
4831
|
if (error instanceof TypeError) {
|
|
@@ -4803,7 +4863,7 @@ function fetchAuthProviders(databaseUrl_1) {
|
|
|
4803
4863
|
try {
|
|
4804
4864
|
const res = yield fetch(`${databaseUrl}/auth-providers`, {
|
|
4805
4865
|
method: 'GET',
|
|
4806
|
-
headers: {
|
|
4866
|
+
headers: { Accept: 'application/json' },
|
|
4807
4867
|
mode: 'cors',
|
|
4808
4868
|
});
|
|
4809
4869
|
if (res.status === 404) {
|
|
@@ -5133,7 +5193,7 @@ function tryParsePolicyAlert(res) {
|
|
|
5133
5193
|
* @param args
|
|
5134
5194
|
*/
|
|
5135
5195
|
function prodLog(level, ...args) {
|
|
5136
|
-
globalThis[
|
|
5196
|
+
globalThis['con' + 'sole'][level](...args);
|
|
5137
5197
|
}
|
|
5138
5198
|
|
|
5139
5199
|
/** This function changes or sets the current user as requested.
|
|
@@ -5263,7 +5323,7 @@ const safariVersion = isSafari
|
|
|
5263
5323
|
const DISABLE_SERVICEWORKER_STRATEGY = (isSafari && safariVersion <= 605) || // Disable for Safari for now.
|
|
5264
5324
|
isFirefox; // Disable for Firefox for now. Seems to have a bug in reading CryptoKeys from IDB from service workers
|
|
5265
5325
|
|
|
5266
|
-
const IS_SERVICE_WORKER = typeof self !==
|
|
5326
|
+
const IS_SERVICE_WORKER = typeof self !== 'undefined' && 'clients' in self && !self.document;
|
|
5267
5327
|
|
|
5268
5328
|
function throwVersionIncrementNeeded() {
|
|
5269
5329
|
throw new Dexie.SchemaError(`Version increment needed to allow dexie-cloud change tracking`);
|
|
@@ -5509,7 +5569,7 @@ function createImplicitPropSetterMiddleware(db) {
|
|
|
5509
5569
|
// We must also degrade from consistent modify operations for the
|
|
5510
5570
|
// same reason - object might be there on server. Must but put up instead.
|
|
5511
5571
|
// FUTURE: This clumpsy behavior of private IDs could be refined later.
|
|
5512
|
-
// Suggestion is to in future, treat private IDs as we treat all objects
|
|
5572
|
+
// Suggestion is to in future, treat private IDs as we treat all objects
|
|
5513
5573
|
// and sync operations normally. Only that deletions should become soft deletes
|
|
5514
5574
|
// for them - so that server knows when a private ID has been deleted on server
|
|
5515
5575
|
// not accept insert/upserts on them.
|
|
@@ -5532,19 +5592,20 @@ function createImplicitPropSetterMiddleware(db) {
|
|
|
5532
5592
|
}
|
|
5533
5593
|
|
|
5534
5594
|
function allSettled(possiblePromises) {
|
|
5535
|
-
return new Promise(resolve => {
|
|
5595
|
+
return new Promise((resolve) => {
|
|
5536
5596
|
if (possiblePromises.length === 0)
|
|
5537
5597
|
resolve([]);
|
|
5538
5598
|
let remaining = possiblePromises.length;
|
|
5539
5599
|
const results = new Array(remaining);
|
|
5540
|
-
possiblePromises.forEach((p, i) => Promise.resolve(p)
|
|
5600
|
+
possiblePromises.forEach((p, i) => Promise.resolve(p)
|
|
5601
|
+
.then((value) => (results[i] = { status: 'fulfilled', value }), (reason) => (results[i] = { status: 'rejected', reason }))
|
|
5541
5602
|
.then(() => --remaining || resolve(results)));
|
|
5542
5603
|
});
|
|
5543
5604
|
}
|
|
5544
5605
|
|
|
5545
5606
|
let counter$1 = 0;
|
|
5546
5607
|
function guardedTable(table) {
|
|
5547
|
-
const prop =
|
|
5608
|
+
const prop = '$lock' + ++counter$1;
|
|
5548
5609
|
return Object.assign(Object.assign({}, table), { count: readLock(table.count, prop), get: readLock(table.get, prop), getMany: readLock(table.getMany, prop), openCursor: readLock(table.openCursor, prop), query: readLock(table.query, prop), mutate: writeLock(table.mutate, prop) });
|
|
5549
5610
|
}
|
|
5550
5611
|
function readLock(fn, prop) {
|
|
@@ -5553,7 +5614,9 @@ function readLock(fn, prop) {
|
|
|
5553
5614
|
const numWriters = writers.length;
|
|
5554
5615
|
const promise = (numWriters > 0
|
|
5555
5616
|
? writers[numWriters - 1].then(() => fn(req), () => fn(req))
|
|
5556
|
-
: fn(req)).finally(() => {
|
|
5617
|
+
: fn(req)).finally(() => {
|
|
5618
|
+
readers.splice(readers.indexOf(promise));
|
|
5619
|
+
});
|
|
5557
5620
|
readers.push(promise);
|
|
5558
5621
|
return promise;
|
|
5559
5622
|
};
|
|
@@ -5565,7 +5628,9 @@ function writeLock(fn, prop) {
|
|
|
5565
5628
|
? writers[writers.length - 1].then(() => fn(req), () => fn(req))
|
|
5566
5629
|
: readers.length > 0
|
|
5567
5630
|
? allSettled(readers).then(() => fn(req))
|
|
5568
|
-
: fn(req)).finally(() => {
|
|
5631
|
+
: fn(req)).finally(() => {
|
|
5632
|
+
writers.shift();
|
|
5633
|
+
});
|
|
5569
5634
|
writers.push(promise);
|
|
5570
5635
|
return promise;
|
|
5571
5636
|
};
|
|
@@ -5843,16 +5908,17 @@ function createMutationTrackingMiddleware({ currentUserObservable, db, }) {
|
|
|
5843
5908
|
userId,
|
|
5844
5909
|
values,
|
|
5845
5910
|
}
|
|
5846
|
-
: upsert && updates
|
|
5847
|
-
|
|
5848
|
-
|
|
5849
|
-
|
|
5850
|
-
|
|
5851
|
-
|
|
5852
|
-
|
|
5853
|
-
|
|
5854
|
-
|
|
5855
|
-
|
|
5911
|
+
: upsert && updates
|
|
5912
|
+
? {
|
|
5913
|
+
type: 'upsert',
|
|
5914
|
+
ts,
|
|
5915
|
+
opNo,
|
|
5916
|
+
keys,
|
|
5917
|
+
values,
|
|
5918
|
+
changeSpecs: updates.changeSpecs.filter((_, idx) => !failures[idx]),
|
|
5919
|
+
txid,
|
|
5920
|
+
userId,
|
|
5921
|
+
}
|
|
5856
5922
|
: criteria && changeSpec
|
|
5857
5923
|
? {
|
|
5858
5924
|
// Common changeSpec for all keys
|
|
@@ -5965,7 +6031,8 @@ class BlobSavingQueue {
|
|
|
5965
6031
|
return;
|
|
5966
6032
|
}
|
|
5967
6033
|
// Atomic update of just the blob property
|
|
5968
|
-
this.db
|
|
6034
|
+
this.db
|
|
6035
|
+
.transaction('rw', item.tableName, (tx) => {
|
|
5969
6036
|
const trans = tx.idbtrans;
|
|
5970
6037
|
trans.disableChangeTracking = true; // Don't regard this as a change for sync purposes
|
|
5971
6038
|
trans.disableAccessControl = true; // Bypass any access control checks since this is an internal operation
|
|
@@ -5974,7 +6041,7 @@ class BlobSavingQueue {
|
|
|
5974
6041
|
for (const blob of item.resolvedBlobs) {
|
|
5975
6042
|
updateSpec[blob.keyPath] = blob.data;
|
|
5976
6043
|
}
|
|
5977
|
-
tx.table(item.tableName).update(item.primaryKey, obj => {
|
|
6044
|
+
tx.table(item.tableName).update(item.primaryKey, (obj) => {
|
|
5978
6045
|
// Check that object still has the same unresolved blob refs before applying update (i.e. it hasn't been modified since we read it)
|
|
5979
6046
|
for (const blob of item.resolvedBlobs) {
|
|
5980
6047
|
// Verify atomicity - none of the blob properties has been modified since we read it. If any of them was modified, skip updating this item to avoid overwriting user changes.
|
|
@@ -5995,9 +6062,11 @@ class BlobSavingQueue {
|
|
|
5995
6062
|
}
|
|
5996
6063
|
delete obj._hasBlobRefs; // Clear the _hasBlobRefs marker if all refs was resolved.
|
|
5997
6064
|
});
|
|
5998
|
-
})
|
|
6065
|
+
})
|
|
6066
|
+
.catch((error) => {
|
|
5999
6067
|
console.error(`Error saving resolved blobs on ${item.tableName}:${item.primaryKey}:`, error);
|
|
6000
|
-
})
|
|
6068
|
+
})
|
|
6069
|
+
.finally(() => {
|
|
6001
6070
|
// Process next item in the queue
|
|
6002
6071
|
return this.processQueue();
|
|
6003
6072
|
});
|
|
@@ -6048,7 +6117,7 @@ function createBlobResolveMiddleware(db) {
|
|
|
6048
6117
|
if ((_a = req.trans) === null || _a === void 0 ? void 0 : _a.disableBlobResolve) {
|
|
6049
6118
|
return downlevelTable.get(req);
|
|
6050
6119
|
}
|
|
6051
|
-
return downlevelTable.get(req).then(result => {
|
|
6120
|
+
return downlevelTable.get(req).then((result) => {
|
|
6052
6121
|
if (result && hasUnresolvedBlobRefs(result)) {
|
|
6053
6122
|
return resolveAndSave(downlevelTable, req.trans, req.key, result, blobSavingQueue, db);
|
|
6054
6123
|
}
|
|
@@ -6060,9 +6129,9 @@ function createBlobResolveMiddleware(db) {
|
|
|
6060
6129
|
if ((_a = req.trans) === null || _a === void 0 ? void 0 : _a.disableBlobResolve) {
|
|
6061
6130
|
return downlevelTable.getMany(req);
|
|
6062
6131
|
}
|
|
6063
|
-
return downlevelTable.getMany(req).then(results => {
|
|
6132
|
+
return downlevelTable.getMany(req).then((results) => {
|
|
6064
6133
|
// Check if any results need resolution
|
|
6065
|
-
const needsResolution = results.some(r => r && hasUnresolvedBlobRefs(r));
|
|
6134
|
+
const needsResolution = results.some((r) => r && hasUnresolvedBlobRefs(r));
|
|
6066
6135
|
if (!needsResolution)
|
|
6067
6136
|
return results;
|
|
6068
6137
|
return Dexie.Promise.all(results.map((result, index) => {
|
|
@@ -6078,19 +6147,19 @@ function createBlobResolveMiddleware(db) {
|
|
|
6078
6147
|
if ((_a = req.trans) === null || _a === void 0 ? void 0 : _a.disableBlobResolve) {
|
|
6079
6148
|
return downlevelTable.query(req);
|
|
6080
6149
|
}
|
|
6081
|
-
return downlevelTable.query(req).then(result => {
|
|
6150
|
+
return downlevelTable.query(req).then((result) => {
|
|
6082
6151
|
if (!result.result || !Array.isArray(result.result))
|
|
6083
6152
|
return result;
|
|
6084
6153
|
// Check if any results need resolution
|
|
6085
|
-
const needsResolution = result.result.some(r => r && hasUnresolvedBlobRefs(r));
|
|
6154
|
+
const needsResolution = result.result.some((r) => r && hasUnresolvedBlobRefs(r));
|
|
6086
6155
|
if (!needsResolution)
|
|
6087
6156
|
return result;
|
|
6088
|
-
return Dexie.Promise.all(result.result.map(item => {
|
|
6157
|
+
return Dexie.Promise.all(result.result.map((item) => {
|
|
6089
6158
|
if (item && hasUnresolvedBlobRefs(item)) {
|
|
6090
6159
|
return resolveAndSave(downlevelTable, req.trans, undefined, item, blobSavingQueue, db);
|
|
6091
6160
|
}
|
|
6092
6161
|
return item;
|
|
6093
|
-
})).then(resolved => (Object.assign(Object.assign({}, result), { result: resolved })));
|
|
6162
|
+
})).then((resolved) => (Object.assign(Object.assign({}, result), { result: resolved })));
|
|
6094
6163
|
});
|
|
6095
6164
|
},
|
|
6096
6165
|
openCursor(req) {
|
|
@@ -6098,7 +6167,7 @@ function createBlobResolveMiddleware(db) {
|
|
|
6098
6167
|
if ((_a = req.trans) === null || _a === void 0 ? void 0 : _a.disableBlobResolve) {
|
|
6099
6168
|
return downlevelTable.openCursor(req);
|
|
6100
6169
|
}
|
|
6101
|
-
return downlevelTable.openCursor(req).then(cursor => {
|
|
6170
|
+
return downlevelTable.openCursor(req).then((cursor) => {
|
|
6102
6171
|
if (!cursor)
|
|
6103
6172
|
return cursor; // No results, so no resolution needed
|
|
6104
6173
|
if (!req.values)
|
|
@@ -6128,7 +6197,7 @@ function createBlobResolvingCursor(cursor, table, blobSavingQueue, db) {
|
|
|
6128
6197
|
value: {
|
|
6129
6198
|
value: cursor.value,
|
|
6130
6199
|
enumerable: true,
|
|
6131
|
-
writable: true
|
|
6200
|
+
writable: true,
|
|
6132
6201
|
},
|
|
6133
6202
|
start: {
|
|
6134
6203
|
value(onNext) {
|
|
@@ -6140,17 +6209,17 @@ function createBlobResolvingCursor(cursor, table, blobSavingQueue, db) {
|
|
|
6140
6209
|
onNext();
|
|
6141
6210
|
return;
|
|
6142
6211
|
}
|
|
6143
|
-
resolveAndSave(table, cursor.trans, cursor.primaryKey, rawValue, blobSavingQueue, db, true).then(resolved => {
|
|
6212
|
+
resolveAndSave(table, cursor.trans, cursor.primaryKey, rawValue, blobSavingQueue, db, true).then((resolved) => {
|
|
6144
6213
|
wrappedCursor.value = resolved;
|
|
6145
6214
|
onNext();
|
|
6146
|
-
}, err => {
|
|
6215
|
+
}, (err) => {
|
|
6147
6216
|
console.error('Failed to resolve BlobRefs for cursor value:', err);
|
|
6148
6217
|
wrappedCursor.value = rawValue;
|
|
6149
6218
|
onNext();
|
|
6150
6219
|
});
|
|
6151
6220
|
});
|
|
6152
|
-
}
|
|
6153
|
-
}
|
|
6221
|
+
},
|
|
6222
|
+
},
|
|
6154
6223
|
});
|
|
6155
6224
|
return wrappedCursor;
|
|
6156
6225
|
}
|
|
@@ -6195,12 +6264,15 @@ obj, blobSavingQueue, db, isCursorValue = false // Flag to indicate if we're res
|
|
|
6195
6264
|
const resolvePromise = needsWaitFor
|
|
6196
6265
|
? Dexie.waitFor(resolutionPromise)
|
|
6197
6266
|
: Dexie.Promise.resolve(resolutionPromise);
|
|
6198
|
-
return resolvePromise
|
|
6267
|
+
return resolvePromise
|
|
6268
|
+
.then((resolved) => {
|
|
6199
6269
|
// Get primary key from the object
|
|
6200
6270
|
const primaryKey = table.schema.primaryKey;
|
|
6201
|
-
const key = pKey !== undefined
|
|
6202
|
-
?
|
|
6203
|
-
:
|
|
6271
|
+
const key = pKey !== undefined
|
|
6272
|
+
? pKey
|
|
6273
|
+
: primaryKey.keyPath
|
|
6274
|
+
? Dexie.getByKeyPath(obj, primaryKey.keyPath)
|
|
6275
|
+
: undefined;
|
|
6204
6276
|
if (key !== undefined) {
|
|
6205
6277
|
// Queue each resolved blob individually for atomic update
|
|
6206
6278
|
// This uses setTimeout(fn, 0) to completely isolate from
|
|
@@ -6211,13 +6283,16 @@ obj, blobSavingQueue, db, isCursorValue = false // Flag to indicate if we're res
|
|
|
6211
6283
|
else {
|
|
6212
6284
|
// For rw transactions, we can save directly without queueing
|
|
6213
6285
|
// since we're still in the same transaction context
|
|
6214
|
-
table
|
|
6286
|
+
table
|
|
6287
|
+
.mutate({ type: 'put', keys: [key], values: [resolved], trans })
|
|
6288
|
+
.catch((err) => {
|
|
6215
6289
|
console.error(`Failed to save resolved blob on ${table.name}:${key}:`, err);
|
|
6216
6290
|
});
|
|
6217
6291
|
}
|
|
6218
6292
|
}
|
|
6219
6293
|
return resolved;
|
|
6220
|
-
})
|
|
6294
|
+
})
|
|
6295
|
+
.catch((err) => {
|
|
6221
6296
|
console.error(`[dexie-cloud:blobResolve] Failed to resolve BlobRefs on ${table.name}:`, err);
|
|
6222
6297
|
return obj; // Return original object on error - never block the read pipeline
|
|
6223
6298
|
});
|
|
@@ -6246,9 +6321,13 @@ function overrideParseStoresSpec(origFunc, dexie) {
|
|
|
6246
6321
|
return; // Continue
|
|
6247
6322
|
}
|
|
6248
6323
|
// They have declared this table. Merge indexes in case they didn't declare all indexes we need.
|
|
6249
|
-
const requestedIndexes = schemaSrc
|
|
6250
|
-
|
|
6251
|
-
|
|
6324
|
+
const requestedIndexes = schemaSrc
|
|
6325
|
+
.split(',')
|
|
6326
|
+
.map((spec) => spec.trim());
|
|
6327
|
+
const builtInIndexes = DEXIE_CLOUD_SCHEMA[tableName]
|
|
6328
|
+
.split(',')
|
|
6329
|
+
.map((spec) => spec.trim());
|
|
6330
|
+
const requestedIndexSet = new Set(requestedIndexes.map((index) => index.replace(/([&*]|\+\+)/g, '')));
|
|
6252
6331
|
// Verify that primary key is unchanged
|
|
6253
6332
|
if (requestedIndexes[0] !== builtInIndexes[0]) {
|
|
6254
6333
|
// Primary key must match exactly
|
|
@@ -6257,7 +6336,7 @@ function overrideParseStoresSpec(origFunc, dexie) {
|
|
|
6257
6336
|
// Merge indexes
|
|
6258
6337
|
for (let i = 1; i < builtInIndexes.length; ++i) {
|
|
6259
6338
|
const builtInIndex = builtInIndexes[i];
|
|
6260
|
-
if (!requestedIndexSet.has(builtInIndex.replace(/([&*]|\+\+)/g,
|
|
6339
|
+
if (!requestedIndexSet.has(builtInIndex.replace(/([&*]|\+\+)/g, ''))) {
|
|
6261
6340
|
// Add built-in index if not already requested
|
|
6262
6341
|
storesClone[tableName] += `,${builtInIndex}`;
|
|
6263
6342
|
}
|
|
@@ -6266,7 +6345,7 @@ function overrideParseStoresSpec(origFunc, dexie) {
|
|
|
6266
6345
|
// Populate dexie.cloud.schema
|
|
6267
6346
|
const cloudSchema = dexie.cloud.schema || (dexie.cloud.schema = {});
|
|
6268
6347
|
const allPrefixes = new Set();
|
|
6269
|
-
Object.keys(storesClone).forEach(tableName => {
|
|
6348
|
+
Object.keys(storesClone).forEach((tableName) => {
|
|
6270
6349
|
var _a;
|
|
6271
6350
|
const schemaSrc = (_a = storesClone[tableName]) === null || _a === void 0 ? void 0 : _a.trim();
|
|
6272
6351
|
const cloudTableSchema = cloudSchema[tableName] || (cloudSchema[tableName] = {});
|
|
@@ -6395,7 +6474,7 @@ if (typeof document !== 'undefined') {
|
|
|
6395
6474
|
class TokenExpiredError extends Error {
|
|
6396
6475
|
constructor() {
|
|
6397
6476
|
super(...arguments);
|
|
6398
|
-
this.name =
|
|
6477
|
+
this.name = 'TokenExpiredError';
|
|
6399
6478
|
}
|
|
6400
6479
|
}
|
|
6401
6480
|
|
|
@@ -6619,7 +6698,7 @@ class WSConnection extends Subscription {
|
|
|
6619
6698
|
// Connect the WebSocket to given url:
|
|
6620
6699
|
console.debug('dexie-cloud WebSocket create');
|
|
6621
6700
|
const ws = (this.ws = new WebSocket(`${wsUrl}/changes?${searchParams}`));
|
|
6622
|
-
ws.binaryType =
|
|
6701
|
+
ws.binaryType = 'arraybuffer';
|
|
6623
6702
|
ws.onclose = (event) => {
|
|
6624
6703
|
if (!this.pinger)
|
|
6625
6704
|
return;
|
|
@@ -6658,10 +6737,17 @@ class WSConnection extends Subscription {
|
|
|
6658
6737
|
getOpenDocSignal(doc).next(); // Make yHandler reopen the document on server.
|
|
6659
6738
|
}
|
|
6660
6739
|
}
|
|
6661
|
-
else if (msg.type === 'u-ack' ||
|
|
6740
|
+
else if (msg.type === 'u-ack' ||
|
|
6741
|
+
msg.type === 'u-reject' ||
|
|
6742
|
+
msg.type === 'u-s' ||
|
|
6743
|
+
msg.type === 'in-sync' ||
|
|
6744
|
+
msg.type === 'outdated-server-rev' ||
|
|
6745
|
+
msg.type === 'y-complete-sync-done') {
|
|
6662
6746
|
applyYServerMessages([msg], this.db).then((_a) => __awaiter(this, [_a], void 0, function* ({ resyncNeeded, yServerRevision, receivedUntils }) {
|
|
6663
6747
|
if (yServerRevision) {
|
|
6664
|
-
yield this.db.$syncState.update('syncState', {
|
|
6748
|
+
yield this.db.$syncState.update('syncState', {
|
|
6749
|
+
yServerRevision: yServerRevision,
|
|
6750
|
+
});
|
|
6665
6751
|
}
|
|
6666
6752
|
if (msg.type === 'u-s' && receivedUntils) {
|
|
6667
6753
|
const utbl = getUpdatesTable(this.db, msg.table, msg.prop);
|
|
@@ -6864,7 +6950,9 @@ function isSyncNeeded(db) {
|
|
|
6864
6950
|
return __awaiter(this, void 0, void 0, function* () {
|
|
6865
6951
|
var _a;
|
|
6866
6952
|
return ((_a = db.cloud.options) === null || _a === void 0 ? void 0 : _a.databaseUrl) && db.cloud.schema
|
|
6867
|
-
? yield sync(db, db.cloud.options, db.cloud.schema, {
|
|
6953
|
+
? yield sync(db, db.cloud.options, db.cloud.schema, {
|
|
6954
|
+
justCheckIfNeeded: true,
|
|
6955
|
+
})
|
|
6868
6956
|
: false;
|
|
6869
6957
|
});
|
|
6870
6958
|
}
|
|
@@ -7076,243 +7164,243 @@ var n,l$1,u$1,i$1,r$1,o$1,e$1,f$1,c$1,s$1,a$1,p$1={},v$1=[],y=/acit|ex(?:s|g|n|p
|
|
|
7076
7164
|
const Styles = {
|
|
7077
7165
|
Alert: {
|
|
7078
7166
|
error: {
|
|
7079
|
-
color:
|
|
7080
|
-
fontWeight:
|
|
7167
|
+
color: 'red',
|
|
7168
|
+
fontWeight: 'bold',
|
|
7081
7169
|
},
|
|
7082
7170
|
warning: {
|
|
7083
|
-
color:
|
|
7084
|
-
fontWeight:
|
|
7171
|
+
color: '#f80',
|
|
7172
|
+
fontWeight: 'bold',
|
|
7085
7173
|
},
|
|
7086
7174
|
info: {
|
|
7087
|
-
color:
|
|
7088
|
-
}
|
|
7175
|
+
color: 'black',
|
|
7176
|
+
},
|
|
7089
7177
|
},
|
|
7090
7178
|
Darken: {
|
|
7091
|
-
position:
|
|
7179
|
+
position: 'fixed',
|
|
7092
7180
|
top: 0,
|
|
7093
7181
|
left: 0,
|
|
7094
7182
|
opacity: 0.5,
|
|
7095
|
-
backgroundColor:
|
|
7096
|
-
width:
|
|
7097
|
-
height:
|
|
7183
|
+
backgroundColor: '#000',
|
|
7184
|
+
width: '100vw',
|
|
7185
|
+
height: '100vh',
|
|
7098
7186
|
zIndex: 150,
|
|
7099
|
-
webkitBackdropFilter:
|
|
7100
|
-
backdropFilter:
|
|
7187
|
+
webkitBackdropFilter: 'blur(2px)',
|
|
7188
|
+
backdropFilter: 'blur(2px)',
|
|
7101
7189
|
},
|
|
7102
7190
|
DialogOuter: {
|
|
7103
|
-
position:
|
|
7191
|
+
position: 'fixed',
|
|
7104
7192
|
top: 0,
|
|
7105
7193
|
left: 0,
|
|
7106
|
-
width:
|
|
7107
|
-
height:
|
|
7194
|
+
width: '100vw',
|
|
7195
|
+
height: '100vh',
|
|
7108
7196
|
zIndex: 150,
|
|
7109
|
-
alignItems:
|
|
7110
|
-
display:
|
|
7111
|
-
justifyContent:
|
|
7112
|
-
padding:
|
|
7113
|
-
boxSizing:
|
|
7197
|
+
alignItems: 'center',
|
|
7198
|
+
display: 'flex',
|
|
7199
|
+
justifyContent: 'center',
|
|
7200
|
+
padding: '16px',
|
|
7201
|
+
boxSizing: 'border-box',
|
|
7114
7202
|
},
|
|
7115
7203
|
DialogInner: {
|
|
7116
|
-
position:
|
|
7117
|
-
color:
|
|
7118
|
-
backgroundColor:
|
|
7119
|
-
padding:
|
|
7120
|
-
marginBottom:
|
|
7121
|
-
maxWidth:
|
|
7122
|
-
width:
|
|
7123
|
-
maxHeight:
|
|
7124
|
-
overflowY:
|
|
7125
|
-
border:
|
|
7126
|
-
borderRadius:
|
|
7127
|
-
boxShadow:
|
|
7128
|
-
fontFamily:
|
|
7129
|
-
boxSizing:
|
|
7204
|
+
position: 'relative',
|
|
7205
|
+
color: '#222',
|
|
7206
|
+
backgroundColor: '#fff',
|
|
7207
|
+
padding: '24px',
|
|
7208
|
+
marginBottom: '2em',
|
|
7209
|
+
maxWidth: '400px',
|
|
7210
|
+
width: '100%',
|
|
7211
|
+
maxHeight: '90%',
|
|
7212
|
+
overflowY: 'auto',
|
|
7213
|
+
border: '3px solid #3d3d5d',
|
|
7214
|
+
borderRadius: '8px',
|
|
7215
|
+
boxShadow: '0 0 80px 10px #666',
|
|
7216
|
+
fontFamily: 'sans-serif',
|
|
7217
|
+
boxSizing: 'border-box',
|
|
7130
7218
|
},
|
|
7131
7219
|
Input: {
|
|
7132
|
-
height:
|
|
7133
|
-
width:
|
|
7134
|
-
maxWidth:
|
|
7135
|
-
borderColor:
|
|
7136
|
-
outline:
|
|
7137
|
-
fontSize:
|
|
7138
|
-
padding:
|
|
7139
|
-
boxSizing:
|
|
7140
|
-
backgroundColor:
|
|
7141
|
-
borderRadius:
|
|
7142
|
-
border:
|
|
7143
|
-
marginTop:
|
|
7144
|
-
fontFamily:
|
|
7220
|
+
height: '35px',
|
|
7221
|
+
width: '100%',
|
|
7222
|
+
maxWidth: '100%',
|
|
7223
|
+
borderColor: '#ccf4',
|
|
7224
|
+
outline: 'none',
|
|
7225
|
+
fontSize: '16px',
|
|
7226
|
+
padding: '8px',
|
|
7227
|
+
boxSizing: 'border-box',
|
|
7228
|
+
backgroundColor: '#f9f9f9',
|
|
7229
|
+
borderRadius: '4px',
|
|
7230
|
+
border: '1px solid #ccc',
|
|
7231
|
+
marginTop: '6px',
|
|
7232
|
+
fontFamily: 'inherit',
|
|
7145
7233
|
},
|
|
7146
7234
|
Button: {
|
|
7147
|
-
padding:
|
|
7148
|
-
margin:
|
|
7149
|
-
border:
|
|
7150
|
-
borderRadius:
|
|
7151
|
-
backgroundColor:
|
|
7152
|
-
cursor:
|
|
7153
|
-
fontSize:
|
|
7154
|
-
fontWeight:
|
|
7155
|
-
color:
|
|
7156
|
-
transition:
|
|
7235
|
+
padding: '10px 20px',
|
|
7236
|
+
margin: '0 4px',
|
|
7237
|
+
border: '1px solid #d1d5db',
|
|
7238
|
+
borderRadius: '6px',
|
|
7239
|
+
backgroundColor: '#ffffff',
|
|
7240
|
+
cursor: 'pointer',
|
|
7241
|
+
fontSize: '14px',
|
|
7242
|
+
fontWeight: '500',
|
|
7243
|
+
color: '#374151',
|
|
7244
|
+
transition: 'all 0.2s ease',
|
|
7157
7245
|
},
|
|
7158
7246
|
PrimaryButton: {
|
|
7159
|
-
padding:
|
|
7160
|
-
margin:
|
|
7161
|
-
border:
|
|
7162
|
-
borderRadius:
|
|
7163
|
-
backgroundColor:
|
|
7164
|
-
color:
|
|
7165
|
-
cursor:
|
|
7166
|
-
fontSize:
|
|
7167
|
-
fontWeight:
|
|
7168
|
-
transition:
|
|
7247
|
+
padding: '10px 20px',
|
|
7248
|
+
margin: '0 4px',
|
|
7249
|
+
border: '1px solid #3b82f6',
|
|
7250
|
+
borderRadius: '6px',
|
|
7251
|
+
backgroundColor: '#3b82f6',
|
|
7252
|
+
color: 'white',
|
|
7253
|
+
cursor: 'pointer',
|
|
7254
|
+
fontSize: '14px',
|
|
7255
|
+
fontWeight: '500',
|
|
7256
|
+
transition: 'all 0.2s ease',
|
|
7169
7257
|
},
|
|
7170
7258
|
ButtonsDiv: {
|
|
7171
|
-
display:
|
|
7172
|
-
justifyContent:
|
|
7173
|
-
gap:
|
|
7174
|
-
marginTop:
|
|
7175
|
-
paddingTop:
|
|
7259
|
+
display: 'flex',
|
|
7260
|
+
justifyContent: 'flex-end',
|
|
7261
|
+
gap: '12px',
|
|
7262
|
+
marginTop: '24px',
|
|
7263
|
+
paddingTop: '20px',
|
|
7176
7264
|
},
|
|
7177
7265
|
Label: {
|
|
7178
|
-
display:
|
|
7179
|
-
marginBottom:
|
|
7180
|
-
fontSize:
|
|
7181
|
-
fontWeight:
|
|
7182
|
-
color:
|
|
7266
|
+
display: 'block',
|
|
7267
|
+
marginBottom: '12px',
|
|
7268
|
+
fontSize: '14px',
|
|
7269
|
+
fontWeight: '500',
|
|
7270
|
+
color: '#333',
|
|
7183
7271
|
},
|
|
7184
7272
|
WindowHeader: {
|
|
7185
|
-
margin:
|
|
7186
|
-
fontSize:
|
|
7187
|
-
fontWeight:
|
|
7188
|
-
color:
|
|
7189
|
-
borderBottom:
|
|
7190
|
-
paddingBottom:
|
|
7273
|
+
margin: '0 0 20px 0',
|
|
7274
|
+
fontSize: '18px',
|
|
7275
|
+
fontWeight: '600',
|
|
7276
|
+
color: '#333',
|
|
7277
|
+
borderBottom: '1px solid #eee',
|
|
7278
|
+
paddingBottom: '10px',
|
|
7191
7279
|
},
|
|
7192
7280
|
// OAuth Provider Button Styles
|
|
7193
7281
|
ProviderButton: {
|
|
7194
|
-
display:
|
|
7195
|
-
alignItems:
|
|
7196
|
-
justifyContent:
|
|
7197
|
-
width:
|
|
7198
|
-
padding:
|
|
7199
|
-
marginBottom:
|
|
7200
|
-
border:
|
|
7201
|
-
borderRadius:
|
|
7202
|
-
backgroundColor:
|
|
7203
|
-
cursor:
|
|
7204
|
-
fontSize:
|
|
7205
|
-
fontWeight:
|
|
7206
|
-
color:
|
|
7207
|
-
transition:
|
|
7208
|
-
gap:
|
|
7282
|
+
display: 'flex',
|
|
7283
|
+
alignItems: 'center',
|
|
7284
|
+
justifyContent: 'center',
|
|
7285
|
+
width: '100%',
|
|
7286
|
+
padding: '12px 16px',
|
|
7287
|
+
marginBottom: '10px',
|
|
7288
|
+
border: '1px solid #d1d5db',
|
|
7289
|
+
borderRadius: '6px',
|
|
7290
|
+
backgroundColor: '#ffffff',
|
|
7291
|
+
cursor: 'pointer',
|
|
7292
|
+
fontSize: '14px',
|
|
7293
|
+
fontWeight: '500',
|
|
7294
|
+
color: '#374151',
|
|
7295
|
+
transition: 'all 0.2s ease',
|
|
7296
|
+
gap: '12px',
|
|
7209
7297
|
},
|
|
7210
7298
|
ProviderButtonIcon: {
|
|
7211
|
-
width:
|
|
7212
|
-
height:
|
|
7299
|
+
width: '20px',
|
|
7300
|
+
height: '20px',
|
|
7213
7301
|
flexShrink: 0,
|
|
7214
|
-
display:
|
|
7215
|
-
alignItems:
|
|
7216
|
-
justifyContent:
|
|
7302
|
+
display: 'flex',
|
|
7303
|
+
alignItems: 'center',
|
|
7304
|
+
justifyContent: 'center',
|
|
7217
7305
|
},
|
|
7218
7306
|
ProviderButtonText: {
|
|
7219
7307
|
flex: 1,
|
|
7220
|
-
textAlign:
|
|
7308
|
+
textAlign: 'left',
|
|
7221
7309
|
},
|
|
7222
7310
|
// Provider-specific colors
|
|
7223
7311
|
ProviderGoogle: {
|
|
7224
|
-
backgroundColor:
|
|
7225
|
-
border:
|
|
7226
|
-
color:
|
|
7312
|
+
backgroundColor: '#ffffff',
|
|
7313
|
+
border: '1px solid #dadce0',
|
|
7314
|
+
color: '#3c4043',
|
|
7227
7315
|
},
|
|
7228
7316
|
ProviderGitHub: {
|
|
7229
|
-
backgroundColor:
|
|
7230
|
-
border:
|
|
7231
|
-
color:
|
|
7317
|
+
backgroundColor: '#ffffff',
|
|
7318
|
+
border: '1px solid #dadce0',
|
|
7319
|
+
color: '#181717',
|
|
7232
7320
|
},
|
|
7233
7321
|
ProviderMicrosoft: {
|
|
7234
|
-
backgroundColor:
|
|
7235
|
-
border:
|
|
7236
|
-
color:
|
|
7322
|
+
backgroundColor: '#ffffff',
|
|
7323
|
+
border: '1px solid #dadce0',
|
|
7324
|
+
color: '#5e5e5e',
|
|
7237
7325
|
},
|
|
7238
7326
|
ProviderApple: {
|
|
7239
|
-
backgroundColor:
|
|
7240
|
-
border:
|
|
7241
|
-
color:
|
|
7327
|
+
backgroundColor: '#000000',
|
|
7328
|
+
border: '1px solid #000000',
|
|
7329
|
+
color: '#ffffff',
|
|
7242
7330
|
},
|
|
7243
7331
|
ProviderCustom: {
|
|
7244
|
-
backgroundColor:
|
|
7245
|
-
border:
|
|
7246
|
-
color:
|
|
7332
|
+
backgroundColor: '#ffffff',
|
|
7333
|
+
border: '1px solid #dadce0',
|
|
7334
|
+
color: '#181717',
|
|
7247
7335
|
},
|
|
7248
7336
|
// Divider styles
|
|
7249
7337
|
Divider: {
|
|
7250
|
-
display:
|
|
7251
|
-
alignItems:
|
|
7252
|
-
margin:
|
|
7253
|
-
color:
|
|
7254
|
-
fontSize:
|
|
7338
|
+
display: 'flex',
|
|
7339
|
+
alignItems: 'center',
|
|
7340
|
+
margin: '20px 0',
|
|
7341
|
+
color: '#6b7280',
|
|
7342
|
+
fontSize: '13px',
|
|
7255
7343
|
},
|
|
7256
7344
|
DividerLine: {
|
|
7257
7345
|
flex: 1,
|
|
7258
|
-
height:
|
|
7259
|
-
backgroundColor:
|
|
7346
|
+
height: '1px',
|
|
7347
|
+
backgroundColor: '#e5e7eb',
|
|
7260
7348
|
},
|
|
7261
7349
|
DividerText: {
|
|
7262
|
-
padding:
|
|
7263
|
-
color:
|
|
7350
|
+
padding: '0 12px',
|
|
7351
|
+
color: '#9ca3af',
|
|
7264
7352
|
},
|
|
7265
7353
|
// OTP Button (Continue with email)
|
|
7266
7354
|
OtpButton: {
|
|
7267
|
-
display:
|
|
7268
|
-
alignItems:
|
|
7269
|
-
justifyContent:
|
|
7270
|
-
width:
|
|
7271
|
-
padding:
|
|
7272
|
-
border:
|
|
7273
|
-
borderRadius:
|
|
7274
|
-
backgroundColor:
|
|
7275
|
-
cursor:
|
|
7276
|
-
fontSize:
|
|
7277
|
-
fontWeight:
|
|
7278
|
-
color:
|
|
7279
|
-
transition:
|
|
7280
|
-
gap:
|
|
7355
|
+
display: 'flex',
|
|
7356
|
+
alignItems: 'center',
|
|
7357
|
+
justifyContent: 'center',
|
|
7358
|
+
width: '100%',
|
|
7359
|
+
padding: '12px 16px',
|
|
7360
|
+
border: '1px solid #d1d5db',
|
|
7361
|
+
borderRadius: '6px',
|
|
7362
|
+
backgroundColor: '#f9fafb',
|
|
7363
|
+
cursor: 'pointer',
|
|
7364
|
+
fontSize: '14px',
|
|
7365
|
+
fontWeight: '500',
|
|
7366
|
+
color: '#374151',
|
|
7367
|
+
transition: 'all 0.2s ease',
|
|
7368
|
+
gap: '12px',
|
|
7281
7369
|
},
|
|
7282
7370
|
// Copy button for alerts with copyText
|
|
7283
7371
|
CopyButton: {
|
|
7284
|
-
display:
|
|
7285
|
-
alignItems:
|
|
7286
|
-
gap:
|
|
7287
|
-
padding:
|
|
7288
|
-
marginTop:
|
|
7289
|
-
border:
|
|
7290
|
-
borderRadius:
|
|
7291
|
-
backgroundColor:
|
|
7292
|
-
cursor:
|
|
7293
|
-
fontSize:
|
|
7294
|
-
fontWeight:
|
|
7295
|
-
color:
|
|
7296
|
-
transition:
|
|
7297
|
-
fontFamily:
|
|
7372
|
+
display: 'inline-flex',
|
|
7373
|
+
alignItems: 'center',
|
|
7374
|
+
gap: '4px',
|
|
7375
|
+
padding: '4px 10px',
|
|
7376
|
+
marginTop: '8px',
|
|
7377
|
+
border: '1px solid #d1d5db',
|
|
7378
|
+
borderRadius: '4px',
|
|
7379
|
+
backgroundColor: '#f9fafb',
|
|
7380
|
+
cursor: 'pointer',
|
|
7381
|
+
fontSize: '12px',
|
|
7382
|
+
fontWeight: '500',
|
|
7383
|
+
color: '#374151',
|
|
7384
|
+
transition: 'all 0.15s ease',
|
|
7385
|
+
fontFamily: 'monospace',
|
|
7298
7386
|
},
|
|
7299
7387
|
CopyButtonCopied: {
|
|
7300
|
-
display:
|
|
7301
|
-
alignItems:
|
|
7302
|
-
gap:
|
|
7303
|
-
padding:
|
|
7304
|
-
marginTop:
|
|
7305
|
-
border:
|
|
7306
|
-
borderRadius:
|
|
7307
|
-
backgroundColor:
|
|
7308
|
-
cursor:
|
|
7309
|
-
fontSize:
|
|
7310
|
-
fontWeight:
|
|
7311
|
-
color:
|
|
7312
|
-
fontFamily:
|
|
7388
|
+
display: 'inline-flex',
|
|
7389
|
+
alignItems: 'center',
|
|
7390
|
+
gap: '4px',
|
|
7391
|
+
padding: '4px 10px',
|
|
7392
|
+
marginTop: '8px',
|
|
7393
|
+
border: '1px solid #22c55e',
|
|
7394
|
+
borderRadius: '4px',
|
|
7395
|
+
backgroundColor: '#f0fdf4',
|
|
7396
|
+
cursor: 'default',
|
|
7397
|
+
fontSize: '12px',
|
|
7398
|
+
fontWeight: '500',
|
|
7399
|
+
color: '#16a34a',
|
|
7400
|
+
fontFamily: 'monospace',
|
|
7313
7401
|
}};
|
|
7314
7402
|
|
|
7315
|
-
function Dialog({ children, className }) {
|
|
7403
|
+
function Dialog({ children, className, }) {
|
|
7316
7404
|
return (_$1("div", { className: `dexie-dialog ${className || ''}` },
|
|
7317
7405
|
_$1("div", { style: Styles.Darken }),
|
|
7318
7406
|
_$1("div", { style: Styles.DialogOuter },
|
|
@@ -7336,7 +7424,7 @@ var t,r,u,i,o=0,f=[],c=l$1,e=c.__b,a=c.__r,v=c.diffed,l=c.__c,m=c.unmount,s=c.__
|
|
|
7336
7424
|
* @returns A final message where parameters have been replaced with values.
|
|
7337
7425
|
*/
|
|
7338
7426
|
function resolveText({ message, messageCode, messageParams }) {
|
|
7339
|
-
return message.replace(/\{\w+\}/
|
|
7427
|
+
return message.replace(/\{\w+\}/gi, (n) => messageParams[n.substring(1, n.length - 1)]);
|
|
7340
7428
|
}
|
|
7341
7429
|
|
|
7342
7430
|
/** Get style based on styleHint (for provider branding, etc.) */
|
|
@@ -7423,13 +7511,13 @@ function LoginDialog({ title, alerts, fields, options, submitLabel, cancelLabel,
|
|
|
7423
7511
|
alerts.map((alert, idx) => (_$1("div", { key: idx },
|
|
7424
7512
|
_$1("p", { style: Styles.Alert[alert.type] }, resolveText(alert)),
|
|
7425
7513
|
alert.copyText && _$1(CopyButton, { text: alert.copyText })))),
|
|
7426
|
-
hasOptions && (_$1("div", { class: "dxc-options" }, hasMultipleGroups
|
|
7427
|
-
|
|
7428
|
-
|
|
7429
|
-
|
|
7430
|
-
|
|
7431
|
-
|
|
7432
|
-
|
|
7514
|
+
hasOptions && (_$1("div", { class: "dxc-options" }, hasMultipleGroups
|
|
7515
|
+
? // Render with dividers between groups
|
|
7516
|
+
Array.from(optionGroups.entries()).map(([groupName, groupOptions], groupIdx) => (_$1(k$1, { key: groupName },
|
|
7517
|
+
groupIdx > 0 && _$1(Divider, null),
|
|
7518
|
+
groupOptions.map((option) => (_$1(OptionButton, { key: `${option.name}-${option.value}`, option: option, onClick: () => handleOptionClick(option) }))))))
|
|
7519
|
+
: // Simple case: all options in one group
|
|
7520
|
+
options.map((option) => (_$1(OptionButton, { key: `${option.name}-${option.value}`, option: option, onClick: () => handleOptionClick(option) }))))),
|
|
7433
7521
|
hasOptions && hasFields && _$1(Divider, null),
|
|
7434
7522
|
hasFields && (_$1("form", { onSubmit: (ev) => {
|
|
7435
7523
|
ev.preventDefault();
|
|
@@ -7441,7 +7529,8 @@ function LoginDialog({ title, alerts, fields, options, submitLabel, cancelLabel,
|
|
|
7441
7529
|
const value = valueTransformer(type, (_a = ev.target) === null || _a === void 0 ? void 0 : _a['value']);
|
|
7442
7530
|
let updatedParams = Object.assign(Object.assign({}, params), { [fieldName]: value });
|
|
7443
7531
|
setParams(updatedParams);
|
|
7444
|
-
if (type === 'otp' &&
|
|
7532
|
+
if (type === 'otp' &&
|
|
7533
|
+
(value === null || value === void 0 ? void 0 : value.trim().length) === OTP_LENGTH) {
|
|
7445
7534
|
// Auto-submit when OTP is filled in.
|
|
7446
7535
|
onSubmit(updatedParams);
|
|
7447
7536
|
}
|
|
@@ -7483,7 +7572,10 @@ function CopyButton({ text }) {
|
|
|
7483
7572
|
const handleClick = () => {
|
|
7484
7573
|
var _a;
|
|
7485
7574
|
if (typeof navigator !== 'undefined' && ((_a = navigator.clipboard) === null || _a === void 0 ? void 0 : _a.writeText)) {
|
|
7486
|
-
navigator.clipboard
|
|
7575
|
+
navigator.clipboard
|
|
7576
|
+
.writeText(text)
|
|
7577
|
+
.then(scheduleCopiedReset)
|
|
7578
|
+
.catch(() => {
|
|
7487
7579
|
fallbackCopy(text, scheduleCopiedReset);
|
|
7488
7580
|
});
|
|
7489
7581
|
}
|
|
@@ -7554,7 +7646,7 @@ function setupDefaultGUI(db) {
|
|
|
7554
7646
|
},
|
|
7555
7647
|
get closed() {
|
|
7556
7648
|
return closed;
|
|
7557
|
-
}
|
|
7649
|
+
},
|
|
7558
7650
|
};
|
|
7559
7651
|
}
|
|
7560
7652
|
|
|
@@ -7599,14 +7691,14 @@ function computeSyncState(db) {
|
|
|
7599
7691
|
lazyWebSocketStatus,
|
|
7600
7692
|
db.syncStateChangedEvent.pipe(startWith({ phase: 'initial' })),
|
|
7601
7693
|
getCurrentUserEmitter(db.dx._novip),
|
|
7602
|
-
userIsReallyActive
|
|
7694
|
+
userIsReallyActive,
|
|
7603
7695
|
]).pipe(map(([status, syncState, user, userIsActive]) => {
|
|
7604
7696
|
var _a;
|
|
7605
7697
|
if (((_a = user.license) === null || _a === void 0 ? void 0 : _a.status) && user.license.status !== 'ok') {
|
|
7606
7698
|
return {
|
|
7607
7699
|
phase: 'offline',
|
|
7608
7700
|
status: 'offline',
|
|
7609
|
-
license: user.license.status
|
|
7701
|
+
license: user.license.status,
|
|
7610
7702
|
};
|
|
7611
7703
|
}
|
|
7612
7704
|
let { phase, error, progress } = syncState;
|
|
@@ -7626,7 +7718,8 @@ function computeSyncState(db) {
|
|
|
7626
7718
|
}
|
|
7627
7719
|
const previousPhase = db.cloud.syncState.value.phase;
|
|
7628
7720
|
//const previousStatus = db.cloud.syncState.value.status;
|
|
7629
|
-
if (previousPhase === 'error' &&
|
|
7721
|
+
if (previousPhase === 'error' &&
|
|
7722
|
+
(syncState.phase === 'pushing' || syncState.phase === 'pulling')) {
|
|
7630
7723
|
// We were in an errored state but is now doing sync. Show "connecting" icon.
|
|
7631
7724
|
adjustedStatus = 'connecting';
|
|
7632
7725
|
}
|
|
@@ -7641,7 +7734,7 @@ function computeSyncState(db) {
|
|
|
7641
7734
|
error,
|
|
7642
7735
|
progress,
|
|
7643
7736
|
status: isOnline ? adjustedStatus : 'offline',
|
|
7644
|
-
license: 'ok'
|
|
7737
|
+
license: 'ok',
|
|
7645
7738
|
};
|
|
7646
7739
|
return retState;
|
|
7647
7740
|
}));
|
|
@@ -7662,7 +7755,7 @@ function createSharedValueObservable(o, defaultValue) {
|
|
|
7662
7755
|
},
|
|
7663
7756
|
complete() {
|
|
7664
7757
|
observer.complete();
|
|
7665
|
-
}
|
|
7758
|
+
},
|
|
7666
7759
|
});
|
|
7667
7760
|
if (!didEmit && !subscription.closed) {
|
|
7668
7761
|
observer.next(currentValue);
|
|
@@ -7903,7 +7996,9 @@ function permissions(dexie, obj, tableName) {
|
|
|
7903
7996
|
const realm = permissionsLookup[realmId || dexie.cloud.currentUserId];
|
|
7904
7997
|
if (!realm)
|
|
7905
7998
|
return new PermissionChecker({}, tableName, !owner || owner === dexie.cloud.currentUserId);
|
|
7906
|
-
return new PermissionChecker(realm.permissions, tableName, realmId === undefined ||
|
|
7999
|
+
return new PermissionChecker(realm.permissions, tableName, realmId === undefined ||
|
|
8000
|
+
realmId === dexie.cloud.currentUserId ||
|
|
8001
|
+
owner === dexie.cloud.currentUserId);
|
|
7907
8002
|
};
|
|
7908
8003
|
const o = source.pipe(map(mapper));
|
|
7909
8004
|
o.getValue = () => mapper(source.getValue());
|
|
@@ -7945,7 +8040,19 @@ function createYHandler(db) {
|
|
|
7945
8040
|
return; // The table that holds the doc is not marked for sync - leave it to dexie. No syncing, no awareness.
|
|
7946
8041
|
}
|
|
7947
8042
|
let awareness;
|
|
8043
|
+
const existingDescriptor = Object.getOwnPropertyDescriptor(provider, 'awareness');
|
|
8044
|
+
if (existingDescriptor) {
|
|
8045
|
+
// Provider already initialized — likely a leaked handler from a previous db instance
|
|
8046
|
+
// (e.g. HMR where db.close() didn't fire). Destroy the stale awareness so the new
|
|
8047
|
+
// handler can take over cleanly.
|
|
8048
|
+
const staleAwareness = provider.awareness;
|
|
8049
|
+
if (staleAwareness) {
|
|
8050
|
+
staleAwareness.destroy();
|
|
8051
|
+
awarenessWeakMap.delete(doc);
|
|
8052
|
+
}
|
|
8053
|
+
}
|
|
7948
8054
|
Object.defineProperty(provider, 'awareness', {
|
|
8055
|
+
configurable: true,
|
|
7949
8056
|
get() {
|
|
7950
8057
|
if (awareness)
|
|
7951
8058
|
return awareness;
|
|
@@ -8128,10 +8235,12 @@ function parseOAuthCallback(url) {
|
|
|
8128
8235
|
const { code, provider, state, error } = payload;
|
|
8129
8236
|
// Check for error first
|
|
8130
8237
|
if (error) {
|
|
8131
|
-
if (error.toLowerCase().includes('access_denied') ||
|
|
8238
|
+
if (error.toLowerCase().includes('access_denied') ||
|
|
8239
|
+
error.toLowerCase().includes('access denied')) {
|
|
8132
8240
|
throw new OAuthError('access_denied', provider, error);
|
|
8133
8241
|
}
|
|
8134
|
-
if (error.toLowerCase().includes('email') &&
|
|
8242
|
+
if (error.toLowerCase().includes('email') &&
|
|
8243
|
+
error.toLowerCase().includes('verif')) {
|
|
8135
8244
|
throw new OAuthError('email_not_verified', provider, error);
|
|
8136
8245
|
}
|
|
8137
8246
|
throw new OAuthError('provider_error', provider, error);
|
|
@@ -8157,7 +8266,9 @@ function cleanupOAuthUrl() {
|
|
|
8157
8266
|
return;
|
|
8158
8267
|
}
|
|
8159
8268
|
url.searchParams.delete('dxc-auth');
|
|
8160
|
-
const cleanUrl = url.pathname +
|
|
8269
|
+
const cleanUrl = url.pathname +
|
|
8270
|
+
(url.searchParams.toString() ? `?${url.searchParams.toString()}` : '') +
|
|
8271
|
+
url.hash;
|
|
8161
8272
|
window.history.replaceState(null, '', cleanUrl);
|
|
8162
8273
|
}
|
|
8163
8274
|
|
|
@@ -8206,7 +8317,7 @@ function dexieCloud(dexie) {
|
|
|
8206
8317
|
const downloading$ = createDownloadingState();
|
|
8207
8318
|
dexie.cloud = {
|
|
8208
8319
|
// @ts-ignore
|
|
8209
|
-
version: "4.4.
|
|
8320
|
+
version: "4.4.7",
|
|
8210
8321
|
options: Object.assign({}, DEFAULT_OPTIONS),
|
|
8211
8322
|
schema: null,
|
|
8212
8323
|
get currentUserId() {
|
|
@@ -8262,7 +8373,10 @@ function dexieCloud(dexie) {
|
|
|
8262
8373
|
const callback = parseOAuthCallback();
|
|
8263
8374
|
if (callback) {
|
|
8264
8375
|
// Store the pending auth code for processing when db is ready
|
|
8265
|
-
pendingOAuthCode = {
|
|
8376
|
+
pendingOAuthCode = {
|
|
8377
|
+
code: callback.code,
|
|
8378
|
+
provider: callback.provider,
|
|
8379
|
+
};
|
|
8266
8380
|
console.debug('[dexie-cloud] OAuth callback detected, auth code stored for processing');
|
|
8267
8381
|
}
|
|
8268
8382
|
}
|
|
@@ -8379,7 +8493,7 @@ function dexieCloud(dexie) {
|
|
|
8379
8493
|
if (eagerBlobDownloadInFlight)
|
|
8380
8494
|
return;
|
|
8381
8495
|
eagerBlobDownloadInFlight = Dexie.ignoreTransaction(() => downloadUnresolvedBlobs(db, downloading$))
|
|
8382
|
-
.catch(err => {
|
|
8496
|
+
.catch((err) => {
|
|
8383
8497
|
console.error('[dexie-cloud] Eager blob download failed:', err);
|
|
8384
8498
|
})
|
|
8385
8499
|
.finally(() => {
|
|
@@ -8472,7 +8586,10 @@ function dexieCloud(dexie) {
|
|
|
8472
8586
|
// Let's assign all props as the newPersistedSchems should be what we should be working with.
|
|
8473
8587
|
Object.assign(schema, newPersistedSchema);
|
|
8474
8588
|
}
|
|
8475
|
-
return [
|
|
8589
|
+
return [
|
|
8590
|
+
persistedSyncState === null || persistedSyncState === void 0 ? void 0 : persistedSyncState.initiallySynced,
|
|
8591
|
+
persistedSyncState === null || persistedSyncState === void 0 ? void 0 : persistedSyncState.realms,
|
|
8592
|
+
];
|
|
8476
8593
|
}));
|
|
8477
8594
|
if (initiallySynced) {
|
|
8478
8595
|
db.setInitiallySynced(true);
|
|
@@ -8481,8 +8598,10 @@ function dexieCloud(dexie) {
|
|
|
8481
8598
|
// Manage CurrentUser observable:
|
|
8482
8599
|
throwIfClosed();
|
|
8483
8600
|
if (!db.cloud.isServiceWorkerDB) {
|
|
8484
|
-
subscriptions.push(liveQuery(() => db.getCurrentUser().then(user => {
|
|
8485
|
-
if (!user.isLoggedIn &&
|
|
8601
|
+
subscriptions.push(liveQuery(() => db.getCurrentUser().then((user) => {
|
|
8602
|
+
if (!user.isLoggedIn &&
|
|
8603
|
+
typeof location !== 'undefined' &&
|
|
8604
|
+
/dxc-auth\=/.test(location.search)) {
|
|
8486
8605
|
// Still loading user because OAuth redirect just happened.
|
|
8487
8606
|
// Keep isLoading true.
|
|
8488
8607
|
return Object.assign(Object.assign({}, user), { isLoading: true });
|
|
@@ -8520,7 +8639,7 @@ function dexieCloud(dexie) {
|
|
|
8520
8639
|
type: 'error',
|
|
8521
8640
|
messageCode: 'GENERIC_ERROR',
|
|
8522
8641
|
message: error.message,
|
|
8523
|
-
messageParams: { provider: error.provider || 'unknown' }
|
|
8642
|
+
messageParams: { provider: error.provider || 'unknown' },
|
|
8524
8643
|
});
|
|
8525
8644
|
// Clean up URL (remove dxc-auth param)
|
|
8526
8645
|
cleanupOAuthUrl();
|
|
@@ -8570,7 +8689,8 @@ function dexieCloud(dexie) {
|
|
|
8570
8689
|
}
|
|
8571
8690
|
}
|
|
8572
8691
|
}
|
|
8573
|
-
if (user.isLoggedIn &&
|
|
8692
|
+
if (user.isLoggedIn &&
|
|
8693
|
+
(!lastSyncedRealms || !lastSyncedRealms.includes(user.userId))) {
|
|
8574
8694
|
// User has been logged in but this is not reflected in the sync state.
|
|
8575
8695
|
// This can happen if page is reloaded after login but before the sync call following
|
|
8576
8696
|
// the login was complete.
|
|
@@ -8633,7 +8753,7 @@ function dexieCloud(dexie) {
|
|
|
8633
8753
|
}
|
|
8634
8754
|
}
|
|
8635
8755
|
// @ts-ignore
|
|
8636
|
-
dexieCloud.version = "4.4.
|
|
8756
|
+
dexieCloud.version = "4.4.7";
|
|
8637
8757
|
Dexie.Cloud = dexieCloud;
|
|
8638
8758
|
|
|
8639
8759
|
// In case the SW lives for a while, let it reuse already opened connections:
|
|
@@ -8725,14 +8845,14 @@ if (!DISABLE_SERVICEWORKER_STRATEGY) {
|
|
|
8725
8845
|
console.debug('SW "sync" Event', event.tag);
|
|
8726
8846
|
const dbName = getDbNameFromTag(event.tag);
|
|
8727
8847
|
if (dbName) {
|
|
8728
|
-
event.waitUntil(syncDB(dbName,
|
|
8848
|
+
event.waitUntil(syncDB(dbName, 'push')); // The purpose of sync events are "push"
|
|
8729
8849
|
}
|
|
8730
8850
|
});
|
|
8731
8851
|
self.addEventListener('periodicsync', (event) => {
|
|
8732
8852
|
console.debug('SW "periodicsync" Event', event.tag);
|
|
8733
8853
|
const dbName = getDbNameFromTag(event.tag);
|
|
8734
8854
|
if (dbName) {
|
|
8735
|
-
event.waitUntil(syncDB(dbName,
|
|
8855
|
+
event.waitUntil(syncDB(dbName, 'pull')); // The purpose of periodic sync events are "pull"
|
|
8736
8856
|
}
|
|
8737
8857
|
});
|
|
8738
8858
|
self.addEventListener('message', (event) => {
|
|
@@ -8742,7 +8862,7 @@ if (!DISABLE_SERVICEWORKER_STRATEGY) {
|
|
|
8742
8862
|
// Mimic background sync behavior - retry in X minutes on failure.
|
|
8743
8863
|
// But lesser timeout and more number of times.
|
|
8744
8864
|
const syncAndRetry = (num = 1) => {
|
|
8745
|
-
return syncDB(dbName, event.data.purpose ||
|
|
8865
|
+
return syncDB(dbName, event.data.purpose || 'pull').catch((e) => __awaiter(void 0, void 0, void 0, function* () {
|
|
8746
8866
|
if (num === 3)
|
|
8747
8867
|
throw e;
|
|
8748
8868
|
yield sleep(60000); // 1 minute
|
|
@@ -8750,10 +8870,10 @@ if (!DISABLE_SERVICEWORKER_STRATEGY) {
|
|
|
8750
8870
|
}));
|
|
8751
8871
|
};
|
|
8752
8872
|
if ('waitUntil' in event) {
|
|
8753
|
-
event.waitUntil(syncAndRetry().catch(error => console.error(error)));
|
|
8873
|
+
event.waitUntil(syncAndRetry().catch((error) => console.error(error)));
|
|
8754
8874
|
}
|
|
8755
8875
|
else {
|
|
8756
|
-
syncAndRetry().catch(error => console.error(error));
|
|
8876
|
+
syncAndRetry().catch((error) => console.error(error));
|
|
8757
8877
|
}
|
|
8758
8878
|
}
|
|
8759
8879
|
});
|