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

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.
@@ -8,7 +8,7 @@
8
8
  *
9
9
  * ==========================================================================
10
10
  *
11
- * Version 4.0.1-beta.35, Tue Apr 11 2023
11
+ * Version 4.0.1-beta.36, Mon Apr 17 2023
12
12
  *
13
13
  * https://dexie.org
14
14
  *
@@ -2510,7 +2510,7 @@ function login(db, hints) {
2510
2510
  }
2511
2511
  }
2512
2512
  // Already authenticated according to given hints.
2513
- return;
2513
+ return false;
2514
2514
  }
2515
2515
  const context = new AuthPersistedContext(db, {
2516
2516
  claims: {},
@@ -2535,6 +2535,7 @@ function login(db, hints) {
2535
2535
  // Make sure to resync as the new login will be authorized
2536
2536
  // for new realms.
2537
2537
  triggerSync(db, "pull");
2538
+ return true;
2538
2539
  });
2539
2540
  }
2540
2541
 
@@ -2608,6 +2609,36 @@ class SWBroadcastChannel {
2608
2609
  }
2609
2610
  }
2610
2611
 
2612
+ const events = globalThis['lbc-events'] || (globalThis['lbc-events'] = new Map());
2613
+ function addListener(name, listener) {
2614
+ if (events.has(name)) {
2615
+ events.get(name).push(listener);
2616
+ }
2617
+ else {
2618
+ events.set(name, [listener]);
2619
+ }
2620
+ }
2621
+ function removeListener(name, listener) {
2622
+ const listeners = events.get(name);
2623
+ if (listeners) {
2624
+ const idx = listeners.indexOf(listener);
2625
+ if (idx !== -1) {
2626
+ listeners.splice(idx, 1);
2627
+ }
2628
+ }
2629
+ }
2630
+ function dispatch(ev) {
2631
+ const listeners = events.get(ev.type);
2632
+ if (listeners) {
2633
+ listeners.forEach(listener => {
2634
+ try {
2635
+ listener(ev);
2636
+ }
2637
+ catch (_a) {
2638
+ }
2639
+ });
2640
+ }
2641
+ }
2611
2642
  class BroadcastedAndLocalEvent extends Observable$1 {
2612
2643
  constructor(name) {
2613
2644
  const bc = typeof BroadcastChannel === "undefined"
@@ -2621,16 +2652,24 @@ class BroadcastedAndLocalEvent extends Observable$1 {
2621
2652
  subscriber.next(ev.data);
2622
2653
  }
2623
2654
  let unsubscribe;
2624
- self.addEventListener(`lbc-${name}`, onCustomEvent);
2625
- if (bc instanceof SWBroadcastChannel) {
2626
- unsubscribe = bc.subscribe(message => subscriber.next(message));
2655
+ //self.addEventListener(`lbc-${name}`, onCustomEvent); // Fails in service workers
2656
+ addListener(`lbc-${name}`, onCustomEvent); // Works better in service worker
2657
+ try {
2658
+ if (bc instanceof SWBroadcastChannel) {
2659
+ unsubscribe = bc.subscribe(message => subscriber.next(message));
2660
+ }
2661
+ else {
2662
+ console.debug("BroadcastedAndLocalEvent: bc.addEventListener()", name, "bc is a", bc);
2663
+ bc.addEventListener("message", onMessageEvent);
2664
+ }
2627
2665
  }
2628
- else {
2629
- console.debug("BroadcastedAndLocalEvent: bc.addEventListener()", name, "bc is a", bc);
2630
- bc.addEventListener("message", onMessageEvent);
2666
+ catch (err) {
2667
+ // Service workers might fail to subscribe outside its initial script.
2668
+ console.warn('Failed to subscribe to broadcast channel', err);
2631
2669
  }
2632
2670
  return () => {
2633
- self.removeEventListener(`lbc-${name}`, onCustomEvent);
2671
+ //self.removeEventListener(`lbc-${name}`, onCustomEvent);
2672
+ removeListener(`lbc-${name}`, onCustomEvent);
2634
2673
  if (bc instanceof SWBroadcastChannel) {
2635
2674
  unsubscribe();
2636
2675
  }
@@ -2646,7 +2685,8 @@ class BroadcastedAndLocalEvent extends Observable$1 {
2646
2685
  console.debug("BroadcastedAndLocalEvent: bc.postMessage()", Object.assign({}, message), "bc is a", this.bc);
2647
2686
  this.bc.postMessage(message);
2648
2687
  const ev = new CustomEvent(`lbc-${this.name}`, { detail: message });
2649
- self.dispatchEvent(ev);
2688
+ //self.dispatchEvent(ev);
2689
+ dispatch(ev);
2650
2690
  }
2651
2691
  }
2652
2692
 
@@ -3635,7 +3675,7 @@ function sync(db, options, schema, syncOptions) {
3635
3675
  return _sync
3636
3676
  .apply(this, arguments)
3637
3677
  .then(() => {
3638
- if (!(syncOptions === null || syncOptions === void 0 ? void 0 : syncOptions.justCheckIfNeeded)) {
3678
+ if (!(syncOptions === null || syncOptions === void 0 ? void 0 : syncOptions.justCheckIfNeeded)) { // && syncOptions?.purpose !== 'push') {
3639
3679
  db.syncStateChangedEvent.next({
3640
3680
  phase: 'in-sync',
3641
3681
  });
@@ -3734,12 +3774,12 @@ function _sync(db, options, schema, { isInitialSync, cancelToken, justCheckIfNee
3734
3774
  }
3735
3775
  return [clientChanges, syncState, baseRevs];
3736
3776
  }));
3737
- const syncIsNeeded = clientChangeSet.some((set) => set.muts.some((mut) => mut.keys.length > 0));
3777
+ const pushSyncIsNeeded = clientChangeSet.some((set) => set.muts.some((mut) => mut.keys.length > 0));
3738
3778
  if (justCheckIfNeeded) {
3739
- console.debug('Sync is needed:', syncIsNeeded);
3740
- return syncIsNeeded;
3779
+ console.debug('Sync is needed:', pushSyncIsNeeded);
3780
+ return pushSyncIsNeeded;
3741
3781
  }
3742
- if (purpose === 'push' && !syncIsNeeded) {
3782
+ if (purpose === 'push' && !pushSyncIsNeeded) {
3743
3783
  // The purpose of this request was to push changes
3744
3784
  return false;
3745
3785
  }
@@ -3857,6 +3897,7 @@ function _sync(db, options, schema, { isInitialSync, cancelToken, justCheckIfNee
3857
3897
  return yield _sync(db, options, schema, { isInitialSync, cancelToken });
3858
3898
  }
3859
3899
  console.debug('SYNC DONE', { isInitialSync });
3900
+ db.syncCompleteEvent.next();
3860
3901
  return false; // Not needed anymore
3861
3902
  });
3862
3903
  }
@@ -4136,6 +4177,7 @@ function DexieCloudDB(dx) {
4136
4177
  if (!db) {
4137
4178
  const localSyncEvent = new Subject();
4138
4179
  let syncStateChangedEvent = new BroadcastedAndLocalEvent(`syncstatechanged-${dx.name}`);
4180
+ let syncCompleteEvent = new BroadcastedAndLocalEvent(`synccomplete-${dx.name}`);
4139
4181
  localSyncEvent['id'] = ++static_counter;
4140
4182
  let initiallySynced = false;
4141
4183
  db = {
@@ -4179,6 +4221,9 @@ function DexieCloudDB(dx) {
4179
4221
  get syncStateChangedEvent() {
4180
4222
  return syncStateChangedEvent;
4181
4223
  },
4224
+ get syncCompleteEvent() {
4225
+ return syncCompleteEvent;
4226
+ },
4182
4227
  dx,
4183
4228
  };
4184
4229
  const helperMethods = {
@@ -4210,6 +4255,7 @@ function DexieCloudDB(dx) {
4210
4255
  },
4211
4256
  reconfigure() {
4212
4257
  syncStateChangedEvent = new BroadcastedAndLocalEvent(`syncstatechanged-${dx.name}`);
4258
+ syncCompleteEvent = new BroadcastedAndLocalEvent(`synccomplete-${dx.name}`);
4213
4259
  },
4214
4260
  };
4215
4261
  Object.assign(db, helperMethods);
@@ -5113,7 +5159,15 @@ function connectWebSocket(db) {
5113
5159
  function createObservable() {
5114
5160
  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.
5115
5161
  take(1), // Don't continue waking up whenever syncState change
5116
- 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]) =>
5162
+ switchMap((syncState) => db.cloud.currentUser.pipe(map((userLogin) => [userLogin, syncState]))), switchMap(([userLogin, syncState]) => userIsReallyActive.pipe(map((isActive) => [isActive ? userLogin : null, syncState]))), switchMap(([userLogin, syncState]) => {
5163
+ if ((userLogin === null || userLogin === void 0 ? void 0 : userLogin.isLoggedIn) && !(syncState === null || syncState === void 0 ? void 0 : syncState.realms.includes(userLogin.userId))) {
5164
+ // We're in an in-between state when user is logged in but the user's realms are not yet synced.
5165
+ // Don't make this change reconnect the websocket just yet. Wait till syncState is updated
5166
+ // to iclude the user's realm.
5167
+ 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]));
5168
+ }
5169
+ return new BehaviorSubject([userLogin, syncState]);
5170
+ }), switchMap(([userLogin, syncState]) => __awaiter(this, void 0, void 0, function* () { return [userLogin, yield computeRealmSetHash(syncState)]; })), switchMap(([userLogin, realmSetHash]) =>
5117
5171
  // Let server end query changes from last entry of same client-ID and forward.
5118
5172
  // If no new entries, server won't bother the client. If new entries, server sends only those
5119
5173
  // and the baseRev of the last from same client-ID.
@@ -5982,8 +6036,9 @@ function dexieCloud(dexie) {
5982
6036
  localSyncWorker = null;
5983
6037
  currentUserEmitter.next(UNAUTHORIZED_USER);
5984
6038
  });
6039
+ const syncComplete = new Subject();
5985
6040
  dexie.cloud = {
5986
- version: '4.0.1-beta.35',
6041
+ version: '4.0.1-beta.36',
5987
6042
  options: Object.assign({}, DEFAULT_OPTIONS),
5988
6043
  schema: null,
5989
6044
  get currentUserId() {
@@ -5994,6 +6049,9 @@ function dexieCloud(dexie) {
5994
6049
  phase: 'initial',
5995
6050
  status: 'not-started',
5996
6051
  }),
6052
+ events: {
6053
+ syncComplete,
6054
+ },
5997
6055
  persistedSyncState: new BehaviorSubject(undefined),
5998
6056
  userInteraction: new BehaviorSubject(undefined),
5999
6057
  webSocketStatus: new BehaviorSubject('not-started'),
@@ -6087,6 +6145,8 @@ function dexieCloud(dexie) {
6087
6145
  if (!db.cloud.isServiceWorkerDB) {
6088
6146
  subscriptions.push(computeSyncState(db).subscribe(dexie.cloud.syncState));
6089
6147
  }
6148
+ // Forward db.syncCompleteEvent to be publicly consumable via db.cloud.events.syncComplete:
6149
+ subscriptions.push(db.syncCompleteEvent.subscribe(syncComplete));
6090
6150
  //verifyConfig(db.cloud.options); Not needed (yet at least!)
6091
6151
  // Verify the user has allowed version increment.
6092
6152
  if (!db.tables.every((table) => table.core)) {
@@ -6194,15 +6254,16 @@ function dexieCloud(dexie) {
6194
6254
  ]).toPromise();
6195
6255
  }
6196
6256
  // HERE: If requireAuth, do athentication now.
6257
+ let changedUser = false;
6197
6258
  if ((_c = db.cloud.options) === null || _c === void 0 ? void 0 : _c.requireAuth) {
6198
- yield login(db);
6259
+ changedUser = yield login(db);
6199
6260
  }
6200
6261
  if (localSyncWorker)
6201
6262
  localSyncWorker.stop();
6202
6263
  localSyncWorker = null;
6203
6264
  throwIfClosed();
6204
6265
  if (db.cloud.usingServiceWorker && ((_d = db.cloud.options) === null || _d === void 0 ? void 0 : _d.databaseUrl)) {
6205
- registerSyncEvent(db, 'push').catch(() => { });
6266
+ registerSyncEvent(db, changedUser ? 'pull' : 'push').catch(() => { });
6206
6267
  registerPeriodicSyncEvent(db).catch(() => { });
6207
6268
  }
6208
6269
  else if (((_e = db.cloud.options) === null || _e === void 0 ? void 0 : _e.databaseUrl) &&
@@ -6211,7 +6272,7 @@ function dexieCloud(dexie) {
6211
6272
  // There's no SW. Start SyncWorker instead.
6212
6273
  localSyncWorker = LocalSyncWorker(db, db.cloud.options, db.cloud.schema);
6213
6274
  localSyncWorker.start();
6214
- triggerSync(db, 'push');
6275
+ triggerSync(db, changedUser ? 'pull' : 'push');
6215
6276
  }
6216
6277
  // Listen to online event and do sync.
6217
6278
  throwIfClosed();
@@ -6238,7 +6299,7 @@ function dexieCloud(dexie) {
6238
6299
  });
6239
6300
  }
6240
6301
  }
6241
- dexieCloud.version = '4.0.1-beta.35';
6302
+ dexieCloud.version = '4.0.1-beta.36';
6242
6303
  Dexie.Cloud = dexieCloud;
6243
6304
 
6244
6305
  export { dexieCloud as default, dexieCloud, getTiedObjectId, getTiedRealmId };