mindoodb 0.0.19 → 0.0.21
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/LICENSE +200 -0
- package/README-server.md +14 -14
- package/README.md +12 -10
- package/dist/browser/appendonlystores/IndexedDBContentAddressedStore.d.ts +6 -0
- package/dist/browser/appendonlystores/IndexedDBContentAddressedStore.d.ts.map +1 -1
- package/dist/browser/appendonlystores/IndexedDBContentAddressedStore.js +519 -373
- package/dist/browser/appendonlystores/IndexedDBContentAddressedStore.js.map +1 -1
- package/dist/browser/cache/IndexedDBLocalCacheStore.d.ts +12 -0
- package/dist/browser/cache/IndexedDBLocalCacheStore.d.ts.map +1 -1
- package/dist/browser/cache/IndexedDBLocalCacheStore.js +152 -65
- package/dist/browser/cache/IndexedDBLocalCacheStore.js.map +1 -1
- package/dist/browser/index.d.ts +1 -1
- package/dist/browser/index.d.ts.map +1 -1
- package/dist/browser/index.js +2 -1
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/index.mjs +14 -0
- package/dist/core/BaseMindooDB.d.ts +594 -6
- package/dist/core/BaseMindooDB.d.ts.map +1 -1
- package/dist/core/BaseMindooDB.js +2478 -191
- package/dist/core/BaseMindooDB.js.map +1 -1
- package/dist/core/BaseMindooTenant.d.ts +65 -1
- package/dist/core/BaseMindooTenant.d.ts.map +1 -1
- package/dist/core/BaseMindooTenant.js +250 -35
- package/dist/core/BaseMindooTenant.js.map +1 -1
- package/dist/core/BaseMindooTenantFactory.d.ts.map +1 -1
- package/dist/core/BaseMindooTenantFactory.js +47 -18
- package/dist/core/BaseMindooTenantFactory.js.map +1 -1
- package/dist/core/DocumentConflictAnalysis.d.ts +22 -0
- package/dist/core/DocumentConflictAnalysis.d.ts.map +1 -0
- package/dist/core/DocumentConflictAnalysis.js +101 -0
- package/dist/core/DocumentConflictAnalysis.js.map +1 -0
- package/dist/core/MindooDBServerAdmin.d.ts +26 -1
- package/dist/core/MindooDBServerAdmin.d.ts.map +1 -1
- package/dist/core/MindooDBServerAdmin.js +19 -3
- package/dist/core/MindooDBServerAdmin.js.map +1 -1
- package/dist/core/appendonlystores/types.d.ts +9 -0
- package/dist/core/appendonlystores/types.d.ts.map +1 -1
- package/dist/core/automerge-adapter.d.ts.map +1 -1
- package/dist/core/automerge-adapter.js +26 -14
- package/dist/core/automerge-adapter.js.map +1 -1
- package/dist/core/cache/EncryptedLocalCacheStore.d.ts +51 -1
- package/dist/core/cache/EncryptedLocalCacheStore.d.ts.map +1 -1
- package/dist/core/cache/EncryptedLocalCacheStore.js +48 -9
- package/dist/core/cache/EncryptedLocalCacheStore.js.map +1 -1
- package/dist/core/cache/LocalCacheStore.d.ts +34 -0
- package/dist/core/cache/LocalCacheStore.d.ts.map +1 -1
- package/dist/core/cache/LocalCacheStore.js +16 -0
- package/dist/core/cache/LocalCacheStore.js.map +1 -1
- package/dist/core/databaseIdValidation.d.ts +13 -0
- package/dist/core/databaseIdValidation.d.ts.map +1 -0
- package/dist/core/databaseIdValidation.js +38 -0
- package/dist/core/databaseIdValidation.js.map +1 -0
- package/dist/core/index.d.ts +2 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +2 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/indexing/virtualviews/MindooDBVirtualViewDataProvider.d.ts.map +1 -1
- package/dist/core/indexing/virtualviews/MindooDBVirtualViewDataProvider.js +5 -1
- package/dist/core/indexing/virtualviews/MindooDBVirtualViewDataProvider.js.map +1 -1
- package/dist/core/indexing/virtualviews/VirtualView.d.ts +14 -0
- package/dist/core/indexing/virtualviews/VirtualView.d.ts.map +1 -1
- package/dist/core/indexing/virtualviews/VirtualView.js +38 -6
- package/dist/core/indexing/virtualviews/VirtualView.js.map +1 -1
- package/dist/core/indexing/virtualviews/VirtualViewDataChange.d.ts +9 -2
- package/dist/core/indexing/virtualviews/VirtualViewDataChange.d.ts.map +1 -1
- package/dist/core/indexing/virtualviews/VirtualViewDataChange.js +10 -3
- package/dist/core/indexing/virtualviews/VirtualViewDataChange.js.map +1 -1
- package/dist/core/indexing/virtualviews/VirtualViewEntryData.d.ts +23 -1
- package/dist/core/indexing/virtualviews/VirtualViewEntryData.d.ts.map +1 -1
- package/dist/core/indexing/virtualviews/VirtualViewEntryData.js +17 -1
- package/dist/core/indexing/virtualviews/VirtualViewEntryData.js.map +1 -1
- package/dist/core/indexing/virtualviews/types.d.ts +8 -0
- package/dist/core/indexing/virtualviews/types.d.ts.map +1 -1
- package/dist/core/indexing/virtualviews/types.js.map +1 -1
- package/dist/core/keys/KeyBag.d.ts +244 -7
- package/dist/core/keys/KeyBag.d.ts.map +1 -1
- package/dist/core/keys/KeyBag.js +299 -82
- package/dist/core/keys/KeyBag.js.map +1 -1
- package/dist/core/tenantIdValidation.d.ts +19 -0
- package/dist/core/tenantIdValidation.d.ts.map +1 -0
- package/dist/core/tenantIdValidation.js +43 -0
- package/dist/core/tenantIdValidation.js.map +1 -0
- package/dist/core/types.d.ts +703 -12
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/node/cache/FileSystemLocalCacheStore.d.ts +2 -1
- package/dist/node/cache/FileSystemLocalCacheStore.d.ts.map +1 -1
- package/dist/node/cache/FileSystemLocalCacheStore.js +4 -0
- package/dist/node/cache/FileSystemLocalCacheStore.js.map +1 -1
- package/dist/node/server/ServerSync.d.ts.map +1 -1
- package/dist/node/server/ServerSync.js +3 -1
- package/dist/node/server/ServerSync.js.map +1 -1
- package/dist/node/server/TenantManager.d.ts +1 -0
- package/dist/node/server/TenantManager.d.ts.map +1 -1
- package/dist/node/server/TenantManager.js +11 -3
- package/dist/node/server/TenantManager.js.map +1 -1
- package/dist/node/server/validation.d.ts +2 -6
- package/dist/node/server/validation.d.ts.map +1 -1
- package/dist/node/server/validation.js +14 -24
- package/dist/node/server/validation.js.map +1 -1
- package/dist/reactnative/cache/MMKVLocalCacheStore.d.ts +1 -0
- package/dist/reactnative/cache/MMKVLocalCacheStore.d.ts.map +1 -1
- package/dist/reactnative/cache/MMKVLocalCacheStore.js +14 -0
- package/dist/reactnative/cache/MMKVLocalCacheStore.js.map +1 -1
- package/package.json +25 -23
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { MindooDB, CreateOptions, DeleteOptions, UndeleteOptions, ChangeOptions, DocumentDagAnalysisTimestamp, DocumentDagAnalysisResult, DocumentDagBranchMaterializationResult, DocumentDagEntryDetails, MindooDoc, MindooTenant, ProcessChangesCursor, ProcessChangesResult, DocumentHistoryResult, AttachmentConfig, DocumentCacheConfig, SnapshotConfig, SigningKeyPair, PerformanceCallback, ProcessChangeSummaryResult, SyncOptions, SyncResult, DocumentHistoryPageOptions, DocumentHistoryPageResult, MindooTextPatch, MindooTextPatchResult } from "./types";
|
|
1
|
+
import { MindooDB, CreateOptions, DeleteOptions, UndeleteOptions, ChangeOptions, DocumentDagAnalysisTimestamp, DocumentDagAnalysisResult, DocumentDagBranchMaterializationResult, DocumentDagEntryDetails, DocumentConflictAnalysisEvent, DocumentConflictAnalysisOptions, DocumentConflictBaseValue, DocumentConflictBaseValueQuery, DocumentConflictReport, DocumentConflictReportOptions, ConflictScanCheckpoint, MindooDoc, MindooTenant, ProcessChangesCursor, ProcessChangesResult, DocumentHistoryResult, AttachmentConfig, DocumentCacheConfig, SnapshotConfig, SigningKeyPair, PerformanceCallback, ProcessChangeSummaryResult, IncompleteAttachmentUploadReclaimResult, SyncOptions, SyncResult, DocumentHistoryPageOptions, DocumentHistoryPageResult, MindooJsonPatch, MindooJsonPatchResult, MindooTextPatch, MindooTextPatchResult, StartBackgroundWarmerOptions, BackgroundWarmerProgress } from "./types";
|
|
2
2
|
import { BaseMindooTenant } from "./BaseMindooTenant";
|
|
3
3
|
import type { ContentAddressedStore } from "./appendonlystores/types";
|
|
4
4
|
import { Logger } from "./logging";
|
|
@@ -59,6 +59,7 @@ export declare class BaseMindooDB implements MindooDB {
|
|
|
59
59
|
private attachmentStore;
|
|
60
60
|
private chunkSizeBytes;
|
|
61
61
|
private _isAdminOnlyDb;
|
|
62
|
+
private readonly timeTravelDate;
|
|
62
63
|
private index;
|
|
63
64
|
private indexLookup;
|
|
64
65
|
private nextChangeSeq;
|
|
@@ -66,7 +67,14 @@ export declare class BaseMindooDB implements MindooDB {
|
|
|
66
67
|
private readonly maxCachedDocs;
|
|
67
68
|
private readonly iteratePrefetchWindowDocs;
|
|
68
69
|
private readonly cacheRestoreLimit;
|
|
70
|
+
private readonly cacheRestoreBatchSize;
|
|
69
71
|
private readonly reconcileRestoredIndexOnInit;
|
|
72
|
+
/**
|
|
73
|
+
* When `true`, startup leaves the in-memory L1 cache empty and lets
|
|
74
|
+
* subsequent reads pull documents lazily from L2 via
|
|
75
|
+
* {@link tryLoadFromL2}. See `DocumentCacheConfig.restoreToL2`.
|
|
76
|
+
*/
|
|
77
|
+
private readonly restoreToL2;
|
|
70
78
|
private readonly snapshotMinChanges;
|
|
71
79
|
private readonly snapshotCooldownMs;
|
|
72
80
|
private processedEntryIds;
|
|
@@ -79,13 +87,57 @@ export declare class BaseMindooDB implements MindooDB {
|
|
|
79
87
|
private cachePrefix;
|
|
80
88
|
private dirtyDocIds;
|
|
81
89
|
private cacheMetaDirty;
|
|
82
|
-
|
|
90
|
+
/**
|
|
91
|
+
* Tenant KeyBag fingerprint observed at the time the in-memory index
|
|
92
|
+
* was last reconciled with the underlying store.
|
|
93
|
+
*
|
|
94
|
+
* Persisted alongside the cache checkpoint so warm starts can compare
|
|
95
|
+
* the current fingerprint against the stored one and skip a full
|
|
96
|
+
* metadata scan (and the associated REST round-trips against remote
|
|
97
|
+
* stores) when the bag composition has not changed since the last
|
|
98
|
+
* flush.
|
|
99
|
+
*
|
|
100
|
+
* Set to `null` when no reconciliation has been performed yet, or
|
|
101
|
+
* when the tenant does not expose a fingerprint method.
|
|
102
|
+
*/
|
|
103
|
+
private lastReconciledKeyBagFingerprint;
|
|
104
|
+
private readonly warmerBatchSize;
|
|
105
|
+
private readonly warmerScheduler;
|
|
106
|
+
/**
|
|
107
|
+
* Resolves when the currently-running warmer pass finishes. `null`
|
|
108
|
+
* when no warmer is running. Re-used to enforce single-flight: a
|
|
109
|
+
* second `startBackgroundWarmer()` call returns the same promise.
|
|
110
|
+
*/
|
|
111
|
+
private warmerPromise;
|
|
112
|
+
/**
|
|
113
|
+
* AbortController for the in-flight warmer. `null` when no warmer is
|
|
114
|
+
* running. {@link stopBackgroundWarmer} aborts via this controller.
|
|
115
|
+
*/
|
|
116
|
+
private warmerAbort;
|
|
117
|
+
/**
|
|
118
|
+
* Snapshot of the most recent warmer pass's progress. Updated
|
|
119
|
+
* in-place by {@link runBackgroundWarmer} so {@link getBackgroundWarmerProgress}
|
|
120
|
+
* can return the current state without additional bookkeeping. Set
|
|
121
|
+
* back to a fresh `{ processed: 0, total, phase: "warming" }` at the
|
|
122
|
+
* start of each new pass; the final value (`"done"` or
|
|
123
|
+
* `"cancelled"`) lingers between passes so a UI that mounts after
|
|
124
|
+
* the warmer settled can still display its outcome.
|
|
125
|
+
*/
|
|
126
|
+
private warmerProgress;
|
|
127
|
+
constructor(tenant: BaseMindooTenant, store: ContentAddressedStore, attachmentStore: ContentAddressedStore, attachmentConfig?: AttachmentConfig, documentCacheConfig?: DocumentCacheConfig, snapshotConfig?: SnapshotConfig, adminOnlyDb?: boolean, logger?: Logger, performanceCallback?: PerformanceCallback, timeTravelDate?: number | null);
|
|
83
128
|
/**
|
|
84
129
|
* Get the admin public key from the tenant.
|
|
85
130
|
* Only used when adminOnlyDb is true.
|
|
86
131
|
*/
|
|
87
132
|
private getAdminPublicKey;
|
|
88
133
|
isAdminOnlyDb(): boolean;
|
|
134
|
+
isTimeTravelMode(): boolean;
|
|
135
|
+
isReadOnly(): boolean;
|
|
136
|
+
getTimeTravelDate(): number | null;
|
|
137
|
+
private assertWritable;
|
|
138
|
+
private metadataVisibleAtTimeTravelDate;
|
|
139
|
+
private applyTimeTravelFilter;
|
|
140
|
+
private mergeTimeTravelScanFilters;
|
|
89
141
|
/**
|
|
90
142
|
* Attach a CacheManager so this DB participates in periodic cache flushing.
|
|
91
143
|
*/
|
|
@@ -97,16 +149,68 @@ export declare class BaseMindooDB implements MindooDB {
|
|
|
97
149
|
private getCachedDocument;
|
|
98
150
|
private touchCachedDocument;
|
|
99
151
|
private storeCachedDocument;
|
|
152
|
+
/**
|
|
153
|
+
* Bring the in-memory L1 cache back under `maxCachedDocs` after a new
|
|
154
|
+
* insert, performing flush-before-evict for any dirty entry that would
|
|
155
|
+
* otherwise be dropped.
|
|
156
|
+
*
|
|
157
|
+
* Without flush-before-evict, an evicted dirty doc loses its in-memory
|
|
158
|
+
* state before the periodic `CacheManager` flush has a chance to
|
|
159
|
+
* persist it, forcing the next read to fall through to the expensive
|
|
160
|
+
* full-materialization path. By writing the doc to L2 inline first, we
|
|
161
|
+
* guarantee the next read can recover it via the cheap L2 read path
|
|
162
|
+
* (Phase 1c) - either as a fresh hit (changeSeq matches) or as a
|
|
163
|
+
* stale hit that only needs the missing deltas re-applied.
|
|
164
|
+
*
|
|
165
|
+
* If no `cacheManager` is attached (i.e. there is no L2 store
|
|
166
|
+
* available), we fall back to the legacy behavior and just drop the
|
|
167
|
+
* dirty marker - matching pre-Phase-1 semantics so embedders who
|
|
168
|
+
* never opted into L2 see no behavior change.
|
|
169
|
+
*/
|
|
100
170
|
private evictCachedDocsIfNeeded;
|
|
171
|
+
/**
|
|
172
|
+
* Synchronous eviction variant used after the periodic flush has
|
|
173
|
+
* already drained `dirtyDocIds`. No L2 work is required because there
|
|
174
|
+
* are no dirty docs left to persist.
|
|
175
|
+
*/
|
|
176
|
+
private evictCleanCachedDocsIfNeeded;
|
|
101
177
|
/**
|
|
102
178
|
* Flush dirty documents and metadata to the cache store.
|
|
103
179
|
*/
|
|
104
180
|
flushToCache(store: LocalCacheStore): Promise<number>;
|
|
181
|
+
/**
|
|
182
|
+
* Serialize and persist a single document into the L2 cache store.
|
|
183
|
+
*
|
|
184
|
+
* Header format (v2):
|
|
185
|
+
* `{ version: 2, id, createdAt, lastModified, decryptionKeyId,
|
|
186
|
+
* isDeleted, changeSeq, automergeHeads }`
|
|
187
|
+
*
|
|
188
|
+
* `changeSeq` is read from the in-memory changefeed index so that on
|
|
189
|
+
* the next open we can compare it against the live index entry and
|
|
190
|
+
* decide whether the persisted Automerge state is up to date or needs
|
|
191
|
+
* incremental delta application. `automergeHeads` snapshots
|
|
192
|
+
* `Automerge.getHeads(doc)` so a future read can identify which entries
|
|
193
|
+
* (if any) still need to be applied to bring the persisted doc current.
|
|
194
|
+
*
|
|
195
|
+
* Both fields are derived inline (no extra index lookups beyond the
|
|
196
|
+
* O(1) `indexLookup`) so this stays cheap to call from the periodic
|
|
197
|
+
* flush as well as from the upcoming flush-before-evict path.
|
|
198
|
+
*/
|
|
199
|
+
private flushDirtyDocToCache;
|
|
105
200
|
private exportMetadataCheckpoint;
|
|
106
201
|
/**
|
|
107
202
|
* Attempt to restore state from cache. Returns true on success.
|
|
108
203
|
*/
|
|
109
204
|
restoreFromCache(store: LocalCacheStore): Promise<boolean>;
|
|
205
|
+
/**
|
|
206
|
+
* Decode a persisted L2 document cache record.
|
|
207
|
+
*
|
|
208
|
+
* Returns `null` for legacy (v1) records - they predate the
|
|
209
|
+
* `changeSeq + automergeHeads` freshness sentinels and so cannot
|
|
210
|
+
* participate in the L2 read-path freshness check; callers should
|
|
211
|
+
* fall back to the normal materialization path when they encounter
|
|
212
|
+
* one. Throws on truly malformed records (caught by callers).
|
|
213
|
+
*/
|
|
110
214
|
private deserializeDoc;
|
|
111
215
|
/**
|
|
112
216
|
* Get or import a CryptoKey for signature verification, with caching.
|
|
@@ -126,14 +230,24 @@ export declare class BaseMindooDB implements MindooDB {
|
|
|
126
230
|
private compareIndexEntries;
|
|
127
231
|
/**
|
|
128
232
|
* Update the index entry for a document.
|
|
129
|
-
* When a document changes, it gets a new monotonic sequence and is moved to
|
|
130
|
-
* maintain order by (changeSeq, docId).
|
|
131
233
|
*
|
|
132
|
-
*
|
|
234
|
+
* When a document changes, it gets a new monotonic sequence and is
|
|
235
|
+
* moved within the sorted index to maintain `(changeSeq, docId)` order.
|
|
236
|
+
* The lookup map is only patched for the range of entries that actually
|
|
237
|
+
* shifted.
|
|
238
|
+
*
|
|
239
|
+
* Idempotent: if every tracked field (`lastModified`, `isDeleted`,
|
|
240
|
+
* `decryptionKeyId`, `accessState`) matches the existing entry the
|
|
241
|
+
* call is a no-op and no new `changeSeq` is consumed. This is what
|
|
242
|
+
* keeps repeated visibility reconciliations from inflating the
|
|
243
|
+
* changefeed.
|
|
133
244
|
*
|
|
134
245
|
* @param docId The document ID
|
|
135
246
|
* @param lastModified The new last modified timestamp
|
|
136
|
-
* @param isDeleted Whether the document is
|
|
247
|
+
* @param isDeleted Whether the document is a deletion/inaccessibility tombstone
|
|
248
|
+
* @param decryptionKeyId Encryption key id derived from the doc's store metadata
|
|
249
|
+
* @param accessState `"visible"` for readable docs, `"inaccessible"` for
|
|
250
|
+
* tombstones produced by the key visibility layer
|
|
137
251
|
*/
|
|
138
252
|
private updateIndex;
|
|
139
253
|
/**
|
|
@@ -179,11 +293,94 @@ export declare class BaseMindooDB implements MindooDB {
|
|
|
179
293
|
* then processes only the delta. Falls back to full rebuild on cache miss.
|
|
180
294
|
*/
|
|
181
295
|
initialize(): Promise<void>;
|
|
296
|
+
/**
|
|
297
|
+
* Compute the current tenant KeyBag fingerprint, or `null` when the
|
|
298
|
+
* tenant does not expose one (older `MindooTenant` implementations).
|
|
299
|
+
*/
|
|
300
|
+
private computeCurrentKeyBagFingerprint;
|
|
301
|
+
/**
|
|
302
|
+
* Record that the in-memory index now reflects the given KeyBag
|
|
303
|
+
* fingerprint. Marks the cache metadata dirty whenever the recorded
|
|
304
|
+
* value changes so the new fingerprint reaches the persisted
|
|
305
|
+
* checkpoint at the next flush.
|
|
306
|
+
*/
|
|
307
|
+
private markKeyBagFingerprintReconciled;
|
|
308
|
+
/**
|
|
309
|
+
* Derive the per-doc visibility summary needed to reconcile the index
|
|
310
|
+
* against the current KeyBag state.
|
|
311
|
+
*
|
|
312
|
+
* - `decryptionKeyId` is taken from the chronologically first lifecycle
|
|
313
|
+
* entry, mirroring how {@link syncStoreChanges} materializes a doc.
|
|
314
|
+
* Replay entries inside a doc cannot retroactively re-key it.
|
|
315
|
+
* - `lastModified` is the latest `createdAt` among the entries that
|
|
316
|
+
* would be replayed for this doc (or, if none exist, the lifecycle
|
|
317
|
+
* entries themselves). This matches the user-visible timestamp the
|
|
318
|
+
* existing read path produces.
|
|
319
|
+
* - `isDeleted` is the lifecycle state derived from the same metadata
|
|
320
|
+
* {@link syncStoreChanges} would have observed.
|
|
321
|
+
*
|
|
322
|
+
* Returns `null` when there are no lifecycle entries for the doc,
|
|
323
|
+
* meaning there is nothing to reconcile.
|
|
324
|
+
*/
|
|
325
|
+
private deriveDocumentVisibilityMetadata;
|
|
326
|
+
/**
|
|
327
|
+
* Evict every locally cached form of a document.
|
|
328
|
+
*
|
|
329
|
+
* Used by the visibility layer whenever a document transitions to
|
|
330
|
+
* `"inaccessible"` (the user lost the decryption key) or when a stale
|
|
331
|
+
* L2 record for an inaccessible doc is discovered. The point is to
|
|
332
|
+
* make sure no decrypted plaintext or in-memory Automerge state for
|
|
333
|
+
* the doc survives beyond the key revocation.
|
|
334
|
+
*
|
|
335
|
+
* - L1 (`docCache`) is cleared and the dirty marker dropped so we do
|
|
336
|
+
* not later persist a stale entry.
|
|
337
|
+
* - The automerge-hash lookup is cleared so any future re-add starts
|
|
338
|
+
* with a clean re-materialization.
|
|
339
|
+
* - The L2 record is deleted via the {@link LocalCacheStore} (if a
|
|
340
|
+
* cache manager is attached). Failures are logged but never thrown:
|
|
341
|
+
* a leftover encrypted record is preferable to crashing the read
|
|
342
|
+
* path that triggered the purge.
|
|
343
|
+
*/
|
|
344
|
+
private purgeMaterializedDocument;
|
|
345
|
+
/**
|
|
346
|
+
* Reconcile the in-memory index with the current tenant KeyBag.
|
|
347
|
+
*
|
|
348
|
+
* This is the core entry point for "the user's keys changed; refresh
|
|
349
|
+
* what this database thinks is visible". It is safe to call repeatedly,
|
|
350
|
+
* including from concurrent live updates: the underlying `updateIndex`
|
|
351
|
+
* call only consumes a new `changeSeq` when state actually transitions.
|
|
352
|
+
*
|
|
353
|
+
* Behaviour for each doc that exists in the underlying store:
|
|
354
|
+
*
|
|
355
|
+
* - **Key now available, no entry / inaccessible entry** -> mark
|
|
356
|
+
* `"visible"` and emit a new index revision so view providers can
|
|
357
|
+
* re-add the doc. The doc body will be materialized lazily on the
|
|
358
|
+
* next read.
|
|
359
|
+
* - **Key now available, already visible** -> no-op.
|
|
360
|
+
* - **Key now missing, currently visible** -> purge any materialized
|
|
361
|
+
* state and mark `"inaccessible"` with `isDeleted: true` so
|
|
362
|
+
* metadata-only feeds emit a single tombstone and views remove
|
|
363
|
+
* the entry.
|
|
364
|
+
* - **Key now missing, already inaccessible (or not yet in index)** ->
|
|
365
|
+
* no index change, but we still call {@link purgeMaterializedDocument}
|
|
366
|
+
* defensively to scrub any leftover plaintext cache that might exist.
|
|
367
|
+
*
|
|
368
|
+
* Time-travel views are immutable; the function returns early for them.
|
|
369
|
+
* After running, if any transition occurred we mark the cache metadata
|
|
370
|
+
* dirty so the new visibility state survives a process restart.
|
|
371
|
+
*/
|
|
372
|
+
reconcileKeyVisibility(): Promise<void>;
|
|
182
373
|
private reconcileRestoredIndexWithStore;
|
|
183
374
|
/**
|
|
184
375
|
* Sync changes from the content-addressed store by finding new entries and processing them.
|
|
185
376
|
* This method can be called multiple times to incrementally sync new entries.
|
|
186
377
|
* On first call (when processedEntryIds is empty), it will process all entries.
|
|
378
|
+
*
|
|
379
|
+
* Sync intentionally does not trigger the L2 background warmer.
|
|
380
|
+
* Callers that want to warm the L2 cache after a sync (e.g. the Haven
|
|
381
|
+
* sync page) must call {@link startBackgroundWarmer} explicitly so
|
|
382
|
+
* casual sync calls stay cheap and the warmer cost is paid only when
|
|
383
|
+
* the workload is about to benefit from it.
|
|
187
384
|
*/
|
|
188
385
|
syncStoreChanges(): Promise<void>;
|
|
189
386
|
private supportsCursorScan;
|
|
@@ -252,6 +449,9 @@ export declare class BaseMindooDB implements MindooDB {
|
|
|
252
449
|
private syncEntriesFromStoreDense;
|
|
253
450
|
getStore(): ContentAddressedStore;
|
|
254
451
|
getAttachmentStore(): ContentAddressedStore;
|
|
452
|
+
reclaimIncompleteAttachmentUploads(options?: {
|
|
453
|
+
minAgeMs?: number;
|
|
454
|
+
}): Promise<IncompleteAttachmentUploadReclaimResult>;
|
|
255
455
|
getTenant(): MindooTenant;
|
|
256
456
|
createDocument(options?: CreateOptions): Promise<MindooDoc>;
|
|
257
457
|
/**
|
|
@@ -289,6 +489,289 @@ export declare class BaseMindooDB implements MindooDB {
|
|
|
289
489
|
materializeDocumentBranchAtEntry(docId: string, headEntryId: string): Promise<DocumentDagBranchMaterializationResult | null>;
|
|
290
490
|
materializeDocumentBranchAtTimestamp(docId: string, timestamp: DocumentDagAnalysisTimestamp, headEntryId: string): Promise<DocumentDagBranchMaterializationResult | null>;
|
|
291
491
|
describeDocumentDagEntry(docId: string, entryId: string): Promise<DocumentDagEntryDetails | null>;
|
|
492
|
+
/**
|
|
493
|
+
* Streams conflict-analysis events for one or more documents.
|
|
494
|
+
*
|
|
495
|
+
* This is the UI/server friendly entry point for conflict analysis. It first
|
|
496
|
+
* does a metadata-only preflight for each document, then only decrypts and
|
|
497
|
+
* replays document changes when the DAG contains concurrency candidates. The
|
|
498
|
+
* yielded DTOs intentionally expose MindooDB concepts only; callers never get
|
|
499
|
+
* direct access to Automerge documents, patches, operation IDs, or objects.
|
|
500
|
+
*
|
|
501
|
+
* @param docIds Document IDs to analyze. Documents are processed sequentially
|
|
502
|
+
* so browser callers can render progress and stop early without a large
|
|
503
|
+
* burst of synchronous work.
|
|
504
|
+
* @param options Controls quick/full mode, value detail level, cancellation,
|
|
505
|
+
* per-document conflict limits, and cooperative event-loop yielding.
|
|
506
|
+
* @returns An async generator yielding progress, conflict, resolution, done,
|
|
507
|
+
* and error events.
|
|
508
|
+
*/
|
|
509
|
+
analyzeDocumentConflicts(docIds: string[], options?: DocumentConflictAnalysisOptions): AsyncGenerator<DocumentConflictAnalysisEvent, void, unknown>;
|
|
510
|
+
/**
|
|
511
|
+
* Builds a complete conflict report for a single document.
|
|
512
|
+
*
|
|
513
|
+
* This is a convenience wrapper around `analyzeDocumentConflicts()`. It forces
|
|
514
|
+
* full analysis mode, consumes the event stream internally, and returns a
|
|
515
|
+
* stable report object suitable for server-side jobs or UI detail panels.
|
|
516
|
+
*
|
|
517
|
+
* @param docId Document ID to analyze.
|
|
518
|
+
* @param options Report options. The wrapper ignores quick-mode limits because
|
|
519
|
+
* reports are intended to describe the full known conflict history.
|
|
520
|
+
* @returns Aggregated conflict and resolution information for the document.
|
|
521
|
+
*/
|
|
522
|
+
getDocumentConflictReport(docId: string, options?: DocumentConflictReportOptions): Promise<DocumentConflictReport>;
|
|
523
|
+
/**
|
|
524
|
+
* Resolves the value each conflicted path had at its merge base.
|
|
525
|
+
*
|
|
526
|
+
* For every query, the database identifies the heads that contributed to
|
|
527
|
+
* the conflict (the merging entry's parents for `entry-after` /
|
|
528
|
+
* `merge-deps` conflicts, or the active heads for `active-heads`
|
|
529
|
+
* conflicts), computes the most recent common ancestor of those heads,
|
|
530
|
+
* materializes the document at that ancestor, and reads the path.
|
|
531
|
+
*
|
|
532
|
+
* Queries that share a merge base are coalesced: the document is
|
|
533
|
+
* materialized at most once per unique base entry.
|
|
534
|
+
*
|
|
535
|
+
* @param docId Document identifier the queries refer to.
|
|
536
|
+
* @param queries One entry per (location, path) lookup the caller wants.
|
|
537
|
+
* @returns A `DocumentConflictBaseValue` aligned 1:1 with `queries`.
|
|
538
|
+
*/
|
|
539
|
+
getDocumentConflictBaseValues(docId: string, queries: DocumentConflictBaseValueQuery[]): Promise<DocumentConflictBaseValue[]>;
|
|
540
|
+
/**
|
|
541
|
+
* Returns the head entry IDs whose merge base should be resolved for one
|
|
542
|
+
* conflict location. Filters out IDs that aren't present in the local
|
|
543
|
+
* metadata so callers don't try to materialize against missing entries.
|
|
544
|
+
*/
|
|
545
|
+
private resolveConflictBaseParents;
|
|
546
|
+
/**
|
|
547
|
+
* Computes the most recent common ancestor of `parents` in the document's
|
|
548
|
+
* dependency DAG.
|
|
549
|
+
*
|
|
550
|
+
* Returns the deepest common ancestor (an ancestor that is not itself a
|
|
551
|
+
* proper ancestor of another common ancestor). If multiple deepest
|
|
552
|
+
* candidates exist, the one with the highest `createdAt` wins so the UI
|
|
553
|
+
* shows a base value as close to the conflict as possible.
|
|
554
|
+
*/
|
|
555
|
+
private computeConflictMergeBaseEntryId;
|
|
556
|
+
/**
|
|
557
|
+
* Captures the current local receipt/index position for future incremental
|
|
558
|
+
* conflict scans.
|
|
559
|
+
*/
|
|
560
|
+
getConflictScanCheckpoint(): Promise<ConflictScanCheckpoint>;
|
|
561
|
+
/**
|
|
562
|
+
* Narrows scan work to documents whose indexed latest state changed after the
|
|
563
|
+
* caller's checkpoint. When the caller asks for pre-existing unresolved
|
|
564
|
+
* conflicts, every requested document remains a candidate because an old active
|
|
565
|
+
* conflict may still need to be returned.
|
|
566
|
+
*/
|
|
567
|
+
private resolveConflictAnalysisCandidateDocIds;
|
|
568
|
+
/**
|
|
569
|
+
* Finds the latest local store receipt order. This is intentionally metadata
|
|
570
|
+
* only and works with stores that do not expose a direct max-receipt query.
|
|
571
|
+
*/
|
|
572
|
+
private getStoreMaxReceiptOrder;
|
|
573
|
+
/**
|
|
574
|
+
* Replays verified document changes and detects conflict/resolution events.
|
|
575
|
+
*
|
|
576
|
+
* The input `plan` is metadata-only and has already determined that analyzing
|
|
577
|
+
* this document is worth the cost. This method performs the private Automerge
|
|
578
|
+
* work: decrypting changes, replaying them in dependency order, inspecting
|
|
579
|
+
* changed paths, and optionally resolving conflicting value summaries. All
|
|
580
|
+
* Automerge-specific objects are converted to MindooDB DTOs before returning.
|
|
581
|
+
*
|
|
582
|
+
* Conflict detection has three phases:
|
|
583
|
+
* 1. Before applying a change, inspect existing multi-head states. This catches
|
|
584
|
+
* conflicts that exist between active heads and conflicts that are about to
|
|
585
|
+
* be resolved by a merge/resolution change.
|
|
586
|
+
* 2. After applying a change, inspect Automerge patches for changed paths and
|
|
587
|
+
* confirm conflicts with `getConflicts()` on those changed paths only.
|
|
588
|
+
* 3. After replay completes, inspect remaining active heads so unresolved
|
|
589
|
+
* conflicts are still reported for documents that never wrote a merge change.
|
|
590
|
+
*
|
|
591
|
+
* @param docId Document being analyzed.
|
|
592
|
+
* @param plan Metadata-only replay/concurrency plan for the document.
|
|
593
|
+
* @param options Analysis options propagated from the public API.
|
|
594
|
+
* @returns Conflict findings, resolution events, and the number of entries
|
|
595
|
+
* successfully replayed.
|
|
596
|
+
*/
|
|
597
|
+
private detectDocumentConflictsFromPlan;
|
|
598
|
+
/**
|
|
599
|
+
* Applies incremental-scan visibility rules to conflict and resolution events.
|
|
600
|
+
*
|
|
601
|
+
* Receipt order is preferred because it represents local arrival. Created-at is
|
|
602
|
+
* only a fallback for legacy metadata that predates receipt-order assignment.
|
|
603
|
+
*/
|
|
604
|
+
private shouldEmitConflictObservation;
|
|
605
|
+
/**
|
|
606
|
+
* Loads, verifies, decrypts, and decodes replay changes for conflict analysis.
|
|
607
|
+
*
|
|
608
|
+
* This mirrors the security checks used by normal materialization paths:
|
|
609
|
+
* admin-only databases ignore non-admin entries, signatures are verified
|
|
610
|
+
* before decryption, and malformed/missing entries are skipped with warnings.
|
|
611
|
+
*
|
|
612
|
+
* @param replayEntries Metadata entries selected by the conflict planner.
|
|
613
|
+
* @returns Map keyed by store entry ID containing decrypted change bytes and
|
|
614
|
+
* decoded Automerge hash/dependency metadata for private replay.
|
|
615
|
+
*/
|
|
616
|
+
private loadVerifiedReplayChanges;
|
|
617
|
+
/**
|
|
618
|
+
* Builds a private lookup from Automerge change hashes to MindooDB entry IDs.
|
|
619
|
+
*
|
|
620
|
+
* Public conflict DTOs use MindooDB entry IDs, while Automerge heads are
|
|
621
|
+
* hashes. This lookup lets us translate internal head sets back to stable
|
|
622
|
+
* store-entry references for UI and report consumers.
|
|
623
|
+
*
|
|
624
|
+
* @param replayEntries Store metadata for replay entries.
|
|
625
|
+
* @param verifiedChanges Decrypted/decoded changes keyed by entry ID.
|
|
626
|
+
* @returns Map from Automerge hash to MindooDB store entry ID.
|
|
627
|
+
*/
|
|
628
|
+
private buildAutomergeHashToEntryId;
|
|
629
|
+
/**
|
|
630
|
+
* Calls Automerge's diff API through a defensive private adapter.
|
|
631
|
+
*
|
|
632
|
+
* The public API must not depend on Automerge patch types. This wrapper keeps
|
|
633
|
+
* the cast and optional-method handling localized so a future Automerge API
|
|
634
|
+
* change affects only this internal method.
|
|
635
|
+
*
|
|
636
|
+
* @param doc Materialized internal Automerge document containing both head sets.
|
|
637
|
+
* @param beforeHeads Heads before applying the current change.
|
|
638
|
+
* @param afterHeads Heads after applying the current change.
|
|
639
|
+
* @returns Raw patch-like records for internal inspection only.
|
|
640
|
+
*/
|
|
641
|
+
private diffAutomergeHeads;
|
|
642
|
+
/**
|
|
643
|
+
* Reads a patch action without leaking Automerge patch types into the codebase.
|
|
644
|
+
*
|
|
645
|
+
* @param patch Raw patch-like record returned by the private diff adapter.
|
|
646
|
+
* @returns Patch action string, or null when unavailable.
|
|
647
|
+
*/
|
|
648
|
+
private getConflictPatchAction;
|
|
649
|
+
/**
|
|
650
|
+
* Normalizes a raw patch path into a JSON-safe MindooDB path array.
|
|
651
|
+
*
|
|
652
|
+
* @param patch Raw patch-like record returned by the private diff adapter.
|
|
653
|
+
* @returns A path made of string/number segments, or null for unsupported
|
|
654
|
+
* patch shapes.
|
|
655
|
+
*/
|
|
656
|
+
private getConflictPatchPath;
|
|
657
|
+
/**
|
|
658
|
+
* Checks Automerge's optional conflict marker on a raw patch.
|
|
659
|
+
*
|
|
660
|
+
* Some conflict states are not surfaced solely by this flag, so callers also
|
|
661
|
+
* verify changed paths with `hasDocumentConflictAtPath()`.
|
|
662
|
+
*
|
|
663
|
+
* @param patch Raw patch-like record returned by the private diff adapter.
|
|
664
|
+
* @returns True when the patch explicitly says it wrote a conflicted value.
|
|
665
|
+
*/
|
|
666
|
+
private isConflictPatch;
|
|
667
|
+
/**
|
|
668
|
+
* Filters MindooDB bookkeeping fields out of app-facing conflict results.
|
|
669
|
+
*
|
|
670
|
+
* `_lastModified` can conflict naturally because independent replicas update
|
|
671
|
+
* it during every change. Reporting it would be noisy and not useful to app
|
|
672
|
+
* developers analyzing their own JSON payload.
|
|
673
|
+
*
|
|
674
|
+
* @param path Candidate conflict path.
|
|
675
|
+
* @returns True when the path belongs to MindooDB internals.
|
|
676
|
+
*/
|
|
677
|
+
private isInternalConflictPath;
|
|
678
|
+
/**
|
|
679
|
+
* Confirms whether a specific document path currently has multiple values.
|
|
680
|
+
*
|
|
681
|
+
* This is the narrow, path-level use of Automerge conflict inspection. It is
|
|
682
|
+
* called only for paths surfaced by patches or by the bounded active-head scan.
|
|
683
|
+
*
|
|
684
|
+
* @param doc Internal document or nested object containing the candidate path.
|
|
685
|
+
* @param path Path relative to `doc`.
|
|
686
|
+
* @returns True when Automerge reports more than one conflicting value.
|
|
687
|
+
*/
|
|
688
|
+
private hasDocumentConflictAtPath;
|
|
689
|
+
/**
|
|
690
|
+
* Converts a conflict path into the public DTO representation.
|
|
691
|
+
*
|
|
692
|
+
* @param doc Internal document used to optionally resolve value summaries.
|
|
693
|
+
* @param path JSON-style path segments for the conflicted field.
|
|
694
|
+
* @param includeValues Whether to include winner/loser value summaries.
|
|
695
|
+
* @returns Public path DTO with optional conflict values.
|
|
696
|
+
*/
|
|
697
|
+
private buildDocumentConflictPath;
|
|
698
|
+
/**
|
|
699
|
+
* Scans a materialized document for current conflicts.
|
|
700
|
+
*
|
|
701
|
+
* This is intentionally used only for bounded multi-head states: before a
|
|
702
|
+
* resolving change is applied and after replay if unresolved active heads
|
|
703
|
+
* remain. Regular per-change analysis stays patch-driven for performance.
|
|
704
|
+
*
|
|
705
|
+
* @param doc Internal materialized document to inspect.
|
|
706
|
+
* @param includeValues Whether to include value summaries in returned paths.
|
|
707
|
+
* @returns Sorted conflict path DTOs.
|
|
708
|
+
*/
|
|
709
|
+
private collectDocumentConflictPaths;
|
|
710
|
+
/**
|
|
711
|
+
* Recursive worker for `collectDocumentConflictPaths()`.
|
|
712
|
+
*
|
|
713
|
+
* @param root Root internal document used when value summaries need absolute
|
|
714
|
+
* paths.
|
|
715
|
+
* @param parent Current object/array being inspected.
|
|
716
|
+
* @param basePath Path from `root` to `parent`.
|
|
717
|
+
* @param includeValues Whether to include value summaries.
|
|
718
|
+
* @param results Mutable result map keyed by path string.
|
|
719
|
+
* @param seen Object identity set used to avoid cycles/proxy revisits.
|
|
720
|
+
*/
|
|
721
|
+
private collectDocumentConflictPathsFromParent;
|
|
722
|
+
/**
|
|
723
|
+
* Reads winner/loser summaries for one conflicted path.
|
|
724
|
+
*
|
|
725
|
+
* Values are converted into JSON-safe summaries so callers can inspect them
|
|
726
|
+
* without seeing Automerge-specific wrappers or mutable document objects.
|
|
727
|
+
*
|
|
728
|
+
* @param doc Internal document containing the conflict.
|
|
729
|
+
* @param path Absolute path to the conflicted field.
|
|
730
|
+
* @returns Stable list of conflict value summaries.
|
|
731
|
+
*/
|
|
732
|
+
private getDocumentConflictValueSummaries;
|
|
733
|
+
/**
|
|
734
|
+
* Reads a nested value using the public path representation.
|
|
735
|
+
*
|
|
736
|
+
* @param root Root object/document to read from.
|
|
737
|
+
* @param path String/number path segments.
|
|
738
|
+
* @returns The value at the path, or undefined when any segment is missing.
|
|
739
|
+
*/
|
|
740
|
+
private readValueAtDocumentPath;
|
|
741
|
+
/**
|
|
742
|
+
* Produces a stable comparison key for conflict winner detection.
|
|
743
|
+
*
|
|
744
|
+
* @param value Value to fingerprint.
|
|
745
|
+
* @returns String key derived from the JSON-safe representation.
|
|
746
|
+
*/
|
|
747
|
+
private fingerprintConflictValue;
|
|
748
|
+
/**
|
|
749
|
+
* Converts arbitrary conflict values to bounded, JSON-safe data.
|
|
750
|
+
*
|
|
751
|
+
* This avoids exposing live Automerge objects and prevents very deep or cyclic
|
|
752
|
+
* structures from overwhelming reports.
|
|
753
|
+
*
|
|
754
|
+
* @param value Value to convert.
|
|
755
|
+
* @param depth Current recursion depth.
|
|
756
|
+
* @param seen Objects already visited during this conversion.
|
|
757
|
+
* @returns JSON-safe scalar, array/object subset, or compact placeholder.
|
|
758
|
+
*/
|
|
759
|
+
private toJsonSafeConflictValue;
|
|
760
|
+
/**
|
|
761
|
+
* Throws when the caller cancels conflict analysis.
|
|
762
|
+
*
|
|
763
|
+
* @param signal Optional `AbortSignal` supplied through analysis options.
|
|
764
|
+
*/
|
|
765
|
+
private throwIfConflictAnalysisAborted;
|
|
766
|
+
/**
|
|
767
|
+
* Cooperatively yields to the event loop during long browser/server scans.
|
|
768
|
+
*
|
|
769
|
+
* @param yieldEveryMs Minimum elapsed time before yielding. Undefined disables
|
|
770
|
+
* cooperative yielding; `0` yields at every call site.
|
|
771
|
+
* @param lastYieldAt Timestamp of the previous yield.
|
|
772
|
+
* @returns Updated timestamp to carry into the next call.
|
|
773
|
+
*/
|
|
774
|
+
private maybeYieldForConflictAnalysis;
|
|
292
775
|
/**
|
|
293
776
|
* Derives human-readable changed field paths for one DAG entry.
|
|
294
777
|
*
|
|
@@ -322,8 +805,17 @@ export declare class BaseMindooDB implements MindooDB {
|
|
|
322
805
|
changeDoc(doc: MindooDoc, changeFunc: (doc: MindooDoc) => void | Promise<void>, options?: ChangeOptions): Promise<void>;
|
|
323
806
|
changeDocWithSigningKey(doc: MindooDoc, changeFunc: (doc: MindooDoc) => void | Promise<void>, signingKeyPair: SigningKeyPair, signingKeyPassword: string): Promise<void>;
|
|
324
807
|
applyTextPatch(doc: MindooDoc, patch: MindooTextPatch): Promise<MindooTextPatchResult>;
|
|
808
|
+
applyJsonPatch(doc: MindooDoc, patch: MindooJsonPatch): Promise<MindooJsonPatchResult>;
|
|
325
809
|
private changeDocInternal;
|
|
326
810
|
private validateTextPatch;
|
|
811
|
+
private validateJsonPatch;
|
|
812
|
+
private validateJsonPath;
|
|
813
|
+
private applyJsonPatchOperations;
|
|
814
|
+
private setJsonValueAtPath;
|
|
815
|
+
private unsetJsonValueAtPath;
|
|
816
|
+
private readJsonListAtPath;
|
|
817
|
+
private ensureJsonParentAtPath;
|
|
818
|
+
private readJsonParentAtPath;
|
|
327
819
|
private ensureTextPath;
|
|
328
820
|
private persistDocumentChange;
|
|
329
821
|
/**
|
|
@@ -388,6 +880,97 @@ export declare class BaseMindooDB implements MindooDB {
|
|
|
388
880
|
* Returns the updated document, or null if document wasn't actually changed.
|
|
389
881
|
*/
|
|
390
882
|
private applyNewEntriesToCachedDocument;
|
|
883
|
+
/**
|
|
884
|
+
* Try to satisfy a document load from the persisted L2 cache without
|
|
885
|
+
* going through the full signature-verify + decrypt + Automerge replay
|
|
886
|
+
* pipeline.
|
|
887
|
+
*
|
|
888
|
+
* Three outcomes:
|
|
889
|
+
*
|
|
890
|
+
* 1. **L2 miss / unusable** (no record, legacy v1 record, deserialize
|
|
891
|
+
* failure, no `cacheManager`, etc.): returns `null`. The caller
|
|
892
|
+
* falls through to the existing full-materialization path.
|
|
893
|
+
*
|
|
894
|
+
* 2. **L2 fresh hit** (`persistedChangeSeq === currentChangeSeq`):
|
|
895
|
+
* promote the deserialized doc to L1 and return it. No store
|
|
896
|
+
* traffic, no crypto, no Automerge replay. This is the common case
|
|
897
|
+
* for warm databases and is what makes view rebuilds fast.
|
|
898
|
+
*
|
|
899
|
+
* 3. **L2 stale hit** (`persistedChangeSeq < currentChangeSeq`): scan
|
|
900
|
+
* the doc's store metadata, identify entries whose `automergeHash`
|
|
901
|
+
* is *not* already in the persisted doc's history, and re-use the
|
|
902
|
+
* existing {@link applyNewEntriesToCachedDocument} pipeline to
|
|
903
|
+
* verify+decrypt+apply only those deltas. Pre-filtering by hash
|
|
904
|
+
* means we never pay signature/decrypt cost for changes already
|
|
905
|
+
* captured in the persisted Automerge state.
|
|
906
|
+
*
|
|
907
|
+
* Any unexpected error degrades gracefully to the full path - the L2
|
|
908
|
+
* read path is purely an optimization and must never lose data.
|
|
909
|
+
*/
|
|
910
|
+
private tryLoadFromL2;
|
|
911
|
+
/**
|
|
912
|
+
* Returns whether a background warmer pass is currently running.
|
|
913
|
+
*
|
|
914
|
+
* @see startBackgroundWarmer
|
|
915
|
+
* @see stopBackgroundWarmer
|
|
916
|
+
*/
|
|
917
|
+
isWarmerRunning(): boolean;
|
|
918
|
+
/**
|
|
919
|
+
* Start the L2 background warmer.
|
|
920
|
+
*
|
|
921
|
+
* Walks a snapshot of the in-memory document index and, for every
|
|
922
|
+
* doc not already in L1, calls {@link tryLoadFromL2}. That path
|
|
923
|
+
* either:
|
|
924
|
+
*
|
|
925
|
+
* - hits L2 fresh and just promotes the doc to L1, or
|
|
926
|
+
* - hits L2 stale and applies missing deltas (re-flushed via the
|
|
927
|
+
* next CacheManager flush), or
|
|
928
|
+
* - falls through to full materialization for L2 misses, which then
|
|
929
|
+
* flushes a fresh L2 record via flush-before-evict.
|
|
930
|
+
*
|
|
931
|
+
* In all cases, after the warmer has visited every doc, every L2
|
|
932
|
+
* record has the current `changeSeq + automergeHeads`. Subsequent
|
|
933
|
+
* read-heavy workloads (most importantly virtual view rebuilds) can
|
|
934
|
+
* then satisfy every doc lookup via the cheap L2 read path.
|
|
935
|
+
*
|
|
936
|
+
* Single-flight: if a warmer is already running, the existing promise
|
|
937
|
+
* is returned. Yields to {@link warmerScheduler} between batches of
|
|
938
|
+
* `warmerBatchSize` docs so the foreground stays responsive.
|
|
939
|
+
*
|
|
940
|
+
* Cancellable via {@link stopBackgroundWarmer} or by passing an
|
|
941
|
+
* external {@link AbortSignal}. Cancellation is observed at batch
|
|
942
|
+
* boundaries; the in-flight doc is allowed to complete.
|
|
943
|
+
*/
|
|
944
|
+
startBackgroundWarmer(options?: StartBackgroundWarmerOptions): Promise<void>;
|
|
945
|
+
/**
|
|
946
|
+
* Returns a snapshot of the most recent background warmer pass's
|
|
947
|
+
* progress, or `null` if no warmer has ever run on this instance.
|
|
948
|
+
*
|
|
949
|
+
* The returned object is the live snapshot used internally by
|
|
950
|
+
* {@link runBackgroundWarmer}; callers MUST NOT mutate it. The snapshot
|
|
951
|
+
* is replaced (not mutated in place) on the next
|
|
952
|
+
* {@link startBackgroundWarmer} call, so consumers polling this
|
|
953
|
+
* method see consistent integer readings.
|
|
954
|
+
*
|
|
955
|
+
* @see startBackgroundWarmer
|
|
956
|
+
*/
|
|
957
|
+
getBackgroundWarmerProgress(): BackgroundWarmerProgress | null;
|
|
958
|
+
/**
|
|
959
|
+
* Cancel the in-flight warmer (if any) and wait for it to settle.
|
|
960
|
+
* Safe to call when no warmer is running - returns a resolved
|
|
961
|
+
* promise immediately.
|
|
962
|
+
*/
|
|
963
|
+
stopBackgroundWarmer(): Promise<void>;
|
|
964
|
+
/**
|
|
965
|
+
* Body of one warmer pass. Pulled out so {@link startBackgroundWarmer}
|
|
966
|
+
* can wrap it in single-flight + abort plumbing without nesting.
|
|
967
|
+
*
|
|
968
|
+
* Maintains `this.warmerProgress` as a fresh snapshot for
|
|
969
|
+
* {@link getBackgroundWarmerProgress} consumers and invokes
|
|
970
|
+
* `onProgress` once per scheduler yield (per `warmerBatchSize` docs)
|
|
971
|
+
* plus once at the end of the pass with the terminal phase.
|
|
972
|
+
*/
|
|
973
|
+
private runBackgroundWarmer;
|
|
391
974
|
/**
|
|
392
975
|
* Internal method to load a document from the content-addressed store
|
|
393
976
|
*/
|
|
@@ -434,6 +1017,11 @@ export declare class BaseMindooDB implements MindooDB {
|
|
|
434
1017
|
* Internal method to add an attachment by chunking the file and storing chunks.
|
|
435
1018
|
*/
|
|
436
1019
|
private addAttachmentInternal;
|
|
1020
|
+
private pendingAttachmentUploadLedgerId;
|
|
1021
|
+
private putEntriesWithRetry;
|
|
1022
|
+
private createPendingAttachmentUploadLedger;
|
|
1023
|
+
private clearPendingAttachmentUploadLedger;
|
|
1024
|
+
private cleanupIncompleteAttachmentUpload;
|
|
437
1025
|
/**
|
|
438
1026
|
* Internal method to add an attachment from a streaming data source.
|
|
439
1027
|
* Memory efficient - processes data chunk by chunk without loading entire file into memory.
|