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.
@@ -203,6 +203,36 @@ class SWBroadcastChannel {
203
203
  }
204
204
  }
205
205
 
206
+ const events = globalThis['lbc-events'] || (globalThis['lbc-events'] = new Map());
207
+ function addListener(name, listener) {
208
+ if (events.has(name)) {
209
+ events.get(name).push(listener);
210
+ }
211
+ else {
212
+ events.set(name, [listener]);
213
+ }
214
+ }
215
+ function removeListener(name, listener) {
216
+ const listeners = events.get(name);
217
+ if (listeners) {
218
+ const idx = listeners.indexOf(listener);
219
+ if (idx !== -1) {
220
+ listeners.splice(idx, 1);
221
+ }
222
+ }
223
+ }
224
+ function dispatch(ev) {
225
+ const listeners = events.get(ev.type);
226
+ if (listeners) {
227
+ listeners.forEach(listener => {
228
+ try {
229
+ listener(ev);
230
+ }
231
+ catch (_a) {
232
+ }
233
+ });
234
+ }
235
+ }
206
236
  class BroadcastedAndLocalEvent extends Observable$1 {
207
237
  constructor(name) {
208
238
  const bc = typeof BroadcastChannel === "undefined"
@@ -216,16 +246,24 @@ class BroadcastedAndLocalEvent extends Observable$1 {
216
246
  subscriber.next(ev.data);
217
247
  }
218
248
  let unsubscribe;
219
- self.addEventListener(`lbc-${name}`, onCustomEvent);
220
- if (bc instanceof SWBroadcastChannel) {
221
- unsubscribe = bc.subscribe(message => subscriber.next(message));
249
+ //self.addEventListener(`lbc-${name}`, onCustomEvent); // Fails in service workers
250
+ addListener(`lbc-${name}`, onCustomEvent); // Works better in service worker
251
+ try {
252
+ if (bc instanceof SWBroadcastChannel) {
253
+ unsubscribe = bc.subscribe(message => subscriber.next(message));
254
+ }
255
+ else {
256
+ console.debug("BroadcastedAndLocalEvent: bc.addEventListener()", name, "bc is a", bc);
257
+ bc.addEventListener("message", onMessageEvent);
258
+ }
222
259
  }
223
- else {
224
- console.debug("BroadcastedAndLocalEvent: bc.addEventListener()", name, "bc is a", bc);
225
- bc.addEventListener("message", onMessageEvent);
260
+ catch (err) {
261
+ // Service workers might fail to subscribe outside its initial script.
262
+ console.warn('Failed to subscribe to broadcast channel', err);
226
263
  }
227
264
  return () => {
228
- self.removeEventListener(`lbc-${name}`, onCustomEvent);
265
+ //self.removeEventListener(`lbc-${name}`, onCustomEvent);
266
+ removeListener(`lbc-${name}`, onCustomEvent);
229
267
  if (bc instanceof SWBroadcastChannel) {
230
268
  unsubscribe();
231
269
  }
@@ -241,7 +279,8 @@ class BroadcastedAndLocalEvent extends Observable$1 {
241
279
  console.debug("BroadcastedAndLocalEvent: bc.postMessage()", Object.assign({}, message), "bc is a", this.bc);
242
280
  this.bc.postMessage(message);
243
281
  const ev = new CustomEvent(`lbc-${this.name}`, { detail: message });
244
- self.dispatchEvent(ev);
282
+ //self.dispatchEvent(ev);
283
+ dispatch(ev);
245
284
  }
246
285
  }
247
286
 
@@ -3389,7 +3428,7 @@ function sync(db, options, schema, syncOptions) {
3389
3428
  return _sync
3390
3429
  .apply(this, arguments)
3391
3430
  .then(() => {
3392
- if (!(syncOptions === null || syncOptions === void 0 ? void 0 : syncOptions.justCheckIfNeeded)) {
3431
+ if (!(syncOptions === null || syncOptions === void 0 ? void 0 : syncOptions.justCheckIfNeeded)) { // && syncOptions?.purpose !== 'push') {
3393
3432
  db.syncStateChangedEvent.next({
3394
3433
  phase: 'in-sync',
3395
3434
  });
@@ -3488,12 +3527,12 @@ function _sync(db, options, schema, { isInitialSync, cancelToken, justCheckIfNee
3488
3527
  }
3489
3528
  return [clientChanges, syncState, baseRevs];
3490
3529
  }));
3491
- const syncIsNeeded = clientChangeSet.some((set) => set.muts.some((mut) => mut.keys.length > 0));
3530
+ const pushSyncIsNeeded = clientChangeSet.some((set) => set.muts.some((mut) => mut.keys.length > 0));
3492
3531
  if (justCheckIfNeeded) {
3493
- console.debug('Sync is needed:', syncIsNeeded);
3494
- return syncIsNeeded;
3532
+ console.debug('Sync is needed:', pushSyncIsNeeded);
3533
+ return pushSyncIsNeeded;
3495
3534
  }
3496
- if (purpose === 'push' && !syncIsNeeded) {
3535
+ if (purpose === 'push' && !pushSyncIsNeeded) {
3497
3536
  // The purpose of this request was to push changes
3498
3537
  return false;
3499
3538
  }
@@ -3611,6 +3650,7 @@ function _sync(db, options, schema, { isInitialSync, cancelToken, justCheckIfNee
3611
3650
  return yield _sync(db, options, schema, { isInitialSync, cancelToken });
3612
3651
  }
3613
3652
  console.debug('SYNC DONE', { isInitialSync });
3653
+ db.syncCompleteEvent.next();
3614
3654
  return false; // Not needed anymore
3615
3655
  });
3616
3656
  }
@@ -3890,6 +3930,7 @@ function DexieCloudDB(dx) {
3890
3930
  if (!db) {
3891
3931
  const localSyncEvent = new Subject();
3892
3932
  let syncStateChangedEvent = new BroadcastedAndLocalEvent(`syncstatechanged-${dx.name}`);
3933
+ let syncCompleteEvent = new BroadcastedAndLocalEvent(`synccomplete-${dx.name}`);
3893
3934
  localSyncEvent['id'] = ++static_counter;
3894
3935
  let initiallySynced = false;
3895
3936
  db = {
@@ -3933,6 +3974,9 @@ function DexieCloudDB(dx) {
3933
3974
  get syncStateChangedEvent() {
3934
3975
  return syncStateChangedEvent;
3935
3976
  },
3977
+ get syncCompleteEvent() {
3978
+ return syncCompleteEvent;
3979
+ },
3936
3980
  dx,
3937
3981
  };
3938
3982
  const helperMethods = {
@@ -3964,6 +4008,7 @@ function DexieCloudDB(dx) {
3964
4008
  },
3965
4009
  reconfigure() {
3966
4010
  syncStateChangedEvent = new BroadcastedAndLocalEvent(`syncstatechanged-${dx.name}`);
4011
+ syncCompleteEvent = new BroadcastedAndLocalEvent(`synccomplete-${dx.name}`);
3967
4012
  },
3968
4013
  };
3969
4014
  Object.assign(db, helperMethods);
@@ -4178,7 +4223,7 @@ function login(db, hints) {
4178
4223
  }
4179
4224
  }
4180
4225
  // Already authenticated according to given hints.
4181
- return;
4226
+ return false;
4182
4227
  }
4183
4228
  const context = new AuthPersistedContext(db, {
4184
4229
  claims: {},
@@ -4203,6 +4248,7 @@ function login(db, hints) {
4203
4248
  // Make sure to resync as the new login will be authorized
4204
4249
  // for new realms.
4205
4250
  triggerSync(db, "pull");
4251
+ return true;
4206
4252
  });
4207
4253
  }
4208
4254
 
@@ -5095,7 +5141,15 @@ function connectWebSocket(db) {
5095
5141
  function createObservable() {
5096
5142
  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.
5097
5143
  take(1), // Don't continue waking up whenever syncState change
5098
- 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]) =>
5144
+ switchMap((syncState) => db.cloud.currentUser.pipe(map((userLogin) => [userLogin, syncState]))), switchMap(([userLogin, syncState]) => userIsReallyActive.pipe(map((isActive) => [isActive ? userLogin : null, syncState]))), switchMap(([userLogin, syncState]) => {
5145
+ if ((userLogin === null || userLogin === void 0 ? void 0 : userLogin.isLoggedIn) && !(syncState === null || syncState === void 0 ? void 0 : syncState.realms.includes(userLogin.userId))) {
5146
+ // We're in an in-between state when user is logged in but the user's realms are not yet synced.
5147
+ // Don't make this change reconnect the websocket just yet. Wait till syncState is updated
5148
+ // to iclude the user's realm.
5149
+ 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]));
5150
+ }
5151
+ return new BehaviorSubject([userLogin, syncState]);
5152
+ }), switchMap(([userLogin, syncState]) => __awaiter(this, void 0, void 0, function* () { return [userLogin, yield computeRealmSetHash(syncState)]; })), switchMap(([userLogin, realmSetHash]) =>
5099
5153
  // Let server end query changes from last entry of same client-ID and forward.
5100
5154
  // If no new entries, server won't bother the client. If new entries, server sends only those
5101
5155
  // and the baseRev of the last from same client-ID.
@@ -5957,8 +6011,9 @@ function dexieCloud(dexie) {
5957
6011
  localSyncWorker = null;
5958
6012
  currentUserEmitter.next(UNAUTHORIZED_USER);
5959
6013
  });
6014
+ const syncComplete = new Subject();
5960
6015
  dexie.cloud = {
5961
- version: '4.0.1-beta.35',
6016
+ version: '4.0.1-beta.36',
5962
6017
  options: Object.assign({}, DEFAULT_OPTIONS),
5963
6018
  schema: null,
5964
6019
  get currentUserId() {
@@ -5969,6 +6024,9 @@ function dexieCloud(dexie) {
5969
6024
  phase: 'initial',
5970
6025
  status: 'not-started',
5971
6026
  }),
6027
+ events: {
6028
+ syncComplete,
6029
+ },
5972
6030
  persistedSyncState: new BehaviorSubject(undefined),
5973
6031
  userInteraction: new BehaviorSubject(undefined),
5974
6032
  webSocketStatus: new BehaviorSubject('not-started'),
@@ -6062,6 +6120,8 @@ function dexieCloud(dexie) {
6062
6120
  if (!db.cloud.isServiceWorkerDB) {
6063
6121
  subscriptions.push(computeSyncState(db).subscribe(dexie.cloud.syncState));
6064
6122
  }
6123
+ // Forward db.syncCompleteEvent to be publicly consumable via db.cloud.events.syncComplete:
6124
+ subscriptions.push(db.syncCompleteEvent.subscribe(syncComplete));
6065
6125
  //verifyConfig(db.cloud.options); Not needed (yet at least!)
6066
6126
  // Verify the user has allowed version increment.
6067
6127
  if (!db.tables.every((table) => table.core)) {
@@ -6169,15 +6229,16 @@ function dexieCloud(dexie) {
6169
6229
  ]).toPromise();
6170
6230
  }
6171
6231
  // HERE: If requireAuth, do athentication now.
6232
+ let changedUser = false;
6172
6233
  if ((_c = db.cloud.options) === null || _c === void 0 ? void 0 : _c.requireAuth) {
6173
- yield login(db);
6234
+ changedUser = yield login(db);
6174
6235
  }
6175
6236
  if (localSyncWorker)
6176
6237
  localSyncWorker.stop();
6177
6238
  localSyncWorker = null;
6178
6239
  throwIfClosed();
6179
6240
  if (db.cloud.usingServiceWorker && ((_d = db.cloud.options) === null || _d === void 0 ? void 0 : _d.databaseUrl)) {
6180
- registerSyncEvent(db, 'push').catch(() => { });
6241
+ registerSyncEvent(db, changedUser ? 'pull' : 'push').catch(() => { });
6181
6242
  registerPeriodicSyncEvent(db).catch(() => { });
6182
6243
  }
6183
6244
  else if (((_e = db.cloud.options) === null || _e === void 0 ? void 0 : _e.databaseUrl) &&
@@ -6186,7 +6247,7 @@ function dexieCloud(dexie) {
6186
6247
  // There's no SW. Start SyncWorker instead.
6187
6248
  localSyncWorker = LocalSyncWorker(db, db.cloud.options, db.cloud.schema);
6188
6249
  localSyncWorker.start();
6189
- triggerSync(db, 'push');
6250
+ triggerSync(db, changedUser ? 'pull' : 'push');
6190
6251
  }
6191
6252
  // Listen to online event and do sync.
6192
6253
  throwIfClosed();
@@ -6213,7 +6274,7 @@ function dexieCloud(dexie) {
6213
6274
  });
6214
6275
  }
6215
6276
  }
6216
- dexieCloud.version = '4.0.1-beta.35';
6277
+ dexieCloud.version = '4.0.1-beta.36';
6217
6278
  Dexie.Cloud = dexieCloud;
6218
6279
 
6219
6280
  // In case the SW lives for a while, let it reuse already opened connections: