dexie-cloud-addon 4.0.1-beta.35 → 4.0.1-beta.37

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.
@@ -210,6 +210,36 @@
210
210
  }
211
211
  }
212
212
 
213
+ const events = globalThis['lbc-events'] || (globalThis['lbc-events'] = new Map());
214
+ function addListener(name, listener) {
215
+ if (events.has(name)) {
216
+ events.get(name).push(listener);
217
+ }
218
+ else {
219
+ events.set(name, [listener]);
220
+ }
221
+ }
222
+ function removeListener(name, listener) {
223
+ const listeners = events.get(name);
224
+ if (listeners) {
225
+ const idx = listeners.indexOf(listener);
226
+ if (idx !== -1) {
227
+ listeners.splice(idx, 1);
228
+ }
229
+ }
230
+ }
231
+ function dispatch(ev) {
232
+ const listeners = events.get(ev.type);
233
+ if (listeners) {
234
+ listeners.forEach(listener => {
235
+ try {
236
+ listener(ev);
237
+ }
238
+ catch (_a) {
239
+ }
240
+ });
241
+ }
242
+ }
213
243
  class BroadcastedAndLocalEvent extends rxjs.Observable {
214
244
  constructor(name) {
215
245
  const bc = typeof BroadcastChannel === "undefined"
@@ -223,16 +253,24 @@
223
253
  subscriber.next(ev.data);
224
254
  }
225
255
  let unsubscribe;
226
- self.addEventListener(`lbc-${name}`, onCustomEvent);
227
- if (bc instanceof SWBroadcastChannel) {
228
- unsubscribe = bc.subscribe(message => subscriber.next(message));
256
+ //self.addEventListener(`lbc-${name}`, onCustomEvent); // Fails in service workers
257
+ addListener(`lbc-${name}`, onCustomEvent); // Works better in service worker
258
+ try {
259
+ if (bc instanceof SWBroadcastChannel) {
260
+ unsubscribe = bc.subscribe(message => subscriber.next(message));
261
+ }
262
+ else {
263
+ console.debug("BroadcastedAndLocalEvent: bc.addEventListener()", name, "bc is a", bc);
264
+ bc.addEventListener("message", onMessageEvent);
265
+ }
229
266
  }
230
- else {
231
- console.debug("BroadcastedAndLocalEvent: bc.addEventListener()", name, "bc is a", bc);
232
- bc.addEventListener("message", onMessageEvent);
267
+ catch (err) {
268
+ // Service workers might fail to subscribe outside its initial script.
269
+ console.warn('Failed to subscribe to broadcast channel', err);
233
270
  }
234
271
  return () => {
235
- self.removeEventListener(`lbc-${name}`, onCustomEvent);
272
+ //self.removeEventListener(`lbc-${name}`, onCustomEvent);
273
+ removeListener(`lbc-${name}`, onCustomEvent);
236
274
  if (bc instanceof SWBroadcastChannel) {
237
275
  unsubscribe();
238
276
  }
@@ -248,7 +286,8 @@
248
286
  console.debug("BroadcastedAndLocalEvent: bc.postMessage()", Object.assign({}, message), "bc is a", this.bc);
249
287
  this.bc.postMessage(message);
250
288
  const ev = new CustomEvent(`lbc-${this.name}`, { detail: message });
251
- self.dispatchEvent(ev);
289
+ //self.dispatchEvent(ev);
290
+ dispatch(ev);
252
291
  }
253
292
  }
254
293
 
@@ -3150,7 +3189,10 @@
3150
3189
  function cloneChange(change, rewriteValues) {
3151
3190
  // clone on demand:
3152
3191
  return Object.assign(Object.assign({}, change), { muts: rewriteValues
3153
- ? change.muts.map((m) => (Object.assign(Object.assign({}, m), { keys: m.keys.slice(), values: m.values.slice() })))
3192
+ ? change.muts.map((m) => {
3193
+ return (m.type === 'insert' || m.type === 'upsert') && m.values
3194
+ ? Object.assign(Object.assign({}, m), { keys: m.keys.slice(), values: m.values.slice() }) : Object.assign(Object.assign({}, m), { keys: m.keys.slice() });
3195
+ })
3154
3196
  : change.muts.map((m) => (Object.assign(Object.assign({}, m), { keys: m.keys.slice() }))) });
3155
3197
  }
3156
3198
 
@@ -3396,7 +3438,7 @@
3396
3438
  return _sync
3397
3439
  .apply(this, arguments)
3398
3440
  .then(() => {
3399
- if (!(syncOptions === null || syncOptions === void 0 ? void 0 : syncOptions.justCheckIfNeeded)) {
3441
+ if (!(syncOptions === null || syncOptions === void 0 ? void 0 : syncOptions.justCheckIfNeeded)) { // && syncOptions?.purpose !== 'push') {
3400
3442
  db.syncStateChangedEvent.next({
3401
3443
  phase: 'in-sync',
3402
3444
  });
@@ -3495,12 +3537,12 @@
3495
3537
  }
3496
3538
  return [clientChanges, syncState, baseRevs];
3497
3539
  }));
3498
- const syncIsNeeded = clientChangeSet.some((set) => set.muts.some((mut) => mut.keys.length > 0));
3540
+ const pushSyncIsNeeded = clientChangeSet.some((set) => set.muts.some((mut) => mut.keys.length > 0));
3499
3541
  if (justCheckIfNeeded) {
3500
- console.debug('Sync is needed:', syncIsNeeded);
3501
- return syncIsNeeded;
3542
+ console.debug('Sync is needed:', pushSyncIsNeeded);
3543
+ return pushSyncIsNeeded;
3502
3544
  }
3503
- if (purpose === 'push' && !syncIsNeeded) {
3545
+ if (purpose === 'push' && !pushSyncIsNeeded) {
3504
3546
  // The purpose of this request was to push changes
3505
3547
  return false;
3506
3548
  }
@@ -3618,6 +3660,7 @@
3618
3660
  return yield _sync(db, options, schema, { isInitialSync, cancelToken });
3619
3661
  }
3620
3662
  console.debug('SYNC DONE', { isInitialSync });
3663
+ db.syncCompleteEvent.next();
3621
3664
  return false; // Not needed anymore
3622
3665
  });
