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.
@@ -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
 
@@ -3143,7 +3182,10 @@ function encodeIdsForServer(schema, currentUser, changes) {
3143
3182
  function cloneChange(change, rewriteValues) {
3144
3183
  // clone on demand:
3145
3184
  return Object.assign(Object.assign({}, change), { muts: rewriteValues
3146
- ? change.muts.map((m) => (Object.assign(Object.assign({}, m), { keys: m.keys.slice(), values: m.values.slice() })))
3185
+ ? change.muts.map((m) => {
3186
+ return (m.type === 'insert' || m.type === 'upsert') && m.values
3187
+ ? Object.assign(Object.assign({}, m), { keys: m.keys.slice(), values: m.values.slice() }) : Object.assign(Object.assign({}, m), { keys: m.keys.slice() });
3188
+ })
3147
3189
  : change.muts.map((m) => (Object.assign(Object.assign({}, m), { keys: m.keys.slice() }))) });
3148
3190
  }
3149
3191
 
@@ -3389,7 +3431,7 @@ function sync(db, options, schema, syncOptions) {
3389
3431
  return _sync
3390
3432
  .apply(this, arguments)
3391
3433
  .then(() => {
3392
- if (!(syncOptions === null || syncOptions === void 0 ? void 0 : syncOptions.justCheckIfNeeded)) {
3434
+ if (!(syncOptions === null || syncOptions === void 0 ? void 0 : syncOptions.justCheckIfNeeded)) { // && syncOptions?.purpose !== 'push') {
3393
3435
  db.syncStateChangedEvent.next({
3394
3436
  phase: 'in-sync',
3395
3437
  });
@@ -3488,12 +3530,12 @@ function _sync(db, options, schema, { isInitialSync, cancelToken, justCheckIfNee
3488
3530
  }
3489
3531
  return [clientChanges, syncState, baseRevs];
3490
3532
  }));
3491
- const syncIsNeeded = clientChangeSet.some((set) => set.muts.some((mut) => mut.keys.length > 0));
3533
+ const pushSyncIsNeeded = clientChangeSet.some((set) => set.muts.some((mut) => mut.keys.length > 0));
3492
3534
  if (justCheckIfNeeded) {
3493
- console.debug('Sync is needed:', syncIsNeeded);
3494
- return syncIsNeeded;
3535
+ console.debug('Sync is needed:', pushSyncIsNeeded);
3536
+ return pushSyncIsNeeded;
3495
3537
  }
3496
- if (purpose === 'push' && !syncIsNeeded) {
3538
+ if (purpose === 'push' && !pushSyncIsNeeded) {
3497
3539
  // The purpose of this request was to push changes
3498
3540
  return false;
3499
3541
  }
@@ -3611,6 +3653,7 @@ function _sync(db, options, schema, { isInitialSync, cancelToken, justCheckIfNee
3611
3653
  return yield _sync(db, options, schema, { isInitialSync, cancelToken });
3612
3654
  }
3613
3655
  console.debug('SYNC DONE', { isInitialSync });
3656
+ db.syncCompleteEvent.next();
3614
3657
  return false; // Not needed anymore
3615
3658
  });
3616
3659
  }
@@ -3890,6 +3933,7 @@ function DexieCloudDB(dx) {
3890
3933
  if (!db) {
3891
3934
  const localSyncEvent = new Subject();
3892
3935
  let syncStateChangedEvent = new BroadcastedAndLocalEvent(`syncstatechanged-${dx.name}`);
3936
+ let syncCompleteEvent = new BroadcastedAndLocalEvent(`synccomplete-${dx.name}`);
3893
3937
  localSyncEvent['id'] = ++static_counter;
3894
3938
  let initiallySynced = false;
3895
3939
  db = {
@@ -3933,6 +3977,9 @@ function DexieCloudDB(dx) {
3933
3977
  get syncStateChangedEvent() {
3934
3978
  return syncStateChangedEvent;
3935
3979
  },
3980
+ get syncCompleteEvent() {
3981
+ return syncCompleteEvent;
3982
+ },
3936
3983
  dx,
3937
3984
  };
3938
3985
  const helperMethods = {
@@ -3964,6 +4011,7 @@ function DexieCloudDB(dx) {
3964
4011
  },
3965
4012
  reconfigure() {
3966
4013
  syncStateChangedEvent = new BroadcastedAndLocalEvent(`syncstatechanged-${dx.name}`);
4014
+ syncCompleteEvent = new BroadcastedAndLocalEvent(`synccomplete-${dx.name}`);
3967
4015
  },
3968
4016
  };
3969
4017
  Object.assign(db, helperMethods);
@@ -4178,7 +4226,7 @@ function login(db, hints) {
4178
4226
  }
4179
4227
  }
4180
4228
  // Already authenticated according to given hints.
4181
- return;
4229
+ return false;
4182
4230
  }
4183
4231
  const context = new AuthPersistedContext(db, {
4184
4232
  claims: {},
@@ -4203,6 +4251,7 @@ function login(db, hints) {
4203
4251
  // Make sure to resync as the new login will be authorized
4204
4252
  // for new realms.
4205
4253
  triggerSync(db, "pull");
4254
+ return true;
4206
4255
  });
4207
4256
  }
4208
4257
 
@@ -5095,7 +5144,15 @@ function connectWebSocket(db) {
5095
5144
  function createObservable() {
5096
5145
  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
5146
  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]) =>
5147
+ switchMap((syncState) => db.cloud.currentUser.pipe(map((userLogin) => [userLogin, syncState]))), switchMap(([userLogin, syncState]) => userIsReallyActive.pipe(map((isActive) => [isActive ? userLogin : null, syncState]))), switchMap(([userLogin, syncState]) => {
5148
+ if ((userLogin === null || userLogin === void 0 ? void 0 : userLogin.isLoggedIn) && !(syncState === null || syncState === void 0 ? void 0 : syncState.realms.includes(userLogin.userId))) {
5149
+ // We're in an in-between state when user is logged in but the user's realms are not yet synced.
5150
+ // Don't make this change reconnect the websocket just yet. Wait till syncState is updated
5151
+ // to iclude the user's realm.
5152
+ 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]));
5153
+ }
5154
+ return new BehaviorSubject([userLogin, syncState]);
5155
+ }), switchMap(([userLogin, syncState]) => __awaiter(this, void 0, void 0, function* () { return [userLogin, yield computeRealmSetHash(syncState)]; })), switchMap(([userLogin, realmSetHash]) =>
5099
5156
  // Let server end query changes from last entry of same client-ID and forward.
5100
5157
  // If no new entries, server won't bother the client. If new entries, server sends only those
5101
5158
  // and the baseRev of the last from same client-ID.
@@ -5957,8 +6014,9 @@ function dexieCloud(dexie) {
5957
6014
  localSyncWorker = null;
5958
6015
  currentUserEmitter.next(UNAUTHORIZED_USER);
5959
6016
  });
6017
+ const syncComplete = new Subject();
5960
6018
  dexie.cloud = {
5961
- version: '4.0.1-beta.35',
6019
+ version: '4.0.1-beta.37',
5962
6020
  options: Object.assign({}, DEFAULT_OPTIONS),
5963
6021
  schema: null,
5964
6022
  get currentUserId() {
@@ -5969,6 +6027,9 @@ function dexieCloud(dexie) {
5969
6027
  phase: 'initial',
5970
6028
  status: 'not-started',
5971
6029
  }),
6030
+ events: {
6031
+ syncComplete,
6032
+ },
5972
6033
  persistedSyncState: new BehaviorSubject(undefined),
5973
6034
  userInteraction: new BehaviorSubject(undefined),
5974
6035
  webSocketStatus: new BehaviorSubject('not-started'),
@@ -6062,6 +6123,8 @@ function dexieCloud(dexie) {
6062
6123
  if (!db.cloud.isServiceWorkerDB) {
6063
6124
  subscriptions.push(computeSyncState(db).subscribe(dexie.cloud.syncState));
6064
6125
  }
6126
+ // Forward db.syncCompleteEvent to be publicly consumable via db.cloud.events.syncComplete:
6127
+ subscriptions.push(db.syncCompleteEvent.subscribe(syncComplete));
6065
6128
  //verifyConfig(db.cloud.options); Not needed (yet at least!)
6066
6129
  // Verify the user has allowed version increment.
6067
6130
  if (!db.tables.every((table) => table.core)) {
@@ -6169,15 +6232,16 @@ function dexieCloud(dexie) {
6169
6232
  ]).toPromise();
6170
6233
  }
6171
6234
  // HERE: If requireAuth, do athentication now.
6235
+ let changedUser = false;
6172
6236
  if ((_c = db.cloud.options) === null || _c === void 0 ? void 0 : _c.requireAuth) {
6173
- yield login(db);
6237
+ changedUser = yield login(db);
6174
6238
  }
6175
6239
  if (localSyncWorker)
6176
6240
  localSyncWorker.stop();
6177
6241
  localSyncWorker = null;
6178
6242
  throwIfClosed();
6179
6243
  if (db.cloud.usingServiceWorker && ((_d = db.cloud.options) === null || _d === void 0 ? void 0 : _d.databaseUrl)) {
6180
- registerSyncEvent(db, 'push').catch(() => { });
6244
+ registerSyncEvent(db, changedUser ? 'pull' : 'push').catch(() => { });
6181
6245
  registerPeriodicSyncEvent(db).catch(() => { });
6182
6246
  }
6183
6247
  else if (((_e = db.cloud.options) === null || _e === void 0 ? void 0 : _e.databaseUrl) &&
@@ -6186,7 +6250,7 @@ function dexieCloud(dexie) {
6186
6250
  // There's no SW. Start SyncWorker instead.
6187
6251
  localSyncWorker = LocalSyncWorker(db, db.cloud.options, db.cloud.schema);
6188
6252
  localSyncWorker.start();
6189
- triggerSync(db, 'push');
6253
+ triggerSync(db, changedUser ? 'pull' : 'push');
6190
6254
  }
6191
6255
  // Listen to online event and do sync.
6192
6256
  throwIfClosed();
@@ -6213,7 +6277,7 @@ function dexieCloud(dexie) {
6213
6277
  });
6214
6278
  }
6215
6279
  }
6216
- dexieCloud.version = '4.0.1-beta.35';
6280
+ dexieCloud.version = '4.0.1-beta.37';
6217
6281
  Dexie.Cloud = dexieCloud;
6218
6282
 
6219
6283
  // In case the SW lives for a while, let it reuse already opened connections: