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.
@@ -2517,7 +2517,7 @@
2517
2517
  }
2518
2518
  }
2519
2519
  // Already authenticated according to given hints.
2520
- return;
2520
+ return false;
2521
2521
  }
2522
2522
  const context = new AuthPersistedContext(db, {
2523
2523
  claims: {},
@@ -2542,6 +2542,7 @@
2542
2542
  // Make sure to resync as the new login will be authorized
2543
2543
  // for new realms.
2544
2544
  triggerSync(db, "pull");
2545
+ return true;
2545
2546
  });
2546
2547
  }
2547
2548
 
@@ -2615,6 +2616,36 @@
2615
2616
  }
2616
2617
  }
2617
2618
 
2619
+ const events = globalThis['lbc-events'] || (globalThis['lbc-events'] = new Map());
2620
+ function addListener(name, listener) {
2621
+ if (events.has(name)) {
2622
+ events.get(name).push(listener);
2623
+ }
2624
+ else {
2625
+ events.set(name, [listener]);
2626
+ }
2627
+ }
2628
+ function removeListener(name, listener) {
2629
+ const listeners = events.get(name);
2630
+ if (listeners) {
2631
+ const idx = listeners.indexOf(listener);
2632
+ if (idx !== -1) {
2633
+ listeners.splice(idx, 1);
2634
+ }
2635
+ }
2636
+ }
2637
+ function dispatch(ev) {
2638
+ const listeners = events.get(ev.type);
2639
+ if (listeners) {
2640
+ listeners.forEach(listener => {
2641
+ try {
2642
+ listener(ev);
2643
+ }
2644
+ catch (_a) {
2645
+ }
2646
+ });
2647
+ }
2648
+ }
2618
2649
  class BroadcastedAndLocalEvent extends rxjs.Observable {
2619
2650
  constructor(name) {
2620
2651
  const bc = typeof BroadcastChannel === "undefined"
@@ -2628,16 +2659,24 @@
2628
2659
  subscriber.next(ev.data);
2629
2660
  }
2630
2661
  let unsubscribe;
2631
- self.addEventListener(`lbc-${name}`, onCustomEvent);
2632
- if (bc instanceof SWBroadcastChannel) {
2633
- unsubscribe = bc.subscribe(message => subscriber.next(message));
2662
+ //self.addEventListener(`lbc-${name}`, onCustomEvent); // Fails in service workers
2663
+ addListener(`lbc-${name}`, onCustomEvent); // Works better in service worker
2664
+ try {
2665
+ if (bc instanceof SWBroadcastChannel) {
2666
+ unsubscribe = bc.subscribe(message => subscriber.next(message));
2667
+ }
2668
+ else {
2669
+ console.debug("BroadcastedAndLocalEvent: bc.addEventListener()", name, "bc is a", bc);
2670
+ bc.addEventListener("message", onMessageEvent);
2671
+ }
2634
2672
  }
2635
- else {
2636
- console.debug("BroadcastedAndLocalEvent: bc.addEventListener()", name, "bc is a", bc);
2637
- bc.addEventListener("message", onMessageEvent);
2673
+ catch (err) {
2674
+ // Service workers might fail to subscribe outside its initial script.
2675
+ console.warn('Failed to subscribe to broadcast channel', err);
2638
2676
  }
2639
2677
  return () => {
2640
- self.removeEventListener(`lbc-${name}`, onCustomEvent);
2678
+ //self.removeEventListener(`lbc-${name}`, onCustomEvent);
2679
+ removeListener(`lbc-${name}`, onCustomEvent);
2641
2680
  if (bc instanceof SWBroadcastChannel) {
2642
2681
  unsubscribe();
2643
2682
  }
@@ -2653,7 +2692,8 @@
2653
2692
  console.debug("BroadcastedAndLocalEvent: bc.postMessage()", Object.assign({}, message), "bc is a", this.bc);
2654
2693
  this.bc.postMessage(message);
2655
2694
  const ev = new CustomEvent(`lbc-${this.name}`, { detail: message });
2656
- self.dispatchEvent(ev);
2695
+ //self.dispatchEvent(ev);
2696
+ dispatch(ev);
2657
2697
  }
2658
2698
  }
2659
2699
 
@@ -3396,7 +3436,10 @@
3396
3436
  function cloneChange(change, rewriteValues) {
3397
3437
  // clone on demand:
3398
3438
  return Object.assign(Object.assign({}, change), { muts: rewriteValues
3399
- ? change.muts.map((m) => (Object.assign(Object.assign({}, m), { keys: m.keys.slice(), values: m.values.slice() })))
3439
+ ? change.muts.map((m) => {
3440
+ return (m.type === 'insert' || m.type === 'upsert') && m.values
3441
+ ? Object.assign(Object.assign({}, m), { keys: m.keys.slice(), values: m.values.slice() }) : Object.assign(Object.assign({}, m), { keys: m.keys.slice() });
3442
+ })
3400
3443
  : change.muts.map((m) => (Object.assign(Object.assign({}, m), { keys: m.keys.slice() }))) });
3401
3444
  }
3402
3445
 
@@ -3642,7 +3685,7 @@
3642
3685
  return _sync
3643
3686
  .apply(this, arguments)
3644
3687
  .then(() => {
3645
- if (!(syncOptions === null || syncOptions === void 0 ? void 0 : syncOptions.justCheckIfNeeded)) {
3688
+ if (!(syncOptions === null || syncOptions === void 0 ? void 0 : syncOptions.justCheckIfNeeded)) { // && syncOptions?.purpose !== 'push') {
3646
3689
  db.syncStateChangedEvent.next({
3647
3690
  phase: 'in-sync',
3648
3691
  });
@@ -3741,12 +3784,12 @@
3741
3784
  }
3742
3785
  return [clientChanges, syncState, baseRevs];
3743
3786
  }));
3744
- const syncIsNeeded = clientChangeSet.some((set) => set.muts.some((mut) => mut.keys.length > 0));
3787
+ const pushSyncIsNeeded = clientChangeSet.some((set) => set.muts.some((mut) => mut.keys.length > 0));
3745
3788
  if (justCheckIfNeeded) {
3746
- console.debug('Sync is needed:', syncIsNeeded);
3747
- return syncIsNeeded;
3789
+ console.debug('Sync is needed:', pushSyncIsNeeded);
3790
+ return pushSyncIsNeeded;
3748
3791
  }
3749
- if (purpose === 'push' && !syncIsNeeded) {
3792
+ if (purpose === 'push' && !pushSyncIsNeeded) {
3750
3793
  // The purpose of this request was to push changes
3751
3794
  return false;
3752
3795
  }
@@ -3864,6 +3907,7 @@
3864
3907
  return yield _sync(db, options, schema, { isInitialSync, cancelToken });
3865
3908
  }
3866
3909
  console.debug('SYNC DONE', { isInitialSync });
3910
+ db.syncCompleteEvent.next();
3867
3911
  return false; // Not needed anymore
3868
3912
  });
