cry-synced-db-client 0.1.189 → 0.1.191
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 +111 -0
- package/dist/index.js +619 -410
- package/dist/src/db/SyncedDb.d.ts +19 -67
- package/dist/src/db/sync/SyncEngine.d.ts +25 -0
- package/dist/src/types/I_RestInterface.d.ts +7 -13
- package/dist/src/types/I_SyncedDb.d.ts +29 -1
- package/dist/src/utils/computeDiff.d.ts +0 -100
- package/dist/src/utils/normalizeUndefined.d.ts +1 -1
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,116 @@
|
|
|
1
1
|
# Versions
|
|
2
2
|
|
|
3
|
+
## 0.1.191 (2026-05-22)
|
|
4
|
+
|
|
5
|
+
Adopts the cry-db 2.5.0 sync contract. **Requires cry-db ≥ 2.5.0 on the
|
|
6
|
+
server.** Three changes:
|
|
7
|
+
|
|
8
|
+
### 1. Diff machinery consolidated into cry-db (`computeObjDiff` / `applyObjDiff`)
|
|
9
|
+
|
|
10
|
+
The local `computeDiff` (in `src/utils/computeDiff.ts`) and
|
|
11
|
+
`SyncedDb.applyDiffLocally` (+ `materializeBracketPath`, `safeDeepClone`)
|
|
12
|
+
were removed. `save()` and init-time dirty overlay now call cry-db's
|
|
13
|
+
`computeObjDiff` / `applyObjDiff` — the server-symmetric counterparts that
|
|
14
|
+
cry-db extracted verbatim from this client. The low-level path primitives
|
|
15
|
+
(`setByPath` / `deleteByPath` / `tokenizePath` / `deepEquals`) are likewise
|
|
16
|
+
imported from cry-db; the local duplicates are gone.
|
|
17
|
+
|
|
18
|
+
`src/utils/computeDiff.ts` now holds only the client-only dirty-accumulation
|
|
19
|
+
helpers with no server counterpart: `mergeDirtyPath`, `mergeDirtyChanges`,
|
|
20
|
+
`pathsOverlap`.
|
|
21
|
+
|
|
22
|
+
Imports use the deep path `cry-db/dist/utils.mjs` (pure, zero imports), NOT
|
|
23
|
+
the package root — the root re-exports `Mongo` (mongodb driver) which esbuild
|
|
24
|
+
would drag into the browser bundle. Verified: bundle stays clean (no
|
|
25
|
+
mongodb/bcrypt; 372 KB).
|
|
26
|
+
|
|
27
|
+
### 2. Sync upload sends `_rev` per entry
|
|
28
|
+
|
|
29
|
+
Every `updates[]` entry in `updateCollections` now carries `_rev` (the dirty
|
|
30
|
+
entry's `baseRev`; `0` when never synced) at entry level — never inside
|
|
31
|
+
`update`. The server uses it to detect concurrent external writes.
|
|
32
|
+
`CollectionUpdateRequest` is re-exported from `Types.CollectionUpdateRequest`
|
|
33
|
+
(cry-db) so the wire shape stays in lockstep.
|
|
34
|
+
|
|
35
|
+
### 3. `mustRefresh` adoption with dirty reconciliation
|
|
36
|
+
|
|
37
|
+
When the server resolves a placeholder (`SEQ_*` / `__hashed__*`) or detects a
|
|
38
|
+
conflict, it returns the full sanitized record in `results.mustRefresh`. The
|
|
39
|
+
new `SyncEngine.adoptMustRefresh` (used by both `uploadDirtyItems` and
|
|
40
|
+
`uploadDirtyItemsForCollection`) honors the cry-db contract — *replace the
|
|
41
|
+
local record with the `mustRefresh` entry, then run the dirty-merge; apply
|
|
42
|
+
`mustRefresh` BEFORE the merge so unsynced local edits to other fields are
|
|
43
|
+
reconciled rather than clobbered*:
|
|
44
|
+
|
|
45
|
+
1. Captures the dirty entry + upload snapshot BEFORE the success-clear.
|
|
46
|
+
2. Takes the `mustRefresh` record as the base.
|
|
47
|
+
3. Re-applies (via `applyObjDiff`) only dirty paths NOT in the upload snapshot
|
|
48
|
+
— local edits made during the round-trip. Uploaded paths (incl. a resolved
|
|
49
|
+
placeholder) are owned by the server record and are not re-applied.
|
|
50
|
+
4. Writes the merged row to Dexie + in-mem (`_deleted`/`_archived` → local
|
|
51
|
+
delete). The advanced `_rev` makes conflict resolution accept the write.
|
|
52
|
+
5. Keeps the re-applied paths dirty (rebased on the new `_rev`) so they upload
|
|
53
|
+
next sync.
|
|
54
|
+
|
|
55
|
+
In the common case (no mid-flight edits) the record is adopted verbatim.
|
|
56
|
+
|
|
57
|
+
### Tests / docs
|
|
58
|
+
|
|
59
|
+
- New `test/uploadRevAndMustRefresh.test.ts` (4 cases): `_rev: 0` on fresh
|
|
60
|
+
insert + not inside `update`; `_rev = baseRev` after a synced edit;
|
|
61
|
+
`mustRefresh` adoption (resolved placeholder); round-trip-edit
|
|
62
|
+
reconciliation.
|
|
63
|
+
- Diff unit tests repointed to cry-db (`computeObjDiff` / `applyObjDiff`),
|
|
64
|
+
kept as a guard. Removed the dead `hasDotNotationPaths` (no callers).
|
|
65
|
+
- Mocks return `mustRefresh: []`; new `MockRestInterfaceFake` test helpers
|
|
66
|
+
(`setUpdateCollectionsForcedMustRefresh`, `lastUpdateCollectionsRequest`).
|
|
67
|
+
- CLAUDE.md / SPEC.md + comments updated.
|
|
68
|
+
|
|
69
|
+
## 0.1.190 (2026-05-15)
|
|
70
|
+
|
|
71
|
+
### `addCollectionsToSync(specs[])` — batch register with single-RTT download
|
|
72
|
+
|
|
73
|
+
Plural counterpart to `addCollectionToSync`. Per-spec semantics are
|
|
74
|
+
identical (permanent existing = skip; temporary or absent = install),
|
|
75
|
+
but the install work is decomposed into three phases optimized for
|
|
76
|
+
batching:
|
|
77
|
+
|
|
78
|
+
1. **Filter + register (sync)** — every survivor's
|
|
79
|
+
`this.collections.set()` and `syncOnlyTheseCollections` extension
|
|
80
|
+
happen up front, so a sync triggered mid-install already sees the
|
|
81
|
+
new collections.
|
|
82
|
+
2. **Hydrate (parallel)** — Dexie cursor reads + in-mem hydrations
|
|
83
|
+
fan out via `Promise.allSettled`. Per-collection failure is logged
|
|
84
|
+
and isolated; the collection stays installed and hydrates on the
|
|
85
|
+
next sync tick.
|
|
86
|
+
3. **Download (one RTT)** — every newly-installed non-`writeOnly`
|
|
87
|
+
spec is bundled into a **single `findNewerMany` request**, then
|
|
88
|
+
each result is fed through `processCollectionServerData` for
|
|
89
|
+
conflict resolution. **N collections = 1 RTT** of wall-clock time.
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
// Login flow: install a workspace's collections in one shot.
|
|
93
|
+
await syncedDb.addCollectionsToSync([
|
|
94
|
+
{ name: "obravnave", syncConfig: { query: () => ({ lokacija_id }) } },
|
|
95
|
+
{ name: "zivali", syncConfig: { query: () => ({ tenant }) } },
|
|
96
|
+
{ name: "racuni", syncConfig: { query: () => ({ leto }) } },
|
|
97
|
+
{ name: "audit_log", writeOnly: true }, // installed but excluded from RTT
|
|
98
|
+
]);
|
|
99
|
+
// → 1 findNewerMany covering [obravnave, zivali, racuni].
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Skipped specs (existing permanent) consume zero install work. No-op
|
|
103
|
+
when `specs` is empty or every spec is skipped. Network failure on the
|
|
104
|
+
batched download leaves collections registered; next auto-sync tick
|
|
105
|
+
retries via the normal sync flow.
|
|
106
|
+
|
|
107
|
+
Compared to looping `addCollectionToSync(spec)` per item:
|
|
108
|
+
- N collections × per-collection RTT (sequential or `Promise.all`)
|
|
109
|
+
→ 1 RTT for the whole batch.
|
|
110
|
+
- Hydration also parallelized.
|
|
111
|
+
- Compatible with `syncOnlyTheseCollections` filter (each addition
|
|
112
|
+
extends the active set).
|
|
113
|
+
|
|
3
114
|
## 0.1.189 (2026-05-15)
|
|
4
115
|
|
|
5
116
|
### Periodic full-resync maintenance heartbeat
|