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.
@@ -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.37, 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
 
@@ -3389,7 +3429,10 @@ function encodeIdsForServer(schema, currentUser, changes) {
3389
3429
  function cloneChange(change, rewriteValues) {
3390
3430
  // clone on demand:
3391
3431
  return Object.assign(Object.assign({}, change), { muts: rewriteValues
3392
- ? change.muts.map((m) => (Object.assign(Object.assign({}, m), { keys: m.keys.slice(), values: m.values.slice() })))
3432
+ ? change.muts.map((m) => {
3433
+ return (m.type === 'insert' || m.type === 'upsert') && m.values
3434
+ ? Object.assign(Object.assign({}, m), { keys: m.keys.slice(), values: m.values.slice() }) : Object.assign(Object.assign({}, m), { keys: m.keys.slice() });
3435
+ })
3393
3436
  : change.muts.map((m) => (Object.assign(Object.assign({}, m), { keys: m.keys.slice() }))) });
3394
3437
  }
3395
3438
 
@@ -3635,7 +3678,7 @@ function sync(db, options, schema, syncOptions) {
3635
3678
  return _sync
3636
3679
  .apply(this, arguments)
3637
3680
  .then(() => {
3638
- if (!(syncOptions === null || syncOptions === void 0 ? void 0 : syncOptions.justCheckIfNeeded)) {
3681
+ if (!(syncOptions === null || syncOptions === void 0 ? void 0 : syncOptions.justCheckIfNeeded)) { // && syncOptions?.purpose !== 'push') {
3639
3682
  db.syncStateChangedEvent.next({
3640
3683
  phase: 'in-sync',
3641
3684
  });
@@ -3734,12 +3777,12 @@ function _sync(db, options, schema, { isInitialSync, cancelToken, justCheckIfNee
3734
3777
  }
3735
3778
  return [clientChanges, syncState, baseRevs];
3736
3779
  }));
3737
- const syncIsNeeded = clientChangeSet.some((set) => set.muts.some((mut) => mut.keys.length > 0));
3780
+ const pushSyncIsNeeded = clientChangeSet.some((set) => set.muts.some((mut) => mut.keys.length > 0));
3738
3781
  if (justCheckIfNeeded) {
3739
- console.debug('Sync is needed:', syncIsNeeded);
3740
- return syncIsNeeded;
3782
+ console.debug('Sync is needed:', pushSyncIsNeeded);
3783
+ return pushSyncIsNeeded;
3741
3784
  }
3742
- if (purpose === 'push' && !syncIsNeeded) {
3785
+ if (purpose === 'push' && !pushSyncIsNeeded) {
3743
3786
  // The purpose of this request was to push changes
3744
3787
  return false;
3745
3788
  }
@@ -3857,6 +3900,7 @@ function _sync(db, options, schema, { isInitialSync, cancelToken, justCheckIfNee
3857
3900
  return yield _sync(db, options, schema, { isInitialSync, cancelToken });
3858
3901
  }
3859
3902
  console.debug('SYNC DONE', { isInitialSync });
3903
+ db.syncCompleteEvent.next();
3860
3904
  return false; // Not needed anymore
3861
3905
  });
3862
3906
  }
@@ -4136,6 +4180,7 @@ function DexieCloudDB(dx) {
4136
4180
  if (!db) {
4137
4181
  const localSyncEvent = new Subject();
4138
4182
  let syncStateChangedEvent = new BroadcastedAndLocalEvent(`syncstatechanged-${dx.name}`);
4183
+ let syncCompleteEvent = new BroadcastedAndLocalEvent(`synccomplete-${dx.name}`);
4139
4184
  localSyncEvent['id'] = ++static_counter;
4140
4185
  let initiallySynced = false;
4141
4186
  db = {
@@ -4179,6 +4224,9 @@ function DexieCloudDB(dx) {
4179
4224
  get syncStateChangedEvent() {
4180
4225
  return syncStateChangedEvent;
4181
4226
  },
4227
+ get syncCompleteEvent() {
4228
+ return syncCompleteEvent;
4229
+ },
4182
4230
  dx,
4183
4231
  };
4184
4232
  const helperMethods = {
@@ -4210,6 +4258,7 @@ function DexieCloudDB(dx) {
4210
4258
  },
4211
4259
  reconfigure() {
4212
4260
  syncStateChangedEvent = new BroadcastedAndLocalEvent(`syncstatechanged-${dx.name}`);
4261
+ syncCompleteEvent = new BroadcastedAndLocalEvent(`synccomplete-${dx.name}`);
4213
4262
  },
4214
4263
  };
4215
4264
  Object.assign(db, helperMethods);
@@ -5113,7 +5162,15 @@ function connectWebSocket(db) {
5113
5162
  function createObservable() {
5114
5163
  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
5164
  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]) =>
5165
+ switchMap((syncState) => db.cloud.currentUser.pipe(map((userLogin) => [userLogin, syncState]))), switchMap(([userLogin, syncState]) => userIsReallyActive.pipe(map((isActive) => [isActive ? userLogin : null, syncState]))), switchMap(([userLogin, syncState]) => {
5166
+ if ((userLogin === null || userLogin === void 0 ? void 0 : userLogin.isLoggedIn) && !(syncState === null || syncState === void 0 ? void 0 : syncState.realms.includes(userLogin.userId))) {
5167
+ // We're in an in-between state when user is logged in but the user's realms are not yet synced.
5168
+ // Don't make this change reconnect the websocket just yet. Wait till syncState is updated
5169
+ // to iclude the user's realm.
5170
+ 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]));
5171
+ }
5172
+ return new BehaviorSubject([userLogin, syncState]);
5173
+ }), switchMap(([userLogin, syncState]) => __awaiter(this, void 0, void 0, function* () { return [userLogin, yield computeRealmSetHash(syncState)]; })), switchMap(([userLogin, realmSetHash]) =>
5117
5174
  // Let server end query changes from last entry of same client-ID and forward.
5118
5175
  // If no new entries, server won't bother the client. If new entries, server sends only those
5119
5176
  // and the baseRev of the last from same client-ID.
@@ -5982,8 +6039,9 @@ function dexieCloud(dexie) {
5982
6039
  localSyncWorker = null;
5983
6040
  currentUserEmitter.next(UNAUTHORIZED_USER);
5984
6041
  });
6042
+ const syncComplete = new Subject();
5985
6043
  dexie.cloud = {
5986
- version: '4.0.1-beta.35',
6044
+ version: '4.0.1-beta.37',
5987
6045
  options: Object.assign({}, DEFAULT_OPTIONS),
5988
6046
  schema: null,
5989
6047
  get currentUserId() {
@@ -5994,6 +6052,9 @@ function dexieCloud(dexie) {
5994
6052
  phase: 'initial',
5995
6053
  status: 'not-started',
5996
6054
  }),
6055
+ events: {
6056
+ syncComplete,
6057
+ },
5997
6058
  persistedSyncState: new BehaviorSubject(undefined),
5998
6059
  userInteraction: new BehaviorSubject(undefined),
5999
6060
  webSocketStatus: new BehaviorSubject('not-started'),
@@ -6087,6 +6148,8 @@ function dexieCloud(dexie) {
6087
6148
  if (!db.cloud.isServiceWorkerDB) {
6088
6149
  subscriptions.push(computeSyncState(db).subscribe(dexie.cloud.syncState));
6089
6150
  }
6151
+ // Forward db.syncCompleteEvent to be publicly consumable via db.cloud.events.syncComplete:
6152
+ subscriptions.push(db.syncCompleteEvent.subscribe(syncComplete));
6090
6153
  //verifyConfig(db.cloud.options); Not needed (yet at least!)
6091
6154
  // Verify the user has allowed version increment.
6092
6155
  if (!db.tables.every((table) => table.core)) {
@@ -6194,15 +6257,16 @@ function dexieCloud(dexie) {
6194
6257
  ]).toPromise();
6195
6258
  }
6196
6259
  // HERE: If requireAuth, do athentication now.
6260
+ let changedUser = false;
6197
6261
  if ((_c = db.cloud.options) === null || _c === void 0 ? void 0 : _c.requireAuth) {
6198
- yield login(db);
6262
+ changedUser = yield login(db);
6199
6263
  }
6200
6264
  if (localSyncWorker)
6201
6265
  localSyncWorker.stop();
6202
6266
  localSyncWorker = null;
6203
6267
  throwIfClosed();
6204
6268
  if (db.cloud.usingServiceWorker && ((_d = db.cloud.options) === null || _d === void 0 ? void 0 : _d.databaseUrl)) {
6205
- registerSyncEvent(db, 'push').catch(() => { });
6269
+ registerSyncEvent(db, changedUser ? 'pull' : 'push').catch(() => { });
6206
6270
  registerPeriodicSyncEvent(db).catch(() => { });
6207
6271
  }
6208
6272
  else if (((_e = db.cloud.options) === null || _e === void 0 ? void 0 : _e.databaseUrl) &&
@@ -6211,7 +6275,7 @@ function dexieCloud(dexie) {
6211
6275
  // There's no SW. Start SyncWorker instead.
6212
6276
  localSyncWorker = LocalSyncWorker(db, db.cloud.options, db.cloud.schema);
6213
6277
  localSyncWorker.start();
6214
- triggerSync(db, 'push');
6278
+ triggerSync(db, changedUser ? 'pull' : 'push');
6215
6279
  }
6216
6280
  // Listen to online event and do sync.
6217
6281
  throwIfClosed();
@@ -6238,7 +6302,7 @@ function dexieCloud(dexie) {
6238
6302
  });
6239
6303
  }
6240
6304
  }
6241
- dexieCloud.version = '4.0.1-beta.35';
6305
+ dexieCloud.version = '4.0.1-beta.37';
6242
6306
  Dexie.Cloud = dexieCloud;
6243
6307
 
6244
6308
  export { dexieCloud as default, dexieCloud, getTiedObjectId, getTiedRealmId };