3869
3913
  }
@@ -4143,6 +4187,7 @@
4143
4187
  if (!db) {
4144
4188
  const localSyncEvent = new rxjs.Subject();
4145
4189
  let syncStateChangedEvent = new BroadcastedAndLocalEvent(`syncstatechanged-${dx.name}`);
4190
+ let syncCompleteEvent = new BroadcastedAndLocalEvent(`synccomplete-${dx.name}`);
4146
4191
  localSyncEvent['id'] = ++static_counter;
4147
4192
  let initiallySynced = false;
4148
4193
  db = {
@@ -4186,6 +4231,9 @@
4186
4231
  get syncStateChangedEvent() {
4187
4232
  return syncStateChangedEvent;
4188
4233
  },
4234
+ get syncCompleteEvent() {
4235
+ return syncCompleteEvent;
4236
+ },
4189
4237
  dx,
4190
4238
  };
4191
4239
  const helperMethods = {
@@ -4217,6 +4265,7 @@
4217
4265
  },
4218
4266
  reconfigure() {
4219
4267
  syncStateChangedEvent = new BroadcastedAndLocalEvent(`syncstatechanged-${dx.name}`);
4268
+ syncCompleteEvent = new BroadcastedAndLocalEvent(`synccomplete-${dx.name}`);
4220
4269
  },
4221
4270
  };
4222
4271
  Object.assign(db, helperMethods);
