dexie-cloud-addon 1.0.0-beta.10 → 1.0.0-beta.11

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.
Files changed (34) hide show
  1. package/dist/modern/dexie-cloud-addon.js +189 -158
  2. package/dist/modern/dexie-cloud-addon.js.map +1 -1
  3. package/dist/modern/dexie-cloud-addon.min.js +1 -1
  4. package/dist/modern/dexie-cloud-addon.min.js.map +1 -1
  5. package/dist/modern/service-worker.js +1208 -1176
  6. package/dist/modern/service-worker.js.map +1 -1
  7. package/dist/modern/service-worker.min.js +1 -1
  8. package/dist/modern/service-worker.min.js.map +1 -1
  9. package/dist/module-es5/dexie-cloud-addon.js +259 -207
  10. package/dist/module-es5/dexie-cloud-addon.js.map +1 -1
  11. package/dist/module-es5/dexie-cloud-addon.min.js +1 -1
  12. package/dist/module-es5/dexie-cloud-addon.min.js.map +1 -1
  13. package/dist/types/WSObservable.d.ts +11 -6
  14. package/dist/types/WebSocketStatus.d.ts +1 -0
  15. package/dist/types/helpers/BroadcastedLocalEvent.d.ts +8 -0
  16. package/dist/types/helpers/visibleState.d.ts +1 -0
  17. package/dist/types/sync/syncServerToClientOnly.d.ts +3 -0
  18. package/dist/types/types/CloudConnectionStatus.d.ts +0 -0
  19. package/dist/types/types/ConnectionStatus.d.ts +0 -0
  20. package/dist/types/types/LoginState.d.ts +41 -0
  21. package/dist/types/types/SyncConnectionStatus.d.ts +1 -0
  22. package/dist/types/types/SyncFlowStatus.d.ts +6 -0
  23. package/dist/types/types/SyncStatus.d.ts +6 -0
  24. package/dist/umd/dexie-cloud-addon.js +259 -207
  25. package/dist/umd/dexie-cloud-addon.js.map +1 -1
  26. package/dist/umd/dexie-cloud-addon.min.js +1 -1
  27. package/dist/umd/dexie-cloud-addon.min.js.map +1 -1
  28. package/dist/umd/service-worker.js +1208 -1176
  29. package/dist/umd/service-worker.js.map +1 -1
  30. package/dist/umd/service-worker.min.js +1 -1
  31. package/dist/umd/service-worker.min.js.map +1 -1
  32. package/dist/umd-modern/dexie-cloud-addon.js +188 -157
  33. package/dist/umd-modern/dexie-cloud-addon.js.map +1 -1
  34. package/package.json +2 -2
@@ -104,7 +104,7 @@
104
104
  *
105
105
  * ==========================================================================
106
106
  *
107
- * Version 1.0.0-beta.10, Wed Sep 08 2021
107
+ * Version 1.0.0-beta.10, Wed Oct 06 2021
108
108
  *
109
109
  * https://dexie.org
110
110
  *
@@ -3142,6 +3142,151 @@
3142
3142
  };
3143
3143
  return BroadcastedAndLocalEvent;
3144
3144
  }(rxjs.Observable));