3623
3666
  }
@@ -3897,6 +3940,7 @@
3897
3940
  if (!db) {
3898
3941
  const localSyncEvent = new rxjs.Subject();
3899
3942
  let syncStateChangedEvent = new BroadcastedAndLocalEvent(`syncstatechanged-${dx.name}`);
3943
+ let syncCompleteEvent = new BroadcastedAndLocalEvent(`synccomplete-${dx.name}`);
3900
3944
  localSyncEvent['id'] = ++static_counter;
3901
3945
  let initiallySynced = false;
3902
3946
  db = {
@@ -3940,6 +3984,9 @@
3940
3984
  get syncStateChangedEvent() {
3941
3985
  return syncStateChangedEvent;
3942
3986
  },
3987
+ get syncCompleteEvent() {
3988
+ return syncCompleteEvent;
3989
+ },
3943
3990
  dx,
3944
3991
  };
3945
3992
  const helperMethods = {
@@ -3971,6 +4018,7 @@
3971
4018
  },
3972
4019
  reconfigure() {
3973
4020
  syncStateChangedEvent = new BroadcastedAndLocalEvent(`syncstatechanged-${dx.name}`);
4021
+ syncCompleteEvent = new BroadcastedAndLocalEvent(`synccomplete-${dx.name}`);
3974
4022
  },
3975
4023
  };
3976
4024
  Object.assign(db, helperMethods);
@@ -4185,7 +4233,7 @@
4185
4233
  }
4186
4234
  }
4187
4235
  // Already authenticated according to given hints.
4188
- return;
4236
+ return false;
4189
4237
  }
4190
4238
  const context = new AuthPersistedContext(db, {
4191
4239
  claims: {},
@@ -4210,6 +4258,7 @@
4210
4258
  // Make sure to resync as the new login will be authorized
4211
4259
  // for new realms.
4212
4260
  triggerSync(db, "pull");
4261
+ return true;
4213
4262
  });
4214
4263
  }
4215
4264
 
@@ -5102,7 +5151,15 @@
5102
5151
  function createObservable() {
5103
5152
  return db.cloud.persistedSyncState.pipe(filter((syncState) => syncState === null || syncState === void 0 ? void 0 : syncState.serverRevision), // Don't connect before there's no initial sync performed.
5104
5153
  take(1), // Don't continue waking up whenever syncState change
5105
- switchMap((syncState) => db.cloud.currentUser.pipe(map((userLogin) => [userLogin, syncState]))), switchMap(([userLogin, syncState]) => userIsReallyActive.pipe(map((isActive) => [isActive ? userLogin : null, syncState]))), switchMap(([userLogin, syncState]) => __awaiter(this, void 0, void 0, function* () { return [userLogin, yield computeRealmSetHash(syncState)]; })), switchMap(([userLogin, realmSetHash]) =>
5154
+ switchMap((syncState) => db.cloud.currentUser.pipe(map((userLogin) => [userLogin, syncState]))), switchMap(([userLogin, syncState]) => userIsReallyActive.pipe(map((isActive) => [isActive ? userLogin : null, syncState]))), switchMap(([userLogin, syncState]) => {
5155
+ if ((userLogin === null || userLogin === void 0 ? void 0 : userLogin.isLoggedIn) && !(syncState === null || syncState === void 0 ? void 0 : syncState.realms.includes(userLogin.userId))) {
5156
+ // We're in an in-between state when user is logged in but the user's realms are not yet synced.
5157
+ // Don't make this change reconnect the websocket just yet. Wait till syncState is updated
5158
+ // to iclude the user's realm.
5159
+ 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]));
5160
+ }
5161
+ return new rxjs.BehaviorSubject([userLogin, syncState]);
5162
+ }), switchMap(([userLogin, syncState]) => __awaiter(this, void 0, void 0, function* () { return [userLogin, yield computeRealmSetHash(syncState)]; })), switchMap(([userLogin, realmSetHash]) =>
5106
5163
  // Let server end query changes from last entry of same client-ID and forward.
5107
5164
  // If no new entries, server won't bother the client. If new entries, server sends only those
5108
5165
  // and the baseRev of the last from same client-ID.
@@ -5964,8 +6021,9 @@
5964
6021
  localSyncWorker = null;
5965
6022
  currentUserEmitter.next(UNAUTHORIZED_USER);
5966
6023
  });
