dexie-cloud-addon 4.1.0-alpha.2 → 4.1.0-alpha.21
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/DexieCloudOptions.d.ts +3 -0
- package/dist/modern/TSON.d.ts +1 -1
- package/dist/modern/WSObservable.d.ts +4 -4
- package/dist/modern/define-ydoc-trigger.d.ts +2 -0
- package/dist/modern/dexie-cloud-addon.d.ts +1 -0
- package/dist/modern/dexie-cloud-addon.js +584 -237
- 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/getInvitesObservable.d.ts +11 -11
- package/dist/modern/service-worker.js +426 -235
- 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/yjs/applyYMessages.d.ts +4 -1
- package/dist/modern/yjs/listYClientMessagesAndStateVector.d.ts +3 -1
- package/dist/umd/DexieCloudOptions.d.ts +3 -0
- package/dist/umd/TSON.d.ts +1 -1
- package/dist/umd/WSObservable.d.ts +4 -4
- package/dist/umd/define-ydoc-trigger.d.ts +2 -0
- package/dist/umd/dexie-cloud-addon.d.ts +1 -0
- package/dist/umd/dexie-cloud-addon.js +582 -234
- 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/getInvitesObservable.d.ts +11 -11
- package/dist/umd/service-worker.js +424 -233
- 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/dist/umd/yjs/applyYMessages.d.ts +4 -1
- package/dist/umd/yjs/listYClientMessagesAndStateVector.d.ts +3 -1
- package/package.json +4 -4
- package/dist/modern/yjs/listYClientMessages.d.ts +0 -3
- package/dist/umd/yjs/listYClientMessages.d.ts +0 -3
- /package/dist/modern/yjs/{y.d.ts → Y.d.ts} +0 -0
- /package/dist/umd/yjs/{y.d.ts → Y.d.ts} +0 -0
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*
|
|
9
9
|
* ==========================================================================
|
|
10
10
|
*
|
|
11
|
-
* Version 4.1.0-alpha.
|
|
11
|
+
* Version 4.1.0-alpha.21, Mon Nov 18 2024
|
|
12
12
|
*
|
|
13
13
|
* https://dexie.org
|
|
14
14
|
*
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
*
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
import Dexie, { PropModification, cmp, DexieYProvider, liveQuery } from 'dexie';
|
|
20
|
-
import { Observable as Observable$1, BehaviorSubject, firstValueFrom, Subject, from as from$1, filter as filter$1, fromEvent, of, merge, mergeMap as mergeMap$1, Subscription as Subscription$1, throwError, combineLatest, map as map$1, share, timer as timer$1 } from 'rxjs';
|
|
19
|
+
import Dexie, { PropModification, cmp, DexieYProvider, RangeSet, liveQuery } from 'dexie';
|
|
20
|
+
import { Observable as Observable$1, BehaviorSubject, firstValueFrom, Subject, from as from$1, filter as filter$1, fromEvent, of, merge, switchMap as switchMap$1, tap as tap$1, mergeMap as mergeMap$1, Subscription as Subscription$1, throwError, combineLatest, map as map$1, share, timer as timer$1 } from 'rxjs';
|
|
21
21
|
|
|
22
22
|
/******************************************************************************
|
|
23
23
|
Copyright (c) Microsoft Corporation.
|
|
@@ -1765,8 +1765,8 @@ function registerSyncEvent(db, purpose) {
|
|
|
1765
1765
|
});
|
|
1766
1766
|
}
|
|
1767
1767
|
function registerPeriodicSyncEvent(db) {
|
|
1768
|
-
var _a;
|
|
1769
1768
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1769
|
+
var _a;
|
|
1770
1770
|
try {
|
|
1771
1771
|
// Register periodicSync event to SW:
|
|
1772
1772
|
// @ts-ignore
|
|
@@ -1831,8 +1831,8 @@ const b64encode = typeof Buffer !== "undefined"
|
|
|
1831
1831
|
return btoa(strs.join(""));
|
|
1832
1832
|
};
|
|
1833
1833
|
|
|
1834
|
-
function computeRealmSetHash(
|
|
1835
|
-
return __awaiter(this,
|
|
1834
|
+
function computeRealmSetHash(_a) {
|
|
1835
|
+
return __awaiter(this, arguments, void 0, function* ({ realms, inviteRealms, }) {
|
|
1836
1836
|
const data = JSON.stringify([
|
|
1837
1837
|
...realms.map((realmId) => ({ realmId, accepted: true })),
|
|
1838
1838
|
...inviteRealms.map((realmId) => ({ realmId, accepted: false })),
|
|
@@ -1868,8 +1868,8 @@ function flatten(a) {
|
|
|
1868
1868
|
return concat.apply([], a);
|
|
1869
1869
|
}
|
|
1870
1870
|
|
|
1871
|
-
function listClientChanges(
|
|
1872
|
-
return __awaiter(this,
|
|
1871
|
+
function listClientChanges(mutationTables_1, db_1) {
|
|
1872
|
+
return __awaiter(this, arguments, void 0, function* (mutationTables, db, { since = {}, limit = Infinity } = {}) {
|
|
1873
1873
|
const allMutsOnTables = yield Promise.all(mutationTables.map((mutationTable) => __awaiter(this, void 0, void 0, function* () {
|
|
1874
1874
|
const tableName = getTableFromMutationTable(mutationTable.name);
|
|
1875
1875
|
const lastRevision = since[tableName];
|
|
@@ -2754,13 +2754,17 @@ const writeAny = (encoder, data) => {
|
|
|
2754
2754
|
function encodeYMessage(msg) {
|
|
2755
2755
|
const encoder = new Encoder();
|
|
2756
2756
|
writeVarString(encoder, msg.type);
|
|
2757
|
-
|
|
2758
|
-
|
|
2757
|
+
if ('table' in msg)
|
|
2758
|
+
writeVarString(encoder, msg.table);
|
|
2759
|
+
if ('prop' in msg)
|
|
2760
|
+
writeVarString(encoder, msg.prop);
|
|
2759
2761
|
switch (msg.type) {
|
|
2760
2762
|
case 'u-ack':
|
|
2761
2763
|
case 'u-reject':
|
|
2762
2764
|
writeBigUint64(encoder, BigInt(msg.i));
|
|
2763
2765
|
break;
|
|
2766
|
+
case 'outdated-server-rev':
|
|
2767
|
+
break;
|
|
2764
2768
|
default:
|
|
2765
2769
|
writeAny(encoder, msg.k);
|
|
2766
2770
|
switch (msg.type) {
|
|
@@ -3104,6 +3108,9 @@ const readAny = decoder => readAnyLookupTable[127 - readUint8(decoder)](decoder)
|
|
|
3104
3108
|
function decodeYMessage(a) {
|
|
3105
3109
|
const decoder = new Decoder(a);
|
|
3106
3110
|
const type = readVarString(decoder);
|
|
3111
|
+
if (type === 'outdated-server-rev') {
|
|
3112
|
+
return { type };
|
|
3113
|
+
}
|
|
3107
3114
|
const table = readVarString(decoder);
|
|
3108
3115
|
const prop = readVarString(decoder);
|
|
3109
3116
|
switch (type) {
|
|
@@ -3516,8 +3523,8 @@ function confirmLogout(userInteraction, currentUserId, numUnsyncedChanges) {
|
|
|
3516
3523
|
}
|
|
3517
3524
|
|
|
3518
3525
|
function loadAccessToken(db) {
|
|
3519
|
-
var _a, _b, _c;
|
|
3520
3526
|
return __awaiter(this, void 0, void 0, function* () {
|
|
3527
|
+
var _a, _b, _c;
|
|
3521
3528
|
const currentUser = yield db.getCurrentUser();
|
|
3522
3529
|
const { accessToken, accessTokenExpiration, refreshToken, refreshTokenExpiration, claims, } = currentUser;
|
|
3523
3530
|
if (!accessToken)
|
|
@@ -4347,8 +4354,8 @@ function cloneChange(change, rewriteValues) {
|
|
|
4347
4354
|
// seconds (given that there is a Ratelimit-Reset header).
|
|
4348
4355
|
let syncRatelimitDelays = new WeakMap();
|
|
4349
4356
|
function checkSyncRateLimitDelay(db) {
|
|
4350
|
-
var _a, _b;
|
|
4351
4357
|
return __awaiter(this, void 0, void 0, function* () {
|
|
4358
|
+
var _a, _b;
|
|
4352
4359
|
const delatMilliseconds = ((_b = (_a = syncRatelimitDelays.get(db)) === null || _a === void 0 ? void 0 : _a.getTime()) !== null && _b !== void 0 ? _b : 0) - Date.now();
|
|
4353
4360
|
if (delatMilliseconds > 0) {
|
|
4354
4361
|
console.debug(`Stalling sync request ${delatMilliseconds} ms to spare ratelimits`);
|
|
@@ -4661,13 +4668,12 @@ function $Y(db) {
|
|
|
4661
4668
|
* @param db
|
|
4662
4669
|
* @returns
|
|
4663
4670
|
*/
|
|
4664
|
-
function listYClientMessagesAndStateVector(db) {
|
|
4665
|
-
var _a;
|
|
4671
|
+
function listYClientMessagesAndStateVector(db, tablesToSync) {
|
|
4666
4672
|
return __awaiter(this, void 0, void 0, function* () {
|
|
4667
4673
|
const result = [];
|
|
4668
4674
|
const lastUpdateIds = {};
|
|
4669
|
-
for (const table of
|
|
4670
|
-
if (table.schema.yProps
|
|
4675
|
+
for (const table of tablesToSync) {
|
|
4676
|
+
if (table.schema.yProps) {
|
|
4671
4677
|
for (const yProp of table.schema.yProps) {
|
|
4672
4678
|
const Y = $Y(db); // This is how we retrieve the user-provided Y library
|
|
4673
4679
|
const yTable = db.table(yProp.updatesTable); // the updates-table for this combo of table+propName
|
|
@@ -4754,12 +4760,14 @@ function getUpdatesTable(db, table, ydocProp) {
|
|
|
4754
4760
|
|
|
4755
4761
|
function applyYServerMessages(yMessages, db) {
|
|
4756
4762
|
return __awaiter(this, void 0, void 0, function* () {
|
|
4757
|
-
|
|
4763
|
+
var _a;
|
|
4764
|
+
const receivedUntils = {};
|
|
4765
|
+
let resyncNeeded = false;
|
|
4758
4766
|
for (const m of yMessages) {
|
|
4759
4767
|
switch (m.type) {
|
|
4760
4768
|
case 'u-s': {
|
|
4761
4769
|
const utbl = getUpdatesTable(db, m.table, m.prop);
|
|
4762
|
-
|
|
4770
|
+
receivedUntils[utbl.name] = yield utbl.add({
|
|
4763
4771
|
k: m.k,
|
|
4764
4772
|
u: m.u,
|
|
4765
4773
|
});
|
|
@@ -4784,7 +4792,24 @@ function applyYServerMessages(yMessages, db) {
|
|
|
4784
4792
|
// See my question in https://discuss.yjs.dev/t/generate-an-inverse-update/2765
|
|
4785
4793
|
console.debug(`Y update rejected. Deleting it.`);
|
|
4786
4794
|
const utbl = getUpdatesTable(db, m.table, m.prop);
|
|
4787
|
-
|
|
4795
|
+
// Delete the rejected update and all local updates since (avoid holes in the CRDT)
|
|
4796
|
+
// and destroy it's open document if there is one.
|
|
4797
|
+
const primaryKey = (_a = (yield utbl.get(m.i))) === null || _a === void 0 ? void 0 : _a.k;
|
|
4798
|
+
if (primaryKey != null) {
|
|
4799
|
+
yield db.transaction('rw', utbl, (tx) => {
|
|
4800
|
+
// @ts-ignore
|
|
4801
|
+
tx.idbtrans._rejecting_y_ypdate = true; // Inform ydoc triggers that we delete because of a rejection and not GC
|
|
4802
|
+
return utbl
|
|
4803
|
+
.where('i')
|
|
4804
|
+
.aboveOrEqual(m.i)
|
|
4805
|
+
.filter((u) => cmp(u.k, primaryKey) === 0 && ((u.f || 0) & 1) === 1)
|
|
4806
|
+
.delete();
|
|
4807
|
+
});
|
|
4808
|
+
// Destroy active doc
|
|
4809
|
+
const activeDoc = DexieYProvider.getDocCache(db.dx).find(m.table, primaryKey, m.prop);
|
|
4810
|
+
if (activeDoc)
|
|
4811
|
+
activeDoc.destroy(); // Destroy the document so that editors don't continue to work on it
|
|
4812
|
+
}
|
|
4788
4813
|
break;
|
|
4789
4814
|
}
|
|
4790
4815
|
case 'in-sync': {
|
|
@@ -4794,22 +4819,28 @@ function applyYServerMessages(yMessages, db) {
|
|
|
4794
4819
|
}
|
|
4795
4820
|
break;
|
|
4796
4821
|
}
|
|
4822
|
+
case 'outdated-server-rev':
|
|
4823
|
+
resyncNeeded = true;
|
|
4824
|
+
break;
|
|
4797
4825
|
}
|
|
4798
4826
|
}
|
|
4799
|
-
return
|
|
4827
|
+
return {
|
|
4828
|
+
receivedUntils,
|
|
4829
|
+
resyncNeeded,
|
|
4830
|
+
};
|
|
4800
4831
|
});
|
|
4801
4832
|
}
|
|
4802
4833
|
|
|
4803
4834
|
function updateYSyncStates(lastUpdateIdsBeforeSync, receivedUntilsAfterSync, db, serverRevision) {
|
|
4804
|
-
var _a, _b;
|
|
4805
4835
|
return __awaiter(this, void 0, void 0, function* () {
|
|
4836
|
+
var _a, _b, _c, _d, _e;
|
|
4806
4837
|
// We want to update unsentFrom for each yTable to the value specified in first argument
|
|
4807
4838
|
// because we got those values before we synced with server and here we are back from server
|
|
4808
4839
|
// that has successfully received all those messages - no matter if the last update was a client or server update,
|
|
4809
4840
|
// we can safely store unsentFrom to a value of the last update + 1 here.
|
|
4810
4841
|
// We also want to update receivedUntil for each yTable to the value specified in the second argument,
|
|
4811
4842
|
// because that contains the highest resulted id of each update from server after storing it.
|
|
4812
|
-
// We could do these two tasks separately, but that would require two update calls on the same YSyncState, so
|
|
4843
|
+
// We could do these two tasks separately, but that would require two update calls on the same YSyncState, so
|
|
4813
4844
|
// to optimize the dexie calls, we merge these two maps into a single one so we can do a single update request
|
|
4814
4845
|
// per yTable.
|
|
4815
4846
|
const mergedSpec = {};
|
|
@@ -4821,28 +4852,42 @@ function updateYSyncStates(lastUpdateIdsBeforeSync, receivedUntilsAfterSync, db,
|
|
|
4821
4852
|
(_b = mergedSpec[yTable]) !== null && _b !== void 0 ? _b : (mergedSpec[yTable] = {});
|
|
4822
4853
|
mergedSpec[yTable].receivedUntil = lastUpdateId;
|
|
4823
4854
|
}
|
|
4824
|
-
// Now go through
|
|
4825
|
-
|
|
4855
|
+
// Now go through all yTables and update their YSyncStates:
|
|
4856
|
+
const allYTables = Object.values(db.dx._dbSchema)
|
|
4857
|
+
.filter((tblSchema) => tblSchema.yProps)
|
|
4858
|
+
.map((tblSchema) => tblSchema.yProps.map((yProp) => yProp.updatesTable))
|
|
4859
|
+
.flat();
|
|
4860
|
+
for (const yTable of allYTables) {
|
|
4861
|
+
const mergedEntry = mergedSpec[yTable];
|
|
4862
|
+
const unsentFrom = (_c = mergedEntry === null || mergedEntry === void 0 ? void 0 : mergedEntry.unsentFrom) !== null && _c !== void 0 ? _c : 1;
|
|
4863
|
+
const receivedUntil = (_e = (_d = mergedEntry === null || mergedEntry === void 0 ? void 0 : mergedEntry.receivedUntil) !== null && _d !== void 0 ? _d :
|
|
4864
|
+
// from local because we are in the same parent transaction (in sync.ts) that
|
|
4865
|
+
// applied all updates from the server
|
|
4866
|
+
(yield db
|
|
4867
|
+
.table(yTable)
|
|
4868
|
+
.where('i')
|
|
4869
|
+
.between(1, Infinity) // Because i might be string DEXIE_CLOUD_SYNCER_ID if not a number.
|
|
4870
|
+
.reverse()
|
|
4871
|
+
.limit(1)
|
|
4872
|
+
.primaryKeys())[0]) !== null && _e !== void 0 ? _e : 0;
|
|
4826
4873
|
// We're already in a transaction, but for the sake of
|
|
4827
4874
|
// code readability and correctness, let's launch an atomic sub transaction:
|
|
4828
4875
|
yield db.transaction('rw', yTable, () => __awaiter(this, void 0, void 0, function* () {
|
|
4829
|
-
const state = yield db
|
|
4876
|
+
const state = yield db
|
|
4877
|
+
.table(yTable)
|
|
4878
|
+
.get(DEXIE_CLOUD_SYNCER_ID);
|
|
4830
4879
|
if (!state) {
|
|
4831
4880
|
yield db.table(yTable).add({
|
|
4832
4881
|
i: DEXIE_CLOUD_SYNCER_ID,
|
|
4833
|
-
unsentFrom
|
|
4834
|
-
receivedUntil
|
|
4882
|
+
unsentFrom,
|
|
4883
|
+
receivedUntil,
|
|
4835
4884
|
serverRev: serverRevision,
|
|
4836
4885
|
});
|
|
4837
4886
|
}
|
|
4838
4887
|
else {
|
|
4839
|
-
|
|
4840
|
-
|
|
4841
|
-
|
|
4842
|
-
if (receivedUntil) {
|
|
4843
|
-
state.receivedUntil = Math.max(receivedUntil, state.receivedUntil || 0);
|
|
4844
|
-
state.serverRev = serverRevision;
|
|
4845
|
-
}
|
|
4888
|
+
state.unsentFrom = Math.max(unsentFrom, state.unsentFrom || 1);
|
|
4889
|
+
state.receivedUntil = Math.max(receivedUntil, state.receivedUntil || 0);
|
|
4890
|
+
state.serverRev = serverRevision;
|
|
4846
4891
|
yield db.table(yTable).put(state);
|
|
4847
4892
|
}
|
|
4848
4893
|
}));
|
|
@@ -4853,9 +4898,11 @@ function updateYSyncStates(lastUpdateIdsBeforeSync, receivedUntilsAfterSync, db,
|
|
|
4853
4898
|
const BINSTREAM_TYPE_REALMID = 1;
|
|
4854
4899
|
const BINSTREAM_TYPE_TABLE_AND_PROP = 2;
|
|
4855
4900
|
const BINSTREAM_TYPE_DOCUMENT = 3;
|
|
4856
|
-
function downloadYDocsFromServer(
|
|
4857
|
-
return __awaiter(this,
|
|
4858
|
-
if (yDownloadedRealms &&
|
|
4901
|
+
function downloadYDocsFromServer(db_1, databaseUrl_1, _a) {
|
|
4902
|
+
return __awaiter(this, arguments, void 0, function* (db, databaseUrl, { yDownloadedRealms, realms }) {
|
|
4903
|
+
if (yDownloadedRealms &&
|
|
4904
|
+
realms &&
|
|
4905
|
+
realms.every((realmId) => yDownloadedRealms[realmId] === '*')) {
|
|
4859
4906
|
return; // Already done!
|
|
4860
4907
|
}
|
|
4861
4908
|
console.debug('Downloading Y.Docs from added realms');
|
|
@@ -4895,16 +4942,19 @@ function downloadYDocsFromServer(db, databaseUrl, { yDownloadedRealms, realms })
|
|
|
4895
4942
|
yield yTable.bulkAdd(docsToInsert);
|
|
4896
4943
|
docsToInsert = [];
|
|
4897
4944
|
}
|
|
4898
|
-
if (currentRealmId &&
|
|
4899
|
-
|
|
4900
|
-
|
|
4901
|
-
|
|
4902
|
-
|
|
4945
|
+
if (currentRealmId &&
|
|
4946
|
+
((currentTable && currentProp && lastDoc) || completedRealm)) {
|
|
4947
|
+
yield db.$syncState.update('syncState', (syncState) => {
|
|
4948
|
+
const yDownloadedRealms = syncState.yDownloadedRealms || {};
|
|
4949
|
+
yDownloadedRealms[currentRealmId] = completedRealm
|
|
4950
|
+
? '*'
|
|
4951
|
+
: {
|
|
4903
4952
|
tbl: currentTable,
|
|
4904
4953
|
prop: currentProp,
|
|
4905
4954
|
key: lastDoc.k,
|
|
4906
|
-
}
|
|
4907
|
-
|
|
4955
|
+
};
|
|
4956
|
+
syncState.yDownloadedRealms = yDownloadedRealms;
|
|
4957
|
+
});
|
|
4908
4958
|
}
|
|
4909
4959
|
});
|
|
4910
4960
|
}
|
|
@@ -5007,11 +5057,11 @@ function sync(db, options, schema, syncOptions) {
|
|
|
5007
5057
|
return Promise.reject(error);
|
|
5008
5058
|
}));
|
|
5009
5059
|
}
|
|
5010
|
-
function _sync(
|
|
5011
|
-
isInitialSync
|
|
5012
|
-
|
|
5013
|
-
|
|
5014
|
-
|
|
5060
|
+
function _sync(db_1, options_1, schema_1) {
|
|
5061
|
+
return __awaiter(this, arguments, void 0, function* (db, options, schema, { isInitialSync, cancelToken, justCheckIfNeeded, purpose } = {
|
|
5062
|
+
isInitialSync: false,
|
|
5063
|
+
}) {
|
|
5064
|
+
var _a;
|
|
5015
5065
|
if (!justCheckIfNeeded) {
|
|
5016
5066
|
console.debug('SYNC STARTED', { isInitialSync, purpose });
|
|
5017
5067
|
}
|
|
@@ -5053,8 +5103,8 @@ function _sync(db, options, schema, { isInitialSync, cancelToken, justCheckIfNee
|
|
|
5053
5103
|
const [clientChangeSet, syncState, baseRevs, { yMessages, lastUpdateIds }] = yield db.transaction('r', db.tables, () => __awaiter(this, void 0, void 0, function* () {
|
|
5054
5104
|
const syncState = yield db.getPersistedSyncState();
|
|
5055
5105
|
const baseRevs = yield db.$baseRevs.toArray();
|
|
5056
|
-
let clientChanges = yield listClientChanges(mutationTables);
|
|
5057
|
-
const yResults = yield listYClientMessagesAndStateVector(db);
|
|
5106
|
+
let clientChanges = yield listClientChanges(mutationTables, db);
|
|
5107
|
+
const yResults = yield listYClientMessagesAndStateVector(db, tablesToSync);
|
|
5058
5108
|
throwIfCancelled(cancelToken);
|
|
5059
5109
|
if (doSyncify) {
|
|
5060
5110
|
const alreadySyncedRealms = [
|
|
@@ -5184,11 +5234,14 @@ function _sync(db, options, schema, { isInitialSync, cancelToken, justCheckIfNee
|
|
|
5184
5234
|
//
|
|
5185
5235
|
// apply yMessages
|
|
5186
5236
|
//
|
|
5187
|
-
const receivedUntils = yield applyYServerMessages(res.yMessages, db);
|
|
5237
|
+
const { receivedUntils, resyncNeeded } = yield applyYServerMessages(res.yMessages, db);
|
|
5188
5238
|
//
|
|
5189
5239
|
// update Y SyncStates
|
|
5190
5240
|
//
|
|
5191
5241
|
yield updateYSyncStates(lastUpdateIds, receivedUntils, db, res.serverRevision);
|
|
5242
|
+
if (resyncNeeded) {
|
|
5243
|
+
newSyncState.yDownloadedRealms = {}; // Will trigger a full download of Y-documents below...
|
|
5244
|
+
}
|
|
5192
5245
|
}
|
|
5193
5246
|
//
|
|
5194
5247
|
// Update regular syncState
|
|
@@ -5322,8 +5375,8 @@ function MessagesFromServerConsumer(db) {
|
|
|
5322
5375
|
event.next(null);
|
|
5323
5376
|
}
|
|
5324
5377
|
function consumeQueue() {
|
|
5325
|
-
var _a, _b, _c, _d, _e, _f;
|
|
5326
5378
|
return __awaiter(this, void 0, void 0, function* () {
|
|
5379
|
+
var _a, _b, _c, _d, _e, _f;
|
|
5327
5380
|
while (queue.length > 0) {
|
|
5328
5381
|
const msg = queue.shift();
|
|
5329
5382
|
try {
|
|
@@ -5638,8 +5691,8 @@ function logout(db) {
|
|
|
5638
5691
|
}
|
|
5639
5692
|
});
|
|
5640
5693
|
}
|
|
5641
|
-
function _logout(
|
|
5642
|
-
return __awaiter(this,
|
|
5694
|
+
function _logout(db_1) {
|
|
5695
|
+
return __awaiter(this, arguments, void 0, function* (db, { deleteUnsyncedData = false } = {}) {
|
|
5643
5696
|
// Clear the database without emptying configuration options.
|
|
5644
5697
|
const [numUnsynced, loggedOut] = yield db.dx.transaction('rw', db.dx.tables, (tx) => __awaiter(this, void 0, void 0, function* () {
|
|
5645
5698
|
// @ts-ignore
|
|
@@ -5677,11 +5730,11 @@ function _logout(db, { deleteUnsyncedData = false } = {}) {
|
|
|
5677
5730
|
|
|
5678
5731
|
function otpFetchTokenCallback(db) {
|
|
5679
5732
|
const { userInteraction } = db.cloud;
|
|
5680
|
-
return function otpAuthenticate(
|
|
5681
|
-
|
|
5682
|
-
|
|
5733
|
+
return function otpAuthenticate(_a) {
|
|
5734
|
+
return __awaiter(this, arguments, void 0, function* ({ public_key, hints }) {
|
|
5735
|
+
var _b;
|
|
5683
5736
|
let tokenRequest;
|
|
5684
|
-
const url = (
|
|
5737
|
+
const url = (_b = db.cloud.options) === null || _b === void 0 ? void 0 : _b.databaseUrl;
|
|
5685
5738
|
if (!url)
|
|
5686
5739
|
throw new Error(`No database URL given.`);
|
|
5687
5740
|
if ((hints === null || hints === void 0 ? void 0 : hints.grant_type) === 'demo') {
|
|
@@ -5847,8 +5900,8 @@ function setCurrentUser(db, user) {
|
|
|
5847
5900
|
}
|
|
5848
5901
|
|
|
5849
5902
|
function login(db, hints) {
|
|
5850
|
-
var _a;
|
|
5851
5903
|
return __awaiter(this, void 0, void 0, function* () {
|
|
5904
|
+
var _a;
|
|
5852
5905
|
const currentUser = yield db.getCurrentUser();
|
|
5853
5906
|
const origUserId = currentUser.userId;
|
|
5854
5907
|
if (currentUser.isLoggedIn && (!hints || (!hints.email && !hints.userId))) {
|
|
@@ -6285,8 +6338,7 @@ function createMutationTrackingMiddleware({ currentUserObservable, db, }) {
|
|
|
6285
6338
|
outstandingTransactions.next(outstandingTransactions.value);
|
|
6286
6339
|
};
|
|
6287
6340
|
const txComplete = () => {
|
|
6288
|
-
if (tx.mutationsAdded &&
|
|
6289
|
-
!isEagerSyncDisabled(db)) {
|
|
6341
|
+
if (tx.mutationsAdded && !isEagerSyncDisabled(db)) {
|
|
6290
6342
|
triggerSync(db, 'push');
|
|
6291
6343
|
}
|
|
6292
6344
|
removeTransaction();
|
|
@@ -6368,26 +6420,107 @@ function createMutationTrackingMiddleware({ currentUserObservable, db, }) {
|
|
|
6368
6420
|
: mutateAndLog(req);
|
|
6369
6421
|
} }));
|
|
6370
6422
|
function mutateAndLog(req) {
|
|
6423
|
+
var _a, _b;
|
|
6371
6424
|
const trans = req.trans;
|
|
6372
|
-
|
|
6425
|
+
const unsyncedProps = (_b = (_a = db.cloud.options) === null || _a === void 0 ? void 0 : _a.unsyncedProperties) === null || _b === void 0 ? void 0 : _b[tableName];
|
|
6373
6426
|
const { txid, currentUser: { userId }, } = trans;
|
|
6374
6427
|
const { type } = req;
|
|
6375
6428
|
const opNo = ++trans.opCount;
|
|
6429
|
+
function stripChangeSpec(changeSpec) {
|
|
6430
|
+
if (!unsyncedProps)
|
|
6431
|
+
return changeSpec;
|
|
6432
|
+
let rv = changeSpec;
|
|
6433
|
+
for (const keyPath of Object.keys(changeSpec)) {
|
|
6434
|
+
if (unsyncedProps.some((p) => keyPath === p || keyPath.startsWith(p + '.'))) {
|
|
6435
|
+
if (rv === changeSpec)
|
|
6436
|
+
rv = Object.assign({}, changeSpec); // clone on demand
|
|
6437
|
+
delete rv[keyPath];
|
|
6438
|
+
}
|
|
6439
|
+
}
|
|
6440
|
+
return rv;
|
|
6441
|
+
}
|
|
6376
6442
|
return table.mutate(req).then((res) => {
|
|
6443
|
+
var _a;
|
|
6377
6444
|
const { numFailures: hasFailures, failures } = res;
|
|
6378
6445
|
let keys = type === 'delete' ? req.keys : res.results;
|
|
6379
6446
|
let values = 'values' in req ? req.values : [];
|
|
6380
|
-
let
|
|
6447
|
+
let changeSpec = 'changeSpec' in req ? req.changeSpec : undefined;
|
|
6448
|
+
let updates = 'updates' in req ? req.updates : undefined;
|
|
6381
6449
|
if (hasFailures) {
|
|
6382
6450
|
keys = keys.filter((_, idx) => !failures[idx]);
|
|
6383
6451
|
values = values.filter((_, idx) => !failures[idx]);
|
|
6384
6452
|
}
|
|
6453
|
+
if (unsyncedProps) {
|
|
6454
|
+
// Filter out unsynced properties
|
|
6455
|
+
values = values.map((value) => {
|
|
6456
|
+
const newValue = Object.assign({}, value);
|
|
6457
|
+
for (const prop of unsyncedProps) {
|
|
6458
|
+
delete newValue[prop];
|
|
6459
|
+
}
|
|
6460
|
+
return newValue;
|
|
6461
|
+
});
|
|
6462
|
+
if (changeSpec) {
|
|
6463
|
+
// modify operation with criteria and changeSpec.
|
|
6464
|
+
// We must strip out unsynced properties from changeSpec.
|
|
6465
|
+
// We deal with criteria later.
|
|
6466
|
+
changeSpec = stripChangeSpec(changeSpec);
|
|
6467
|
+
if (Object.keys(changeSpec).length === 0) {
|
|
6468
|
+
// Nothing to change on server
|
|
6469
|
+
return res;
|
|
6470
|
+
}
|
|
6471
|
+
}
|
|
6472
|
+
if (updates) {
|
|
6473
|
+
let strippedChangeSpecs = updates.changeSpecs.map(stripChangeSpec);
|
|
6474
|
+
let newUpdates = {
|
|
6475
|
+
keys: [],
|
|
6476
|
+
changeSpecs: [],
|
|
6477
|
+
};
|
|
6478
|
+
const validKeys = new RangeSet();
|
|
6479
|
+
let anyChangeSpecBecameEmpty = false;
|
|
6480
|
+
for (let i = 0, l = strippedChangeSpecs.length; i < l; ++i) {
|
|
6481
|
+
if (Object.keys(strippedChangeSpecs[i]).length > 0) {
|
|
6482
|
+
newUpdates.keys.push(updates.keys[i]);
|
|
6483
|
+
newUpdates.changeSpecs.push(strippedChangeSpecs[i]);
|
|
6484
|
+
validKeys.addKey(updates.keys[i]);
|
|
6485
|
+
}
|
|
6486
|
+
else {
|
|
6487
|
+
anyChangeSpecBecameEmpty = true;
|
|
6488
|
+
}
|
|
6489
|
+
}
|
|
6490
|
+
updates = newUpdates;
|
|
6491
|
+
if (anyChangeSpecBecameEmpty) {
|
|
6492
|
+
// Some keys were stripped. We must also strip them from keys and values
|
|
6493
|
+
let newKeys = [];
|
|
6494
|
+
let newValues = [];
|
|
6495
|
+
for (let i = 0, l = keys.length; i < l; ++i) {
|
|
6496
|
+
if (validKeys.hasKey(keys[i])) {
|
|
6497
|
+
newKeys.push(keys[i]);
|
|
6498
|
+
newValues.push(values[i]);
|
|
6499
|
+
}
|
|
6500
|
+
}
|
|
6501
|
+
keys = newKeys;
|
|
6502
|
+
values = newValues;
|
|
6503
|
+
}
|
|
6504
|
+
}
|
|
6505
|
+
}
|
|
6385
6506
|
const ts = Date.now();
|
|
6386
6507
|
// Canonicalize req.criteria.index to null if it's on the primary key.
|
|
6387
|
-
|
|
6508
|
+
let criteria = 'criteria' in req && req.criteria
|
|
6388
6509
|
? Object.assign(Object.assign({}, req.criteria), { index: req.criteria.index === schema.primaryKey.keyPath // Use null to inform server that criteria is on primary key
|
|
6389
6510
|
? null // This will disable the server from trying to log consistent operations where it shouldnt.
|
|
6390
6511
|
: req.criteria.index }) : undefined;
|
|
6512
|
+
if (unsyncedProps && (criteria === null || criteria === void 0 ? void 0 : criteria.index)) {
|
|
6513
|
+
const keyPaths = (_a = schema.indexes.find((idx) => idx.name === criteria.index)) === null || _a === void 0 ? void 0 : _a.keyPath;
|
|
6514
|
+
const involvedProps = keyPaths
|
|
6515
|
+
? typeof keyPaths === 'string'
|
|
6516
|
+
? [keyPaths]
|
|
6517
|
+
: keyPaths
|
|
6518
|
+
: [];
|
|
6519
|
+
if (involvedProps.some((p) => unsyncedProps === null || unsyncedProps === void 0 ? void 0 : unsyncedProps.includes(p))) {
|
|
6520
|
+
// Don't log criteria on unsynced properties as the server could not test them.
|
|
6521
|
+
criteria = undefined;
|
|
6522
|
+
}
|
|
6523
|
+
}
|
|
6391
6524
|
const mut = req.type === 'delete'
|
|
6392
6525
|
? {
|
|
6393
6526
|
type: 'delete',
|
|
@@ -6408,7 +6541,7 @@ function createMutationTrackingMiddleware({ currentUserObservable, db, }) {
|
|
|
6408
6541
|
userId,
|
|
6409
6542
|
values,
|
|
6410
6543
|
}
|
|
6411
|
-
: criteria &&
|
|
6544
|
+
: criteria && changeSpec
|
|
6412
6545
|
? {
|
|
6413
6546
|
// Common changeSpec for all keys
|
|
6414
6547
|
type: 'modify',
|
|
@@ -6416,37 +6549,51 @@ function createMutationTrackingMiddleware({ currentUserObservable, db, }) {
|
|
|
6416
6549
|
opNo,
|
|
6417
6550
|
keys,
|
|
6418
6551
|
criteria,
|
|
6419
|
-
changeSpec
|
|
6552
|
+
changeSpec,
|
|
6420
6553
|
txid,
|
|
6421
6554
|
userId,
|
|
6422
6555
|
}
|
|
6423
|
-
:
|
|
6556
|
+
: changeSpec
|
|
6424
6557
|
? {
|
|
6425
|
-
//
|
|
6558
|
+
// In case criteria involved an unsynced property, we go for keys instead.
|
|
6426
6559
|
type: 'update',
|
|
6427
6560
|
ts,
|
|
6428
6561
|
opNo,
|
|
6429
|
-
keys: updates.keys,
|
|
6430
|
-
changeSpecs: updates.changeSpecs,
|
|
6431
|
-
txid,
|
|
6432
|
-
userId,
|
|
6433
|
-
}
|
|
6434
|
-
: {
|
|
6435
|
-
type: 'upsert',
|
|
6436
|
-
ts,
|
|
6437
|
-
opNo,
|
|
6438
6562
|
keys,
|
|
6439
|
-
|
|
6563
|
+
changeSpecs: keys.map(() => changeSpec),
|
|
6440
6564
|
txid,
|
|
6441
6565
|
userId,
|
|
6442
|
-
}
|
|
6566
|
+
}
|
|
6567
|
+
: updates
|
|
6568
|
+
? {
|
|
6569
|
+
// One changeSpec per key
|
|
6570
|
+
type: 'update',
|
|
6571
|
+
ts,
|
|
6572
|
+
opNo,
|
|
6573
|
+
keys: updates.keys,
|
|
6574
|
+
changeSpecs: updates.changeSpecs,
|
|
6575
|
+
txid,
|
|
6576
|
+
userId,
|
|
6577
|
+
}
|
|
6578
|
+
: {
|
|
6579
|
+
type: 'upsert',
|
|
6580
|
+
ts,
|
|
6581
|
+
opNo,
|
|
6582
|
+
keys,
|
|
6583
|
+
values,
|
|
6584
|
+
txid,
|
|
6585
|
+
userId,
|
|
6586
|
+
};
|
|
6443
6587
|
if ('isAdditionalChunk' in req && req.isAdditionalChunk) {
|
|
6444
6588
|
mut.isAdditionalChunk = true;
|
|
6445
6589
|
}
|
|
6446
6590
|
return keys.length > 0 || criteria
|
|
6447
6591
|
? mutsTable
|
|
6448
6592
|
.mutate({ type: 'add', trans, values: [mut] }) // Log entry
|
|
6449
|
-
.then(() =>
|
|
6593
|
+
.then(() => {
|
|
6594
|
+
trans.mutationsAdded = true; // Mark transaction as having added mutations to trigger eager sync
|
|
6595
|
+
return res; // Return original response
|
|
6596
|
+
})
|
|
6450
6597
|
: res;
|
|
6451
6598
|
});
|
|
6452
6599
|
}
|
|
@@ -6613,38 +6760,51 @@ class TokenExpiredError extends Error {
|
|
|
6613
6760
|
|
|
6614
6761
|
function createYClientUpdateObservable(db) {
|
|
6615
6762
|
const yTableRecords = flatten(db.tables
|
|
6616
|
-
.filter((table) => { var _a; return ((_a = db.cloud.schema) === null || _a === void 0 ? void 0 : _a[table.name].markedForSync) && table.schema.yProps; })
|
|
6763
|
+
.filter((table) => { var _a, _b; return ((_b = (_a = db.cloud.schema) === null || _a === void 0 ? void 0 : _a[table.name]) === null || _b === void 0 ? void 0 : _b.markedForSync) && table.schema.yProps; })
|
|
6617
6764
|
.map((table) => table.schema.yProps.map((p) => ({
|
|
6618
6765
|
table: table.name,
|
|
6619
6766
|
ydocProp: p.prop,
|
|
6620
6767
|
updatesTable: p.updatesTable,
|
|
6621
6768
|
}))));
|
|
6622
6769
|
return merge(...yTableRecords.map(({ table, ydocProp, updatesTable }) => {
|
|
6623
|
-
|
|
6624
|
-
|
|
6625
|
-
|
|
6626
|
-
|
|
6627
|
-
|
|
6628
|
-
|
|
6629
|
-
|
|
6630
|
-
|
|
6631
|
-
|
|
6632
|
-
|
|
6633
|
-
|
|
6634
|
-
|
|
6635
|
-
|
|
6636
|
-
|
|
6637
|
-
|
|
6638
|
-
|
|
6639
|
-
|
|
6640
|
-
|
|
6641
|
-
|
|
6642
|
-
|
|
6643
|
-
|
|
6644
|
-
|
|
6645
|
-
|
|
6770
|
+
// Per updates table (table+prop combo), we first read syncer.unsentFrom,
|
|
6771
|
+
// and then start listening for updates since that number.
|
|
6772
|
+
const yTbl = db.table(updatesTable);
|
|
6773
|
+
return from$1(yTbl.get(DEXIE_CLOUD_SYNCER_ID)).pipe(switchMap$1((syncer) => {
|
|
6774
|
+
let currentUnsentFrom = (syncer === null || syncer === void 0 ? void 0 : syncer.unsentFrom) || 1;
|
|
6775
|
+
return from$1(liveQuery(() => __awaiter(this, void 0, void 0, function* () {
|
|
6776
|
+
const addedUpdates = yield listUpdatesSince(yTbl, currentUnsentFrom);
|
|
6777
|
+
return addedUpdates
|
|
6778
|
+
.filter((update) => update.f && update.f & 1) // Only include local updates
|
|
6779
|
+
.map((update) => {
|
|
6780
|
+
return {
|
|
6781
|
+
type: 'u-c',
|
|
6782
|
+
table,
|
|
6783
|
+
prop: ydocProp,
|
|
6784
|
+
k: update.k,
|
|
6785
|
+
u: update.u,
|
|
6786
|
+
i: update.i,
|
|
6787
|
+
};
|
|
6788
|
+
});
|
|
6789
|
+
}))).pipe(tap$1((addedUpdates) => {
|
|
6790
|
+
// Update currentUnsentFrom to only listen for updates that will be newer than the ones we emitted.
|
|
6791
|
+
// (Before, we did this within the liveQuery, but that caused a bug because
|
|
6792
|
+
// a cancelled emittion of a liveQuery would update the currentUnsentFrom without
|
|
6793
|
+
// emitting anything, leading to that we jumped over some updates. Here we update it
|
|
6794
|
+
// after the liveQuery has emitted its updates)
|
|
6795
|
+
if (addedUpdates.length > 0) {
|
|
6796
|
+
currentUnsentFrom = addedUpdates.at(-1).i + 1;
|
|
6797
|
+
}
|
|
6798
|
+
}));
|
|
6646
6799
|
}));
|
|
6647
|
-
})).pipe(
|
|
6800
|
+
})).pipe(
|
|
6801
|
+
// Flatten the array of messages.
|
|
6802
|
+
// If messageProducer emits empty array, nothing is emitted
|
|
6803
|
+
// but if messageProducer emits array of messages, they are
|
|
6804
|
+
// emitted one by one.
|
|
6805
|
+
mergeMap$1((messages) => messages), tap$1((message) => {
|
|
6806
|
+
console.debug('dexie-cloud emitting y-c', message);
|
|
6807
|
+
}));
|
|
6648
6808
|
}
|
|
6649
6809
|
|
|
6650
6810
|
function getAwarenessLibrary(db) {
|
|
@@ -6661,25 +6821,24 @@ const SERVER_PING_TIMEOUT = 20000;
|
|
|
6661
6821
|
const CLIENT_PING_INTERVAL = 30000;
|
|
6662
6822
|
const FAIL_RETRY_WAIT_TIME = 60000;
|
|
6663
6823
|
class WSObservable extends Observable$1 {
|
|
6664
|
-
constructor(db, rev, realmSetHash, clientIdentity, messageProducer, webSocketStatus,
|
|
6665
|
-
super((subscriber) => new WSConnection(db, rev, realmSetHash, clientIdentity,
|
|
6824
|
+
constructor(db, rev, realmSetHash, clientIdentity, messageProducer, webSocketStatus, user) {
|
|
6825
|
+
super((subscriber) => new WSConnection(db, rev, realmSetHash, clientIdentity, user, subscriber, messageProducer, webSocketStatus));
|
|
6666
6826
|
}
|
|
6667
6827
|
}
|
|
6668
6828
|
let counter = 0;
|
|
6669
6829
|
class WSConnection extends Subscription$1 {
|
|
6670
|
-
constructor(db, rev, realmSetHash, clientIdentity,
|
|
6830
|
+
constructor(db, rev, realmSetHash, clientIdentity, user, subscriber, messageProducer, webSocketStatus) {
|
|
6671
6831
|
super(() => this.teardown());
|
|
6672
6832
|
this.id = ++counter;
|
|
6673
6833
|
this.subscriptions = new Set();
|
|
6674
6834
|
this.reconnecting = false;
|
|
6675
|
-
console.debug('New WebSocket Connection', this.id,
|
|
6835
|
+
console.debug('New WebSocket Connection', this.id, user.accessToken ? 'authorized' : 'unauthorized');
|
|
6676
6836
|
this.db = db;
|
|
6677
6837
|
this.databaseUrl = db.cloud.options.databaseUrl;
|
|
6678
6838
|
this.rev = rev;
|
|
6679
6839
|
this.realmSetHash = realmSetHash;
|
|
6680
6840
|
this.clientIdentity = clientIdentity;
|
|
6681
|
-
this.
|
|
6682
|
-
this.tokenExpiration = tokenExpiration;
|
|
6841
|
+
this.user = user;
|
|
6683
6842
|
this.subscriber = subscriber;
|
|
6684
6843
|
this.lastUserActivity = new Date();
|
|
6685
6844
|
this.messageProducer = messageProducer;
|
|
@@ -6739,7 +6898,8 @@ class WSConnection extends Subscription$1 {
|
|
|
6739
6898
|
//console.debug('SyncStatus: DUBB: Ooops it was closed!');
|
|
6740
6899
|
return;
|
|
6741
6900
|
}
|
|
6742
|
-
|
|
6901
|
+
const tokenExpiration = this.user.accessTokenExpiration;
|
|
6902
|
+
if (tokenExpiration && tokenExpiration < new Date()) {
|
|
6743
6903
|
this.subscriber.error(new TokenExpiredError()); // Will be handled in connectWebSocket.ts.
|
|
6744
6904
|
return;
|
|
6745
6905
|
}
|
|
@@ -6794,8 +6954,8 @@ class WSConnection extends Subscription$1 {
|
|
|
6794
6954
|
searchParams.set('rev', this.rev);
|
|
6795
6955
|
searchParams.set('realmsHash', this.realmSetHash);
|
|
6796
6956
|
searchParams.set('clientId', this.clientIdentity);
|
|
6797
|
-
if (this.
|
|
6798
|
-
searchParams.set('token', this.
|
|
6957
|
+
if (this.user.accessToken) {
|
|
6958
|
+
searchParams.set('token', this.user.accessToken);
|
|
6799
6959
|
}
|
|
6800
6960
|
// Connect the WebSocket to given url:
|
|
6801
6961
|
console.debug('dexie-cloud WebSocket create');
|
|
@@ -6810,12 +6970,12 @@ class WSConnection extends Subscription$1 {
|
|
|
6810
6970
|
ws.onmessage = (event) => {
|
|
6811
6971
|
if (!this.pinger)
|
|
6812
6972
|
return;
|
|
6813
|
-
console.debug('dexie-cloud WebSocket onmessage', event.data);
|
|
6814
6973
|
this.lastServerActivity = new Date();
|
|
6815
6974
|
try {
|
|
6816
6975
|
const msg = typeof event.data === 'string'
|
|
6817
6976
|
? TSON.parse(event.data)
|
|
6818
6977
|
: decodeYMessage(new Uint8Array(event.data));
|
|
6978
|
+
console.debug('dexie-cloud WebSocket onmessage', msg.type, msg);
|
|
6819
6979
|
if (msg.type === 'error') {
|
|
6820
6980
|
throw new Error(`Error message from dexie-cloud: ${msg.error}`);
|
|
6821
6981
|
}
|
|
@@ -6836,6 +6996,10 @@ class WSConnection extends Subscription$1 {
|
|
|
6836
6996
|
else if (msg.type === 'u-ack' || msg.type === 'u-reject' || msg.type === 'u-s' || msg.type === 'in-sync') {
|
|
6837
6997
|
applyYServerMessages([msg], this.db);
|
|
6838
6998
|
}
|
|
6999
|
+
else if (msg.type === 'outdated-server-rev') {
|
|
7000
|
+
// Won't happen but need this for typing.
|
|
7001
|
+
throw new Error('Outdated server revision not expected over WebSocket - only in sync using fetch()');
|
|
7002
|
+
}
|
|
6839
7003
|
else if (msg.type !== 'pong') {
|
|
6840
7004
|
this.subscriber.next(msg);
|
|
6841
7005
|
}
|
|
@@ -6871,17 +7035,27 @@ class WSConnection extends Subscription$1 {
|
|
|
6871
7035
|
this.webSocketStatus.value !== 'connected') {
|
|
6872
7036
|
this.webSocketStatus.next('connected');
|
|
6873
7037
|
}
|
|
7038
|
+
console.debug('dexie-cloud WebSocket send', msg.type, msg);
|
|
6874
7039
|
if (msg.type === 'ready') {
|
|
6875
7040
|
(_a = this.ws) === null || _a === void 0 ? void 0 : _a.send(TSON.stringify(msg));
|
|
6876
7041
|
}
|
|
6877
7042
|
else {
|
|
6878
7043
|
// If it's not a "ready" message, it's an YMessage.
|
|
6879
7044
|
// YMessages can be sent binary encoded.
|
|
7045
|
+
if (msg.type === 'u-c') {
|
|
7046
|
+
console.log("u-c:B", ++gotClientUpdateB);
|
|
7047
|
+
}
|
|
6880
7048
|
(_b = this.ws) === null || _b === void 0 ? void 0 : _b.send(encodeYMessage(msg));
|
|
6881
7049
|
}
|
|
6882
7050
|
}
|
|
6883
7051
|
}));
|
|
6884
|
-
|
|
7052
|
+
if (this.user.isLoggedIn && !isEagerSyncDisabled(this.db)) {
|
|
7053
|
+
this.subscriptions.add(createYClientUpdateObservable(this.db).pipe(tap$1((msg) => {
|
|
7054
|
+
if (msg.type === 'u-c') {
|
|
7055
|
+
console.log("u-c:A", ++gotClientUpdateA, msg.i);
|
|
7056
|
+
}
|
|
7057
|
+
})).subscribe(this.db.messageProducer));
|
|
7058
|
+
}
|
|
6885
7059
|
}
|
|
6886
7060
|
catch (error) {
|
|
6887
7061
|
this.pauseUntil = new Date(Date.now() + FAIL_RETRY_WAIT_TIME);
|
|
@@ -6889,6 +7063,8 @@ class WSConnection extends Subscription$1 {
|
|
|
6889
7063
|
});
|
|
6890
7064
|
}
|
|
6891
7065
|
}
|
|
7066
|
+
let gotClientUpdateA = 0;
|
|
7067
|
+
let gotClientUpdateB = 0;
|
|
6892
7068
|
|
|
6893
7069
|
class InvalidLicenseError extends Error {
|
|
6894
7070
|
constructor(license) {
|
|
@@ -6951,7 +7127,7 @@ function connectWebSocket(db) {
|
|
|
6951
7127
|
return db.cloud.persistedSyncState.pipe(filter((syncState) => (syncState === null || syncState === void 0 ? void 0 : syncState.realms.includes(userLogin.userId)) || false), take(1), map((syncState) => [userLogin, syncState]));
|
|
6952
7128
|
}
|
|
6953
7129
|
return new BehaviorSubject([userLogin, syncState]);
|
|
6954
|
-
}), switchMap((
|
|
7130
|
+
}), switchMap((_a) => __awaiter(this, [_a], void 0, function* ([userLogin, syncState]) { return [userLogin, yield computeRealmSetHash(syncState)]; })), distinctUntilChanged(([prevUser, prevHash], [currUser, currHash]) => prevUser === currUser && prevHash === currHash), switchMap(([userLogin, realmSetHash]) => {
|
|
6955
7131
|
var _a;
|
|
6956
7132
|
if (!((_a = db.cloud.persistedSyncState) === null || _a === void 0 ? void 0 : _a.value)) {
|
|
6957
7133
|
// Restart the flow if persistedSyncState is not yet available.
|
|
@@ -6961,7 +7137,7 @@ function connectWebSocket(db) {
|
|
|
6961
7137
|
// If no new entries, server won't bother the client. If new entries, server sends only those
|
|
6962
7138
|
// and the baseRev of the last from same client-ID.
|
|
6963
7139
|
if (userLogin) {
|
|
6964
|
-
return new WSObservable(db, db.cloud.persistedSyncState.value.serverRevision, realmSetHash, db.cloud.persistedSyncState.value.clientIdentity, messageProducer, db.cloud.webSocketStatus, userLogin
|
|
7140
|
+
return new WSObservable(db, db.cloud.persistedSyncState.value.serverRevision, realmSetHash, db.cloud.persistedSyncState.value.clientIdentity, messageProducer, db.cloud.webSocketStatus, userLogin);
|
|
6965
7141
|
}
|
|
6966
7142
|
else {
|
|
6967
7143
|
return from$1([]);
|
|
@@ -7012,8 +7188,8 @@ function connectWebSocket(db) {
|
|
|
7012
7188
|
}
|
|
7013
7189
|
|
|
7014
7190
|
function isSyncNeeded(db) {
|
|
7015
|
-
var _a;
|
|
7016
7191
|
return __awaiter(this, void 0, void 0, function* () {
|
|
7192
|
+
var _a;
|
|
7017
7193
|
return ((_a = db.cloud.options) === null || _a === void 0 ? void 0 : _a.databaseUrl) && db.cloud.schema
|
|
7018
7194
|
? yield sync(db, db.cloud.options, db.cloud.schema, { justCheckIfNeeded: true })
|
|
7019
7195
|
: false;
|
|
@@ -7697,6 +7873,7 @@ class PermissionChecker {
|
|
|
7697
7873
|
// If user can update any prop in any table in this realm, return true unless
|
|
7698
7874
|
// it regards to ownership change:
|
|
7699
7875
|
if (this.permissions.update === '*') {
|
|
7876
|
+
// @ts-ignore
|
|
7700
7877
|
return props.every((prop) => prop !== 'owner');
|
|
7701
7878
|
}
|
|
7702
7879
|
const tablePermissions = (_b = this.permissions.update) === null || _b === void 0 ? void 0 : _b[this.tableName];
|
|
@@ -7768,125 +7945,139 @@ const getInvitesObservable = associate((db) => {
|
|
|
7768
7945
|
});
|
|
7769
7946
|
|
|
7770
7947
|
function createYHandler(db) {
|
|
7771
|
-
const awap = getAwarenessLibrary(db);
|
|
7772
7948
|
return (provider) => {
|
|
7773
7949
|
var _a;
|
|
7774
7950
|
const doc = provider.doc;
|
|
7775
|
-
const { parentTable
|
|
7951
|
+
const { parentTable } = doc.meta || {};
|
|
7776
7952
|
if (!((_a = db.cloud.schema) === null || _a === void 0 ? void 0 : _a[parentTable].markedForSync)) {
|
|
7777
7953
|
return; // The table that holds the doc is not marked for sync - leave it to dexie. No syncing, no awareness.
|
|
7778
7954
|
}
|
|
7779
|
-
let awareness
|
|
7780
|
-
|
|
7781
|
-
|
|
7782
|
-
|
|
7783
|
-
|
|
7784
|
-
|
|
7785
|
-
|
|
7786
|
-
|
|
7955
|
+
let awareness;
|
|
7956
|
+
Object.defineProperty(provider, "awareness", {
|
|
7957
|
+
get() {
|
|
7958
|
+
if (awareness)
|
|
7959
|
+
return awareness;
|
|
7960
|
+
awareness = createAwareness(db, doc, provider);
|
|
7961
|
+
awarenessWeakMap.set(doc, awareness);
|
|
7962
|
+
return awareness;
|
|
7963
|
+
}
|
|
7964
|
+
});
|
|
7965
|
+
};
|
|
7966
|
+
}
|
|
7967
|
+
function createAwareness(db, doc, provider) {
|
|
7968
|
+
const { parentTable, parentId, parentProp, updatesTable } = doc.meta;
|
|
7969
|
+
const awap = getAwarenessLibrary(db);
|
|
7970
|
+
const awareness = new awap.Awareness(doc);
|
|
7971
|
+
awareness.on('update', ({ added, updated, removed }, origin) => {
|
|
7972
|
+
// Send the update
|
|
7973
|
+
const changedClients = added.concat(updated).concat(removed);
|
|
7974
|
+
const user = db.cloud.currentUser.value;
|
|
7975
|
+
if (origin !== 'server' && user.isLoggedIn && !isEagerSyncDisabled(db)) {
|
|
7976
|
+
const update = awap.encodeAwarenessUpdate(awareness, changedClients);
|
|
7977
|
+
db.messageProducer.next({
|
|
7978
|
+
type: 'aware',
|
|
7979
|
+
table: parentTable,
|
|
7980
|
+
prop: parentProp,
|
|
7981
|
+
k: doc.meta.parentId,
|
|
7982
|
+
u: update,
|
|
7983
|
+
});
|
|
7984
|
+
if (provider.destroyed) {
|
|
7985
|
+
// We're called from awareness.on('destroy') that did
|
|
7986
|
+
// removeAwarenessStates.
|
|
7987
|
+
// It's time to also send the doc-close message that dexie-cloud understands
|
|
7988
|
+
// and uses to stop subscribing for updates and awareness updates and brings
|
|
7989
|
+
// down the cached information in memory on the WS connection for this.
|
|
7787
7990
|
db.messageProducer.next({
|
|
7788
|
-
type: '
|
|
7991
|
+
type: 'doc-close',
|
|
7789
7992
|
table: parentTable,
|
|
7790
7993
|
prop: parentProp,
|
|
7791
|
-
k: doc.meta.parentId
|
|
7792
|
-
u: update,
|
|
7994
|
+
k: doc.meta.parentId
|
|
7793
7995
|
});
|
|
7794
|
-
if (provider.destroyed) {
|
|
7795
|
-
// We're called from awareness.on('destroy') that did
|
|
7796
|
-
// removeAwarenessStates.
|
|
7797
|
-
// It's time to also send the doc-close message that dexie-cloud understands
|
|
7798
|
-
// and uses to stop subscribing for updates and awareness updates and brings
|
|
7799
|
-
// down the cached information in memory on the WS connection for this.
|
|
7800
|
-
db.messageProducer.next({
|
|
7801
|
-
type: 'doc-close',
|
|
7802
|
-
table: parentTable,
|
|
7803
|
-
prop: parentProp,
|
|
7804
|
-
k: doc.meta.parentId
|
|
7805
|
-
});
|
|
7806
|
-
}
|
|
7807
7996
|
}
|
|
7808
|
-
}
|
|
7809
|
-
|
|
7810
|
-
|
|
7811
|
-
|
|
7812
|
-
|
|
7813
|
-
|
|
7814
|
-
|
|
7815
|
-
|
|
7997
|
+
}
|
|
7998
|
+
});
|
|
7999
|
+
awareness.on('destroy', () => {
|
|
8000
|
+
// Signal to server that this provider is destroyed (the update event will be triggered, which
|
|
8001
|
+
// in turn will trigger db.messageProducer that will send the message to the server if WS is connected)
|
|
8002
|
+
awap.removeAwarenessStates(awareness, [doc.clientID], 'provider destroyed');
|
|
8003
|
+
});
|
|
8004
|
+
// Open the document on the server
|
|
8005
|
+
(() => __awaiter(this, void 0, void 0, function* () {
|
|
8006
|
+
if (provider.destroyed)
|
|
8007
|
+
return;
|
|
8008
|
+
let connected = false;
|
|
8009
|
+
let currentFlowId = 1;
|
|
8010
|
+
const subscription = db.cloud.webSocketStatus.subscribe((wsStatus) => {
|
|
7816
8011
|
if (provider.destroyed)
|
|
7817
8012
|
return;
|
|
7818
|
-
|
|
7819
|
-
|
|
7820
|
-
|
|
7821
|
-
|
|
8013
|
+
// Keep "connected" state in a variable so we can check it after async operations
|
|
8014
|
+
connected = wsStatus === 'connected';
|
|
8015
|
+
// We are or got connected. Open the document on the server.
|
|
8016
|
+
const user = db.cloud.currentUser.value;
|
|
8017
|
+
if (wsStatus === "connected" && user.isLoggedIn && !isEagerSyncDisabled(db)) {
|
|
8018
|
+
++currentFlowId;
|
|
8019
|
+
openDocumentOnServer().catch(error => {
|
|
8020
|
+
console.warn(`Error catched in createYHandler.ts: ${error}`);
|
|
8021
|
+
});
|
|
8022
|
+
}
|
|
8023
|
+
});
|
|
8024
|
+
// Wait until WebSocket is connected
|
|
8025
|
+
provider.addCleanupHandler(subscription);
|
|
8026
|
+
/** Sends an 'doc-open' message to server whenever websocket becomes
|
|
8027
|
+
* connected, or if it is already connected.
|
|
8028
|
+
* The flow is aborted in case websocket is disconnected while querying
|
|
8029
|
+
* information required to compute the state vector. Flow is also
|
|
8030
|
+
* aborted in case document or provider has been destroyed during
|
|
8031
|
+
* the async parts of the task.
|
|
8032
|
+
*
|
|
8033
|
+
* The state vector is only computed from the updates that have occured
|
|
8034
|
+
* after the last full sync - which could very often be zero - in which
|
|
8035
|
+
* case no state vector is sent (then the server already knows us by
|
|
8036
|
+
* revision)
|
|
8037
|
+
*
|
|
8038
|
+
* When server gets the doc-open message, it will authorized us for
|
|
8039
|
+
* whether we are allowed to read / write to this document, and then
|
|
8040
|
+
* keep the cached information in memory on the WS connection for this
|
|
8041
|
+
* particular document, as well as subscribe to updates and awareness updates
|
|
8042
|
+
* from other clients on the document.
|
|
8043
|
+
*/
|
|
8044
|
+
function openDocumentOnServer(wsStatus) {
|
|
8045
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
8046
|
+
const myFlow = currentFlowId; // So we can abort when a new flow is started
|
|
8047
|
+
const yTbl = db.table(updatesTable);
|
|
8048
|
+
const syncState = yield yTbl.get(DEXIE_CLOUD_SYNCER_ID);
|
|
8049
|
+
// After every await, check if we still should be working on this task.
|
|
8050
|
+
if (provider.destroyed || currentFlowId !== myFlow || !connected)
|
|
7822
8051
|
return;
|
|
7823
|
-
|
|
7824
|
-
|
|
7825
|
-
|
|
7826
|
-
|
|
7827
|
-
|
|
7828
|
-
|
|
7829
|
-
|
|
7830
|
-
|
|
8052
|
+
const receivedUntil = (syncState === null || syncState === void 0 ? void 0 : syncState.receivedUntil) || 0;
|
|
8053
|
+
const docOpenMsg = {
|
|
8054
|
+
type: 'doc-open',
|
|
8055
|
+
table: parentTable,
|
|
8056
|
+
prop: parentProp,
|
|
8057
|
+
k: parentId,
|
|
8058
|
+
serverRev: syncState === null || syncState === void 0 ? void 0 : syncState.serverRev,
|
|
8059
|
+
};
|
|
8060
|
+
const serverUpdatesSinceLastSync = yield yTbl
|
|
8061
|
+
.where('i')
|
|
8062
|
+
.between(receivedUntil, Infinity, false)
|
|
8063
|
+
.filter((update) => cmp(update.k, parentId) === 0 && // Only updates for this document
|
|
8064
|
+
((update.f || 0) & 1) === 0 // Don't include local changes
|
|
8065
|
+
)
|
|
8066
|
+
.toArray();
|
|
8067
|
+
// After every await, check if we still should be working on this task.
|
|
8068
|
+
if (provider.destroyed || currentFlowId !== myFlow || !connected)
|
|
8069
|
+
return;
|
|
8070
|
+
if (serverUpdatesSinceLastSync.length > 0) {
|
|
8071
|
+
const Y = $Y(db); // Get the Yjs library from Dexie constructor options
|
|
8072
|
+
const mergedUpdate = Y.mergeUpdatesV2(serverUpdatesSinceLastSync.map((update) => update.u));
|
|
8073
|
+
const stateVector = Y.encodeStateVectorFromUpdateV2(mergedUpdate);
|
|
8074
|
+
docOpenMsg.sv = stateVector;
|
|
7831
8075
|
}
|
|
8076
|
+
db.messageProducer.next(docOpenMsg);
|
|
7832
8077
|
});
|
|
7833
|
-
|
|
7834
|
-
|
|
7835
|
-
|
|
7836
|
-
* connected, or if it is already connected.
|
|
7837
|
-
* The flow is aborted in case websocket is disconnected while querying
|
|
7838
|
-
* information required to compute the state vector. Flow is also
|
|
7839
|
-
* aborted in case document or provider has been destroyed during
|
|
7840
|
-
* the async parts of the task.
|
|
7841
|
-
*
|
|
7842
|
-
* The state vector is only computed from the updates that have occured
|
|
7843
|
-
* after the last full sync - which could very often be zero - in which
|
|
7844
|
-
* case no state vector is sent (then the server already knows us by
|
|
7845
|
-
* revision)
|
|
7846
|
-
*
|
|
7847
|
-
* When server gets the doc-open message, it will authorized us for
|
|
7848
|
-
* whether we are allowed to read / write to this document, and then
|
|
7849
|
-
* keep the cached information in memory on the WS connection for this
|
|
7850
|
-
* particular document, as well as subscribe to updates and awareness updates
|
|
7851
|
-
* from other clients on the document.
|
|
7852
|
-
*/
|
|
7853
|
-
function openDocumentOnServer(wsStatus) {
|
|
7854
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
7855
|
-
const myFlow = currentFlowId; // So we can abort when a new flow is started
|
|
7856
|
-
const yTbl = db.table(updatesTable);
|
|
7857
|
-
const syncState = yield yTbl.get(DEXIE_CLOUD_SYNCER_ID);
|
|
7858
|
-
// After every await, check if we still should be working on this task.
|
|
7859
|
-
if (provider.destroyed || currentFlowId !== myFlow || !connected)
|
|
7860
|
-
return;
|
|
7861
|
-
const receivedUntil = (syncState === null || syncState === void 0 ? void 0 : syncState.receivedUntil) || 0;
|
|
7862
|
-
const docOpenMsg = {
|
|
7863
|
-
type: 'doc-open',
|
|
7864
|
-
table: parentTable,
|
|
7865
|
-
prop: parentProp,
|
|
7866
|
-
k: parentId,
|
|
7867
|
-
serverRev: syncState === null || syncState === void 0 ? void 0 : syncState.serverRev,
|
|
7868
|
-
};
|
|
7869
|
-
const serverUpdatesSinceLastSync = yield yTbl
|
|
7870
|
-
.where('i')
|
|
7871
|
-
.between(receivedUntil, Infinity, false)
|
|
7872
|
-
.filter((update) => cmp(update.k, parentId) === 0 && // Only updates for this document
|
|
7873
|
-
((update.f || 0) & 1) === 0 // Don't include local changes
|
|
7874
|
-
)
|
|
7875
|
-
.toArray();
|
|
7876
|
-
// After every await, check if we still should be working on this task.
|
|
7877
|
-
if (provider.destroyed || currentFlowId !== myFlow || !connected)
|
|
7878
|
-
return;
|
|
7879
|
-
if (serverUpdatesSinceLastSync.length > 0) {
|
|
7880
|
-
const Y = $Y(db); // Get the Yjs library from Dexie constructor options
|
|
7881
|
-
const mergedUpdate = Y.mergeUpdatesV2(serverUpdatesSinceLastSync.map((update) => update.u));
|
|
7882
|
-
const stateVector = Y.encodeStateVectorFromUpdateV2(mergedUpdate);
|
|
7883
|
-
docOpenMsg.sv = stateVector;
|
|
7884
|
-
}
|
|
7885
|
-
db.messageProducer.next(docOpenMsg);
|
|
7886
|
-
});
|
|
7887
|
-
}
|
|
7888
|
-
}));
|
|
7889
|
-
};
|
|
8078
|
+
}
|
|
8079
|
+
}))();
|
|
8080
|
+
return awareness;
|
|
7890
8081
|
}
|
|
7891
8082
|
|
|
7892
8083
|
const DEFAULT_OPTIONS = {
|
|
@@ -7929,7 +8120,7 @@ function dexieCloud(dexie) {
|
|
|
7929
8120
|
const syncComplete = new Subject();
|
|
7930
8121
|
dexie.cloud = {
|
|
7931
8122
|
// @ts-ignore
|
|
7932
|
-
version: "4.1.0-alpha.
|
|
8123
|
+
version: "4.1.0-alpha.21",
|
|
7933
8124
|
options: Object.assign({}, DEFAULT_OPTIONS),
|
|
7934
8125
|
schema: null,
|
|
7935
8126
|
get currentUserId() {
|
|
@@ -7965,16 +8156,16 @@ function dexieCloud(dexie) {
|
|
|
7965
8156
|
}
|
|
7966
8157
|
updateSchemaFromOptions(dexie.cloud.schema, dexie.cloud.options);
|
|
7967
8158
|
},
|
|
7968
|
-
logout(
|
|
7969
|
-
return __awaiter(this,
|
|
8159
|
+
logout() {
|
|
8160
|
+
return __awaiter(this, arguments, void 0, function* ({ force } = {}) {
|
|
7970
8161
|
force
|
|
7971
8162
|
? yield _logout(DexieCloudDB(dexie), { deleteUnsyncedData: true })
|
|
7972
8163
|
: yield logout(DexieCloudDB(dexie));
|
|
7973
8164
|
});
|
|
7974
8165
|
},
|
|
7975
|
-
sync(
|
|
7976
|
-
|
|
7977
|
-
|
|
8166
|
+
sync() {
|
|
8167
|
+
return __awaiter(this, arguments, void 0, function* ({ wait, purpose } = { wait: true, purpose: 'push' }) {
|
|
8168
|
+
var _a;
|
|
7978
8169
|
if (wait === undefined)
|
|
7979
8170
|
wait = true;
|
|
7980
8171
|
const db = DexieCloudDB(dexie);
|
|
@@ -8032,8 +8223,8 @@ function dexieCloud(dexie) {
|
|
|
8032
8223
|
dexie.use(createImplicitPropSetterMiddleware(DexieCloudDB(dexie)));
|
|
8033
8224
|
dexie.use(createIdGenerationMiddleware(DexieCloudDB(dexie)));
|
|
8034
8225
|
function onDbReady(dexie) {
|
|
8035
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
8036
8226
|
return __awaiter(this, void 0, void 0, function* () {
|
|
8227
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
8037
8228
|
closed = false; // As Dexie calls us, we are not closed anymore. Maybe reopened? Remember db.ready event is registered with sticky flag!
|
|
8038
8229
|
const db = DexieCloudDB(dexie);
|
|
8039
8230
|
// Setup default GUI:
|
|
@@ -8056,7 +8247,7 @@ function dexieCloud(dexie) {
|
|
|
8056
8247
|
? yield navigator.serviceWorker.getRegistrations()
|
|
8057
8248
|
: [];
|
|
8058
8249
|
const [initiallySynced, lastSyncedRealms] = yield db.transaction('rw', db.$syncState, () => __awaiter(this, void 0, void 0, function* () {
|
|
8059
|
-
var
|
|
8250
|
+
var _a, _b;
|
|
8060
8251
|
const { options, schema } = db.cloud;
|
|
8061
8252
|
const [persistedOptions, persistedSchema, persistedSyncState] = yield Promise.all([
|
|
8062
8253
|
db.getOptions(),
|
|
@@ -8078,7 +8269,7 @@ function dexieCloud(dexie) {
|
|
|
8078
8269
|
delete newPersistedOptions.awarenessProtocol;
|
|
8079
8270
|
yield db.$syncState.put(newPersistedOptions, 'options');
|
|
8080
8271
|
}
|
|
8081
|
-
if (((
|
|
8272
|
+
if (((_a = db.cloud.options) === null || _a === void 0 ? void 0 : _a.tryUseServiceWorker) &&
|
|
8082
8273
|
'serviceWorker' in navigator &&
|
|
8083
8274
|
swRegistrations.length > 0 &&
|
|
8084
8275
|
!DISABLE_SERVICEWORKER_STRATEGY) {
|
|
@@ -8092,7 +8283,7 @@ function dexieCloud(dexie) {
|
|
|
8092
8283
|
// Not configured for using service worker or no service worker
|
|
8093
8284
|
// registration exists. Don't rely on service worker to do any job.
|
|
8094
8285
|
// Use LocalSyncWorker instead.
|
|
8095
|
-
if (((
|
|
8286
|
+
if (((_b = db.cloud.options) === null || _b === void 0 ? void 0 : _b.tryUseServiceWorker) &&
|
|
8096
8287
|
!db.cloud.isServiceWorkerDB) {
|
|
8097
8288
|
console.debug('dexie-cloud-addon: Not using service worker.', swRegistrations.length === 0
|
|
8098
8289
|
? 'No SW registrations found.'
|
|
@@ -8231,7 +8422,7 @@ function dexieCloud(dexie) {
|
|
|
8231
8422
|
}
|
|
8232
8423
|
}
|
|
8233
8424
|
// @ts-ignore
|
|
8234
|
-
dexieCloud.version = "4.1.0-alpha.
|
|
8425
|
+
dexieCloud.version = "4.1.0-alpha.21";
|
|
8235
8426
|
Dexie.Cloud = dexieCloud;
|
|
8236
8427
|
|
|
8237
8428
|
// In case the SW lives for a while, let it reuse already opened connections:
|
|
@@ -8261,8 +8452,8 @@ function syncDB(dbName, purpose) {
|
|
|
8261
8452
|
}
|
|
8262
8453
|
return promise;
|
|
8263
8454
|
function _syncDB(dbName, purpose) {
|
|
8264
|
-
var _a;
|
|
8265
8455
|
return __awaiter(this, void 0, void 0, function* () {
|
|
8456
|
+
var _a;
|
|
8266
8457
|
let db = managedDBs.get(dbName);
|
|
8267
8458
|
if (!db) {
|
|
8268
8459
|
console.debug('Dexie Cloud SW: Creating new Dexie instance for', dbName);
|