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
  *
@@ -4661,13 +4661,12 @@ function $Y(db) {
4661
4661
  * @param db
4662
4662
  * @returns
4663
4663
  */
4664
- function listYClientMessagesAndStateVector(db) {
4665
- var _a;
4664
+ function listYClientMessagesAndStateVector(db, tablesToSync) {
4666
4665
  return __awaiter(this, void 0, void 0, function* () {
4667
4666
  const result = [];
4668
4667
  const lastUpdateIds = {};
4669
- for (const table of db.tables) {
4670
- if (table.schema.yProps && ((_a = db.cloud.schema) === null || _a === void 0 ? void 0 : _a[table.name].markedForSync)) {
4668
+ for (const table of tablesToSync) {
4669
+ if (table.schema.yProps) {
4671
4670
  for (const yProp of table.schema.yProps) {
4672
4671
  const Y = $Y(db); // This is how we retrieve the user-provided Y library
4673
4672
  const yTable = db.table(yProp.updatesTable); // the updates-table for this combo of table+propName
@@ -4801,7 +4800,7 @@ function applyYServerMessages(yMessages, db) {
4801
4800
  }
4802
4801
 
4803
4802
  function updateYSyncStates(lastUpdateIdsBeforeSync, receivedUntilsAfterSync, db, serverRevision) {
4804
- var _a, _b;
4803
+ var _a, _b, _c, _d, _e;
4805
4804
  return __awaiter(this, void 0, void 0, function* () {
4806
4805
  // We want to update unsentFrom for each yTable to the value specified in first argument
4807
4806
  // because we got those values before we synced with server and here we are back from server
@@ -4809,7 +4808,7 @@ function updateYSyncStates(lastUpdateIdsBeforeSync, receivedUntilsAfterSync, db,
4809
4808
  // we can safely store unsentFrom to a value of the last update + 1 here.
4810
4809
  // We also want to update receivedUntil for each yTable to the value specified in the second argument,
4811
4810
  // because that contains the highest resulted id of each update from server after storing it.
4812
- // We could do these two tasks separately, but that would require two update calls on the same YSyncState, so
4811
+ // We could do these two tasks separately, but that would require two update calls on the same YSyncState, so
4813
4812
  // to optimize the dexie calls, we merge these two maps into a single one so we can do a single update request
4814
4813
  // per yTable.
4815
4814
  const mergedSpec = {};
@@ -4821,28 +4820,42 @@ function updateYSyncStates(lastUpdateIdsBeforeSync, receivedUntilsAfterSync, db,
4821
4820
  (_b = mergedSpec[yTable]) !== null && _b !== void 0 ? _b : (mergedSpec[yTable] = {});
4822
4821
  mergedSpec[yTable].receivedUntil = lastUpdateId;
4823
4822
  }
4824
- // Now go through the merged map and update YSyncStates accordingly:
4825
- for (const [yTable, { unsentFrom, receivedUntil }] of Object.entries(mergedSpec)) {
4823
+ // Now go through all yTables and update their YSyncStates:
4824
+ const allYTables = Object.values(db.dx._dbSchema)
4825
+ .filter((tblSchema) => tblSchema.yProps)
4826
+ .map((tblSchema) => tblSchema.yProps.map((yProp) => yProp.updatesTable))
4827
+ .flat();
4828
+ for (const yTable of allYTables) {
4829
+ const mergedEntry = mergedSpec[yTable];
4830
+ const unsentFrom = (_c = mergedEntry === null || mergedEntry === void 0 ? void 0 : mergedEntry.unsentFrom) !== null && _c !== void 0 ? _c : 1;
4831
+ const receivedUntil = (_e = (_d = mergedEntry === null || mergedEntry === void 0 ? void 0 : mergedEntry.receivedUntil) !== null && _d !== void 0 ? _d :
4832
+ // from local because we are in the same parent transaction (in sync.ts) that
4833
+ // applied all updates from the server
4834
+ (yield db
4835
+ .table(yTable)
4836
+ .where('i')
4837
+ .between(1, Infinity) // Because i might be string DEXIE_CLOUD_SYNCER_ID if not a number.
4838
+ .reverse()
4839
+ .limit(1)
4840
+ .primaryKeys())[0]) !== null && _e !== void 0 ? _e : 0;
4826
4841
  // We're already in a transaction, but for the sake of
4827
4842
  // code readability and correctness, let's launch an atomic sub transaction:
4828
4843
  yield db.transaction('rw', yTable, () => __awaiter(this, void 0, void 0, function* () {
4829
- const state = yield db.table(yTable).get(DEXIE_CLOUD_SYNCER_ID);
4844
+ const state = yield db
4845
+ .table(yTable)
4846
+ .get(DEXIE_CLOUD_SYNCER_ID);
4830
4847
  if (!state) {
4831
4848
  yield db.table(yTable).add({
4832
4849
  i: DEXIE_CLOUD_SYNCER_ID,
4833
- unsentFrom: unsentFrom || 1,
4834
- receivedUntil: receivedUntil || 0,
4850
+ unsentFrom,
4851
+ receivedUntil,
4835
4852
  serverRev: serverRevision,
4836
4853
  });
4837
4854
  }
4838
4855
  else {
4839
- if (unsentFrom) {
4840
- state.unsentFrom = Math.max(unsentFrom, state.unsentFrom || 1);
4841
- }
4842
- if (receivedUntil) {
4843
- state.receivedUntil = Math.max(receivedUntil, state.receivedUntil || 0);
4844
- state.serverRev = serverRevision;
4845
- }
4856
+ state.unsentFrom = Math.max(unsentFrom, state.unsentFrom || 1);
4857
+ state.receivedUntil = Math.max(receivedUntil, state.receivedUntil || 0);
4858
+ state.serverRev = serverRevision;
4846
4859
  yield db.table(yTable).put(state);
4847
4860
  }
4848
4861
  }));
@@ -4855,7 +4868,9 @@ const BINSTREAM_TYPE_TABLE_AND_PROP = 2;
4855
4868
  const BINSTREAM_TYPE_DOCUMENT = 3;
4856
4869
  function downloadYDocsFromServer(db, databaseUrl, { yDownloadedRealms, realms }) {
4857
4870
  return __awaiter(this, void 0, void 0, function* () {
4858
- if (yDownloadedRealms && realms && realms.every(realmId => yDownloadedRealms[realmId] === '*')) {
4871
+ if (yDownloadedRealms &&
4872
+ realms &&
4873
+ realms.every((realmId) => yDownloadedRealms[realmId] === '*')) {
4859
4874
  return; // Already done!
4860
4875
  }
4861
4876
  console.debug('Downloading Y.Docs from added realms');
@@ -4895,16 +4910,19 @@ function downloadYDocsFromServer(db, databaseUrl, { yDownloadedRealms, realms })
4895
4910
  yield yTable.bulkAdd(docsToInsert);
4896
4911
  docsToInsert = [];
4897
4912
  }
4898
- if (currentRealmId && currentTable && currentProp && (lastDoc || completedRealm)) {
4899
- yield db.$syncState.update('syncState', completedRealm
4900
- ? '*'
4901
- : {
4902
- [`yDownloadedRealms.${currentRealmId}`]: {
4913
+ if (currentRealmId &&
4914
+ ((currentTable && currentProp && lastDoc) || completedRealm)) {
4915
+ yield db.$syncState.update('syncState', (syncState) => {
4916
+ const yDownloadedRealms = syncState.yDownloadedRealms || {};
4917
+ yDownloadedRealms[currentRealmId] = completedRealm
4918
+ ? '*'
4919
+ : {
4903
4920
  tbl: currentTable,
4904
4921
  prop: currentProp,
4905
4922
  key: lastDoc.k,
4906
- },
4907
- });
4923
+ };
4924
+ syncState.yDownloadedRealms = yDownloadedRealms;
4925
+ });
4908
4926
  }
4909
4927
  });
4910
4928
  }
@@ -5054,7 +5072,7 @@ function _sync(db, options, schema, { isInitialSync, cancelToken, justCheckIfNee
5054
5072
  const syncState = yield db.getPersistedSyncState();
5055
5073
  const baseRevs = yield db.$baseRevs.toArray();
5056
5074
  let clientChanges = yield listClientChanges(mutationTables);
5057
- const yResults = yield listYClientMessagesAndStateVector(db);
5075
+ const yResults = yield listYClientMessagesAndStateVector(db, tablesToSync);
5058
5076
  throwIfCancelled(cancelToken);
5059
5077
  if (doSyncify) {
5060
5078
  const alreadySyncedRealms = [
@@ -6613,7 +6631,7 @@ class TokenExpiredError extends Error {
6613
6631
 
6614
6632
  function createYClientUpdateObservable(db) {
6615
6633
  const yTableRecords = flatten(db.tables
6616
- .filter((table) => { var _a; return ((_a = db.cloud.schema) === null || _a === void 0 ? void 0 : _a[table.name].markedForSync) && table.schema.yProps; })
6634
+ .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; })
6617
6635
  .map((table) => table.schema.yProps.map((p) => ({
6618
6636
  table: table.name,
6619
6637
  ydocProp: p.prop,
@@ -6644,7 +6662,12 @@ function createYClientUpdateObservable(db) {
6644
6662
  };
6645
6663
  });
6646
6664
  }));
6647
- })).pipe(mergeMap$1((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.
6665
+ })).pipe(
6666
+ // Flatten the array of messages.
6667
+ // If messageProducer emits empty array, nothing is emitted
6668
+ // but if messageProducer emits array of messages, they are
6669
+ // emitted one by one.
6670
+ mergeMap$1((messages) => messages));
6648
6671
  }
6649
6672
 
6650
6673
  function getAwarenessLibrary(db) {
@@ -6661,25 +6684,24 @@ const SERVER_PING_TIMEOUT = 20000;
6661
6684
  const CLIENT_PING_INTERVAL = 30000;
6662
6685
  const FAIL_RETRY_WAIT_TIME = 60000;
6663
6686
  class WSObservable extends Observable$1 {
6664
- constructor(db, rev, realmSetHash, clientIdentity, messageProducer, webSocketStatus, token, tokenExpiration) {
6665
- super((subscriber) => new WSConnection(db, rev, realmSetHash, clientIdentity, token, tokenExpiration, subscriber, messageProducer, webSocketStatus));
6687
+ constructor(db, rev, realmSetHash, clientIdentity, messageProducer, webSocketStatus, user) {
6688
+ super((subscriber) => new WSConnection(db, rev, realmSetHash, clientIdentity, user, subscriber, messageProducer, webSocketStatus));
6666
6689
  }
6667
6690
  }
6668
6691
  let counter = 0;
6669
6692
  class WSConnection extends Subscription$1 {
6670
- constructor(db, rev, realmSetHash, clientIdentity, token, tokenExpiration, subscriber, messageProducer, webSocketStatus) {
6693
+ constructor(db, rev, realmSetHash, clientIdentity, user, subscriber, messageProducer, webSocketStatus) {
6671
6694
  super(() => this.teardown());
6672
6695
  this.id = ++counter;
6673
6696
  this.subscriptions = new Set();
6674
6697
  this.reconnecting = false;
6675
- console.debug('New WebSocket Connection', this.id, token ? 'authorized' : 'unauthorized');
6698
+ console.debug('New WebSocket Connection', this.id, user.accessToken ? 'authorized' : 'unauthorized');
6676
6699
  this.db = db;
6677
6700
  this.databaseUrl = db.cloud.options.databaseUrl;
6678
6701
  this.rev = rev;
6679
6702
  this.realmSetHash = realmSetHash;
6680
6703
  this.clientIdentity = clientIdentity;
6681
- this.token = token;
6682
- this.tokenExpiration = tokenExpiration;
6704
+ this.user = user;
6683
6705
  this.subscriber = subscriber;
6684
6706
  this.lastUserActivity = new Date();
6685
6707
  this.messageProducer = messageProducer;
@@ -6739,7 +6761,8 @@ class WSConnection extends Subscription$1 {
6739
6761
  //console.debug('SyncStatus: DUBB: Ooops it was closed!');
6740
6762
  return;
6741
6763
  }
6742
- if (this.tokenExpiration && this.tokenExpiration < new Date()) {
6764
+ const tokenExpiration = this.user.accessTokenExpiration;
6765
+ if (tokenExpiration && tokenExpiration < new Date()) {
6743
6766
  this.subscriber.error(new TokenExpiredError()); // Will be handled in connectWebSocket.ts.
6744
6767
  return;
6745
6768
  }
@@ -6794,8 +6817,8 @@ class WSConnection extends Subscription$1 {
6794
6817
  searchParams.set('rev', this.rev);
6795
6818
  searchParams.set('realmsHash', this.realmSetHash);
6796
6819
  searchParams.set('clientId', this.clientIdentity);
6797
- if (this.token) {
6798
- searchParams.set('token', this.token);
6820
+ if (this.user.accessToken) {
6821
+ searchParams.set('token', this.user.accessToken);
6799
6822
  }
6800
6823
  // Connect the WebSocket to given url:
6801
6824
  console.debug('dexie-cloud WebSocket create');
@@ -6881,7 +6904,9 @@ class WSConnection extends Subscription$1 {
6881
6904
  }
6882
6905
  }
6883
6906
  }));
6884
- this.subscriptions.add(createYClientUpdateObservable(this.db).subscribe(this.db.messageProducer));
6907
+ if (this.user.isLoggedIn && !isEagerSyncDisabled(this.db)) {
6908
+ this.subscriptions.add(createYClientUpdateObservable(this.db).subscribe(this.db.messageProducer));
6909
+ }
6885
6910
  }
6886
6911
  catch (error) {
6887
6912
  this.pauseUntil = new Date(Date.now() + FAIL_RETRY_WAIT_TIME);
@@ -6961,7 +6986,7 @@ function connectWebSocket(db) {
6961
6986
  // If no new entries, server won't bother the client. If new entries, server sends only those
6962
6987
  // and the baseRev of the last from same client-ID.
6963
6988
  if (userLogin) {
6964
- return new WSObservable(db, db.cloud.persistedSyncState.value.serverRevision, realmSetHash, db.cloud.persistedSyncState.value.clientIdentity, messageProducer, db.cloud.webSocketStatus, userLogin.accessToken, userLogin.accessTokenExpiration);
6989
+ return new WSObservable(db, db.cloud.persistedSyncState.value.serverRevision, realmSetHash, db.cloud.persistedSyncState.value.clientIdentity, messageProducer, db.cloud.webSocketStatus, userLogin);
6965
6990
  }
6966
6991
  else {
6967
6992
  return from$1([]);
@@ -7768,9 +7793,9 @@ const getInvitesObservable = associate((db) => {
7768
7793
  });
7769
7794
 
7770
7795
  function createYHandler(db) {
7771
- const awap = getAwarenessLibrary(db);
7772
7796
  return (provider) => {
7773
7797
  var _a;
7798
+ const awap = getAwarenessLibrary(db);
7774
7799
  const doc = provider.doc;
7775
7800
  const { parentTable, parentId, parentProp, updatesTable } = doc.meta;
7776
7801
  if (!((_a = db.cloud.schema) === null || _a === void 0 ? void 0 : _a[parentTable].markedForSync)) {
@@ -7782,7 +7807,8 @@ function createYHandler(db) {
7782
7807
  awareness.on('update', ({ added, updated, removed }, origin) => {
7783
7808
  // Send the update
7784
7809
  const changedClients = added.concat(updated).concat(removed);
7785
- if (origin !== 'server') {
7810
+ const user = db.cloud.currentUser.value;
7811
+ if (origin !== 'server' && user.isLoggedIn && !isEagerSyncDisabled(db)) {
7786
7812
  const update = awap.encodeAwarenessUpdate(awareness, changedClients);
7787
7813
  db.messageProducer.next({
7788
7814
  type: 'aware',
@@ -7823,7 +7849,8 @@ function createYHandler(db) {
7823
7849
  // Keep "connected" state in a variable so we can check it after async operations
7824
7850
  connected = wsStatus === 'connected';
7825
7851
  // We are or got connected. Open the document on the server.
7826
- if (wsStatus === "connected") {
7852
+ const user = db.cloud.currentUser.value;
7853
+ if (wsStatus === "connected" && user.isLoggedIn && !isEagerSyncDisabled(db)) {
7827
7854
  ++currentFlowId;
7828
7855
  openDocumentOnServer().catch(error => {
7829
7856
  console.warn(`Error catched in createYHandler.ts: ${error}`);
@@ -7929,7 +7956,7 @@ function dexieCloud(dexie) {
7929
7956
  const syncComplete = new Subject();
7930
7957
  dexie.cloud = {
7931
7958
  // @ts-ignore
7932
- version: "4.1.0-alpha.2",
7959
+ version: "4.1.0-alpha.5",
7933
7960
  options: Object.assign({}, DEFAULT_OPTIONS),
7934
7961
  schema: null,
7935
7962
  get currentUserId() {
@@ -8231,7 +8258,7 @@ function dexieCloud(dexie) {
8231
8258
  }
8232
8259
  }
8233
8260
  // @ts-ignore
8234
- dexieCloud.version = "4.1.0-alpha.2";
8261
+ dexieCloud.version = "4.1.0-alpha.5";
8235
8262
  Dexie.Cloud = dexieCloud;
8236
8263
 
8237
8264
  // In case the SW lives for a while, let it reuse already opened connections: