cry-synced-db-client 0.1.132 → 0.1.135
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.
- package/CHANGELOG.md +8 -0
- package/dist/index.js +31 -23
- package/dist/src/utils/conflictResolution.d.ts +4 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Versions
|
|
2
2
|
|
|
3
|
+
## 0.1.135 (2026-04-20)
|
|
4
|
+
|
|
5
|
+
- Conflict resolution: server wins on primitive field conflicts when `external._rev > local._rev`
|
|
6
|
+
- Previously local always won for overlapping primitive fields during conflict merge
|
|
7
|
+
- New rule applies recursively to object elements inside arrays (via `mergeObjectArrays` → `mergeObjects`)
|
|
8
|
+
- Arrays still unionize; nested objects without `_rev` keep local-wins behavior
|
|
9
|
+
- Affects dirty-conflict resolution path ([SyncEngine.resolveCollectionConflict](src/db/sync/SyncEngine.ts))
|
|
10
|
+
|
|
3
11
|
## 0.1.126 (2026-04-08)
|
|
4
12
|
|
|
5
13
|
- Eviction: remove out-of-scope records from Dexie and in-mem cache
|
package/dist/index.js
CHANGED
|
@@ -2319,6 +2319,7 @@ function resolveConflict(local, external) {
|
|
|
2319
2319
|
}
|
|
2320
2320
|
function mergeObjects(local, external) {
|
|
2321
2321
|
const result = __spreadValues({}, local);
|
|
2322
|
+
const serverWinsOnConflict = typeof local._rev === "number" && typeof external._rev === "number" && external._rev > local._rev;
|
|
2322
2323
|
for (const key of Object.keys(external)) {
|
|
2323
2324
|
if (key === "_id" || key === "_dirty") {
|
|
2324
2325
|
continue;
|
|
@@ -2336,6 +2337,8 @@ function mergeObjects(local, external) {
|
|
|
2336
2337
|
result[key] = mergeArrays(localValue, externalValue);
|
|
2337
2338
|
} else if (isPlainObject3(localValue) && isPlainObject3(externalValue)) {
|
|
2338
2339
|
result[key] = mergeObjects(localValue, externalValue);
|
|
2340
|
+
} else if (serverWinsOnConflict) {
|
|
2341
|
+
result[key] = externalValue;
|
|
2339
2342
|
}
|
|
2340
2343
|
}
|
|
2341
2344
|
return result;
|
|
@@ -2567,20 +2570,15 @@ var _SyncEngine = class _SyncEngine {
|
|
|
2567
2570
|
dirtyChangesMap.set(String(dirtyItem._id), dirtyItem);
|
|
2568
2571
|
}
|
|
2569
2572
|
const updates = [];
|
|
2570
|
-
const deletes = [];
|
|
2571
2573
|
const ids = dirtyChanges.map((dc) => dc._id);
|
|
2572
2574
|
const fullItems = await this.dexieDb.getByIds(collectionName, ids);
|
|
2573
2575
|
for (let i = 0; i < fullItems.length; i++) {
|
|
2574
2576
|
const fullItem = fullItems[i];
|
|
2575
2577
|
const id = ids[i];
|
|
2576
2578
|
if (fullItem) {
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
const delta = dirtyChangesMap.get(String(fullItem._id));
|
|
2581
|
-
if (delta) {
|
|
2582
|
-
updates.push({ _id: fullItem._id, delta });
|
|
2583
|
-
}
|
|
2579
|
+
const delta = dirtyChangesMap.get(String(fullItem._id));
|
|
2580
|
+
if (delta) {
|
|
2581
|
+
updates.push({ _id: fullItem._id, delta });
|
|
2584
2582
|
}
|
|
2585
2583
|
} else if (id != null) {
|
|
2586
2584
|
const delta = dirtyChangesMap.get(String(id));
|
|
@@ -2591,9 +2589,9 @@ var _SyncEngine = class _SyncEngine {
|
|
|
2591
2589
|
}
|
|
2592
2590
|
}
|
|
2593
2591
|
}
|
|
2594
|
-
if (updates.length === 0
|
|
2592
|
+
if (updates.length === 0) {
|
|
2595
2593
|
console.warn(
|
|
2596
|
-
`uploadDirtyItems: ${collectionName} has ${dirtyChanges.length} dirty entries but 0
|
|
2594
|
+
`uploadDirtyItems: ${collectionName} has ${dirtyChanges.length} dirty entries but 0 resolvable items`
|
|
2597
2595
|
);
|
|
2598
2596
|
continue;
|
|
2599
2597
|
}
|
|
@@ -2607,7 +2605,7 @@ var _SyncEngine = class _SyncEngine {
|
|
|
2607
2605
|
update: changes
|
|
2608
2606
|
};
|
|
2609
2607
|
}),
|
|
2610
|
-
deletes:
|
|
2608
|
+
deletes: []
|
|
2611
2609
|
}
|
|
2612
2610
|
}]);
|
|
2613
2611
|
}
|
|
@@ -2650,14 +2648,19 @@ var _SyncEngine = class _SyncEngine {
|
|
|
2650
2648
|
const dexieItems = await this.dexieDb.getByIds(collection, idsToCheck);
|
|
2651
2649
|
const dexieSaveBatch = [];
|
|
2652
2650
|
const inMemUpdateBatch = [];
|
|
2651
|
+
const inMemDeleteIds = [];
|
|
2652
|
+
const dexieDeleteIds = [];
|
|
2653
2653
|
for (let i = 0; i < insertedAndUpdated.length; i++) {
|
|
2654
2654
|
const entity = insertedAndUpdated[i];
|
|
2655
2655
|
const dexieItem = dexieItems[i];
|
|
2656
2656
|
if (dexieItem) {
|
|
2657
2657
|
dexieItem._rev = entity._rev;
|
|
2658
2658
|
dexieItem._ts = entity._ts;
|
|
2659
|
-
|
|
2660
|
-
|
|
2659
|
+
if (dexieItem._deleted) {
|
|
2660
|
+
inMemDeleteIds.push(entity._id);
|
|
2661
|
+
dexieDeleteIds.push(entity._id);
|
|
2662
|
+
} else {
|
|
2663
|
+
dexieSaveBatch.push(dexieItem);
|
|
2661
2664
|
const inMemItem = this.deps.getInMemById(collection, entity._id);
|
|
2662
2665
|
if (inMemItem) {
|
|
2663
2666
|
inMemUpdateBatch.push(__spreadProps(__spreadValues({}, inMemItem), {
|
|
@@ -2671,9 +2674,19 @@ var _SyncEngine = class _SyncEngine {
|
|
|
2671
2674
|
if (dexieSaveBatch.length > 0) {
|
|
2672
2675
|
await this.dexieDb.saveMany(collection, dexieSaveBatch);
|
|
2673
2676
|
}
|
|
2677
|
+
if (dexieDeleteIds.length > 0) {
|
|
2678
|
+
await this.dexieDb.deleteMany(collection, dexieDeleteIds);
|
|
2679
|
+
}
|
|
2674
2680
|
if (inMemUpdateBatch.length > 0) {
|
|
2675
2681
|
this.deps.writeToInMemBatch(collection, inMemUpdateBatch, "upsert");
|
|
2676
2682
|
}
|
|
2683
|
+
if (inMemDeleteIds.length > 0) {
|
|
2684
|
+
this.deps.writeToInMemBatch(
|
|
2685
|
+
collection,
|
|
2686
|
+
inMemDeleteIds.map((id) => ({ _id: id })),
|
|
2687
|
+
"delete"
|
|
2688
|
+
);
|
|
2689
|
+
}
|
|
2677
2690
|
}
|
|
2678
2691
|
sentCount += insertedAndUpdated.length;
|
|
2679
2692
|
collectionSentCount += insertedAndUpdated.length;
|
|
@@ -2756,19 +2769,14 @@ var _SyncEngine = class _SyncEngine {
|
|
|
2756
2769
|
dirtyChangesMap.set(String(dirtyItem._id), dirtyItem);
|
|
2757
2770
|
}
|
|
2758
2771
|
const updates = [];
|
|
2759
|
-
const deletes = [];
|
|
2760
2772
|
for (const fullItem of fullItems) {
|
|
2761
2773
|
if (!fullItem) continue;
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
const delta = dirtyChangesMap.get(String(fullItem._id));
|
|
2766
|
-
if (delta) {
|
|
2767
|
-
updates.push({ _id: fullItem._id, delta });
|
|
2768
|
-
}
|
|
2774
|
+
const delta = dirtyChangesMap.get(String(fullItem._id));
|
|
2775
|
+
if (delta) {
|
|
2776
|
+
updates.push({ _id: fullItem._id, delta });
|
|
2769
2777
|
}
|
|
2770
2778
|
}
|
|
2771
|
-
if (updates.length === 0
|
|
2779
|
+
if (updates.length === 0) {
|
|
2772
2780
|
return { sentCount: 0 };
|
|
2773
2781
|
}
|
|
2774
2782
|
const collectionBatches = [[{
|
|
@@ -2778,7 +2786,7 @@ var _SyncEngine = class _SyncEngine {
|
|
|
2778
2786
|
const _a = item.delta, { _ts, _rev } = _a, changes = __objRest(_a, ["_ts", "_rev"]);
|
|
2779
2787
|
return { _id: item._id, update: changes };
|
|
2780
2788
|
}),
|
|
2781
|
-
deletes:
|
|
2789
|
+
deletes: []
|
|
2782
2790
|
}
|
|
2783
2791
|
}]];
|
|
2784
2792
|
const results = await this.deps.withSyncTimeout(
|
|
@@ -5,13 +5,15 @@ import type { DbEntity } from "../types/DbEntity";
|
|
|
5
5
|
* 1. Če ima lokalni objekt _rev in ima objekt s serverja nižji ali isti _rev, ignoriramo server
|
|
6
6
|
* 2. Polja, ki niso array in niso object:
|
|
7
7
|
* - če lokalna verzija nima polja, zunanja pa ga ima, polje dodamo
|
|
8
|
-
* - če imata oba objekta polje
|
|
8
|
+
* - če imata oba objekta polje:
|
|
9
|
+
* - če external._rev > local._rev (oba definirana), zmaga server
|
|
10
|
+
* - sicer ohranimo lokalno vrednost
|
|
9
11
|
* 3. Polja tipa array:
|
|
10
12
|
* - če lokalni objekt nima polja, ga dodamo
|
|
11
13
|
* - če je tip podatkov string[], shranimo deduplicirano unijo
|
|
12
14
|
* - če je tip podatkov Object[]:
|
|
13
15
|
* - elemente brez _id dodamo v lokalni array
|
|
14
|
-
* - objekte z _id primerjamo rekurzivno
|
|
16
|
+
* - objekte z _id primerjamo rekurzivno (rekurzija uporabi isto _rev pravilo)
|
|
15
17
|
* 4. Če je tip podatkov Record<string, Object>:
|
|
16
18
|
* - za vsak key, ki ga ni v lokalnem objektu, dodamo vrednost
|
|
17
19
|
* - za vsak key, ki obstaja, primerjamo rekurzivno
|