dexie-cloud-addon 4.1.0-alpha.9 → 4.1.0-beta.26
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 +623 -260
- 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 +465 -258
- 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 +621 -257
- 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 +463 -256
- 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
- package/postinstall-banner.js +23 -0
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*
|
|
9
9
|
* ==========================================================================
|
|
10
10
|
*
|
|
11
|
-
* Version 4.1.0-
|
|
11
|
+
* Version 4.1.0-beta.26, 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,
|
|
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,38 +6789,42 @@ 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.
|
|
6667
6824
|
// If messageProducer emits empty array, nothing is emitted
|
|
6668
6825
|
// but if messageProducer emits array of messages, they are
|
|
6669
6826
|
// emitted one by one.
|
|
6670
|
-
mergeMap$1((messages) => messages)
|
|
6671
|
-
console.debug('dexie-cloud emitting y-c', message);
|
|
6672
|
-
}));
|
|
6827
|
+
mergeMap$1((messages) => messages));
|
|
6673
6828
|
}
|
|
6674
6829
|
|
|
6675
6830
|
function getAwarenessLibrary(db) {
|
|
@@ -6682,6 +6837,23 @@ function getAwarenessLibrary(db) {
|
|
|
6682
6837
|
const awarenessWeakMap = new WeakMap();
|
|
6683
6838
|
const getDocAwareness = (doc) => awarenessWeakMap.get(doc);
|
|
6684
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
|
+
|
|
6685
6857
|
const SERVER_PING_TIMEOUT = 20000;
|
|
6686
6858
|
const CLIENT_PING_INTERVAL = 30000;
|
|
6687
6859
|
const FAIL_RETRY_WAIT_TIME = 60000;
|
|
@@ -6844,9 +7016,6 @@ class WSConnection extends Subscription$1 {
|
|
|
6844
7016
|
if (msg.type === 'error') {
|
|
6845
7017
|
throw new Error(`Error message from dexie-cloud: ${msg.error}`);
|
|
6846
7018
|
}
|
|
6847
|
-
else if (msg.type === 'rev') {
|
|
6848
|
-
this.rev = msg.rev; // No meaning but seems reasonable.
|
|
6849
|
-
}
|
|
6850
7019
|
else if (msg.type === 'aware') {
|
|
6851
7020
|
const docCache = DexieYProvider.getDocCache(this.db.dx);
|
|
6852
7021
|
const doc = docCache.find(msg.table, msg.k, msg.prop);
|
|
@@ -6861,7 +7030,19 @@ class WSConnection extends Subscription$1 {
|
|
|
6861
7030
|
else if (msg.type === 'u-ack' || msg.type === 'u-reject' || msg.type === 'u-s' || msg.type === 'in-sync') {
|
|
6862
7031
|
applyYServerMessages([msg], this.db);
|
|
6863
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
|
+
}
|
|
6864
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!)
|
|
6865
7046
|
this.subscriber.next(msg);
|
|
6866
7047
|
}
|
|
6867
7048
|
}
|
|
@@ -6898,6 +7079,10 @@ class WSConnection extends Subscription$1 {
|
|
|
6898
7079
|
}
|
|
6899
7080
|
console.debug('dexie-cloud WebSocket send', msg.type, msg);
|
|
6900
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!
|
|
6901
7086
|
(_a = this.ws) === null || _a === void 0 ? void 0 : _a.send(TSON.stringify(msg));
|
|
6902
7087
|
}
|
|
6903
7088
|
else {
|
|
@@ -6979,7 +7164,7 @@ function connectWebSocket(db) {
|
|
|
6979
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]));
|
|
6980
7165
|
}
|
|
6981
7166
|
return new BehaviorSubject([userLogin, syncState]);
|
|
6982
|
-
}), 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]) => {
|
|
6983
7168
|
var _a;
|
|
6984
7169
|
if (!((_a = db.cloud.persistedSyncState) === null || _a === void 0 ? void 0 : _a.value)) {
|
|
6985
7170
|
// Restart the flow if persistedSyncState is not yet available.
|
|
@@ -7040,22 +7225,14 @@ function connectWebSocket(db) {
|
|
|
7040
7225
|
}
|
|
7041
7226
|
|
|
7042
7227
|
function isSyncNeeded(db) {
|
|
7043
|
-
var _a;
|
|
7044
7228
|
return __awaiter(this, void 0, void 0, function* () {
|
|
7229
|
+
var _a;
|
|
7045
7230
|
return ((_a = db.cloud.options) === null || _a === void 0 ? void 0 : _a.databaseUrl) && db.cloud.schema
|
|
7046
7231
|
? yield sync(db, db.cloud.options, db.cloud.schema, { justCheckIfNeeded: true })
|
|
7047
7232
|
: false;
|
|
7048
7233
|
});
|
|
7049
7234
|
}
|
|
7050
7235
|
|
|
7051
|
-
function performGuardedJob(db, jobName, job) {
|
|
7052
|
-
if (typeof navigator === 'undefined' || !navigator.locks) {
|
|
7053
|
-
// No support for guarding jobs. IE11, node.js, etc.
|
|
7054
|
-
return job();
|
|
7055
|
-
}
|
|
7056
|
-
return navigator.locks.request(db.name + '|' + jobName, () => job());
|
|
7057
|
-
}
|
|
7058
|
-
|
|
7059
7236
|
const ongoingSyncs = new WeakMap();
|
|
7060
7237
|
function syncIfPossible(db, cloudOptions, cloudSchema, options) {
|
|
7061
7238
|
const ongoing = ongoingSyncs.get(db);
|
|
@@ -7109,20 +7286,7 @@ function syncIfPossible(db, cloudOptions, cloudSchema, options) {
|
|
|
7109
7286
|
try {
|
|
7110
7287
|
// Check if should delay sync due to ratelimit:
|
|
7111
7288
|
yield checkSyncRateLimitDelay(db);
|
|
7112
|
-
|
|
7113
|
-
if (db.cloud.isServiceWorkerDB) {
|
|
7114
|
-
// We are the dedicated sync SW:
|
|
7115
|
-
yield sync(db, cloudOptions, cloudSchema, options);
|
|
7116
|
-
}
|
|
7117
|
-
else if (!db.cloud.usingServiceWorker) {
|
|
7118
|
-
// We use a flow that is better suited for the case when multiple workers want to
|
|
7119
|
-
// do the same thing.
|
|
7120
|
-
yield performGuardedJob(db, CURRENT_SYNC_WORKER, () => sync(db, cloudOptions, cloudSchema, options));
|
|
7121
|
-
}
|
|
7122
|
-
else {
|
|
7123
|
-
assert(false);
|
|
7124
|
-
throw new Error('Internal _syncIfPossible() - invalid precondition - should not have been called.');
|
|
7125
|
-
}
|
|
7289
|
+
yield performGuardedJob(db, CURRENT_SYNC_WORKER, () => sync(db, cloudOptions, cloudSchema, options));
|
|
7126
7290
|
ongoingSyncs.delete(db);
|
|
7127
7291
|
console.debug('Done sync');
|
|
7128
7292
|
}
|
|
@@ -7725,6 +7889,7 @@ class PermissionChecker {
|
|
|
7725
7889
|
// If user can update any prop in any table in this realm, return true unless
|
|
7726
7890
|
// it regards to ownership change:
|
|
7727
7891
|
if (this.permissions.update === '*') {
|
|
7892
|
+
// @ts-ignore
|
|
7728
7893
|
return props.every((prop) => prop !== 'owner');
|
|
7729
7894
|
}
|
|
7730
7895
|
const tablePermissions = (_b = this.permissions.update) === null || _b === void 0 ? void 0 : _b[this.tableName];
|
|
@@ -7798,125 +7963,151 @@ const getInvitesObservable = associate((db) => {
|
|
|
7798
7963
|
function createYHandler(db) {
|
|
7799
7964
|
return (provider) => {
|
|
7800
7965
|
var _a;
|
|
7801
|
-
const awap = getAwarenessLibrary(db);
|
|
7802
7966
|
const doc = provider.doc;
|
|
7803
|
-
const { parentTable
|
|
7967
|
+
const { parentTable } = doc.meta || {};
|
|
7804
7968
|
if (!((_a = db.cloud.schema) === null || _a === void 0 ? void 0 : _a[parentTable].markedForSync)) {
|
|
7805
7969
|
return; // The table that holds the doc is not marked for sync - leave it to dexie. No syncing, no awareness.
|
|
7806
7970
|
}
|
|
7807
|
-
let awareness
|
|
7808
|
-
|
|
7809
|
-
|
|
7810
|
-
|
|
7811
|
-
|
|
7812
|
-
|
|
7813
|
-
|
|
7814
|
-
|
|
7815
|
-
|
|
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.
|
|
7816
8007
|
db.messageProducer.next({
|
|
7817
|
-
type: '
|
|
8008
|
+
type: 'doc-close',
|
|
7818
8009
|
table: parentTable,
|
|
7819
8010
|
prop: parentProp,
|
|
7820
8011
|
k: doc.meta.parentId,
|
|
7821
|
-
u: update,
|
|
7822
8012
|
});
|
|
7823
|
-
if (provider.destroyed) {
|
|
7824
|
-
// We're called from awareness.on('destroy') that did
|
|
7825
|
-
// removeAwarenessStates.
|
|
7826
|
-
// It's time to also send the doc-close message that dexie-cloud understands
|
|
7827
|
-
// and uses to stop subscribing for updates and awareness updates and brings
|
|
7828
|
-
// down the cached information in memory on the WS connection for this.
|
|
7829
|
-
db.messageProducer.next({
|
|
7830
|
-
type: 'doc-close',
|
|
7831
|
-
table: parentTable,
|
|
7832
|
-
prop: parentProp,
|
|
7833
|
-
k: doc.meta.parentId
|
|
7834
|
-
});
|
|
7835
|
-
}
|
|
7836
8013
|
}
|
|
7837
|
-
}
|
|
7838
|
-
|
|
7839
|
-
|
|
7840
|
-
|
|
7841
|
-
|
|
7842
|
-
|
|
7843
|
-
|
|
7844
|
-
|
|
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]) => {
|
|
7845
8031
|
if (provider.destroyed)
|
|
7846
8032
|
return;
|
|
7847
|
-
|
|
7848
|
-
|
|
7849
|
-
|
|
7850
|
-
|
|
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)
|
|
7851
8082
|
return;
|
|
7852
|
-
|
|
7853
|
-
|
|
7854
|
-
|
|
7855
|
-
|
|
7856
|
-
|
|
7857
|
-
|
|
7858
|
-
|
|
7859
|
-
|
|
7860
|
-
|
|
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;
|
|
7861
8105
|
}
|
|
8106
|
+
db.messageProducer.next(docOpenMsg);
|
|
7862
8107
|
});
|
|
7863
|
-
|
|
7864
|
-
|
|
7865
|
-
|
|
7866
|
-
* connected, or if it is already connected.
|
|
7867
|
-
* The flow is aborted in case websocket is disconnected while querying
|
|
7868
|
-
* information required to compute the state vector. Flow is also
|
|
7869
|
-
* aborted in case document or provider has been destroyed during
|
|
7870
|
-
* the async parts of the task.
|
|
7871
|
-
*
|
|
7872
|
-
* The state vector is only computed from the updates that have occured
|
|
7873
|
-
* after the last full sync - which could very often be zero - in which
|
|
7874
|
-
* case no state vector is sent (then the server already knows us by
|
|
7875
|
-
* revision)
|
|
7876
|
-
*
|
|
7877
|
-
* When server gets the doc-open message, it will authorized us for
|
|
7878
|
-
* whether we are allowed to read / write to this document, and then
|
|
7879
|
-
* keep the cached information in memory on the WS connection for this
|
|
7880
|
-
* particular document, as well as subscribe to updates and awareness updates
|
|
7881
|
-
* from other clients on the document.
|
|
7882
|
-
*/
|
|
7883
|
-
function openDocumentOnServer(wsStatus) {
|
|
7884
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
7885
|
-
const myFlow = currentFlowId; // So we can abort when a new flow is started
|
|
7886
|
-
const yTbl = db.table(updatesTable);
|
|
7887
|
-
const syncState = yield yTbl.get(DEXIE_CLOUD_SYNCER_ID);
|
|
7888
|
-
// After every await, check if we still should be working on this task.
|
|
7889
|
-
if (provider.destroyed || currentFlowId !== myFlow || !connected)
|
|
7890
|
-
return;
|
|
7891
|
-
const receivedUntil = (syncState === null || syncState === void 0 ? void 0 : syncState.receivedUntil) || 0;
|
|
7892
|
-
const docOpenMsg = {
|
|
7893
|
-
type: 'doc-open',
|
|
7894
|
-
table: parentTable,
|
|
7895
|
-
prop: parentProp,
|
|
7896
|
-
k: parentId,
|
|
7897
|
-
serverRev: syncState === null || syncState === void 0 ? void 0 : syncState.serverRev,
|
|
7898
|
-
};
|
|
7899
|
-
const serverUpdatesSinceLastSync = yield yTbl
|
|
7900
|
-
.where('i')
|
|
7901
|
-
.between(receivedUntil, Infinity, false)
|
|
7902
|
-
.filter((update) => cmp(update.k, parentId) === 0 && // Only updates for this document
|
|
7903
|
-
((update.f || 0) & 1) === 0 // Don't include local changes
|
|
7904
|
-
)
|
|
7905
|
-
.toArray();
|
|
7906
|
-
// After every await, check if we still should be working on this task.
|
|
7907
|
-
if (provider.destroyed || currentFlowId !== myFlow || !connected)
|
|
7908
|
-
return;
|
|
7909
|
-
if (serverUpdatesSinceLastSync.length > 0) {
|
|
7910
|
-
const Y = $Y(db); // Get the Yjs library from Dexie constructor options
|
|
7911
|
-
const mergedUpdate = Y.mergeUpdatesV2(serverUpdatesSinceLastSync.map((update) => update.u));
|
|
7912
|
-
const stateVector = Y.encodeStateVectorFromUpdateV2(mergedUpdate);
|
|
7913
|
-
docOpenMsg.sv = stateVector;
|
|
7914
|
-
}
|
|
7915
|
-
db.messageProducer.next(docOpenMsg);
|
|
7916
|
-
});
|
|
7917
|
-
}
|
|
7918
|
-
}));
|
|
7919
|
-
};
|
|
8108
|
+
}
|
|
8109
|
+
}))();
|
|
8110
|
+
return awareness;
|
|
7920
8111
|
}
|
|
7921
8112
|
|
|
7922
8113
|
const DEFAULT_OPTIONS = {
|
|
@@ -7959,7 +8150,7 @@ function dexieCloud(dexie) {
|
|
|
7959
8150
|
const syncComplete = new Subject();
|
|
7960
8151
|
dexie.cloud = {
|
|
7961
8152
|
// @ts-ignore
|
|
7962
|
-
version: "4.1.0-
|
|
8153
|
+
version: "4.1.0-beta.26",
|
|
7963
8154
|
options: Object.assign({}, DEFAULT_OPTIONS),
|
|
7964
8155
|
schema: null,
|
|
7965
8156
|
get currentUserId() {
|
|
@@ -7995,16 +8186,16 @@ function dexieCloud(dexie) {
|
|
|
7995
8186
|
}
|
|
7996
8187
|
updateSchemaFromOptions(dexie.cloud.schema, dexie.cloud.options);
|
|
7997
8188
|
},
|
|
7998
|
-
logout(
|
|
7999
|
-
return __awaiter(this,
|
|
8189
|
+
logout() {
|
|
8190
|
+
return __awaiter(this, arguments, void 0, function* ({ force } = {}) {
|
|
8000
8191
|
force
|
|
8001
8192
|
? yield _logout(DexieCloudDB(dexie), { deleteUnsyncedData: true })
|
|
8002
8193
|
: yield logout(DexieCloudDB(dexie));
|
|
8003
8194
|
});
|
|
8004
8195
|
},
|
|
8005
|
-
sync(
|
|
8006
|
-
|
|
8007
|
-
|
|
8196
|
+
sync() {
|
|
8197
|
+
return __awaiter(this, arguments, void 0, function* ({ wait, purpose } = { wait: true, purpose: 'push' }) {
|
|
8198
|
+
var _a;
|
|
8008
8199
|
if (wait === undefined)
|
|
8009
8200
|
wait = true;
|
|
8010
8201
|
const db = DexieCloudDB(dexie);
|
|
@@ -8062,8 +8253,8 @@ function dexieCloud(dexie) {
|
|
|
8062
8253
|
dexie.use(createImplicitPropSetterMiddleware(DexieCloudDB(dexie)));
|
|
8063
8254
|
dexie.use(createIdGenerationMiddleware(DexieCloudDB(dexie)));
|
|
8064
8255
|
function onDbReady(dexie) {
|
|
8065
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
8066
8256
|
return __awaiter(this, void 0, void 0, function* () {
|
|
8257
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
8067
8258
|
closed = false; // As Dexie calls us, we are not closed anymore. Maybe reopened? Remember db.ready event is registered with sticky flag!
|
|
8068
8259
|
const db = DexieCloudDB(dexie);
|
|
8069
8260
|
// Setup default GUI:
|
|
@@ -8086,7 +8277,7 @@ function dexieCloud(dexie) {
|
|
|
8086
8277
|
? yield navigator.serviceWorker.getRegistrations()
|
|
8087
8278
|
: [];
|
|
8088
8279
|
const [initiallySynced, lastSyncedRealms] = yield db.transaction('rw', db.$syncState, () => __awaiter(this, void 0, void 0, function* () {
|
|
8089
|
-
var
|
|
8280
|
+
var _a, _b;
|
|
8090
8281
|
const { options, schema } = db.cloud;
|
|
8091
8282
|
const [persistedOptions, persistedSchema, persistedSyncState] = yield Promise.all([
|
|
8092
8283
|
db.getOptions(),
|
|
@@ -8108,7 +8299,7 @@ function dexieCloud(dexie) {
|
|
|
8108
8299
|
delete newPersistedOptions.awarenessProtocol;
|
|
8109
8300
|
yield db.$syncState.put(newPersistedOptions, 'options');
|
|
8110
8301
|
}
|
|
8111
|
-
if (((
|
|
8302
|
+
if (((_a = db.cloud.options) === null || _a === void 0 ? void 0 : _a.tryUseServiceWorker) &&
|
|
8112
8303
|
'serviceWorker' in navigator &&
|
|
8113
8304
|
swRegistrations.length > 0 &&
|
|
8114
8305
|
!DISABLE_SERVICEWORKER_STRATEGY) {
|
|
@@ -8122,7 +8313,7 @@ function dexieCloud(dexie) {
|
|
|
8122
8313
|
// Not configured for using service worker or no service worker
|
|
8123
8314
|
// registration exists. Don't rely on service worker to do any job.
|
|
8124
8315
|
// Use LocalSyncWorker instead.
|
|
8125
|
-
if (((
|
|
8316
|
+
if (((_b = db.cloud.options) === null || _b === void 0 ? void 0 : _b.tryUseServiceWorker) &&
|
|
8126
8317
|
!db.cloud.isServiceWorkerDB) {
|
|
8127
8318
|
console.debug('dexie-cloud-addon: Not using service worker.', swRegistrations.length === 0
|
|
8128
8319
|
? 'No SW registrations found.'
|
|
@@ -8165,10 +8356,6 @@ function dexieCloud(dexie) {
|
|
|
8165
8356
|
db.setInitiallySynced(true);
|
|
8166
8357
|
}
|
|
8167
8358
|
verifySchema(db);
|
|
8168
|
-
if (((_b = db.cloud.options) === null || _b === void 0 ? void 0 : _b.databaseUrl) && !initiallySynced) {
|
|
8169
|
-
yield performInitialSync(db, db.cloud.options, db.cloud.schema);
|
|
8170
|
-
db.setInitiallySynced(true);
|
|
8171
|
-
}
|
|
8172
8359
|
// Manage CurrentUser observable:
|
|
8173
8360
|
throwIfClosed();
|
|
8174
8361
|
if (!db.cloud.isServiceWorkerDB) {
|
|
@@ -8193,20 +8380,29 @@ function dexieCloud(dexie) {
|
|
|
8193
8380
|
// HERE: If requireAuth, do athentication now.
|
|
8194
8381
|
let changedUser = false;
|
|
8195
8382
|
const user = yield db.getCurrentUser();
|
|
8196
|
-
const requireAuth = (
|
|
8383
|
+
const requireAuth = (_b = db.cloud.options) === null || _b === void 0 ? void 0 : _b.requireAuth;
|
|
8197
8384
|
if (requireAuth) {
|
|
8198
|
-
if (
|
|
8199
|
-
//
|
|
8200
|
-
|
|
8201
|
-
|
|
8202
|
-
|
|
8203
|
-
|
|
8204
|
-
changedUser = yield login(db, requireAuth);
|
|
8205
|
-
}
|
|
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.');
|
|
8206
8391
|
}
|
|
8207
|
-
else
|
|
8208
|
-
|
|
8209
|
-
|
|
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
|
+
}
|
|
8210
8406
|
}
|
|
8211
8407
|
}
|
|
8212
8408
|
if (user.isLoggedIn && (!lastSyncedRealms || !lastSyncedRealms.includes(user.userId))) {
|
|
@@ -8221,8 +8417,17 @@ function dexieCloud(dexie) {
|
|
|
8221
8417
|
localSyncWorker.stop();
|
|
8222
8418
|
localSyncWorker = null;
|
|
8223
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();
|
|
8224
8427
|
if (db.cloud.usingServiceWorker && ((_d = db.cloud.options) === null || _d === void 0 ? void 0 : _d.databaseUrl)) {
|
|
8225
|
-
|
|
8428
|
+
if (!doInitialSync) {
|
|
8429
|
+
registerSyncEvent(db, 'push').catch(() => { });
|
|
8430
|
+
}
|
|
8226
8431
|
registerPeriodicSyncEvent(db).catch(() => { });
|
|
8227
8432
|
}
|
|
8228
8433
|
else if (((_e = db.cloud.options) === null || _e === void 0 ? void 0 : _e.databaseUrl) &&
|
|
@@ -8231,7 +8436,9 @@ function dexieCloud(dexie) {
|
|
|
8231
8436
|
// There's no SW. Start SyncWorker instead.
|
|
8232
8437
|
localSyncWorker = LocalSyncWorker(db, db.cloud.options, db.cloud.schema);
|
|
8233
8438
|
localSyncWorker.start();
|
|
8234
|
-
|
|
8439
|
+
if (!doInitialSync) {
|
|
8440
|
+
triggerSync(db, 'push');
|
|
8441
|
+
}
|
|
8235
8442
|
}
|
|
8236
8443
|
// Listen to online event and do sync.
|
|
8237
8444
|
throwIfClosed();
|
|
@@ -8251,7 +8458,7 @@ function dexieCloud(dexie) {
|
|
|
8251
8458
|
});
|
|
8252
8459
|
}));
|
|
8253
8460
|
}
|
|
8254
|
-
// Connect WebSocket unless we
|
|
8461
|
+
// Connect WebSocket unless we are in a service worker or websocket is disabled.
|
|
8255
8462
|
if (((_f = db.cloud.options) === null || _f === void 0 ? void 0 : _f.databaseUrl) &&
|
|
8256
8463
|
!((_g = db.cloud.options) === null || _g === void 0 ? void 0 : _g.disableWebSocket) &&
|
|
8257
8464
|
!IS_SERVICE_WORKER) {
|
|
@@ -8261,7 +8468,7 @@ function dexieCloud(dexie) {
|
|
|
8261
8468
|
}
|
|
8262
8469
|
}
|
|
8263
8470
|
// @ts-ignore
|
|
8264
|
-
dexieCloud.version = "4.1.0-
|
|
8471
|
+
dexieCloud.version = "4.1.0-beta.26";
|
|
8265
8472
|
Dexie.Cloud = dexieCloud;
|
|
8266
8473
|
|
|
8267
8474
|
// In case the SW lives for a while, let it reuse already opened connections:
|
|
@@ -8291,8 +8498,8 @@ function syncDB(dbName, purpose) {
|
|
|
8291
8498
|
}
|
|
8292
8499
|
return promise;
|
|
8293
8500
|
function _syncDB(dbName, purpose) {
|
|
8294
|
-
var _a;
|
|
8295
8501
|
return __awaiter(this, void 0, void 0, function* () {
|
|
8502
|
+
var _a;
|
|
8296
8503
|
let db = managedDBs.get(dbName);
|
|
8297
8504
|
if (!db) {
|
|
8298
8505
|
console.debug('Dexie Cloud SW: Creating new Dexie instance for', dbName);
|