dexie-cloud-addon 4.4.6 → 4.4.8
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 +653 -531
- 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 +655 -533
- 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 +7 -4
- 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 +661 -539
- 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 +663 -541
- 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 +2 -2
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*
|
|
9
9
|
* ==========================================================================
|
|
10
10
|
*
|
|
11
|
-
* Version 4.4.
|
|
11
|
+
* Version 4.4.8, Tue Mar 31 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
|
/**
|
|
@@ -2914,10 +2941,7 @@ function applyServerChanges(changes, db) {
|
|
|
2914
2941
|
const DEXIE_CLOUD_SYNCER_ID = 'dexie-cloud-syncer';
|
|
2915
2942
|
|
|
2916
2943
|
function listUpdatesSince(yTable, sinceIncluding) {
|
|
2917
|
-
return yTable
|
|
2918
|
-
.where('i')
|
|
2919
|
-
.between(sinceIncluding, Infinity, true)
|
|
2920
|
-
.toArray();
|
|
2944
|
+
return yTable.where('i').between(sinceIncluding, Infinity, true).toArray();
|
|
2921
2945
|
}
|
|
2922
2946
|
|
|
2923
2947
|
/** Queries the local database for YMessages to send to server.
|
|
@@ -3012,7 +3036,7 @@ function listYClientMessagesAndStateVector(db, tablesToSync) {
|
|
|
3012
3036
|
}
|
|
3013
3037
|
return {
|
|
3014
3038
|
yMessages: result,
|
|
3015
|
-
lastUpdateIds
|
|
3039
|
+
lastUpdateIds,
|
|
3016
3040
|
};
|
|
3017
3041
|
});
|
|
3018
3042
|
}
|
|
@@ -3021,7 +3045,8 @@ function getUpdatesTable(db, table, ydocProp) {
|
|
|
3021
3045
|
var _a, _b, _c;
|
|
3022
3046
|
if (!db.dx._allTables[table])
|
|
3023
3047
|
return undefined;
|
|
3024
|
-
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;
|
|
3025
3050
|
if (!utbl) {
|
|
3026
3051
|
console.debug(`No updatesTable found for ${table}.${ydocProp}`);
|
|
3027
3052
|
return undefined;
|
|
@@ -3154,10 +3179,18 @@ const blobEndpointSupported = new Map();
|
|
|
3154
3179
|
*/
|
|
3155
3180
|
// TypedArray/DataView tags for size check
|
|
3156
3181
|
const ARRAYBUFFER_VIEW_TAGS = new Set([
|
|
3157
|
-
'Int8Array',
|
|
3158
|
-
'
|
|
3159
|
-
'
|
|
3160
|
-
'
|
|
3182
|
+
'Int8Array',
|
|
3183
|
+
'Uint8Array',
|
|
3184
|
+
'Uint8ClampedArray',
|
|
3185
|
+
'Int16Array',
|
|
3186
|
+
'Uint16Array',
|
|
3187
|
+
'Int32Array',
|
|
3188
|
+
'Uint32Array',
|
|
3189
|
+
'Float32Array',
|
|
3190
|
+
'Float64Array',
|
|
3191
|
+
'BigInt64Array',
|
|
3192
|
+
'BigUint64Array',
|
|
3193
|
+
'DataView',
|
|
3161
3194
|
]);
|
|
3162
3195
|
// Static Set for O(1) lookup of binary type tags
|
|
3163
3196
|
const BINARY_TYPE_TAGS = new Set([
|
|
@@ -3257,7 +3290,7 @@ function uploadBlob(databaseUrl, getCachedAccessToken, blob) {
|
|
|
3257
3290
|
const response = yield fetch(uploadUrl, {
|
|
3258
3291
|
method: 'PUT',
|
|
3259
3292
|
headers: {
|
|
3260
|
-
|
|
3293
|
+
Authorization: `Bearer ${accessToken}`,
|
|
3261
3294
|
'Content-Type': contentType,
|
|
3262
3295
|
},
|
|
3263
3296
|
body,
|
|
@@ -3273,8 +3306,7 @@ function uploadBlob(databaseUrl, getCachedAccessToken, blob) {
|
|
|
3273
3306
|
// The server returns the ref with version prefix (e.g., "1:blobId")
|
|
3274
3307
|
const result = yield response.json();
|
|
3275
3308
|
// Return BlobRef with server's ref (includes version) and original type preserved in _bt
|
|
3276
|
-
return Object.assign({ _bt: origType, ref: result.ref, size: size }, (origType === 'Blob' ? { ct: contentType } : {})
|
|
3277
|
-
);
|
|
3309
|
+
return Object.assign({ _bt: origType, ref: result.ref, size: size }, (origType === 'Blob' ? { ct: contentType } : {}));
|
|
3278
3310
|
});
|
|
3279
3311
|
}
|
|
3280
3312
|
function offloadBlobsAndMarkDirty(obj_1, databaseUrl_1, getCachedAccessToken_1) {
|
|
@@ -3282,7 +3314,10 @@ function offloadBlobsAndMarkDirty(obj_1, databaseUrl_1, getCachedAccessToken_1)
|
|
|
3282
3314
|
const dirtyFlag = { dirty: false };
|
|
3283
3315
|
const result = yield offloadBlobs(obj, databaseUrl, getCachedAccessToken, maxStringLength, dirtyFlag);
|
|
3284
3316
|
// Mark the object as dirty for sync if any blobs were offloaded
|
|
3285
|
-
if (dirtyFlag.dirty &&
|
|
3317
|
+
if (dirtyFlag.dirty &&
|
|
3318
|
+
typeof result === 'object' &&
|
|
3319
|
+
result !== null &&
|
|
3320
|
+
result.constructor === Object) {
|
|
3286
3321
|
result._hasBlobRefs = 1;
|
|
3287
3322
|
}
|
|
3288
3323
|
return result;
|
|
@@ -3298,7 +3333,9 @@ function offloadBlobs(obj_1, databaseUrl_1, getCachedAccessToken_1) {
|
|
|
3298
3333
|
return obj;
|
|
3299
3334
|
}
|
|
3300
3335
|
// Check if this is a long string that should be offloaded
|
|
3301
|
-
if (typeof obj === 'string' &&
|
|
3336
|
+
if (typeof obj === 'string' &&
|
|
3337
|
+
obj.length > maxStringLength &&
|
|
3338
|
+
maxStringLength !== Infinity) {
|
|
3302
3339
|
if (blobEndpointSupported.get(databaseUrl) === false) {
|
|
3303
3340
|
return obj;
|
|
3304
3341
|
}
|
|
@@ -3384,11 +3421,11 @@ function offloadBlobsInOperation(op_1, databaseUrl_1, getCachedAccessToken_1) {
|
|
|
3384
3421
|
switch (op.type) {
|
|
3385
3422
|
case 'insert':
|
|
3386
3423
|
case 'upsert': {
|
|
3387
|
-
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)));
|
|
3388
3425
|
return Object.assign(Object.assign({}, op), { values: processedValues });
|
|
3389
3426
|
}
|
|
3390
3427
|
case 'update': {
|
|
3391
|
-
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)));
|
|
3392
3429
|
return Object.assign(Object.assign({}, op), { changeSpecs: processedChangeSpecs });
|
|
3393
3430
|
}
|
|
3394
3431
|
case 'modify': {
|
|
@@ -3421,9 +3458,9 @@ function hasLargeBlobsInOperation(op, maxStringLength) {
|
|
|
3421
3458
|
switch (op.type) {
|
|
3422
3459
|
case 'insert':
|
|
3423
3460
|
case 'upsert':
|
|
3424
|
-
return op.values.some(value => hasLargeBlobs(value, maxStringLength));
|
|
3461
|
+
return op.values.some((value) => hasLargeBlobs(value, maxStringLength));
|
|
3425
3462
|
case 'update':
|
|
3426
|
-
return op.changeSpecs.some(spec => hasLargeBlobs(spec, maxStringLength));
|
|
3463
|
+
return op.changeSpecs.some((spec) => hasLargeBlobs(spec, maxStringLength));
|
|
3427
3464
|
case 'modify':
|
|
3428
3465
|
return hasLargeBlobs(op.changeSpec, maxStringLength);
|
|
3429
3466
|
default:
|
|
@@ -3435,7 +3472,9 @@ function hasLargeBlobs(obj, maxStringLength, visited = new WeakSet()) {
|
|
|
3435
3472
|
return false;
|
|
3436
3473
|
}
|
|
3437
3474
|
// Check long strings
|
|
3438
|
-
if (typeof obj === 'string' &&
|
|
3475
|
+
if (typeof obj === 'string' &&
|
|
3476
|
+
obj.length > maxStringLength &&
|
|
3477
|
+
maxStringLength !== Infinity) {
|
|
3439
3478
|
return true;
|
|
3440
3479
|
}
|
|
3441
3480
|
if (shouldOffloadBlob(obj)) {
|
|
@@ -3450,13 +3489,13 @@ function hasLargeBlobs(obj, maxStringLength, visited = new WeakSet()) {
|
|
|
3450
3489
|
}
|
|
3451
3490
|
visited.add(obj);
|
|
3452
3491
|
if (Array.isArray(obj)) {
|
|
3453
|
-
return obj.some(item => hasLargeBlobs(item, maxStringLength, visited));
|
|
3492
|
+
return obj.some((item) => hasLargeBlobs(item, maxStringLength, visited));
|
|
3454
3493
|
}
|
|
3455
3494
|
// Traverse plain objects (POJO-like) - use duck typing since IndexedDB
|
|
3456
3495
|
// may return objects where constructor !== Object
|
|
3457
3496
|
const proto = Object.getPrototypeOf(obj);
|
|
3458
3497
|
if (proto === Object.prototype || proto === null) {
|
|
3459
|
-
return Object.values(obj).some(value => hasLargeBlobs(value, maxStringLength, visited));
|
|
3498
|
+
return Object.values(obj).some((value) => hasLargeBlobs(value, maxStringLength, visited));
|
|
3460
3499
|
}
|
|
3461
3500
|
return false;
|
|
3462
3501
|
}
|
|
@@ -3510,7 +3549,7 @@ function updateYSyncStates(lastUpdateIdsBeforeSync, receivedUntilsAfterSync, db)
|
|
|
3510
3549
|
yield db.table(yTable).add({
|
|
3511
3550
|
i: DEXIE_CLOUD_SYNCER_ID,
|
|
3512
3551
|
unsentFrom,
|
|
3513
|
-
receivedUntil
|
|
3552
|
+
receivedUntil,
|
|
3514
3553
|
});
|
|
3515
3554
|
}
|
|
3516
3555
|
else {
|
|
@@ -3650,19 +3689,30 @@ function loadCachedAccessToken(db) {
|
|
|
3650
3689
|
return Promise.resolve(cached.accessToken);
|
|
3651
3690
|
}
|
|
3652
3691
|
const currentUser = db.cloud.currentUser.value;
|
|
3653
|
-
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) {
|
|
3654
3696
|
wm$3.set(db, {
|
|
3655
3697
|
accessToken: currentUser.accessToken,
|
|
3656
|
-
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,
|
|
3657
3699
|
});
|
|
3658
3700
|
return Promise.resolve(currentUser.accessToken);
|
|
3659
3701
|
}
|
|
3660
|
-
|
|
3702
|
+
// If the current user is not logged in (no isLoggedIn flag), there's no
|
|
3703
|
+
// token to load from the database — skip the Dexie.ignoreTransaction() call.
|
|
3704
|
+
// This avoids a crash in service worker context where Dexie's Promise zone
|
|
3705
|
+
// (PSD.transless.env) may be undefined when called from within an active
|
|
3706
|
+
// rw transaction (e.g. during applyServerChanges).
|
|
3707
|
+
if (!(currentUser === null || currentUser === void 0 ? void 0 : currentUser.isLoggedIn)) {
|
|
3708
|
+
return Promise.resolve(null);
|
|
3709
|
+
}
|
|
3710
|
+
return Dexie.ignoreTransaction(() => loadAccessToken(db).then((user) => {
|
|
3661
3711
|
var _a, _b;
|
|
3662
3712
|
if (user === null || user === void 0 ? void 0 : user.accessToken) {
|
|
3663
3713
|
wm$3.set(db, {
|
|
3664
3714
|
accessToken: user.accessToken,
|
|
3665
|
-
expiration: (_b = (_a = user.accessTokenExpiration) === null || _a === void 0 ? void 0 : _a.getTime()) !== null && _b !== void 0 ? _b : Infinity
|
|
3715
|
+
expiration: (_b = (_a = user.accessTokenExpiration) === null || _a === void 0 ? void 0 : _a.getTime()) !== null && _b !== void 0 ? _b : Infinity,
|
|
3666
3716
|
});
|
|
3667
3717
|
}
|
|
3668
3718
|
return (user === null || user === void 0 ? void 0 : user.accessToken) || null;
|
|
@@ -3673,7 +3723,8 @@ const CURRENT_SYNC_WORKER = 'currentSyncWorker';
|
|
|
3673
3723
|
function sync(db, options, schema, syncOptions) {
|
|
3674
3724
|
return _sync(db, options, schema, syncOptions)
|
|
3675
3725
|
.then((result) => {
|
|
3676
|
-
if (!(syncOptions === null || syncOptions === void 0 ? void 0 : syncOptions.justCheckIfNeeded)) {
|
|
3726
|
+
if (!(syncOptions === null || syncOptions === void 0 ? void 0 : syncOptions.justCheckIfNeeded)) {
|
|
3727
|
+
// && syncOptions?.purpose !== 'push') {
|
|
3677
3728
|
db.syncStateChangedEvent.next({
|
|
3678
3729
|
phase: 'in-sync',
|
|
3679
3730
|
});
|
|
@@ -3760,7 +3811,7 @@ function _sync(db_1, options_1, schema_1) {
|
|
|
3760
3811
|
const syncState = yield db.getPersistedSyncState();
|
|
3761
3812
|
let baseRevs = yield db.$baseRevs.toArray();
|
|
3762
3813
|
// Resolve #2168
|
|
3763
|
-
baseRevs = baseRevs.filter(br => tablesToSync.some(tbl => tbl.name === br.tableName));
|
|
3814
|
+
baseRevs = baseRevs.filter((br) => tablesToSync.some((tbl) => tbl.name === br.tableName));
|
|
3764
3815
|
let clientChanges = yield listClientChanges(mutationTables, db);
|
|
3765
3816
|
const yResults = yield listYClientMessagesAndStateVector(db, tablesToSync);
|
|
3766
3817
|
throwIfCancelled(cancelToken);
|
|
@@ -3776,7 +3827,7 @@ function _sync(db_1, options_1, schema_1) {
|
|
|
3776
3827
|
}
|
|
3777
3828
|
return [clientChanges, syncState, baseRevs, yResults];
|
|
3778
3829
|
}));
|
|
3779
|
-
const pushSyncIsNeeded = clientChangeSet.some((set) => set.muts.some((mut) => mut.keys.length > 0)) || yMessages.some(m => m.type === 'u-c');
|
|
3830
|
+
const pushSyncIsNeeded = clientChangeSet.some((set) => set.muts.some((mut) => mut.keys.length > 0)) || yMessages.some((m) => m.type === 'u-c');
|
|
3780
3831
|
if (justCheckIfNeeded) {
|
|
3781
3832
|
console.debug('Sync is needed:', pushSyncIsNeeded);
|
|
3782
3833
|
return pushSyncIsNeeded;
|
|
@@ -3920,7 +3971,7 @@ function _sync(db_1, options_1, schema_1) {
|
|
|
3920
3971
|
db.$syncState.put(newSyncState, 'syncState');
|
|
3921
3972
|
return {
|
|
3922
3973
|
done: addedClientChanges.length === 0,
|
|
3923
|
-
newSyncState
|
|
3974
|
+
newSyncState,
|
|
3924
3975
|
};
|
|
3925
3976
|
}));
|
|
3926
3977
|
if (!done) {
|
|
@@ -3928,7 +3979,7 @@ function _sync(db_1, options_1, schema_1) {
|
|
|
3928
3979
|
yield checkSyncRateLimitDelay(db);
|
|
3929
3980
|
return yield _sync(db, options, schema, { isInitialSync, cancelToken });
|
|
3930
3981
|
}
|
|
3931
|
-
const usingYProps = Object.values(schema).some(tbl => { var _a; return (_a = tbl.yProps) === null || _a === void 0 ? void 0 : _a.length; });
|
|
3982
|
+
const usingYProps = Object.values(schema).some((tbl) => { var _a; return (_a = tbl.yProps) === null || _a === void 0 ? void 0 : _a.length; });
|
|
3932
3983
|
const serverSupportsYprops = !!res.yMessages;
|
|
3933
3984
|
if (usingYProps && serverSupportsYprops) {
|
|
3934
3985
|
try {
|
|
@@ -4235,11 +4286,14 @@ class BlobDownloadTracker {
|
|
|
4235
4286
|
download(blobRef, dbUrl) {
|
|
4236
4287
|
let promise = this.inFlight.get(blobRef.ref);
|
|
4237
4288
|
if (!promise) {
|
|
4238
|
-
promise = loadCachedAccessToken(this.db)
|
|
4239
|
-
|
|
4240
|
-
|
|
4289
|
+
promise = loadCachedAccessToken(this.db)
|
|
4290
|
+
.then((accessToken) => {
|
|
4291
|
+
// accessToken may be null for anonymous/unauthenticated users.
|
|
4292
|
+
// Public realm blobs (rlm-public) are accessible without auth.
|
|
4293
|
+
// downloadBlob will omit the Authorization header when token is null.
|
|
4241
4294
|
return downloadBlob(blobRef, dbUrl, accessToken);
|
|
4242
|
-
})
|
|
4295
|
+
})
|
|
4296
|
+
.finally(() => this.inFlight.delete(blobRef.ref));
|
|
4243
4297
|
// When the promise settles (either fulfilled or rejected), remove it from the in-flight map
|
|
4244
4298
|
this.inFlight.set(blobRef.ref, promise);
|
|
4245
4299
|
}
|
|
@@ -4249,19 +4303,22 @@ class BlobDownloadTracker {
|
|
|
4249
4303
|
/**
|
|
4250
4304
|
* Download blob data from server via proxy endpoint.
|
|
4251
4305
|
* Uses auth header for authentication (same as sync).
|
|
4306
|
+
* When accessToken is null, the request is made without Authorization header —
|
|
4307
|
+
* this allows downloading blobs from public realms (rlm-public) for
|
|
4308
|
+
* unauthenticated users.
|
|
4252
4309
|
*
|
|
4253
4310
|
* @param blobRef - The BlobRef to download
|
|
4254
4311
|
* @param dbUrl - Base URL for the database (e.g., 'https://mydb.dexie.cloud')
|
|
4255
|
-
* @param accessToken - Access token for authentication
|
|
4312
|
+
* @param accessToken - Access token for authentication, or null for anonymous access
|
|
4256
4313
|
*/
|
|
4257
4314
|
function downloadBlob(blobRef, dbUrl, accessToken) {
|
|
4258
4315
|
return __awaiter(this, void 0, void 0, function* () {
|
|
4259
4316
|
const downloadUrl = `${dbUrl}/blob/${blobRef.ref}`;
|
|
4260
|
-
const
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
});
|
|
4317
|
+
const headers = {};
|
|
4318
|
+
if (accessToken) {
|
|
4319
|
+
headers['Authorization'] = `Bearer ${accessToken}`;
|
|
4320
|
+
}
|
|
4321
|
+
const response = yield fetch(downloadUrl, { headers });
|
|
4265
4322
|
if (!response.ok) {
|
|
4266
4323
|
throw new Error(`Failed to download blob ${blobRef.ref}: ${response.status} ${response.statusText}`);
|
|
4267
4324
|
}
|
|
@@ -4352,7 +4409,9 @@ function DexieCloudDB(dx) {
|
|
|
4352
4409
|
return db.$syncState.get('schema').then((schema) => {
|
|
4353
4410
|
if (schema) {
|
|
4354
4411
|
for (const table of db.tables) {
|
|
4355
|
-
if (table.schema.primKey &&
|
|
4412
|
+
if (table.schema.primKey &&
|
|
4413
|
+
table.schema.primKey.keyPath &&
|
|
4414
|
+
schema[table.name]) {
|
|
4356
4415
|
schema[table.name].primaryKey = nameFromKeyPath(table.schema.primKey.keyPath);
|
|
4357
4416
|
}
|
|
4358
4417
|
}
|
|
@@ -4380,9 +4439,11 @@ function DexieCloudDB(dx) {
|
|
|
4380
4439
|
return db;
|
|
4381
4440
|
}
|
|
4382
4441
|
function nameFromKeyPath(keyPath) {
|
|
4383
|
-
return typeof keyPath === 'string'
|
|
4384
|
-
keyPath
|
|
4385
|
-
|
|
4442
|
+
return typeof keyPath === 'string'
|
|
4443
|
+
? keyPath
|
|
4444
|
+
: keyPath
|
|
4445
|
+
? '[' + [].join.call(keyPath, '+') + ']'
|
|
4446
|
+
: '';
|
|
4386
4447
|
}
|
|
4387
4448
|
|
|
4388
4449
|
/**
|
|
@@ -4440,7 +4501,7 @@ function observeBlobProgress(db, downloading$) {
|
|
|
4440
4501
|
isDownloading: isDownloading && stats.blobsRemaining > 0,
|
|
4441
4502
|
blobsRemaining: stats.blobsRemaining,
|
|
4442
4503
|
bytesRemaining: stats.bytesRemaining,
|
|
4443
|
-
})), share({ resetOnRefCountZero: () => timer(2000) }) // Keep alive for 2s after last unsubscription to avoid rapid re-subscriptions during UI updates
|
|
4504
|
+
})), share({ resetOnRefCountZero: () => timer(2000) }) // Keep alive for 2s after last unsubscription to avoid rapid re-subscriptions during UI updates
|
|
4444
4505
|
);
|
|
4445
4506
|
}
|
|
4446
4507
|
/**
|
|
@@ -4524,13 +4585,13 @@ function downloadUnresolvedBlobs(db, downloading$, signal) {
|
|
|
4524
4585
|
}
|
|
4525
4586
|
setDownloadingState(downloading$, true);
|
|
4526
4587
|
try {
|
|
4527
|
-
debugLog(`Eager download: Found ${syncedTables.length} syncable tables: ${syncedTables.map(t => t.name).join(', ')}`);
|
|
4588
|
+
debugLog(`Eager download: Found ${syncedTables.length} syncable tables: ${syncedTables.map((t) => t.name).join(', ')}`);
|
|
4528
4589
|
for (const table of syncedTables) {
|
|
4529
4590
|
if (signal === null || signal === void 0 ? void 0 : signal.aborted)
|
|
4530
4591
|
;
|
|
4531
4592
|
try {
|
|
4532
4593
|
// Check if table has _hasBlobRefs index
|
|
4533
|
-
const hasIndex = table.schema.indexes.some(idx => idx.name === '_hasBlobRefs');
|
|
4594
|
+
const hasIndex = table.schema.indexes.some((idx) => idx.name === '_hasBlobRefs');
|
|
4534
4595
|
if (!hasIndex)
|
|
4535
4596
|
continue;
|
|
4536
4597
|
// Query objects with _hasBlobRefs marker
|
|
@@ -4546,7 +4607,7 @@ function downloadUnresolvedBlobs(db, downloading$, signal) {
|
|
|
4546
4607
|
const MAX_CONCURRENT = 6;
|
|
4547
4608
|
const primaryKey = table.schema.primKey;
|
|
4548
4609
|
// Filter to actionable objects first
|
|
4549
|
-
const pending = unresolvedObjects.filter(obj => {
|
|
4610
|
+
const pending = unresolvedObjects.filter((obj) => {
|
|
4550
4611
|
if (!hasUnresolvedBlobRefs(obj))
|
|
4551
4612
|
return false;
|
|
4552
4613
|
const key = primaryKey.keyPath
|
|
@@ -4609,20 +4670,20 @@ class AuthPersistedContext {
|
|
|
4609
4670
|
}
|
|
4610
4671
|
static load(db, userId) {
|
|
4611
4672
|
return db
|
|
4612
|
-
.table(
|
|
4673
|
+
.table('$logins')
|
|
4613
4674
|
.get(userId)
|
|
4614
4675
|
.then((userLogin) => new AuthPersistedContext(db, userLogin || {
|
|
4615
4676
|
userId,
|
|
4616
4677
|
claims: {
|
|
4617
|
-
sub: userId
|
|
4678
|
+
sub: userId,
|
|
4618
4679
|
},
|
|
4619
|
-
lastLogin: new Date(0)
|
|
4680
|
+
lastLogin: new Date(0),
|
|
4620
4681
|
}));
|
|
4621
4682
|
}
|
|
4622
4683
|
save() {
|
|
4623
4684
|
return __awaiter(this, void 0, void 0, function* () {
|
|
4624
4685
|
const db = wm$1.get(this);
|
|
4625
|
-
db.table(
|
|
4686
|
+
db.table('$logins').put(this);
|
|
4626
4687
|
});
|
|
4627
4688
|
}
|
|
4628
4689
|
}
|
|
@@ -4717,7 +4778,7 @@ class OAuthError extends Error {
|
|
|
4717
4778
|
*/
|
|
4718
4779
|
function exchangeOAuthCode(options) {
|
|
4719
4780
|
return __awaiter(this, void 0, void 0, function* () {
|
|
4720
|
-
const { databaseUrl, code, publicKey, scopes = ['ACCESS_DB'], intent } = options;
|
|
4781
|
+
const { databaseUrl, code, publicKey, scopes = ['ACCESS_DB'], intent, } = options;
|
|
4721
4782
|
const tokenRequest = Object.assign({ grant_type: 'authorization_code', code, public_key: publicKey, scopes }, (intent !== undefined ? { intent } : {}));
|
|
4722
4783
|
try {
|
|
4723
4784
|
const res = yield fetch(`${databaseUrl}/token`, {
|
|
@@ -4775,7 +4836,8 @@ function exchangeOAuthCode(options) {
|
|
|
4775
4836
|
return response;
|
|
4776
4837
|
}
|
|
4777
4838
|
catch (error) {
|
|
4778
|
-
if (error instanceof OAuthError ||
|
|
4839
|
+
if (error instanceof OAuthError ||
|
|
4840
|
+
error instanceof TokenErrorResponseError) {
|
|
4779
4841
|
throw error;
|
|
4780
4842
|
}
|
|
4781
4843
|
if (error instanceof TypeError) {
|
|
@@ -4813,7 +4875,7 @@ function fetchAuthProviders(databaseUrl_1) {
|
|
|
4813
4875
|
try {
|
|
4814
4876
|
const res = yield fetch(`${databaseUrl}/auth-providers`, {
|
|
4815
4877
|
method: 'GET',
|
|
4816
|
-
headers: {
|
|
4878
|
+
headers: { Accept: 'application/json' },
|
|
4817
4879
|
mode: 'cors',
|
|
4818
4880
|
});
|
|
4819
4881
|
if (res.status === 404) {
|
|
@@ -5143,7 +5205,7 @@ function tryParsePolicyAlert(res) {
|
|
|
5143
5205
|
* @param args
|
|
5144
5206
|
*/
|
|
5145
5207
|
function prodLog(level, ...args) {
|
|
5146
|
-
globalThis[
|
|
5208
|
+
globalThis['con' + 'sole'][level](...args);
|
|
5147
5209
|
}
|
|
5148
5210
|
|
|
5149
5211
|
/** This function changes or sets the current user as requested.
|
|
@@ -5273,7 +5335,7 @@ const safariVersion = isSafari
|
|
|
5273
5335
|
const DISABLE_SERVICEWORKER_STRATEGY = (isSafari && safariVersion <= 605) || // Disable for Safari for now.
|
|
5274
5336
|
isFirefox; // Disable for Firefox for now. Seems to have a bug in reading CryptoKeys from IDB from service workers
|
|
5275
5337
|
|
|
5276
|
-
const IS_SERVICE_WORKER = typeof self !==
|
|
5338
|
+
const IS_SERVICE_WORKER = typeof self !== 'undefined' && 'clients' in self && !self.document;
|
|
5277
5339
|
|
|
5278
5340
|
function throwVersionIncrementNeeded() {
|
|
5279
5341
|
throw new Dexie.SchemaError(`Version increment needed to allow dexie-cloud change tracking`);
|
|
@@ -5519,7 +5581,7 @@ function createImplicitPropSetterMiddleware(db) {
|
|
|
5519
5581
|
// We must also degrade from consistent modify operations for the
|
|
5520
5582
|
// same reason - object might be there on server. Must but put up instead.
|
|
5521
5583
|
// FUTURE: This clumpsy behavior of private IDs could be refined later.
|
|
5522
|
-
// Suggestion is to in future, treat private IDs as we treat all objects
|
|
5584
|
+
// Suggestion is to in future, treat private IDs as we treat all objects
|
|
5523
5585
|
// and sync operations normally. Only that deletions should become soft deletes
|
|
5524
5586
|
// for them - so that server knows when a private ID has been deleted on server
|
|
5525
5587
|
// not accept insert/upserts on them.
|
|
@@ -5542,19 +5604,20 @@ function createImplicitPropSetterMiddleware(db) {
|
|
|
5542
5604
|
}
|
|
5543
5605
|
|
|
5544
5606
|
function allSettled(possiblePromises) {
|
|
5545
|
-
return new Promise(resolve => {
|
|
5607
|
+
return new Promise((resolve) => {
|
|
5546
5608
|
if (possiblePromises.length === 0)
|
|
5547
5609
|
resolve([]);
|
|
5548
5610
|
let remaining = possiblePromises.length;
|
|
5549
5611
|
const results = new Array(remaining);
|
|
5550
|
-
possiblePromises.forEach((p, i) => Promise.resolve(p)
|
|
5612
|
+
possiblePromises.forEach((p, i) => Promise.resolve(p)
|
|
5613
|
+
.then((value) => (results[i] = { status: 'fulfilled', value }), (reason) => (results[i] = { status: 'rejected', reason }))
|
|
5551
5614
|
.then(() => --remaining || resolve(results)));
|
|
5552
5615
|
});
|
|
5553
5616
|
}
|
|
5554
5617
|
|
|
5555
5618
|
let counter$1 = 0;
|
|
5556
5619
|
function guardedTable(table) {
|
|
5557
|
-
const prop =
|
|
5620
|
+
const prop = '$lock' + ++counter$1;
|
|
5558
5621
|
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) });
|
|
5559
5622
|
}
|
|
5560
5623
|
function readLock(fn, prop) {
|
|
@@ -5563,7 +5626,9 @@ function readLock(fn, prop) {
|
|
|
5563
5626
|
const numWriters = writers.length;
|
|
5564
5627
|
const promise = (numWriters > 0
|
|
5565
5628
|
? writers[numWriters - 1].then(() => fn(req), () => fn(req))
|
|
5566
|
-
: fn(req)).finally(() => {
|
|
5629
|
+
: fn(req)).finally(() => {
|
|
5630
|
+
readers.splice(readers.indexOf(promise));
|
|
5631
|
+
});
|
|
5567
5632
|
readers.push(promise);
|
|
5568
5633
|
return promise;
|
|
5569
5634
|
};
|
|
@@ -5575,7 +5640,9 @@ function writeLock(fn, prop) {
|
|
|
5575
5640
|
? writers[writers.length - 1].then(() => fn(req), () => fn(req))
|
|
5576
5641
|
: readers.length > 0
|
|
5577
5642
|
? allSettled(readers).then(() => fn(req))
|
|
5578
|
-
: fn(req)).finally(() => {
|
|
5643
|
+
: fn(req)).finally(() => {
|
|
5644
|
+
writers.shift();
|
|
5645
|
+
});
|
|
5579
5646
|
writers.push(promise);
|
|
5580
5647
|
return promise;
|
|
5581
5648
|
};
|
|
@@ -5853,16 +5920,17 @@ function createMutationTrackingMiddleware({ currentUserObservable, db, }) {
|
|
|
5853
5920
|
userId,
|
|
5854
5921
|
values,
|
|
5855
5922
|
}
|
|
5856
|
-
: upsert && updates
|
|
5857
|
-
|
|
5858
|
-
|
|
5859
|
-
|
|
5860
|
-
|
|
5861
|
-
|
|
5862
|
-
|
|
5863
|
-
|
|
5864
|
-
|
|
5865
|
-
|
|
5923
|
+
: upsert && updates
|
|
5924
|
+
? {
|
|
5925
|
+
type: 'upsert',
|
|
5926
|
+
ts,
|
|
5927
|
+
opNo,
|
|
5928
|
+
keys,
|
|
5929
|
+
values,
|
|
5930
|
+
changeSpecs: updates.changeSpecs.filter((_, idx) => !failures[idx]),
|
|
5931
|
+
txid,
|
|
5932
|
+
userId,
|
|
5933
|
+
}
|
|
5866
5934
|
: criteria && changeSpec
|
|
5867
5935
|
? {
|
|
5868
5936
|
// Common changeSpec for all keys
|
|
@@ -5975,7 +6043,8 @@ class BlobSavingQueue {
|
|
|
5975
6043
|
return;
|
|
5976
6044
|
}
|
|
5977
6045
|
// Atomic update of just the blob property
|
|
5978
|
-
this.db
|
|
6046
|
+
this.db
|
|
6047
|
+
.transaction('rw', item.tableName, (tx) => {
|
|
5979
6048
|
const trans = tx.idbtrans;
|
|
5980
6049
|
trans.disableChangeTracking = true; // Don't regard this as a change for sync purposes
|
|
5981
6050
|
trans.disableAccessControl = true; // Bypass any access control checks since this is an internal operation
|
|
@@ -5984,7 +6053,7 @@ class BlobSavingQueue {
|
|
|
5984
6053
|
for (const blob of item.resolvedBlobs) {
|
|
5985
6054
|
updateSpec[blob.keyPath] = blob.data;
|
|
5986
6055
|
}
|
|
5987
|
-
tx.table(item.tableName).update(item.primaryKey, obj => {
|
|
6056
|
+
tx.table(item.tableName).update(item.primaryKey, (obj) => {
|
|
5988
6057
|
// Check that object still has the same unresolved blob refs before applying update (i.e. it hasn't been modified since we read it)
|
|
5989
6058
|
for (const blob of item.resolvedBlobs) {
|
|
5990
6059
|
// 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.
|
|
@@ -6005,9 +6074,11 @@ class BlobSavingQueue {
|
|
|
6005
6074
|
}
|
|
6006
6075
|
delete obj._hasBlobRefs; // Clear the _hasBlobRefs marker if all refs was resolved.
|
|
6007
6076
|
});
|
|
6008
|
-
})
|
|
6077
|
+
})
|
|
6078
|
+
.catch((error) => {
|
|
6009
6079
|
console.error(`Error saving resolved blobs on ${item.tableName}:${item.primaryKey}:`, error);
|
|
6010
|
-
})
|
|
6080
|
+
})
|
|
6081
|
+
.finally(() => {
|
|
6011
6082
|
// Process next item in the queue
|
|
6012
6083
|
return this.processQueue();
|
|
6013
6084
|
});
|
|
@@ -6058,7 +6129,7 @@ function createBlobResolveMiddleware(db) {
|
|
|
6058
6129
|
if ((_a = req.trans) === null || _a === void 0 ? void 0 : _a.disableBlobResolve) {
|
|
6059
6130
|
return downlevelTable.get(req);
|
|
6060
6131
|
}
|
|
6061
|
-
return downlevelTable.get(req).then(result => {
|
|
6132
|
+
return downlevelTable.get(req).then((result) => {
|
|
6062
6133
|
if (result && hasUnresolvedBlobRefs(result)) {
|
|
6063
6134
|
return resolveAndSave(downlevelTable, req.trans, req.key, result, blobSavingQueue, db);
|
|
6064
6135
|
}
|
|
@@ -6070,9 +6141,9 @@ function createBlobResolveMiddleware(db) {
|
|
|
6070
6141
|
if ((_a = req.trans) === null || _a === void 0 ? void 0 : _a.disableBlobResolve) {
|
|
6071
6142
|
return downlevelTable.getMany(req);
|
|
6072
6143
|
}
|
|
6073
|
-
return downlevelTable.getMany(req).then(results => {
|
|
6144
|
+
return downlevelTable.getMany(req).then((results) => {
|
|
6074
6145
|
// Check if any results need resolution
|
|
6075
|
-
const needsResolution = results.some(r => r && hasUnresolvedBlobRefs(r));
|
|
6146
|
+
const needsResolution = results.some((r) => r && hasUnresolvedBlobRefs(r));
|
|
6076
6147
|
if (!needsResolution)
|
|
6077
6148
|
return results;
|
|
6078
6149
|
return Dexie.Promise.all(results.map((result, index) => {
|
|
@@ -6088,19 +6159,19 @@ function createBlobResolveMiddleware(db) {
|
|
|
6088
6159
|
if ((_a = req.trans) === null || _a === void 0 ? void 0 : _a.disableBlobResolve) {
|
|
6089
6160
|
return downlevelTable.query(req);
|
|
6090
6161
|
}
|
|
6091
|
-
return downlevelTable.query(req).then(result => {
|
|
6162
|
+
return downlevelTable.query(req).then((result) => {
|
|
6092
6163
|
if (!result.result || !Array.isArray(result.result))
|
|
6093
6164
|
return result;
|
|
6094
6165
|
// Check if any results need resolution
|
|
6095
|
-
const needsResolution = result.result.some(r => r && hasUnresolvedBlobRefs(r));
|
|
6166
|
+
const needsResolution = result.result.some((r) => r && hasUnresolvedBlobRefs(r));
|
|
6096
6167
|
if (!needsResolution)
|
|
6097
6168
|
return result;
|
|
6098
|
-
return Dexie.Promise.all(result.result.map(item => {
|
|
6169
|
+
return Dexie.Promise.all(result.result.map((item) => {
|
|
6099
6170
|
if (item && hasUnresolvedBlobRefs(item)) {
|
|
6100
6171
|
return resolveAndSave(downlevelTable, req.trans, undefined, item, blobSavingQueue, db);
|
|
6101
6172
|
}
|
|
6102
6173
|
return item;
|
|
6103
|
-
})).then(resolved => (Object.assign(Object.assign({}, result), { result: resolved })));
|
|
6174
|
+
})).then((resolved) => (Object.assign(Object.assign({}, result), { result: resolved })));
|
|
6104
6175
|
});
|
|
6105
6176
|
},
|
|
6106
6177
|
openCursor(req) {
|
|
@@ -6108,7 +6179,7 @@ function createBlobResolveMiddleware(db) {
|
|
|
6108
6179
|
if ((_a = req.trans) === null || _a === void 0 ? void 0 : _a.disableBlobResolve) {
|
|
6109
6180
|
return downlevelTable.openCursor(req);
|
|
6110
6181
|
}
|
|
6111
|
-
return downlevelTable.openCursor(req).then(cursor => {
|
|
6182
|
+
return downlevelTable.openCursor(req).then((cursor) => {
|
|
6112
6183
|
if (!cursor)
|
|
6113
6184
|
return cursor; // No results, so no resolution needed
|
|
6114
6185
|
if (!req.values)
|
|
@@ -6138,7 +6209,7 @@ function createBlobResolvingCursor(cursor, table, blobSavingQueue, db) {
|
|
|
6138
6209
|
value: {
|
|
6139
6210
|
value: cursor.value,
|
|
6140
6211
|
enumerable: true,
|
|
6141
|
-
writable: true
|
|
6212
|
+
writable: true,
|
|
6142
6213
|
},
|
|
6143
6214
|
start: {
|
|
6144
6215
|
value(onNext) {
|
|
@@ -6150,17 +6221,17 @@ function createBlobResolvingCursor(cursor, table, blobSavingQueue, db) {
|
|
|
6150
6221
|
onNext();
|
|
6151
6222
|
return;
|
|
6152
6223
|
}
|
|
6153
|
-
resolveAndSave(table, cursor.trans, cursor.primaryKey, rawValue, blobSavingQueue, db, true).then(resolved => {
|
|
6224
|
+
resolveAndSave(table, cursor.trans, cursor.primaryKey, rawValue, blobSavingQueue, db, true).then((resolved) => {
|
|
6154
6225
|
wrappedCursor.value = resolved;
|
|
6155
6226
|
onNext();
|
|
6156
|
-
}, err => {
|
|
6227
|
+
}, (err) => {
|
|
6157
6228
|
console.error('Failed to resolve BlobRefs for cursor value:', err);
|
|
6158
6229
|
wrappedCursor.value = rawValue;
|
|
6159
6230
|
onNext();
|
|
6160
6231
|
});
|
|
6161
6232
|
});
|
|
6162
|
-
}
|
|
6163
|
-
}
|
|
6233
|
+
},
|
|
6234
|
+
},
|
|
6164
6235
|
});
|
|
6165
6236
|
return wrappedCursor;
|
|
6166
6237
|
}
|
|
@@ -6205,12 +6276,15 @@ obj, blobSavingQueue, db, isCursorValue = false // Flag to indicate if we're res
|
|
|
6205
6276
|
const resolvePromise = needsWaitFor
|
|
6206
6277
|
? Dexie.waitFor(resolutionPromise)
|
|
6207
6278
|
: Dexie.Promise.resolve(resolutionPromise);
|
|
6208
|
-
return resolvePromise
|
|
6279
|
+
return resolvePromise
|
|
6280
|
+
.then((resolved) => {
|
|
6209
6281
|
// Get primary key from the object
|
|
6210
6282
|
const primaryKey = table.schema.primaryKey;
|
|
6211
|
-
const key = pKey !== undefined
|
|
6212
|
-
?
|
|
6213
|
-
:
|
|
6283
|
+
const key = pKey !== undefined
|
|
6284
|
+
? pKey
|
|
6285
|
+
: primaryKey.keyPath
|
|
6286
|
+
? Dexie.getByKeyPath(obj, primaryKey.keyPath)
|
|
6287
|
+
: undefined;
|
|
6214
6288
|
if (key !== undefined) {
|
|
6215
6289
|
// Queue each resolved blob individually for atomic update
|
|
6216
6290
|
// This uses setTimeout(fn, 0) to completely isolate from
|
|
@@ -6221,13 +6295,16 @@ obj, blobSavingQueue, db, isCursorValue = false // Flag to indicate if we're res
|
|
|
6221
6295
|
else {
|
|
6222
6296
|
// For rw transactions, we can save directly without queueing
|
|
6223
6297
|
// since we're still in the same transaction context
|
|
6224
|
-
table
|
|
6298
|
+
table
|
|
6299
|
+
.mutate({ type: 'put', keys: [key], values: [resolved], trans })
|
|
6300
|
+
.catch((err) => {
|
|
6225
6301
|
console.error(`Failed to save resolved blob on ${table.name}:${key}:`, err);
|
|
6226
6302
|
});
|
|
6227
6303
|
}
|
|
6228
6304
|
}
|
|
6229
6305
|
return resolved;
|
|
6230
|
-
})
|
|
6306
|
+
})
|
|
6307
|
+
.catch((err) => {
|
|
6231
6308
|
console.error(`[dexie-cloud:blobResolve] Failed to resolve BlobRefs on ${table.name}:`, err);
|
|
6232
6309
|
return obj; // Return original object on error - never block the read pipeline
|
|
6233
6310
|
});
|
|
@@ -6256,9 +6333,13 @@ function overrideParseStoresSpec(origFunc, dexie) {
|
|
|
6256
6333
|
return; // Continue
|
|
6257
6334
|
}
|
|
6258
6335
|
// They have declared this table. Merge indexes in case they didn't declare all indexes we need.
|
|
6259
|
-
const requestedIndexes = schemaSrc
|
|
6260
|
-
|
|
6261
|
-
|
|
6336
|
+
const requestedIndexes = schemaSrc
|
|
6337
|
+
.split(',')
|
|
6338
|
+
.map((spec) => spec.trim());
|
|
6339
|
+
const builtInIndexes = DEXIE_CLOUD_SCHEMA[tableName]
|
|
6340
|
+
.split(',')
|
|
6341
|
+
.map((spec) => spec.trim());
|
|
6342
|
+
const requestedIndexSet = new Set(requestedIndexes.map((index) => index.replace(/([&*]|\+\+)/g, '')));
|
|
6262
6343
|
// Verify that primary key is unchanged
|
|
6263
6344
|
if (requestedIndexes[0] !== builtInIndexes[0]) {
|
|
6264
6345
|
// Primary key must match exactly
|
|
@@ -6267,7 +6348,7 @@ function overrideParseStoresSpec(origFunc, dexie) {
|
|
|
6267
6348
|
// Merge indexes
|
|
6268
6349
|
for (let i = 1; i < builtInIndexes.length; ++i) {
|
|
6269
6350
|
const builtInIndex = builtInIndexes[i];
|
|
6270
|
-
if (!requestedIndexSet.has(builtInIndex.replace(/([&*]|\+\+)/g,
|
|
6351
|
+
if (!requestedIndexSet.has(builtInIndex.replace(/([&*]|\+\+)/g, ''))) {
|
|
6271
6352
|
// Add built-in index if not already requested
|
|
6272
6353
|
storesClone[tableName] += `,${builtInIndex}`;
|
|
6273
6354
|
}
|
|
@@ -6276,7 +6357,7 @@ function overrideParseStoresSpec(origFunc, dexie) {
|
|
|
6276
6357
|
// Populate dexie.cloud.schema
|
|
6277
6358
|
const cloudSchema = dexie.cloud.schema || (dexie.cloud.schema = {});
|
|
6278
6359
|
const allPrefixes = new Set();
|
|
6279
|
-
Object.keys(storesClone).forEach(tableName => {
|
|
6360
|
+
Object.keys(storesClone).forEach((tableName) => {
|
|
6280
6361
|
var _a;
|
|
6281
6362
|
const schemaSrc = (_a = storesClone[tableName]) === null || _a === void 0 ? void 0 : _a.trim();
|
|
6282
6363
|
const cloudTableSchema = cloudSchema[tableName] || (cloudSchema[tableName] = {});
|
|
@@ -6405,7 +6486,7 @@ if (typeof document !== 'undefined') {
|
|
|
6405
6486
|
class TokenExpiredError extends Error {
|
|
6406
6487
|
constructor() {
|
|
6407
6488
|
super(...arguments);
|
|
6408
|
-
this.name =
|
|
6489
|
+
this.name = 'TokenExpiredError';
|
|
6409
6490
|
}
|
|
6410
6491
|
}
|
|
6411
6492
|
|
|
@@ -6629,7 +6710,7 @@ class WSConnection extends Subscription {
|
|
|
6629
6710
|
// Connect the WebSocket to given url:
|
|
6630
6711
|
console.debug('dexie-cloud WebSocket create');
|
|
6631
6712
|
const ws = (this.ws = new WebSocket(`${wsUrl}/changes?${searchParams}`));
|
|
6632
|
-
ws.binaryType =
|
|
6713
|
+
ws.binaryType = 'arraybuffer';
|
|
6633
6714
|
ws.onclose = (event) => {
|
|
6634
6715
|
if (!this.pinger)
|
|
6635
6716
|
return;
|
|
@@ -6668,10 +6749,17 @@ class WSConnection extends Subscription {
|
|
|
6668
6749
|
getOpenDocSignal(doc).next(); // Make yHandler reopen the document on server.
|
|
6669
6750
|
}
|
|
6670
6751
|
}
|
|
6671
|
-
else if (msg.type === 'u-ack' ||
|
|
6752
|
+
else if (msg.type === 'u-ack' ||
|
|
6753
|
+
msg.type === 'u-reject' ||
|
|
6754
|
+
msg.type === 'u-s' ||
|
|
6755
|
+
msg.type === 'in-sync' ||
|
|
6756
|
+
msg.type === 'outdated-server-rev' ||
|
|
6757
|
+
msg.type === 'y-complete-sync-done') {
|
|
6672
6758
|
applyYServerMessages([msg], this.db).then((_a) => __awaiter(this, [_a], void 0, function* ({ resyncNeeded, yServerRevision, receivedUntils }) {
|
|
6673
6759
|
if (yServerRevision) {
|
|
6674
|
-
yield this.db.$syncState.update('syncState', {
|
|
6760
|
+
yield this.db.$syncState.update('syncState', {
|
|
6761
|
+
yServerRevision: yServerRevision,
|
|
6762
|
+
});
|
|
6675
6763
|
}
|
|
6676
6764
|
if (msg.type === 'u-s' && receivedUntils) {
|
|
6677
6765
|
const utbl = getUpdatesTable(this.db, msg.table, msg.prop);
|
|
@@ -6874,7 +6962,9 @@ function isSyncNeeded(db) {
|
|
|
6874
6962
|
return __awaiter(this, void 0, void 0, function* () {
|
|
6875
6963
|
var _a;
|
|
6876
6964
|
return ((_a = db.cloud.options) === null || _a === void 0 ? void 0 : _a.databaseUrl) && db.cloud.schema
|
|
6877
|
-
? yield sync(db, db.cloud.options, db.cloud.schema, {
|
|
6965
|
+
? yield sync(db, db.cloud.options, db.cloud.schema, {
|
|
6966
|
+
justCheckIfNeeded: true,
|
|
6967
|
+
})
|
|
6878
6968
|
: false;
|
|
6879
6969
|
});
|
|
6880
6970
|
}
|
|
@@ -7086,243 +7176,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
|
|
|
7086
7176
|
const Styles = {
|
|
7087
7177
|
Alert: {
|
|
7088
7178
|
error: {
|
|
7089
|
-
color:
|
|
7090
|
-
fontWeight:
|
|
7179
|
+
color: 'red',
|
|
7180
|
+
fontWeight: 'bold',
|
|
7091
7181
|
},
|
|
7092
7182
|
warning: {
|
|
7093
|
-
color:
|
|
7094
|
-
fontWeight:
|
|
7183
|
+
color: '#f80',
|
|
7184
|
+
fontWeight: 'bold',
|
|
7095
7185
|
},
|
|
7096
7186
|
info: {
|
|
7097
|
-
color:
|
|
7098
|
-
}
|
|
7187
|
+
color: 'black',
|
|
7188
|
+
},
|
|
7099
7189
|
},
|
|
7100
7190
|
Darken: {
|
|
7101
|
-
position:
|
|
7191
|
+
position: 'fixed',
|
|
7102
7192
|
top: 0,
|
|
7103
7193
|
left: 0,
|
|
7104
7194
|
opacity: 0.5,
|
|
7105
|
-
backgroundColor:
|
|
7106
|
-
width:
|
|
7107
|
-
height:
|
|
7195
|
+
backgroundColor: '#000',
|
|
7196
|
+
width: '100vw',
|
|
7197
|
+
height: '100vh',
|
|
7108
7198
|
zIndex: 150,
|
|
7109
|
-
webkitBackdropFilter:
|
|
7110
|
-
backdropFilter:
|
|
7199
|
+
webkitBackdropFilter: 'blur(2px)',
|
|
7200
|
+
backdropFilter: 'blur(2px)',
|
|
7111
7201
|
},
|
|
7112
7202
|
DialogOuter: {
|
|
7113
|
-
position:
|
|
7203
|
+
position: 'fixed',
|
|
7114
7204
|
top: 0,
|
|
7115
7205
|
left: 0,
|
|
7116
|
-
width:
|
|
7117
|
-
height:
|
|
7206
|
+
width: '100vw',
|
|
7207
|
+
height: '100vh',
|
|
7118
7208
|
zIndex: 150,
|
|
7119
|
-
alignItems:
|
|
7120
|
-
display:
|
|
7121
|
-
justifyContent:
|
|
7122
|
-
padding:
|
|
7123
|
-
boxSizing:
|
|
7209
|
+
alignItems: 'center',
|
|
7210
|
+
display: 'flex',
|
|
7211
|
+
justifyContent: 'center',
|
|
7212
|
+
padding: '16px',
|
|
7213
|
+
boxSizing: 'border-box',
|
|
7124
7214
|
},
|
|
7125
7215
|
DialogInner: {
|
|
7126
|
-
position:
|
|
7127
|
-
color:
|
|
7128
|
-
backgroundColor:
|
|
7129
|
-
padding:
|
|
7130
|
-
marginBottom:
|
|
7131
|
-
maxWidth:
|
|
7132
|
-
width:
|
|
7133
|
-
maxHeight:
|
|
7134
|
-
overflowY:
|
|
7135
|
-
border:
|
|
7136
|
-
borderRadius:
|
|
7137
|
-
boxShadow:
|
|
7138
|
-
fontFamily:
|
|
7139
|
-
boxSizing:
|
|
7216
|
+
position: 'relative',
|
|
7217
|
+
color: '#222',
|
|
7218
|
+
backgroundColor: '#fff',
|
|
7219
|
+
padding: '24px',
|
|
7220
|
+
marginBottom: '2em',
|
|
7221
|
+
maxWidth: '400px',
|
|
7222
|
+
width: '100%',
|
|
7223
|
+
maxHeight: '90%',
|
|
7224
|
+
overflowY: 'auto',
|
|
7225
|
+
border: '3px solid #3d3d5d',
|
|
7226
|
+
borderRadius: '8px',
|
|
7227
|
+
boxShadow: '0 0 80px 10px #666',
|
|
7228
|
+
fontFamily: 'sans-serif',
|
|
7229
|
+
boxSizing: 'border-box',
|
|
7140
7230
|
},
|
|
7141
7231
|
Input: {
|
|
7142
|
-
height:
|
|
7143
|
-
width:
|
|
7144
|
-
maxWidth:
|
|
7145
|
-
borderColor:
|
|
7146
|
-
outline:
|
|
7147
|
-
fontSize:
|
|
7148
|
-
padding:
|
|
7149
|
-
boxSizing:
|
|
7150
|
-
backgroundColor:
|
|
7151
|
-
borderRadius:
|
|
7152
|
-
border:
|
|
7153
|
-
marginTop:
|
|
7154
|
-
fontFamily:
|
|
7232
|
+
height: '35px',
|
|
7233
|
+
width: '100%',
|
|
7234
|
+
maxWidth: '100%',
|
|
7235
|
+
borderColor: '#ccf4',
|
|
7236
|
+
outline: 'none',
|
|
7237
|
+
fontSize: '16px',
|
|
7238
|
+
padding: '8px',
|
|
7239
|
+
boxSizing: 'border-box',
|
|
7240
|
+
backgroundColor: '#f9f9f9',
|
|
7241
|
+
borderRadius: '4px',
|
|
7242
|
+
border: '1px solid #ccc',
|
|
7243
|
+
marginTop: '6px',
|
|
7244
|
+
fontFamily: 'inherit',
|
|
7155
7245
|
},
|
|
7156
7246
|
Button: {
|
|
7157
|
-
padding:
|
|
7158
|
-
margin:
|
|
7159
|
-
border:
|
|
7160
|
-
borderRadius:
|
|
7161
|
-
backgroundColor:
|
|
7162
|
-
cursor:
|
|
7163
|
-
fontSize:
|
|
7164
|
-
fontWeight:
|
|
7165
|
-
color:
|
|
7166
|
-
transition:
|
|
7247
|
+
padding: '10px 20px',
|
|
7248
|
+
margin: '0 4px',
|
|
7249
|
+
border: '1px solid #d1d5db',
|
|
7250
|
+
borderRadius: '6px',
|
|
7251
|
+
backgroundColor: '#ffffff',
|
|
7252
|
+
cursor: 'pointer',
|
|
7253
|
+
fontSize: '14px',
|
|
7254
|
+
fontWeight: '500',
|
|
7255
|
+
color: '#374151',
|
|
7256
|
+
transition: 'all 0.2s ease',
|
|
7167
7257
|
},
|
|
7168
7258
|
PrimaryButton: {
|
|
7169
|
-
padding:
|
|
7170
|
-
margin:
|
|
7171
|
-
border:
|
|
7172
|
-
borderRadius:
|
|
7173
|
-
backgroundColor:
|
|
7174
|
-
color:
|
|
7175
|
-
cursor:
|
|
7176
|
-
fontSize:
|
|
7177
|
-
fontWeight:
|
|
7178
|
-
transition:
|
|
7259
|
+
padding: '10px 20px',
|
|
7260
|
+
margin: '0 4px',
|
|
7261
|
+
border: '1px solid #3b82f6',
|
|
7262
|
+
borderRadius: '6px',
|
|
7263
|
+
backgroundColor: '#3b82f6',
|
|
7264
|
+
color: 'white',
|
|
7265
|
+
cursor: 'pointer',
|
|
7266
|
+
fontSize: '14px',
|
|
7267
|
+
fontWeight: '500',
|
|
7268
|
+
transition: 'all 0.2s ease',
|
|
7179
7269
|
},
|
|
7180
7270
|
ButtonsDiv: {
|
|
7181
|
-
display:
|
|
7182
|
-
justifyContent:
|
|
7183
|
-
gap:
|
|
7184
|
-
marginTop:
|
|
7185
|
-
paddingTop:
|
|
7271
|
+
display: 'flex',
|
|
7272
|
+
justifyContent: 'flex-end',
|
|
7273
|
+
gap: '12px',
|
|
7274
|
+
marginTop: '24px',
|
|
7275
|
+
paddingTop: '20px',
|
|
7186
7276
|
},
|
|
7187
7277
|
Label: {
|
|
7188
|
-
display:
|
|
7189
|
-
marginBottom:
|
|
7190
|
-
fontSize:
|
|
7191
|
-
fontWeight:
|
|
7192
|
-
color:
|
|
7278
|
+
display: 'block',
|
|
7279
|
+
marginBottom: '12px',
|
|
7280
|
+
fontSize: '14px',
|
|
7281
|
+
fontWeight: '500',
|
|
7282
|
+
color: '#333',
|
|
7193
7283
|
},
|
|
7194
7284
|
WindowHeader: {
|
|
7195
|
-
margin:
|
|
7196
|
-
fontSize:
|
|
7197
|
-
fontWeight:
|
|
7198
|
-
color:
|
|
7199
|
-
borderBottom:
|
|
7200
|
-
paddingBottom:
|
|
7285
|
+
margin: '0 0 20px 0',
|
|
7286
|
+
fontSize: '18px',
|
|
7287
|
+
fontWeight: '600',
|
|
7288
|
+
color: '#333',
|
|
7289
|
+
borderBottom: '1px solid #eee',
|
|
7290
|
+
paddingBottom: '10px',
|
|
7201
7291
|
},
|
|
7202
7292
|
// OAuth Provider Button Styles
|
|
7203
7293
|
ProviderButton: {
|
|
7204
|
-
display:
|
|
7205
|
-
alignItems:
|
|
7206
|
-
justifyContent:
|
|
7207
|
-
width:
|
|
7208
|
-
padding:
|
|
7209
|
-
marginBottom:
|
|
7210
|
-
border:
|
|
7211
|
-
borderRadius:
|
|
7212
|
-
backgroundColor:
|
|
7213
|
-
cursor:
|
|
7214
|
-
fontSize:
|
|
7215
|
-
fontWeight:
|
|
7216
|
-
color:
|
|
7217
|
-
transition:
|
|
7218
|
-
gap:
|
|
7294
|
+
display: 'flex',
|
|
7295
|
+
alignItems: 'center',
|
|
7296
|
+
justifyContent: 'center',
|
|
7297
|
+
width: '100%',
|
|
7298
|
+
padding: '12px 16px',
|
|
7299
|
+
marginBottom: '10px',
|
|
7300
|
+
border: '1px solid #d1d5db',
|
|
7301
|
+
borderRadius: '6px',
|
|
7302
|
+
backgroundColor: '#ffffff',
|
|
7303
|
+
cursor: 'pointer',
|
|
7304
|
+
fontSize: '14px',
|
|
7305
|
+
fontWeight: '500',
|
|
7306
|
+
color: '#374151',
|
|
7307
|
+
transition: 'all 0.2s ease',
|
|
7308
|
+
gap: '12px',
|
|
7219
7309
|
},
|
|
7220
7310
|
ProviderButtonIcon: {
|
|
7221
|
-
width:
|
|
7222
|
-
height:
|
|
7311
|
+
width: '20px',
|
|
7312
|
+
height: '20px',
|
|
7223
7313
|
flexShrink: 0,
|
|
7224
|
-
display:
|
|
7225
|
-
alignItems:
|
|
7226
|
-
justifyContent:
|
|
7314
|
+
display: 'flex',
|
|
7315
|
+
alignItems: 'center',
|
|
7316
|
+
justifyContent: 'center',
|
|
7227
7317
|
},
|
|
7228
7318
|
ProviderButtonText: {
|
|
7229
7319
|
flex: 1,
|
|
7230
|
-
textAlign:
|
|
7320
|
+
textAlign: 'left',
|
|
7231
7321
|
},
|
|
7232
7322
|
// Provider-specific colors
|
|
7233
7323
|
ProviderGoogle: {
|
|
7234
|
-
backgroundColor:
|
|
7235
|
-
border:
|
|
7236
|
-
color:
|
|
7324
|
+
backgroundColor: '#ffffff',
|
|
7325
|
+
border: '1px solid #dadce0',
|
|
7326
|
+
color: '#3c4043',
|
|
7237
7327
|
},
|
|
7238
7328
|
ProviderGitHub: {
|
|
7239
|
-
backgroundColor:
|
|
7240
|
-
border:
|
|
7241
|
-
color:
|
|
7329
|
+
backgroundColor: '#ffffff',
|
|
7330
|
+
border: '1px solid #dadce0',
|
|
7331
|
+
color: '#181717',
|
|
7242
7332
|
},
|
|
7243
7333
|
ProviderMicrosoft: {
|
|
7244
|
-
backgroundColor:
|
|
7245
|
-
border:
|
|
7246
|
-
color:
|
|
7334
|
+
backgroundColor: '#ffffff',
|
|
7335
|
+
border: '1px solid #dadce0',
|
|
7336
|
+
color: '#5e5e5e',
|
|
7247
7337
|
},
|
|
7248
7338
|
ProviderApple: {
|
|
7249
|
-
backgroundColor:
|
|
7250
|
-
border:
|
|
7251
|
-
color:
|
|
7339
|
+
backgroundColor: '#000000',
|
|
7340
|
+
border: '1px solid #000000',
|
|
7341
|
+
color: '#ffffff',
|
|
7252
7342
|
},
|
|
7253
7343
|
ProviderCustom: {
|
|
7254
|
-
backgroundColor:
|
|
7255
|
-
border:
|
|
7256
|
-
color:
|
|
7344
|
+
backgroundColor: '#ffffff',
|
|
7345
|
+
border: '1px solid #dadce0',
|
|
7346
|
+
color: '#181717',
|
|
7257
7347
|
},
|
|
7258
7348
|
// Divider styles
|
|
7259
7349
|
Divider: {
|
|
7260
|
-
display:
|
|
7261
|
-
alignItems:
|
|
7262
|
-
margin:
|
|
7263
|
-
color:
|
|
7264
|
-
fontSize:
|
|
7350
|
+
display: 'flex',
|
|
7351
|
+
alignItems: 'center',
|
|
7352
|
+
margin: '20px 0',
|
|
7353
|
+
color: '#6b7280',
|
|
7354
|
+
fontSize: '13px',
|
|
7265
7355
|
},
|
|
7266
7356
|
DividerLine: {
|
|
7267
7357
|
flex: 1,
|
|
7268
|
-
height:
|
|
7269
|
-
backgroundColor:
|
|
7358
|
+
height: '1px',
|
|
7359
|
+
backgroundColor: '#e5e7eb',
|
|
7270
7360
|
},
|
|
7271
7361
|
DividerText: {
|
|
7272
|
-
padding:
|
|
7273
|
-
color:
|
|
7362
|
+
padding: '0 12px',
|
|
7363
|
+
color: '#9ca3af',
|
|
7274
7364
|
},
|
|
7275
7365
|
// OTP Button (Continue with email)
|
|
7276
7366
|
OtpButton: {
|
|
7277
|
-
display:
|
|
7278
|
-
alignItems:
|
|
7279
|
-
justifyContent:
|
|
7280
|
-
width:
|
|
7281
|
-
padding:
|
|
7282
|
-
border:
|
|
7283
|
-
borderRadius:
|
|
7284
|
-
backgroundColor:
|
|
7285
|
-
cursor:
|
|
7286
|
-
fontSize:
|
|
7287
|
-
fontWeight:
|
|
7288
|
-
color:
|
|
7289
|
-
transition:
|
|
7290
|
-
gap:
|
|
7367
|
+
display: 'flex',
|
|
7368
|
+
alignItems: 'center',
|
|
7369
|
+
justifyContent: 'center',
|
|
7370
|
+
width: '100%',
|
|
7371
|
+
padding: '12px 16px',
|
|
7372
|
+
border: '1px solid #d1d5db',
|
|
7373
|
+
borderRadius: '6px',
|
|
7374
|
+
backgroundColor: '#f9fafb',
|
|
7375
|
+
cursor: 'pointer',
|
|
7376
|
+
fontSize: '14px',
|
|
7377
|
+
fontWeight: '500',
|
|
7378
|
+
color: '#374151',
|
|
7379
|
+
transition: 'all 0.2s ease',
|
|
7380
|
+
gap: '12px',
|
|
7291
7381
|
},
|
|
7292
7382
|
// Copy button for alerts with copyText
|
|
7293
7383
|
CopyButton: {
|
|
7294
|
-
display:
|
|
7295
|
-
alignItems:
|
|
7296
|
-
gap:
|
|
7297
|
-
padding:
|
|
7298
|
-
marginTop:
|
|
7299
|
-
border:
|
|
7300
|
-
borderRadius:
|
|
7301
|
-
backgroundColor:
|
|
7302
|
-
cursor:
|
|
7303
|
-
fontSize:
|
|
7304
|
-
fontWeight:
|
|
7305
|
-
color:
|
|
7306
|
-
transition:
|
|
7307
|
-
fontFamily:
|
|
7384
|
+
display: 'inline-flex',
|
|
7385
|
+
alignItems: 'center',
|
|
7386
|
+
gap: '4px',
|
|
7387
|
+
padding: '4px 10px',
|
|
7388
|
+
marginTop: '8px',
|
|
7389
|
+
border: '1px solid #d1d5db',
|
|
7390
|
+
borderRadius: '4px',
|
|
7391
|
+
backgroundColor: '#f9fafb',
|
|
7392
|
+
cursor: 'pointer',
|
|
7393
|
+
fontSize: '12px',
|
|
7394
|
+
fontWeight: '500',
|
|
7395
|
+
color: '#374151',
|
|
7396
|
+
transition: 'all 0.15s ease',
|
|
7397
|
+
fontFamily: 'monospace',
|
|
7308
7398
|
},
|
|
7309
7399
|
CopyButtonCopied: {
|
|
7310
|
-
display:
|
|
7311
|
-
alignItems:
|
|
7312
|
-
gap:
|
|
7313
|
-
padding:
|
|
7314
|
-
marginTop:
|
|
7315
|
-
border:
|
|
7316
|
-
borderRadius:
|
|
7317
|
-
backgroundColor:
|
|
7318
|
-
cursor:
|
|
7319
|
-
fontSize:
|
|
7320
|
-
fontWeight:
|
|
7321
|
-
color:
|
|
7322
|
-
fontFamily:
|
|
7400
|
+
display: 'inline-flex',
|
|
7401
|
+
alignItems: 'center',
|
|
7402
|
+
gap: '4px',
|
|
7403
|
+
padding: '4px 10px',
|
|
7404
|
+
marginTop: '8px',
|
|
7405
|
+
border: '1px solid #22c55e',
|
|
7406
|
+
borderRadius: '4px',
|
|
7407
|
+
backgroundColor: '#f0fdf4',
|
|
7408
|
+
cursor: 'default',
|
|
7409
|
+
fontSize: '12px',
|
|
7410
|
+
fontWeight: '500',
|
|
7411
|
+
color: '#16a34a',
|
|
7412
|
+
fontFamily: 'monospace',
|
|
7323
7413
|
}};
|
|
7324
7414
|
|
|
7325
|
-
function Dialog({ children, className }) {
|
|
7415
|
+
function Dialog({ children, className, }) {
|
|
7326
7416
|
return (_$1("div", { className: `dexie-dialog ${className || ''}` },
|
|
7327
7417
|
_$1("div", { style: Styles.Darken }),
|
|
7328
7418
|
_$1("div", { style: Styles.DialogOuter },
|
|
@@ -7346,7 +7436,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.__
|
|
|
7346
7436
|
* @returns A final message where parameters have been replaced with values.
|
|
7347
7437
|
*/
|
|
7348
7438
|
function resolveText({ message, messageCode, messageParams }) {
|
|
7349
|
-
return message.replace(/\{\w+\}/
|
|
7439
|
+
return message.replace(/\{\w+\}/gi, (n) => messageParams[n.substring(1, n.length - 1)]);
|
|
7350
7440
|
}
|
|
7351
7441
|
|
|
7352
7442
|
/** Get style based on styleHint (for provider branding, etc.) */
|
|
@@ -7433,13 +7523,13 @@ function LoginDialog({ title, alerts, fields, options, submitLabel, cancelLabel,
|
|
|
7433
7523
|
alerts.map((alert, idx) => (_$1("div", { key: idx },
|
|
7434
7524
|
_$1("p", { style: Styles.Alert[alert.type] }, resolveText(alert)),
|
|
7435
7525
|
alert.copyText && _$1(CopyButton, { text: alert.copyText })))),
|
|
7436
|
-
hasOptions && (_$1("div", { class: "dxc-options" }, hasMultipleGroups
|
|
7437
|
-
|
|
7438
|
-
|
|
7439
|
-
|
|
7440
|
-
|
|
7441
|
-
|
|
7442
|
-
|
|
7526
|
+
hasOptions && (_$1("div", { class: "dxc-options" }, hasMultipleGroups
|
|
7527
|
+
? // Render with dividers between groups
|
|
7528
|
+
Array.from(optionGroups.entries()).map(([groupName, groupOptions], groupIdx) => (_$1(k$1, { key: groupName },
|
|
7529
|
+
groupIdx > 0 && _$1(Divider, null),
|
|
7530
|
+
groupOptions.map((option) => (_$1(OptionButton, { key: `${option.name}-${option.value}`, option: option, onClick: () => handleOptionClick(option) }))))))
|
|
7531
|
+
: // Simple case: all options in one group
|
|
7532
|
+
options.map((option) => (_$1(OptionButton, { key: `${option.name}-${option.value}`, option: option, onClick: () => handleOptionClick(option) }))))),
|
|
7443
7533
|
hasOptions && hasFields && _$1(Divider, null),
|
|
7444
7534
|
hasFields && (_$1("form", { onSubmit: (ev) => {
|
|
7445
7535
|
ev.preventDefault();
|
|
@@ -7451,7 +7541,8 @@ function LoginDialog({ title, alerts, fields, options, submitLabel, cancelLabel,
|
|
|
7451
7541
|
const value = valueTransformer(type, (_a = ev.target) === null || _a === void 0 ? void 0 : _a['value']);
|
|
7452
7542
|
let updatedParams = Object.assign(Object.assign({}, params), { [fieldName]: value });
|
|
7453
7543
|
setParams(updatedParams);
|
|
7454
|
-
if (type === 'otp' &&
|
|
7544
|
+
if (type === 'otp' &&
|
|
7545
|
+
(value === null || value === void 0 ? void 0 : value.trim().length) === OTP_LENGTH) {
|
|
7455
7546
|
// Auto-submit when OTP is filled in.
|
|
7456
7547
|
onSubmit(updatedParams);
|
|
7457
7548
|
}
|
|
@@ -7493,7 +7584,10 @@ function CopyButton({ text }) {
|
|
|
7493
7584
|
const handleClick = () => {
|
|
7494
7585
|
var _a;
|
|
7495
7586
|
if (typeof navigator !== 'undefined' && ((_a = navigator.clipboard) === null || _a === void 0 ? void 0 : _a.writeText)) {
|
|
7496
|
-
navigator.clipboard
|
|
7587
|
+
navigator.clipboard
|
|
7588
|
+
.writeText(text)
|
|
7589
|
+
.then(scheduleCopiedReset)
|
|
7590
|
+
.catch(() => {
|
|
7497
7591
|
fallbackCopy(text, scheduleCopiedReset);
|
|
7498
7592
|
});
|
|
7499
7593
|
}
|
|
@@ -7564,7 +7658,7 @@ function setupDefaultGUI(db) {
|
|
|
7564
7658
|
},
|
|
7565
7659
|
get closed() {
|
|
7566
7660
|
return closed;
|
|
7567
|
-
}
|
|
7661
|
+
},
|
|
7568
7662
|
};
|
|
7569
7663
|
}
|
|
7570
7664
|
|
|
@@ -7609,14 +7703,14 @@ function computeSyncState(db) {
|
|
|
7609
7703
|
lazyWebSocketStatus,
|
|
7610
7704
|
db.syncStateChangedEvent.pipe(startWith({ phase: 'initial' })),
|
|
7611
7705
|
getCurrentUserEmitter(db.dx._novip),
|
|
7612
|
-
userIsReallyActive
|
|
7706
|
+
userIsReallyActive,
|
|
7613
7707
|
]).pipe(map(([status, syncState, user, userIsActive]) => {
|
|
7614
7708
|
var _a;
|
|
7615
7709
|
if (((_a = user.license) === null || _a === void 0 ? void 0 : _a.status) && user.license.status !== 'ok') {
|
|
7616
7710
|
return {
|
|
7617
7711
|
phase: 'offline',
|
|
7618
7712
|
status: 'offline',
|
|
7619
|
-
license: user.license.status
|
|
7713
|
+
license: user.license.status,
|
|
7620
7714
|
};
|
|
7621
7715
|
}
|
|
7622
7716
|
let { phase, error, progress } = syncState;
|
|
@@ -7636,7 +7730,8 @@ function computeSyncState(db) {
|
|
|
7636
7730
|
}
|
|
7637
7731
|
const previousPhase = db.cloud.syncState.value.phase;
|
|
7638
7732
|
//const previousStatus = db.cloud.syncState.value.status;
|
|
7639
|
-
if (previousPhase === 'error' &&
|
|
7733
|
+
if (previousPhase === 'error' &&
|
|
7734
|
+
(syncState.phase === 'pushing' || syncState.phase === 'pulling')) {
|
|
7640
7735
|
// We were in an errored state but is now doing sync. Show "connecting" icon.
|
|
7641
7736
|
adjustedStatus = 'connecting';
|
|
7642
7737
|
}
|
|
@@ -7651,7 +7746,7 @@ function computeSyncState(db) {
|
|
|
7651
7746
|
error,
|
|
7652
7747
|
progress,
|
|
7653
7748
|
status: isOnline ? adjustedStatus : 'offline',
|
|
7654
|
-
license: 'ok'
|
|
7749
|
+
license: 'ok',
|
|
7655
7750
|
};
|
|
7656
7751
|
return retState;
|
|
7657
7752
|
}));
|
|
@@ -7672,7 +7767,7 @@ function createSharedValueObservable(o, defaultValue) {
|
|
|
7672
7767
|
},
|
|
7673
7768
|
complete() {
|
|
7674
7769
|
observer.complete();
|
|
7675
|
-
}
|
|
7770
|
+
},
|
|
7676
7771
|
});
|
|
7677
7772
|
if (!didEmit && !subscription.closed) {
|
|
7678
7773
|
observer.next(currentValue);
|
|
@@ -7913,7 +8008,9 @@ function permissions(dexie, obj, tableName) {
|
|
|
7913
8008
|
const realm = permissionsLookup[realmId || dexie.cloud.currentUserId];
|
|
7914
8009
|
if (!realm)
|
|
7915
8010
|
return new PermissionChecker({}, tableName, !owner || owner === dexie.cloud.currentUserId);
|
|
7916
|
-
return new PermissionChecker(realm.permissions, tableName, realmId === undefined ||
|
|
8011
|
+
return new PermissionChecker(realm.permissions, tableName, realmId === undefined ||
|
|
8012
|
+
realmId === dexie.cloud.currentUserId ||
|
|
8013
|
+
owner === dexie.cloud.currentUserId);
|
|
7917
8014
|
};
|
|
7918
8015
|
const o = source.pipe(map(mapper));
|
|
7919
8016
|
o.getValue = () => mapper(source.getValue());
|
|
@@ -7955,7 +8052,19 @@ function createYHandler(db) {
|
|
|
7955
8052
|
return; // The table that holds the doc is not marked for sync - leave it to dexie. No syncing, no awareness.
|
|
7956
8053
|
}
|
|
7957
8054
|
let awareness;
|
|
8055
|
+
const existingDescriptor = Object.getOwnPropertyDescriptor(provider, 'awareness');
|
|
8056
|
+
if (existingDescriptor) {
|
|
8057
|
+
// Provider already initialized — likely a leaked handler from a previous db instance
|
|
8058
|
+
// (e.g. HMR where db.close() didn't fire). Destroy the stale awareness so the new
|
|
8059
|
+
// handler can take over cleanly.
|
|
8060
|
+
const staleAwareness = provider.awareness;
|
|
8061
|
+
if (staleAwareness) {
|
|
8062
|
+
staleAwareness.destroy();
|
|
8063
|
+
awarenessWeakMap.delete(doc);
|
|
8064
|
+
}
|
|
8065
|
+
}
|
|
7958
8066
|
Object.defineProperty(provider, 'awareness', {
|
|
8067
|
+
configurable: true,
|
|
7959
8068
|
get() {
|
|
7960
8069
|
if (awareness)
|
|
7961
8070
|
return awareness;
|
|
@@ -8138,10 +8247,12 @@ function parseOAuthCallback(url) {
|
|
|
8138
8247
|
const { code, provider, state, error } = payload;
|
|
8139
8248
|
// Check for error first
|
|
8140
8249
|
if (error) {
|
|
8141
|
-
if (error.toLowerCase().includes('access_denied') ||
|
|
8250
|
+
if (error.toLowerCase().includes('access_denied') ||
|
|
8251
|
+
error.toLowerCase().includes('access denied')) {
|
|
8142
8252
|
throw new OAuthError('access_denied', provider, error);
|
|
8143
8253
|
}
|
|
8144
|
-
if (error.toLowerCase().includes('email') &&
|
|
8254
|
+
if (error.toLowerCase().includes('email') &&
|
|
8255
|
+
error.toLowerCase().includes('verif')) {
|
|
8145
8256
|
throw new OAuthError('email_not_verified', provider, error);
|
|
8146
8257
|
}
|
|
8147
8258
|
throw new OAuthError('provider_error', provider, error);
|
|
@@ -8167,7 +8278,9 @@ function cleanupOAuthUrl() {
|
|
|
8167
8278
|
return;
|
|
8168
8279
|
}
|
|
8169
8280
|
url.searchParams.delete('dxc-auth');
|
|
8170
|
-
const cleanUrl = url.pathname +
|
|
8281
|
+
const cleanUrl = url.pathname +
|
|
8282
|
+
(url.searchParams.toString() ? `?${url.searchParams.toString()}` : '') +
|
|
8283
|
+
url.hash;
|
|
8171
8284
|
window.history.replaceState(null, '', cleanUrl);
|
|
8172
8285
|
}
|
|
8173
8286
|
|
|
@@ -8216,7 +8329,7 @@ function dexieCloud(dexie) {
|
|
|
8216
8329
|
const downloading$ = createDownloadingState();
|
|
8217
8330
|
dexie.cloud = {
|
|
8218
8331
|
// @ts-ignore
|
|
8219
|
-
version: "4.4.
|
|
8332
|
+
version: "4.4.8",
|
|
8220
8333
|
options: Object.assign({}, DEFAULT_OPTIONS),
|
|
8221
8334
|
schema: null,
|
|
8222
8335
|
get currentUserId() {
|
|
@@ -8272,7 +8385,10 @@ function dexieCloud(dexie) {
|
|
|
8272
8385
|
const callback = parseOAuthCallback();
|
|
8273
8386
|
if (callback) {
|
|
8274
8387
|
// Store the pending auth code for processing when db is ready
|
|
8275
|
-
pendingOAuthCode = {
|
|
8388
|
+
pendingOAuthCode = {
|
|
8389
|
+
code: callback.code,
|
|
8390
|
+
provider: callback.provider,
|
|
8391
|
+
};
|
|
8276
8392
|
console.debug('[dexie-cloud] OAuth callback detected, auth code stored for processing');
|
|
8277
8393
|
}
|
|
8278
8394
|
}
|
|
@@ -8389,7 +8505,7 @@ function dexieCloud(dexie) {
|
|
|
8389
8505
|
if (eagerBlobDownloadInFlight)
|
|
8390
8506
|
return;
|
|
8391
8507
|
eagerBlobDownloadInFlight = Dexie.ignoreTransaction(() => downloadUnresolvedBlobs(db, downloading$))
|
|
8392
|
-
.catch(err => {
|
|
8508
|
+
.catch((err) => {
|
|
8393
8509
|
console.error('[dexie-cloud] Eager blob download failed:', err);
|
|
8394
8510
|
})
|
|
8395
8511
|
.finally(() => {
|
|
@@ -8482,7 +8598,10 @@ function dexieCloud(dexie) {
|
|
|
8482
8598
|
// Let's assign all props as the newPersistedSchems should be what we should be working with.
|
|
8483
8599
|
Object.assign(schema, newPersistedSchema);
|
|
8484
8600
|
}
|
|
8485
|
-
return [
|
|
8601
|
+
return [
|
|
8602
|
+
persistedSyncState === null || persistedSyncState === void 0 ? void 0 : persistedSyncState.initiallySynced,
|
|
8603
|
+
persistedSyncState === null || persistedSyncState === void 0 ? void 0 : persistedSyncState.realms,
|
|
8604
|
+
];
|
|
8486
8605
|
}));
|
|
8487
8606
|
if (initiallySynced) {
|
|
8488
8607
|
db.setInitiallySynced(true);
|
|
@@ -8491,8 +8610,10 @@ function dexieCloud(dexie) {
|
|
|
8491
8610
|
// Manage CurrentUser observable:
|
|
8492
8611
|
throwIfClosed();
|
|
8493
8612
|
if (!db.cloud.isServiceWorkerDB) {
|
|
8494
|
-
subscriptions.push(liveQuery(() => db.getCurrentUser().then(user => {
|
|
8495
|
-
if (!user.isLoggedIn &&
|
|
8613
|
+
subscriptions.push(liveQuery(() => db.getCurrentUser().then((user) => {
|
|
8614
|
+
if (!user.isLoggedIn &&
|
|
8615
|
+
typeof location !== 'undefined' &&
|
|
8616
|
+
/dxc-auth\=/.test(location.search)) {
|
|
8496
8617
|
// Still loading user because OAuth redirect just happened.
|
|
8497
8618
|
// Keep isLoading true.
|
|
8498
8619
|
return Object.assign(Object.assign({}, user), { isLoading: true });
|
|
@@ -8530,7 +8651,7 @@ function dexieCloud(dexie) {
|
|
|
8530
8651
|
type: 'error',
|
|
8531
8652
|
messageCode: 'GENERIC_ERROR',
|
|
8532
8653
|
message: error.message,
|
|
8533
|
-
messageParams: { provider: error.provider || 'unknown' }
|
|
8654
|
+
messageParams: { provider: error.provider || 'unknown' },
|
|
8534
8655
|
});
|
|
8535
8656
|
// Clean up URL (remove dxc-auth param)
|
|
8536
8657
|
cleanupOAuthUrl();
|
|
@@ -8580,7 +8701,8 @@ function dexieCloud(dexie) {
|
|
|
8580
8701
|
}
|
|
8581
8702
|
}
|
|
8582
8703
|
}
|
|
8583
|
-
if (user.isLoggedIn &&
|
|
8704
|
+
if (user.isLoggedIn &&
|
|
8705
|
+
(!lastSyncedRealms || !lastSyncedRealms.includes(user.userId))) {
|
|
8584
8706
|
// User has been logged in but this is not reflected in the sync state.
|
|
8585
8707
|
// This can happen if page is reloaded after login but before the sync call following
|
|
8586
8708
|
// the login was complete.
|
|
@@ -8643,7 +8765,7 @@ function dexieCloud(dexie) {
|
|
|
8643
8765
|
}
|
|
8644
8766
|
}
|
|
8645
8767
|
// @ts-ignore
|
|
8646
|
-
dexieCloud.version = "4.4.
|
|
8768
|
+
dexieCloud.version = "4.4.8";
|
|
8647
8769
|
Dexie.Cloud = dexieCloud;
|
|
8648
8770
|
|
|
8649
8771
|
// In case the SW lives for a while, let it reuse already opened connections:
|
|
@@ -8735,14 +8857,14 @@ if (!DISABLE_SERVICEWORKER_STRATEGY) {
|
|
|
8735
8857
|
console.debug('SW "sync" Event', event.tag);
|
|
8736
8858
|
const dbName = getDbNameFromTag(event.tag);
|
|
8737
8859
|
if (dbName) {
|
|
8738
|
-
event.waitUntil(syncDB(dbName,
|
|
8860
|
+
event.waitUntil(syncDB(dbName, 'push')); // The purpose of sync events are "push"
|
|
8739
8861
|
}
|
|
8740
8862
|
});
|
|
8741
8863
|
self.addEventListener('periodicsync', (event) => {
|
|
8742
8864
|
console.debug('SW "periodicsync" Event', event.tag);
|
|
8743
8865
|
const dbName = getDbNameFromTag(event.tag);
|
|
8744
8866
|
if (dbName) {
|
|
8745
|
-
event.waitUntil(syncDB(dbName,
|
|
8867
|
+
event.waitUntil(syncDB(dbName, 'pull')); // The purpose of periodic sync events are "pull"
|
|
8746
8868
|
}
|
|
8747
8869
|
});
|
|
8748
8870
|
self.addEventListener('message', (event) => {
|
|
@@ -8752,7 +8874,7 @@ if (!DISABLE_SERVICEWORKER_STRATEGY) {
|
|
|
8752
8874
|
// Mimic background sync behavior - retry in X minutes on failure.
|
|
8753
8875
|
// But lesser timeout and more number of times.
|
|
8754
8876
|
const syncAndRetry = (num = 1) => {
|
|
8755
|
-
return syncDB(dbName, event.data.purpose ||
|
|
8877
|
+
return syncDB(dbName, event.data.purpose || 'pull').catch((e) => __awaiter(void 0, void 0, void 0, function* () {
|
|
8756
8878
|
if (num === 3)
|
|
8757
8879
|
throw e;
|
|
8758
8880
|
yield sleep(60000); // 1 minute
|
|
@@ -8760,10 +8882,10 @@ if (!DISABLE_SERVICEWORKER_STRATEGY) {
|
|
|
8760
8882
|
}));
|
|
8761
8883
|
};
|
|
8762
8884
|
if ('waitUntil' in event) {
|
|
8763
|
-
event.waitUntil(syncAndRetry().catch(error => console.error(error)));
|
|
8885
|
+
event.waitUntil(syncAndRetry().catch((error) => console.error(error)));
|
|
8764
8886
|
}
|
|
8765
8887
|
else {
|
|
8766
|
-
syncAndRetry().catch(error => console.error(error));
|
|
8888
|
+
syncAndRetry().catch((error) => console.error(error));
|
|
8767
8889
|
}
|
|
8768
8890
|
}
|
|
8769
8891
|
});
|