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
@@ -97,7 +97,7 @@ function __spreadArray(to, from) {
97
97
  *
98
98
  * ==========================================================================
99
99
  *
100
- * Version 1.0.0-beta.10, Wed Sep 08 2021
100
+ * Version 1.0.0-beta.10, Wed Oct 06 2021
101
101
  *
102
102
  * https://dexie.org
103
103
  *
@@ -3135,6 +3135,151 @@ var BroadcastedAndLocalEvent = /** @class */ (function (_super_1) {
3135
3135
  };
3136
3136
  return BroadcastedAndLocalEvent;
3137
3137
  }(Observable$1));
3138
+ function computeRealmSetHash(_g) {
3139
+ var realms = _g.realms, inviteRealms = _g.inviteRealms;
3140
+ return __awaiter(this, void 0, void 0, function () {
3141
+ var data, byteArray, digestBytes, base64;
3142
+ return __generator(this, function (_h) {
3143
+ switch (_h.label) {
3144
+ case 0:
3145
+ 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; }));
3146
+ byteArray = new TextEncoder().encode(data);
3147
+ return [4 /*yield*/, crypto.subtle.digest('SHA-1', byteArray)];
3148
+ case 1:
3149
+ digestBytes = _h.sent();
3150
+ base64 = b64encode(digestBytes);
3151
+ return [2 /*return*/, base64];
3152
+ }
3153
+ });
3154
+ });
3155
+ }
3156
+ function getSyncableTables(db) {
3157
+ return Object.entries(db.cloud.schema || {})
3158
+ .filter(function (_g) {
3159
+ var markedForSync = _g[1].markedForSync;
3160
+ return markedForSync;
3161
+ })
3162
+ .map(function (_g) {
3163
+ var tbl = _g[0];
3164
+ return db.table(tbl);
3165
+ });
3166
+ }
3167
+ function getMutationTable(tableName) {
3168
+ return "$" + tableName + "_mutations";
3169
+ }
3170
+ function getTableFromMutationTable(mutationTable) {
3171
+ var _a;
3172
+ var tableName = (_a = /^\$(.*)_mutations$/.exec(mutationTable)) === null || _a === void 0 ? void 0 : _a[1];
3173
+ if (!tableName)
3174
+ throw new Error("Given mutationTable " + mutationTable + " is not correct");
3175
+ return tableName;
3176
+ }
3177
+ function listClientChanges(mutationTables, db, _g) {
3178
+ var _h = _g === void 0 ? {} : _g, _j = _h.since, since = _j === void 0 ? {} : _j, _k = _h.limit, limit = _k === void 0 ? Infinity : _k;
3179
+ return __awaiter(this, void 0, void 0, function () {
3180
+ var allMutsOnTables;
3181
+ var _this_1 = this;
3182
+ return __generator(this, function (_l) {
3183
+ switch (_l.label) {
3184
+ case 0: return [4 /*yield*/, Promise.all(mutationTables.map(function (mutationTable) { return __awaiter(_this_1, void 0, void 0, function () {
3185
+ var tableName, lastRevision, query, muts;
3186
+ return __generator(this, function (_g) {
3187
+ switch (_g.label) {
3188
+ case 0:
3189
+ tableName = getTableFromMutationTable(mutationTable.name);
3190
+ lastRevision = since[tableName];
3191
+ query = lastRevision
3192
+ ? mutationTable.where("rev").above(lastRevision)
3193
+ : mutationTable;
3194
+ if (limit < Infinity)
3195
+ query = query.limit(limit);
3196
+ return [4 /*yield*/, query.toArray()];
3197
+ case 1:
3198
+ muts = _g.sent();
3199
+ //const objTable = db.table(tableName);
3200
+ /*for (const mut of muts) {
3201
+ if (mut.type === "insert" || mut.type === "upsert") {
3202
+ mut.values = await objTable.bulkGet(mut.keys);
3203
+ }
3204
+ }*/
3205
+ return [2 /*return*/, {
3206
+ table: tableName,
3207
+ muts: muts,
3208
+ }];
3209
+ }
3210
+ });
3211
+ }); }))];
3212
+ case 1:
3213
+ allMutsOnTables = _l.sent();
3214
+ // Filter out those tables that doesn't have any mutations:
3215
+ return [2 /*return*/, allMutsOnTables.filter(function (_g) {
3216
+ var muts = _g.muts;
3217
+ return muts.length > 0;
3218
+ })];
3219
+ }
3220
+ });
3221
+ });
3222
+ }
3223
+ function listSyncifiedChanges(tablesToSyncify, currentUser, schema, alreadySyncedRealms) {
3224
+ return __awaiter(this, void 0, void 0, function () {
3225
+ var ignoredRealms_1, inserts;
3226
+ var _this_1 = this;
3227
+ return __generator(this, function (_g) {
3228
+ switch (_g.label) {
3229
+ case 0:
3230
+ if (!currentUser.isLoggedIn) return [3 /*break*/, 2];
3231
+ if (!(tablesToSyncify.length > 0)) return [3 /*break*/, 2];
3232
+ ignoredRealms_1 = new Set(alreadySyncedRealms || []);
3233
+ return [4 /*yield*/, Promise.all(tablesToSyncify.map(function (table) { return __awaiter(_this_1, void 0, void 0, function () {
3234
+ var extractKey, dexieCloudTableSchema, query, unsyncedObjects, mut;
3235
+ return __generator(this, function (_g) {
3236
+ switch (_g.label) {
3237
+ case 0:
3238
+ extractKey = table.core.schema.primaryKey.extractKey;
3239
+ if (!extractKey)
3240
+ return [2 /*return*/, { table: table.name, muts: [] }]; // Outbound tables are not synced.
3241
+ dexieCloudTableSchema = schema[table.name];
3242
+ query = (dexieCloudTableSchema === null || dexieCloudTableSchema === void 0 ? void 0 : dexieCloudTableSchema.generatedGlobalId)
3243
+ ? table.filter(function (item) { return !ignoredRealms_1.has(item.realmId || "") && isValidSyncableID(extractKey(item)); })
3244
+ : table.filter(function (item) { return !ignoredRealms_1.has(item.realmId || "") && isValidAtID(extractKey(item), dexieCloudTableSchema === null || dexieCloudTableSchema === void 0 ? void 0 : dexieCloudTableSchema.idPrefix); });
3245
+ return [4 /*yield*/, query.toArray()];
3246
+ case 1:
3247
+ unsyncedObjects = _g.sent();
3248
+ if (unsyncedObjects.length > 0) {
3249
+ mut = {
3250
+ type: "insert",
3251
+ values: unsyncedObjects,
3252
+ keys: unsyncedObjects.map(extractKey),
3253
+ userId: currentUser.userId,
3254
+ };
3255
+ return [2 /*return*/, {
3256
+ table: table.name,
3257
+ muts: [mut],
3258
+ }];
3259
+ }
3260
+ else {
3261
+ return [2 /*return*/, {
3262
+ table: table.name,
3263
+ muts: []
3264
+ }];
3265
+ }
3266
+ }
3267
+ });
3268
+ }); }))];
3269
+ case 1:
3270
+ inserts = _g.sent();
3271
+ return [2 /*return*/, inserts.filter(function (op) { return op.muts.length > 0; })];
3272
+ case 2: return [2 /*return*/, []];
3273
+ }
3274
+ });
3275
+ });
3276
+ }
3277
+ function getTablesToSyncify(db, syncState) {
3278
+ var syncedTables = (syncState === null || syncState === void 0 ? void 0 : syncState.syncedTables) || [];
3279
+ var syncableTables = getSyncableTables(db);
3280
+ var tablesToSyncify = syncableTables.filter(function (tbl) { return !syncedTables.includes(tbl.name); });
3281
+ return tablesToSyncify;
3282
+ }
3138
3283
  var toStr = {}.toString;