3145
+ function computeRealmSetHash(_g) {
3146
+ var realms = _g.realms, inviteRealms = _g.inviteRealms;
3147
+ return __awaiter(this, void 0, void 0, function () {
3148
+ var data, byteArray, digestBytes, base64;
3149
+ return __generator(this, function (_h) {
3150
+ switch (_h.label) {
3151
+ case 0:
3152
+ data = JSON.stringify(__spreadArray(__spreadArray([], realms.map(function (realmId) { return ({ realmId: realmId, accepted: true }); })), inviteRealms.map(function (realmId) { return ({ realmId: realmId, accepted: false }); })).sort(function (a, b) { return a.realmId < b.realmId ? -1 : a.realmId > b.realmId ? 1 : 0; }));
3153
+ byteArray = new TextEncoder().encode(data);
3154
+ return [4 /*yield*/, crypto.subtle.digest('SHA-1', byteArray)];
3155
+ case 1:
3156
+ digestBytes = _h.sent();
3157
+ base64 = b64encode(digestBytes);
3158
+ return [2 /*return*/, base64];
3159
+ }
3160
+ });
3161
+ });
3162
+ }
3163
+ function getSyncableTables(db) {
3164
+ return Object.entries(db.cloud.schema || {})
3165
+ .filter(function (_g) {
3166
+ var markedForSync = _g[1].markedForSync;
3167
+ return markedForSync;
3168
+ })
3169
+ .map(function (_g) {
3170
+ var tbl = _g[0];
3171
+ return db.table(tbl);
3172
+ });
3173
+ }
3174
+ function getMutationTable(tableName) {
3175
+ return "$" + tableName + "_mutations";
3176
+ }
3177
+ function getTableFromMutationTable(mutationTable) {
3178
+ var _a;
3179
+ var tableName = (_a = /^\$(.*)_mutations$/.exec(mutationTable)) === null || _a === void 0 ? void 0 : _a[1];
3180
+ if (!tableName)
3181
+ throw new Error("Given mutationTable " + mutationTable + " is not correct");
3182
+ return tableName;
3183
+ }
3184
+ function listClientChanges(mutationTables, db, _g) {
3185
+ var _h = _g === void 0 ? {} : _g, _j = _h.since, since = _j === void 0 ? {} : _j, _k = _h.limit, limit = _k === void 0 ? Infinity : _k;
3186
+ return __awaiter(this, void 0, void 0, function () {
3187
+ var allMutsOnTables;
3188
+ var _this_1 = this;
3189
+ return __generator(this, function (_l) {
3190
+ switch (_l.label) {
3191
+ case 0: return [4 /*yield*/, Promise.all(mutationTables.map(function (mutationTable) { return __awaiter(_this_1, void 0, void 0, function () {
3192
+ var tableName, lastRevision, query, muts;
3193
+ return __generator(this, function (_g) {
3194
+ switch (_g.label) {
3195
+ case 0:
3196
+ tableName = getTableFromMutationTable(mutationTable.name);
3197
+ lastRevision = since[tableName];
3198
+ query = lastRevision
3199
+ ? mutationTable.where("rev").above(lastRevision)
3200
+ : mutationTable;
3201
+ if (limit < Infinity)
3202
+ query = query.limit(limit);
3203
+ return [4 /*yield*/, query.toArray()];
3204
+ case 1:
3205
+ muts = _g.sent();
3206
+ //const objTable = db.table(tableName);
3207
+ /*for (const mut of muts) {
3208
+ if (mut.type === "insert" || mut.type === "upsert") {
3209
+ mut.values = await objTable.bulkGet(mut.keys);
3210
+ }
3211
+ }*/
3212
+ return [2 /*return*/, {
3213
+ table: tableName,
3214
+ muts: muts,
3215
+ }];
3216
+ }
3217
+ });
3218
+ }); }))];
3219
+ case 1:
3220
+ allMutsOnTables = _l.sent();
3221
+ // Filter out those tables that doesn't have any mutations:
3222
+ return [2 /*return*/, allMutsOnTables.filter(function (_g) {
3223
+ var muts = _g.muts;
3224
+ return muts.length > 0;
3225
+ })];
3226
+ }
3227
+ });
3228
+ });
3229
+ }
3230
+ function listSyncifiedChanges(tablesToSyncify, currentUser, schema, alreadySyncedRealms) {
3231
+ return __awaiter(this, void 0, void 0, function () {
3232
+ var ignoredRealms_1, inserts;
3233
+ var _this_1 = this;
3234
+ return __generator(this, function (_g) {
3235
+ switch (_g.label) {
3236
+ case 0:
3237
+ if (!currentUser.isLoggedIn) return [3 /*break*/, 2];
3238
+ if (!(tablesToSyncify.length > 0)) return [3 /*break*/, 2];
3239
+ ignoredRealms_1 = new Set(alreadySyncedRealms || []);
3240
+ return [4 /*yield*/, Promise.all(tablesToSyncify.map(function (table) { return __awaiter(_this_1, void 0, void 0, function () {
3241
+ var extractKey, dexieCloudTableSchema, query, unsyncedObjects, mut;
3242
+ return __generator(this, function (_g) {
3243
+ switch (_g.label) {
3244
+ case 0:
3245
+ extractKey = table.core.schema.primaryKey.extractKey;
3246
+ if (!extractKey)
3247
+ return [2 /*return*/, { table: table.name, muts: [] }]; // Outbound tables are not synced.
3248
+ dexieCloudTableSchema = schema[table.name];
3249
+ query = (dexieCloudTableSchema === null || dexieCloudTableSchema === void 0 ? void 0 : dexieCloudTableSchema.generatedGlobalId)
3250
+ ? table.filter(function (item) { return !ignoredRealms_1.has(item.realmId || "") && isValidSyncableID(extractKey(item)); })
3251
+ : table.filter(function (item) { return !ignoredRealms_1.has(item.realmId || "") && isValidAtID(extractKey(item), dexieCloudTableSchema === null || dexieCloudTableSchema === void 0 ? void 0 : dexieCloudTableSchema.idPrefix); });
3252
+ return [4 /*yield*/, query.toArray()];
3253
+ case 1:
3254
+ unsyncedObjects = _g.sent();
3255
+ if (unsyncedObjects.length > 0) {
3256
+ mut = {
3257
+ type: "insert",
3258
+ values: unsyncedObjects,
3259
+ keys: unsyncedObjects.map(extractKey),
3260
+ userId: currentUser.userId,
3261
+ };
3262
+ return [2 /*return*/, {
3263
+ table: table.name,
3264
+ muts: [mut],
3265
+ }];
3266
+ }
3267
+ else {
3268
+ return [2 /*return*/, {
3269
+ table: table.name,
3270
+ muts: []
3271
+ }];
3272
+ }
3273
+ }
3274
+ });
3275
+ }); }))];
3276
+ case 1:
3277
+ inserts = _g.sent();
3278
+ return [2 /*return*/, inserts.filter(function (op) { return op.muts.length > 0; })];
3279
+ case 2: return [2 /*return*/, []];
3280
+ }
3281
+ });
3282
+ });
3283
+ }
3284
+ function getTablesToSyncify(db, syncState) {
3285
+ var syncedTables = (syncState === null || syncState === void 0 ? void 0 : syncState.syncedTables) || [];
3286
+ var syncableTables = getSyncableTables(db);
3287
+ var tablesToSyncify = syncableTables.filter(function (tbl) { return !syncedTables.includes(tbl.name); });
3288
+ return tablesToSyncify;
3289
+ }
3145
3290
  var toStr = {}.toString;
