dexie-cloud-addon 4.2.0 → 4.2.1

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.
@@ -0,0 +1,6 @@
1
+ {
2
+ "demoUsers": {
3
+ "foo@demo.local": {},
4
+ "bar@demo.local": {}
5
+ }
6
+ }
@@ -8,7 +8,7 @@
8
8
  *
9
9
  * ==========================================================================
10
10
  *
11
- * Version 4.2.0, Wed Aug 13 2025
11
+ * Version 4.2.1, Wed Oct 01 2025
12
12
  *
13
13
  * https://dexie.org
14
14
  *
@@ -1653,17 +1653,14 @@ function listClientChanges(mutationTables_1, db_1) {
1653
1653
  : mutationTable;
1654
1654
  if (limit < Infinity)
1655
1655
  query = query.limit(limit);
1656
- const muts = yield query.toArray();
1657
- //const objTable = db.table(tableName);
1658
- /*for (const mut of muts) {
1659
- if (mut.type === "insert" || mut.type === "upsert") {
1660
- mut.values = await objTable.bulkGet(mut.keys);
1661
- }
1662
- }*/
1663
- return muts.map((mut) => ({
1656
+ let muts = yield query.toArray();
1657
+ muts = canonicalizeToUpdateOps(muts);
1658
+ muts = removeRedundantUpdateOps(muts);
1659
+ const rv = muts.map((mut) => ({
1664
1660
  table: tableName,
1665
1661
  mut,
1666
1662
  }));
1663
+ return rv;
1667
1664
  })));
1668
1665
  // Sort by time to get a true order of the operations (between tables)
1669
1666
  const sorted = flatten(allMutsOnTables).sort((a, b) => a.mut.txid === b.mut.txid
@@ -1692,6 +1689,69 @@ function listClientChanges(mutationTables_1, db_1) {
1692
1689
  return result;
1693
1690
  });
1694
1691
  }
1692
+ function removeRedundantUpdateOps(muts) {
1693
+ const updateCoverage = new Map();
1694
+ for (const mut of muts) {
1695
+ if (mut.type === 'update') {
1696
+ if (mut.keys.length !== 1 || mut.changeSpecs.length !== 1) {
1697
+ continue; // Don't optimize multi-key updates
1698
+ }
1699
+ const strKey = '' + mut.keys[0];
1700
+ const changeSpecs = mut.changeSpecs[0];
1701
+ if (Object.values(changeSpecs).some(v => typeof v === "object" && v && "@@propmod" in v)) {
1702
+ continue; // Cannot optimize if any PropModification is present
1703
+ }
1704
+ let keyCoverage = updateCoverage.get(strKey);
1705
+ if (keyCoverage) {
1706
+ keyCoverage.push({ txid: mut.txid, updateSpec: changeSpecs });
1707
+ }
1708
+ else {
1709
+ updateCoverage.set(strKey, [{ txid: mut.txid, updateSpec: changeSpecs }]);
1710
+ }
1711
+ }
1712
+ }
1713
+ muts = muts.filter(mut => {
1714
+ // Only apply optimization to update mutations that are single-key
1715
+ if (mut.type !== 'update')
1716
+ return true;
1717
+ if (mut.keys.length !== 1 || mut.changeSpecs.length !== 1)
1718
+ return true;
1719
+ // Keep track of properties that aren't overlapped by later transactions
1720
+ const unoverlappedProps = new Set(Object.keys(mut.changeSpecs[0]));
1721
+ const strKey = '' + mut.keys[0];
1722
+ const keyCoverage = updateCoverage.get(strKey);
1723
+ for (let i = keyCoverage.length - 1; i >= 0; --i) {
1724
+ const { txid, updateSpec } = keyCoverage[i];
1725
+ if (txid === mut.txid)
1726
+ break; // Stop when reaching own txid
1727
+ // If all changes in updateSpec are covered by all props on all mut.changeSpecs then
1728
+ // txid is redundant and can be removed.
1729
+ for (const keyPath of Object.keys(updateSpec)) {
1730
+ unoverlappedProps.delete(keyPath);
1731
+ }
1732
+ }
1733
+ if (unoverlappedProps.size === 0) {
1734
+ // This operation is completely overlapped by later operations. It can be removed.
1735
+ return false;
1736
+ }
1737
+ return true;
1738
+ });
1739
+ return muts;
1740
+ }
1741
+ function canonicalizeToUpdateOps(muts) {
1742
+ muts = muts.map(mut => {
1743
+ if (mut.type === 'modify' && mut.criteria.index === null) {
1744
+ // The criteria is on primary key. Convert to an update operation instead.
1745
+ // It is simpler for the server to handle and also more efficient.
1746
+ const updateMut = Object.assign(Object.assign({}, mut), { criteria: undefined, changeSpec: undefined, type: 'update', keys: mut.keys, changeSpecs: [mut.changeSpec] });
1747
+ delete updateMut.criteria;
1748
+ delete updateMut.changeSpec;
1749
+ return updateMut;
1750
+ }
1751
+ return mut;
1752
+ });
1753
+ return muts;
1754
+ }
1695
1755
 
1696
1756
  function randomString(bytes) {
1697
1757
  const buf = new Uint8Array(bytes);
@@ -6137,7 +6197,7 @@ function dexieCloud(dexie) {
6137
6197
  const syncComplete = new Subject();
6138
6198
  dexie.cloud = {
6139
6199
  // @ts-ignore
6140
- version: "4.2.0",
6200
+ version: "4.2.1",
6141
6201
  options: Object.assign({}, DEFAULT_OPTIONS),
6142
6202
  schema: null,
6143
6203
  get currentUserId() {
@@ -6454,7 +6514,7 @@ function dexieCloud(dexie) {
6454
6514
  }
6455
6515
  }
6456
6516
  // @ts-ignore
6457
- dexieCloud.version = "4.2.0";
6517
+ dexieCloud.version = "4.2.1";
6458
6518
  Dexie.Cloud = dexieCloud;
6459
6519
 
6460
6520
  export { dexieCloud as default, defineYDocTrigger, dexieCloud, getTiedObjectId, getTiedRealmId, resolveText };