3139
3284
  function getToStringTag(val) {
3140
3285
  return toStr.call(val).slice(8, -1);
@@ -3654,22 +3799,6 @@ var undefinedDef = {
3654
3799
  // else
3655
3800
  // serverRev.rev = new FakeBigInt(server.rev)
3656
3801
  var hasBigIntSupport = typeof BigInt(0) === 'bigint';
3657
- function getValueOfBigInt(x) {
3658
- if (typeof x === 'bigint') {
3659
- return x;
3660
- }
3661
- if (hasBigIntSupport) {
3662
- return typeof x === 'string' ? BigInt(x) : BigInt(x.v);
3663
- }
3664
- else {
3665
- return typeof x === 'string' ? Number(x) : Number(x.v);
3666
- }
3667
- }
3668
- function compareBigInts(a, b) {
3669
- var valA = getValueOfBigInt(a);
3670
- var valB = getValueOfBigInt(b);
3671
- return valA < valB ? -1 : valA > valB ? 1 : 0;
3672
- }
3673
3802
  var FakeBigInt = /** @class */ (function () {
3674
3803
  function FakeBigInt(value) {
3675
3804
  this.v = value;
@@ -3695,151 +3824,6 @@ var defs = __assign(__assign({}, undefinedDef), (hasBigIntSupport
3695
3824
  }));
3696
3825
  var TSON = TypesonSimplified(builtin, defs);
3697
3826
  var BISON = Bison(defs);
3698
- function computeRealmSetHash(_g) {
3699
- var realms = _g.realms, inviteRealms = _g.inviteRealms;
3700
- return __awaiter(this, void 0, void 0, function () {
3701
- var data, byteArray, digestBytes, base64;
3702
- return __generator(this, function (_h) {
3703
- switch (_h.label) {
3704
- case 0:
3705
- 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; }));
3706
- byteArray = new TextEncoder().encode(data);
3707
- return [4 /*yield*/, crypto.subtle.digest('SHA-1', byteArray)];
3708
- case 1:
3709
- digestBytes = _h.sent();
3710
- base64 = b64encode(digestBytes);
3711
- return [2 /*return*/, base64];
3712
- }
3713
- });
3714
- });
3715
- }
3716
- function getSyncableTables(db) {
3717
- return Object.entries(db.cloud.schema || {})
3718
- .filter(function (_g) {
3719
- var markedForSync = _g[1].markedForSync;
3720
- return markedForSync;
3721
- })
3722
- .map(function (_g) {
3723
- var tbl = _g[0];
3724
- return db.table(tbl);
3725
- });
3726
- }
3727
- function getMutationTable(tableName) {
3728
- return "$" + tableName + "_mutations";
3729
- }
3730
- function getTableFromMutationTable(mutationTable) {
3731
- var _a;
3732
- var tableName = (_a = /^\$(.*)_mutations$/.exec(mutationTable)) === null || _a === void 0 ? void 0 : _a[1];
3733
- if (!tableName)
3734
- throw new Error("Given mutationTable " + mutationTable + " is not correct");
3735
- return tableName;
3736
- }
3737
- function listClientChanges(mutationTables, db, _g) {
3738
- var _h = _g === void 0 ? {} : _g, _j = _h.since, since = _j === void 0 ? {} : _j, _k = _h.limit, limit = _k === void 0 ? Infinity : _k;
3739
- return __awaiter(this, void 0, void 0, function () {
3740
- var allMutsOnTables;
3741
- var _this_1 = this;
3742
- return __generator(this, function (_l) {
3743
- switch (_l.label) {
3744
- case 0: return [4 /*yield*/, Promise.all(mutationTables.map(function (mutationTable) { return __awaiter(_this_1, void 0, void 0, function () {
3745
- var tableName, lastRevision, query, muts;
3746
- return __generator(this, function (_g) {
3747
- switch (_g.label) {
3748
- case 0:
3749
- tableName = getTableFromMutationTable(mutationTable.name);
3750
- lastRevision = since[tableName];
3751
- query = lastRevision
3752
- ? mutationTable.where("rev").above(lastRevision)
3753
- : mutationTable;
3754
- if (limit < Infinity)
3755
- query = query.limit(limit);
3756
- return [4 /*yield*/, query.toArray()];
3757
- case 1:
3758
- muts = _g.sent();
3759
- //const objTable = db.table(tableName);
3760
- /*for (const mut of muts) {
3761
- if (mut.type === "insert" || mut.type === "upsert") {
3762
- mut.values = await objTable.bulkGet(mut.keys);
3763
- }
3764
- }*/
3765
- return [2 /*return*/, {
3766
- table: tableName,
3767
- muts: muts,
3768
- }];
3769
- }
3770
- });
3771
- }); }))];
3772
- case 1:
3773
- allMutsOnTables = _l.sent();
3774
- // Filter out those tables that doesn't have any mutations:
3775
- return [2 /*return*/, allMutsOnTables.filter(function (_g) {
3776
- var muts = _g.muts;
3777
- return muts.length > 0;
3778
- })];
3779
- }
3780
- });
3781
- });
3782
- }
3783
- function listSyncifiedChanges(tablesToSyncify, currentUser, schema, alreadySyncedRealms) {
3784
- return __awaiter(this, void 0, void 0, function () {
3785
- var ignoredRealms_1, inserts;
3786
- var _this_1 = this;
3787
- return __generator(this, function (_g) {
3788
- switch (_g.label) {
3789
- case 0:
3790
- if (!currentUser.isLoggedIn) return [3 /*break*/, 2];
3791
- if (!(tablesToSyncify.length > 0)) return [3 /*break*/, 2];
3792
- ignoredRealms_1 = new Set(alreadySyncedRealms || []);
3793
- return [4 /*yield*/, Promise.all(tablesToSyncify.map(function (table) { return __awaiter(_this_1, void 0, void 0, function () {
3794
- var extractKey, dexieCloudTableSchema, query, unsyncedObjects, mut;
3795
- return __generator(this, function (_g) {
3796
- switch (_g.label) {
3797
- case 0:
3798
- extractKey = table.core.schema.primaryKey.extractKey;
3799
- if (!extractKey)
3800
- return [2 /*return*/, { table: table.name, muts: [] }]; // Outbound tables are not synced.
3801
- dexieCloudTableSchema = schema[table.name];
3802
- query = (dexieCloudTableSchema === null || dexieCloudTableSchema === void 0 ? void 0 : dexieCloudTableSchema.generatedGlobalId)
3803
- ? table.filter(function (item) { return !ignoredRealms_1.has(item.realmId || "") && isValidSyncableID(extractKey(item)); })
3804
- : table.filter(function (item) { return !ignoredRealms_1.has(item.realmId || "") && isValidAtID(extractKey(item), dexieCloudTableSchema === null || dexieCloudTableSchema === void 0 ? void 0 : dexieCloudTableSchema.idPrefix); });
3805
- return [4 /*yield*/, query.toArray()];
3806
- case 1:
3807
- unsyncedObjects = _g.sent();
3808
- if (unsyncedObjects.length > 0) {
3809
- mut = {
3810
- type: "insert",
3811
- values: unsyncedObjects,
3812
- keys: unsyncedObjects.map(extractKey),
3813
- userId: currentUser.userId,
3814
- };
3815
- return [2 /*return*/, {
3816
- table: table.name,
3817
- muts: [mut],
3818
- }];
3819
- }
3820
- else {
3821
- return [2 /*return*/, {
3822
- table: table.name,
3823
- muts: []
3824
- }];
3825
- }
3826
- }
3827
- });
3828
- }); }))];
3829
- case 1:
3830
- inserts = _g.sent();
3831
- return [2 /*return*/, inserts.filter(function (op) { return op.muts.length > 0; })];
3832
- case 2: return [2 /*return*/, []];
3833
- }
3834
- });
3835
- });
3836
- }
3837
- function getTablesToSyncify(db, syncState) {
3838
- var syncedTables = (syncState === null || syncState === void 0 ? void 0 : syncState.syncedTables) || [];
3839
- var syncableTables = getSyncableTables(db);
3840
- var tablesToSyncify = syncableTables.filter(function (tbl) { return !syncedTables.includes(tbl.name); });
3841
- return tablesToSyncify;
3842
- }
3843
3827
  //import {BisonWebStreamReader} from "dreambase-library/dist/typeson-simplified/BisonWebStreamReader";
3844
3828
  function syncWithServer(changes, syncState, baseRevs, db, databaseUrl, schema, clientIdentity) {
3845
3829
  return __awaiter(this, void 0, void 0, function () {
@@ -3858,6 +3842,7 @@ function syncWithServer(changes, syncState, baseRevs, db, databaseUrl, schema, c
3858
3842
  headers.Authorization = "Bearer " + accessToken;
3859
3843
  }
3860
3844
  syncRequest = {
3845
+ v: 2,
3861
3846
  dbID: syncState === null || syncState === void 0 ? void 0 : syncState.remoteDbId,
3862
3847
  clientIdentity: clientIdentity,
3863
3848
  schema: schema || {},
@@ -4039,8 +4024,8 @@ function getLatestRevisionsPerTable(clientChangeSet, lastRevisions) {
4039
4024
  if (lastRevisions === void 0) { lastRevisions = {}; }
4040
4025
  for (var _g = 0, clientChangeSet_1 = clientChangeSet; _g < clientChangeSet_1.length; _g++) {
4041
4026
  var _h = clientChangeSet_1[_g], table = _h.table, muts = _h.muts;
4042
- var lastRev = muts.length > 0 ? muts[muts.length - 1].rev || 0 : 0;
4043
- lastRevisions[table] = lastRev;
4027
+ var lastRev = muts.length > 0 ? muts[muts.length - 1].rev : null;
4028
+ lastRevisions[table] = lastRev || lastRevisions[table] || 0;
4044
4029
  }
4045
4030
  return lastRevisions;
4046
4031
  }
@@ -4545,27 +4530,49 @@ function MessagesFromServerConsumer(db) {
4545
4530
  var readyToServe = new BehaviorSubject(true);
4546
4531
  var event = new BehaviorSubject(null);
4547
4532
  var isWorking = false;
4533
+ var loopWarning = 0;
4534
+ var loopDetection = [0, 0, 0, 0, 0, 0, 0, 0, 0, Date.now()];
4548
4535
  event.subscribe(function () { return __awaiter(_this_1, void 0, void 0, function () {
4549
4536
  return __generator(this, function (_g) {
4550
4537
  switch (_g.label) {
4551
4538
  case 0:
4552
4539
  if (isWorking)
4553
4540
  return [2 /*return*/];
4554
- if (!(queue.length > 0)) return [3 /*break*/, 4];
4541
+ if (!(queue.length > 0)) return [3 /*break*/, 8];
4555
4542
  isWorking = true;
4543
+ loopDetection.shift();
4544
+ loopDetection.push(Date.now());
4556
4545
  readyToServe.next(false);
4557
4546
  _g.label = 1;
4558
4547
  case 1:
4559
- _g.trys.push([1, , 3, 4]);
4548
+ _g.trys.push([1, , 3, 8]);
4560
4549
  return [4 /*yield*/, consumeQueue()];
4561
4550
  case 2:
4562
4551
  _g.sent();
4563
- return [3 /*break*/, 4];
4552
+ return [3 /*break*/, 8];
4564
4553
  case 3:
4554
+ if (!(loopDetection[loopDetection.length - 1] - loopDetection[0] < 10000)) return [3 /*break*/, 7];
4555
+ if (!(Date.now() - loopWarning < 5000)) return [3 /*break*/, 5];
4556
+ // Last time we did this, we ended up here too. Wait for a minute.
4557
+ console.warn("Slowing down websocket loop for one minute");
4558
+ loopWarning = Date.now() + 60000;
4559
+ return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(resolve, 60000); })];
4560
+ case 4:
4561
+ _g.sent();
4562
+ return [3 /*break*/, 7];
4563
+ case 5:
4564
+ // This is a one-time event. Just pause 10 seconds.
4565
+ console.warn("Slowing down websocket loop for 10 seconds");
4566
+ loopWarning = Date.now() + 10000;
4567
+ return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(resolve, 10000); })];
4568
+ case 6:
4569
+ _g.sent();
4570
+ _g.label = 7;
4571
+ case 7:
4565
4572
  isWorking = false;
4566
4573
  readyToServe.next(true);
4567
4574
  return [7 /*endfinally*/];
4568
- case 4: return [2 /*return*/];
4575
+ case 8: return [2 /*return*/];
4569
4576
  }
4570
4577
  });
4571
4578
  }); });
