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
|
*
|
|
@@ -104,12 +104,12 @@
|
|
|
104
104
|
};
|
|
105
105
|
|
|
106
106
|
const UNAUTHORIZED_USER = {
|
|
107
|
-
userId:
|
|
108
|
-
name:
|
|
107
|
+
userId: 'unauthorized',
|
|
108
|
+
name: 'Unauthorized',
|
|
109
109
|
claims: {
|
|
110
|
-
sub:
|
|
110
|
+
sub: 'unauthorized',
|
|
111
111
|
},
|
|
112
|
-
lastLogin: new Date(0)
|
|
112
|
+
lastLogin: new Date(0),
|
|
113
113
|
};
|
|
114
114
|
try {
|
|
115
115
|
Object.freeze(UNAUTHORIZED_USER);
|
|
@@ -118,8 +118,10 @@
|
|
|
118
118
|
catch (_a) { }
|
|
119
119
|
|
|
120
120
|
const swHolder = {};
|
|
121
|
-
const swContainer = typeof self !== 'undefined' &&
|
|
122
|
-
|
|
121
|
+
const swContainer = typeof self !== 'undefined' &&
|
|
122
|
+
self.document && // self.document is to verify we're not the SW ourself
|
|
123
|
+
typeof navigator !== 'undefined' &&
|
|
124
|
+
navigator.serviceWorker;
|
|
123
125
|
if (swContainer)
|
|
124
126
|
swContainer.ready.then((registration) => (swHolder.registration = registration));
|
|
125
127
|
if (typeof self !== 'undefined' && 'clients' in self && !self.document) {
|
|
@@ -173,7 +175,8 @@
|
|
|
173
175
|
}
|
|
174
176
|
}
|
|
175
177
|
|
|
176
|
-
const events = globalThis['lbc-events'] ||
|
|
178
|
+
const events = globalThis['lbc-events'] ||
|
|
179
|
+
(globalThis['lbc-events'] = new Map());
|
|
177
180
|
function addListener(name, listener) {
|
|
178
181
|
if (events.has(name)) {
|
|
179
182
|
events.get(name).push(listener);
|
|
@@ -194,25 +197,25 @@
|
|
|
194
197
|
function dispatch(ev) {
|
|
195
198
|
const listeners = events.get(ev.type);
|
|
196
199
|
if (listeners) {
|
|
197
|
-
listeners.forEach(listener => {
|
|
200
|
+
listeners.forEach((listener) => {
|
|
198
201
|
try {
|
|
199
202
|
listener(ev);
|
|
200
203
|
}
|
|
201
|
-
catch (_a) {
|
|
202
|
-
}
|
|
204
|
+
catch (_a) { }
|
|
203
205
|
});
|
|
204
206
|
}
|
|
205
207
|
}
|
|
206
208
|
class BroadcastedAndLocalEvent extends rxjs.Observable {
|
|
207
209
|
constructor(name) {
|
|
208
|
-
const bc = typeof BroadcastChannel ===
|
|
209
|
-
? new SWBroadcastChannel(name)
|
|
210
|
-
|
|
210
|
+
const bc = typeof BroadcastChannel === 'undefined'
|
|
211
|
+
? new SWBroadcastChannel(name)
|
|
212
|
+
: new BroadcastChannel(name);
|
|
213
|
+
super((subscriber) => {
|
|
211
214
|
function onCustomEvent(ev) {
|
|
212
215
|
subscriber.next(ev.detail);
|
|
213
216
|
}
|
|
214
217
|
function onMessageEvent(ev) {
|
|
215
|
-
console.debug(
|
|
218
|
+
console.debug('BroadcastedAndLocalEvent: onMessageEvent', ev);
|
|
216
219
|
subscriber.next(ev.data);
|
|
217
220
|
}
|
|
218
221
|
let unsubscribe;
|
|
@@ -220,11 +223,11 @@
|
|
|
220
223
|
addListener(`lbc-${name}`, onCustomEvent); // Works better in service worker
|
|
221
224
|
try {
|
|
222
225
|
if (bc instanceof SWBroadcastChannel) {
|
|
223
|
-
unsubscribe = bc.subscribe(message => subscriber.next(message));
|
|
226
|
+
unsubscribe = bc.subscribe((message) => subscriber.next(message));
|
|
224
227
|
}
|
|
225
228
|
else {
|
|
226
|
-
console.debug(
|
|
227
|
-
bc.addEventListener(
|
|
229
|
+
console.debug('BroadcastedAndLocalEvent: bc.addEventListener()', name, 'bc is a', bc);
|
|
230
|
+
bc.addEventListener('message', onMessageEvent);
|
|
228
231
|
}
|
|
229
232
|
}
|
|
230
233
|
catch (err) {
|
|
@@ -238,7 +241,7 @@
|
|
|
238
241
|
unsubscribe();
|
|
239
242
|
}
|
|
240
243
|
else {
|
|
241
|
-
bc.removeEventListener(
|
|
244
|
+
bc.removeEventListener('message', onMessageEvent);
|
|
242
245
|
}
|
|
243
246
|
};
|
|
244
247
|
});
|
|
@@ -246,7 +249,7 @@
|
|
|
246
249
|
this.bc = bc;
|
|
247
250
|
}
|
|
248
251
|
next(message) {
|
|
249
|
-
console.debug(
|
|
252
|
+
console.debug('BroadcastedAndLocalEvent: bc.postMessage()', Object.assign({}, message), 'bc is a', this.bc);
|
|
250
253
|
this.bc.postMessage(message);
|
|
251
254
|
const ev = new CustomEvent(`lbc-${this.name}`, { detail: message });
|
|
252
255
|
//self.dispatchEvent(ev);
|
|
@@ -261,7 +264,7 @@
|
|
|
261
264
|
try {
|
|
262
265
|
// Send sync event to SW:
|
|
263
266
|
const sw = yield navigator.serviceWorker.ready;
|
|
264
|
-
if (purpose ===
|
|
267
|
+
if (purpose === 'push' && sw.sync) {
|
|
265
268
|
yield sw.sync.register(`dexie-cloud:${db.name}`);
|
|
266
269
|
}
|
|
267
270
|
if (sw.active) {
|
|
@@ -270,7 +273,7 @@
|
|
|
270
273
|
sw.active.postMessage({
|
|
271
274
|
type: 'dexie-cloud-sync',
|
|
272
275
|
dbName: db.name,
|
|
273
|
-
purpose
|
|
276
|
+
purpose,
|
|
274
277
|
});
|
|
275
278
|
}
|
|
276
279
|
else {
|
|
@@ -330,7 +333,7 @@
|
|
|
330
333
|
const keys = Object.keys(value);
|
|
331
334
|
let dollarKeys = null;
|
|
332
335
|
for (let i = 0, l = keys.length; i < l; ++i) {
|
|
333
|
-
if (keys[i][0] ===
|
|
336
|
+
if (keys[i][0] === '$') {
|
|
334
337
|
dollarKeys = dollarKeys || [];
|
|
335
338
|
dollarKeys.push(keys[i]);
|
|
336
339
|
}
|
|
@@ -342,7 +345,7 @@
|
|
|
342
345
|
delete clone[k];
|
|
343
346
|
}
|
|
344
347
|
for (const k of dollarKeys) {
|
|
345
|
-
clone[
|
|
348
|
+
clone['$' + k] = value[k];
|
|
346
349
|
}
|
|
347
350
|
return clone;
|
|
348
351
|
}
|
|
@@ -393,7 +396,7 @@
|
|
|
393
396
|
//
|
|
394
397
|
// Child part
|
|
395
398
|
//
|
|
396
|
-
if (value === undefined || (key[0] ===
|
|
399
|
+
if (value === undefined || (key[0] === '$' && key !== '$t')) {
|
|
397
400
|
top = stack[stack.length - 1];
|
|
398
401
|
let deletes;
|
|
399
402
|
let mods;
|
|
@@ -404,7 +407,7 @@
|
|
|
404
407
|
else {
|
|
405
408
|
stack.push([this, (deletes = []), (mods = {})]);
|
|
406
409
|
}
|
|
407
|
-
if (key[0] ===
|
|
410
|
+
if (key[0] === '$' && key !== '$t') {
|
|
408
411
|
// Unescape props (also preserves undefined if this is a combo)
|
|
409
412
|
deletes.push(key);
|
|
410
413
|
mods[key.substr(1)] = value;
|
|
@@ -421,8 +424,8 @@
|
|
|
421
424
|
function getTypeDef(realVal) {
|
|
422
425
|
const type = typeof realVal;
|
|
423
426
|
switch (typeof realVal) {
|
|
424
|
-
case
|
|
425
|
-
case
|
|
427
|
+
case 'object':
|
|
428
|
+
case 'function': {
|
|
426
429
|
// "object", "function", null
|
|
427
430
|
if (realVal === null)
|
|
428
431
|
return null;
|
|
@@ -438,7 +441,7 @@
|
|
|
438
441
|
if (!typeDef) {
|
|
439
442
|
typeDef = Array.isArray(realVal)
|
|
440
443
|
? null
|
|
441
|
-
: typeof realVal ===
|
|
444
|
+
: typeof realVal === 'function'
|
|
442
445
|
? typeDefs.function || null
|
|
443
446
|
: ObjectDef;
|
|
444
447
|
}
|
|
@@ -614,13 +617,13 @@
|
|
|
614
617
|
|
|
615
618
|
function readBlobSync(b) {
|
|
616
619
|
const req = new XMLHttpRequest();
|
|
617
|
-
req.overrideMimeType(
|
|
620
|
+
req.overrideMimeType('text/plain; charset=x-user-defined');
|
|
618
621
|
const url = URL.createObjectURL(b);
|
|
619
622
|
try {
|
|
620
|
-
req.open(
|
|
623
|
+
req.open('GET', url, false); // Sync
|
|
621
624
|
req.send();
|
|
622
625
|
if (req.status !== 200 && req.status !== 0) {
|
|
623
|
-
throw new Error(
|
|
626
|
+
throw new Error('Bad Blob access: ' + req.status);
|
|
624
627
|
}
|
|
625
628
|
return req.responseText;
|
|
626
629
|
}
|
|
@@ -634,11 +637,11 @@
|
|
|
634
637
|
replace: (num) => {
|
|
635
638
|
switch (true) {
|
|
636
639
|
case isNaN(num):
|
|
637
|
-
return { $t:
|
|
640
|
+
return { $t: 'number', v: 'NaN' };
|
|
638
641
|
case num === Infinity:
|
|
639
|
-
return { $t:
|
|
642
|
+
return { $t: 'number', v: 'Infinity' };
|
|
640
643
|
case num === -Infinity:
|
|
641
|
-
return { $t:
|
|
644
|
+
return { $t: 'number', v: '-Infinity' };
|
|
642
645
|
default:
|
|
643
646
|
return num;
|
|
644
647
|
}
|
|
@@ -650,17 +653,17 @@
|
|
|
650
653
|
const dateTypeDef = {
|
|
651
654
|
Date: {
|
|
652
655
|
replace: (date) => ({
|
|
653
|
-
$t:
|
|
654
|
-
v: isNaN(date.getTime()) ?
|
|
656
|
+
$t: 'Date',
|
|
657
|
+
v: isNaN(date.getTime()) ? 'NaN' : date.toISOString(),
|
|
655
658
|
}),
|
|
656
|
-
revive: ({ v }) => new Date(v ===
|
|
659
|
+
revive: ({ v }) => new Date(v === 'NaN' ? NaN : Date.parse(v)),
|
|
657
660
|
},
|
|
658
661
|
};
|
|
659
662
|
|
|
660
663
|
const setTypeDef = {
|
|
661
664
|
Set: {
|
|
662
665
|
replace: (set) => ({
|
|
663
|
-
$t:
|
|
666
|
+
$t: 'Set',
|
|
664
667
|
v: Array.from(set),
|
|
665
668
|
}),
|
|
666
669
|
revive: ({ v }) => new Set(v),
|
|
@@ -670,34 +673,34 @@
|
|
|
670
673
|
const mapTypeDef = {
|
|
671
674
|
Map: {
|
|
672
675
|
replace: (map) => ({
|
|
673
|
-
$t:
|
|
676
|
+
$t: 'Map',
|
|
674
677
|
v: Array.from(map.entries()),
|
|
675
678
|
}),
|
|
676
679
|
revive: ({ v }) => new Map(v),
|
|
677
680
|
},
|
|
678
681
|
};
|
|
679
682
|
|
|
680
|
-
const _global = typeof globalThis !==
|
|
683
|
+
const _global = typeof globalThis !== 'undefined' // All modern environments (node, bun, deno, browser, workers, webview etc)
|
|
681
684
|
? globalThis
|
|
682
|
-
: typeof self !==
|
|
685
|
+
: typeof self !== 'undefined' // Older browsers, workers, webview, window etc
|
|
683
686
|
? self
|
|
684
|
-
: typeof global !==
|
|
687
|
+
: typeof global !== 'undefined' // Older versions of node
|
|
685
688
|
? global
|
|
686
689
|
: undefined; // Unsupported environment. No idea to return 'this' since we are in a module or a function scope anyway.
|
|
687
690
|
|
|
688
691
|
const typedArrayTypeDefs = [
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
692
|
+
'Int8Array',
|
|
693
|
+
'Uint8Array',
|
|
694
|
+
'Uint8ClampedArray',
|
|
695
|
+
'Int16Array',
|
|
696
|
+
'Uint16Array',
|
|
697
|
+
'Int32Array',
|
|
698
|
+
'Uint32Array',
|
|
699
|
+
'Float32Array',
|
|
700
|
+
'Float64Array',
|
|
701
|
+
'DataView',
|
|
702
|
+
'BigInt64Array',
|
|
703
|
+
'BigUint64Array',
|
|
701
704
|
].reduce((specs, typeName) => ({
|
|
702
705
|
...specs,
|
|
703
706
|
[typeName]: {
|
|
@@ -725,10 +728,10 @@
|
|
|
725
728
|
},
|
|
726
729
|
}), {});
|
|
727
730
|
|
|
728
|
-
const hasArrayBufferFromBase64 =
|
|
729
|
-
const hasArrayBufferToBase64 =
|
|
730
|
-
const b64decode = typeof Buffer !==
|
|
731
|
-
? (base64) => Buffer.from(base64,
|
|
731
|
+
const hasArrayBufferFromBase64 = 'fromBase64' in Uint8Array; // https://github.com/tc39/proposal-arraybuffer-base64;
|
|
732
|
+
const hasArrayBufferToBase64 = 'toBase64' in Uint8Array.prototype; // https://github.com/tc39/proposal-arraybuffer-base64;
|
|
733
|
+
const b64decode = typeof Buffer !== 'undefined'
|
|
734
|
+
? (base64) => Buffer.from(base64, 'base64') // Node
|
|
732
735
|
: hasArrayBufferFromBase64
|
|
733
736
|
? // @ts-ignore: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array/fromBase64
|
|
734
737
|
(base64) => Uint8Array.fromBase64(base64) // Modern javascript standard
|
|
@@ -742,14 +745,14 @@
|
|
|
742
745
|
}
|
|
743
746
|
return bytes;
|
|
744
747
|
};
|
|
745
|
-
const b64encode = typeof Buffer !==
|
|
748
|
+
const b64encode = typeof Buffer !== 'undefined'
|
|
746
749
|
? (b) => {
|
|
747
750
|
// Node
|
|
748
751
|
if (ArrayBuffer.isView(b)) {
|
|
749
|
-
return Buffer.from(b.buffer, b.byteOffset, b.byteLength).toString(
|
|
752
|
+
return Buffer.from(b.buffer, b.byteOffset, b.byteLength).toString('base64');
|
|
750
753
|
}
|
|
751
754
|
else {
|
|
752
|
-
return Buffer.from(b).toString(
|
|
755
|
+
return Buffer.from(b).toString('base64');
|
|
753
756
|
}
|
|
754
757
|
}
|
|
755
758
|
: hasArrayBufferToBase64
|
|
@@ -768,7 +771,7 @@
|
|
|
768
771
|
const chunk = u8a.subarray(i, i + CHUNK_SIZE);
|
|
769
772
|
strs.push(String.fromCharCode.apply(null, Array.from(chunk)));
|
|
770
773
|
}
|
|
771
|
-
return btoa(strs.join(
|
|
774
|
+
return btoa(strs.join(''));
|
|
772
775
|
};
|
|
773
776
|
|
|
774
777
|
function b64LexEncode(b) {
|
|
@@ -778,7 +781,7 @@
|
|
|
778
781
|
return b64decode(lexToB64(b64Lex));
|
|
779
782
|
}
|
|
780
783
|
function b64ToLex(base64) {
|
|
781
|
-
var encoded =
|
|
784
|
+
var encoded = '';
|
|
782
785
|
for (var i = 0, length = base64.length; i < length; i++) {
|
|
783
786
|
encoded += ENCODE_TABLE[base64[i]];
|
|
784
787
|
}
|
|
@@ -786,81 +789,81 @@
|
|
|
786
789
|
}
|
|
787
790
|
function lexToB64(base64lex) {
|
|
788
791
|
// only accept string input
|
|
789
|
-
if (typeof base64lex !==
|
|
790
|
-
throw new Error(
|
|
792
|
+
if (typeof base64lex !== 'string') {
|
|
793
|
+
throw new Error('invalid decoder input: ' + base64lex);
|
|
791
794
|
}
|
|
792
|
-
var base64 =
|
|
795
|
+
var base64 = '';
|
|
793
796
|
for (var i = 0, length = base64lex.length; i < length; i++) {
|
|
794
797
|
base64 += DECODE_TABLE[base64lex[i]];
|
|
795
798
|
}
|
|
796
799
|
return base64;
|
|
797
800
|
}
|
|
798
801
|
const DECODE_TABLE = {
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
A:
|
|
811
|
-
B:
|
|
812
|
-
C:
|
|
813
|
-
D:
|
|
814
|
-
E:
|
|
815
|
-
F:
|
|
816
|
-
G:
|
|
817
|
-
H:
|
|
818
|
-
I:
|
|
819
|
-
J:
|
|
820
|
-
K:
|
|
821
|
-
L:
|
|
822
|
-
M:
|
|
823
|
-
N:
|
|
824
|
-
O:
|
|
825
|
-
P:
|
|
826
|
-
Q:
|
|
827
|
-
R:
|
|
828
|
-
S:
|
|
829
|
-
T:
|
|
830
|
-
U:
|
|
831
|
-
V:
|
|
832
|
-
W:
|
|
833
|
-
X:
|
|
834
|
-
Y:
|
|
835
|
-
Z:
|
|
836
|
-
_:
|
|
837
|
-
a:
|
|
838
|
-
b:
|
|
839
|
-
c:
|
|
840
|
-
d:
|
|
841
|
-
e:
|
|
842
|
-
f:
|
|
843
|
-
g:
|
|
844
|
-
h:
|
|
845
|
-
i:
|
|
846
|
-
j:
|
|
847
|
-
k:
|
|
848
|
-
l:
|
|
849
|
-
m:
|
|
850
|
-
n:
|
|
851
|
-
o:
|
|
852
|
-
p:
|
|
853
|
-
q:
|
|
854
|
-
r:
|
|
855
|
-
s:
|
|
856
|
-
t:
|
|
857
|
-
u:
|
|
858
|
-
v:
|
|
859
|
-
w:
|
|
860
|
-
x:
|
|
861
|
-
y:
|
|
862
|
-
z:
|
|
863
|
-
|
|
802
|
+
'-': '=',
|
|
803
|
+
'0': 'A',
|
|
804
|
+
'1': 'B',
|
|
805
|
+
'2': 'C',
|
|
806
|
+
'3': 'D',
|
|
807
|
+
'4': 'E',
|
|
808
|
+
'5': 'F',
|
|
809
|
+
'6': 'G',
|
|
810
|
+
'7': 'H',
|
|
811
|
+
'8': 'I',
|
|
812
|
+
'9': 'J',
|
|
813
|
+
A: 'K',
|
|
814
|
+
B: 'L',
|
|
815
|
+
C: 'M',
|
|
816
|
+
D: 'N',
|
|
817
|
+
E: 'O',
|
|
818
|
+
F: 'P',
|
|
819
|
+
G: 'Q',
|
|
820
|
+
H: 'R',
|
|
821
|
+
I: 'S',
|
|
822
|
+
J: 'T',
|
|
823
|
+
K: 'U',
|
|
824
|
+
L: 'V',
|
|
825
|
+
M: 'W',
|
|
826
|
+
N: 'X',
|
|
827
|
+
O: 'Y',
|
|
828
|
+
P: 'Z',
|
|
829
|
+
Q: 'a',
|
|
830
|
+
R: 'b',
|
|
831
|
+
S: 'c',
|
|
832
|
+
T: 'd',
|
|
833
|
+
U: 'e',
|
|
834
|
+
V: 'f',
|
|
835
|
+
W: 'g',
|
|
836
|
+
X: 'h',
|
|
837
|
+
Y: 'i',
|
|
838
|
+
Z: 'j',
|
|
839
|
+
_: 'k',
|
|
840
|
+
a: 'l',
|
|
841
|
+
b: 'm',
|
|
842
|
+
c: 'n',
|
|
843
|
+
d: 'o',
|
|
844
|
+
e: 'p',
|
|
845
|
+
f: 'q',
|
|
846
|
+
g: 'r',
|
|
847
|
+
h: 's',
|
|
848
|
+
i: 't',
|
|
849
|
+
j: 'u',
|
|
850
|
+
k: 'v',
|
|
851
|
+
l: 'w',
|
|
852
|
+
m: 'x',
|
|
853
|
+
n: 'y',
|
|
854
|
+
o: 'z',
|
|
855
|
+
p: '0',
|
|
856
|
+
q: '1',
|
|
857
|
+
r: '2',
|
|
858
|
+
s: '3',
|
|
859
|
+
t: '4',
|
|
860
|
+
u: '5',
|
|
861
|
+
v: '6',
|
|
862
|
+
w: '7',
|
|
863
|
+
x: '8',
|
|
864
|
+
y: '9',
|
|
865
|
+
z: '+',
|
|
866
|
+
'|': '/',
|
|
864
867
|
};
|
|
865
868
|
const ENCODE_TABLE = {};
|
|
866
869
|
for (const c of Object.keys(DECODE_TABLE)) {
|
|
@@ -870,7 +873,7 @@
|
|
|
870
873
|
const arrayBufferTypeDef = {
|
|
871
874
|
ArrayBuffer: {
|
|
872
875
|
replace: (ab) => ({
|
|
873
|
-
$t:
|
|
876
|
+
$t: 'ArrayBuffer',
|
|
874
877
|
v: b64LexEncode(ab),
|
|
875
878
|
}),
|
|
876
879
|
revive: ({ v }) => {
|
|
@@ -893,9 +896,9 @@
|
|
|
893
896
|
|
|
894
897
|
const blobTypeDef = {
|
|
895
898
|
Blob: {
|
|
896
|
-
test: (blob, toStringTag) => toStringTag ===
|
|
899
|
+
test: (blob, toStringTag) => toStringTag === 'Blob' || blob instanceof FakeBlob,
|
|
897
900
|
replace: (blob) => ({
|
|
898
|
-
$t:
|
|
901
|
+
$t: 'Blob',
|
|
899
902
|
v: blob instanceof FakeBlob
|
|
900
903
|
? b64encode(blob.buf)
|
|
901
904
|
: b64encode(string2ArrayBuffer(readBlobSync(blob))),
|
|
@@ -906,7 +909,7 @@
|
|
|
906
909
|
const buf = ab.buffer.byteLength === ab.byteLength
|
|
907
910
|
? ab.buffer
|
|
908
911
|
: ab.buffer.slice(ab.byteOffset, ab.byteOffset + ab.byteLength);
|
|
909
|
-
return typeof Blob !==
|
|
912
|
+
return typeof Blob !== 'undefined'
|
|
910
913
|
? new Blob([new Uint8Array(buf)], { type })
|
|
911
914
|
: new FakeBlob(buf, type);
|
|
912
915
|
},
|
|
@@ -925,15 +928,15 @@
|
|
|
925
928
|
|
|
926
929
|
const fileTypeDef = {
|
|
927
930
|
File: {
|
|
928
|
-
test: (file, toStringTag) => toStringTag ===
|
|
931
|
+
test: (file, toStringTag) => toStringTag === 'File',
|
|
929
932
|
replace: (file) => ({
|
|
930
|
-
$t:
|
|
933
|
+
$t: 'File',
|
|
931
934
|
v: b64encode(string2ArrayBuffer(readBlobSync(file))),
|
|
932
935
|
type: file.type,
|
|
933
936
|
name: file.name,
|
|
934
937
|
lastModified: new Date(file.lastModified).toISOString(),
|
|
935
938
|
}),
|
|
936
|
-
revive: ({ type, v, name, lastModified }) => {
|
|
939
|
+
revive: ({ type, v, name, lastModified, }) => {
|
|
937
940
|
const ab = b64decode(v);
|
|
938
941
|
const buf = ab.buffer.byteLength === ab.byteLength
|
|
939
942
|
? ab.buffer
|
|
@@ -957,13 +960,13 @@
|
|
|
957
960
|
const undefinedTypeDef = {
|
|
958
961
|
undefined: {
|
|
959
962
|
replace: () => ({
|
|
960
|
-
$t:
|
|
963
|
+
$t: 'undefined',
|
|
961
964
|
}),
|
|
962
965
|
revive: () => undefined,
|
|
963
966
|
},
|
|
964
967
|
};
|
|
965
968
|
|
|
966
|
-
const getRandomValues$1 = typeof crypto !==
|
|
969
|
+
const getRandomValues$1 = typeof crypto !== 'undefined'
|
|
967
970
|
? crypto.getRandomValues.bind(crypto)
|
|
968
971
|
: (buf) => {
|
|
969
972
|
for (let i = 0; i < buf.length; ++i) {
|
|
@@ -1064,7 +1067,7 @@
|
|
|
1064
1067
|
var innerObj = obj[currentKeyPath];
|
|
1065
1068
|
//@ts-ignore: even if currentKeyPath would be numeric string and obj would be array - it works.
|
|
1066
1069
|
if (!innerObj || !hasOwn(obj, currentKeyPath))
|
|
1067
|
-
innerObj =
|
|
1070
|
+
innerObj = obj[currentKeyPath] = {};
|
|
1068
1071
|
setByKeyPath(innerObj, remainingKeyPath, value);
|
|
1069
1072
|
}
|
|
1070
1073
|
}
|
|
@@ -1083,17 +1086,23 @@
|
|
|
1083
1086
|
}
|
|
1084
1087
|
}
|
|
1085
1088
|
}
|
|
1086
|
-
const randomString$1 = typeof self !== 'undefined' && typeof crypto !== 'undefined'
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1089
|
+
const randomString$1 = typeof self !== 'undefined' && typeof crypto !== 'undefined'
|
|
1090
|
+
? (bytes, randomFill = crypto.getRandomValues.bind(crypto)) => {
|
|
1091
|
+
// Web
|
|
1092
|
+
const buf = new Uint8Array(bytes);
|
|
1093
|
+
randomFill(buf);
|
|
1094
|
+
return self.btoa(String.fromCharCode.apply(null, buf));
|
|
1095
|
+
}
|
|
1096
|
+
: typeof Buffer !== 'undefined'
|
|
1097
|
+
? (bytes, randomFill = simpleRandomFill) => {
|
|
1098
|
+
// Node
|
|
1099
|
+
const buf = Buffer.alloc(bytes);
|
|
1100
|
+
randomFill(buf);
|
|
1101
|
+
return buf.toString('base64');
|
|
1102
|
+
}
|
|
1103
|
+
: () => {
|
|
1104
|
+
throw new Error('No implementation of randomString was found');
|
|
1105
|
+
};
|
|
1097
1106
|
function simpleRandomFill(buf) {
|
|
1098
1107
|
for (let i = 0; i < buf.length; ++i) {
|
|
1099
1108
|
buf[i] = Math.floor(Math.random() * 256);
|
|
@@ -1112,11 +1121,13 @@
|
|
|
1112
1121
|
* @returns
|
|
1113
1122
|
*/
|
|
1114
1123
|
function isValidSyncableID(id) {
|
|
1115
|
-
if (typeof id ===
|
|
1124
|
+
if (typeof id === 'string')
|
|
1116
1125
|
return true;
|
|
1117
1126
|
//if (validIDTypes[toStringTag(id)]) return true;
|
|
1118
1127
|
//if (Array.isArray(id)) return id.every((part) => isValidSyncableID(part));
|
|
1119
|
-
if (Array.isArray(id) &&
|
|
1128
|
+
if (Array.isArray(id) &&
|
|
1129
|
+
id.some((key) => isValidSyncableID(key)) &&
|
|
1130
|
+
id.every(isValidSyncableIDPart))
|
|
1120
1131
|
return true;
|
|
1121
1132
|
return false;
|
|
1122
1133
|
}
|
|
@@ -1125,53 +1136,53 @@
|
|
|
1125
1136
|
* For example, ArrayBuffer cannot be used (gives "object ArrayBuffer") but Uint8Array can be
|
|
1126
1137
|
* used (gives comma-delimited list of included bytes).
|
|
1127
1138
|
* 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.
|
|
1128
|
-
|
|
1139
|
+
*/
|
|
1129
1140
|
function isValidSyncableIDPart(part) {
|
|
1130
|
-
return typeof part ===
|
|
1141
|
+
return (typeof part === 'string' ||
|
|
1142
|
+
typeof part === 'number' ||
|
|
1143
|
+
(Array.isArray(part) && part.every(isValidSyncableIDPart)));
|
|
1131
1144
|
}
|
|
1132
1145
|
function isValidAtID(id, idPrefix) {
|
|
1133
|
-
return !idPrefix || (typeof id ===
|
|
1146
|
+
return !idPrefix || (typeof id === 'string' && id.startsWith(idPrefix));
|
|
1134
1147
|
}
|
|
1135
1148
|
|
|
1136
1149
|
function applyOperation(target, table, op) {
|
|
1137
1150
|
const tbl = target[table] || (target[table] = {});
|
|
1138
|
-
const keys = op.keys.map(key => typeof key === 'string' ? key : JSON.stringify(key));
|
|
1151
|
+
const keys = op.keys.map((key) => typeof key === 'string' ? key : JSON.stringify(key));
|
|
1139
1152
|
switch (op.type) {
|
|
1140
|
-
case
|
|
1153
|
+
case 'insert':
|
|
1141
1154
|
// TODO: Don't treat insert and upsert the same?
|
|
1142
|
-
case
|
|
1155
|
+
case 'upsert':
|
|
1143
1156
|
keys.forEach((key, idx) => {
|
|
1144
1157
|
tbl[key] = {
|
|
1145
|
-
type:
|
|
1158
|
+
type: 'ups',
|
|
1146
1159
|
val: op.values[idx],
|
|
1147
1160
|
};
|
|
1148
1161
|
});
|
|
1149
1162
|
break;
|
|
1150
|
-
case
|
|
1151
|
-
case
|
|
1163
|
+
case 'update':
|
|
1164
|
+
case 'modify': {
|
|
1152
1165
|
keys.forEach((key, idx) => {
|
|
1153
|
-
const changeSpec = op.type ===
|
|
1154
|
-
? op.changeSpecs[idx]
|
|
1155
|
-
: op.changeSpec;
|
|
1166
|
+
const changeSpec = op.type === 'update' ? op.changeSpecs[idx] : op.changeSpec;
|
|
1156
1167
|
const entry = tbl[key];
|
|
1157
1168
|
if (!entry) {
|
|
1158
1169
|
tbl[key] = {
|
|
1159
|
-
type:
|
|
1170
|
+
type: 'upd',
|
|
1160
1171
|
mod: changeSpec,
|
|
1161
1172
|
};
|
|
1162
1173
|
}
|
|
1163
1174
|
else {
|
|
1164
1175
|
switch (entry.type) {
|
|
1165
|
-
case
|
|
1176
|
+
case 'ups':
|
|
1166
1177
|
// Adjust the existing upsert with additional updates
|
|
1167
1178
|
for (const [propPath, value] of Object.entries(changeSpec)) {
|
|
1168
1179
|
setByKeyPath(entry.val, propPath, value);
|
|
1169
1180
|
}
|
|
1170
1181
|
break;
|
|
1171
|
-
case
|
|
1182
|
+
case 'del':
|
|
1172
1183
|
// No action.
|
|
1173
1184
|
break;
|
|
1174
|
-
case
|
|
1185
|
+
case 'upd':
|
|
1175
1186
|
// Adjust existing update with additional updates
|
|
1176
1187
|
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)
|
|
1177
1188
|
break;
|
|
@@ -1180,10 +1191,10 @@
|
|
|
1180
1191
|
});
|
|
1181
1192
|
break;
|
|
1182
1193
|
}
|
|
1183
|
-
case
|
|
1194
|
+
case 'delete':
|
|
1184
1195
|
keys.forEach((key) => {
|
|
1185
1196
|
tbl[key] = {
|
|
1186
|
-
type:
|
|
1197
|
+
type: 'del',
|
|
1187
1198
|
};
|
|
1188
1199
|
});
|
|
1189
1200
|
break;
|
|
@@ -1280,30 +1291,30 @@
|
|
|
1280
1291
|
};
|
|
1281
1292
|
for (const [optype, muts] of Object.entries(ops)) {
|
|
1282
1293
|
switch (optype) {
|
|
1283
|
-
case
|
|
1294
|
+
case 'ups': {
|
|
1284
1295
|
const op = {
|
|
1285
|
-
type:
|
|
1286
|
-
keys: muts.map(mut => mut.key),
|
|
1287
|
-
values: muts.map(mut => mut.val),
|
|
1288
|
-
txid
|
|
1296
|
+
type: 'upsert',
|
|
1297
|
+
keys: muts.map((mut) => mut.key),
|
|
1298
|
+
values: muts.map((mut) => mut.val),
|
|
1299
|
+
txid,
|
|
1289
1300
|
};
|
|
1290
1301
|
resultEntry.muts.push(op);
|
|
1291
1302
|
break;
|
|
1292
1303
|
}
|
|
1293
|
-
case
|
|
1304
|
+
case 'upd': {
|
|
1294
1305
|
const op = {
|
|
1295
|
-
type:
|
|
1296
|
-
keys: muts.map(mut => mut.key),
|
|
1297
|
-
changeSpecs: muts.map(mut => mut.mod),
|
|
1298
|
-
txid
|
|
1306
|
+
type: 'update',
|
|
1307
|
+
keys: muts.map((mut) => mut.key),
|
|
1308
|
+
changeSpecs: muts.map((mut) => mut.mod),
|
|
1309
|
+
txid,
|
|
1299
1310
|
};
|
|
1300
1311
|
resultEntry.muts.push(op);
|
|
1301
1312
|
break;
|
|
1302
1313
|
}
|
|
1303
|
-
case
|
|
1314
|
+
case 'del': {
|
|
1304
1315
|
const op = {
|
|
1305
|
-
type:
|
|
1306
|
-
keys: muts.map(mut => mut.key),
|
|
1316
|
+
type: 'delete',
|
|
1317
|
+
keys: muts.map((mut) => mut.key),
|
|
1307
1318
|
txid,
|
|
1308
1319
|
};
|
|
1309
1320
|
resultEntry.muts.push(op);
|
|
@@ -1318,7 +1329,7 @@
|
|
|
1318
1329
|
|
|
1319
1330
|
function getDbNameFromDbUrl(dbUrl) {
|
|
1320
1331
|
const url = new URL(dbUrl);
|
|
1321
|
-
return url.pathname ===
|
|
1332
|
+
return url.pathname === '/'
|
|
1322
1333
|
? url.hostname.split('.')[0]
|
|
1323
1334
|
: url.pathname.split('/')[1];
|
|
1324
1335
|
}
|
|
@@ -2739,7 +2750,8 @@
|
|
|
2739
2750
|
prop,
|
|
2740
2751
|
k,
|
|
2741
2752
|
u: readVarUint8Array(decoder),
|
|
2742
|
-
r: (decoder.pos < decoder.arr.length && readVarString(decoder)) ||
|
|
2753
|
+
r: (decoder.pos < decoder.arr.length && readVarString(decoder)) ||
|
|
2754
|
+
undefined,
|
|
2743
2755
|
};
|
|
2744
2756
|
default:
|
|
2745
2757
|
throw new TypeError(`Unknown message type: ${type}`);
|
|
@@ -2756,7 +2768,8 @@
|
|
|
2756
2768
|
}
|
|
2757
2769
|
// Start running the machine. If the last stage is a sink, it will consume the data and never emit anything
|
|
2758
2770
|
// to us here...
|
|
2759
|
-
for await (const chunk of result) {
|
|
2771
|
+
for await (const chunk of result) {
|
|
2772
|
+
}
|
|
2760
2773
|
}
|
|
2761
2774
|
|
|
2762
2775
|
async function* consumeChunkedBinaryStream(source) {
|
|
@@ -2810,7 +2823,7 @@
|
|
|
2810
2823
|
}
|
|
2811
2824
|
if (pos + len > chunk.byteLength) {
|
|
2812
2825
|
bufs.push(chunk.slice(pos));
|
|
2813
|
-
len -=
|
|
2826
|
+
len -= chunk.byteLength - pos;
|
|
2814
2827
|
state = 2;
|
|
2815
2828
|
pos = chunk.byteLength; // will break while loop.
|
|
2816
2829
|
}
|
|
@@ -2841,7 +2854,7 @@
|
|
|
2841
2854
|
function getFetchResponseBodyGenerator(res) {
|
|
2842
2855
|
return async function* () {
|
|
2843
2856
|
if (!res.body)
|
|
2844
|
-
throw new Error(
|
|
2857
|
+
throw new Error('Response body is not readable');
|
|
2845
2858
|
const reader = res.body.getReader();
|
|
2846
2859
|
try {
|
|
2847
2860
|
while (true) {
|
|
@@ -2949,7 +2962,7 @@
|
|
|
2949
2962
|
}
|
|
2950
2963
|
const strKey = '' + mut.keys[0];
|
|
2951
2964
|
const changeSpecs = mut.changeSpecs[0];
|
|
2952
|
-
if (Object.values(changeSpecs).some(v => typeof v ===
|
|
2965
|
+
if (Object.values(changeSpecs).some((v) => typeof v === 'object' && v && '@@propmod' in v)) {
|
|
2953
2966
|
continue; // Cannot optimize if any PropModification is present
|
|
2954
2967
|
}
|
|
2955
2968
|
let keyCoverage = updateCoverage.get(strKey);
|
|
@@ -2957,11 +2970,13 @@
|
|
|
2957
2970
|
keyCoverage.push({ txid: mut.txid, updateSpec: changeSpecs });
|
|
2958
2971
|
}
|
|
2959
2972
|
else {
|
|
2960
|
-
updateCoverage.set(strKey, [
|
|
2973
|
+
updateCoverage.set(strKey, [
|
|
2974
|
+
{ txid: mut.txid, updateSpec: changeSpecs },
|
|
2975
|
+
]);
|
|
2961
2976
|
}
|
|
2962
2977
|
}
|
|
2963
2978
|
}
|
|
2964
|
-
muts = muts.filter(mut => {
|
|
2979
|
+
muts = muts.filter((mut) => {
|
|
2965
2980
|
// Only apply optimization to update mutations that are single-key
|
|
2966
2981
|
if (mut.type !== 'update')
|
|
2967
2982
|
return true;
|
|
@@ -2969,7 +2984,7 @@
|
|
|
2969
2984
|
return true;
|
|
2970
2985
|
// Check if this has PropModifications - if so, skip optimization
|
|
2971
2986
|
const changeSpecs = mut.changeSpecs[0];
|
|
2972
|
-
if (Object.values(changeSpecs).some(v => typeof v ===
|
|
2987
|
+
if (Object.values(changeSpecs).some((v) => typeof v === 'object' && v && '@@propmod' in v)) {
|
|
2973
2988
|
return true; // Cannot optimize if any PropModification is present
|
|
2974
2989
|
}
|
|
2975
2990
|
// Keep track of properties that aren't overlapped by later transactions
|
|
@@ -2997,7 +3012,7 @@
|
|
|
2997
3012
|
return muts;
|
|
2998
3013
|
}
|
|
2999
3014
|
function canonicalizeToUpdateOps(muts) {
|
|
3000
|
-
muts = muts.map(mut => {
|
|
3015
|
+
muts = muts.map((mut) => {
|
|
3001
3016
|
if (mut.type === 'modify' && mut.criteria.index === null) {
|
|
3002
3017
|
// The criteria is on primary key. Convert to an update operation instead.
|
|
3003
3018
|
// It is simpler for the server to handle and also more efficient.
|
|
@@ -3163,14 +3178,15 @@
|
|
|
3163
3178
|
// the domain extension like .com, .net, etc.
|
|
3164
3179
|
// (\sas\s[\w-+.]+@([\w-]+\.)+[\w-]{2,10})?$ : This part is optional (due to the ? at the end).
|
|
3165
3180
|
// If present, it matches " as " followed by another valid email address. This allows for the
|
|
3166
|
-
// input to be either a single email address or two email addresses separated by " as ".
|
|
3181
|
+
// input to be either a single email address or two email addresses separated by " as ".
|
|
3167
3182
|
//
|
|
3168
3183
|
// The use case for "<email1> as <email2>"" is for when a database owner with full access to the
|
|
3169
3184
|
// database needs to impersonate another user in the database in order to troubleshoot. This
|
|
3170
3185
|
// format will only be possible to use when email1 is the owner of an API client with GLOBAL_READ
|
|
3171
3186
|
// and GLOBAL_WRITE permissions on the database. The email will be checked on the server before
|
|
3172
3187
|
// allowing it and giving out a token for email2, using the OTP sent to email1.
|
|
3173
|
-
while (!email ||
|
|
3188
|
+
while (!email ||
|
|
3189
|
+
!/^[\w-+.]+@([\w-]+\.)+[\w-]{2,10}(\sas\s[\w-+.]+@([\w-]+\.)+[\w-]{2,10})?$/.test(email)) {
|
|
3174
3190
|
const alerts = [];
|
|
3175
3191
|
if (firstPrompt && initialAlert)
|
|
3176
3192
|
alerts.push(initialAlert);
|
|
@@ -3236,7 +3252,7 @@
|
|
|
3236
3252
|
messageParams: {
|
|
3237
3253
|
currentUserId,
|
|
3238
3254
|
numUnsyncedChanges: numUnsyncedChanges.toString(),
|
|
3239
|
-
}
|
|
3255
|
+
},
|
|
3240
3256
|
},
|
|
3241
3257
|
];
|
|
3242
3258
|
return yield interactWithUser(userInteraction, {
|
|
@@ -3245,7 +3261,7 @@
|
|
|
3245
3261
|
alerts,
|
|
3246
3262
|
fields: {},
|
|
3247
3263
|
submitLabel: 'Confirm logout',
|
|
3248
|
-
cancelLabel: 'Cancel'
|
|
3264
|
+
cancelLabel: 'Cancel',
|
|
3249
3265
|
})
|
|
3250
3266
|
.then(() => true)
|
|
3251
3267
|
.catch(() => false);
|
|
@@ -3362,7 +3378,8 @@
|
|
|
3362
3378
|
if (!accessToken)
|
|
3363
3379
|
return null;
|
|
3364
3380
|
const expTime = (_a = accessTokenExpiration === null || accessTokenExpiration === void 0 ? void 0 : accessTokenExpiration.getTime()) !== null && _a !== void 0 ? _a : Infinity;
|
|
3365
|
-
if (expTime >
|
|
3381
|
+
if (expTime > Date.now() + 5 * MINUTES &&
|
|
3382
|
+
(((_b = currentUser.license) === null || _b === void 0 ? void 0 : _b.status) || 'ok') === 'ok') {
|
|
3366
3383
|
return currentUser;
|
|
3367
3384
|
}
|
|
3368
3385
|
if (!refreshToken) {
|
|
@@ -3522,11 +3539,13 @@
|
|
|
3522
3539
|
}
|
|
3523
3540
|
catch (error) {
|
|
3524
3541
|
// OAuth redirect is not an error - page is navigating away
|
|
3525
|
-
if (error instanceof OAuthRedirectError ||
|
|
3542
|
+
if (error instanceof OAuthRedirectError ||
|
|
3543
|
+
(error === null || error === void 0 ? void 0 : error.name) === 'OAuthRedirectError') {
|
|
3526
3544
|
throw error; // Re-throw without logging
|
|
3527
3545
|
}
|
|
3528
3546
|
// Policy rejections have already been shown to the user as a challenge
|
|
3529
|
-
if (error instanceof PolicyRejectionError ||
|
|
3547
|
+
if (error instanceof PolicyRejectionError ||
|
|
3548
|
+
(error === null || error === void 0 ? void 0 : error.name) === 'PolicyRejectionError') {
|
|
3530
3549
|
throw error;
|
|
3531
3550
|
}
|
|
3532
3551
|
if (error instanceof TokenErrorResponseError) {
|
|
@@ -3545,7 +3564,10 @@
|
|
|
3545
3564
|
if (isOffline) {
|
|
3546
3565
|
message = `You seem to be offline. Please connect to the internet and try again.`;
|
|
3547
3566
|
}
|
|
3548
|
-
else if (typeof location !== 'undefined' &&
|
|
3567
|
+
else if (typeof location !== 'undefined' &&
|
|
3568
|
+
(Dexie.debug ||
|
|
3569
|
+
location.hostname === 'localhost' ||
|
|
3570
|
+
location.hostname === '127.0.0.1')) {
|
|
3549
3571
|
// The audience is most likely the developer. Suggest to whitelist the localhost origin:
|
|
3550
3572
|
const whitelistCommand = `npx dexie-cloud whitelist ${location.origin}`;
|
|
3551
3573
|
message = `Could not connect to server. Please verify that your origin '${location.origin}' is whitelisted using \`npx dexie-cloud whitelist\``;
|
|
@@ -3648,7 +3670,7 @@
|
|
|
3648
3670
|
this.httpStatus = res.status;
|
|
3649
3671
|
}
|
|
3650
3672
|
get name() {
|
|
3651
|
-
return
|
|
3673
|
+
return 'HttpError';
|
|
3652
3674
|
}
|
|
3653
3675
|
}
|
|
3654
3676
|
|
|
@@ -3725,7 +3747,7 @@
|
|
|
3725
3747
|
const delatMilliseconds = ((_b = (_a = syncRatelimitDelays.get(db)) === null || _a === void 0 ? void 0 : _a.getTime()) !== null && _b !== void 0 ? _b : 0) - Date.now();
|
|
3726
3748
|
if (delatMilliseconds > 0) {
|
|
3727
3749
|
console.debug(`Stalling sync request ${delatMilliseconds} ms to spare ratelimits`);
|
|
3728
|
-
yield new Promise(resolve => setTimeout(resolve, delatMilliseconds));
|
|
3750
|
+
yield new Promise((resolve) => setTimeout(resolve, delatMilliseconds));
|
|
3729
3751
|
}
|
|
3730
3752
|
});
|
|
3731
3753
|
}
|
|
@@ -3790,7 +3812,7 @@
|
|
|
3790
3812
|
baseRevs,
|
|
3791
3813
|
changes: encodeIdsForServer(db.dx.core.schema, currentUser, changes),
|
|
3792
3814
|
y,
|
|
3793
|
-
dxcv: db.cloud.version
|
|
3815
|
+
dxcv: db.cloud.version,
|
|
3794
3816
|
};
|
|
3795
3817
|
console.debug('Sync request', syncRequest);
|
|
3796
3818
|
db.syncStateChangedEvent.next({
|
|
@@ -3830,19 +3852,22 @@
|
|
|
3830
3852
|
return __awaiter(this, void 0, void 0, function* () {
|
|
3831
3853
|
const ignoredRealms = new Set(alreadySyncedRealms || []);
|
|
3832
3854
|
for (const table of syncifiedTables) {
|
|
3833
|
-
if (table.name ===
|
|
3855
|
+
if (table.name === 'members') {
|
|
3834
3856
|
// members
|
|
3835
3857
|
yield table.toCollection().modify((member) => {
|
|
3836
|
-
if (!ignoredRealms.has(member.realmId) &&
|
|
3858
|
+
if (!ignoredRealms.has(member.realmId) &&
|
|
3859
|
+
(!member.userId || member.userId === UNAUTHORIZED_USER.userId)) {
|
|
3837
3860
|
member.userId = currentUser.userId;
|
|
3838
3861
|
}
|
|
3839
3862
|
});
|
|
3840
3863
|
}
|
|
3841
|
-
else if (table.name ===
|
|
3842
|
-
else if (table.name ===
|
|
3864
|
+
else if (table.name === 'roles') ;
|
|
3865
|
+
else if (table.name === 'realms') {
|
|
3843
3866
|
// realms
|
|
3844
3867
|
yield table.toCollection().modify((realm) => {
|
|
3845
|
-
if (!ignoredRealms.has(realm.realmId) &&
|
|
3868
|
+
if (!ignoredRealms.has(realm.realmId) &&
|
|
3869
|
+
(realm.owner === undefined ||
|
|
3870
|
+
realm.owner === UNAUTHORIZED_USER.userId)) {
|
|
3846
3871
|
realm.owner = currentUser.userId;
|
|
3847
3872
|
}
|
|
3848
3873
|
});
|
|
@@ -3875,8 +3900,8 @@
|
|
|
3875
3900
|
let isOnline = false;
|
|
3876
3901
|
if (typeof self !== 'undefined' && typeof navigator !== 'undefined') {
|
|
3877
3902
|
isOnline = navigator.onLine;
|
|
3878
|
-
self.addEventListener('online', () => isOnline = true);
|
|
3879
|
-
self.addEventListener('offline', () => isOnline = false);
|
|
3903
|
+
self.addEventListener('online', () => (isOnline = true));
|
|
3904
|
+
self.addEventListener('offline', () => (isOnline = false));
|
|
3880
3905
|
}
|
|
3881
3906
|
|
|
3882
3907
|
function updateBaseRevs(db, schema, latestRevisions, serverRev) {
|
|
@@ -3893,7 +3918,10 @@
|
|
|
3893
3918
|
}));
|
|
3894
3919
|
// Clean up baseRevs for tables that do not exist anymore or are no longer marked for sync
|
|
3895
3920
|
// Resolve #2168 by also cleaning up baseRevs for tables that are not marked for sync
|
|
3896
|
-
yield db.$baseRevs
|
|
3921
|
+
yield db.$baseRevs
|
|
3922
|
+
.where('tableName')
|
|
3923
|
+
.noneOf(Object.keys(schema).filter((table) => schema[table].markedForSync))
|
|
3924
|
+
.delete();
|
|
3897
3925
|
});
|
|
3898
3926
|
}
|
|
3899
3927
|
|
|
@@ -3986,11 +4014,11 @@
|
|
|
3986
4014
|
return false;
|
|
3987
4015
|
}
|
|
3988
4016
|
if (Array.isArray(obj)) {
|
|
3989
|
-
return obj.some(item => hasBlobRefs(item, visited));
|
|
4017
|
+
return obj.some((item) => hasBlobRefs(item, visited));
|
|
3990
4018
|
}
|
|
3991
4019
|
// Only traverse POJOs
|
|
3992
4020
|
if (obj.constructor === Object) {
|
|
3993
|
-
return Object.values(obj).some(value => hasBlobRefs(value, visited));
|
|
4021
|
+
return Object.values(obj).some((value) => hasBlobRefs(value, visited));
|
|
3994
4022
|
}
|
|
3995
4023
|
return false;
|
|
3996
4024
|
}
|
|
@@ -4054,7 +4082,8 @@
|
|
|
4054
4082
|
*/
|
|
4055
4083
|
function resolveAllBlobRefs(obj_1, dbUrl_1) {
|
|
4056
4084
|
return __awaiter(this, arguments, void 0, function* (obj, dbUrl, resolvedBlobs = [], currentPath = '', visited = new WeakMap(), tracker) {
|
|
4057
|
-
if (obj == null) {
|
|
4085
|
+
if (obj == null) {
|
|
4086
|
+
// null or undefined
|
|
4058
4087
|
return obj;
|
|
4059
4088
|
}
|
|
4060
4089
|
// Check if this is a BlobRef - resolve it and track it
|
|
@@ -4103,9 +4132,7 @@
|
|
|
4103
4132
|
* Check if an object has unresolved BlobRefs
|
|
4104
4133
|
*/
|
|
4105
4134
|
function hasUnresolvedBlobRefs(obj) {
|
|
4106
|
-
return (typeof obj === 'object' &&
|
|
4107
|
-
obj !== null &&
|
|
4108
|
-
obj._hasBlobRefs === 1);
|
|
4135
|
+
return (typeof obj === 'object' && obj !== null && obj._hasBlobRefs === 1);
|
|
4109
4136
|
}
|
|
4110
4137
|
|
|
4111
4138
|
/**
|
|
@@ -4214,10 +4241,7 @@
|
|
|
4214
4241
|
const DEXIE_CLOUD_SYNCER_ID = 'dexie-cloud-syncer';
|
|
4215
4242
|
|
|
4216
4243
|
function listUpdatesSince(yTable, sinceIncluding) {
|
|
4217
|
-
return yTable
|
|
4218
|
-
.where('i')
|
|
4219
|
-
.between(sinceIncluding, Infinity, true)
|
|
4220
|
-
.toArray();
|
|
4244
|
+
return yTable.where('i').between(sinceIncluding, Infinity, true).toArray();
|
|
4221
4245
|
}
|
|
4222
4246
|
|
|
4223
4247
|
/**
|
|
@@ -13569,7 +13593,7 @@
|
|
|
13569
13593
|
}
|
|
13570
13594
|
return {
|
|
13571
13595
|
yMessages: result,
|
|
13572
|
-
lastUpdateIds
|
|
13596
|
+
lastUpdateIds,
|
|
13573
13597
|
};
|
|
13574
13598
|
});
|
|
13575
13599
|
}
|
|
@@ -13578,7 +13602,8 @@
|
|
|
13578
13602
|
var _a, _b, _c;
|
|
13579
13603
|
if (!db.dx._allTables[table])
|
|
13580
13604
|
return undefined;
|
|
13581
|
-
const utbl = (_c = (_b = (_a = db
|
|
13605
|
+
const utbl = (_c = (_b = (_a = db
|
|
13606
|
+
.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;
|
|
13582
13607
|
if (!utbl) {
|
|
13583
13608
|
console.debug(`No updatesTable found for ${table}.${ydocProp}`);
|
|
13584
13609
|
return undefined;
|
|
@@ -13598,7 +13623,7 @@
|
|
|
13598
13623
|
*
|
|
13599
13624
|
* ==========================================================================
|
|
13600
13625
|
*
|
|
13601
|
-
* Version 4.4.0,
|
|
13626
|
+
* Version 4.4.0, Tue Mar 31 2026
|
|
13602
13627
|
*
|
|
13603
13628
|
* https://dexie.org
|
|
13604
13629
|
*
|
|
@@ -13615,7 +13640,7 @@
|
|
|
13615
13640
|
function getDocCache(db) {
|
|
13616
13641
|
var _a;
|
|
13617
13642
|
var _b;
|
|
13618
|
-
return (_a = (_b = db._novip)['_docCache']) !== null && _a !== void 0 ? _a : (_b['_docCache'] = {
|
|
13643
|
+
return ((_a = (_b = db._novip)['_docCache']) !== null && _a !== void 0 ? _a : (_b['_docCache'] = {
|
|
13619
13644
|
cache: {},
|
|
13620
13645
|
get size() {
|
|
13621
13646
|
return Object.keys(this.cache).length;
|
|
@@ -13646,7 +13671,7 @@
|
|
|
13646
13671
|
delete this.cache[cacheKey]; // Remove the entry from the cache only if it is the same doc.
|
|
13647
13672
|
}
|
|
13648
13673
|
},
|
|
13649
|
-
});
|
|
13674
|
+
}));
|
|
13650
13675
|
}
|
|
13651
13676
|
// Emulate a private boolean property "destroyed" on Y.Doc instances that we manage
|
|
13652
13677
|
// in createYDocProperty.ts:
|
|
@@ -13962,7 +13987,7 @@
|
|
|
13962
13987
|
}
|
|
13963
13988
|
throwIfDestroyed(doc);
|
|
13964
13989
|
this.stopObserving = observeYDocUpdates(this, doc, db, parentTable, updatesTable, parentId);
|
|
13965
|
-
DexieYProvider.on(
|
|
13990
|
+
DexieYProvider.on('new').fire(this); // Allow for addons to invoke their sync- and awareness providers here.
|
|
13966
13991
|
}
|
|
13967
13992
|
destroy() {
|
|
13968
13993
|
var _a, _b, _c;
|
|
@@ -13987,16 +14012,16 @@
|
|
|
13987
14012
|
});
|
|
13988
14013
|
DexieYProvider.getDocCache = getDocCache;
|
|
13989
14014
|
//
|
|
13990
|
-
// Eliminate dual package hazard
|
|
14015
|
+
// Eliminate dual package hazard
|
|
13991
14016
|
//
|
|
13992
14017
|
// Since we're holding static state, make sure to singletonize DexieYProvider
|
|
13993
14018
|
//
|
|
13994
|
-
if (Dexie.Dexie[
|
|
14019
|
+
if (Dexie.Dexie['DexieYProvider']) {
|
|
13995
14020
|
// @ts-ignore
|
|
13996
|
-
DexieYProvider = Dexie.Dexie[
|
|
14021
|
+
DexieYProvider = Dexie.Dexie['DexieYProvider'] || DexieYProvider;
|
|
13997
14022
|
}
|
|
13998
14023
|
else {
|
|
13999
|
-
Dexie.Dexie[
|
|
14024
|
+
Dexie.Dexie['DexieYProvider'] = DexieYProvider;
|
|
14000
14025
|
}
|
|
14001
14026
|
|
|
14002
14027
|
function applyYServerMessages(yMessages, db) {
|
|
@@ -14122,10 +14147,18 @@
|
|
|
14122
14147
|
*/
|
|
14123
14148
|
// TypedArray/DataView tags for size check
|
|
14124
14149
|
const ARRAYBUFFER_VIEW_TAGS = new Set([
|
|
14125
|
-
'Int8Array',
|
|
14126
|
-
'
|
|
14127
|
-
'
|
|
14128
|
-
'
|
|
14150
|
+
'Int8Array',
|
|
14151
|
+
'Uint8Array',
|
|
14152
|
+
'Uint8ClampedArray',
|
|
14153
|
+
'Int16Array',
|
|
14154
|
+
'Uint16Array',
|
|
14155
|
+
'Int32Array',
|
|
14156
|
+
'Uint32Array',
|
|
14157
|
+
'Float32Array',
|
|
14158
|
+
'Float64Array',
|
|
14159
|
+
'BigInt64Array',
|
|
14160
|
+
'BigUint64Array',
|
|
14161
|
+
'DataView',
|
|
14129
14162
|
]);
|
|
14130
14163
|
// Static Set for O(1) lookup of binary type tags
|
|
14131
14164
|
const BINARY_TYPE_TAGS = new Set([
|
|
@@ -14225,7 +14258,7 @@
|
|
|
14225
14258
|
const response = yield fetch(uploadUrl, {
|
|
14226
14259
|
method: 'PUT',
|
|
14227
14260
|
headers: {
|
|
14228
|
-
|
|
14261
|
+
Authorization: `Bearer ${accessToken}`,
|
|
14229
14262
|
'Content-Type': contentType,
|
|
14230
14263
|
},
|
|
14231
14264
|
body,
|
|
@@ -14241,8 +14274,7 @@
|
|
|
14241
14274
|
// The server returns the ref with version prefix (e.g., "1:blobId")
|
|
14242
14275
|
const result = yield response.json();
|
|
14243
14276
|
// Return BlobRef with server's ref (includes version) and original type preserved in _bt
|
|
14244
|
-
return Object.assign({ _bt: origType, ref: result.ref, size: size }, (origType === 'Blob' ? { ct: contentType } : {})
|
|
14245
|
-
);
|
|
14277
|
+
return Object.assign({ _bt: origType, ref: result.ref, size: size }, (origType === 'Blob' ? { ct: contentType } : {}));
|
|
14246
14278
|
});
|
|
14247
14279
|
}
|
|
14248
14280
|
function offloadBlobsAndMarkDirty(obj_1, databaseUrl_1, getCachedAccessToken_1) {
|
|
@@ -14250,7 +14282,10 @@
|
|
|
14250
14282
|
const dirtyFlag = { dirty: false };
|
|
14251
14283
|
const result = yield offloadBlobs(obj, databaseUrl, getCachedAccessToken, maxStringLength, dirtyFlag);
|
|
14252
14284
|
// Mark the object as dirty for sync if any blobs were offloaded
|
|
14253
|
-
if (dirtyFlag.dirty &&
|
|
14285
|
+
if (dirtyFlag.dirty &&
|
|
14286
|
+
typeof result === 'object' &&
|
|
14287
|
+
result !== null &&
|
|
14288
|
+
result.constructor === Object) {
|
|
14254
14289
|
result._hasBlobRefs = 1;
|
|
14255
14290
|
}
|
|
14256
14291
|
return result;
|
|
@@ -14266,7 +14301,9 @@
|
|
|
14266
14301
|
return obj;
|
|
14267
14302
|
}
|
|
14268
14303
|
// Check if this is a long string that should be offloaded
|
|
14269
|
-
if (typeof obj === 'string' &&
|
|
14304
|
+
if (typeof obj === 'string' &&
|
|
14305
|
+
obj.length > maxStringLength &&
|
|
14306
|
+
maxStringLength !== Infinity) {
|
|
14270
14307
|
if (blobEndpointSupported.get(databaseUrl) === false) {
|
|
14271
14308
|
return obj;
|
|
14272
14309
|
}
|
|
@@ -14352,11 +14389,11 @@
|
|
|
14352
14389
|
switch (op.type) {
|
|
14353
14390
|
case 'insert':
|
|
14354
14391
|
case 'upsert': {
|
|
14355
|
-
const processedValues = yield Promise.all(op.values.map(value => offloadBlobsAndMarkDirty(value, databaseUrl, getCachedAccessToken, maxStringLength)));
|
|
14392
|
+
const processedValues = yield Promise.all(op.values.map((value) => offloadBlobsAndMarkDirty(value, databaseUrl, getCachedAccessToken, maxStringLength)));
|
|
14356
14393
|
return Object.assign(Object.assign({}, op), { values: processedValues });
|
|
14357
14394
|
}
|
|
14358
14395
|
case 'update': {
|
|
14359
|
-
const processedChangeSpecs = yield Promise.all(op.changeSpecs.map(spec => offloadBlobsAndMarkDirty(spec, databaseUrl, getCachedAccessToken, maxStringLength)));
|
|
14396
|
+
const processedChangeSpecs = yield Promise.all(op.changeSpecs.map((spec) => offloadBlobsAndMarkDirty(spec, databaseUrl, getCachedAccessToken, maxStringLength)));
|
|
14360
14397
|
return Object.assign(Object.assign({}, op), { changeSpecs: processedChangeSpecs });
|
|
14361
14398
|
}
|
|
14362
14399
|
case 'modify': {
|
|
@@ -14389,9 +14426,9 @@
|
|
|
14389
14426
|
switch (op.type) {
|
|
14390
14427
|
case 'insert':
|
|
14391
14428
|
case 'upsert':
|
|
14392
|
-
return op.values.some(value => hasLargeBlobs(value, maxStringLength));
|
|
14429
|
+
return op.values.some((value) => hasLargeBlobs(value, maxStringLength));
|
|
14393
14430
|
case 'update':
|
|
14394
|
-
return op.changeSpecs.some(spec => hasLargeBlobs(spec, maxStringLength));
|
|
14431
|
+
return op.changeSpecs.some((spec) => hasLargeBlobs(spec, maxStringLength));
|
|
14395
14432
|
case 'modify':
|
|
14396
14433
|
return hasLargeBlobs(op.changeSpec, maxStringLength);
|
|
14397
14434
|
default:
|
|
@@ -14403,7 +14440,9 @@
|
|
|
14403
14440
|
return false;
|
|
14404
14441
|
}
|
|
14405
14442
|
// Check long strings
|
|
14406
|
-
if (typeof obj === 'string' &&
|
|
14443
|
+
if (typeof obj === 'string' &&
|
|
14444
|
+
obj.length > maxStringLength &&
|
|
14445
|
+
maxStringLength !== Infinity) {
|
|
14407
14446
|
return true;
|
|
14408
14447
|
}
|
|
14409
14448
|
if (shouldOffloadBlob(obj)) {
|
|
@@ -14418,13 +14457,13 @@
|
|
|
14418
14457
|
}
|
|
14419
14458
|
visited.add(obj);
|
|
14420
14459
|
if (Array.isArray(obj)) {
|
|
14421
|
-
return obj.some(item => hasLargeBlobs(item, maxStringLength, visited));
|
|
14460
|
+
return obj.some((item) => hasLargeBlobs(item, maxStringLength, visited));
|
|
14422
14461
|
}
|
|
14423
14462
|
// Traverse plain objects (POJO-like) - use duck typing since IndexedDB
|
|
14424
14463
|
// may return objects where constructor !== Object
|
|
14425
14464
|
const proto = Object.getPrototypeOf(obj);
|
|
14426
14465
|
if (proto === Object.prototype || proto === null) {
|
|
14427
|
-
return Object.values(obj).some(value => hasLargeBlobs(value, maxStringLength, visited));
|
|
14466
|
+
return Object.values(obj).some((value) => hasLargeBlobs(value, maxStringLength, visited));
|
|
14428
14467
|
}
|
|
14429
14468
|
return false;
|
|
14430
14469
|
}
|
|
@@ -14478,7 +14517,7 @@
|
|
|
14478
14517
|
yield db.table(yTable).add({
|
|
14479
14518
|
i: DEXIE_CLOUD_SYNCER_ID,
|
|
14480
14519
|
unsentFrom,
|
|
14481
|
-
receivedUntil
|
|
14520
|
+
receivedUntil,
|
|
14482
14521
|
});
|
|
14483
14522
|
}
|
|
14484
14523
|
else {
|
|
@@ -14618,19 +14657,30 @@
|
|
|
14618
14657
|
return Promise.resolve(cached.accessToken);
|
|
14619
14658
|
}
|
|
14620
14659
|
const currentUser = db.cloud.currentUser.value;
|
|
14621
|
-
if (currentUser &&
|
|
14660
|
+
if (currentUser &&
|
|
14661
|
+
currentUser.accessToken &&
|
|
14662
|
+
((_b = (_a = currentUser.accessTokenExpiration) === null || _a === void 0 ? void 0 : _a.getTime()) !== null && _b !== void 0 ? _b : Infinity) >
|
|
14663
|
+
Date.now() + 5 * MINUTES) {
|
|
14622
14664
|
wm$3.set(db, {
|
|
14623
14665
|
accessToken: currentUser.accessToken,
|
|
14624
|
-
expiration: (_d = (_c = currentUser.accessTokenExpiration) === null || _c === void 0 ? void 0 : _c.getTime()) !== null && _d !== void 0 ? _d : Infinity
|
|
14666
|
+
expiration: (_d = (_c = currentUser.accessTokenExpiration) === null || _c === void 0 ? void 0 : _c.getTime()) !== null && _d !== void 0 ? _d : Infinity,
|
|
14625
14667
|
});
|
|
14626
14668
|
return Promise.resolve(currentUser.accessToken);
|
|
14627
14669
|
}
|
|
14628
|
-
|
|
14670
|
+
// If the current user is not logged in (no isLoggedIn flag), there's no
|
|
14671
|
+
// token to load from the database — skip the Dexie.ignoreTransaction() call.
|
|
14672
|
+
// This avoids a crash in service worker context where Dexie's Promise zone
|
|
14673
|
+
// (PSD.transless.env) may be undefined when called from within an active
|
|
14674
|
+
// rw transaction (e.g. during applyServerChanges).
|
|
14675
|
+
if (!(currentUser === null || currentUser === void 0 ? void 0 : currentUser.isLoggedIn)) {
|
|
14676
|
+
return Promise.resolve(null);
|
|
14677
|
+
}
|
|
14678
|
+
return Dexie.ignoreTransaction(() => loadAccessToken(db).then((user) => {
|
|
14629
14679
|
var _a, _b;
|
|
14630
14680
|
if (user === null || user === void 0 ? void 0 : user.accessToken) {
|
|
14631
14681
|
wm$3.set(db, {
|
|
14632
14682
|
accessToken: user.accessToken,
|
|
14633
|
-
expiration: (_b = (_a = user.accessTokenExpiration) === null || _a === void 0 ? void 0 : _a.getTime()) !== null && _b !== void 0 ? _b : Infinity
|
|
14683
|
+
expiration: (_b = (_a = user.accessTokenExpiration) === null || _a === void 0 ? void 0 : _a.getTime()) !== null && _b !== void 0 ? _b : Infinity,
|
|
14634
14684
|
});
|
|
14635
14685
|
}
|
|
14636
14686
|
return (user === null || user === void 0 ? void 0 : user.accessToken) || null;
|
|
@@ -14641,7 +14691,8 @@
|
|
|
14641
14691
|
function sync(db, options, schema, syncOptions) {
|
|
14642
14692
|
return _sync(db, options, schema, syncOptions)
|
|
14643
14693
|
.then((result) => {
|
|
14644
|
-
if (!(syncOptions === null || syncOptions === void 0 ? void 0 : syncOptions.justCheckIfNeeded)) {
|
|
14694
|
+
if (!(syncOptions === null || syncOptions === void 0 ? void 0 : syncOptions.justCheckIfNeeded)) {
|
|
14695
|
+
// && syncOptions?.purpose !== 'push') {
|
|
14645
14696
|
db.syncStateChangedEvent.next({
|
|
14646
14697
|
phase: 'in-sync',
|
|
14647
14698
|
});
|
|
@@ -14728,7 +14779,7 @@
|
|
|
14728
14779
|
const syncState = yield db.getPersistedSyncState();
|
|
14729
14780
|
let baseRevs = yield db.$baseRevs.toArray();
|
|
14730
14781
|
// Resolve #2168
|
|
14731
|
-
baseRevs = baseRevs.filter(br => tablesToSync.some(tbl => tbl.name === br.tableName));
|
|
14782
|
+
baseRevs = baseRevs.filter((br) => tablesToSync.some((tbl) => tbl.name === br.tableName));
|
|
14732
14783
|
let clientChanges = yield listClientChanges(mutationTables, db);
|
|
14733
14784
|
const yResults = yield listYClientMessagesAndStateVector(db, tablesToSync);
|
|
14734
14785
|
throwIfCancelled(cancelToken);
|
|
@@ -14744,7 +14795,7 @@
|
|
|
14744
14795
|
}
|
|
14745
14796
|
return [clientChanges, syncState, baseRevs, yResults];
|
|
14746
14797
|
}));
|
|
14747
|
-
const pushSyncIsNeeded = clientChangeSet.some((set) => set.muts.some((mut) => mut.keys.length > 0)) || yMessages.some(m => m.type === 'u-c');
|
|
14798
|
+
const pushSyncIsNeeded = clientChangeSet.some((set) => set.muts.some((mut) => mut.keys.length > 0)) || yMessages.some((m) => m.type === 'u-c');
|
|
14748
14799
|
if (justCheckIfNeeded) {
|
|
14749
14800
|
console.debug('Sync is needed:', pushSyncIsNeeded);
|
|
14750
14801
|
return pushSyncIsNeeded;
|
|
@@ -14888,7 +14939,7 @@
|
|
|
14888
14939
|
db.$syncState.put(newSyncState, 'syncState');
|
|
14889
14940
|
return {
|
|
14890
14941
|
done: addedClientChanges.length === 0,
|
|
14891
|
-
newSyncState
|
|
14942
|
+
newSyncState,
|
|
14892
14943
|
};
|
|
14893
14944
|
}));
|
|
14894
14945
|
if (!done) {
|
|
@@ -14896,7 +14947,7 @@
|
|
|
14896
14947
|
yield checkSyncRateLimitDelay(db);
|
|
14897
14948
|
return yield _sync(db, options, schema, { isInitialSync, cancelToken });
|
|
14898
14949
|
}
|
|
14899
|
-
const usingYProps = Object.values(schema).some(tbl => { var _a; return (_a = tbl.yProps) === null || _a === void 0 ? void 0 : _a.length; });
|
|
14950
|
+
const usingYProps = Object.values(schema).some((tbl) => { var _a; return (_a = tbl.yProps) === null || _a === void 0 ? void 0 : _a.length; });
|
|
14900
14951
|
const serverSupportsYprops = !!res.yMessages;
|
|
14901
14952
|
if (usingYProps && serverSupportsYprops) {
|
|
14902
14953
|
try {
|
|
@@ -15203,11 +15254,14 @@
|
|
|
15203
15254
|
download(blobRef, dbUrl) {
|
|
15204
15255
|
let promise = this.inFlight.get(blobRef.ref);
|
|
15205
15256
|
if (!promise) {
|
|
15206
|
-
promise = loadCachedAccessToken(this.db)
|
|
15207
|
-
|
|
15208
|
-
|
|
15257
|
+
promise = loadCachedAccessToken(this.db)
|
|
15258
|
+
.then((accessToken) => {
|
|
15259
|
+
// accessToken may be null for anonymous/unauthenticated users.
|
|
15260
|
+
// Public realm blobs (rlm-public) are accessible without auth.
|
|
15261
|
+
// downloadBlob will omit the Authorization header when token is null.
|
|
15209
15262
|
return downloadBlob(blobRef, dbUrl, accessToken);
|
|
15210
|
-
})
|
|
15263
|
+
})
|
|
15264
|
+
.finally(() => this.inFlight.delete(blobRef.ref));
|
|
15211
15265
|
// When the promise settles (either fulfilled or rejected), remove it from the in-flight map
|
|
15212
15266
|
this.inFlight.set(blobRef.ref, promise);
|
|
15213
15267
|
}
|
|
@@ -15217,19 +15271,22 @@
|
|
|
15217
15271
|
/**
|
|
15218
15272
|
* Download blob data from server via proxy endpoint.
|
|
15219
15273
|
* Uses auth header for authentication (same as sync).
|
|
15274
|
+
* When accessToken is null, the request is made without Authorization header —
|
|
15275
|
+
* this allows downloading blobs from public realms (rlm-public) for
|
|
15276
|
+
* unauthenticated users.
|
|
15220
15277
|
*
|
|
15221
15278
|
* @param blobRef - The BlobRef to download
|
|
15222
15279
|
* @param dbUrl - Base URL for the database (e.g., 'https://mydb.dexie.cloud')
|
|
15223
|
-
* @param accessToken - Access token for authentication
|
|
15280
|
+
* @param accessToken - Access token for authentication, or null for anonymous access
|
|
15224
15281
|
*/
|
|
15225
15282
|
function downloadBlob(blobRef, dbUrl, accessToken) {
|
|
15226
15283
|
return __awaiter(this, void 0, void 0, function* () {
|
|
15227
15284
|
const downloadUrl = `${dbUrl}/blob/${blobRef.ref}`;
|
|
15228
|
-
const
|
|
15229
|
-
|
|
15230
|
-
|
|
15231
|
-
|
|
15232
|
-
});
|
|
15285
|
+
const headers = {};
|
|
15286
|
+
if (accessToken) {
|
|
15287
|
+
headers['Authorization'] = `Bearer ${accessToken}`;
|
|
15288
|
+
}
|
|
15289
|
+
const response = yield fetch(downloadUrl, { headers });
|
|
15233
15290
|
if (!response.ok) {
|
|
15234
15291
|
throw new Error(`Failed to download blob ${blobRef.ref}: ${response.status} ${response.statusText}`);
|
|
15235
15292
|
}
|
|
@@ -15320,7 +15377,9 @@
|
|
|
15320
15377
|
return db.$syncState.get('schema').then((schema) => {
|
|
15321
15378
|
if (schema) {
|
|
15322
15379
|
for (const table of db.tables) {
|
|
15323
|
-
if (table.schema.primKey &&
|
|
15380
|
+
if (table.schema.primKey &&
|
|
15381
|
+
table.schema.primKey.keyPath &&
|
|
15382
|
+
schema[table.name]) {
|
|
15324
15383
|
schema[table.name].primaryKey = nameFromKeyPath(table.schema.primKey.keyPath);
|
|
15325
15384
|
}
|
|
15326
15385
|
}
|
|
@@ -15348,9 +15407,11 @@
|
|
|
15348
15407
|
return db;
|
|
15349
15408
|
}
|
|
15350
15409
|
function nameFromKeyPath(keyPath) {
|
|
15351
|
-
return typeof keyPath === 'string'
|
|
15352
|
-
keyPath
|
|
15353
|
-
|
|
15410
|
+
return typeof keyPath === 'string'
|
|
15411
|
+
? keyPath
|
|
15412
|
+
: keyPath
|
|
15413
|
+
? '[' + [].join.call(keyPath, '+') + ']'
|
|
15414
|
+
: '';
|
|
15354
15415
|
}
|
|
15355
15416
|
|
|
15356
15417
|
/**
|
|
@@ -15408,7 +15469,7 @@
|
|
|
15408
15469
|
isDownloading: isDownloading && stats.blobsRemaining > 0,
|
|
15409
15470
|
blobsRemaining: stats.blobsRemaining,
|
|
15410
15471
|
bytesRemaining: stats.bytesRemaining,
|
|
15411
|
-
})), operators.share({ resetOnRefCountZero: () => rxjs.timer(2000) }) // Keep alive for 2s after last unsubscription to avoid rapid re-subscriptions during UI updates
|
|
15472
|
+
})), operators.share({ resetOnRefCountZero: () => rxjs.timer(2000) }) // Keep alive for 2s after last unsubscription to avoid rapid re-subscriptions during UI updates
|
|
15412
15473
|
);
|
|
15413
15474
|
}
|
|
15414
15475
|
/**
|
|
@@ -15492,13 +15553,13 @@
|
|
|
15492
15553
|
}
|
|
15493
15554
|
setDownloadingState(downloading$, true);
|
|
15494
15555
|
try {
|
|
15495
|
-
debugLog(`Eager download: Found ${syncedTables.length} syncable tables: ${syncedTables.map(t => t.name).join(', ')}`);
|
|
15556
|
+
debugLog(`Eager download: Found ${syncedTables.length} syncable tables: ${syncedTables.map((t) => t.name).join(', ')}`);
|
|
15496
15557
|
for (const table of syncedTables) {
|
|
15497
15558
|
if (signal === null || signal === void 0 ? void 0 : signal.aborted)
|
|
15498
15559
|
;
|
|
15499
15560
|
try {
|
|
15500
15561
|
// Check if table has _hasBlobRefs index
|
|
15501
|
-
const hasIndex = table.schema.indexes.some(idx => idx.name === '_hasBlobRefs');
|
|
15562
|
+
const hasIndex = table.schema.indexes.some((idx) => idx.name === '_hasBlobRefs');
|
|
15502
15563
|
if (!hasIndex)
|
|
15503
15564
|
continue;
|
|
15504
15565
|
// Query objects with _hasBlobRefs marker
|
|
@@ -15514,7 +15575,7 @@
|
|
|
15514
15575
|
const MAX_CONCURRENT = 6;
|
|
15515
15576
|
const primaryKey = table.schema.primKey;
|
|
15516
15577
|
// Filter to actionable objects first
|
|
15517
|
-
const pending = unresolvedObjects.filter(obj => {
|
|
15578
|
+
const pending = unresolvedObjects.filter((obj) => {
|
|
15518
15579
|
if (!hasUnresolvedBlobRefs(obj))
|
|
15519
15580
|
return false;
|
|
15520
15581
|
const key = primaryKey.keyPath
|
|
@@ -15577,20 +15638,20 @@
|
|
|
15577
15638
|
}
|
|
15578
15639
|
static load(db, userId) {
|
|
15579
15640
|
return db
|
|
15580
|
-
.table(
|
|
15641
|
+
.table('$logins')
|
|
15581
15642
|
.get(userId)
|
|
15582
15643
|
.then((userLogin) => new AuthPersistedContext(db, userLogin || {
|
|
15583
15644
|
userId,
|
|
15584
15645
|
claims: {
|
|
15585
|
-
sub: userId
|
|
15646
|
+
sub: userId,
|
|
15586
15647
|
},
|
|
15587
|
-
lastLogin: new Date(0)
|
|
15648
|
+
lastLogin: new Date(0),
|
|
15588
15649
|
}));
|
|
15589
15650
|
}
|
|
15590
15651
|
save() {
|
|
15591
15652
|
return __awaiter(this, void 0, void 0, function* () {
|
|
15592
15653
|
const db = wm$1.get(this);
|
|
15593
|
-
db.table(
|
|
15654
|
+
db.table('$logins').put(this);
|
|
15594
15655
|
});
|
|
15595
15656
|
}
|
|
15596
15657
|
}
|
|
@@ -15685,7 +15746,7 @@
|
|
|
15685
15746
|
*/
|
|
15686
15747
|
function exchangeOAuthCode(options) {
|
|
15687
15748
|
return __awaiter(this, void 0, void 0, function* () {
|
|
15688
|
-
const { databaseUrl, code, publicKey, scopes = ['ACCESS_DB'], intent } = options;
|
|
15749
|
+
const { databaseUrl, code, publicKey, scopes = ['ACCESS_DB'], intent, } = options;
|
|
15689
15750
|
const tokenRequest = Object.assign({ grant_type: 'authorization_code', code, public_key: publicKey, scopes }, (intent !== undefined ? { intent } : {}));
|
|
15690
15751
|
try {
|
|
15691
15752
|
const res = yield fetch(`${databaseUrl}/token`, {
|
|
@@ -15743,7 +15804,8 @@
|
|
|
15743
15804
|
return response;
|
|
15744
15805
|
}
|
|
15745
15806
|
catch (error) {
|
|
15746
|
-
if (error instanceof OAuthError ||
|
|
15807
|
+
if (error instanceof OAuthError ||
|
|
15808
|
+
error instanceof TokenErrorResponseError) {
|
|
15747
15809
|
throw error;
|
|
15748
15810
|
}
|
|
15749
15811
|
if (error instanceof TypeError) {
|
|
@@ -15781,7 +15843,7 @@
|
|
|
15781
15843
|
try {
|
|
15782
15844
|
const res = yield fetch(`${databaseUrl}/auth-providers`, {
|
|
15783
15845
|
method: 'GET',
|
|
15784
|
-
headers: {
|
|
15846
|
+
headers: { Accept: 'application/json' },
|
|
15785
15847
|
mode: 'cors',
|
|
15786
15848
|
});
|
|
15787
15849
|
if (res.status === 404) {
|
|
@@ -16111,7 +16173,7 @@
|
|
|
16111
16173
|
* @param args
|
|
16112
16174
|
*/
|
|
16113
16175
|
function prodLog(level, ...args) {
|
|
16114
|
-
globalThis[
|
|
16176
|
+
globalThis['con' + 'sole'][level](...args);
|
|
16115
16177
|
}
|
|
16116
16178
|
|
|
16117
16179
|
/** This function changes or sets the current user as requested.
|
|
@@ -16241,7 +16303,7 @@
|
|
|
16241
16303
|
const DISABLE_SERVICEWORKER_STRATEGY = (isSafari && safariVersion <= 605) || // Disable for Safari for now.
|
|
16242
16304
|
isFirefox; // Disable for Firefox for now. Seems to have a bug in reading CryptoKeys from IDB from service workers
|
|
16243
16305
|
|
|
16244
|
-
const IS_SERVICE_WORKER = typeof self !==
|
|
16306
|
+
const IS_SERVICE_WORKER = typeof self !== 'undefined' && 'clients' in self && !self.document;
|
|
16245
16307
|
|
|
16246
16308
|
function throwVersionIncrementNeeded() {
|
|
16247
16309
|
throw new Dexie.SchemaError(`Version increment needed to allow dexie-cloud change tracking`);
|
|
@@ -16487,7 +16549,7 @@
|
|
|
16487
16549
|
// We must also degrade from consistent modify operations for the
|
|
16488
16550
|
// same reason - object might be there on server. Must but put up instead.
|
|
16489
16551
|
// FUTURE: This clumpsy behavior of private IDs could be refined later.
|
|
16490
|
-
// Suggestion is to in future, treat private IDs as we treat all objects
|
|
16552
|
+
// Suggestion is to in future, treat private IDs as we treat all objects
|
|
16491
16553
|
// and sync operations normally. Only that deletions should become soft deletes
|
|
16492
16554
|
// for them - so that server knows when a private ID has been deleted on server
|
|
16493
16555
|
// not accept insert/upserts on them.
|
|
@@ -16510,19 +16572,20 @@
|
|
|
16510
16572
|
}
|
|
16511
16573
|
|
|
16512
16574
|
function allSettled(possiblePromises) {
|
|
16513
|
-
return new Promise(resolve => {
|
|
16575
|
+
return new Promise((resolve) => {
|
|
16514
16576
|
if (possiblePromises.length === 0)
|
|
16515
16577
|
resolve([]);
|
|
16516
16578
|
let remaining = possiblePromises.length;
|
|
16517
16579
|
const results = new Array(remaining);
|
|
16518
|
-
possiblePromises.forEach((p, i) => Promise.resolve(p)
|
|
16580
|
+
possiblePromises.forEach((p, i) => Promise.resolve(p)
|
|
16581
|
+
.then((value) => (results[i] = { status: 'fulfilled', value }), (reason) => (results[i] = { status: 'rejected', reason }))
|
|
16519
16582
|
.then(() => --remaining || resolve(results)));
|
|
16520
16583
|
});
|
|
16521
16584
|
}
|
|
16522
16585
|
|
|
16523
16586
|
let counter$1 = 0;
|
|
16524
16587
|
function guardedTable(table) {
|
|
16525
|
-
const prop =
|
|
16588
|
+
const prop = '$lock' + ++counter$1;
|
|
16526
16589
|
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) });
|
|
16527
16590
|
}
|
|
16528
16591
|
function readLock(fn, prop) {
|
|
@@ -16531,7 +16594,9 @@
|
|
|
16531
16594
|
const numWriters = writers.length;
|
|
16532
16595
|
const promise = (numWriters > 0
|
|
16533
16596
|
? writers[numWriters - 1].then(() => fn(req), () => fn(req))
|
|
16534
|
-
: fn(req)).finally(() => {
|
|
16597
|
+
: fn(req)).finally(() => {
|
|
16598
|
+
readers.splice(readers.indexOf(promise));
|
|
16599
|
+
});
|
|
16535
16600
|
readers.push(promise);
|
|
16536
16601
|
return promise;
|
|
16537
16602
|
};
|
|
@@ -16543,7 +16608,9 @@
|
|
|
16543
16608
|
? writers[writers.length - 1].then(() => fn(req), () => fn(req))
|
|
16544
16609
|
: readers.length > 0
|
|
16545
16610
|
? allSettled(readers).then(() => fn(req))
|
|
16546
|
-
: fn(req)).finally(() => {
|
|
16611
|
+
: fn(req)).finally(() => {
|
|
16612
|
+
writers.shift();
|
|
16613
|
+
});
|
|
16547
16614
|
writers.push(promise);
|
|
16548
16615
|
return promise;
|
|
16549
16616
|
};
|
|
@@ -16821,16 +16888,17 @@
|
|
|
16821
16888
|
userId,
|
|
16822
16889
|
values,
|
|
16823
16890
|
}
|
|
16824
|
-
: upsert && updates
|
|
16825
|
-
|
|
16826
|
-
|
|
16827
|
-
|
|
16828
|
-
|
|
16829
|
-
|
|
16830
|
-
|
|
16831
|
-
|
|
16832
|
-
|
|
16833
|
-
|
|
16891
|
+
: upsert && updates
|
|
16892
|
+
? {
|
|
16893
|
+
type: 'upsert',
|
|
16894
|
+
ts,
|
|
16895
|
+
opNo,
|
|
16896
|
+
keys,
|
|
16897
|
+
values,
|
|
16898
|
+
changeSpecs: updates.changeSpecs.filter((_, idx) => !failures[idx]),
|
|
16899
|
+
txid,
|
|
16900
|
+
userId,
|
|
16901
|
+
}
|
|
16834
16902
|
: criteria && changeSpec
|
|
16835
16903
|
? {
|
|
16836
16904
|
// Common changeSpec for all keys
|
|
@@ -16943,7 +17011,8 @@
|
|
|
16943
17011
|
return;
|
|
16944
17012
|
}
|
|
16945
17013
|
// Atomic update of just the blob property
|
|
16946
|
-
this.db
|
|
17014
|
+
this.db
|
|
17015
|
+
.transaction('rw', item.tableName, (tx) => {
|
|
16947
17016
|
const trans = tx.idbtrans;
|
|
16948
17017
|
trans.disableChangeTracking = true; // Don't regard this as a change for sync purposes
|
|
16949
17018
|
trans.disableAccessControl = true; // Bypass any access control checks since this is an internal operation
|
|
@@ -16952,7 +17021,7 @@
|
|
|
16952
17021
|
for (const blob of item.resolvedBlobs) {
|
|
16953
17022
|
updateSpec[blob.keyPath] = blob.data;
|
|
16954
17023
|
}
|
|
16955
|
-
tx.table(item.tableName).update(item.primaryKey, obj => {
|
|
17024
|
+
tx.table(item.tableName).update(item.primaryKey, (obj) => {
|
|
16956
17025
|
// Check that object still has the same unresolved blob refs before applying update (i.e. it hasn't been modified since we read it)
|
|
16957
17026
|
for (const blob of item.resolvedBlobs) {
|
|
16958
17027
|
// 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.
|
|
@@ -16973,9 +17042,11 @@
|
|
|
16973
17042
|
}
|
|
16974
17043
|
delete obj._hasBlobRefs; // Clear the _hasBlobRefs marker if all refs was resolved.
|
|
16975
17044
|
});
|
|
16976
|
-
})
|
|
17045
|
+
})
|
|
17046
|
+
.catch((error) => {
|
|
16977
17047
|
console.error(`Error saving resolved blobs on ${item.tableName}:${item.primaryKey}:`, error);
|
|
16978
|
-
})
|
|
17048
|
+
})
|
|
17049
|
+
.finally(() => {
|
|
16979
17050
|
// Process next item in the queue
|
|
16980
17051
|
return this.processQueue();
|
|
16981
17052
|
});
|
|
@@ -17026,7 +17097,7 @@
|
|
|
17026
17097
|
if ((_a = req.trans) === null || _a === void 0 ? void 0 : _a.disableBlobResolve) {
|
|
17027
17098
|
return downlevelTable.get(req);
|
|
17028
17099
|
}
|
|
17029
|
-
return downlevelTable.get(req).then(result => {
|
|
17100
|
+
return downlevelTable.get(req).then((result) => {
|
|
17030
17101
|
if (result && hasUnresolvedBlobRefs(result)) {
|
|
17031
17102
|
return resolveAndSave(downlevelTable, req.trans, req.key, result, blobSavingQueue, db);
|
|
17032
17103
|
}
|
|
@@ -17038,9 +17109,9 @@
|
|
|
17038
17109
|
if ((_a = req.trans) === null || _a === void 0 ? void 0 : _a.disableBlobResolve) {
|
|
17039
17110
|
return downlevelTable.getMany(req);
|
|
17040
17111
|
}
|
|
17041
|
-
return downlevelTable.getMany(req).then(results => {
|
|
17112
|
+
return downlevelTable.getMany(req).then((results) => {
|
|
17042
17113
|
// Check if any results need resolution
|
|
17043
|
-
const needsResolution = results.some(r => r && hasUnresolvedBlobRefs(r));
|
|
17114
|
+
const needsResolution = results.some((r) => r && hasUnresolvedBlobRefs(r));
|
|
17044
17115
|
if (!needsResolution)
|
|
17045
17116
|
return results;
|
|
17046
17117
|
return Dexie.Promise.all(results.map((result, index) => {
|
|
@@ -17056,19 +17127,19 @@
|
|
|
17056
17127
|
if ((_a = req.trans) === null || _a === void 0 ? void 0 : _a.disableBlobResolve) {
|
|
17057
17128
|
return downlevelTable.query(req);
|
|
17058
17129
|
}
|
|
17059
|
-
return downlevelTable.query(req).then(result => {
|
|
17130
|
+
return downlevelTable.query(req).then((result) => {
|
|
17060
17131
|
if (!result.result || !Array.isArray(result.result))
|
|
17061
17132
|
return result;
|
|
17062
17133
|
// Check if any results need resolution
|
|
17063
|
-
const needsResolution = result.result.some(r => r && hasUnresolvedBlobRefs(r));
|
|
17134
|
+
const needsResolution = result.result.some((r) => r && hasUnresolvedBlobRefs(r));
|
|
17064
17135
|
if (!needsResolution)
|
|
17065
17136
|
return result;
|
|
17066
|
-
return Dexie.Promise.all(result.result.map(item => {
|
|
17137
|
+
return Dexie.Promise.all(result.result.map((item) => {
|
|
17067
17138
|
if (item && hasUnresolvedBlobRefs(item)) {
|
|
17068
17139
|
return resolveAndSave(downlevelTable, req.trans, undefined, item, blobSavingQueue, db);
|
|
17069
17140
|
}
|
|
17070
17141
|
return item;
|
|
17071
|
-
})).then(resolved => (Object.assign(Object.assign({}, result), { result: resolved })));
|
|
17142
|
+
})).then((resolved) => (Object.assign(Object.assign({}, result), { result: resolved })));
|
|
17072
17143
|
});
|
|
17073
17144
|
},
|
|
17074
17145
|
openCursor(req) {
|
|
@@ -17076,7 +17147,7 @@
|
|
|
17076
17147
|
if ((_a = req.trans) === null || _a === void 0 ? void 0 : _a.disableBlobResolve) {
|
|
17077
17148
|
return downlevelTable.openCursor(req);
|
|
17078
17149
|
}
|
|
17079
|
-
return downlevelTable.openCursor(req).then(cursor => {
|
|
17150
|
+
return downlevelTable.openCursor(req).then((cursor) => {
|
|
17080
17151
|
if (!cursor)
|
|
17081
17152
|
return cursor; // No results, so no resolution needed
|
|
17082
17153
|
if (!req.values)
|
|
@@ -17106,7 +17177,7 @@
|
|
|
17106
17177
|
value: {
|
|
17107
17178
|
value: cursor.value,
|
|
17108
17179
|
enumerable: true,
|
|
17109
|
-
writable: true
|
|
17180
|
+
writable: true,
|
|
17110
17181
|
},
|
|
17111
17182
|
start: {
|
|
17112
17183
|
value(onNext) {
|
|
@@ -17118,17 +17189,17 @@
|
|
|
17118
17189
|
onNext();
|
|
17119
17190
|
return;
|
|
17120
17191
|
}
|
|
17121
|
-
resolveAndSave(table, cursor.trans, cursor.primaryKey, rawValue, blobSavingQueue, db, true).then(resolved => {
|
|
17192
|
+
resolveAndSave(table, cursor.trans, cursor.primaryKey, rawValue, blobSavingQueue, db, true).then((resolved) => {
|
|
17122
17193
|
wrappedCursor.value = resolved;
|
|
17123
17194
|
onNext();
|
|
17124
|
-
}, err => {
|
|
17195
|
+
}, (err) => {
|
|
17125
17196
|
console.error('Failed to resolve BlobRefs for cursor value:', err);
|
|
17126
17197
|
wrappedCursor.value = rawValue;
|
|
17127
17198
|
onNext();
|
|
17128
17199
|
});
|
|
17129
17200
|
});
|
|
17130
|
-
}
|
|
17131
|
-
}
|
|
17201
|
+
},
|
|
17202
|
+
},
|
|
17132
17203
|
});
|
|
17133
17204
|
return wrappedCursor;
|
|
17134
17205
|
}
|
|
@@ -17173,12 +17244,15 @@
|
|
|
17173
17244
|
const resolvePromise = needsWaitFor
|
|
17174
17245
|
? Dexie.waitFor(resolutionPromise)
|
|
17175
17246
|
: Dexie.Promise.resolve(resolutionPromise);
|
|
17176
|
-
return resolvePromise
|
|
17247
|
+
return resolvePromise
|
|
17248
|
+
.then((resolved) => {
|
|
17177
17249
|
// Get primary key from the object
|
|
17178
17250
|
const primaryKey = table.schema.primaryKey;
|
|
17179
|
-
const key = pKey !== undefined
|
|
17180
|
-
?
|
|
17181
|
-
:
|
|
17251
|
+
const key = pKey !== undefined
|
|
17252
|
+
? pKey
|
|
17253
|
+
: primaryKey.keyPath
|
|
17254
|
+
? Dexie.getByKeyPath(obj, primaryKey.keyPath)
|
|
17255
|
+
: undefined;
|
|
17182
17256
|
if (key !== undefined) {
|
|
17183
17257
|
// Queue each resolved blob individually for atomic update
|
|
17184
17258
|
// This uses setTimeout(fn, 0) to completely isolate from
|
|
@@ -17189,13 +17263,16 @@
|
|
|
17189
17263
|
else {
|
|
17190
17264
|
// For rw transactions, we can save directly without queueing
|
|
17191
17265
|
// since we're still in the same transaction context
|
|
17192
|
-
table
|
|
17266
|
+
table
|
|
17267
|
+
.mutate({ type: 'put', keys: [key], values: [resolved], trans })
|
|
17268
|
+
.catch((err) => {
|
|
17193
17269
|
console.error(`Failed to save resolved blob on ${table.name}:${key}:`, err);
|
|
17194
17270
|
});
|
|
17195
17271
|
}
|
|
17196
17272
|
}
|
|
17197
17273
|
return resolved;
|
|
17198
|
-
})
|
|
17274
|
+
})
|
|
17275
|
+
.catch((err) => {
|
|
17199
17276
|
console.error(`[dexie-cloud:blobResolve] Failed to resolve BlobRefs on ${table.name}:`, err);
|
|
17200
17277
|
return obj; // Return original object on error - never block the read pipeline
|
|
17201
17278
|
});
|
|
@@ -17224,9 +17301,13 @@
|
|
|
17224
17301
|
return; // Continue
|
|
17225
17302
|
}
|
|
17226
17303
|
// They have declared this table. Merge indexes in case they didn't declare all indexes we need.
|
|
17227
|
-
const requestedIndexes = schemaSrc
|
|
17228
|
-
|
|
17229
|
-
|
|
17304
|
+
const requestedIndexes = schemaSrc
|
|
17305
|
+
.split(',')
|
|
17306
|
+
.map((spec) => spec.trim());
|
|
17307
|
+
const builtInIndexes = DEXIE_CLOUD_SCHEMA[tableName]
|
|
17308
|
+
.split(',')
|
|
17309
|
+
.map((spec) => spec.trim());
|
|
17310
|
+
const requestedIndexSet = new Set(requestedIndexes.map((index) => index.replace(/([&*]|\+\+)/g, '')));
|
|
17230
17311
|
// Verify that primary key is unchanged
|
|
17231
17312
|
if (requestedIndexes[0] !== builtInIndexes[0]) {
|
|
17232
17313
|
// Primary key must match exactly
|
|
@@ -17235,7 +17316,7 @@
|
|
|
17235
17316
|
// Merge indexes
|
|
17236
17317
|
for (let i = 1; i < builtInIndexes.length; ++i) {
|
|
17237
17318
|
const builtInIndex = builtInIndexes[i];
|
|
17238
|
-
if (!requestedIndexSet.has(builtInIndex.replace(/([&*]|\+\+)/g,
|
|
17319
|
+
if (!requestedIndexSet.has(builtInIndex.replace(/([&*]|\+\+)/g, ''))) {
|
|
17239
17320
|
// Add built-in index if not already requested
|
|
17240
17321
|
storesClone[tableName] += `,${builtInIndex}`;
|
|
17241
17322
|
}
|
|
@@ -17244,7 +17325,7 @@
|
|
|
17244
17325
|
// Populate dexie.cloud.schema
|
|
17245
17326
|
const cloudSchema = dexie.cloud.schema || (dexie.cloud.schema = {});
|
|
17246
17327
|
const allPrefixes = new Set();
|
|
17247
|
-
Object.keys(storesClone).forEach(tableName => {
|
|
17328
|
+
Object.keys(storesClone).forEach((tableName) => {
|
|
17248
17329
|
var _a;
|
|
17249
17330
|
const schemaSrc = (_a = storesClone[tableName]) === null || _a === void 0 ? void 0 : _a.trim();
|
|
17250
17331
|
const cloudTableSchema = cloudSchema[tableName] || (cloudSchema[tableName] = {});
|
|
@@ -17373,7 +17454,7 @@
|
|
|
17373
17454
|
class TokenExpiredError extends Error {
|
|
17374
17455
|
constructor() {
|
|
17375
17456
|
super(...arguments);
|
|
17376
|
-
this.name =
|
|
17457
|
+
this.name = 'TokenExpiredError';
|
|
17377
17458
|
}
|
|
17378
17459
|
}
|
|
17379
17460
|
|
|
@@ -17859,7 +17940,7 @@
|
|
|
17859
17940
|
// Connect the WebSocket to given url:
|
|
17860
17941
|
console.debug('dexie-cloud WebSocket create');
|
|
17861
17942
|
const ws = (this.ws = new WebSocket(`${wsUrl}/changes?${searchParams}`));
|
|
17862
|
-
ws.binaryType =
|
|
17943
|
+
ws.binaryType = 'arraybuffer';
|
|
17863
17944
|
ws.onclose = (event) => {
|
|
17864
17945
|
if (!this.pinger)
|
|
17865
17946
|
return;
|
|
@@ -17898,10 +17979,17 @@
|
|
|
17898
17979
|
getOpenDocSignal(doc).next(); // Make yHandler reopen the document on server.
|
|
17899
17980
|
}
|
|
17900
17981
|
}
|
|
17901
|
-
else if (msg.type === 'u-ack' ||
|
|
17982
|
+
else if (msg.type === 'u-ack' ||
|
|
17983
|
+
msg.type === 'u-reject' ||
|
|
17984
|
+
msg.type === 'u-s' ||
|
|
17985
|
+
msg.type === 'in-sync' ||
|
|
17986
|
+
msg.type === 'outdated-server-rev' ||
|
|
17987
|
+
msg.type === 'y-complete-sync-done') {
|
|
17902
17988
|
applyYServerMessages([msg], this.db).then((_a) => __awaiter(this, [_a], void 0, function* ({ resyncNeeded, yServerRevision, receivedUntils }) {
|
|
17903
17989
|
if (yServerRevision) {
|
|
17904
|
-
yield this.db.$syncState.update('syncState', {
|
|
17990
|
+
yield this.db.$syncState.update('syncState', {
|
|
17991
|
+
yServerRevision: yServerRevision,
|
|
17992
|
+
});
|
|
17905
17993
|
}
|
|
17906
17994
|
if (msg.type === 'u-s' && receivedUntils) {
|
|
17907
17995
|
const utbl = getUpdatesTable(this.db, msg.table, msg.prop);
|
|
@@ -18104,7 +18192,9 @@
|
|
|
18104
18192
|
return __awaiter(this, void 0, void 0, function* () {
|
|
18105
18193
|
var _a;
|
|
18106
18194
|
return ((_a = db.cloud.options) === null || _a === void 0 ? void 0 : _a.databaseUrl) && db.cloud.schema
|
|
18107
|
-
? yield sync(db, db.cloud.options, db.cloud.schema, {
|
|
18195
|
+
? yield sync(db, db.cloud.options, db.cloud.schema, {
|
|
18196
|
+
justCheckIfNeeded: true,
|
|
18197
|
+
})
|
|
18108
18198
|
: false;
|
|
18109
18199
|
});
|
|
18110
18200
|
}
|
|
@@ -18316,243 +18406,243 @@
|
|
|
18316
18406
|
const Styles = {
|
|
18317
18407
|
Alert: {
|
|
18318
18408
|
error: {
|
|
18319
|
-
color:
|
|
18320
|
-
fontWeight:
|
|
18409
|
+
color: 'red',
|
|
18410
|
+
fontWeight: 'bold',
|
|
18321
18411
|
},
|
|
18322
18412
|
warning: {
|
|
18323
|
-
color:
|
|
18324
|
-
fontWeight:
|
|
18413
|
+
color: '#f80',
|
|
18414
|
+
fontWeight: 'bold',
|
|
18325
18415
|
},
|
|
18326
18416
|
info: {
|
|
18327
|
-
color:
|
|
18328
|
-
}
|
|
18417
|
+
color: 'black',
|
|
18418
|
+
},
|
|
18329
18419
|
},
|
|
18330
18420
|
Darken: {
|
|
18331
|
-
position:
|
|
18421
|
+
position: 'fixed',
|
|
18332
18422
|
top: 0,
|
|
18333
18423
|
left: 0,
|
|
18334
18424
|
opacity: 0.5,
|
|
18335
|
-
backgroundColor:
|
|
18336
|
-
width:
|
|
18337
|
-
height:
|
|
18425
|
+
backgroundColor: '#000',
|
|
18426
|
+
width: '100vw',
|
|
18427
|
+
height: '100vh',
|
|
18338
18428
|
zIndex: 150,
|
|
18339
|
-
webkitBackdropFilter:
|
|
18340
|
-
backdropFilter:
|
|
18429
|
+
webkitBackdropFilter: 'blur(2px)',
|
|
18430
|
+
backdropFilter: 'blur(2px)',
|
|
18341
18431
|
},
|
|
18342
18432
|
DialogOuter: {
|
|
18343
|
-
position:
|
|
18433
|
+
position: 'fixed',
|
|
18344
18434
|
top: 0,
|
|
18345
18435
|
left: 0,
|
|
18346
|
-
width:
|
|
18347
|
-
height:
|
|
18436
|
+
width: '100vw',
|
|
18437
|
+
height: '100vh',
|
|
18348
18438
|
zIndex: 150,
|
|
18349
|
-
alignItems:
|
|
18350
|
-
display:
|
|
18351
|
-
justifyContent:
|
|
18352
|
-
padding:
|
|
18353
|
-
boxSizing:
|
|
18439
|
+
alignItems: 'center',
|
|
18440
|
+
display: 'flex',
|
|
18441
|
+
justifyContent: 'center',
|
|
18442
|
+
padding: '16px',
|
|
18443
|
+
boxSizing: 'border-box',
|
|
18354
18444
|
},
|
|
18355
18445
|
DialogInner: {
|
|
18356
|
-
position:
|
|
18357
|
-
color:
|
|
18358
|
-
backgroundColor:
|
|
18359
|
-
padding:
|
|
18360
|
-
marginBottom:
|
|
18361
|
-
maxWidth:
|
|
18362
|
-
width:
|
|
18363
|
-
maxHeight:
|
|
18364
|
-
overflowY:
|
|
18365
|
-
border:
|
|
18366
|
-
borderRadius:
|
|
18367
|
-
boxShadow:
|
|
18368
|
-
fontFamily:
|
|
18369
|
-
boxSizing:
|
|
18446
|
+
position: 'relative',
|
|
18447
|
+
color: '#222',
|
|
18448
|
+
backgroundColor: '#fff',
|
|
18449
|
+
padding: '24px',
|
|
18450
|
+
marginBottom: '2em',
|
|
18451
|
+
maxWidth: '400px',
|
|
18452
|
+
width: '100%',
|
|
18453
|
+
maxHeight: '90%',
|
|
18454
|
+
overflowY: 'auto',
|
|
18455
|
+
border: '3px solid #3d3d5d',
|
|
18456
|
+
borderRadius: '8px',
|
|
18457
|
+
boxShadow: '0 0 80px 10px #666',
|
|
18458
|
+
fontFamily: 'sans-serif',
|
|
18459
|
+
boxSizing: 'border-box',
|
|
18370
18460
|
},
|
|
18371
18461
|
Input: {
|
|
18372
|
-
height:
|
|
18373
|
-
width:
|
|
18374
|
-
maxWidth:
|
|
18375
|
-
borderColor:
|
|
18376
|
-
outline:
|
|
18377
|
-
fontSize:
|
|
18378
|
-
padding:
|
|
18379
|
-
boxSizing:
|
|
18380
|
-
backgroundColor:
|
|
18381
|
-
borderRadius:
|
|
18382
|
-
border:
|
|
18383
|
-
marginTop:
|
|
18384
|
-
fontFamily:
|
|
18462
|
+
height: '35px',
|
|
18463
|
+
width: '100%',
|
|
18464
|
+
maxWidth: '100%',
|
|
18465
|
+
borderColor: '#ccf4',
|
|
18466
|
+
outline: 'none',
|
|
18467
|
+
fontSize: '16px',
|
|
18468
|
+
padding: '8px',
|
|
18469
|
+
boxSizing: 'border-box',
|
|
18470
|
+
backgroundColor: '#f9f9f9',
|
|
18471
|
+
borderRadius: '4px',
|
|
18472
|
+
border: '1px solid #ccc',
|
|
18473
|
+
marginTop: '6px',
|
|
18474
|
+
fontFamily: 'inherit',
|
|
18385
18475
|
},
|
|
18386
18476
|
Button: {
|
|
18387
|
-
padding:
|
|
18388
|
-
margin:
|
|
18389
|
-
border:
|
|
18390
|
-
borderRadius:
|
|
18391
|
-
backgroundColor:
|
|
18392
|
-
cursor:
|
|
18393
|
-
fontSize:
|
|
18394
|
-
fontWeight:
|
|
18395
|
-
color:
|
|
18396
|
-
transition:
|
|
18477
|
+
padding: '10px 20px',
|
|
18478
|
+
margin: '0 4px',
|
|
18479
|
+
border: '1px solid #d1d5db',
|
|
18480
|
+
borderRadius: '6px',
|
|
18481
|
+
backgroundColor: '#ffffff',
|
|
18482
|
+
cursor: 'pointer',
|
|
18483
|
+
fontSize: '14px',
|
|
18484
|
+
fontWeight: '500',
|
|
18485
|
+
color: '#374151',
|
|
18486
|
+
transition: 'all 0.2s ease',
|
|
18397
18487
|
},
|
|
18398
18488
|
PrimaryButton: {
|
|
18399
|
-
padding:
|
|
18400
|
-
margin:
|
|
18401
|
-
border:
|
|
18402
|
-
borderRadius:
|
|
18403
|
-
backgroundColor:
|
|
18404
|
-
color:
|
|
18405
|
-
cursor:
|
|
18406
|
-
fontSize:
|
|
18407
|
-
fontWeight:
|
|
18408
|
-
transition:
|
|
18489
|
+
padding: '10px 20px',
|
|
18490
|
+
margin: '0 4px',
|
|
18491
|
+
border: '1px solid #3b82f6',
|
|
18492
|
+
borderRadius: '6px',
|
|
18493
|
+
backgroundColor: '#3b82f6',
|
|
18494
|
+
color: 'white',
|
|
18495
|
+
cursor: 'pointer',
|
|
18496
|
+
fontSize: '14px',
|
|
18497
|
+
fontWeight: '500',
|
|
18498
|
+
transition: 'all 0.2s ease',
|
|
18409
18499
|
},
|
|
18410
18500
|
ButtonsDiv: {
|
|
18411
|
-
display:
|
|
18412
|
-
justifyContent:
|
|
18413
|
-
gap:
|
|
18414
|
-
marginTop:
|
|
18415
|
-
paddingTop:
|
|
18501
|
+
display: 'flex',
|
|
18502
|
+
justifyContent: 'flex-end',
|
|
18503
|
+
gap: '12px',
|
|
18504
|
+
marginTop: '24px',
|
|
18505
|
+
paddingTop: '20px',
|
|
18416
18506
|
},
|
|
18417
18507
|
Label: {
|
|
18418
|
-
display:
|
|
18419
|
-
marginBottom:
|
|
18420
|
-
fontSize:
|
|
18421
|
-
fontWeight:
|
|
18422
|
-
color:
|
|
18508
|
+
display: 'block',
|
|
18509
|
+
marginBottom: '12px',
|
|
18510
|
+
fontSize: '14px',
|
|
18511
|
+
fontWeight: '500',
|
|
18512
|
+
color: '#333',
|
|
18423
18513
|
},
|
|
18424
18514
|
WindowHeader: {
|
|
18425
|
-
margin:
|
|
18426
|
-
fontSize:
|
|
18427
|
-
fontWeight:
|
|
18428
|
-
color:
|
|
18429
|
-
borderBottom:
|
|
18430
|
-
paddingBottom:
|
|
18515
|
+
margin: '0 0 20px 0',
|
|
18516
|
+
fontSize: '18px',
|
|
18517
|
+
fontWeight: '600',
|
|
18518
|
+
color: '#333',
|
|
18519
|
+
borderBottom: '1px solid #eee',
|
|
18520
|
+
paddingBottom: '10px',
|
|
18431
18521
|
},
|
|
18432
18522
|
// OAuth Provider Button Styles
|
|
18433
18523
|
ProviderButton: {
|
|
18434
|
-
display:
|
|
18435
|
-
alignItems:
|
|
18436
|
-
justifyContent:
|
|
18437
|
-
width:
|
|
18438
|
-
padding:
|
|
18439
|
-
marginBottom:
|
|
18440
|
-
border:
|
|
18441
|
-
borderRadius:
|
|
18442
|
-
backgroundColor:
|
|
18443
|
-
cursor:
|
|
18444
|
-
fontSize:
|
|
18445
|
-
fontWeight:
|
|
18446
|
-
color:
|
|
18447
|
-
transition:
|
|
18448
|
-
gap:
|
|
18524
|
+
display: 'flex',
|
|
18525
|
+
alignItems: 'center',
|
|
18526
|
+
justifyContent: 'center',
|
|
18527
|
+
width: '100%',
|
|
18528
|
+
padding: '12px 16px',
|
|
18529
|
+
marginBottom: '10px',
|
|
18530
|
+
border: '1px solid #d1d5db',
|
|
18531
|
+
borderRadius: '6px',
|
|
18532
|
+
backgroundColor: '#ffffff',
|
|
18533
|
+
cursor: 'pointer',
|
|
18534
|
+
fontSize: '14px',
|
|
18535
|
+
fontWeight: '500',
|
|
18536
|
+
color: '#374151',
|
|
18537
|
+
transition: 'all 0.2s ease',
|
|
18538
|
+
gap: '12px',
|
|
18449
18539
|
},
|
|
18450
18540
|
ProviderButtonIcon: {
|
|
18451
|
-
width:
|
|
18452
|
-
height:
|
|
18541
|
+
width: '20px',
|
|
18542
|
+
height: '20px',
|
|
18453
18543
|
flexShrink: 0,
|
|
18454
|
-
display:
|
|
18455
|
-
alignItems:
|
|
18456
|
-
justifyContent:
|
|
18544
|
+
display: 'flex',
|
|
18545
|
+
alignItems: 'center',
|
|
18546
|
+
justifyContent: 'center',
|
|
18457
18547
|
},
|
|
18458
18548
|
ProviderButtonText: {
|
|
18459
18549
|
flex: 1,
|
|
18460
|
-
textAlign:
|
|
18550
|
+
textAlign: 'left',
|
|
18461
18551
|
},
|
|
18462
18552
|
// Provider-specific colors
|
|
18463
18553
|
ProviderGoogle: {
|
|
18464
|
-
backgroundColor:
|
|
18465
|
-
border:
|
|
18466
|
-
color:
|
|
18554
|
+
backgroundColor: '#ffffff',
|
|
18555
|
+
border: '1px solid #dadce0',
|
|
18556
|
+
color: '#3c4043',
|
|
18467
18557
|
},
|
|
18468
18558
|
ProviderGitHub: {
|
|
18469
|
-
backgroundColor:
|
|
18470
|
-
border:
|
|
18471
|
-
color:
|
|
18559
|
+
backgroundColor: '#ffffff',
|
|
18560
|
+
border: '1px solid #dadce0',
|
|
18561
|
+
color: '#181717',
|
|
18472
18562
|
},
|
|
18473
18563
|
ProviderMicrosoft: {
|
|
18474
|
-
backgroundColor:
|
|
18475
|
-
border:
|
|
18476
|
-
color:
|
|
18564
|
+
backgroundColor: '#ffffff',
|
|
18565
|
+
border: '1px solid #dadce0',
|
|
18566
|
+
color: '#5e5e5e',
|
|
18477
18567
|
},
|
|
18478
18568
|
ProviderApple: {
|
|
18479
|
-
backgroundColor:
|
|
18480
|
-
border:
|
|
18481
|
-
color:
|
|
18569
|
+
backgroundColor: '#000000',
|
|
18570
|
+
border: '1px solid #000000',
|
|
18571
|
+
color: '#ffffff',
|
|
18482
18572
|
},
|
|
18483
18573
|
ProviderCustom: {
|
|
18484
|
-
backgroundColor:
|
|
18485
|
-
border:
|
|
18486
|
-
color:
|
|
18574
|
+
backgroundColor: '#ffffff',
|
|
18575
|
+
border: '1px solid #dadce0',
|
|
18576
|
+
color: '#181717',
|
|
18487
18577
|
},
|
|
18488
18578
|
// Divider styles
|
|
18489
18579
|
Divider: {
|
|
18490
|
-
display:
|
|
18491
|
-
alignItems:
|
|
18492
|
-
margin:
|
|
18493
|
-
color:
|
|
18494
|
-
fontSize:
|
|
18580
|
+
display: 'flex',
|
|
18581
|
+
alignItems: 'center',
|
|
18582
|
+
margin: '20px 0',
|
|
18583
|
+
color: '#6b7280',
|
|
18584
|
+
fontSize: '13px',
|
|
18495
18585
|
},
|
|
18496
18586
|
DividerLine: {
|
|
18497
18587
|
flex: 1,
|
|
18498
|
-
height:
|
|
18499
|
-
backgroundColor:
|
|
18588
|
+
height: '1px',
|
|
18589
|
+
backgroundColor: '#e5e7eb',
|
|
18500
18590
|
},
|
|
18501
18591
|
DividerText: {
|
|
18502
|
-
padding:
|
|
18503
|
-
color:
|
|
18592
|
+
padding: '0 12px',
|
|
18593
|
+
color: '#9ca3af',
|
|
18504
18594
|
},
|
|
18505
18595
|
// OTP Button (Continue with email)
|
|
18506
18596
|
OtpButton: {
|
|
18507
|
-
display:
|
|
18508
|
-
alignItems:
|
|
18509
|
-
justifyContent:
|
|
18510
|
-
width:
|
|
18511
|
-
padding:
|
|
18512
|
-
border:
|
|
18513
|
-
borderRadius:
|
|
18514
|
-
backgroundColor:
|
|
18515
|
-
cursor:
|
|
18516
|
-
fontSize:
|
|
18517
|
-
fontWeight:
|
|
18518
|
-
color:
|
|
18519
|
-
transition:
|
|
18520
|
-
gap:
|
|
18597
|
+
display: 'flex',
|
|
18598
|
+
alignItems: 'center',
|
|
18599
|
+
justifyContent: 'center',
|
|
18600
|
+
width: '100%',
|
|
18601
|
+
padding: '12px 16px',
|
|
18602
|
+
border: '1px solid #d1d5db',
|
|
18603
|
+
borderRadius: '6px',
|
|
18604
|
+
backgroundColor: '#f9fafb',
|
|
18605
|
+
cursor: 'pointer',
|
|
18606
|
+
fontSize: '14px',
|
|
18607
|
+
fontWeight: '500',
|
|
18608
|
+
color: '#374151',
|
|
18609
|
+
transition: 'all 0.2s ease',
|
|
18610
|
+
gap: '12px',
|
|
18521
18611
|
},
|
|
18522
18612
|
// Copy button for alerts with copyText
|
|
18523
18613
|
CopyButton: {
|
|
18524
|
-
display:
|
|
18525
|
-
alignItems:
|
|
18526
|
-
gap:
|
|
18527
|
-
padding:
|
|
18528
|
-
marginTop:
|
|
18529
|
-
border:
|
|
18530
|
-
borderRadius:
|
|
18531
|
-
backgroundColor:
|
|
18532
|
-
cursor:
|
|
18533
|
-
fontSize:
|
|
18534
|
-
fontWeight:
|
|
18535
|
-
color:
|
|
18536
|
-
transition:
|
|
18537
|
-
fontFamily:
|
|
18614
|
+
display: 'inline-flex',
|
|
18615
|
+
alignItems: 'center',
|
|
18616
|
+
gap: '4px',
|
|
18617
|
+
padding: '4px 10px',
|
|
18618
|
+
marginTop: '8px',
|
|
18619
|
+
border: '1px solid #d1d5db',
|
|
18620
|
+
borderRadius: '4px',
|
|
18621
|
+
backgroundColor: '#f9fafb',
|
|
18622
|
+
cursor: 'pointer',
|
|
18623
|
+
fontSize: '12px',
|
|
18624
|
+
fontWeight: '500',
|
|
18625
|
+
color: '#374151',
|
|
18626
|
+
transition: 'all 0.15s ease',
|
|
18627
|
+
fontFamily: 'monospace',
|
|
18538
18628
|
},
|
|
18539
18629
|
CopyButtonCopied: {
|
|
18540
|
-
display:
|
|
18541
|
-
alignItems:
|
|
18542
|
-
gap:
|
|
18543
|
-
padding:
|
|
18544
|
-
marginTop:
|
|
18545
|
-
border:
|
|
18546
|
-
borderRadius:
|
|
18547
|
-
backgroundColor:
|
|
18548
|
-
cursor:
|
|
18549
|
-
fontSize:
|
|
18550
|
-
fontWeight:
|
|
18551
|
-
color:
|
|
18552
|
-
fontFamily:
|
|
18630
|
+
display: 'inline-flex',
|
|
18631
|
+
alignItems: 'center',
|
|
18632
|
+
gap: '4px',
|
|
18633
|
+
padding: '4px 10px',
|
|
18634
|
+
marginTop: '8px',
|
|
18635
|
+
border: '1px solid #22c55e',
|
|
18636
|
+
borderRadius: '4px',
|
|
18637
|
+
backgroundColor: '#f0fdf4',
|
|
18638
|
+
cursor: 'default',
|
|
18639
|
+
fontSize: '12px',
|
|
18640
|
+
fontWeight: '500',
|
|
18641
|
+
color: '#16a34a',
|
|
18642
|
+
fontFamily: 'monospace',
|
|
18553
18643
|
}};
|
|
18554
18644
|
|
|
18555
|
-
function Dialog({ children, className }) {
|
|
18645
|
+
function Dialog({ children, className, }) {
|
|
18556
18646
|
return (_$1("div", { className: `dexie-dialog ${className || ''}` },
|
|
18557
18647
|
_$1("div", { style: Styles.Darken }),
|
|
18558
18648
|
_$1("div", { style: Styles.DialogOuter },
|
|
@@ -18576,7 +18666,7 @@
|
|
|
18576
18666
|
* @returns A final message where parameters have been replaced with values.
|
|
18577
18667
|
*/
|
|
18578
18668
|
function resolveText({ message, messageCode, messageParams }) {
|
|
18579
|
-
return message.replace(/\{\w+\}/
|
|
18669
|
+
return message.replace(/\{\w+\}/gi, (n) => messageParams[n.substring(1, n.length - 1)]);
|
|
18580
18670
|
}
|
|
18581
18671
|
|
|
18582
18672
|
/** Get style based on styleHint (for provider branding, etc.) */
|
|
@@ -18663,13 +18753,13 @@
|
|
|
18663
18753
|
alerts.map((alert, idx) => (_$1("div", { key: idx },
|
|
18664
18754
|
_$1("p", { style: Styles.Alert[alert.type] }, resolveText(alert)),
|
|
18665
18755
|
alert.copyText && _$1(CopyButton, { text: alert.copyText })))),
|
|
18666
|
-
hasOptions && (_$1("div", { class: "dxc-options" }, hasMultipleGroups
|
|
18667
|
-
|
|
18668
|
-
|
|
18669
|
-
|
|
18670
|
-
|
|
18671
|
-
|
|
18672
|
-
|
|
18756
|
+
hasOptions && (_$1("div", { class: "dxc-options" }, hasMultipleGroups
|
|
18757
|
+
? // Render with dividers between groups
|
|
18758
|
+
Array.from(optionGroups.entries()).map(([groupName, groupOptions], groupIdx) => (_$1(k$1, { key: groupName },
|
|
18759
|
+
groupIdx > 0 && _$1(Divider, null),
|
|
18760
|
+
groupOptions.map((option) => (_$1(OptionButton, { key: `${option.name}-${option.value}`, option: option, onClick: () => handleOptionClick(option) }))))))
|
|
18761
|
+
: // Simple case: all options in one group
|
|
18762
|
+
options.map((option) => (_$1(OptionButton, { key: `${option.name}-${option.value}`, option: option, onClick: () => handleOptionClick(option) }))))),
|
|
18673
18763
|
hasOptions && hasFields && _$1(Divider, null),
|
|
18674
18764
|
hasFields && (_$1("form", { onSubmit: (ev) => {
|
|
18675
18765
|
ev.preventDefault();
|
|
@@ -18681,7 +18771,8 @@
|
|
|
18681
18771
|
const value = valueTransformer(type, (_a = ev.target) === null || _a === void 0 ? void 0 : _a['value']);
|
|
18682
18772
|
let updatedParams = Object.assign(Object.assign({}, params), { [fieldName]: value });
|
|
18683
18773
|
setParams(updatedParams);
|
|
18684
|
-
if (type === 'otp' &&
|
|
18774
|
+
if (type === 'otp' &&
|
|
18775
|
+
(value === null || value === void 0 ? void 0 : value.trim().length) === OTP_LENGTH) {
|
|
18685
18776
|
// Auto-submit when OTP is filled in.
|
|
18686
18777
|
onSubmit(updatedParams);
|
|
18687
18778
|
}
|
|
@@ -18723,7 +18814,10 @@
|
|
|
18723
18814
|
const handleClick = () => {
|
|
18724
18815
|
var _a;
|
|
18725
18816
|
if (typeof navigator !== 'undefined' && ((_a = navigator.clipboard) === null || _a === void 0 ? void 0 : _a.writeText)) {
|
|
18726
|
-
navigator.clipboard
|
|
18817
|
+
navigator.clipboard
|
|
18818
|
+
.writeText(text)
|
|
18819
|
+
.then(scheduleCopiedReset)
|
|
18820
|
+
.catch(() => {
|
|
18727
18821
|
fallbackCopy(text, scheduleCopiedReset);
|
|
18728
18822
|
});
|
|
18729
18823
|
}
|
|
@@ -18794,7 +18888,7 @@
|
|
|
18794
18888
|
},
|
|
18795
18889
|
get closed() {
|
|
18796
18890
|
return closed;
|
|
18797
|
-
}
|
|
18891
|
+
},
|
|
18798
18892
|
};
|
|
18799
18893
|
}
|
|
18800
18894
|
|
|
@@ -18839,14 +18933,14 @@
|
|
|
18839
18933
|
lazyWebSocketStatus,
|
|
18840
18934
|
db.syncStateChangedEvent.pipe(operators.startWith({ phase: 'initial' })),
|
|
18841
18935
|
getCurrentUserEmitter(db.dx._novip),
|
|
18842
|
-
userIsReallyActive
|
|
18936
|
+
userIsReallyActive,
|
|
18843
18937
|
]).pipe(operators.map(([status, syncState, user, userIsActive]) => {
|
|
18844
18938
|
var _a;
|
|
18845
18939
|
if (((_a = user.license) === null || _a === void 0 ? void 0 : _a.status) && user.license.status !== 'ok') {
|
|
18846
18940
|
return {
|
|
18847
18941
|
phase: 'offline',
|
|
18848
18942
|
status: 'offline',
|
|
18849
|
-
license: user.license.status
|
|
18943
|
+
license: user.license.status,
|
|
18850
18944
|
};
|
|
18851
18945
|
}
|
|
18852
18946
|
let { phase, error, progress } = syncState;
|
|
@@ -18866,7 +18960,8 @@
|
|
|
18866
18960
|
}
|
|
18867
18961
|
const previousPhase = db.cloud.syncState.value.phase;
|
|
18868
18962
|
//const previousStatus = db.cloud.syncState.value.status;
|
|
18869
|
-
if (previousPhase === 'error' &&
|
|
18963
|
+
if (previousPhase === 'error' &&
|
|
18964
|
+
(syncState.phase === 'pushing' || syncState.phase === 'pulling')) {
|
|
18870
18965
|
// We were in an errored state but is now doing sync. Show "connecting" icon.
|
|
18871
18966
|
adjustedStatus = 'connecting';
|
|
18872
18967
|
}
|
|
@@ -18881,7 +18976,7 @@
|
|
|
18881
18976
|
error,
|
|
18882
18977
|
progress,
|
|
18883
18978
|
status: isOnline ? adjustedStatus : 'offline',
|
|
18884
|
-
license: 'ok'
|
|
18979
|
+
license: 'ok',
|
|
18885
18980
|
};
|
|
18886
18981
|
return retState;
|
|
18887
18982
|
}));
|
|
@@ -18902,7 +18997,7 @@
|
|
|
18902
18997
|
},
|
|
18903
18998
|
complete() {
|
|
18904
18999
|
observer.complete();
|
|
18905
|
-
}
|
|
19000
|
+
},
|
|
18906
19001
|
});
|
|
18907
19002
|
if (!didEmit && !subscription.closed) {
|
|
18908
19003
|
observer.next(currentValue);
|
|
@@ -19143,7 +19238,9 @@
|
|
|
19143
19238
|
const realm = permissionsLookup[realmId || dexie.cloud.currentUserId];
|
|
19144
19239
|
if (!realm)
|
|
19145
19240
|
return new PermissionChecker({}, tableName, !owner || owner === dexie.cloud.currentUserId);
|
|
19146
|
-
return new PermissionChecker(realm.permissions, tableName, realmId === undefined ||
|
|
19241
|
+
return new PermissionChecker(realm.permissions, tableName, realmId === undefined ||
|
|
19242
|
+
realmId === dexie.cloud.currentUserId ||
|
|
19243
|
+
owner === dexie.cloud.currentUserId);
|
|
19147
19244
|
};
|
|
19148
19245
|
const o = source.pipe(operators.map(mapper));
|
|
19149
19246
|
o.getValue = () => mapper(source.getValue());
|
|
@@ -19185,7 +19282,19 @@
|
|
|
19185
19282
|
return; // The table that holds the doc is not marked for sync - leave it to dexie. No syncing, no awareness.
|
|
19186
19283
|
}
|
|
19187
19284
|
let awareness;
|
|
19285
|
+
const existingDescriptor = Object.getOwnPropertyDescriptor(provider, 'awareness');
|
|
19286
|
+
if (existingDescriptor) {
|
|
19287
|
+
// Provider already initialized — likely a leaked handler from a previous db instance
|
|
19288
|
+
// (e.g. HMR where db.close() didn't fire). Destroy the stale awareness so the new
|
|
19289
|
+
// handler can take over cleanly.
|
|
19290
|
+
const staleAwareness = provider.awareness;
|
|
19291
|
+
if (staleAwareness) {
|
|
19292
|
+
staleAwareness.destroy();
|
|
19293
|
+
awarenessWeakMap.delete(doc);
|
|
19294
|
+
}
|
|
19295
|
+
}
|
|
19188
19296
|
Object.defineProperty(provider, 'awareness', {
|
|
19297
|
+
configurable: true,
|
|
19189
19298
|
get() {
|
|
19190
19299
|
if (awareness)
|
|
19191
19300
|
return awareness;
|
|
@@ -19368,10 +19477,12 @@
|
|
|
19368
19477
|
const { code, provider, state, error } = payload;
|
|
19369
19478
|
// Check for error first
|
|
19370
19479
|
if (error) {
|
|
19371
|
-
if (error.toLowerCase().includes('access_denied') ||
|
|
19480
|
+
if (error.toLowerCase().includes('access_denied') ||
|
|
19481
|
+
error.toLowerCase().includes('access denied')) {
|
|
19372
19482
|
throw new OAuthError('access_denied', provider, error);
|
|
19373
19483
|
}
|
|
19374
|
-
if (error.toLowerCase().includes('email') &&
|
|
19484
|
+
if (error.toLowerCase().includes('email') &&
|
|
19485
|
+
error.toLowerCase().includes('verif')) {
|
|
19375
19486
|
throw new OAuthError('email_not_verified', provider, error);
|
|
19376
19487
|
}
|
|
19377
19488
|
throw new OAuthError('provider_error', provider, error);
|
|
@@ -19397,7 +19508,9 @@
|
|
|
19397
19508
|
return;
|
|
19398
19509
|
}
|
|
19399
19510
|
url.searchParams.delete('dxc-auth');
|
|
19400
|
-
const cleanUrl = url.pathname +
|
|
19511
|
+
const cleanUrl = url.pathname +
|
|
19512
|
+
(url.searchParams.toString() ? `?${url.searchParams.toString()}` : '') +
|
|
19513
|
+
url.hash;
|
|
19401
19514
|
window.history.replaceState(null, '', cleanUrl);
|
|
19402
19515
|
}
|
|
19403
19516
|
|
|
@@ -19446,7 +19559,7 @@
|
|
|
19446
19559
|
const downloading$ = createDownloadingState();
|
|
19447
19560
|
dexie.cloud = {
|
|
19448
19561
|
// @ts-ignore
|
|
19449
|
-
version: "4.4.
|
|
19562
|
+
version: "4.4.8",
|
|
19450
19563
|
options: Object.assign({}, DEFAULT_OPTIONS),
|
|
19451
19564
|
schema: null,
|
|
19452
19565
|
get currentUserId() {
|
|
@@ -19502,7 +19615,10 @@
|
|
|
19502
19615
|
const callback = parseOAuthCallback();
|
|
19503
19616
|
if (callback) {
|
|
19504
19617
|
// Store the pending auth code for processing when db is ready
|
|
19505
|
-
pendingOAuthCode = {
|
|
19618
|
+
pendingOAuthCode = {
|
|
19619
|
+
code: callback.code,
|
|
19620
|
+
provider: callback.provider,
|
|
19621
|
+
};
|
|
19506
19622
|
console.debug('[dexie-cloud] OAuth callback detected, auth code stored for processing');
|
|
19507
19623
|
}
|
|
19508
19624
|
}
|
|
@@ -19619,7 +19735,7 @@
|
|
|
19619
19735
|
if (eagerBlobDownloadInFlight)
|
|
19620
19736
|
return;
|
|
19621
19737
|
eagerBlobDownloadInFlight = Dexie.ignoreTransaction(() => downloadUnresolvedBlobs(db, downloading$))
|
|
19622
|
-
.catch(err => {
|
|
19738
|
+
.catch((err) => {
|
|
19623
19739
|
console.error('[dexie-cloud] Eager blob download failed:', err);
|
|
19624
19740
|
})
|
|
19625
19741
|
.finally(() => {
|
|
@@ -19712,7 +19828,10 @@
|
|
|
19712
19828
|
// Let's assign all props as the newPersistedSchems should be what we should be working with.
|
|
19713
19829
|
Object.assign(schema, newPersistedSchema);
|
|
19714
19830
|
}
|
|
19715
|
-
return [
|
|
19831
|
+
return [
|
|
19832
|
+
persistedSyncState === null || persistedSyncState === void 0 ? void 0 : persistedSyncState.initiallySynced,
|
|
19833
|
+
persistedSyncState === null || persistedSyncState === void 0 ? void 0 : persistedSyncState.realms,
|
|
19834
|
+
];
|
|
19716
19835
|
}));
|
|
19717
19836
|
if (initiallySynced) {
|
|
19718
19837
|
db.setInitiallySynced(true);
|
|
@@ -19721,8 +19840,10 @@
|
|
|
19721
19840
|
// Manage CurrentUser observable:
|
|
19722
19841
|
throwIfClosed();
|
|
19723
19842
|
if (!db.cloud.isServiceWorkerDB) {
|
|
19724
|
-
subscriptions.push(Dexie.liveQuery(() => db.getCurrentUser().then(user => {
|
|
19725
|
-
if (!user.isLoggedIn &&
|
|
19843
|
+
subscriptions.push(Dexie.liveQuery(() => db.getCurrentUser().then((user) => {
|
|
19844
|
+
if (!user.isLoggedIn &&
|
|
19845
|
+
typeof location !== 'undefined' &&
|
|
19846
|
+
/dxc-auth\=/.test(location.search)) {
|
|
19726
19847
|
// Still loading user because OAuth redirect just happened.
|
|
19727
19848
|
// Keep isLoading true.
|
|
19728
19849
|
return Object.assign(Object.assign({}, user), { isLoading: true });
|
|
@@ -19760,7 +19881,7 @@
|
|
|
19760
19881
|
type: 'error',
|
|
19761
19882
|
messageCode: 'GENERIC_ERROR',
|
|
19762
19883
|
message: error.message,
|
|
19763
|
-
messageParams: { provider: error.provider || 'unknown' }
|
|
19884
|
+
messageParams: { provider: error.provider || 'unknown' },
|
|
19764
19885
|
});
|
|
19765
19886
|
// Clean up URL (remove dxc-auth param)
|
|
19766
19887
|
cleanupOAuthUrl();
|
|
@@ -19810,7 +19931,8 @@
|
|
|
19810
19931
|
}
|
|
19811
19932
|
}
|
|
19812
19933
|
}
|
|
19813
|
-
if (user.isLoggedIn &&
|
|
19934
|
+
if (user.isLoggedIn &&
|
|
19935
|
+
(!lastSyncedRealms || !lastSyncedRealms.includes(user.userId))) {
|
|
19814
19936
|
// User has been logged in but this is not reflected in the sync state.
|
|
19815
19937
|
// This can happen if page is reloaded after login but before the sync call following
|
|
19816
19938
|
// the login was complete.
|
|
@@ -19873,7 +19995,7 @@
|
|
|
19873
19995
|
}
|
|
19874
19996
|
}
|
|
19875
19997
|
// @ts-ignore
|
|
19876
|
-
dexieCloud.version = "4.4.
|
|
19998
|
+
dexieCloud.version = "4.4.8";
|
|
19877
19999
|
Dexie.Cloud = dexieCloud;
|
|
19878
20000
|
|
|
19879
20001
|
// In case the SW lives for a while, let it reuse already opened connections:
|
|
@@ -19965,14 +20087,14 @@
|
|
|
19965
20087
|
console.debug('SW "sync" Event', event.tag);
|
|
19966
20088
|
const dbName = getDbNameFromTag(event.tag);
|
|
19967
20089
|
if (dbName) {
|
|
19968
|
-
event.waitUntil(syncDB(dbName,
|
|
20090
|
+
event.waitUntil(syncDB(dbName, 'push')); // The purpose of sync events are "push"
|
|
19969
20091
|
}
|
|
19970
20092
|
});
|
|
19971
20093
|
self.addEventListener('periodicsync', (event) => {
|
|
19972
20094
|
console.debug('SW "periodicsync" Event', event.tag);
|
|
19973
20095
|
const dbName = getDbNameFromTag(event.tag);
|
|
19974
20096
|
if (dbName) {
|
|
19975
|
-
event.waitUntil(syncDB(dbName,
|
|
20097
|
+
event.waitUntil(syncDB(dbName, 'pull')); // The purpose of periodic sync events are "pull"
|
|
19976
20098
|
}
|
|
19977
20099
|
});
|
|
19978
20100
|
self.addEventListener('message', (event) => {
|
|
@@ -19982,7 +20104,7 @@
|
|
|
19982
20104
|
// Mimic background sync behavior - retry in X minutes on failure.
|
|
19983
20105
|
// But lesser timeout and more number of times.
|
|
19984
20106
|
const syncAndRetry = (num = 1) => {
|
|
19985
|
-
return syncDB(dbName, event.data.purpose ||
|
|
20107
|
+
return syncDB(dbName, event.data.purpose || 'pull').catch((e) => __awaiter(void 0, void 0, void 0, function* () {
|
|
19986
20108
|
if (num === 3)
|
|
19987
20109
|
throw e;
|
|
19988
20110
|
yield sleep(60000); // 1 minute
|
|
@@ -19990,10 +20112,10 @@
|
|
|
19990
20112
|
}));
|
|
19991
20113
|
};
|
|
19992
20114
|
if ('waitUntil' in event) {
|
|
19993
|
-
event.waitUntil(syncAndRetry().catch(error => console.error(error)));
|
|
20115
|
+
event.waitUntil(syncAndRetry().catch((error) => console.error(error)));
|
|
19994
20116
|
}
|
|
19995
20117
|
else {
|
|
19996
|
-
syncAndRetry().catch(error => console.error(error));
|
|
20118
|
+
syncAndRetry().catch((error) => console.error(error));
|
|
19997
20119
|
}
|
|
19998
20120
|
}
|
|
19999
20121
|
});
|