3146
3291
  function getToStringTag(val) {
3147
3292
  return toStr.call(val).slice(8, -1);
@@ -3661,22 +3806,6 @@
3661
3806
  // else
3662
3807
  // serverRev.rev = new FakeBigInt(server.rev)
3663
3808
  var hasBigIntSupport = typeof BigInt(0) === 'bigint';
3664
- function getValueOfBigInt(x) {
3665
- if (typeof x === 'bigint') {
3666
- return x;
3667
- }
3668
- if (hasBigIntSupport) {
3669
- return typeof x === 'string' ? BigInt(x) : BigInt(x.v);
3670
- }
3671
- else {
3672
- return typeof x === 'string' ? Number(x) : Number(x.v);
3673
- }
3674
- }
3675
- function compareBigInts(a, b) {
3676
- var valA = getValueOfBigInt(a);
3677
- var valB = getValueOfBigInt(b);
3678
- return valA < valB ? -1 : valA > valB ? 1 : 0;
3679
- }
3680
3809
  var FakeBigInt = /** @class */ (function () {
3681
3810
  function FakeBigInt(value) {
3682
3811
  this.v = value;
@@ -3702,151 +3831,6 @@
3702
3831
  }));
3703
3832
  var TSON = TypesonSimplified(builtin, defs);
3704
3833
  var BISON = Bison(defs);
3705
- function computeRealmSetHash(_g) {
3706
- var realms = _g.realms, inviteRealms = _g.inviteRealms;
3707
- return __awaiter(this, void 0, void 0, function () {
3708
- var data, byteArray, digestBytes, base64;
3709
- return __generator(this, function (_h) {
3710
- switch (_h.label) {
3711
- case 0:
3712
- data = JSON.stringify(__spreadArray(__spreadArray([], realms.map(function (realmId) { return ({ realmId: realmId, accepted: true }); })), inviteRealms.map(function (realmId) { return ({ realmId: realmId, accepted: false }); })).sort(function (a, b) { return a.realmId < b.realmId ? -1 : a.realmId > b.realmId ? 1 : 0; }));
3713
- byteArray = new TextEncoder().encode(data);
3714
- return [4 /*yield*/, crypto.subtle.digest('SHA-1', byteArray)];
3715
- case 1:
3716
- digestBytes = _h.sent();
3717
- base64 = b64encode(digestBytes);
3718
- return [2 /*return*/, base64];
3719
- }
3720
- });
3721
- });
3722
- }
3723
- function getSyncableTables(db) {
3724
- return Object.entries(db.cloud.schema || {})
3725
- .filter(function (_g) {
3726
- var markedForSync = _g[1].markedForSync;
3727
- return markedForSync;
3728
- })
3729
- .map(function (_g) {
3730
- var tbl = _g[0];
3731
- return db.table(tbl);
3732
- });
3733
- }
3734
- function getMutationTable(tableName) {
3735
- return "$" + tableName + "_mutations";
3736
- }
3737
- function getTableFromMutationTable(mutationTable) {
3738
- var _a;
3739
- var tableName = (_a = /^\$(.*)_mutations$/.exec(mutationTable)) === null || _a === void 0 ? void 0 : _a[1];
3740
- if (!tableName)
3741
- throw new Error("Given mutationTable " + mutationTable + " is not correct");
3742
- return tableName;
3743
- }
3744
- function listClientChanges(mutationTables, db, _g) {
3745
- var _h = _g === void 0 ? {} : _g, _j = _h.since, since = _j === void 0 ? {} : _j, _k = _h.limit, limit = _k === void 0 ? Infinity : _k;
3746
- return __awaiter(this, void 0, void 0, function () {
3747
- var allMutsOnTables;
3748
- var _this_1 = this;
3749
- return __generator(this, function (_l) {
3750
- switch (_l.label) {
3751
- case 0: return [4 /*yield*/, Promise.all(mutationTables.map(function (mutationTable) { return __awaiter(_this_1, void 0, void 0, function () {
3752
- var tableName, lastRevision, query, muts;
3753
- return __generator(this, function (_g) {
3754
- switch (_g.label) {
3755
- case 0:
3756
- tableName = getTableFromMutationTable(mutationTable.name);
3757
- lastRevision = since[tableName];
3758
- query = lastRevision
3759
- ? mutationTable.where("rev").above(lastRevision)
3760
- : mutationTable;
3761
- if (limit < Infinity)
3762
- query = query.limit(limit);
3763
- return [4 /*yield*/, query.toArray()];
3764
- case 1:
3765
- muts = _g.sent();
3766
- //const objTable = db.table(tableName);
3767
- /*for (const mut of muts) {
3768
- if (mut.type === "insert" || mut.type === "upsert") {
3769
- mut.values = await objTable.bulkGet(mut.keys);
3770
- }
3771
- }*/
3772
- return [2 /*return*/, {
3773
- table: tableName,
3774
- muts: muts,
3775
- }];
3776
- }
3777
- });
3778
- }); }))];
3779
- case 1:
3780
- allMutsOnTables = _l.sent();
3781
- // Filter out those tables that doesn't have any mutations:
3782
- return [2 /*return*/, allMutsOnTables.filter(function (_g) {
3783
- var muts = _g.muts;
3784
- return muts.length > 0;
3785
- })];
3786
- }
3787
- });
3788
- });
3789
- }
3790
- function listSyncifiedChanges(tablesToSyncify, currentUser, schema, alreadySyncedRealms) {
3791
- return __awaiter(this, void 0, void 0, function () {
3792
- var ignoredRealms_1, inserts;
3793
- var _this_1 = this;
3794
- return __generator(this, function (_g) {
3795
- switch (_g.label) {
3796
- case 0:
3797
- if (!currentUser.isLoggedIn) return [3 /*break*/, 2];
3798
- if (!(tablesToSyncify.length > 0)) return [3 /*break*/, 2];
3799
- ignoredRealms_1 = new Set(alreadySyncedRealms || []);
3800
- return [4 /*yield*/, Promise.all(tablesToSyncify.map(function (table) { return __awaiter(_this_1, void 0, void 0, function () {
3801
- var extractKey, dexieCloudTableSchema, query, unsyncedObjects, mut;
3802
- return __generator(this, function (_g) {
3803
- switch (_g.label) {
3804
- case 0:
3805
- extractKey = table.core.schema.primaryKey.extractKey;
3806
- if (!extractKey)
3807
- return [2 /*return*/, { table: table.name, muts: [] }]; // Outbound tables are not synced.
3808
- dexieCloudTableSchema = schema[table.name];
3809
- query = (dexieCloudTableSchema === null || dexieCloudTableSchema === void 0 ? void 0 : dexieCloudTableSchema.generatedGlobalId)
3810
- ? table.filter(function (item) { return !ignoredRealms_1.has(item.realmId || "") && isValidSyncableID(extractKey(item)); })
3811
- : table.filter(function (item) { return !ignoredRealms_1.has(item.realmId || "") && isValidAtID(extractKey(item), dexieCloudTableSchema === null || dexieCloudTableSchema === void 0 ? void 0 : dexieCloudTableSchema.idPrefix); });
3812
- return [4 /*yield*/, query.toArray()];
3813
- case 1:
3814
- unsyncedObjects = _g.sent();
3815
- if (unsyncedObjects.length > 0) {
3816
- mut = {
3817
- type: "insert",
3818
- values: unsyncedObjects,
3819
- keys: unsyncedObjects.map(extractKey),
3820
- userId: currentUser.userId,
3821
- };
3822
- return [2 /*return*/, {
3823
- table: table.name,
3824
- muts: [mut],
3825
- }];
3826
- }
3827
- else {
3828
- return [2 /*return*/, {
3829
- table: table.name,
3830
- muts: []
3831
- }];
3832
- }
3833
- }
3834
- });
3835
- }); }))];
3836
- case 1:
3837
- inserts = _g.sent();
3838
- return [2 /*return*/, inserts.filter(function (op) { return op.muts.length > 0; })];
3839
- case 2: return [2 /*return*/, []];
3840
- }
3841
- });
3842
- });
3843
- }
3844
- function getTablesToSyncify(db, syncState) {
3845
- var syncedTables = (syncState === null || syncState === void 0 ? void 0 : syncState.syncedTables) || [];
3846
- var syncableTables = getSyncableTables(db);
3847
- var tablesToSyncify = syncableTables.filter(function (tbl) { return !syncedTables.includes(tbl.name); });
3848
- return tablesToSyncify;
3849
- }
3850
3834
  //import {BisonWebStreamReader} from "dreambase-library/dist/typeson-simplified/BisonWebStreamReader";
3851
3835
  function syncWithServer(changes, syncState, baseRevs, db, databaseUrl, schema, clientIdentity) {
3852
3836
  return __awaiter(this, void 0, void 0, function () {
@@ -3865,6 +3849,7 @@
3865
3849
  headers.Authorization = "Bearer " + accessToken;
3866
3850
  }
3867
3851
  syncRequest = {
3852
+ v: 2,
3868
3853
  dbID: syncState === null || syncState === void 0 ? void 0 : syncState.remoteDbId,
3869
3854
  clientIdentity: clientIdentity,
3870
3855
  schema: schema || {},
@@ -4046,8 +4031,8 @@
4046
4031
  if (lastRevisions === void 0) { lastRevisions = {}; }
4047
4032
  for (var _g = 0, clientChangeSet_1 = clientChangeSet; _g < clientChangeSet_1.length; _g++) {
4048
4033
  var _h = clientChangeSet_1[_g], table = _h.table, muts = _h.muts;
4049
- var lastRev = muts.length > 0 ? muts[muts.length - 1].rev || 0 : 0;
4050
- lastRevisions[table] = lastRev;
4034
+ var lastRev = muts.length > 0 ? muts[muts.length - 1].rev : null;
4035
+ lastRevisions[table] = lastRev || lastRevisions[table] || 0;
4051
4036
  }
4052
4037
  return lastRevisions;
4053
4038
  }
@@ -4552,27 +4537,49 @@
4552
4537
  var readyToServe = new rxjs.BehaviorSubject(true);
4553
4538
  var event = new rxjs.BehaviorSubject(null);
4554
4539
  var isWorking = false;
4540
+ var loopWarning = 0;
4541
+ var loopDetection = [0, 0, 0, 0, 0, 0, 0, 0, 0, Date.now()];
4555
4542
  event.subscribe(function () { return __awaiter(_this_1, void 0, void 0, function () {
4556
4543
  return __generator(this, function (_g) {
4557
4544
  switch (_g.label) {
4558
4545
  case 0:
4559
4546
  if (isWorking)
4560
4547
  return [2 /*return*/];
4561
- if (!(queue.length > 0)) return [3 /*break*/, 4];
4548
+ if (!(queue.length > 0)) return [3 /*break*/, 8];
4562
4549
  isWorking = true;
4550
+ loopDetection.shift();
4551
+ loopDetection.push(Date.now());
4563
4552
  readyToServe.next(false);
4564
4553
  _g.label = 1;
4565
4554
  case 1:
4566
- _g.trys.push([1, , 3, 4]);
4555
+ _g.trys.push([1, , 3, 8]);
4567
4556
  return [4 /*yield*/, consumeQueue()];
4568
4557
  case 2:
4569
4558
  _g.sent();
4570
- return [3 /*break*/, 4];
4559
+ return [3 /*break*/, 8];
4571
4560
  case 3:
4561
+ if (!(loopDetection[loopDetection.length - 1] - loopDetection[0] < 10000)) return [3 /*break*/, 7];
4562
+ if (!(Date.now() - loopWarning < 5000)) return [3 /*break*/, 5];
4563
+ // Last time we did this, we ended up here too. Wait for a minute.
4564
+ console.warn("Slowing down websocket loop for one minute");
4565
+ loopWarning = Date.now() + 60000;
4566
+ return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(resolve, 60000); })];
4567
+ case 4:
4568
+ _g.sent();
4569
+ return [3 /*break*/, 7];
4570
+ case 5:
4571
+ // This is a one-time event. Just pause 10 seconds.
4572
+ console.warn("Slowing down websocket loop for 10 seconds");
4573
+ loopWarning = Date.now() + 10000;
4574
+ return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(resolve, 10000); })];
4575
+ case 6:
4576
+ _g.sent();
4577
+ _g.label = 7;
4578
+ case 7:
4572
4579
  isWorking = false;
4573
4580
  readyToServe.next(true);
4574
4581
  return [7 /*endfinally*/];
4575
- case 4: return [2 /*return*/];
4582
+ case 8: return [2 /*return*/];
4576
4583
  }
4577
4584
  });
4578
4585
  }); });