@@ -4590,6 +4597,9 @@ function MessagesFromServerConsumer(db) {
4590
4597
  case 1:
4591
4598
  _j.trys.push([1, 12, , 13]);
4592
4599
  console.debug('processing msg', msg);
4600
+ // If the sync worker or service worker is syncing, wait 'til thei're done.
4601
+ // It's no need to have two channels at the same time - even though it wouldnt
4602
+ // be a problem - this is an optimization.
4593
4603
  return [4 /*yield*/, db.cloud.syncState
4594
4604
  .pipe(filter(function (_g) {
4595
4605
  var phase = _g.phase;
@@ -4597,6 +4607,9 @@ function MessagesFromServerConsumer(db) {
4597
4607
  }), take(1))
4598
4608
  .toPromise()];
4599
4609
  case 2:
4610
+ // If the sync worker or service worker is syncing, wait 'til thei're done.
4611
+ // It's no need to have two channels at the same time - even though it wouldnt
4612
+ // be a problem - this is an optimization.
4600
4613
  _j.sent();
4601
4614
  console.debug('processing msg', msg);
4602
4615
  persistedSyncState = db.cloud.persistedSyncState.value;
@@ -4606,9 +4619,9 @@ function MessagesFromServerConsumer(db) {
4606
4619
  _h = msg.type;
4607
4620
  switch (_h) {
4608
4621
  case 'token-expired': return [3 /*break*/, 3];
4609
- case 'rev': return [3 /*break*/, 6];
4610
- case 'realm-added': return [3 /*break*/, 7];
4611
- case 'realm-removed': return [3 /*break*/, 8];
4622
+ case 'realm-added': return [3 /*break*/, 6];
4623
+ case 'realm-removed': return [3 /*break*/, 7];
4624
+ case 'realms-changed': return [3 /*break*/, 8];
4612
4625
  case 'changes': return [3 /*break*/, 9];
4613
4626
  }
4614
4627
  return [3 /*break*/, 11];
@@ -4631,25 +4644,22 @@ function MessagesFromServerConsumer(db) {
4631
4644
  // new token. So we don't need to do anything more here.
4632
4645
  return [3 /*break*/, 11];
4633
4646
  case 6:
4634
- if (!(persistedSyncState === null || persistedSyncState === void 0 ? void 0 : persistedSyncState.serverRevision) ||
4635
- compareBigInts(persistedSyncState.serverRevision, msg.rev) < 0) {
4636
- triggerSync(db, "pull");
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');
4637
4649
  }
4638
4650
  return [3 /*break*/, 11];
4639
4651
  case 7:
4640
- if (!((_a = persistedSyncState === null || persistedSyncState === void 0 ? void 0 : persistedSyncState.realms) === null || _a === void 0 ? void 0 : _a.includes(msg.realm))) {
4641
- triggerSync(db, "pull");
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');
4642
4654
  }
4643
4655
  return [3 /*break*/, 11];
4644
4656
  case 8:
4645
- if ((_b = persistedSyncState === null || persistedSyncState === void 0 ? void 0 : persistedSyncState.realms) === null || _b === void 0 ? void 0 : _b.includes(msg.realm)) {
4646
- triggerSync(db, "pull");
4647
- }
4657
+ triggerSync(db, 'pull');
4648
4658
  return [3 /*break*/, 11];
4649
4659
  case 9:
4650
4660
  console.debug('changes');
4651
4661
  if (((_c = db.cloud.syncState.value) === null || _c === void 0 ? void 0 : _c.phase) === 'error') {
4652
- triggerSync(db, "pull");
4662
+ triggerSync(db, 'pull');
4653
4663
  return [3 /*break*/, 11];
4654
4664
  }
4655
4665
  return [4 /*yield*/, db.transaction('rw', db.dx.tables, function (tx) { return __awaiter(_this_1, void 0, void 0, function () {
@@ -4678,17 +4688,35 @@ function MessagesFromServerConsumer(db) {
4678
4688
  return [2 /*return*/]; // Initial sync must have taken place - otherwise, ignore this.
4679
4689
  }
4680
4690
  // Verify again in ACID tx that we're on same server revision.
4681
- if (compareBigInts(msg.baseRev, syncState.serverRevision) !== 0) {
4691
+ if (msg.baseRev !== syncState.serverRevision) {
4682
4692
  console.debug("baseRev (" + msg.baseRev + ") differs from our serverRevision in syncState (" + syncState.serverRevision + ")");
4693
+ // Should we trigger a sync now? No. This is a normal case
4694
+ // when another local peer (such as the SW or a websocket channel on other tab) has
4695
+ // updated syncState from new server information but we are not aware yet. It would
4696
+ // be unnescessary to do a sync in that case. Instead, the caller of this consumeQueue()
4697
+ // function will do readyToServe.next(true) right after this return, which will lead
4698
+ // to a "ready" message being sent to server with the new accurate serverRev we have,
4699
+ // so that the next message indeed will be correct.
4700
+ if (typeof msg.baseRev === 'string' && // v2 format
4701
+ (typeof syncState.serverRevision === 'bigint' || // v1 format
4702
+ typeof syncState.serverRevision === 'object') // v1 format old browser
4703
+ ) {
4704
+ // The reason for the diff seems to be that server has migrated the revision format.
4705
+ // Do a full sync to update revision format.
4706
+ // If we don't do a sync request now, we could stuck in an endless loop.
4707
+ triggerSync(db, 'pull');
4708
+ }
4683
4709
  return [2 /*return*/]; // Ignore message
4684
4710
  }
4685
- return [4 /*yield*/, Dexie.waitFor(computeRealmSetHash(syncState))];
4711
+ return [4 /*yield*/, Dexie.waitFor(
4712
+ // Keep TX in non-IDB work
4713
+ computeRealmSetHash(syncState))];
4686
4714
  case 2:
4687
4715
  ourRealmSetHash = _h.sent();
4688
4716
  console.debug('ourRealmSetHash', ourRealmSetHash);
4689
4717
  if (ourRealmSetHash !== msg.realmSetHash) {
4690
4718
  console.debug('not same realmSetHash', msg.realmSetHash);
4691
- triggerSync(db, "pull");
4719
+ triggerSync(db, 'pull');
4692
4720
  // The message isn't based on the same realms.
4693
4721
  // Trigger a sync instead to resolve all things up.
4694
4722
  return [2 /*return*/];
@@ -4702,6 +4730,7 @@ function MessagesFromServerConsumer(db) {
4702
4730
  console.debug('msg queue: client changes', clientChanges);
4703
4731
  _h.label = 4;
4704
4732
  case 4:
4733
+ if (!(msg.changes.length > 0)) return [3 /*break*/, 6];
4705
4734
  filteredChanges = filterServerChangesThroughAddedClientChanges(msg.changes, clientChanges);
4706
4735
  //
4707
4736
  // apply server changes
@@ -4710,6 +4739,8 @@ function MessagesFromServerConsumer(db) {
4710
4739
  return [4 /*yield*/, applyServerChanges(filteredChanges, db)];
4711
4740
  case 5:
4712
4741
  _h.sent();
4742
+ _h.label = 6;
4743
+ case 6:
4713
4744
  // Update latest revisions per table in case there are unsynced changes
4714
4745
  // This can be a real case in future when we allow non-eagery sync.
4715
4746
  // And it can actually be realistic now also, but very rare.
@@ -4718,14 +4749,14 @@ function MessagesFromServerConsumer(db) {
4718
4749
  // Update base revs
4719
4750
  console.debug('Updating baseRefs', syncState.latestRevisions);
4720
4751
  return [4 /*yield*/, updateBaseRevs(db, schema, syncState.latestRevisions, msg.newRev)];
4721
- case 6:
4752
+ case 7:
4722
4753
  _h.sent();
4723
4754
  //
4724
4755
  // Update syncState
4725
4756
  //
4726
4757
  console.debug('Updating syncState', syncState);
4727
4758
  return [4 /*yield*/, db.$syncState.put(syncState, 'syncState')];
4728
- case 7:
4759
+ case 8:
4729
4760
  _h.sent();
4730
4761
  return [2 /*return*/];
4731
4762
  }
@@ -5612,20 +5643,21 @@ var CLIENT_PING_INTERVAL = 30000;
5612
5643
  var FAIL_RETRY_WAIT_TIME = 60000;
5613
5644
  var WSObservable = /** @class */ (function (_super_1) {
5614
5645
  __extends$1(WSObservable, _super_1);
5615
- function WSObservable(databaseUrl, rev, clientIdentity, messageProducer, webSocketStatus, token, tokenExpiration) {
5616
- return _super_1.call(this, function (subscriber) { return new WSConnection(databaseUrl, rev, clientIdentity, token, tokenExpiration, subscriber, messageProducer, webSocketStatus); }) || this;
5646
+ function WSObservable(databaseUrl, rev, realmSetHash, clientIdentity, messageProducer, webSocketStatus, token, tokenExpiration) {
5647
+ return _super_1.call(this, function (subscriber) { return new WSConnection(databaseUrl, rev, realmSetHash, clientIdentity, token, tokenExpiration, subscriber, messageProducer, webSocketStatus); }) || this;
5617
5648
  }
5618
5649
  return WSObservable;
5619
5650
  }(Observable$1));
5620
5651
  var counter = 0;
5621
5652
  var WSConnection = /** @class */ (function (_super_1) {
5622
5653
  __extends$1(WSConnection, _super_1);
5623
- function WSConnection(databaseUrl, rev, clientIdentity, token, tokenExpiration, subscriber, messageProducer, webSocketStatus) {
5654
+ function WSConnection(databaseUrl, rev, realmSetHash, clientIdentity, token, tokenExpiration, subscriber, messageProducer, webSocketStatus) {
5624
5655
  var _this_1 = _super_1.call(this, function () { return _this_1.teardown(); }) || this;
5625
5656
  _this_1.id = ++counter;
5626
5657
  console.debug('New WebSocket Connection', _this_1.id, token ? 'authorized' : 'unauthorized');
5627
5658
  _this_1.databaseUrl = databaseUrl;
5628
5659
  _this_1.rev = rev;
5660
+ _this_1.realmSetHash = realmSetHash;
5629
5661
  _this_1.clientIdentity = clientIdentity;
5630
5662
  _this_1.token = token;
5631
5663
  _this_1.tokenExpiration = tokenExpiration;
@@ -5740,7 +5772,9 @@ var WSConnection = /** @class */ (function (_super_1) {
5740
5772
  searchParams = new URLSearchParams();
5741
5773
  if (this.subscriber.closed)
5742
5774
  return [2 /*return*/];
5775
+ searchParams.set('v', "2");
5743
5776
  searchParams.set('rev', this.rev);
5777
+ searchParams.set('realmsHash', this.realmSetHash);
5744
5778
  searchParams.set('clientId', this.clientIdentity);
5745
5779
  if (this.token) {
5746
5780
  searchParams.set('token', this.token);
@@ -5857,12 +5891,26 @@ function connectWebSocket(db) {
5857
5891
  var _this_1 = this;
5858
5892
  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.
5859
5893
  take(1), // Don't continue waking up whenever syncState change
5860
- switchMap(function () { return db.cloud.currentUser; }), switchMap(function (userLogin) { return userIsReallyActive.pipe(map(function (isActive) { return (isActive ? userLogin : null); })); }), switchMap(function (userLogin) {
5894
+ switchMap(function (syncState) { return db.cloud.currentUser.pipe(map(function (userLogin) { return [userLogin, syncState]; })); }), switchMap(function (_g) {
5895
+ var userLogin = _g[0], syncState = _g[1];
5896
+ return userIsReallyActive.pipe(map(function (isActive) { return [isActive ? userLogin : null, syncState]; }));
5897
+ }), switchMap(function (_g) {
5898
+ var userLogin = _g[0], syncState = _g[1];
5899
+ return __awaiter(_this_1, void 0, void 0, function () { var _h; return __generator(this, function (_j) {
5900
+ switch (_j.label) {
5901
+ case 0:
5902
+ _h = [userLogin];
5903
+ return [4 /*yield*/, computeRealmSetHash(syncState)];
5904
+ case 1: return [2 /*return*/, _h.concat([_j.sent()])];
5905
+ }
5906
+ }); });
5907
+ }), switchMap(function (_g) {
5908
+ var userLogin = _g[0], realmSetHash = _g[1];
5861
5909
  // Let server end query changes from last entry of same client-ID and forward.
5862
5910
  // If no new entries, server won't bother the client. If new entries, server sends only those
5863
5911
  // and the baseRev of the last from same client-ID.
5864
5912
  return userLogin
5865
- ? new WSObservable(db.cloud.options.databaseUrl, db.cloud.persistedSyncState.value.serverRevision, db.cloud.persistedSyncState.value.clientIdentity, messageProducer, db.cloud.webSocketStatus, userLogin.accessToken, userLogin.accessTokenExpiration)
5913
+ ? 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)
5866
5914
  : from$1([]);
5867
5915
  }), catchError(function (error) {
5868
5916
  if ((error === null || error === void 0 ? void 0 : error.name) === 'TokenExpiredError') {
@@ -6018,22 +6066,26 @@ function LocalSyncWorker(db, cloudOptions, cloudSchema) {
6018
6066
  var cancelToken = { cancelled: false };
6019
6067
  function syncAndRetry(purpose, retryNum) {
6020
6068
  if (retryNum === void 0) { retryNum = 1; }
6021
- syncIfPossible(db, cloudOptions, cloudSchema, {
6022
- cancelToken: cancelToken,
6023
- retryImmediatelyOnFetchError: true,
6024
- purpose: purpose
6025
- }).catch(function (e) {
6026
- console.error('error in syncIfPossible()', e);
6027
- if (cancelToken.cancelled) {
6028
- stop();
6029
- }
6030
- else if (retryNum < 3) {
6031
- // Mimic service worker sync event: retry 3 times
6032
- // * first retry after 5 minutes
6033
- // * second retry 15 minutes later
6034
- setTimeout(function () { return syncAndRetry(purpose, retryNum + 1); }, [0, 5, 15][retryNum] * MINUTES);
6035
- }
6036
- });
6069
+ // Use setTimeout() to get onto a clean stack and
6070
+ // break free from possible active transaction:
6071
+ setTimeout(function () {
6072
+ syncIfPossible(db, cloudOptions, cloudSchema, {
6073
+ cancelToken: cancelToken,
6074
+ retryImmediatelyOnFetchError: true,
6075
+ purpose: purpose,
6076
+ }).catch(function (e) {
6077
+ console.error('error in syncIfPossible()', e);
6078
+ if (cancelToken.cancelled) {
6079
+ stop();
6080
+ }
6081
+ else if (retryNum < 3) {
6082
+ // Mimic service worker sync event: retry 3 times
6083
+ // * first retry after 5 minutes
6084
+ // * second retry 15 minutes later
6085
+ setTimeout(function () { return syncAndRetry(purpose, retryNum + 1); }, [0, 5, 15][retryNum] * MINUTES);
6086
+ }
6087
+ });
6088
+ }, 0);
6037
6089
  }
6038
6090
  var start = function () {
6039
6091
  // Sync eagerly whenever a change has happened (+ initially when there's no syncState yet)
@@ -6042,7 +6094,7 @@ function LocalSyncWorker(db, cloudOptions, cloudSchema) {
6042
6094
  localSyncEventSubscription = db.localSyncEvent.subscribe(function (_g) {
6043
6095
  var purpose = _g.purpose;
6044
6096
  try {
6045
- syncAndRetry(purpose || "pull");
6097
+ syncAndRetry(purpose || 'pull');
6046
6098
  }
6047
6099
  catch (err) {
6048
6100
  console.error('What-the....', err);