cry-synced-db-client 0.1.190 → 0.1.193

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 CHANGED
@@ -1,5 +1,101 @@
1
1
  # Versions
2
2
 
3
+ ## 0.1.192 (2026-05-25)
4
+
5
+ Adds per-collection preload status reporting (non-breaking, additive).
6
+
7
+ ### `getPreloadStatus()` + `onPreloadStatusChange`
8
+
9
+ New synchronous getter `getPreloadStatus(): PreloadStatus` and config callback
10
+ `onPreloadStatusChange?(status)` expose hydration status for every readable
11
+ (non-`writeOnly`), in-scope collection:
12
+
13
+ - Per-collection `state` (`pending` / `hydrated` / `failed`), `itemCount`,
14
+ `lastError`, `everDownloaded`, and a derived `ready` flag
15
+ (`ready = hydrated && (itemCount > 0 || everDownloaded)` — a hydrated-but-empty
16
+ collection that was never downloaded is **not** ready, so a fresh device
17
+ doesn't report "full" before its first server sync).
18
+ - Rolled-up `aggregate`: `idle` / `full` / `partial` / `failed`.
19
+
20
+ The callback fires on each hydration transition (success/failure), on scope
21
+ changes (`setSyncOnlyTheseCollections`), and at sync end (a download that
22
+ advances a cursor can flip a hydrated-empty collection to ready).
23
+
24
+ ### Per-collection hydration failures no longer abort the batch
25
+
26
+ `loadCollectionsToInMem`'s worker pool now isolates a single collection's
27
+ Dexie hydration failure (try/catch per collection) instead of rejecting the
28
+ whole `Promise.all` — matching the existing `Promise.allSettled` tolerance in
29
+ `addCollectionsToSync`. The failure is recorded as `state: "failed"` and
30
+ surfaced via `getPreloadStatus()` (`aggregate: "partial"`) rather than throwing
31
+ out of `init()`.
32
+
33
+ ## 0.1.191 (2026-05-22)
34
+
35
+ Adopts the cry-db 2.5.0 sync contract. **Requires cry-db ≥ 2.5.0 on the
36
+ server.** Three changes:
37
+
38
+ ### 1. Diff machinery consolidated into cry-db (`computeObjDiff` / `applyObjDiff`)
39
+
40
+ The local `computeDiff` (in `src/utils/computeDiff.ts`) and
41
+ `SyncedDb.applyDiffLocally` (+ `materializeBracketPath`, `safeDeepClone`)
42
+ were removed. `save()` and init-time dirty overlay now call cry-db's
43
+ `computeObjDiff` / `applyObjDiff` — the server-symmetric counterparts that
44
+ cry-db extracted verbatim from this client. The low-level path primitives
45
+ (`setByPath` / `deleteByPath` / `tokenizePath` / `deepEquals`) are likewise
46
+ imported from cry-db; the local duplicates are gone.
47
+
48
+ `src/utils/computeDiff.ts` now holds only the client-only dirty-accumulation
49
+ helpers with no server counterpart: `mergeDirtyPath`, `mergeDirtyChanges`,
50
+ `pathsOverlap`.
51
+
52
+ Imports use the deep path `cry-db/dist/utils.mjs` (pure, zero imports), NOT
53
+ the package root — the root re-exports `Mongo` (mongodb driver) which esbuild
54
+ would drag into the browser bundle. Verified: bundle stays clean (no
55
+ mongodb/bcrypt; 372 KB).
56
+
57
+ ### 2. Sync upload sends `_rev` per entry
58
+
59
+ Every `updates[]` entry in `updateCollections` now carries `_rev` (the dirty
60
+ entry's `baseRev`; `0` when never synced) at entry level — never inside
61
+ `update`. The server uses it to detect concurrent external writes.
62
+ `CollectionUpdateRequest` is re-exported from `Types.CollectionUpdateRequest`
63
+ (cry-db) so the wire shape stays in lockstep.
64
+
65
+ ### 3. `mustRefresh` adoption with dirty reconciliation
66
+
67
+ When the server resolves a placeholder (`SEQ_*` / `__hashed__*`) or detects a
68
+ conflict, it returns the full sanitized record in `results.mustRefresh`. The
69
+ new `SyncEngine.adoptMustRefresh` (used by both `uploadDirtyItems` and
70
+ `uploadDirtyItemsForCollection`) honors the cry-db contract — *replace the
71
+ local record with the `mustRefresh` entry, then run the dirty-merge; apply
72
+ `mustRefresh` BEFORE the merge so unsynced local edits to other fields are
73
+ reconciled rather than clobbered*:
74
+
75
+ 1. Captures the dirty entry + upload snapshot BEFORE the success-clear.
76
+ 2. Takes the `mustRefresh` record as the base.
77
+ 3. Re-applies (via `applyObjDiff`) only dirty paths NOT in the upload snapshot
78
+ — local edits made during the round-trip. Uploaded paths (incl. a resolved
79
+ placeholder) are owned by the server record and are not re-applied.
80
+ 4. Writes the merged row to Dexie + in-mem (`_deleted`/`_archived` → local
81
+ delete). The advanced `_rev` makes conflict resolution accept the write.
82
+ 5. Keeps the re-applied paths dirty (rebased on the new `_rev`) so they upload
83
+ next sync.
84
+
85
+ In the common case (no mid-flight edits) the record is adopted verbatim.
86
+
87
+ ### Tests / docs
88
+
89
+ - New `test/uploadRevAndMustRefresh.test.ts` (4 cases): `_rev: 0` on fresh
90
+ insert + not inside `update`; `_rev = baseRev` after a synced edit;
91
+ `mustRefresh` adoption (resolved placeholder); round-trip-edit
92
+ reconciliation.
93
+ - Diff unit tests repointed to cry-db (`computeObjDiff` / `applyObjDiff`),
94
+ kept as a guard. Removed the dead `hasDotNotationPaths` (no callers).
95
+ - Mocks return `mustRefresh: []`; new `MockRestInterfaceFake` test helpers
96
+ (`setUpdateCollectionsForcedMustRefresh`, `lastUpdateCollectionsRequest`).
97
+ - CLAUDE.md / SPEC.md + comments updated.
98
+
3
99
  ## 0.1.190 (2026-05-15)
4
100
 
5
101
  ### `addCollectionsToSync(specs[])` — batch register with single-RTT download