@@ -4597,6 +4604,9 @@
4597
4604
  case 1:
4598
4605
  _j.trys.push([1, 12, , 13]);
4599
4606
  console.debug('processing msg', msg);
4607
+ // If the sync worker or service worker is syncing, wait 'til thei're done.
4608
+ // It's no need to have two channels at the same time - even though it wouldnt
4609
+ // be a problem - this is an optimization.
4600
4610
  return [4 /*yield*/, db.cloud.syncState
4601
4611
  .pipe(filter(function (_g) {
4602
4612
  var phase = _g.phase;
@@ -4604,6 +4614,9 @@
4604
4614
  }), take(1))
4605
4615
  .toPromise()];
4606
4616
  case 2:
4617
+ // If the sync worker or service worker is syncing, wait 'til thei're done.
4618
+ // It's no need to have two channels at the same time - even though it wouldnt
4619
+ // be a problem - this is an optimization.
4607
4620
  _j.sent();
4608
4621
  console.debug('processing msg', msg);
4609
4622
  persistedSyncState = db.cloud.persistedSyncState.value;
@@ -4613,9 +4626,9 @@
4613
4626
  _h = msg.type;
4614
4627
  switch (_h) {
4615
4628
  case 'token-expired': return [3 /*break*/, 3];
4616
- case 'rev': return [3 /*break*/, 6];
4617
- case 'realm-added': return [3 /*break*/, 7];
4618
- case 'realm-removed': return [3 /*break*/, 8];
4629
+ case 'realm-added': return [3 /*break*/, 6];
4630
+ case 'realm-removed': return [3 /*break*/, 7];
4631
+ case 'realms-changed': return [3 /*break*/, 8];
4619
4632
  case 'changes': return [3 /*break*/, 9];
4620
4633
  }
4621
4634
  return [3 /*break*/, 11];
@@ -4638,25 +4651,22 @@
4638
4651
  // new token. So we don't need to do anything more here.
4639
4652
  return [3 /*break*/, 11];
4640
4653
  case 6:
4641
- if (!(persistedSyncState === null || persistedSyncState === void 0 ? void 0 : persistedSyncState.serverRevision) ||
4642
- compareBigInts(persistedSyncState.serverRevision, msg.rev) < 0) {
4643
- triggerSync(db, "pull");
4654
+ if (!((_a = persistedSyncState === null || persistedSyncState === void 0 ? void 0 : persistedSyncState.realms) === null || _a === void 0 ? void 0 : _a.includes(msg.realm))) {
4655
+ triggerSync(db, 'pull');
4644
4656
  }
4645
4657
  return [3 /*break*/, 11];
4646
4658
  case 7:
4647
- if (!((_a = persistedSyncState === null || persistedSyncState === void 0 ? void 0 : persistedSyncState.realms) === null || _a === void 0 ? void 0 : _a.includes(msg.realm))) {
4648
- triggerSync(db, "pull");
4659
+ if ((_b = persistedSyncState === null || persistedSyncState === void 0 ? void 0 : persistedSyncState.realms) === null || _b === void 0 ? void 0 : _b.includes(msg.realm)) {
4660
+ triggerSync(db, 'pull');
4649
4661
  }
4650
4662
  return [3 /*break*/, 11];
4651
4663
  case 8:
4652
- if ((_b = persistedSyncState === null || persistedSyncState === void 0 ? void 0 : persistedSyncState.realms) === null || _b === void 0 ? void 0 : _b.includes(msg.realm)) {
4653
- triggerSync(db, "pull");
4654
- }
4664
+ triggerSync(db, 'pull');
4655
4665
  return [3 /*break*/, 11];
4656
4666
  case 9:
4657
4667
  console.debug('changes');
4658
4668
  if (((_c = db.cloud.syncState.value) === null || _c === void 0 ? void 0 : _c.phase) === 'error') {
4659
- triggerSync(db, "pull");
4669
+ triggerSync(db, 'pull');
4660
4670
  return [3 /*break*/, 11];
4661
4671
  }
4662
4672
  return [4 /*yield*/, db.transaction('rw', db.dx.tables, function (tx) { return __awaiter(_this_1, void 0, void 0, function () {
@@ -4685,17 +4695,35 @@
4685
4695
  return [2 /*return*/]; // Initial sync must have taken place - otherwise, ignore this.
4686
4696
  }
4687
4697
  // Verify again in ACID tx that we're on same server revision.
4688
- if (compareBigInts(msg.baseRev, syncState.serverRevision) !== 0) {
4698
+ if (msg.baseRev !== syncState.serverRevision) {
4689
4699
  console.debug("baseRev (" + msg.baseRev + ") differs from our serverRevision in syncState (" + syncState.serverRevision + ")");
4700
+ // Should we trigger a sync now? No. This is a normal case
4701
+ // when another local peer (such as the SW or a websocket channel on other tab) has
4702
+ // updated syncState from new server information but we are not aware yet. It would
4703
+ // be unnescessary to do a sync in that case. Instead, the caller of this consumeQueue()
4704
+ // function will do readyToServe.next(true) right after this return, which will lead
4705
+ // to a "ready" message being sent to server with the new accurate serverRev we have,
4706
+ // so that the next message indeed will be correct.
4707
+ if (typeof msg.baseRev === 'string' && // v2 format
4708
+ (typeof syncState.serverRevision === 'bigint' || // v1 format
4709
+ typeof syncState.serverRevision === 'object') // v1 format old browser
4710
+ ) {
4711
+ // The reason for the diff seems to be that server has migrated the revision format.
4712
+ // Do a full sync to update revision format.
4713
+ // If we don't do a sync request now, we could stuck in an endless loop.
4714
+ triggerSync(db, 'pull');
4715
+ }
4690
4716
  return [2 /*return*/]; // Ignore message
4691
4717
  }
4692
- return [4 /*yield*/, Dexie__default['default'].waitFor(computeRealmSetHash(syncState))];
4718
+ return [4 /*yield*/, Dexie__default['default'].waitFor(
4719
+ // Keep TX in non-IDB work
4720
+ computeRealmSetHash(syncState))];
4693
4721
  case 2:
4694
4722
  ourRealmSetHash = _h.sent();
4695
4723
  console.debug('ourRealmSetHash', ourRealmSetHash);
4696
4724
  if (ourRealmSetHash !== msg.realmSetHash) {
4697
4725
  console.debug('not same realmSetHash', msg.realmSetHash);
4698
- triggerSync(db, "pull");
4726
+ triggerSync(db, 'pull');
4699
4727
  // The message isn't based on the same realms.
4700
4728
  // Trigger a sync instead to resolve all things up.
4701
4729
  return [2 /*return*/];
@@ -4709,6 +4737,7 @@
4709
4737
  console.debug('msg queue: client changes', clientChanges);
4710
4738
  _h.label = 4;
4711
4739
  case 4:
4740
+ if (!(msg.changes.length > 0)) return [3 /*break*/, 6];
4712
4741
  filteredChanges = filterServerChangesThroughAddedClientChanges(msg.changes, clientChanges);
4713
4742
  //
4714
4743
  // apply server changes
@@ -4717,6 +4746,8 @@
4717
4746
  return [4 /*yield*/, applyServerChanges(filteredChanges, db)];
4718
4747
  case 5:
4719
4748
  _h.sent();
4749
+ _h.label = 6;
4750
+ case 6:
4720
4751
  // Update latest revisions per table in case there are unsynced changes
4721
4752
  // This can be a real case in future when we allow non-eagery sync.
4722
4753
  // And it can actually be realistic now also, but very rare.
@@ -4725,14 +4756,14 @@
4725
4756
  // Update base revs
4726
4757
  console.debug('Updating baseRefs', syncState.latestRevisions);
4727
4758
  return [4 /*yield*/, updateBaseRevs(db, schema, syncState.latestRevisions, msg.newRev)];
4728
- case 6:
4759
+ case 7:
4729
4760
  _h.sent();
4730
4761
  //
4731
4762
  // Update syncState
4732
4763
  //
4733
4764
  console.debug('Updating syncState', syncState);
4734
4765
  return [4 /*yield*/, db.$syncState.put(syncState, 'syncState')];
4735
- case 7:
4766
+ case 8:
4736
4767
  _h.sent();
4737
4768
  return [2 /*return*/];
4738
4769
  }
@@ -5619,20 +5650,21 @@
5619
5650
  var FAIL_RETRY_WAIT_TIME = 60000;
5620
5651
  var WSObservable = /** @class */ (function (_super_1) {
5621
5652
  __extends$1(WSObservable, _super_1);
5622
- function WSObservable(databaseUrl, rev, clientIdentity, messageProducer, webSocketStatus, token, tokenExpiration) {
5623
- return _super_1.call(this, function (subscriber) { return new WSConnection(databaseUrl, rev, clientIdentity, token, tokenExpiration, subscriber, messageProducer, webSocketStatus); }) || this;
5653
+ function WSObservable(databaseUrl, rev, realmSetHash, clientIdentity, messageProducer, webSocketStatus, token, tokenExpiration) {
5654
+ return _super_1.call(this, function (subscriber) { return new WSConnection(databaseUrl, rev, realmSetHash, clientIdentity, token, tokenExpiration, subscriber, messageProducer, webSocketStatus); }) || this;
5624
5655
  }
5625
5656
  return WSObservable;
5626
5657
  }(rxjs.Observable));
5627
5658
  var counter = 0;
5628
5659
  var WSConnection = /** @class */ (function (_super_1) {
5629
5660
  __extends$1(WSConnection, _super_1);
5630
- function WSConnection(databaseUrl, rev, clientIdentity, token, tokenExpiration, subscriber, messageProducer, webSocketStatus) {
5661
+ function WSConnection(databaseUrl, rev, realmSetHash, clientIdentity, token, tokenExpiration, subscriber, messageProducer, webSocketStatus) {
5631
5662
  var _this_1 = _super_1.call(this, function () { return _this_1.teardown(); }) || this;
5632
5663
  _this_1.id = ++counter;
5633
5664
  console.debug('New WebSocket Connection', _this_1.id, token ? 'authorized' : 'unauthorized');
5634
5665
  _this_1.databaseUrl = databaseUrl;
5635
5666
  _this_1.rev = rev;
5667
+ _this_1.realmSetHash = realmSetHash;
5636
5668
  _this_1.clientIdentity = clientIdentity;
5637
5669
  _this_1.token = token;
5638
5670
  _this_1.tokenExpiration = tokenExpiration;
@@ -5747,7 +5779,9 @@
5747
5779
  searchParams = new URLSearchParams();
5748
5780
  if (this.subscriber.closed)
5749
5781
  return [2 /*return*/];
5782
+ searchParams.set('v', "2");
5750
5783
  searchParams.set('rev', this.rev);
5784
+ searchParams.set('realmsHash', this.realmSetHash);
5751
5785
  searchParams.set('clientId', this.clientIdentity);
5752
5786
  if (this.token) {
5753
5787
  searchParams.set('token', this.token);
@@ -5864,12 +5898,26 @@
5864
5898
  var _this_1 = this;
5865
5899
  return db.cloud.persistedSyncState.pipe(filter(function (syncState) { return syncState === null || syncState === void 0 ? void 0 : syncState.serverRevision; }), // Don't connect before there's no initial sync performed.
5866
5900
  take(1), // Don't continue waking up whenever syncState change
5867
- switchMap(function () { return db.cloud.currentUser; }), switchMap(function (userLogin) { return userIsReallyActive.pipe(map(function (isActive) { return (isActive ? userLogin : null); })); }), switchMap(function (userLogin) {
5901
+ switchMap(function (syncState) { return db.cloud.currentUser.pipe(map(function (userLogin) { return [userLogin, syncState]; })); }), switchMap(function (_g) {
5902
+ var userLogin = _g[0], syncState = _g[1];
5903
+ return userIsReallyActive.pipe(map(function (isActive) { return [isActive ? userLogin : null, syncState]; }));
5904
+ }), switchMap(function (_g) {
5905
+ var userLogin = _g[0], syncState = _g[1];
5906
+ return __awaiter(_this_1, void 0, void 0, function () { var _h; return __generator(this, function (_j) {
5907
+ switch (_j.label) {
5908
+ case 0:
5909
+ _h = [userLogin];
5910
+ return [4 /*yield*/, computeRealmSetHash(syncState)];
5911
+ case 1: return [2 /*return*/, _h.concat([_j.sent()])];
5912
+ }
5913
+ }); });
5914
+ }), switchMap(function (_g) {
5915
+ var userLogin = _g[0], realmSetHash = _g[1];
5868
5916
  // Let server end query changes from last entry of same client-ID and forward.
5869
5917
  // If no new entries, server won't bother the client. If new entries, server sends only those
5870
5918
  // and the baseRev of the last from same client-ID.
5871
5919
  return userLogin
5872
- ? new WSObservable(db.cloud.options.databaseUrl, db.cloud.persistedSyncState.value.serverRevision, db.cloud.persistedSyncState.value.clientIdentity, messageProducer, db.cloud.webSocketStatus, userLogin.accessToken, userLogin.accessTokenExpiration)
5920
+ ? new WSObservable(db.cloud.options.databaseUrl, db.cloud.persistedSyncState.value.serverRevision, realmSetHash, db.cloud.persistedSyncState.value.clientIdentity, messageProducer, db.cloud.webSocketStatus, userLogin.accessToken, userLogin.accessTokenExpiration)
5873
5921
  : rxjs.from([]);
5874
5922
  }), catchError(function (error) {
5875
5923
  if ((error === null || error === void 0 ? void 0 : error.name) === 'TokenExpiredError') {
@@ -6025,22 +6073,26 @@
6025
6073
  var cancelToken = { cancelled: false };
6026
6074
  function syncAndRetry(purpose, retryNum) {
6027
6075
  if (retryNum === void 0) { retryNum = 1; }
6028
- syncIfPossible(db, cloudOptions, cloudSchema, {
6029
- cancelToken: cancelToken,
6030
- retryImmediatelyOnFetchError: true,
6031
- purpose: purpose
6032
- }).catch(function (e) {
6033
- console.error('error in syncIfPossible()', e);
6034
- if (cancelToken.cancelled) {
6035
- stop();
6036
- }
6037
- else if (retryNum < 3) {
6038
- // Mimic service worker sync event: retry 3 times
6039
- // * first retry after 5 minutes
6040
- // * second retry 15 minutes later
6041
- setTimeout(function () { return syncAndRetry(purpose, retryNum + 1); }, [0, 5, 15][retryNum] * MINUTES);
6042
- }
6043
- });
6076
+ // Use setTimeout() to get onto a clean stack and
6077
+ // break free from possible active transaction:
6078
+ setTimeout(function () {
6079
+ syncIfPossible(db, cloudOptions, cloudSchema, {
6080
+ cancelToken: cancelToken,
6081
+ retryImmediatelyOnFetchError: true,
6082
+ purpose: purpose,
6083
+ }).catch(function (e) {
6084
+ console.error('error in syncIfPossible()', e);
6085
+ if (cancelToken.cancelled) {
6086
+ stop();
6087
+ }
6088
+ else if (retryNum < 3) {
6089
+ // Mimic service worker sync event: retry 3 times
6090
+ // * first retry after 5 minutes
6091
+ // * second retry 15 minutes later
6092
+ setTimeout(function () { return syncAndRetry(purpose, retryNum + 1); }, [0, 5, 15][retryNum] * MINUTES);
6093
+ }
6094
+ });
6095
+ }, 0);
6044
6096
  }
6045
6097
  var start = function () {
6046
6098
  // Sync eagerly whenever a change has happened (+ initially when there's no syncState yet)
@@ -6049,7 +6101,7 @@
6049
6101
  localSyncEventSubscription = db.localSyncEvent.subscribe(function (_g) {
6050
6102
  var purpose = _g.purpose;
6051
6103
  try {
6052
- syncAndRetry(purpose || "pull");
6104
+ syncAndRetry(purpose || 'pull');
6053
6105
  }
6054
6106
  catch (err) {
6055
6107
  console.error('What-the....', err);