dexie-cloud-addon 4.1.0-alpha.2 → 4.1.0-alpha.5

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.1.0-alpha.2, Mon Oct 07 2024
11
+ * Version 4.1.0-alpha.5, Mon Oct 14 2024
12
12
  *
13
13
  * https://dexie.org
14
14
  *
@@ -4664,13 +4664,12 @@
4664
4664
  * @param db
4665
4665
  * @returns
4666
4666
  */
4667
- function listYClientMessagesAndStateVector(db) {
4668
- var _a;
4667
+ function listYClientMessagesAndStateVector(db, tablesToSync) {
4669
4668
  return __awaiter(this, void 0, void 0, function* () {
4670
4669
  const result = [];
4671
4670
  const lastUpdateIds = {};
4672
- for (const table of db.tables) {
4673
- if (table.schema.yProps && ((_a = db.cloud.schema) === null || _a === void 0 ? void 0 : _a[table.name].markedForSync)) {
4671
+ for (const table of tablesToSync) {
4672
+ if (table.schema.yProps) {
4674
4673
  for (const yProp of table.schema.yProps) {
4675
4674
  const Y = $Y(db); // This is how we retrieve the user-provided Y library
4676
4675
  const yTable = db.table(yProp.updatesTable); // the updates-table for this combo of table+propName
@@ -4804,7 +4803,7 @@
4804
4803
  }
4805
4804
 
4806
4805
  function updateYSyncStates(lastUpdateIdsBeforeSync, receivedUntilsAfterSync, db, serverRevision) {
4807
- var _a, _b;
4806
+ var _a, _b, _c, _d, _e;
4808
4807
  return __awaiter(this, void 0, void 0, function* () {
4809
4808
  // We want to update unsentFrom for each yTable to the value specified in first argument
4810
4809
  // because we got those values before we synced with server and here we are back from server
@@ -4812,7 +4811,7 @@
4812
4811
  // we can safely store unsentFrom to a value of the last update + 1 here.
4813
4812
  // We also want to update receivedUntil for each yTable to the value specified in the second argument,
4814
4813
  // because that contains the highest resulted id of each update from server after storing it.
4815
- // We could do these two tasks separately, but that would require two update calls on the same YSyncState, so
4814
+ // We could do these two tasks separately, but that would require two update calls on the same YSyncState, so
4816
4815
  // to optimize the dexie calls, we merge these two maps into a single one so we can do a single update request
4817
4816
  // per yTable.
4818
4817
  const mergedSpec = {};
@@ -4824,28 +4823,42 @@
4824
4823
  (_b = mergedSpec[yTable]) !== null && _b !== void 0 ? _b : (mergedSpec[yTable] = {});
4825
4824
  mergedSpec[yTable].receivedUntil = lastUpdateId;
4826
4825
  }
4827
- // Now go through the merged map and update YSyncStates accordingly:
4828
- for (const [yTable, { unsentFrom, receivedUntil }] of Object.entries(mergedSpec)) {
4826
+ // Now go through all yTables and update their YSyncStates:
4827
+ const allYTables = Object.values(db.dx._dbSchema)
4828
+ .filter((tblSchema) => tblSchema.yProps)
4829
+ .map((tblSchema) => tblSchema.yProps.map((yProp) => yProp.updatesTable))
4830
+ .flat();
4831
+ for (const yTable of allYTables) {
4832
+ const mergedEntry = mergedSpec[yTable];
4833
+ const unsentFrom = (_c = mergedEntry === null || mergedEntry === void 0 ? void 0 : mergedEntry.unsentFrom) !== null && _c !== void 0 ? _c : 1;
4834
+ const receivedUntil = (_e = (_d = mergedEntry === null || mergedEntry === void 0 ? void 0 : mergedEntry.receivedUntil) !== null && _d !== void 0 ? _d :
4835
+ // from local because we are in the same parent transaction (in sync.ts) that
4836
+ // applied all updates from the server
4837
+ (yield db
4838
+ .table(yTable)
4839
+ .where('i')
4840
+ .between(1, Infinity) // Because i might be string DEXIE_CLOUD_SYNCER_ID if not a number.
4841
+ .reverse()
4842
+ .limit(1)
4843
+ .primaryKeys())[0]) !== null && _e !== void 0 ? _e : 0;
4829
4844
  // We're already in a transaction, but for the sake of
4830
4845
  // code readability and correctness, let's launch an atomic sub transaction:
4831
4846
  yield db.transaction('rw', yTable, () => __awaiter(this, void 0, void 0, function* () {
4832
- const state = yield db.table(yTable).get(DEXIE_CLOUD_SYNCER_ID);
4847
+ const state = yield db
4848
+ .table(yTable)
4849
+ .get(DEXIE_CLOUD_SYNCER_ID);
4833
4850
  if (!state) {
4834
4851
  yield db.table(yTable).add({
4835
4852
  i: DEXIE_CLOUD_SYNCER_ID,
4836
- unsentFrom: unsentFrom || 1,
4837
- receivedUntil: receivedUntil || 0,
4853
+ unsentFrom,
4854
+ receivedUntil,
4838
4855
  serverRev: serverRevision,
4839
4856
  });
4840
4857
  }
4841
4858
  else {
4842
- if (unsentFrom) {
4843
- state.unsentFrom = Math.max(unsentFrom, state.unsentFrom || 1);
4844
- }
4845
- if (receivedUntil) {
4846
- state.receivedUntil = Math.max(receivedUntil, state.receivedUntil || 0);
4847
- state.serverRev = serverRevision;
4848
- }
4859
+ state.unsentFrom = Math.max(unsentFrom, state.unsentFrom || 1);
4860
+ state.receivedUntil = Math.max(receivedUntil, state.receivedUntil || 0);
4861
+ state.serverRev = serverRevision;
4849
4862
  yield db.table(yTable).put(state);
4850
4863
  }
4851
4864
  }));
@@ -4858,7 +4871,9 @@
4858
4871
  const BINSTREAM_TYPE_DOCUMENT = 3;
4859
4872
  function downloadYDocsFromServer(db, databaseUrl, { yDownloadedRealms, realms }) {
4860
4873
  return __awaiter(this, void 0, void 0, function* () {
4861
- if (yDownloadedRealms && realms && realms.every(realmId => yDownloadedRealms[realmId] === '*')) {
4874
+ if (yDownloadedRealms &&
4875
+ realms &&
4876
+ realms.every((realmId) => yDownloadedRealms[realmId] === '*')) {
4862
4877
  return; // Already done!
4863
4878
  }
4864
4879
  console.debug('Downloading Y.Docs from added realms');
@@ -4898,16 +4913,19 @@
4898
4913
  yield yTable.bulkAdd(docsToInsert);
4899
4914
  docsToInsert = [];
4900
4915
  }
4901
- if (currentRealmId && currentTable && currentProp && (lastDoc || completedRealm)) {
4902
- yield db.$syncState.update('syncState', completedRealm
4903
- ? '*'
4904
- : {
4905
- [`yDownloadedRealms.${currentRealmId}`]: {
4916
+ if (currentRealmId &&
4917
+ ((currentTable && currentProp && lastDoc) || completedRealm)) {
4918
+ yield db.$syncState.update('syncState', (syncState) => {
4919
+ const yDownloadedRealms = syncState.yDownloadedRealms || {};
4920
+ yDownloadedRealms[currentRealmId] = completedRealm
4921
+ ? '*'
4922
+ : {
4906
4923
  tbl: currentTable,
4907
4924
  prop: currentProp,
4908
4925
  key: lastDoc.k,
4909
- },
4910
- });
4926
+ };
4927
+ syncState.yDownloadedRealms = yDownloadedRealms;
4928
+ });
4911
4929
  }
4912
4930
  });
4913
4931
  }
@@ -5057,7 +5075,7 @@
5057
5075
  const syncState = yield db.getPersistedSyncState();
5058
5076
  const baseRevs = yield db.$baseRevs.toArray();
5059
5077
  let clientChanges = yield listClientChanges(mutationTables);
5060
- const yResults = yield listYClientMessagesAndStateVector(db);
5078
+ const yResults = yield listYClientMessagesAndStateVector(db, tablesToSync);
5061
5079
  throwIfCancelled(cancelToken);
5062
5080
  if (doSyncify) {
5063
5081
  const alreadySyncedRealms = [
@@ -6616,7 +6634,7 @@
6616
6634
 
6617
6635
  function createYClientUpdateObservable(db) {
6618
6636
  const yTableRecords = flatten(db.tables
6619
- .filter((table) => { var _a; return ((_a = db.cloud.schema) === null || _a === void 0 ? void 0 : _a[table.name].markedForSync) && table.schema.yProps; })
6637
+ .filter((table) => { var _a, _b; return ((_b = (_a = db.cloud.schema) === null || _a === void 0 ? void 0 : _a[table.name]) === null || _b === void 0 ? void 0 : _b.markedForSync) && table.schema.yProps; })
6620
6638
  .map((table) => table.schema.yProps.map((p) => ({
6621
6639
  table: table.name,
6622
6640
  ydocProp: p.prop,
@@ -6647,7 +6665,12 @@
6647
6665
  };
6648
6666
  });
6649
6667
  }));
6650
- })).pipe(rxjs.mergeMap((messages) => messages)); // Flattens the array of messages. If messageProducer emits empty array, nothing is emitted but if messageProducer emits array of messages, they are emitted one by one.
6668
+ })).pipe(
6669
+ // Flatten the array of messages.
6670
+ // If messageProducer emits empty array, nothing is emitted
6671
+ // but if messageProducer emits array of messages, they are
6672
+ // emitted one by one.
6673
+ rxjs.mergeMap((messages) => messages));
6651
6674
  }
6652
6675
 
6653
6676
  function getAwarenessLibrary(db) {
@@ -6664,25 +6687,24 @@
6664
6687
  const CLIENT_PING_INTERVAL = 30000;
6665
6688
  const FAIL_RETRY_WAIT_TIME = 60000;
6666
6689
  class WSObservable extends rxjs.Observable {
6667
- constructor(db, rev, realmSetHash, clientIdentity, messageProducer, webSocketStatus, token, tokenExpiration) {
6668
- super((subscriber) => new WSConnection(db, rev, realmSetHash, clientIdentity, token, tokenExpiration, subscriber, messageProducer, webSocketStatus));
6690
+ constructor(db, rev, realmSetHash, clientIdentity, messageProducer, webSocketStatus, user) {
6691
+ super((subscriber) => new WSConnection(db, rev, realmSetHash, clientIdentity, user, subscriber, messageProducer, webSocketStatus));
6669
6692
  }
6670
6693
  }
6671
6694
  let counter = 0;
6672
6695
  class WSConnection extends rxjs.Subscription {
6673
- constructor(db, rev, realmSetHash, clientIdentity, token, tokenExpiration, subscriber, messageProducer, webSocketStatus) {
6696
+ constructor(db, rev, realmSetHash, clientIdentity, user, subscriber, messageProducer, webSocketStatus) {
6674
6697
  super(() => this.teardown());
6675
6698
  this.id = ++counter;
6676
6699
  this.subscriptions = new Set();
6677
6700
  this.reconnecting = false;
6678
- console.debug('New WebSocket Connection', this.id, token ? 'authorized' : 'unauthorized');
6701
+ console.debug('New WebSocket Connection', this.id, user.accessToken ? 'authorized' : 'unauthorized');
6679
6702
  this.db = db;
6680
6703
  this.databaseUrl = db.cloud.options.databaseUrl;
6681
6704
  this.rev = rev;
6682
6705
  this.realmSetHash = realmSetHash;
6683
6706
  this.clientIdentity = clientIdentity;
6684
- this.token = token;
6685
- this.tokenExpiration = tokenExpiration;
6707
+ this.user = user;
6686
6708
  this.subscriber = subscriber;
6687
6709
  this.lastUserActivity = new Date();
6688
6710
  this.messageProducer = messageProducer;
@@ -6742,7 +6764,8 @@
6742
6764
  //console.debug('SyncStatus: DUBB: Ooops it was closed!');
6743
6765
  return;
6744
6766
  }
6745
- if (this.tokenExpiration && this.tokenExpiration < new Date()) {
6767
+ const tokenExpiration = this.user.accessTokenExpiration;
6768
+ if (tokenExpiration && tokenExpiration < new Date()) {
6746
6769
  this.subscriber.error(new TokenExpiredError()); // Will be handled in connectWebSocket.ts.
6747
6770
  return;
6748
6771
  }
@@ -6797,8 +6820,8 @@
6797
6820
  searchParams.set('rev', this.rev);
6798
6821
  searchParams.set('realmsHash', this.realmSetHash);
6799
6822
  searchParams.set('clientId', this.clientIdentity);
6800
- if (this.token) {
6801
- searchParams.set('token', this.token);
6823
+ if (this.user.accessToken) {
6824
+ searchParams.set('token', this.user.accessToken);
6802
6825
  }
6803
6826
  // Connect the WebSocket to given url:
6804
6827
  console.debug('dexie-cloud WebSocket create');
@@ -6884,7 +6907,9 @@
6884
6907
  }
6885
6908
  }
6886
6909
  }));
6887
- this.subscriptions.add(createYClientUpdateObservable(this.db).subscribe(this.db.messageProducer));
6910
+ if (this.user.isLoggedIn && !isEagerSyncDisabled(this.db)) {
6911
+ this.subscriptions.add(createYClientUpdateObservable(this.db).subscribe(this.db.messageProducer));
6912
+ }
6888
6913
  }
6889
6914
  catch (error) {
6890
6915
  this.pauseUntil = new Date(Date.now() + FAIL_RETRY_WAIT_TIME);
@@ -6964,7 +6989,7 @@
6964
6989
  // If no new entries, server won't bother the client. If new entries, server sends only those
6965
6990
  // and the baseRev of the last from same client-ID.
6966
6991
  if (userLogin) {
6967
- return new WSObservable(db, db.cloud.persistedSyncState.value.serverRevision, realmSetHash, db.cloud.persistedSyncState.value.clientIdentity, messageProducer, db.cloud.webSocketStatus, userLogin.accessToken, userLogin.accessTokenExpiration);
6992
+ return new WSObservable(db, db.cloud.persistedSyncState.value.serverRevision, realmSetHash, db.cloud.persistedSyncState.value.clientIdentity, messageProducer, db.cloud.webSocketStatus, userLogin);
6968
6993
  }
6969
6994
  else {
6970
6995
  return rxjs.from([]);
@@ -7771,9 +7796,9 @@
7771
7796
  });
7772
7797
 
7773
7798
  function createYHandler(db) {
7774
- const awap = getAwarenessLibrary(db);
7775
7799
  return (provider) => {
7776
7800
  var _a;
7801
+ const awap = getAwarenessLibrary(db);
7777
7802
  const doc = provider.doc;
7778
7803
  const { parentTable, parentId, parentProp, updatesTable } = doc.meta;
7779
7804
  if (!((_a = db.cloud.schema) === null || _a === void 0 ? void 0 : _a[parentTable].markedForSync)) {
@@ -7785,7 +7810,8 @@
7785
7810
  awareness.on('update', ({ added, updated, removed }, origin) => {
7786
7811
  // Send the update
7787
7812
  const changedClients = added.concat(updated).concat(removed);
7788
- if (origin !== 'server') {
7813
+ const user = db.cloud.currentUser.value;
7814
+ if (origin !== 'server' && user.isLoggedIn && !isEagerSyncDisabled(db)) {
7789
7815
  const update = awap.encodeAwarenessUpdate(awareness, changedClients);
7790
7816
  db.messageProducer.next({
7791
7817
  type: 'aware',
@@ -7826,7 +7852,8 @@
7826
7852
  // Keep "connected" state in a variable so we can check it after async operations
7827
7853
  connected = wsStatus === 'connected';
7828
7854
  // We are or got connected. Open the document on the server.
7829
- if (wsStatus === "connected") {
7855
+ const user = db.cloud.currentUser.value;
7856
+ if (wsStatus === "connected" && user.isLoggedIn && !isEagerSyncDisabled(db)) {
7830
7857
  ++currentFlowId;
7831
7858
  openDocumentOnServer().catch(error => {
7832
7859
  console.warn(`Error catched in createYHandler.ts: ${error}`);
@@ -7932,7 +7959,7 @@
7932
7959
  const syncComplete = new rxjs.Subject();
7933
7960
  dexie.cloud = {
7934
7961
  // @ts-ignore
7935
- version: "4.1.0-alpha.2",
7962
+ version: "4.1.0-alpha.5",
7936
7963
  options: Object.assign({}, DEFAULT_OPTIONS),
7937
7964
  schema: null,
7938
7965
  get currentUserId() {
@@ -8234,7 +8261,7 @@
8234
8261
  }
8235
8262
  }
8236
8263
  // @ts-ignore
8237
- dexieCloud.version = "4.1.0-alpha.2";
8264
+ dexieCloud.version = "4.1.0-alpha.5";
8238
8265
  Dexie.Cloud = dexieCloud;
8239
8266
 
8240
8267
  // In case the SW lives for a while, let it reuse already opened connections: