dexie-cloud-addon 4.1.0-alpha.8 → 4.1.0-beta.25
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/db/entities/PersistedSyncState.d.ts +1 -0
- 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 +622 -257
- 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 +464 -255
- 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/YDexieCloudSyncState.d.ts +0 -1
- package/dist/modern/yjs/applyYMessages.d.ts +5 -1
- package/dist/modern/yjs/reopenDocSignal.d.ts +10 -0
- package/dist/modern/yjs/updateYSyncStates.d.ts +1 -1
- package/dist/umd/DexieCloudOptions.d.ts +3 -0
- package/dist/umd/TSON.d.ts +1 -1
- package/dist/umd/db/entities/PersistedSyncState.d.ts +1 -0
- 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 +620 -254
- 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 +462 -253
- 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/YDexieCloudSyncState.d.ts +0 -1
- package/dist/umd/yjs/applyYMessages.d.ts +5 -1
- package/dist/umd/yjs/reopenDocSignal.d.ts +10 -0
- package/dist/umd/yjs/updateYSyncStates.d.ts +1 -1
- package/package.json +6 -5
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*
|
|
9
9
|
* ==========================================================================
|
|
10
10
|
*
|
|
11
|
-
* Version 4.1.0-
|
|
11
|
+
* Version 4.1.0-beta.25, Wed Dec 04 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, startWith as startWith$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,20 @@ 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;
|
|
2768
|
+
case 'y-complete-sync-done':
|
|
2769
|
+
writeVarString(encoder, msg.yServerRev);
|
|
2770
|
+
break;
|
|
2764
2771
|
default:
|
|
2765
2772
|
writeAny(encoder, msg.k);
|
|
2766
2773
|
switch (msg.type) {
|
|
@@ -3104,6 +3111,12 @@ const readAny = decoder => readAnyLookupTable[127 - readUint8(decoder)](decoder)
|
|
|
3104
3111
|
function decodeYMessage(a) {
|
|
3105
3112
|
const decoder = new Decoder(a);
|
|
3106
3113
|
const type = readVarString(decoder);
|
|
3114
|
+
if (type === 'outdated-server-rev') {
|
|
3115
|
+
return { type };
|
|
3116
|
+
}
|
|
3117
|
+
if (type === 'y-complete-sync-done') {
|
|
3118
|
+
return { type, yServerRev: readVarString(decoder) };
|
|
3119
|
+
}
|
|
3107
3120
|
const table = readVarString(decoder);
|
|
3108
3121
|
const prop = readVarString(decoder);
|
|
3109
3122
|
switch (type) {
|
|
@@ -3516,8 +3529,8 @@ function confirmLogout(userInteraction, currentUserId, numUnsyncedChanges) {
|
|
|
3516
3529
|
}
|
|
3517
3530
|
|
|
3518
3531
|
function loadAccessToken(db) {
|
|
3519
|
-
var _a, _b, _c;
|
|
3520
3532
|
return __awaiter(this, void 0, void 0, function* () {
|
|
3533
|
+
var _a, _b, _c;
|
|
3521
3534
|
const currentUser = yield db.getCurrentUser();
|
|
3522
3535
|
const { accessToken, accessTokenExpiration, refreshToken, refreshTokenExpiration, claims, } = currentUser;
|
|
3523
3536
|
if (!accessToken)
|
|
@@ -4347,8 +4360,8 @@ function cloneChange(change, rewriteValues) {
|
|
|
4347
4360
|
// seconds (given that there is a Ratelimit-Reset header).
|
|
4348
4361
|
let syncRatelimitDelays = new WeakMap();
|
|
4349
4362
|
function checkSyncRateLimitDelay(db) {
|
|
4350
|
-
var _a, _b;
|
|
4351
4363
|
return __awaiter(this, void 0, void 0, function* () {
|
|
4364
|
+
var _a, _b;
|
|
4352
4365
|
const delatMilliseconds = ((_b = (_a = syncRatelimitDelays.get(db)) === null || _a === void 0 ? void 0 : _a.getTime()) !== null && _b !== void 0 ? _b : 0) - Date.now();
|
|
4353
4366
|
if (delatMilliseconds > 0) {
|
|
4354
4367
|
console.debug(`Stalling sync request ${delatMilliseconds} ms to spare ratelimits`);
|
|
@@ -4409,6 +4422,7 @@ function syncWithServer(changes, y, syncState, baseRevs, db, databaseUrl, schema
|
|
|
4409
4422
|
lastPull: syncState
|
|
4410
4423
|
? {
|
|
4411
4424
|
serverRevision: syncState.serverRevision,
|
|
4425
|
+
yServerRevision: syncState.yServerRevision,
|
|
4412
4426
|
realms: syncState.realms,
|
|
4413
4427
|
inviteRealms: syncState.inviteRealms,
|
|
4414
4428
|
}
|
|
@@ -4753,12 +4767,15 @@ function getUpdatesTable(db, table, ydocProp) {
|
|
|
4753
4767
|
|
|
4754
4768
|
function applyYServerMessages(yMessages, db) {
|
|
4755
4769
|
return __awaiter(this, void 0, void 0, function* () {
|
|
4756
|
-
|
|
4770
|
+
var _a;
|
|
4771
|
+
const receivedUntils = {};
|
|
4772
|
+
let resyncNeeded = false;
|
|
4773
|
+
let yServerRevision;
|
|
4757
4774
|
for (const m of yMessages) {
|
|
4758
4775
|
switch (m.type) {
|
|
4759
4776
|
case 'u-s': {
|
|
4760
4777
|
const utbl = getUpdatesTable(db, m.table, m.prop);
|
|
4761
|
-
|
|
4778
|
+
receivedUntils[utbl.name] = yield utbl.add({
|
|
4762
4779
|
k: m.k,
|
|
4763
4780
|
u: m.u,
|
|
4764
4781
|
});
|
|
@@ -4783,7 +4800,24 @@ function applyYServerMessages(yMessages, db) {
|
|
|
4783
4800
|
// See my question in https://discuss.yjs.dev/t/generate-an-inverse-update/2765
|
|
4784
4801
|
console.debug(`Y update rejected. Deleting it.`);
|
|
4785
4802
|
const utbl = getUpdatesTable(db, m.table, m.prop);
|
|
4786
|
-
|
|
4803
|
+
// Delete the rejected update and all local updates since (avoid holes in the CRDT)
|
|
4804
|
+
// and destroy it's open document if there is one.
|
|
4805
|
+
const primaryKey = (_a = (yield utbl.get(m.i))) === null || _a === void 0 ? void 0 : _a.k;
|
|
4806
|
+
if (primaryKey != null) {
|
|
4807
|
+
yield db.transaction('rw', utbl, (tx) => {
|
|
4808
|
+
// @ts-ignore
|
|
4809
|
+
tx.idbtrans._rejecting_y_ypdate = true; // Inform ydoc triggers that we delete because of a rejection and not GC
|
|
4810
|
+
return utbl
|
|
4811
|
+
.where('i')
|
|
4812
|
+
.aboveOrEqual(m.i)
|
|
4813
|
+
.filter((u) => cmp(u.k, primaryKey) === 0 && ((u.f || 0) & 1) === 1)
|
|
4814
|
+
.delete();
|
|
4815
|
+
});
|
|
4816
|
+
// Destroy active doc
|
|
4817
|
+
const activeDoc = DexieYProvider.getDocCache(db.dx).find(m.table, primaryKey, m.prop);
|
|
4818
|
+
if (activeDoc)
|
|
4819
|
+
activeDoc.destroy(); // Destroy the document so that editors don't continue to work on it
|
|
4820
|
+
}
|
|
4787
4821
|
break;
|
|
4788
4822
|
}
|
|
4789
4823
|
case 'in-sync': {
|
|
@@ -4793,15 +4827,26 @@ function applyYServerMessages(yMessages, db) {
|
|
|
4793
4827
|
}
|
|
4794
4828
|
break;
|
|
4795
4829
|
}
|
|
4830
|
+
case 'y-complete-sync-done': {
|
|
4831
|
+
yServerRevision = m.yServerRev;
|
|
4832
|
+
break;
|
|
4833
|
+
}
|
|
4834
|
+
case 'outdated-server-rev':
|
|
4835
|
+
resyncNeeded = true;
|
|
4836
|
+
break;
|
|
4796
4837
|
}
|
|
4797
4838
|
}
|
|
4798
|
-
return
|
|
4839
|
+
return {
|
|
4840
|
+
receivedUntils,
|
|
4841
|
+
resyncNeeded,
|
|
4842
|
+
yServerRevision
|
|
4843
|
+
};
|
|
4799
4844
|
});
|
|
4800
4845
|
}
|
|
4801
4846
|
|
|
4802
|
-
function updateYSyncStates(lastUpdateIdsBeforeSync, receivedUntilsAfterSync, db
|
|
4803
|
-
var _a, _b, _c, _d, _e;
|
|
4847
|
+
function updateYSyncStates(lastUpdateIdsBeforeSync, receivedUntilsAfterSync, db) {
|
|
4804
4848
|
return __awaiter(this, void 0, void 0, function* () {
|
|
4849
|
+
var _a, _b, _c, _d, _e;
|
|
4805
4850
|
// We want to update unsentFrom for each yTable to the value specified in first argument
|
|
4806
4851
|
// because we got those values before we synced with server and here we are back from server
|
|
4807
4852
|
// that has successfully received all those messages - no matter if the last update was a client or server update,
|
|
@@ -4848,14 +4893,12 @@ function updateYSyncStates(lastUpdateIdsBeforeSync, receivedUntilsAfterSync, db,
|
|
|
4848
4893
|
yield db.table(yTable).add({
|
|
4849
4894
|
i: DEXIE_CLOUD_SYNCER_ID,
|
|
4850
4895
|
unsentFrom,
|
|
4851
|
-
receivedUntil
|
|
4852
|
-
serverRev: serverRevision,
|
|
4896
|
+
receivedUntil
|
|
4853
4897
|
});
|
|
4854
4898
|
}
|
|
4855
4899
|
else {
|
|
4856
4900
|
state.unsentFrom = Math.max(unsentFrom, state.unsentFrom || 1);
|
|
4857
4901
|
state.receivedUntil = Math.max(receivedUntil, state.receivedUntil || 0);
|
|
4858
|
-
state.serverRev = serverRevision;
|
|
4859
4902
|
yield db.table(yTable).put(state);
|
|
4860
4903
|
}
|
|
4861
4904
|
}));
|
|
@@ -4866,8 +4909,8 @@ function updateYSyncStates(lastUpdateIdsBeforeSync, receivedUntilsAfterSync, db,
|
|
|
4866
4909
|
const BINSTREAM_TYPE_REALMID = 1;
|
|
4867
4910
|
const BINSTREAM_TYPE_TABLE_AND_PROP = 2;
|
|
4868
4911
|
const BINSTREAM_TYPE_DOCUMENT = 3;
|
|
4869
|
-
function downloadYDocsFromServer(
|
|
4870
|
-
return __awaiter(this,
|
|
4912
|
+
function downloadYDocsFromServer(db_1, databaseUrl_1, _a) {
|
|
4913
|
+
return __awaiter(this, arguments, void 0, function* (db, databaseUrl, { yDownloadedRealms, realms }) {
|
|
4871
4914
|
if (yDownloadedRealms &&
|
|
4872
4915
|
realms &&
|
|
4873
4916
|
realms.every((realmId) => yDownloadedRealms[realmId] === '*')) {
|
|
@@ -4982,8 +5025,7 @@ function downloadYDocsFromServer(db, databaseUrl, { yDownloadedRealms, realms })
|
|
|
4982
5025
|
|
|
4983
5026
|
const CURRENT_SYNC_WORKER = 'currentSyncWorker';
|
|
4984
5027
|
function sync(db, options, schema, syncOptions) {
|
|
4985
|
-
return _sync
|
|
4986
|
-
.apply(this, arguments)
|
|
5028
|
+
return _sync(db, options, schema, syncOptions)
|
|
4987
5029
|
.then((result) => {
|
|
4988
5030
|
if (!(syncOptions === null || syncOptions === void 0 ? void 0 : syncOptions.justCheckIfNeeded)) { // && syncOptions?.purpose !== 'push') {
|
|
4989
5031
|
db.syncStateChangedEvent.next({
|
|
@@ -5025,11 +5067,11 @@ function sync(db, options, schema, syncOptions) {
|
|
|
5025
5067
|
return Promise.reject(error);
|
|
5026
5068
|
}));
|
|
5027
5069
|
}
|
|
5028
|
-
function _sync(
|
|
5029
|
-
isInitialSync
|
|
5030
|
-
|
|
5031
|
-
|
|
5032
|
-
|
|
5070
|
+
function _sync(db_1, options_1, schema_1) {
|
|
5071
|
+
return __awaiter(this, arguments, void 0, function* (db, options, schema, { isInitialSync, cancelToken, justCheckIfNeeded, purpose } = {
|
|
5072
|
+
isInitialSync: false,
|
|
5073
|
+
}) {
|
|
5074
|
+
var _a;
|
|
5033
5075
|
if (!justCheckIfNeeded) {
|
|
5034
5076
|
console.debug('SYNC STARTED', { isInitialSync, purpose });
|
|
5035
5077
|
}
|
|
@@ -5046,7 +5088,7 @@ function _sync(db, options, schema, { isInitialSync, cancelToken, justCheckIfNee
|
|
|
5046
5088
|
// Prepare for syncification by modifying locally unauthorized objects:
|
|
5047
5089
|
//
|
|
5048
5090
|
const persistedSyncState = yield db.getPersistedSyncState();
|
|
5049
|
-
const readyForSyncification =
|
|
5091
|
+
const readyForSyncification = currentUser.isLoggedIn;
|
|
5050
5092
|
const tablesToSyncify = readyForSyncification
|
|
5051
5093
|
? getTablesToSyncify(db, persistedSyncState)
|
|
5052
5094
|
: [];
|
|
@@ -5071,7 +5113,7 @@ function _sync(db, options, schema, { isInitialSync, cancelToken, justCheckIfNee
|
|
|
5071
5113
|
const [clientChangeSet, syncState, baseRevs, { yMessages, lastUpdateIds }] = yield db.transaction('r', db.tables, () => __awaiter(this, void 0, void 0, function* () {
|
|
5072
5114
|
const syncState = yield db.getPersistedSyncState();
|
|
5073
5115
|
const baseRevs = yield db.$baseRevs.toArray();
|
|
5074
|
-
let clientChanges = yield listClientChanges(mutationTables);
|
|
5116
|
+
let clientChanges = yield listClientChanges(mutationTables, db);
|
|
5075
5117
|
const yResults = yield listYClientMessagesAndStateVector(db, tablesToSync);
|
|
5076
5118
|
throwIfCancelled(cancelToken);
|
|
5077
5119
|
if (doSyncify) {
|
|
@@ -5191,6 +5233,7 @@ function _sync(db, options, schema, { isInitialSync, cancelToken, justCheckIfNee
|
|
|
5191
5233
|
newSyncState.realms = res.realms;
|
|
5192
5234
|
newSyncState.inviteRealms = res.inviteRealms;
|
|
5193
5235
|
newSyncState.serverRevision = res.serverRevision;
|
|
5236
|
+
newSyncState.yServerRevision = res.serverRevision;
|
|
5194
5237
|
newSyncState.timestamp = new Date();
|
|
5195
5238
|
delete newSyncState.error;
|
|
5196
5239
|
const filteredChanges = filterServerChangesThroughAddedClientChanges(res.changes, addedClientChanges);
|
|
@@ -5202,11 +5245,17 @@ function _sync(db, options, schema, { isInitialSync, cancelToken, justCheckIfNee
|
|
|
5202
5245
|
//
|
|
5203
5246
|
// apply yMessages
|
|
5204
5247
|
//
|
|
5205
|
-
const receivedUntils = yield applyYServerMessages(res.yMessages, db);
|
|
5248
|
+
const { receivedUntils, resyncNeeded, yServerRevision } = yield applyYServerMessages(res.yMessages, db);
|
|
5249
|
+
if (yServerRevision) {
|
|
5250
|
+
newSyncState.yServerRevision = yServerRevision;
|
|
5251
|
+
}
|
|
5206
5252
|
//
|
|
5207
5253
|
// update Y SyncStates
|
|
5208
5254
|
//
|
|
5209
|
-
yield updateYSyncStates(lastUpdateIds, receivedUntils, db
|
|
5255
|
+
yield updateYSyncStates(lastUpdateIds, receivedUntils, db);
|
|
5256
|
+
if (resyncNeeded) {
|
|
5257
|
+
newSyncState.yDownloadedRealms = {}; // Will trigger a full download of Y-documents below...
|
|
5258
|
+
}
|
|
5210
5259
|
}
|
|
5211
5260
|
//
|
|
5212
5261
|
// Update regular syncState
|
|
@@ -5340,8 +5389,8 @@ function MessagesFromServerConsumer(db) {
|
|
|
5340
5389
|
event.next(null);
|
|
5341
5390
|
}
|
|
5342
5391
|
function consumeQueue() {
|
|
5343
|
-
var _a, _b, _c, _d, _e, _f;
|
|
5344
5392
|
return __awaiter(this, void 0, void 0, function* () {
|
|
5393
|
+
var _a, _b, _c, _d, _e, _f;
|
|
5345
5394
|
while (queue.length > 0) {
|
|
5346
5395
|
const msg = queue.shift();
|
|
5347
5396
|
try {
|
|
@@ -5499,7 +5548,7 @@ function MessagesFromServerConsumer(db) {
|
|
|
5499
5548
|
};
|
|
5500
5549
|
}
|
|
5501
5550
|
|
|
5502
|
-
const wm$
|
|
5551
|
+
const wm$2 = new WeakMap();
|
|
5503
5552
|
const DEXIE_CLOUD_SCHEMA = {
|
|
5504
5553
|
members: '@id, [userId+realmId], [email+realmId], realmId',
|
|
5505
5554
|
roles: '[realmId+name]',
|
|
@@ -5513,7 +5562,7 @@ let static_counter = 0;
|
|
|
5513
5562
|
function DexieCloudDB(dx) {
|
|
5514
5563
|
if ('vip' in dx)
|
|
5515
5564
|
dx = dx['vip']; // Avoid race condition. Always map to a vipped dexie that don't block during db.on.ready().
|
|
5516
|
-
let db = wm$
|
|
5565
|
+
let db = wm$2.get(dx.cloud);
|
|
5517
5566
|
if (!db) {
|
|
5518
5567
|
const localSyncEvent = new Subject();
|
|
5519
5568
|
let syncStateChangedEvent = new BroadcastedAndLocalEvent(`syncstatechanged-${dx.name}`);
|
|
@@ -5601,7 +5650,7 @@ function DexieCloudDB(dx) {
|
|
|
5601
5650
|
Object.assign(db, helperMethods);
|
|
5602
5651
|
db.messageConsumer = MessagesFromServerConsumer(db);
|
|
5603
5652
|
db.messageProducer = new Subject();
|
|
5604
|
-
wm$
|
|
5653
|
+
wm$2.set(dx.cloud, db);
|
|
5605
5654
|
}
|
|
5606
5655
|
return db;
|
|
5607
5656
|
}
|
|
@@ -5612,10 +5661,10 @@ function nameFromKeyPath(keyPath) {
|
|
|
5612
5661
|
}
|
|
5613
5662
|
|
|
5614
5663
|
// Emulate true-private property db. Why? So it's not stored in DB.
|
|
5615
|
-
const wm = new WeakMap();
|
|
5664
|
+
const wm$1 = new WeakMap();
|
|
5616
5665
|
class AuthPersistedContext {
|
|
5617
5666
|
constructor(db, userLogin) {
|
|
5618
|
-
wm.set(this, db);
|
|
5667
|
+
wm$1.set(this, db);
|
|
5619
5668
|
Object.assign(this, userLogin);
|
|
5620
5669
|
}
|
|
5621
5670
|
static load(db, userId) {
|
|
@@ -5632,7 +5681,7 @@ class AuthPersistedContext {
|
|
|
5632
5681
|
}
|
|
5633
5682
|
save() {
|
|
5634
5683
|
return __awaiter(this, void 0, void 0, function* () {
|
|
5635
|
-
const db = wm.get(this);
|
|
5684
|
+
const db = wm$1.get(this);
|
|
5636
5685
|
db.table("$logins").put(this);
|
|
5637
5686
|
});
|
|
5638
5687
|
}
|
|
@@ -5656,8 +5705,8 @@ function logout(db) {
|
|
|
5656
5705
|
}
|
|
5657
5706
|
});
|
|
5658
5707
|
}
|
|
5659
|
-
function _logout(
|
|
5660
|
-
return __awaiter(this,
|
|
5708
|
+
function _logout(db_1) {
|
|
5709
|
+
return __awaiter(this, arguments, void 0, function* (db, { deleteUnsyncedData = false } = {}) {
|
|
5661
5710
|
// Clear the database without emptying configuration options.
|
|
5662
5711
|
const [numUnsynced, loggedOut] = yield db.dx.transaction('rw', db.dx.tables, (tx) => __awaiter(this, void 0, void 0, function* () {
|
|
5663
5712
|
// @ts-ignore
|
|
@@ -5695,11 +5744,11 @@ function _logout(db, { deleteUnsyncedData = false } = {}) {
|
|
|
5695
5744
|
|
|
5696
5745
|
function otpFetchTokenCallback(db) {
|
|
5697
5746
|
const { userInteraction } = db.cloud;
|
|
5698
|
-
return function otpAuthenticate(
|
|
5699
|
-
|
|
5700
|
-
|
|
5747
|
+
return function otpAuthenticate(_a) {
|
|
5748
|
+
return __awaiter(this, arguments, void 0, function* ({ public_key, hints }) {
|
|
5749
|
+
var _b;
|
|
5701
5750
|
let tokenRequest;
|
|
5702
|
-
const url = (
|
|
5751
|
+
const url = (_b = db.cloud.options) === null || _b === void 0 ? void 0 : _b.databaseUrl;
|
|
5703
5752
|
if (!url)
|
|
5704
5753
|
throw new Error(`No database URL given.`);
|
|
5705
5754
|
if ((hints === null || hints === void 0 ? void 0 : hints.grant_type) === 'demo') {
|
|
@@ -5865,8 +5914,8 @@ function setCurrentUser(db, user) {
|
|
|
5865
5914
|
}
|
|
5866
5915
|
|
|
5867
5916
|
function login(db, hints) {
|
|
5868
|
-
var _a;
|
|
5869
5917
|
return __awaiter(this, void 0, void 0, function* () {
|
|
5918
|
+
var _a;
|
|
5870
5919
|
const currentUser = yield db.getCurrentUser();
|
|
5871
5920
|
const origUserId = currentUser.userId;
|
|
5872
5921
|
if (currentUser.isLoggedIn && (!hints || (!hints.email && !hints.userId))) {
|
|
@@ -6303,8 +6352,7 @@ function createMutationTrackingMiddleware({ currentUserObservable, db, }) {
|
|
|
6303
6352
|
outstandingTransactions.next(outstandingTransactions.value);
|
|
6304
6353
|
};
|
|
6305
6354
|
const txComplete = () => {
|
|
6306
|
-
if (tx.mutationsAdded &&
|
|
6307
|
-
!isEagerSyncDisabled(db)) {
|
|
6355
|
+
if (tx.mutationsAdded && !isEagerSyncDisabled(db)) {
|
|
6308
6356
|
triggerSync(db, 'push');
|
|
6309
6357
|
}
|
|
6310
6358
|
removeTransaction();
|
|
@@ -6386,26 +6434,107 @@ function createMutationTrackingMiddleware({ currentUserObservable, db, }) {
|
|
|
6386
6434
|
: mutateAndLog(req);
|
|
6387
6435
|
} }));
|
|
6388
6436
|
function mutateAndLog(req) {
|
|
6437
|
+
var _a, _b;
|
|
6389
6438
|
const trans = req.trans;
|
|
6390
|
-
|
|
6439
|
+
const unsyncedProps = (_b = (_a = db.cloud.options) === null || _a === void 0 ? void 0 : _a.unsyncedProperties) === null || _b === void 0 ? void 0 : _b[tableName];
|
|
6391
6440
|
const { txid, currentUser: { userId }, } = trans;
|
|
6392
6441
|
const { type } = req;
|
|
6393
6442
|
const opNo = ++trans.opCount;
|
|
6443
|
+
function stripChangeSpec(changeSpec) {
|
|
6444
|
+
if (!unsyncedProps)
|
|
6445
|
+
return changeSpec;
|
|
6446
|
+
let rv = changeSpec;
|
|
6447
|
+
for (const keyPath of Object.keys(changeSpec)) {
|
|
6448
|
+
if (unsyncedProps.some((p) => keyPath === p || keyPath.startsWith(p + '.'))) {
|
|
6449
|
+
if (rv === changeSpec)
|
|
6450
|
+
rv = Object.assign({}, changeSpec); // clone on demand
|
|
6451
|
+
delete rv[keyPath];
|
|
6452
|
+
}
|
|
6453
|
+
}
|
|
6454
|
+
return rv;
|
|
6455
|
+
}
|
|
6394
6456
|
return table.mutate(req).then((res) => {
|
|
6457
|
+
var _a;
|
|
6395
6458
|
const { numFailures: hasFailures, failures } = res;
|
|
6396
6459
|
let keys = type === 'delete' ? req.keys : res.results;
|
|
6397
6460
|
let values = 'values' in req ? req.values : [];
|
|
6398
|
-
let
|
|
6461
|
+
let changeSpec = 'changeSpec' in req ? req.changeSpec : undefined;
|
|
6462
|
+
let updates = 'updates' in req ? req.updates : undefined;
|
|
6399
6463
|
if (hasFailures) {
|
|
6400
6464
|
keys = keys.filter((_, idx) => !failures[idx]);
|
|
6401
6465
|
values = values.filter((_, idx) => !failures[idx]);
|
|
6402
6466
|
}
|
|
6467
|
+
if (unsyncedProps) {
|
|
6468
|
+
// Filter out unsynced properties
|
|
6469
|
+
values = values.map((value) => {
|
|
6470
|
+
const newValue = Object.assign({}, value);
|
|
6471
|
+
for (const prop of unsyncedProps) {
|
|
6472
|
+
delete newValue[prop];
|
|
6473
|
+
}
|
|
6474
|
+
return newValue;
|
|
6475
|
+
});
|
|
6476
|
+
if (changeSpec) {
|
|
6477
|
+
// modify operation with criteria and changeSpec.
|
|
6478
|
+
// We must strip out unsynced properties from changeSpec.
|
|
6479
|
+
// We deal with criteria later.
|
|
6480
|
+
changeSpec = stripChangeSpec(changeSpec);
|
|
6481
|
+
if (Object.keys(changeSpec).length === 0) {
|
|
6482
|
+
// Nothing to change on server
|
|
6483
|
+
return res;
|
|
6484
|
+
}
|
|
6485
|
+
}
|
|
6486
|
+
if (updates) {
|
|
6487
|
+
let strippedChangeSpecs = updates.changeSpecs.map(stripChangeSpec);
|
|
6488
|
+
let newUpdates = {
|
|
6489
|
+
keys: [],
|
|
6490
|
+
changeSpecs: [],
|
|
6491
|
+
};
|
|
6492
|
+
const validKeys = new RangeSet();
|
|
6493
|
+
let anyChangeSpecBecameEmpty = false;
|
|
6494
|
+
for (let i = 0, l = strippedChangeSpecs.length; i < l; ++i) {
|
|
6495
|
+
if (Object.keys(strippedChangeSpecs[i]).length > 0) {
|
|
6496
|
+
newUpdates.keys.push(updates.keys[i]);
|
|
6497
|
+
newUpdates.changeSpecs.push(strippedChangeSpecs[i]);
|
|
6498
|
+
validKeys.addKey(updates.keys[i]);
|
|
6499
|
+
}
|
|
6500
|
+
else {
|
|
6501
|
+
anyChangeSpecBecameEmpty = true;
|
|
6502
|
+
}
|
|
6503
|
+
}
|
|
6504
|
+
updates = newUpdates;
|
|
6505
|
+
if (anyChangeSpecBecameEmpty) {
|
|
6506
|
+
// Some keys were stripped. We must also strip them from keys and values
|
|
6507
|
+
let newKeys = [];
|
|
6508
|
+
let newValues = [];
|
|
6509
|
+
for (let i = 0, l = keys.length; i < l; ++i) {
|
|
6510
|
+
if (validKeys.hasKey(keys[i])) {
|
|
6511
|
+
newKeys.push(keys[i]);
|
|
6512
|
+
newValues.push(values[i]);
|
|
6513
|
+
}
|
|
6514
|
+
}
|
|
6515
|
+
keys = newKeys;
|
|
6516
|
+
values = newValues;
|
|
6517
|
+
}
|
|
6518
|
+
}
|
|
6519
|
+
}
|
|
6403
6520
|
const ts = Date.now();
|
|
6404
6521
|
// Canonicalize req.criteria.index to null if it's on the primary key.
|
|
6405
|
-
|
|
6522
|
+
let criteria = 'criteria' in req && req.criteria
|
|
6406
6523
|
? Object.assign(Object.assign({}, req.criteria), { index: req.criteria.index === schema.primaryKey.keyPath // Use null to inform server that criteria is on primary key
|
|
6407
6524
|
? null // This will disable the server from trying to log consistent operations where it shouldnt.
|
|
6408
6525
|
: req.criteria.index }) : undefined;
|
|
6526
|
+
if (unsyncedProps && (criteria === null || criteria === void 0 ? void 0 : criteria.index)) {
|
|
6527
|
+
const keyPaths = (_a = schema.indexes.find((idx) => idx.name === criteria.index)) === null || _a === void 0 ? void 0 : _a.keyPath;
|
|
6528
|
+
const involvedProps = keyPaths
|
|
6529
|
+
? typeof keyPaths === 'string'
|
|
6530
|
+
? [keyPaths]
|
|
6531
|
+
: keyPaths
|
|
6532
|
+
: [];
|
|
6533
|
+
if (involvedProps.some((p) => unsyncedProps === null || unsyncedProps === void 0 ? void 0 : unsyncedProps.includes(p))) {
|
|
6534
|
+
// Don't log criteria on unsynced properties as the server could not test them.
|
|
6535
|
+
criteria = undefined;
|
|
6536
|
+
}
|
|
6537
|
+
}
|
|
6409
6538
|
const mut = req.type === 'delete'
|
|
6410
6539
|
? {
|
|
6411
6540
|
type: 'delete',
|
|
@@ -6426,7 +6555,7 @@ function createMutationTrackingMiddleware({ currentUserObservable, db, }) {
|
|
|
6426
6555
|
userId,
|
|
6427
6556
|
values,
|
|
6428
6557
|
}
|
|
6429
|
-
: criteria &&
|
|
6558
|
+
: criteria && changeSpec
|
|
6430
6559
|
? {
|
|
6431
6560
|
// Common changeSpec for all keys
|
|
6432
6561
|
type: 'modify',
|
|
@@ -6434,37 +6563,51 @@ function createMutationTrackingMiddleware({ currentUserObservable, db, }) {
|
|
|
6434
6563
|
opNo,
|
|
6435
6564
|
keys,
|
|
6436
6565
|
criteria,
|
|
6437
|
-
changeSpec
|
|
6566
|
+
changeSpec,
|
|
6438
6567
|
txid,
|
|
6439
6568
|
userId,
|
|
6440
6569
|
}
|
|
6441
|
-
:
|
|
6570
|
+
: changeSpec
|
|
6442
6571
|
? {
|
|
6443
|
-
//
|
|
6572
|
+
// In case criteria involved an unsynced property, we go for keys instead.
|
|
6444
6573
|
type: 'update',
|
|
6445
6574
|
ts,
|
|
6446
6575
|
opNo,
|
|
6447
|
-
keys: updates.keys,
|
|
6448
|
-
changeSpecs: updates.changeSpecs,
|
|
6449
|
-
txid,
|
|
6450
|
-
userId,
|
|
6451
|
-
}
|
|
6452
|
-
: {
|
|
6453
|
-
type: 'upsert',
|
|
6454
|
-
ts,
|
|
6455
|
-
opNo,
|
|
6456
6576
|
keys,
|
|
6457
|
-
|
|
6577
|
+
changeSpecs: keys.map(() => changeSpec),
|
|
6458
6578
|
txid,
|
|
6459
6579
|
userId,
|
|
6460
|
-
}
|
|
6580
|
+
}
|
|
6581
|
+
: updates
|
|
6582
|
+
? {
|
|
6583
|
+
// One changeSpec per key
|
|
6584
|
+
type: 'update',
|
|
6585
|
+
ts,
|
|
6586
|
+
opNo,
|
|
6587
|
+
keys: updates.keys,
|
|
6588
|
+
changeSpecs: updates.changeSpecs,
|
|
6589
|
+
txid,
|
|
6590
|
+
userId,
|
|
6591
|
+
}
|
|
6592
|
+
: {
|
|
6593
|
+
type: 'upsert',
|
|
6594
|
+
ts,
|
|
6595
|
+
opNo,
|
|
6596
|
+
keys,
|
|
6597
|
+
values,
|
|
6598
|
+
txid,
|
|
6599
|
+
userId,
|
|
6600
|
+
};
|
|
6461
6601
|
if ('isAdditionalChunk' in req && req.isAdditionalChunk) {
|
|
6462
6602
|
mut.isAdditionalChunk = true;
|
|
6463
6603
|
}
|
|
6464
6604
|
return keys.length > 0 || criteria
|
|
6465
6605
|
? mutsTable
|
|
6466
6606
|
.mutate({ type: 'add', trans, values: [mut] }) // Log entry
|
|
6467
|
-
.then(() =>
|
|
6607
|
+
.then(() => {
|
|
6608
|
+
trans.mutationsAdded = true; // Mark transaction as having added mutations to trigger eager sync
|
|
6609
|
+
return res; // Return original response
|
|
6610
|
+
})
|
|
6468
6611
|
: res;
|
|
6469
6612
|
});
|
|
6470
6613
|
}
|
|
@@ -6548,10 +6691,18 @@ function overrideParseStoresSpec(origFunc, dexie) {
|
|
|
6548
6691
|
};
|
|
6549
6692
|
}
|
|
6550
6693
|
|
|
6694
|
+
function performGuardedJob(db, jobName, job) {
|
|
6695
|
+
if (typeof navigator === 'undefined' || !navigator.locks) {
|
|
6696
|
+
// No support for guarding jobs. IE11, node.js, etc.
|
|
6697
|
+
return job();
|
|
6698
|
+
}
|
|
6699
|
+
return navigator.locks.request(db.name + '|' + jobName, () => job());
|
|
6700
|
+
}
|
|
6701
|
+
|
|
6551
6702
|
function performInitialSync(db, cloudOptions, cloudSchema) {
|
|
6552
6703
|
return __awaiter(this, void 0, void 0, function* () {
|
|
6553
6704
|
console.debug('Performing initial sync');
|
|
6554
|
-
yield sync(db, cloudOptions, cloudSchema, { isInitialSync: true });
|
|
6705
|
+
yield performGuardedJob(db, CURRENT_SYNC_WORKER, () => sync(db, cloudOptions, cloudSchema, { isInitialSync: true }));
|
|
6555
6706
|
console.debug('Done initial sync');
|
|
6556
6707
|
});
|
|
6557
6708
|
}
|
|
@@ -6638,29 +6789,35 @@ function createYClientUpdateObservable(db) {
|
|
|
6638
6789
|
updatesTable: p.updatesTable,
|
|
6639
6790
|
}))));
|
|
6640
6791
|
return merge(...yTableRecords.map(({ table, ydocProp, updatesTable }) => {
|
|
6641
|
-
|
|
6642
|
-
|
|
6643
|
-
|
|
6644
|
-
|
|
6645
|
-
|
|
6646
|
-
|
|
6647
|
-
|
|
6648
|
-
|
|
6649
|
-
|
|
6650
|
-
|
|
6651
|
-
|
|
6652
|
-
|
|
6653
|
-
|
|
6654
|
-
|
|
6655
|
-
|
|
6656
|
-
|
|
6657
|
-
|
|
6658
|
-
|
|
6659
|
-
|
|
6660
|
-
|
|
6661
|
-
|
|
6662
|
-
|
|
6663
|
-
|
|
6792
|
+
// Per updates table (table+prop combo), we first read syncer.unsentFrom,
|
|
6793
|
+
// and then start listening for updates since that number.
|
|
6794
|
+
const yTbl = db.table(updatesTable);
|
|
6795
|
+
return from$1(yTbl.get(DEXIE_CLOUD_SYNCER_ID)).pipe(switchMap$1((syncer) => {
|
|
6796
|
+
let currentUnsentFrom = (syncer === null || syncer === void 0 ? void 0 : syncer.unsentFrom) || 1;
|
|
6797
|
+
return from$1(liveQuery(() => __awaiter(this, void 0, void 0, function* () {
|
|
6798
|
+
const addedUpdates = yield listUpdatesSince(yTbl, currentUnsentFrom);
|
|
6799
|
+
return addedUpdates
|
|
6800
|
+
.filter((update) => update.f && update.f & 1) // Only include local updates
|
|
6801
|
+
.map((update) => {
|
|
6802
|
+
return {
|
|
6803
|
+
type: 'u-c',
|
|
6804
|
+
table,
|
|
6805
|
+
prop: ydocProp,
|
|
6806
|
+
k: update.k,
|
|
6807
|
+
u: update.u,
|
|
6808
|
+
i: update.i,
|
|
6809
|
+
};
|
|
6810
|
+
});
|
|
6811
|
+
}))).pipe(tap$1((addedUpdates) => {
|
|
6812
|
+
// Update currentUnsentFrom to only listen for updates that will be newer than the ones we emitted.
|
|
6813
|
+
// (Before, we did this within the liveQuery, but that caused a bug because
|
|
6814
|
+
// a cancelled emittion of a liveQuery would update the currentUnsentFrom without
|
|
6815
|
+
// emitting anything, leading to that we jumped over some updates. Here we update it
|
|
6816
|
+
// after the liveQuery has emitted its updates)
|
|
6817
|
+
if (addedUpdates.length > 0) {
|
|
6818
|
+
currentUnsentFrom = addedUpdates.at(-1).i + 1;
|
|
6819
|
+
}
|
|
6820
|
+
}));
|
|
6664
6821
|
}));
|
|
6665
6822
|
})).pipe(
|
|
6666
6823
|
// Flatten the array of messages.
|
|
@@ -6680,6 +6837,23 @@ function getAwarenessLibrary(db) {
|
|
|
6680
6837
|
const awarenessWeakMap = new WeakMap();
|
|
6681
6838
|
const getDocAwareness = (doc) => awarenessWeakMap.get(doc);
|
|
6682
6839
|
|
|
6840
|
+
const wm = new WeakMap();
|
|
6841
|
+
/** A property (package-private) on Y.Doc that is used
|
|
6842
|
+
* to signal that the server wants us to send a 'doc-open' message
|
|
6843
|
+
* to the server for this document.
|
|
6844
|
+
*
|
|
6845
|
+
* @param doc
|
|
6846
|
+
* @returns
|
|
6847
|
+
*/
|
|
6848
|
+
function getOpenDocSignal(doc) {
|
|
6849
|
+
let signal = wm.get(doc);
|
|
6850
|
+
if (!signal) {
|
|
6851
|
+
signal = new Subject();
|
|
6852
|
+
wm.set(doc, signal);
|
|
6853
|
+
}
|
|
6854
|
+
return signal;
|
|
6855
|
+
}
|
|
6856
|
+
|
|
6683
6857
|
const SERVER_PING_TIMEOUT = 20000;
|
|
6684
6858
|
const CLIENT_PING_INTERVAL = 30000;
|
|
6685
6859
|
const FAIL_RETRY_WAIT_TIME = 60000;
|
|
@@ -6842,9 +7016,6 @@ class WSConnection extends Subscription$1 {
|
|
|
6842
7016
|
if (msg.type === 'error') {
|
|
6843
7017
|
throw new Error(`Error message from dexie-cloud: ${msg.error}`);
|
|
6844
7018
|
}
|
|
6845
|
-
else if (msg.type === 'rev') {
|
|
6846
|
-
this.rev = msg.rev; // No meaning but seems reasonable.
|
|
6847
|
-
}
|
|
6848
7019
|
else if (msg.type === 'aware') {
|
|
6849
7020
|
const docCache = DexieYProvider.getDocCache(this.db.dx);
|
|
6850
7021
|
const doc = docCache.find(msg.table, msg.k, msg.prop);
|
|
@@ -6859,7 +7030,19 @@ class WSConnection extends Subscription$1 {
|
|
|
6859
7030
|
else if (msg.type === 'u-ack' || msg.type === 'u-reject' || msg.type === 'u-s' || msg.type === 'in-sync') {
|
|
6860
7031
|
applyYServerMessages([msg], this.db);
|
|
6861
7032
|
}
|
|
7033
|
+
else if (msg.type === 'doc-open') {
|
|
7034
|
+
const docCache = DexieYProvider.getDocCache(this.db.dx);
|
|
7035
|
+
const doc = docCache.find(msg.table, msg.k, msg.prop);
|
|
7036
|
+
if (doc) {
|
|
7037
|
+
getOpenDocSignal(doc).next(); // Make yHandler reopen the document on server.
|
|
7038
|
+
}
|
|
7039
|
+
}
|
|
7040
|
+
else if (msg.type === 'outdated-server-rev' || msg.type === 'y-complete-sync-done') {
|
|
7041
|
+
// Won't happen but need this for typing.
|
|
7042
|
+
throw new Error('Outdated server revision or y-complete-sync-done not expected over WebSocket - only in sync using fetch()');
|
|
7043
|
+
}
|
|
6862
7044
|
else if (msg.type !== 'pong') {
|
|
7045
|
+
// Forward the request to our subscriber, wich is in messageFromServerQueue.ts (via connectWebSocket's subscribe() at the end!)
|
|
6863
7046
|
this.subscriber.next(msg);
|
|
6864
7047
|
}
|
|
6865
7048
|
}
|
|
@@ -6896,6 +7079,10 @@ class WSConnection extends Subscription$1 {
|
|
|
6896
7079
|
}
|
|
6897
7080
|
console.debug('dexie-cloud WebSocket send', msg.type, msg);
|
|
6898
7081
|
if (msg.type === 'ready') {
|
|
7082
|
+
// Ok, we are certain to have stored everything up until revision msg.rev.
|
|
7083
|
+
// Update this.rev in case of reconnect - remember where we were and don't just start over!
|
|
7084
|
+
this.rev = msg.rev;
|
|
7085
|
+
// ... and then send along the request to the server so it would also be updated!
|
|
6899
7086
|
(_a = this.ws) === null || _a === void 0 ? void 0 : _a.send(TSON.stringify(msg));
|
|
6900
7087
|
}
|
|
6901
7088
|
else {
|
|
@@ -6977,7 +7164,7 @@ function connectWebSocket(db) {
|
|
|
6977
7164
|
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]));
|
|
6978
7165
|
}
|
|
6979
7166
|
return new BehaviorSubject([userLogin, syncState]);
|
|
6980
|
-
}), switchMap((
|
|
7167
|
+
}), 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]) => {
|
|
6981
7168
|
var _a;
|
|
6982
7169
|
if (!((_a = db.cloud.persistedSyncState) === null || _a === void 0 ? void 0 : _a.value)) {
|
|
6983
7170
|
// Restart the flow if persistedSyncState is not yet available.
|
|
@@ -7038,22 +7225,14 @@ function connectWebSocket(db) {
|
|
|
7038
7225
|
}
|
|
7039
7226
|
|
|
7040
7227
|
function isSyncNeeded(db) {
|
|
7041
|
-
var _a;
|
|
7042
7228
|
return __awaiter(this, void 0, void 0, function* () {
|
|
7229
|
+
var _a;
|
|
7043
7230
|
return ((_a = db.cloud.options) === null || _a === void 0 ? void 0 : _a.databaseUrl) && db.cloud.schema
|
|
7044
7231
|
? yield sync(db, db.cloud.options, db.cloud.schema, { justCheckIfNeeded: true })
|
|
7045
7232
|
: false;
|
|
7046
7233
|
});
|
|
7047
7234
|
}
|
|
7048
7235
|
|
|
7049
|
-
function performGuardedJob(db, jobName, job) {
|
|
7050
|
-
if (typeof navigator === 'undefined' || !navigator.locks) {
|
|
7051
|
-
// No support for guarding jobs. IE11, node.js, etc.
|
|
7052
|
-
return job();
|
|
7053
|
-
}
|
|
7054
|
-
return navigator.locks.request(db.name + '|' + jobName, () => job());
|
|
7055
|
-
}
|
|
7056
|
-
|
|
7057
7236
|
const ongoingSyncs = new WeakMap();
|
|
7058
7237
|
function syncIfPossible(db, cloudOptions, cloudSchema, options) {
|
|
7059
7238
|
const ongoing = ongoingSyncs.get(db);
|
|
@@ -7107,20 +7286,7 @@ function syncIfPossible(db, cloudOptions, cloudSchema, options) {
|
|
|
7107
7286
|
try {
|
|
7108
7287
|
// Check if should delay sync due to ratelimit:
|
|
7109
7288
|
yield checkSyncRateLimitDelay(db);
|
|
7110
|
-
|
|
7111
|
-
if (db.cloud.isServiceWorkerDB) {
|
|
7112
|
-
// We are the dedicated sync SW:
|
|
7113
|
-
yield sync(db, cloudOptions, cloudSchema, options);
|
|
7114
|
-
}
|
|
7115
|
-
else if (!db.cloud.usingServiceWorker) {
|
|
7116
|
-
// We use a flow that is better suited for the case when multiple workers want to
|
|
7117
|
-
// do the same thing.
|
|
7118
|
-
yield performGuardedJob(db, CURRENT_SYNC_WORKER, () => sync(db, cloudOptions, cloudSchema, options));
|
|
7119
|
-
}
|
|
7120
|
-
else {
|
|
7121
|
-
assert(false);
|
|
7122
|
-
throw new Error('Internal _syncIfPossible() - invalid precondition - should not have been called.');
|
|
7123
|
-
}
|
|
7289
|
+
yield performGuardedJob(db, CURRENT_SYNC_WORKER, () => sync(db, cloudOptions, cloudSchema, options));
|
|
7124
7290
|
ongoingSyncs.delete(db);
|
|
7125
7291
|
console.debug('Done sync');
|
|
7126
7292
|
}
|
|
@@ -7723,6 +7889,7 @@ class PermissionChecker {
|
|
|
7723
7889
|
// If user can update any prop in any table in this realm, return true unless
|
|
7724
7890
|
// it regards to ownership change:
|
|
7725
7891
|
if (this.permissions.update === '*') {
|
|
7892
|
+
// @ts-ignore
|
|
7726
7893
|
return props.every((prop) => prop !== 'owner');
|
|
7727
7894
|
}
|
|
7728
7895
|
const tablePermissions = (_b = this.permissions.update) === null || _b === void 0 ? void 0 : _b[this.tableName];
|
|
@@ -7796,125 +7963,151 @@ const getInvitesObservable = associate((db) => {
|
|
|
7796
7963
|
function createYHandler(db) {
|
|
7797
7964
|
return (provider) => {
|
|
7798
7965
|
var _a;
|
|
7799
|
-
const awap = getAwarenessLibrary(db);
|
|
7800
7966
|
const doc = provider.doc;
|
|
7801
|
-
const { parentTable
|
|
7967
|
+
const { parentTable } = doc.meta || {};
|
|
7802
7968
|
if (!((_a = db.cloud.schema) === null || _a === void 0 ? void 0 : _a[parentTable].markedForSync)) {
|
|
7803
7969
|
return; // The table that holds the doc is not marked for sync - leave it to dexie. No syncing, no awareness.
|
|
7804
7970
|
}
|
|
7805
|
-
let awareness
|
|
7806
|
-
|
|
7807
|
-
|
|
7808
|
-
|
|
7809
|
-
|
|
7810
|
-
|
|
7811
|
-
|
|
7812
|
-
|
|
7813
|
-
|
|
7971
|
+
let awareness;
|
|
7972
|
+
Object.defineProperty(provider, 'awareness', {
|
|
7973
|
+
get() {
|
|
7974
|
+
if (awareness)
|
|
7975
|
+
return awareness;
|
|
7976
|
+
awareness = createAwareness(db, doc, provider);
|
|
7977
|
+
awarenessWeakMap.set(doc, awareness);
|
|
7978
|
+
return awareness;
|
|
7979
|
+
},
|
|
7980
|
+
});
|
|
7981
|
+
};
|
|
7982
|
+
}
|
|
7983
|
+
function createAwareness(db, doc, provider) {
|
|
7984
|
+
const { parentTable, parentId, parentProp, updatesTable } = doc.meta;
|
|
7985
|
+
const awap = getAwarenessLibrary(db);
|
|
7986
|
+
const awareness = new awap.Awareness(doc);
|
|
7987
|
+
const reopenDocSignal = getOpenDocSignal(doc);
|
|
7988
|
+
awareness.on('update', ({ added, updated, removed }, origin) => {
|
|
7989
|
+
// Send the update
|
|
7990
|
+
const changedClients = added.concat(updated).concat(removed);
|
|
7991
|
+
const user = db.cloud.currentUser.value;
|
|
7992
|
+
if (origin !== 'server' && user.isLoggedIn && !isEagerSyncDisabled(db)) {
|
|
7993
|
+
const update = awap.encodeAwarenessUpdate(awareness, changedClients);
|
|
7994
|
+
db.messageProducer.next({
|
|
7995
|
+
type: 'aware',
|
|
7996
|
+
table: parentTable,
|
|
7997
|
+
prop: parentProp,
|
|
7998
|
+
k: doc.meta.parentId,
|
|
7999
|
+
u: update,
|
|
8000
|
+
});
|
|
8001
|
+
if (provider.destroyed) {
|
|
8002
|
+
// We're called from awareness.on('destroy') that did
|
|
8003
|
+
// removeAwarenessStates.
|
|
8004
|
+
// It's time to also send the doc-close message that dexie-cloud understands
|
|
8005
|
+
// and uses to stop subscribing for updates and awareness updates and brings
|
|
8006
|
+
// down the cached information in memory on the WS connection for this.
|
|
7814
8007
|
db.messageProducer.next({
|
|
7815
|
-
type: '
|
|
8008
|
+
type: 'doc-close',
|
|
7816
8009
|
table: parentTable,
|
|
7817
8010
|
prop: parentProp,
|
|
7818
8011
|
k: doc.meta.parentId,
|
|
7819
|
-
u: update,
|
|
7820
8012
|
});
|
|
7821
|
-
if (provider.destroyed) {
|
|
7822
|
-
// We're called from awareness.on('destroy') that did
|
|
7823
|
-
// removeAwarenessStates.
|
|
7824
|
-
// It's time to also send the doc-close message that dexie-cloud understands
|
|
7825
|
-
// and uses to stop subscribing for updates and awareness updates and brings
|
|
7826
|
-
// down the cached information in memory on the WS connection for this.
|
|
7827
|
-
db.messageProducer.next({
|
|
7828
|
-
type: 'doc-close',
|
|
7829
|
-
table: parentTable,
|
|
7830
|
-
prop: parentProp,
|
|
7831
|
-
k: doc.meta.parentId
|
|
7832
|
-
});
|
|
7833
|
-
}
|
|
7834
8013
|
}
|
|
7835
|
-
}
|
|
7836
|
-
|
|
7837
|
-
|
|
7838
|
-
|
|
7839
|
-
|
|
7840
|
-
|
|
7841
|
-
|
|
7842
|
-
|
|
8014
|
+
}
|
|
8015
|
+
});
|
|
8016
|
+
awareness.on('destroy', () => {
|
|
8017
|
+
// Signal to server that this provider is destroyed (the update event will be triggered, which
|
|
8018
|
+
// in turn will trigger db.messageProducer that will send the message to the server if WS is connected)
|
|
8019
|
+
awap.removeAwarenessStates(awareness, [doc.clientID], 'provider destroyed');
|
|
8020
|
+
});
|
|
8021
|
+
// Open the document on the server
|
|
8022
|
+
(() => __awaiter(this, void 0, void 0, function* () {
|
|
8023
|
+
if (provider.destroyed)
|
|
8024
|
+
return;
|
|
8025
|
+
let connected = false;
|
|
8026
|
+
let currentFlowId = 1;
|
|
8027
|
+
const subscription = combineLatest([
|
|
8028
|
+
db.cloud.webSocketStatus, // Wake up when webSocket status changes
|
|
8029
|
+
reopenDocSignal.pipe(startWith$1(null)), // Wake up when reopenDocSignal emits
|
|
8030
|
+
]).subscribe(([wsStatus]) => {
|
|
7843
8031
|
if (provider.destroyed)
|
|
7844
8032
|
return;
|
|
7845
|
-
|
|
7846
|
-
|
|
7847
|
-
|
|
7848
|
-
|
|
8033
|
+
// Keep "connected" state in a variable so we can check it after async operations
|
|
8034
|
+
connected = wsStatus === 'connected';
|
|
8035
|
+
// We are or got connected. Open the document on the server.
|
|
8036
|
+
const user = db.cloud.currentUser.value;
|
|
8037
|
+
if (wsStatus === 'connected' &&
|
|
8038
|
+
user.isLoggedIn &&
|
|
8039
|
+
!isEagerSyncDisabled(db)) {
|
|
8040
|
+
++currentFlowId;
|
|
8041
|
+
openDocumentOnServer().catch((error) => {
|
|
8042
|
+
console.warn(`Error catched in createYHandler.ts: ${error}`);
|
|
8043
|
+
});
|
|
8044
|
+
}
|
|
8045
|
+
});
|
|
8046
|
+
// Wait until WebSocket is connected
|
|
8047
|
+
provider.addCleanupHandler(subscription);
|
|
8048
|
+
/** Sends an 'doc-open' message to server whenever websocket becomes
|
|
8049
|
+
* connected, or if it is already connected.
|
|
8050
|
+
* The flow is aborted in case websocket is disconnected while querying
|
|
8051
|
+
* information required to compute the state vector. Flow is also
|
|
8052
|
+
* aborted in case document or provider has been destroyed during
|
|
8053
|
+
* the async parts of the task.
|
|
8054
|
+
*
|
|
8055
|
+
* The state vector is only computed from the updates that have occured
|
|
8056
|
+
* after the last full sync - which could very often be zero - in which
|
|
8057
|
+
* case no state vector is sent (then the server already knows us by
|
|
8058
|
+
* revision)
|
|
8059
|
+
*
|
|
8060
|
+
* When server gets the doc-open message, it will authorize us for
|
|
8061
|
+
* whether we are allowed to read / write to this document, and then
|
|
8062
|
+
* keep the cached information in memory on the WS connection for this
|
|
8063
|
+
* particular document, as well as subscribe to updates and awareness updates
|
|
8064
|
+
* from other clients on the document.
|
|
8065
|
+
*/
|
|
8066
|
+
function openDocumentOnServer() {
|
|
8067
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
8068
|
+
const myFlow = currentFlowId; // So we can abort when a new flow is started
|
|
8069
|
+
const yTbl = db.table(updatesTable);
|
|
8070
|
+
const syncStateTbl = db.$syncState;
|
|
8071
|
+
const [receivedUntil, yServerRev] = yield db.transaction('r', syncStateTbl, yTbl, () => __awaiter(this, void 0, void 0, function* () {
|
|
8072
|
+
const syncState = yield yTbl.get(DEXIE_CLOUD_SYNCER_ID);
|
|
8073
|
+
const persistedSyncState = yield syncStateTbl.get('syncState');
|
|
8074
|
+
return [
|
|
8075
|
+
(syncState === null || syncState === void 0 ? void 0 : syncState.receivedUntil) || 0,
|
|
8076
|
+
(persistedSyncState === null || persistedSyncState === void 0 ? void 0 : persistedSyncState.yServerRevision) ||
|
|
8077
|
+
(persistedSyncState === null || persistedSyncState === void 0 ? void 0 : persistedSyncState.serverRevision),
|
|
8078
|
+
];
|
|
8079
|
+
}));
|
|
8080
|
+
// After every await, check if we still should be working on this task.
|
|
8081
|
+
if (provider.destroyed || currentFlowId !== myFlow || !connected)
|
|
7849
8082
|
return;
|
|
7850
|
-
|
|
7851
|
-
|
|
7852
|
-
|
|
7853
|
-
|
|
7854
|
-
|
|
7855
|
-
|
|
7856
|
-
|
|
7857
|
-
|
|
7858
|
-
|
|
8083
|
+
const docOpenMsg = {
|
|
8084
|
+
type: 'doc-open',
|
|
8085
|
+
table: parentTable,
|
|
8086
|
+
prop: parentProp,
|
|
8087
|
+
k: parentId,
|
|
8088
|
+
serverRev: yServerRev,
|
|
8089
|
+
};
|
|
8090
|
+
const serverUpdatesSinceLastSync = yield yTbl
|
|
8091
|
+
.where('i')
|
|
8092
|
+
.between(receivedUntil, Infinity, false)
|
|
8093
|
+
.filter((update) => cmp(update.k, parentId) === 0 && // Only updates for this document
|
|
8094
|
+
((update.f || 0) & 1) === 0 // Don't include local changes
|
|
8095
|
+
)
|
|
8096
|
+
.toArray();
|
|
8097
|
+
// After every await, check if we still should be working on this task.
|
|
8098
|
+
if (provider.destroyed || currentFlowId !== myFlow || !connected)
|
|
8099
|
+
return;
|
|
8100
|
+
if (serverUpdatesSinceLastSync.length > 0) {
|
|
8101
|
+
const Y = $Y(db); // Get the Yjs library from Dexie constructor options
|
|
8102
|
+
const mergedUpdate = Y.mergeUpdatesV2(serverUpdatesSinceLastSync.map((update) => update.u));
|
|
8103
|
+
const stateVector = Y.encodeStateVectorFromUpdateV2(mergedUpdate);
|
|
8104
|
+
docOpenMsg.sv = stateVector;
|
|
7859
8105
|
}
|
|
8106
|
+
db.messageProducer.next(docOpenMsg);
|
|
7860
8107
|
});
|
|
7861
|
-
|
|
7862
|
-
|
|
7863
|
-
|
|
7864
|
-
* connected, or if it is already connected.
|
|
7865
|
-
* The flow is aborted in case websocket is disconnected while querying
|
|
7866
|
-
* information required to compute the state vector. Flow is also
|
|
7867
|
-
* aborted in case document or provider has been destroyed during
|
|
7868
|
-
* the async parts of the task.
|
|
7869
|
-
*
|
|
7870
|
-
* The state vector is only computed from the updates that have occured
|
|
7871
|
-
* after the last full sync - which could very often be zero - in which
|
|
7872
|
-
* case no state vector is sent (then the server already knows us by
|
|
7873
|
-
* revision)
|
|
7874
|
-
*
|
|
7875
|
-
* When server gets the doc-open message, it will authorized us for
|
|
7876
|
-
* whether we are allowed to read / write to this document, and then
|
|
7877
|
-
* keep the cached information in memory on the WS connection for this
|
|
7878
|
-
* particular document, as well as subscribe to updates and awareness updates
|
|
7879
|
-
* from other clients on the document.
|
|
7880
|
-
*/
|
|
7881
|
-
function openDocumentOnServer(wsStatus) {
|
|
7882
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
7883
|
-
const myFlow = currentFlowId; // So we can abort when a new flow is started
|
|
7884
|
-
const yTbl = db.table(updatesTable);
|
|
7885
|
-
const syncState = yield yTbl.get(DEXIE_CLOUD_SYNCER_ID);
|
|
7886
|
-
// After every await, check if we still should be working on this task.
|
|
7887
|
-
if (provider.destroyed || currentFlowId !== myFlow || !connected)
|
|
7888
|
-
return;
|
|
7889
|
-
const receivedUntil = (syncState === null || syncState === void 0 ? void 0 : syncState.receivedUntil) || 0;
|
|
7890
|
-
const docOpenMsg = {
|
|
7891
|
-
type: 'doc-open',
|
|
7892
|
-
table: parentTable,
|
|
7893
|
-
prop: parentProp,
|
|
7894
|
-
k: parentId,
|
|
7895
|
-
serverRev: syncState === null || syncState === void 0 ? void 0 : syncState.serverRev,
|
|
7896
|
-
};
|
|
7897
|
-
const serverUpdatesSinceLastSync = yield yTbl
|
|
7898
|
-
.where('i')
|
|
7899
|
-
.between(receivedUntil, Infinity, false)
|
|
7900
|
-
.filter((update) => cmp(update.k, parentId) === 0 && // Only updates for this document
|
|
7901
|
-
((update.f || 0) & 1) === 0 // Don't include local changes
|
|
7902
|
-
)
|
|
7903
|
-
.toArray();
|
|
7904
|
-
// After every await, check if we still should be working on this task.
|
|
7905
|
-
if (provider.destroyed || currentFlowId !== myFlow || !connected)
|
|
7906
|
-
return;
|
|
7907
|
-
if (serverUpdatesSinceLastSync.length > 0) {
|
|
7908
|
-
const Y = $Y(db); // Get the Yjs library from Dexie constructor options
|
|
7909
|
-
const mergedUpdate = Y.mergeUpdatesV2(serverUpdatesSinceLastSync.map((update) => update.u));
|
|
7910
|
-
const stateVector = Y.encodeStateVectorFromUpdateV2(mergedUpdate);
|
|
7911
|
-
docOpenMsg.sv = stateVector;
|
|
7912
|
-
}
|
|
7913
|
-
db.messageProducer.next(docOpenMsg);
|
|
7914
|
-
});
|
|
7915
|
-
}
|
|
7916
|
-
}));
|
|
7917
|
-
};
|
|
8108
|
+
}
|
|
8109
|
+
}))();
|
|
8110
|
+
return awareness;
|
|
7918
8111
|
}
|
|
7919
8112
|
|
|
7920
8113
|
const DEFAULT_OPTIONS = {
|
|
@@ -7957,7 +8150,7 @@ function dexieCloud(dexie) {
|
|
|
7957
8150
|
const syncComplete = new Subject();
|
|
7958
8151
|
dexie.cloud = {
|
|
7959
8152
|
// @ts-ignore
|
|
7960
|
-
version: "4.1.0-
|
|
8153
|
+
version: "4.1.0-beta.25",
|
|
7961
8154
|
options: Object.assign({}, DEFAULT_OPTIONS),
|
|
7962
8155
|
schema: null,
|
|
7963
8156
|
get currentUserId() {
|
|
@@ -7993,16 +8186,16 @@ function dexieCloud(dexie) {
|
|
|
7993
8186
|
}
|
|
7994
8187
|
updateSchemaFromOptions(dexie.cloud.schema, dexie.cloud.options);
|
|
7995
8188
|
},
|
|
7996
|
-
logout(
|
|
7997
|
-
return __awaiter(this,
|
|
8189
|
+
logout() {
|
|
8190
|
+
return __awaiter(this, arguments, void 0, function* ({ force } = {}) {
|
|
7998
8191
|
force
|
|
7999
8192
|
? yield _logout(DexieCloudDB(dexie), { deleteUnsyncedData: true })
|
|
8000
8193
|
: yield logout(DexieCloudDB(dexie));
|
|
8001
8194
|
});
|
|
8002
8195
|
},
|
|
8003
|
-
sync(
|
|
8004
|
-
|
|
8005
|
-
|
|
8196
|
+
sync() {
|
|
8197
|
+
return __awaiter(this, arguments, void 0, function* ({ wait, purpose } = { wait: true, purpose: 'push' }) {
|
|
8198
|
+
var _a;
|
|
8006
8199
|
if (wait === undefined)
|
|
8007
8200
|
wait = true;
|
|
8008
8201
|
const db = DexieCloudDB(dexie);
|
|
@@ -8060,8 +8253,8 @@ function dexieCloud(dexie) {
|
|
|
8060
8253
|
dexie.use(createImplicitPropSetterMiddleware(DexieCloudDB(dexie)));
|
|
8061
8254
|
dexie.use(createIdGenerationMiddleware(DexieCloudDB(dexie)));
|
|
8062
8255
|
function onDbReady(dexie) {
|
|
8063
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
8064
8256
|
return __awaiter(this, void 0, void 0, function* () {
|
|
8257
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
8065
8258
|
closed = false; // As Dexie calls us, we are not closed anymore. Maybe reopened? Remember db.ready event is registered with sticky flag!
|
|
8066
8259
|
const db = DexieCloudDB(dexie);
|
|
8067
8260
|
// Setup default GUI:
|
|
@@ -8084,7 +8277,7 @@ function dexieCloud(dexie) {
|
|
|
8084
8277
|
? yield navigator.serviceWorker.getRegistrations()
|
|
8085
8278
|
: [];
|
|
8086
8279
|
const [initiallySynced, lastSyncedRealms] = yield db.transaction('rw', db.$syncState, () => __awaiter(this, void 0, void 0, function* () {
|
|
8087
|
-
var
|
|
8280
|
+
var _a, _b;
|
|
8088
8281
|
const { options, schema } = db.cloud;
|
|
8089
8282
|
const [persistedOptions, persistedSchema, persistedSyncState] = yield Promise.all([
|
|
8090
8283
|
db.getOptions(),
|
|
@@ -8106,7 +8299,7 @@ function dexieCloud(dexie) {
|
|
|
8106
8299
|
delete newPersistedOptions.awarenessProtocol;
|
|
8107
8300
|
yield db.$syncState.put(newPersistedOptions, 'options');
|
|
8108
8301
|
}
|
|
8109
|
-
if (((
|
|
8302
|
+
if (((_a = db.cloud.options) === null || _a === void 0 ? void 0 : _a.tryUseServiceWorker) &&
|
|
8110
8303
|
'serviceWorker' in navigator &&
|
|
8111
8304
|
swRegistrations.length > 0 &&
|
|
8112
8305
|
!DISABLE_SERVICEWORKER_STRATEGY) {
|
|
@@ -8120,7 +8313,7 @@ function dexieCloud(dexie) {
|
|
|
8120
8313
|
// Not configured for using service worker or no service worker
|
|
8121
8314
|
// registration exists. Don't rely on service worker to do any job.
|
|
8122
8315
|
// Use LocalSyncWorker instead.
|
|
8123
|
-
if (((
|
|
8316
|
+
if (((_b = db.cloud.options) === null || _b === void 0 ? void 0 : _b.tryUseServiceWorker) &&
|
|
8124
8317
|
!db.cloud.isServiceWorkerDB) {
|
|
8125
8318
|
console.debug('dexie-cloud-addon: Not using service worker.', swRegistrations.length === 0
|
|
8126
8319
|
? 'No SW registrations found.'
|
|
@@ -8163,10 +8356,6 @@ function dexieCloud(dexie) {
|
|
|
8163
8356
|
db.setInitiallySynced(true);
|
|
8164
8357
|
}
|
|
8165
8358
|
verifySchema(db);
|
|
8166
|
-
if (((_b = db.cloud.options) === null || _b === void 0 ? void 0 : _b.databaseUrl) && !initiallySynced) {
|
|
8167
|
-
yield performInitialSync(db, db.cloud.options, db.cloud.schema);
|
|
8168
|
-
db.setInitiallySynced(true);
|
|
8169
|
-
}
|
|
8170
8359
|
// Manage CurrentUser observable:
|
|
8171
8360
|
throwIfClosed();
|
|
8172
8361
|
if (!db.cloud.isServiceWorkerDB) {
|
|
@@ -8191,20 +8380,29 @@ function dexieCloud(dexie) {
|
|
|
8191
8380
|
// HERE: If requireAuth, do athentication now.
|
|
8192
8381
|
let changedUser = false;
|
|
8193
8382
|
const user = yield db.getCurrentUser();
|
|
8194
|
-
const requireAuth = (
|
|
8383
|
+
const requireAuth = (_b = db.cloud.options) === null || _b === void 0 ? void 0 : _b.requireAuth;
|
|
8195
8384
|
if (requireAuth) {
|
|
8196
|
-
if (
|
|
8197
|
-
//
|
|
8198
|
-
|
|
8199
|
-
|
|
8200
|
-
|
|
8201
|
-
|
|
8202
|
-
changedUser = yield login(db, requireAuth);
|
|
8203
|
-
}
|
|
8385
|
+
if (db.cloud.isServiceWorkerDB) {
|
|
8386
|
+
// If this is a service worker DB, we can't do authentication here,
|
|
8387
|
+
// we just wait until the application has done it.
|
|
8388
|
+
console.debug('Dexie Cloud Service worker. Waiting for application to authenticate.');
|
|
8389
|
+
yield firstValueFrom(currentUserEmitter.pipe(filter((user) => !!user.isLoggedIn), take(1)));
|
|
8390
|
+
console.debug('Dexie Cloud Service worker. Application has authenticated.');
|
|
8204
8391
|
}
|
|
8205
|
-
else
|
|
8206
|
-
|
|
8207
|
-
|
|
8392
|
+
else {
|
|
8393
|
+
if (typeof requireAuth === 'object') {
|
|
8394
|
+
// requireAuth contains login hints. Check if we already fulfil it:
|
|
8395
|
+
if (!user.isLoggedIn ||
|
|
8396
|
+
(requireAuth.userId && user.userId !== requireAuth.userId) ||
|
|
8397
|
+
(requireAuth.email && user.email !== requireAuth.email)) {
|
|
8398
|
+
// If not, login the configured user:
|
|
8399
|
+
changedUser = yield login(db, requireAuth);
|
|
8400
|
+
}
|
|
8401
|
+
}
|
|
8402
|
+
else if (!user.isLoggedIn) {
|
|
8403
|
+
// requireAuth is true and user is not logged in
|
|
8404
|
+
changedUser = yield login(db);
|
|
8405
|
+
}
|
|
8208
8406
|
}
|
|
8209
8407
|
}
|
|
8210
8408
|
if (user.isLoggedIn && (!lastSyncedRealms || !lastSyncedRealms.includes(user.userId))) {
|
|
@@ -8219,8 +8417,17 @@ function dexieCloud(dexie) {
|
|
|
8219
8417
|
localSyncWorker.stop();
|
|
8220
8418
|
localSyncWorker = null;
|
|
8221
8419
|
throwIfClosed();
|
|
8420
|
+
const doInitialSync = ((_c = db.cloud.options) === null || _c === void 0 ? void 0 : _c.databaseUrl) && (!initiallySynced || changedUser);
|
|
8421
|
+
if (doInitialSync) {
|
|
8422
|
+
// Do the initial sync directly in the browser thread no matter if we are using service worker or not.
|
|
8423
|
+
yield performInitialSync(db, db.cloud.options, db.cloud.schema);
|
|
8424
|
+
db.setInitiallySynced(true);
|
|
8425
|
+
}
|
|
8426
|
+
throwIfClosed();
|
|
8222
8427
|
if (db.cloud.usingServiceWorker && ((_d = db.cloud.options) === null || _d === void 0 ? void 0 : _d.databaseUrl)) {
|
|
8223
|
-
|
|
8428
|
+
if (!doInitialSync) {
|
|
8429
|
+
registerSyncEvent(db, 'push').catch(() => { });
|
|
8430
|
+
}
|
|
8224
8431
|
registerPeriodicSyncEvent(db).catch(() => { });
|
|
8225
8432
|
}
|
|
8226
8433
|
else if (((_e = db.cloud.options) === null || _e === void 0 ? void 0 : _e.databaseUrl) &&
|
|
@@ -8229,7 +8436,9 @@ function dexieCloud(dexie) {
|
|
|
8229
8436
|
// There's no SW. Start SyncWorker instead.
|
|
8230
8437
|
localSyncWorker = LocalSyncWorker(db, db.cloud.options, db.cloud.schema);
|
|
8231
8438
|
localSyncWorker.start();
|
|
8232
|
-
|
|
8439
|
+
if (!doInitialSync) {
|
|
8440
|
+
triggerSync(db, 'push');
|
|
8441
|
+
}
|
|
8233
8442
|
}
|
|
8234
8443
|
// Listen to online event and do sync.
|
|
8235
8444
|
throwIfClosed();
|
|
@@ -8249,7 +8458,7 @@ function dexieCloud(dexie) {
|
|
|
8249
8458
|
});
|
|
8250
8459
|
}));
|
|
8251
8460
|
}
|
|
8252
|
-
// Connect WebSocket unless we
|
|
8461
|
+
// Connect WebSocket unless we are in a service worker or websocket is disabled.
|
|
8253
8462
|
if (((_f = db.cloud.options) === null || _f === void 0 ? void 0 : _f.databaseUrl) &&
|
|
8254
8463
|
!((_g = db.cloud.options) === null || _g === void 0 ? void 0 : _g.disableWebSocket) &&
|
|
8255
8464
|
!IS_SERVICE_WORKER) {
|
|
@@ -8259,7 +8468,7 @@ function dexieCloud(dexie) {
|
|
|
8259
8468
|
}
|
|
8260
8469
|
}
|
|
8261
8470
|
// @ts-ignore
|
|
8262
|
-
dexieCloud.version = "4.1.0-
|
|
8471
|
+
dexieCloud.version = "4.1.0-beta.25";
|
|
8263
8472
|
Dexie.Cloud = dexieCloud;
|
|
8264
8473
|
|
|
8265
8474
|
// In case the SW lives for a while, let it reuse already opened connections:
|
|
@@ -8289,8 +8498,8 @@ function syncDB(dbName, purpose) {
|
|
|
8289
8498
|
}
|
|
8290
8499
|
return promise;
|
|
8291
8500
|
function _syncDB(dbName, purpose) {
|
|
8292
|
-
var _a;
|
|
8293
8501
|
return __awaiter(this, void 0, void 0, function* () {
|
|
8502
|
+
var _a;
|
|
8294
8503
|
let db = managedDBs.get(dbName);
|
|
8295
8504
|
if (!db) {
|
|
8296
8505
|
console.debug('Dexie Cloud SW: Creating new Dexie instance for', dbName);
|