6024
+ const syncComplete = new rxjs.Subject();
5967
6025
  dexie.cloud = {
5968
- version: '4.0.1-beta.35',
6026
+ version: '4.0.1-beta.37',
5969
6027
  options: Object.assign({}, DEFAULT_OPTIONS),
5970
6028
  schema: null,
5971
6029
  get currentUserId() {
@@ -5976,6 +6034,9 @@
5976
6034
  phase: 'initial',
5977
6035
  status: 'not-started',
5978
6036
  }),
6037
+ events: {
6038
+ syncComplete,
6039
+ },
5979
6040
  persistedSyncState: new rxjs.BehaviorSubject(undefined),
5980
6041
  userInteraction: new rxjs.BehaviorSubject(undefined),
5981
6042
  webSocketStatus: new rxjs.BehaviorSubject('not-started'),
@@ -6069,6 +6130,8 @@
6069
6130
  if (!db.cloud.isServiceWorkerDB) {
6070
6131
  subscriptions.push(computeSyncState(db).subscribe(dexie.cloud.syncState));
6071
6132
  }
6133
+ // Forward db.syncCompleteEvent to be publicly consumable via db.cloud.events.syncComplete:
6134
+ subscriptions.push(db.syncCompleteEvent.subscribe(syncComplete));
6072
6135
  //verifyConfig(db.cloud.options); Not needed (yet at least!)
6073
6136
  // Verify the user has allowed version increment.
6074
6137
  if (!db.tables.every((table) => table.core)) {
@@ -6176,15 +6239,16 @@
6176
6239
  ]).toPromise();
6177
6240
  }
6178
6241
  // HERE: If requireAuth, do athentication now.
6242
+ let changedUser = false;
6179
6243
  if ((_c = db.cloud.options) === null || _c === void 0 ? void 0 : _c.requireAuth) {
6180
- yield login(db);
6244
+ changedUser = yield login(db);
6181
6245
  }
6182
6246
  if (localSyncWorker)
6183
6247
  localSyncWorker.stop();
6184
6248
  localSyncWorker = null;
6185
6249
  throwIfClosed();
6186
6250
  if (db.cloud.usingServiceWorker && ((_d = db.cloud.options) === null || _d === void 0 ? void 0 : _d.databaseUrl)) {
6187
- registerSyncEvent(db, 'push').catch(() => { });
6251
+ registerSyncEvent(db, changedUser ? 'pull' : 'push').catch(() => { });
6188
6252
  registerPeriodicSyncEvent(db).catch(() => { });
6189
6253
  }
6190
6254
  else if (((_e = db.cloud.options) === null || _e === void 0 ? void 0 : _e.databaseUrl) &&
@@ -6193,7 +6257,7 @@
6193
6257
  // There's no SW. Start SyncWorker instead.
6194
6258
  localSyncWorker = LocalSyncWorker(db, db.cloud.options, db.cloud.schema);
6195
6259
  localSyncWorker.start();
6196
- triggerSync(db, 'push');
6260
+ triggerSync(db, changedUser ? 'pull' : 'push');
6197
6261
  }
6198
6262
  // Listen to online event and do sync.
6199
6263
  throwIfClosed();
@@ -6220,7 +6284,7 @@
6220
6284
  });
6221
6285
  }
6222
6286
  }
6223
- dexieCloud.version = '4.0.1-beta.35';
6287
+ dexieCloud.version = '4.0.1-beta.37';
6224
6288
  Dexie__default["default"].Cloud = dexieCloud;
6225
6289
 
6226
6290
  // In case the SW lives for a while, let it reuse already opened connections: