cry-synced-db-client 0.1.143 → 0.1.145
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 +65 -0
- package/dist/index.js +131 -2
- package/dist/src/db/SyncedDb.d.ts +56 -1
- package/dist/src/db/types/managers.d.ts +1 -0
- package/dist/src/types/I_SyncedDb.d.ts +27 -4
- package/dist/src/utils/localQuery.d.ts +4 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,40 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
### Fix: filtered-sync tombstone (scope-exit from other writers)
|
|
6
|
+
|
|
7
|
+
When a collection has `syncConfig.query` (e.g. `{ status: { $ne: "obsolete" } }`)
|
|
8
|
+
and another device mutates a record out of scope while this client is offline,
|
|
9
|
+
the filtered delta feed (`findNewer` with the positive query) never returns the
|
|
10
|
+
mutated record — the server filters it out. The local copy stayed stale
|
|
11
|
+
indefinitely, even across reloads and full re-syncs (positive query still
|
|
12
|
+
excludes it).
|
|
13
|
+
|
|
14
|
+
`evictOutOfScopeRecords` now runs a second, server-assisted pass that fires the
|
|
15
|
+
**negated** query `{ $and: [{ $nor: [syncConfig.query] }, { _id: { $in: knownIds } }] }`
|
|
16
|
+
against the server (scoped by local IDs for both bandwidth and authz) and
|
|
17
|
+
evicts any returned records locally. Purely client-side — no server protocol
|
|
18
|
+
change. Sound only when `syncConfig.query` is the complete server-side
|
|
19
|
+
predicate (no implicit server policy).
|
|
20
|
+
|
|
21
|
+
- New `opts.serverAssisted` parameter on `evictOutOfScopeRecords(collection, opts?)`.
|
|
22
|
+
Defaults to `true` when online and not `writeOnly`. Set `false` for pure
|
|
23
|
+
local pass (previous behavior).
|
|
24
|
+
- New `opts.outOfWindowLookbehindMs` parameter restricts the server-assisted
|
|
25
|
+
query to records changed in the last N ms (translates to `findNewer`'s
|
|
26
|
+
seconds-resolution timestamp filter). When unspecified, the scope-exit
|
|
27
|
+
scan uses the collection's current `meta.lastSyncTs` — the same cursor
|
|
28
|
+
`sync()` passes to `findNewer`, so it covers the same window as a delta
|
|
29
|
+
sync. Pass `Date.now()` to scan full history. Note: when eviction runs
|
|
30
|
+
post-sync, `lastSyncTs` has advanced past the window sync just covered;
|
|
31
|
+
set a lookbehind to re-scan that window.
|
|
32
|
+
- Dirty records are still preserved across the combined eviction.
|
|
33
|
+
- Auto-eviction (`evictStaleRecordsEveryHrs`) picks up the new behavior
|
|
34
|
+
transparently — no config change needed.
|
|
35
|
+
- `matchesQuery` (`src/utils/localQuery.ts`) gained top-level `$and`, `$or`,
|
|
36
|
+
`$nor` support, required for the negated query to evaluate against the test
|
|
37
|
+
mock and for any client-side filtering that uses logical operators.
|
|
38
|
+
|
|
5
39
|
### `getDirtyMeta()` for lightweight dirty-state inspection
|
|
6
40
|
|
|
7
41
|
- New `SyncedDb.getDirtyMeta()` returns dirty-entry meta (everything except the
|
|
@@ -74,6 +108,37 @@ Signature is identical. No other callback changes.
|
|
|
74
108
|
- Noop when offline or on writeOnly collections.
|
|
75
109
|
- Ignored on `find` / `findOne` (use `referToServer` there).
|
|
76
110
|
|
|
111
|
+
## 0.1.145 (2026-04-25)
|
|
112
|
+
|
|
113
|
+
### Fix: `onSyncProgress` back-track during initial sync
|
|
114
|
+
|
|
115
|
+
`onSyncProgress` is fired from two distinct phases that can run **concurrently**
|
|
116
|
+
during initial sync — Dexie → in-mem hydration (`SyncedDb.loadCollectionsToInMem`)
|
|
117
|
+
and server → Dexie download (`SyncEngine.findNewerManyStream`). Each phase
|
|
118
|
+
carries its own `loaded`/`total`, so consumers wiring the callback into a single
|
|
119
|
+
progress bar saw the percentage back-track every time a tick from the other
|
|
120
|
+
phase arrived (e.g. dexie 9/58 → server 1/62 → dexie 10/58 → server 2/62 …).
|
|
121
|
+
|
|
122
|
+
The payload now carries a `phase: 'dexie' | 'server'` discriminator so consumers
|
|
123
|
+
can attribute each tick to its source and either filter or render the two
|
|
124
|
+
streams separately. **Non-breaking**: consumers that destructure
|
|
125
|
+
`{ collection, loaded, total }` and ignore `phase` keep working unchanged.
|
|
126
|
+
|
|
127
|
+
Type change in `I_SyncedDb.SyncedDbConfig` and internal `SyncEngineCallbacks`:
|
|
128
|
+
```ts
|
|
129
|
+
onSyncProgress?: (info: {
|
|
130
|
+
phase: 'dexie' | 'server';
|
|
131
|
+
collection: string;
|
|
132
|
+
loaded: number;
|
|
133
|
+
total: number;
|
|
134
|
+
items: number;
|
|
135
|
+
}) => void;
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
The JSDoc on `onSyncProgress` previously claimed "Fires only during
|
|
139
|
+
init/setSyncOnlyTheseCollections" — that was wrong; it also fires during server
|
|
140
|
+
sync. Doc corrected.
|
|
141
|
+
|
|
77
142
|
## 0.1.136 (2026-04-20)
|
|
78
143
|
|
|
79
144
|
- `DexieDb.saveMany` is now fail-safe:
|
package/dist/index.js
CHANGED
|
@@ -39,6 +39,27 @@ import { ObjectId as ObjectId2 } from "bson";
|
|
|
39
39
|
// src/utils/localQuery.ts
|
|
40
40
|
function matchesQuery(item, query) {
|
|
41
41
|
for (const [key, condition] of Object.entries(query)) {
|
|
42
|
+
if (key === "$and") {
|
|
43
|
+
if (!Array.isArray(condition)) return false;
|
|
44
|
+
if (!condition.every((sub) => matchesQuery(item, sub))) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if (key === "$or") {
|
|
50
|
+
if (!Array.isArray(condition) || condition.length === 0) return false;
|
|
51
|
+
if (!condition.some((sub) => matchesQuery(item, sub))) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (key === "$nor") {
|
|
57
|
+
if (!Array.isArray(condition) || condition.length === 0) return false;
|
|
58
|
+
if (condition.some((sub) => matchesQuery(item, sub))) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
42
63
|
if (!matchesCondition(item, key, condition)) {
|
|
43
64
|
return false;
|
|
44
65
|
}
|
|
@@ -2481,6 +2502,7 @@ var _SyncEngine = class _SyncEngine {
|
|
|
2481
2502
|
if (!completedCollections.has(collection)) {
|
|
2482
2503
|
completedCollections.add(collection);
|
|
2483
2504
|
this.callbackSafe(this.callbacks.onSyncProgress, {
|
|
2505
|
+
phase: "server",
|
|
2484
2506
|
collection,
|
|
2485
2507
|
loaded: completedCollections.size,
|
|
2486
2508
|
total: syncSpecs.length,
|
|
@@ -4662,9 +4684,42 @@ var _SyncedDb = class _SyncedDb {
|
|
|
4662
4684
|
* Remove records from Dexie and in-mem that no longer match the
|
|
4663
4685
|
* collection's current syncConfig.query. Does NOT delete from server.
|
|
4664
4686
|
* Skips records with dirty changes (pending local writes).
|
|
4687
|
+
*
|
|
4688
|
+
* Runs two passes:
|
|
4689
|
+
* 1. Local: evicts items whose locally-cached state fails the query.
|
|
4690
|
+
* Covers self-inflicted scope exits (the client moved an item out).
|
|
4691
|
+
* 2. Server-assisted (default when online and not writeOnly): of the
|
|
4692
|
+
* items that still match locally, ask the server which now fail the
|
|
4693
|
+
* query server-side. Covers scope exits caused by other writers — the
|
|
4694
|
+
* filtered delta feed (`findNewer` with the positive query) never
|
|
4695
|
+
* ships those records, so the local cache would otherwise go stale
|
|
4696
|
+
* forever.
|
|
4697
|
+
*
|
|
4698
|
+
* The server-assisted query is `{ $and: [{ $nor: [query] }, { _id: { $in: chunk } }] }`
|
|
4699
|
+
* with `project: { _id: 1 }`. Scoped to known IDs to preserve both
|
|
4700
|
+
* bandwidth and authorization (server only reveals state of IDs the
|
|
4701
|
+
* client already knew about). Sound only if `syncConfig.query` is the
|
|
4702
|
+
* complete server-side predicate (no implicit server policy).
|
|
4703
|
+
*
|
|
4704
|
+
* @param opts.serverAssisted - Override auto-detection. Default: `true`
|
|
4705
|
+
* when online and not writeOnly. Set `false` for pure local eviction.
|
|
4706
|
+
* @param opts.outOfWindowLookbehindMs - Restrict the server-assisted
|
|
4707
|
+
* query to records changed in the last N ms (adds `_ts > now-N` via
|
|
4708
|
+
* `findNewer`'s timestamp filter). When unspecified, the collection's
|
|
4709
|
+
* current `meta.lastSyncTs` is used — the same cursor `sync()` passes
|
|
4710
|
+
* to `findNewer`, so scope-exit scan covers the same time window as a
|
|
4711
|
+
* regular delta sync. Pass `Date.now()` (or any value larger than
|
|
4712
|
+
* elapsed time) to scan full history.
|
|
4713
|
+
*
|
|
4714
|
+
* Note on post-sync timing: when this method runs AFTER `sync()`
|
|
4715
|
+
* (including via auto-eviction), `lastSyncTs` has already advanced
|
|
4716
|
+
* past the window sync just covered, so a record whose scope-exit
|
|
4717
|
+
* mutation landed in that window will not be re-examined on this
|
|
4718
|
+
* pass. Specify `outOfWindowLookbehindMs` (e.g., to cover since last
|
|
4719
|
+
* eviction) or call this before `sync()` to close that gap.
|
|
4665
4720
|
*/
|
|
4666
|
-
async evictOutOfScopeRecords(collection) {
|
|
4667
|
-
var _a;
|
|
4721
|
+
async evictOutOfScopeRecords(collection, opts) {
|
|
4722
|
+
var _a, _b, _c, _d;
|
|
4668
4723
|
this.assertCollection(collection);
|
|
4669
4724
|
const config = this.collections.get(collection);
|
|
4670
4725
|
const syncQuery = (_a = config.syncConfig) == null ? void 0 : _a.query;
|
|
@@ -4675,9 +4730,11 @@ var _SyncedDb = class _SyncedDb {
|
|
|
4675
4730
|
await this.pendingChanges.flushForCollection(collection);
|
|
4676
4731
|
const dirtyItems = await this.dexieDb.getDirty(collection);
|
|
4677
4732
|
const dirtyIds = new Set(dirtyItems.map((d) => String(d._id)));
|
|
4733
|
+
const serverAssisted = (_b = opts == null ? void 0 : opts.serverAssisted) != null ? _b : !config.writeOnly && this.connectionManager.isOnline();
|
|
4678
4734
|
let scannedCount = 0;
|
|
4679
4735
|
let dirtySkipped = 0;
|
|
4680
4736
|
const evictIds = [];
|
|
4737
|
+
const serverCandidateIds = [];
|
|
4681
4738
|
await this.dexieDb.forEachBatch(
|
|
4682
4739
|
collection,
|
|
4683
4740
|
2e3,
|
|
@@ -4691,10 +4748,38 @@ var _SyncedDb = class _SyncedDb {
|
|
|
4691
4748
|
}
|
|
4692
4749
|
if (!matchesQuery(item, query)) {
|
|
4693
4750
|
evictIds.push(id);
|
|
4751
|
+
} else if (serverAssisted) {
|
|
4752
|
+
serverCandidateIds.push(id);
|
|
4694
4753
|
}
|
|
4695
4754
|
}
|
|
4696
4755
|
}
|
|
4697
4756
|
);
|
|
4757
|
+
if (serverAssisted && serverCandidateIds.length > 0) {
|
|
4758
|
+
let scopeExitTimestamp;
|
|
4759
|
+
const lookbehindMs = opts == null ? void 0 : opts.outOfWindowLookbehindMs;
|
|
4760
|
+
if (lookbehindMs != null && lookbehindMs > 0) {
|
|
4761
|
+
scopeExitTimestamp = Math.max(
|
|
4762
|
+
0,
|
|
4763
|
+
Math.floor((Date.now() - lookbehindMs) / 1e3)
|
|
4764
|
+
);
|
|
4765
|
+
} else {
|
|
4766
|
+
scopeExitTimestamp = (_d = (_c = this.syncMetaCache.get(collection)) == null ? void 0 : _c.lastSyncTs) != null ? _d : 0;
|
|
4767
|
+
}
|
|
4768
|
+
try {
|
|
4769
|
+
const serverExits = await this.findServerSideScopeExits(
|
|
4770
|
+
collection,
|
|
4771
|
+
query,
|
|
4772
|
+
serverCandidateIds,
|
|
4773
|
+
scopeExitTimestamp
|
|
4774
|
+
);
|
|
4775
|
+
for (const id of serverExits) evictIds.push(id);
|
|
4776
|
+
} catch (err) {
|
|
4777
|
+
console.error(
|
|
4778
|
+
`[evict] server-assisted pass failed for ${collection} (proceeding with local-only):`,
|
|
4779
|
+
err
|
|
4780
|
+
);
|
|
4781
|
+
}
|
|
4782
|
+
}
|
|
4698
4783
|
if (evictIds.length > 0) {
|
|
4699
4784
|
await this.dexieDb.deleteMany(collection, evictIds);
|
|
4700
4785
|
if (!config.writeOnly) {
|
|
@@ -4708,6 +4793,49 @@ var _SyncedDb = class _SyncedDb {
|
|
|
4708
4793
|
}
|
|
4709
4794
|
return { collection, evictedCount: evictIds.length, dirtySkipped, scannedCount };
|
|
4710
4795
|
}
|
|
4796
|
+
/**
|
|
4797
|
+
* Ask the server which of the given IDs no longer match the positive
|
|
4798
|
+
* query server-side. Used by `evictOutOfScopeRecords` server-assisted
|
|
4799
|
+
* pass to close the "filtered-delta tombstone" gap — records mutated
|
|
4800
|
+
* out of scope by other writers that the filtered delta feed would
|
|
4801
|
+
* never report.
|
|
4802
|
+
*
|
|
4803
|
+
* Chunks `candidateIds` into `$in`-sized batches to keep the request
|
|
4804
|
+
* payload bounded. Uses `project: { _id: 1 }` to keep the response
|
|
4805
|
+
* payload minimal.
|
|
4806
|
+
*
|
|
4807
|
+
* @param timestamp - `findNewer` timestamp cursor. Only records with
|
|
4808
|
+
* `_ts > timestamp` are examined. Caller decides the window (usually
|
|
4809
|
+
* the collection's `meta.lastSyncTs` to mirror the positive sync's
|
|
4810
|
+
* cursor, or a lookbehind-derived value for shorter windows).
|
|
4811
|
+
* @returns IDs the server reports as out-of-scope (i.e. matching
|
|
4812
|
+
* `NOT query`). These are candidates for local-only eviction.
|
|
4813
|
+
*/
|
|
4814
|
+
async findServerSideScopeExits(collection, positiveQuery, candidateIds, timestamp) {
|
|
4815
|
+
const CHUNK_SIZE = 500;
|
|
4816
|
+
const scopeExits = [];
|
|
4817
|
+
const negated = { $nor: [positiveQuery] };
|
|
4818
|
+
for (let i = 0; i < candidateIds.length; i += CHUNK_SIZE) {
|
|
4819
|
+
const chunk = candidateIds.slice(i, i + CHUNK_SIZE);
|
|
4820
|
+
const scopedNegation = {
|
|
4821
|
+
$and: [negated, { _id: { $in: chunk } }]
|
|
4822
|
+
};
|
|
4823
|
+
const results = await this.connectionManager.withRestTimeout(
|
|
4824
|
+
this.restInterface.findNewer(
|
|
4825
|
+
collection,
|
|
4826
|
+
timestamp,
|
|
4827
|
+
scopedNegation,
|
|
4828
|
+
{ project: { _id: 1 } }
|
|
4829
|
+
),
|
|
4830
|
+
"evictOutOfScopeRecords.serverAssisted"
|
|
4831
|
+
);
|
|
4832
|
+
for (const item of results) {
|
|
4833
|
+
const id = item._id;
|
|
4834
|
+
if (id !== void 0) scopeExits.push(String(id));
|
|
4835
|
+
}
|
|
4836
|
+
}
|
|
4837
|
+
return scopeExits;
|
|
4838
|
+
}
|
|
4711
4839
|
/**
|
|
4712
4840
|
* Evict out-of-scope records for all collections.
|
|
4713
4841
|
* Skips writeOnly and collections without syncConfig.query.
|
|
@@ -4856,6 +4984,7 @@ var _SyncedDb = class _SyncedDb {
|
|
|
4856
4984
|
totalItems += items;
|
|
4857
4985
|
loaded++;
|
|
4858
4986
|
this.safeCallback(this.onSyncProgress, {
|
|
4987
|
+
phase: "dexie",
|
|
4859
4988
|
collection: name,
|
|
4860
4989
|
loaded,
|
|
4861
4990
|
total: names.length,
|
|
@@ -183,8 +183,63 @@ export declare class SyncedDb implements I_SyncedDb {
|
|
|
183
183
|
* Remove records from Dexie and in-mem that no longer match the
|
|
184
184
|
* collection's current syncConfig.query. Does NOT delete from server.
|
|
185
185
|
* Skips records with dirty changes (pending local writes).
|
|
186
|
+
*
|
|
187
|
+
* Runs two passes:
|
|
188
|
+
* 1. Local: evicts items whose locally-cached state fails the query.
|
|
189
|
+
* Covers self-inflicted scope exits (the client moved an item out).
|
|
190
|
+
* 2. Server-assisted (default when online and not writeOnly): of the
|
|
191
|
+
* items that still match locally, ask the server which now fail the
|
|
192
|
+
* query server-side. Covers scope exits caused by other writers — the
|
|
193
|
+
* filtered delta feed (`findNewer` with the positive query) never
|
|
194
|
+
* ships those records, so the local cache would otherwise go stale
|
|
195
|
+
* forever.
|
|
196
|
+
*
|
|
197
|
+
* The server-assisted query is `{ $and: [{ $nor: [query] }, { _id: { $in: chunk } }] }`
|
|
198
|
+
* with `project: { _id: 1 }`. Scoped to known IDs to preserve both
|
|
199
|
+
* bandwidth and authorization (server only reveals state of IDs the
|
|
200
|
+
* client already knew about). Sound only if `syncConfig.query` is the
|
|
201
|
+
* complete server-side predicate (no implicit server policy).
|
|
202
|
+
*
|
|
203
|
+
* @param opts.serverAssisted - Override auto-detection. Default: `true`
|
|
204
|
+
* when online and not writeOnly. Set `false` for pure local eviction.
|
|
205
|
+
* @param opts.outOfWindowLookbehindMs - Restrict the server-assisted
|
|
206
|
+
* query to records changed in the last N ms (adds `_ts > now-N` via
|
|
207
|
+
* `findNewer`'s timestamp filter). When unspecified, the collection's
|
|
208
|
+
* current `meta.lastSyncTs` is used — the same cursor `sync()` passes
|
|
209
|
+
* to `findNewer`, so scope-exit scan covers the same time window as a
|
|
210
|
+
* regular delta sync. Pass `Date.now()` (or any value larger than
|
|
211
|
+
* elapsed time) to scan full history.
|
|
212
|
+
*
|
|
213
|
+
* Note on post-sync timing: when this method runs AFTER `sync()`
|
|
214
|
+
* (including via auto-eviction), `lastSyncTs` has already advanced
|
|
215
|
+
* past the window sync just covered, so a record whose scope-exit
|
|
216
|
+
* mutation landed in that window will not be re-examined on this
|
|
217
|
+
* pass. Specify `outOfWindowLookbehindMs` (e.g., to cover since last
|
|
218
|
+
* eviction) or call this before `sync()` to close that gap.
|
|
219
|
+
*/
|
|
220
|
+
evictOutOfScopeRecords(collection: string, opts?: {
|
|
221
|
+
serverAssisted?: boolean;
|
|
222
|
+
outOfWindowLookbehindMs?: number;
|
|
223
|
+
}): Promise<EvictionCollectionInfo>;
|
|
224
|
+
/**
|
|
225
|
+
* Ask the server which of the given IDs no longer match the positive
|
|
226
|
+
* query server-side. Used by `evictOutOfScopeRecords` server-assisted
|
|
227
|
+
* pass to close the "filtered-delta tombstone" gap — records mutated
|
|
228
|
+
* out of scope by other writers that the filtered delta feed would
|
|
229
|
+
* never report.
|
|
230
|
+
*
|
|
231
|
+
* Chunks `candidateIds` into `$in`-sized batches to keep the request
|
|
232
|
+
* payload bounded. Uses `project: { _id: 1 }` to keep the response
|
|
233
|
+
* payload minimal.
|
|
234
|
+
*
|
|
235
|
+
* @param timestamp - `findNewer` timestamp cursor. Only records with
|
|
236
|
+
* `_ts > timestamp` are examined. Caller decides the window (usually
|
|
237
|
+
* the collection's `meta.lastSyncTs` to mirror the positive sync's
|
|
238
|
+
* cursor, or a lookbehind-derived value for shorter windows).
|
|
239
|
+
* @returns IDs the server reports as out-of-scope (i.e. matching
|
|
240
|
+
* `NOT query`). These are candidates for local-only eviction.
|
|
186
241
|
*/
|
|
187
|
-
|
|
242
|
+
private findServerSideScopeExits;
|
|
188
243
|
/**
|
|
189
244
|
* Evict out-of-scope records for all collections.
|
|
190
245
|
* Skips writeOnly and collections without syncConfig.query.
|
|
@@ -345,8 +345,15 @@ export interface SyncedDbConfig {
|
|
|
345
345
|
totalItems: number;
|
|
346
346
|
durationMs: number;
|
|
347
347
|
}) => void;
|
|
348
|
-
/**
|
|
348
|
+
/**
|
|
349
|
+
* Callback after each collection completes loading. Fires from two distinct phases that can run
|
|
350
|
+
* concurrently — `phase` discriminates the source so consumers can render progress coherently:
|
|
351
|
+
* - `'dexie'` — Dexie → in-memory hydration during init/setSyncOnlyTheseCollections
|
|
352
|
+
* - `'server'` — server → Dexie download during full/initial sync (findNewerManyStream)
|
|
353
|
+
* `loaded`/`total` are scoped to the phase that emitted the event.
|
|
354
|
+
*/
|
|
349
355
|
onSyncProgress?: (info: {
|
|
356
|
+
phase: 'dexie' | 'server';
|
|
350
357
|
collection: string;
|
|
351
358
|
loaded: number;
|
|
352
359
|
total: number;
|
|
@@ -738,9 +745,25 @@ export interface I_SyncedDb {
|
|
|
738
745
|
* Remove records from Dexie and in-mem that no longer match the
|
|
739
746
|
* collection's current syncConfig.query. Does NOT delete from server.
|
|
740
747
|
* Skips records with dirty changes (pending local writes).
|
|
741
|
-
*
|
|
742
|
-
|
|
743
|
-
|
|
748
|
+
*
|
|
749
|
+
* When `serverAssisted` is true (default when online and not writeOnly),
|
|
750
|
+
* also asks the server which of the locally-matching records no longer
|
|
751
|
+
* match the query server-side. This catches scope-exits caused by other
|
|
752
|
+
* writers — records the filtered delta feed would never report because
|
|
753
|
+
* the server-side state no longer matches the positive query.
|
|
754
|
+
*
|
|
755
|
+
* @param opts.serverAssisted - Override default auto-detection. Set
|
|
756
|
+
* `false` to skip the server round-trip (local-only pass).
|
|
757
|
+
* @param opts.outOfWindowLookbehindMs - Restrict the server-assisted
|
|
758
|
+
* query to records changed in the last N ms. When unspecified, uses
|
|
759
|
+
* the collection's current `meta.lastSyncTs` — the same cursor
|
|
760
|
+
* `sync()` passes to `findNewer`. Pass `Date.now()` to scan full
|
|
761
|
+
* history.
|
|
762
|
+
*/
|
|
763
|
+
evictOutOfScopeRecords(collection: string, opts?: {
|
|
764
|
+
serverAssisted?: boolean;
|
|
765
|
+
outOfWindowLookbehindMs?: number;
|
|
766
|
+
}): Promise<EvictionCollectionInfo>;
|
|
744
767
|
/**
|
|
745
768
|
* Same as evictOutOfScopeRecords but for all configured collections.
|
|
746
769
|
* Skips writeOnly collections and collections without syncConfig.query.
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import type { QuerySpec, QueryOpts, Projection } from "../types/I_RestInterface";
|
|
2
2
|
import type { DbEntity } from "../types/DbEntity";
|
|
3
3
|
/**
|
|
4
|
-
* Preveri, ali objekt ustreza MongoDB-style query specifikaciji
|
|
5
|
-
* Podpira
|
|
4
|
+
* Preveri, ali objekt ustreza MongoDB-style query specifikaciji.
|
|
5
|
+
* Podpira polje-operatorje: $eq, $ne, $gt, $gte, $lt, $lte, $in, $nin,
|
|
6
|
+
* $exists, $regex, $elemMatch, $size, $all — in logične operatorje
|
|
7
|
+
* $and, $or, $nor na top-levelu.
|
|
6
8
|
*/
|
|
7
9
|
export declare function matchesQuery<T extends DbEntity>(item: T, query: QuerySpec<T>): boolean;
|
|
8
10
|
/**
|