@@ -5120,7 +5169,15 @@
5120
5169
  function createObservable() {
5121
5170
  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.
5122
5171
  take(1), // Don't continue waking up whenever syncState change
5123
- 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]) =>
5172
+ switchMap((syncState) => db.cloud.currentUser.pipe(map((userLogin) => [userLogin, syncState]))), switchMap(([userLogin, syncState]) => userIsReallyActive.pipe(map((isActive) => [isActive ? userLogin : null, syncState]))), switchMap(([userLogin, syncState]) => {
5173
+ if ((userLogin === null || userLogin === void 0 ? void 0 : userLogin.isLoggedIn) && !(syncState === null || syncState === void 0 ? void 0 : syncState.realms.includes(userLogin.userId))) {
5174
+ // We're in an in-between state when user is logged in but the user's realms are not yet synced.
5175
+ // Don't make this change reconnect the websocket just yet. Wait till syncState is updated
5176
+ // to iclude the user's realm.
5177
+ 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]));
5178
+ }
5179
+ return new rxjs.BehaviorSubject([userLogin, syncState]);
5180
+ }), switchMap(([userLogin, syncState]) => __awaiter(this, void 0, void 0, function* () { return [userLogin, yield computeRealmSetHash(syncState)]; })), switchMap(([userLogin, realmSetHash]) =>
5124
5181
  // Let server end query changes from last entry of same client-ID and forward.
5125
5182
  // If no new entries, server won't bother the client. If new entries, server sends only those
5126
5183
  // and the baseRev of the last from same client-ID.
@@ -5989,6 +6046,7 @@
5989
6046
  localSyncWorker = null;
5990
6047
  currentUserEmitter.next(UNAUTHORIZED_USER);
5991
6048
  });
6049
+ const syncComplete = new rxjs.Subject();
5992
6050
  dexie.cloud = {
5993
6051
  version: '{version}',
5994
6052
  options: Object.assign({}, DEFAULT_OPTIONS),
@@ -6001,6 +6059,9 @@
6001
6059
  phase: 'initial',
6002
6060
  status: 'not-started',
6003
6061
  }),
6062
+ events: {
6063
+ syncComplete,
6064
+ },
6004
6065
  persistedSyncState: new rxjs.BehaviorSubject(undefined),
6005
6066
  userInteraction: new rxjs.BehaviorSubject(undefined),
6006
6067
  webSocketStatus: new rxjs.BehaviorSubject('not-started'),
@@ -6094,6 +6155,8 @@
6094
6155
  if (!db.cloud.isServiceWorkerDB) {
6095
6156
  subscriptions.push(computeSyncState(db).subscribe(dexie.cloud.syncState));
6096
6157
  }
6158
+ // Forward db.syncCompleteEvent to be publicly consumable via db.cloud.events.syncComplete:
6159
+ subscriptions.push(db.syncCompleteEvent.subscribe(syncComplete));
6097
6160
  //verifyConfig(db.cloud.options); Not needed (yet at least!)
6098
6161
  // Verify the user has allowed version increment.
6099
6162
  if (!db.tables.every((table) => table.core)) {
@@ -6201,15 +6264,16 @@
6201
6264
  ]).toPromise();
6202
6265
  }
6203
6266
  // HERE: If requireAuth, do athentication now.
6267
+ let changedUser = false;
6204
6268
  if ((_c = db.cloud.options) === null || _c === void 0 ? void 0 : _c.requireAuth) {
6205
- yield login(db);
6269
+ changedUser = yield login(db);
6206
6270
  }
6207
6271
  if (localSyncWorker)
6208
6272
  localSyncWorker.stop();
6209
6273
  localSyncWorker = null;
6210
6274
  throwIfClosed();
6211
6275
  if (db.cloud.usingServiceWorker && ((_d = db.cloud.options) === null || _d === void 0 ? void 0 : _d.databaseUrl)) {
6212
- registerSyncEvent(db, 'push').catch(() => { });
6276
+ registerSyncEvent(db, changedUser ? 'pull' : 'push').catch(() => { });
6213
6277
  registerPeriodicSyncEvent(db).catch(() => { });
6214
6278
  }
6215
6279
  else if (((_e = db.cloud.options) === null || _e === void 0 ? void 0 : _e.databaseUrl) &&
@@ -6218,7 +6282,7 @@
6218
6282
  // There's no SW. Start SyncWorker instead.
6219
6283
  localSyncWorker = LocalSyncWorker(db, db.cloud.options, db.cloud.schema);
6220
6284
  localSyncWorker.start();
6221
- triggerSync(db, 'push');
6285
+ triggerSync(db, changedUser ? 'pull' : 'push');
6222
6286
  }
6223
6287
  // Listen to online event and do sync.
6224
6288
  throwIfClosed();