cry-synced-db-client 0.1.189 → 0.1.190
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 +45 -0
- package/dist/index.js +93 -0
- package/dist/src/db/SyncedDb.d.ts +17 -0
- package/dist/src/types/I_SyncedDb.d.ts +28 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,50 @@
|
|
|
1
1
|
# Versions
|
|
2
2
|
|
|
3
|
+
## 0.1.190 (2026-05-15)
|
|
4
|
+
|
|
5
|
+
### `addCollectionsToSync(specs[])` — batch register with single-RTT download
|
|
6
|
+
|
|
7
|
+
Plural counterpart to `addCollectionToSync`. Per-spec semantics are
|
|
8
|
+
identical (permanent existing = skip; temporary or absent = install),
|
|
9
|
+
but the install work is decomposed into three phases optimized for
|
|
10
|
+
batching:
|
|
11
|
+
|
|
12
|
+
1. **Filter + register (sync)** — every survivor's
|
|
13
|
+
`this.collections.set()` and `syncOnlyTheseCollections` extension
|
|
14
|
+
happen up front, so a sync triggered mid-install already sees the
|
|
15
|
+
new collections.
|
|
16
|
+
2. **Hydrate (parallel)** — Dexie cursor reads + in-mem hydrations
|
|
17
|
+
fan out via `Promise.allSettled`. Per-collection failure is logged
|
|
18
|
+
and isolated; the collection stays installed and hydrates on the
|
|
19
|
+
next sync tick.
|
|
20
|
+
3. **Download (one RTT)** — every newly-installed non-`writeOnly`
|
|
21
|
+
spec is bundled into a **single `findNewerMany` request**, then
|
|
22
|
+
each result is fed through `processCollectionServerData` for
|
|
23
|
+
conflict resolution. **N collections = 1 RTT** of wall-clock time.
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
// Login flow: install a workspace's collections in one shot.
|
|
27
|
+
await syncedDb.addCollectionsToSync([
|
|
28
|
+
{ name: "obravnave", syncConfig: { query: () => ({ lokacija_id }) } },
|
|
29
|
+
{ name: "zivali", syncConfig: { query: () => ({ tenant }) } },
|
|
30
|
+
{ name: "racuni", syncConfig: { query: () => ({ leto }) } },
|
|
31
|
+
{ name: "audit_log", writeOnly: true }, // installed but excluded from RTT
|
|
32
|
+
]);
|
|
33
|
+
// → 1 findNewerMany covering [obravnave, zivali, racuni].
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Skipped specs (existing permanent) consume zero install work. No-op
|
|
37
|
+
when `specs` is empty or every spec is skipped. Network failure on the
|
|
38
|
+
batched download leaves collections registered; next auto-sync tick
|
|
39
|
+
retries via the normal sync flow.
|
|
40
|
+
|
|
41
|
+
Compared to looping `addCollectionToSync(spec)` per item:
|
|
42
|
+
- N collections × per-collection RTT (sequential or `Promise.all`)
|
|
43
|
+
→ 1 RTT for the whole batch.
|
|
44
|
+
- Hydration also parallelized.
|
|
45
|
+
- Compatible with `syncOnlyTheseCollections` filter (each addition
|
|
46
|
+
extends the active set).
|
|
47
|
+
|
|
3
48
|
## 0.1.189 (2026-05-15)
|
|
4
49
|
|
|
5
50
|
### Periodic full-resync maintenance heartbeat
|
package/dist/index.js
CHANGED
|
@@ -4770,6 +4770,99 @@ var _SyncedDb = class _SyncedDb {
|
|
|
4770
4770
|
}
|
|
4771
4771
|
await this._installCollectionConfig(spec);
|
|
4772
4772
|
}
|
|
4773
|
+
/**
|
|
4774
|
+
* Batch register. See `I_SyncedDb.addCollectionsToSync`.
|
|
4775
|
+
*
|
|
4776
|
+
* The work decomposes into three phases:
|
|
4777
|
+
*
|
|
4778
|
+
* 1. Filter + synchronously seed `this.collections` and the
|
|
4779
|
+
* `syncOnlyCollections` filter so any concurrent sync triggered
|
|
4780
|
+
* mid-install already sees the new collections.
|
|
4781
|
+
* 2. Parallel Dexie cursor load + in-mem hydration.
|
|
4782
|
+
* 3. Parallel per-collection one-shot download.
|
|
4783
|
+
*
|
|
4784
|
+
* Per-spec errors in phase 2/3 are isolated via `Promise.allSettled`:
|
|
4785
|
+
* one collection's hydration / download failure does not block the
|
|
4786
|
+
* others. Failures are logged and the spec is left installed (its
|
|
4787
|
+
* cache will hydrate on the next sync tick).
|
|
4788
|
+
*/
|
|
4789
|
+
async addCollectionsToSync(specs) {
|
|
4790
|
+
var _a;
|
|
4791
|
+
if (specs.length === 0) return;
|
|
4792
|
+
const toInstall = [];
|
|
4793
|
+
for (const spec of specs) {
|
|
4794
|
+
const existing = this.collections.get(spec.name);
|
|
4795
|
+
if (existing && !existing.temporaryConfig) continue;
|
|
4796
|
+
this.collections.set(spec.name, spec);
|
|
4797
|
+
if (this.syncOnlyCollections) {
|
|
4798
|
+
this.syncOnlyCollections.add(spec.name);
|
|
4799
|
+
}
|
|
4800
|
+
toInstall.push(spec);
|
|
4801
|
+
}
|
|
4802
|
+
if (toInstall.length === 0) return;
|
|
4803
|
+
const hydrationResults = await Promise.allSettled(
|
|
4804
|
+
toInstall.map(async (spec) => {
|
|
4805
|
+
const meta = await this.dexieDb.getSyncMeta(spec.name);
|
|
4806
|
+
if (meta) this.syncMetaCache.set(spec.name, meta);
|
|
4807
|
+
if (!spec.writeOnly) {
|
|
4808
|
+
await this.loadCollectionToInMem(spec.name);
|
|
4809
|
+
}
|
|
4810
|
+
})
|
|
4811
|
+
);
|
|
4812
|
+
for (let i = 0; i < hydrationResults.length; i++) {
|
|
4813
|
+
const r = hydrationResults[i];
|
|
4814
|
+
if (r.status === "rejected") {
|
|
4815
|
+
console.error(
|
|
4816
|
+
`[SyncedDb] addCollectionsToSync: hydration failed for "${toInstall[i].name}":`,
|
|
4817
|
+
r.reason
|
|
4818
|
+
);
|
|
4819
|
+
}
|
|
4820
|
+
}
|
|
4821
|
+
if (!this.connectionManager.canSync()) return;
|
|
4822
|
+
const downloadable = toInstall.filter((s) => !s.writeOnly);
|
|
4823
|
+
if (downloadable.length === 0) return;
|
|
4824
|
+
const plans = [];
|
|
4825
|
+
const fetchSpecs = [];
|
|
4826
|
+
for (const spec of downloadable) {
|
|
4827
|
+
const rawQuery = (_a = spec.syncConfig) == null ? void 0 : _a.query;
|
|
4828
|
+
const query = typeof rawQuery === "function" ? rawQuery() : rawQuery;
|
|
4829
|
+
const meta = this.syncMetaCache.get(spec.name);
|
|
4830
|
+
const timestamp = (meta == null ? void 0 : meta.lastSyncTs) || 0;
|
|
4831
|
+
plans.push({ spec, wasFirstTime: !timestamp });
|
|
4832
|
+
fetchSpecs.push({
|
|
4833
|
+
collection: spec.name,
|
|
4834
|
+
timestamp,
|
|
4835
|
+
query,
|
|
4836
|
+
opts: { returnDeleted: true }
|
|
4837
|
+
});
|
|
4838
|
+
}
|
|
4839
|
+
let results;
|
|
4840
|
+
try {
|
|
4841
|
+
results = await this.connectionManager.withRestTimeout(
|
|
4842
|
+
this.restInterface.findNewerMany(fetchSpecs),
|
|
4843
|
+
"addCollectionsToSync"
|
|
4844
|
+
);
|
|
4845
|
+
} catch (err) {
|
|
4846
|
+
console.error(
|
|
4847
|
+
`[SyncedDb] addCollectionsToSync: batched findNewerMany failed:`,
|
|
4848
|
+
err
|
|
4849
|
+
);
|
|
4850
|
+
return;
|
|
4851
|
+
}
|
|
4852
|
+
for (const plan of plans) {
|
|
4853
|
+
const data = results[plan.spec.name];
|
|
4854
|
+
if (!data || data.length === 0) continue;
|
|
4855
|
+
const source = plan.wasFirstTime ? "initial" : "incremental";
|
|
4856
|
+
try {
|
|
4857
|
+
await this.syncEngine.processCollectionServerData(plan.spec.name, data, { source });
|
|
4858
|
+
} catch (err) {
|
|
4859
|
+
console.error(
|
|
4860
|
+
`[SyncedDb] addCollectionsToSync: processCollectionServerData failed for "${plan.spec.name}":`,
|
|
4861
|
+
err
|
|
4862
|
+
);
|
|
4863
|
+
}
|
|
4864
|
+
}
|
|
4865
|
+
}
|
|
4773
4866
|
/**
|
|
4774
4867
|
* Replace the collection config and re-sync. See `I_SyncedDb.replaceSyncCollection`.
|
|
4775
4868
|
*/
|
|
@@ -100,6 +100,23 @@ export declare class SyncedDb implements I_SyncedDb {
|
|
|
100
100
|
* Register a collection for sync at runtime. See `I_SyncedDb.addCollectionToSync`.
|
|
101
101
|
*/
|
|
102
102
|
addCollectionToSync(spec: CollectionConfig): Promise<void>;
|
|
103
|
+
/**
|
|
104
|
+
* Batch register. See `I_SyncedDb.addCollectionsToSync`.
|
|
105
|
+
*
|
|
106
|
+
* The work decomposes into three phases:
|
|
107
|
+
*
|
|
108
|
+
* 1. Filter + synchronously seed `this.collections` and the
|
|
109
|
+
* `syncOnlyCollections` filter so any concurrent sync triggered
|
|
110
|
+
* mid-install already sees the new collections.
|
|
111
|
+
* 2. Parallel Dexie cursor load + in-mem hydration.
|
|
112
|
+
* 3. Parallel per-collection one-shot download.
|
|
113
|
+
*
|
|
114
|
+
* Per-spec errors in phase 2/3 are isolated via `Promise.allSettled`:
|
|
115
|
+
* one collection's hydration / download failure does not block the
|
|
116
|
+
* others. Failures are logged and the spec is left installed (its
|
|
117
|
+
* cache will hydrate on the next sync tick).
|
|
118
|
+
*/
|
|
119
|
+
addCollectionsToSync(specs: CollectionConfig[]): Promise<void>;
|
|
103
120
|
/**
|
|
104
121
|
* Replace the collection config and re-sync. See `I_SyncedDb.replaceSyncCollection`.
|
|
105
122
|
*/
|
|
@@ -943,6 +943,34 @@ export interface I_SyncedDb {
|
|
|
943
943
|
* @param spec Collection config to register
|
|
944
944
|
*/
|
|
945
945
|
addCollectionToSync(spec: CollectionConfig): Promise<void>;
|
|
946
|
+
/**
|
|
947
|
+
* Batch variant of `addCollectionToSync`. Semantics are identical
|
|
948
|
+
* per-spec (permanent existing: no-op; temporary or absent: install).
|
|
949
|
+
*
|
|
950
|
+
* Three-phase install:
|
|
951
|
+
*
|
|
952
|
+
* 1. **Filter + register (sync)** — `this.collections.set()` and
|
|
953
|
+
* `syncOnlyTheseCollections` extensions happen up front so any
|
|
954
|
+
* concurrent sync triggered mid-install already sees the new
|
|
955
|
+
* collections.
|
|
956
|
+
* 2. **Hydrate (parallel)** — Dexie cursor reads + in-mem
|
|
957
|
+
* hydrations run via `Promise.allSettled`. Per-collection
|
|
958
|
+
* failures are logged and isolated; the collection stays
|
|
959
|
+
* installed and hydrates on the next sync tick.
|
|
960
|
+
* 3. **Download (one RTT)** — every newly-installed non-writeOnly
|
|
961
|
+
* collection is bundled into a SINGLE `findNewerMany` request,
|
|
962
|
+
* then each result is fed through `processCollectionServerData`
|
|
963
|
+
* for conflict resolution. N collections cost 1 RTT total
|
|
964
|
+
* instead of N parallel RTTs.
|
|
965
|
+
*
|
|
966
|
+
* Skipped specs (existing permanent) consume no install work. No-op
|
|
967
|
+
* when `specs` is empty or every spec is a no-op. Network failure on
|
|
968
|
+
* the batched download leaves the collections installed; the next
|
|
969
|
+
* auto-sync tick retries via the normal sync flow.
|
|
970
|
+
*
|
|
971
|
+
* @param specs Array of collection configs to register
|
|
972
|
+
*/
|
|
973
|
+
addCollectionsToSync(specs: CollectionConfig[]): Promise<void>;
|
|
946
974
|
/**
|
|
947
975
|
* Replace the collection config and re-sync.
|
|
948
976
|
*
|