mindoodb 0.0.19 → 0.0.20
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 +7 -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 +63 -1
- package/dist/core/BaseMindooTenant.d.ts.map +1 -1
- package/dist/core/BaseMindooTenant.js +198 -21
- package/dist/core/BaseMindooTenant.js.map +1 -1
- package/dist/core/BaseMindooTenantFactory.d.ts.map +1 -1
- package/dist/core/BaseMindooTenantFactory.js +18 -7
- 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 +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +1 -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/types.d.ts +678 -5
- 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 -2
- package/dist/node/server/validation.d.ts.map +1 -1
- package/dist/node/server/validation.js +6 -10
- 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
package/dist/core/types.d.ts
CHANGED
|
@@ -102,12 +102,78 @@ export interface OpenTenantOptions {
|
|
|
102
102
|
* Map value: true if trusted, false if explicitly revoked
|
|
103
103
|
*/
|
|
104
104
|
additionalTrustedKeys?: ReadonlyMap<string, boolean>;
|
|
105
|
+
/**
|
|
106
|
+
* Optional pre-decrypted signing/encryption CryptoKeys for the current
|
|
107
|
+
* user. When supplied, the tenant uses these directly instead of
|
|
108
|
+
* decrypting the encrypted private keys with the user password on first
|
|
109
|
+
* use. Typically derived once at login (see e.g.
|
|
110
|
+
* {@link KeyBag.deriveWrappingKey}) and held as `extractable: false`
|
|
111
|
+
* CryptoKeys for the lifetime of the session.
|
|
112
|
+
*
|
|
113
|
+
* When provided, the `currentUserPassword` argument to
|
|
114
|
+
* {@link MindooTenantFactory.openTenant} may be empty - it will not be
|
|
115
|
+
* used as long as the requested cached key is already present.
|
|
116
|
+
*/
|
|
117
|
+
preDecryptedUserKeys?: PreDecryptedUserKeys;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Pre-decrypted user CryptoKeys that callers can pass to
|
|
121
|
+
* {@link MindooTenantFactory.openTenant} via {@link OpenTenantOptions}.
|
|
122
|
+
*
|
|
123
|
+
* Each key is independent. Whichever key is set is used directly; the
|
|
124
|
+
* other is still decrypted on demand from the user password on first
|
|
125
|
+
* use.
|
|
126
|
+
*/
|
|
127
|
+
export interface PreDecryptedUserKeys {
|
|
128
|
+
/**
|
|
129
|
+
* Pre-imported Ed25519 signing {@link CryptoKey} (`["sign"]` usage).
|
|
130
|
+
* Skips the password-based decryption + import for the user's signing key.
|
|
131
|
+
*/
|
|
132
|
+
signingKey?: CryptoKey;
|
|
133
|
+
/**
|
|
134
|
+
* Pre-imported RSA-OAEP encryption {@link CryptoKey} (`["decrypt"]` usage).
|
|
135
|
+
* Skips the password-based decryption + import for the user's encryption key.
|
|
136
|
+
*/
|
|
137
|
+
encryptionKey?: CryptoKey;
|
|
138
|
+
/**
|
|
139
|
+
* Pre-derived AES-GCM cache encryption {@link CryptoKey} (`["encrypt", "decrypt"]`
|
|
140
|
+
* usage). Skips the password-based PBKDF2 derivation that the
|
|
141
|
+
* `EncryptedLocalCacheStore` performs internally.
|
|
142
|
+
*/
|
|
143
|
+
cacheEncryptionKey?: CryptoKey;
|
|
105
144
|
}
|
|
106
145
|
interface CreateTenantPasswords {
|
|
107
146
|
/** Password for the admin user's private keys */
|
|
108
147
|
adminPassword: string;
|
|
109
|
-
/**
|
|
148
|
+
/**
|
|
149
|
+
* Password for the regular (app) user's private keys.
|
|
150
|
+
*
|
|
151
|
+
* When {@link existingKeyBag} **and** {@link preDecryptedAppUserKeys}
|
|
152
|
+
* are both supplied the password is no longer needed by `createTenant`
|
|
153
|
+
* (the bag has already been wrapped, and `openTenant` consumes the
|
|
154
|
+
* pre-imported `CryptoKey`s directly). Callers in that live-bag mode
|
|
155
|
+
* may pass an empty string.
|
|
156
|
+
*/
|
|
110
157
|
userPassword: string;
|
|
158
|
+
/**
|
|
159
|
+
* Optional pre-existing {@link KeyBag} to extend with the new tenant's
|
|
160
|
+
* keys. When supplied, `createTenant` will mutate this bag in place
|
|
161
|
+
* (adding the new tenant's `default` and `$publicinfos` doc keys) and
|
|
162
|
+
* return the same instance in {@link CreateTenantResult.keyBag}. The
|
|
163
|
+
* caller is then responsible for persisting the bag once.
|
|
164
|
+
*
|
|
165
|
+
* When omitted, `createTenant` constructs a fresh bag using the legacy
|
|
166
|
+
* password-based KeyBag wrapping derivation (existing behavior).
|
|
167
|
+
*/
|
|
168
|
+
existingKeyBag?: KeyBag;
|
|
169
|
+
/**
|
|
170
|
+
* Optional pre-decrypted CryptoKeys for the *app user* identity that
|
|
171
|
+
* are forwarded to the underlying {@link MindooTenantFactory.openTenant}
|
|
172
|
+
* call. When supplied alongside {@link existingKeyBag} the
|
|
173
|
+
* password-based decryption + import of the app user's signing /
|
|
174
|
+
* encryption private keys is skipped entirely.
|
|
175
|
+
*/
|
|
176
|
+
preDecryptedAppUserKeys?: PreDecryptedUserKeys;
|
|
111
177
|
}
|
|
112
178
|
/**
|
|
113
179
|
* Options for creating a new tenant with a single convenience call.
|
|
@@ -129,6 +195,11 @@ export type CreateTenantOptions = ({
|
|
|
129
195
|
} & CreateTenantPasswords);
|
|
130
196
|
/**
|
|
131
197
|
* Result of creating a new tenant via createTenant().
|
|
198
|
+
*
|
|
199
|
+
* When the caller provided {@link CreateTenantOptions.existingKeyBag}, the
|
|
200
|
+
* returned `keyBag` is the same instance (mutated in place with the new
|
|
201
|
+
* tenant's keys). Callers should not double-save in that case - persist
|
|
202
|
+
* the bag once after `createTenant` returns.
|
|
132
203
|
*/
|
|
133
204
|
export interface CreateTenantResult {
|
|
134
205
|
/** The opened tenant, ready to use */
|
|
@@ -204,13 +275,49 @@ export interface JoinResponse {
|
|
|
204
275
|
export interface JoinTenantOptions {
|
|
205
276
|
/** The user's locally-generated private identity (keys never leave this device) */
|
|
206
277
|
user: PrivateUserId;
|
|
207
|
-
/**
|
|
278
|
+
/**
|
|
279
|
+
* The password for the user's private keys.
|
|
280
|
+
*
|
|
281
|
+
* Required when neither {@link existingKeyBag} nor
|
|
282
|
+
* {@link preDecryptedUserKeys} is supplied. When `existingKeyBag` is
|
|
283
|
+
* provided the password is *not* used to construct a new KeyBag; when
|
|
284
|
+
* `preDecryptedUserKeys.signingKey` and `preDecryptedUserKeys.encryptionKey`
|
|
285
|
+
* are both supplied the password is *not* used to decrypt the user's
|
|
286
|
+
* private keys before opening the tenant. In those live-bag cases
|
|
287
|
+
* callers may pass an empty string.
|
|
288
|
+
*/
|
|
208
289
|
password: string;
|
|
209
290
|
/** The shared password used to decrypt the keys in the join response */
|
|
210
291
|
sharePassword: string;
|
|
292
|
+
/**
|
|
293
|
+
* Optional pre-existing {@link KeyBag} to extend with the joined tenant's
|
|
294
|
+
* keys. When supplied, `joinTenant` will mutate this bag in place (adding
|
|
295
|
+
* the joined tenant's `default` and `$publicinfos` doc keys) and return
|
|
296
|
+
* the same instance in {@link JoinTenantResult.keyBag}. The caller is
|
|
297
|
+
* then responsible for persisting the bag once.
|
|
298
|
+
*
|
|
299
|
+
* When omitted, `joinTenant` constructs a fresh bag using the legacy
|
|
300
|
+
* password-based KeyBag wrapping derivation (existing behavior).
|
|
301
|
+
*/
|
|
302
|
+
existingKeyBag?: KeyBag;
|
|
303
|
+
/**
|
|
304
|
+
* Optional pre-decrypted user keys forwarded to the underlying
|
|
305
|
+
* {@link MindooTenantFactory.openTenant} call. When the joining user's
|
|
306
|
+
* signing/encryption {@link CryptoKey}s are already available
|
|
307
|
+
* (e.g. because they were unlocked once at app startup via a live
|
|
308
|
+
* Haven session) supplying them here avoids the password-based
|
|
309
|
+
* decryption + import that `openTenant` would otherwise perform on
|
|
310
|
+
* the encrypted private keys carried on the user identity.
|
|
311
|
+
*/
|
|
312
|
+
preDecryptedUserKeys?: PreDecryptedUserKeys;
|
|
211
313
|
}
|
|
212
314
|
/**
|
|
213
315
|
* Result of joining a tenant via joinTenant().
|
|
316
|
+
*
|
|
317
|
+
* When the caller provided {@link JoinTenantOptions.existingKeyBag}, the
|
|
318
|
+
* returned `keyBag` is the same instance (mutated in place with the joined
|
|
319
|
+
* tenant's keys). Callers should not double-save in that case - persist the
|
|
320
|
+
* bag once after `joinTenant` returns.
|
|
214
321
|
*/
|
|
215
322
|
export interface JoinTenantResult {
|
|
216
323
|
/** The opened tenant, ready to use */
|
|
@@ -450,6 +557,32 @@ export interface MindooTenant {
|
|
|
450
557
|
* @return The database instance
|
|
451
558
|
*/
|
|
452
559
|
openDB(id: string, options?: OpenDBOptions): Promise<MindooDB>;
|
|
560
|
+
/**
|
|
561
|
+
* Replay any pending local KeyBag mutations and refresh open live
|
|
562
|
+
* databases so document visibility matches the current key set.
|
|
563
|
+
*
|
|
564
|
+
* Implementations must be idempotent and safe to call concurrently.
|
|
565
|
+
* The optional shape allows alternative tenant implementations (e.g.
|
|
566
|
+
* server-side, test doubles) to omit visibility reconciliation when it
|
|
567
|
+
* is not applicable.
|
|
568
|
+
*/
|
|
569
|
+
reconcileKeyBagChanges?(): Promise<void>;
|
|
570
|
+
/**
|
|
571
|
+
* Return whether the current KeyBag can resolve the given document
|
|
572
|
+
* encryption key id. Implementations must not throw when the key is
|
|
573
|
+
* missing; they should return `false` instead so callers can use the
|
|
574
|
+
* result as a guard before attempting decryption.
|
|
575
|
+
*/
|
|
576
|
+
hasDecryptionKey?(decryptionKeyId: string): Promise<boolean>;
|
|
577
|
+
/**
|
|
578
|
+
* Return a stable, opaque fingerprint of the doc keys this tenant
|
|
579
|
+
* currently has access to. The fingerprint must change whenever the
|
|
580
|
+
* set of available doc keys changes for the tenant, and must be safe
|
|
581
|
+
* to persist (no raw key material). Used by databases to skip
|
|
582
|
+
* visibility reconciliation on warm starts when the KeyBag composition
|
|
583
|
+
* has not changed since the last cache flush.
|
|
584
|
+
*/
|
|
585
|
+
getDocKeyFingerprint?(): Promise<string>;
|
|
453
586
|
/**
|
|
454
587
|
* Creates a MindooDocSigner instance for signing and verifying document items.
|
|
455
588
|
* The signer uses the tenant's cryptographic infrastructure for key management.
|
|
@@ -512,7 +645,7 @@ export { StoreKind } from "./appendonlystores/types";
|
|
|
512
645
|
* - doc_* entries are for Automerge document operations
|
|
513
646
|
* - attachment_* entries are for file attachment storage
|
|
514
647
|
*/
|
|
515
|
-
export type StoreEntryType = "doc_create" | "doc_change" | "doc_snapshot" | "doc_delete" | "doc_undelete" | "attachment_chunk";
|
|
648
|
+
export type StoreEntryType = "doc_create" | "doc_change" | "doc_snapshot" | "doc_delete" | "doc_undelete" | "pending_attachment_upload" | "attachment_chunk";
|
|
516
649
|
/**
|
|
517
650
|
* Metadata for entries stored in the ContentAddressedStore.
|
|
518
651
|
* This contains all information except the actual encrypted payload,
|
|
@@ -580,6 +713,21 @@ export interface StoreEntryMetadata {
|
|
|
580
713
|
* must only return cursors built from entries that have a concrete value.
|
|
581
714
|
*/
|
|
582
715
|
receiptOrder?: number;
|
|
716
|
+
/**
|
|
717
|
+
* Attachment id associated with attachment chunks or pending upload ledgers.
|
|
718
|
+
* For historical safety, cleanup only acts on pending upload ledgers that
|
|
719
|
+
* prove an attachment never reached a committed document revision.
|
|
720
|
+
*/
|
|
721
|
+
attachmentId?: string;
|
|
722
|
+
/**
|
|
723
|
+
* Attachment ids committed by this document entry. Used by local recovery to
|
|
724
|
+
* distinguish never-committed uploads from attachments required by history.
|
|
725
|
+
*/
|
|
726
|
+
attachmentIds?: string[];
|
|
727
|
+
/**
|
|
728
|
+
* Start timestamp for `pending_attachment_upload` recovery ledgers.
|
|
729
|
+
*/
|
|
730
|
+
uploadStartedAt?: number;
|
|
583
731
|
/**
|
|
584
732
|
* The public signing key of the user who created this entry (Ed25519, PEM format).
|
|
585
733
|
* Used for signature verification and audit trails.
|
|
@@ -664,6 +812,13 @@ export interface AttachmentReference {
|
|
|
664
812
|
*/
|
|
665
813
|
createdBy: string;
|
|
666
814
|
}
|
|
815
|
+
export interface IncompleteAttachmentUploadReclaimResult {
|
|
816
|
+
scannedLedgers: number;
|
|
817
|
+
reclaimedUploads: number;
|
|
818
|
+
reclaimedChunks: number;
|
|
819
|
+
keptCommittedUploads: number;
|
|
820
|
+
keptRecentUploads: number;
|
|
821
|
+
}
|
|
667
822
|
/**
|
|
668
823
|
* Configuration for attachment handling in MindooDB.
|
|
669
824
|
*/
|
|
@@ -698,6 +853,27 @@ export interface DocumentCacheConfig {
|
|
|
698
853
|
* Default: same as `maxEntries`
|
|
699
854
|
*/
|
|
700
855
|
restoreLimit?: number;
|
|
856
|
+
/**
|
|
857
|
+
* Number of cached documents fetched per batch during the eager
|
|
858
|
+
* startup restore (`restoreFromCache`). Each batch issues a single
|
|
859
|
+
* `LocalCacheStore.getMany` call, so this knob trades transaction
|
|
860
|
+
* overhead for transient memory pressure:
|
|
861
|
+
*
|
|
862
|
+
* - smaller values (e.g. 32-64) reduce peak memory at the cost of
|
|
863
|
+
* more cache-store transactions; sensible on memory-constrained
|
|
864
|
+
* targets (mobile, RN) or with very large average doc bodies (e.g.
|
|
865
|
+
* attachments-as-documents),
|
|
866
|
+
* - larger values (e.g. 512-1024) amortise per-transaction overhead
|
|
867
|
+
* but hold more encrypted+decrypted byte buffers in memory at the
|
|
868
|
+
* same time.
|
|
869
|
+
*
|
|
870
|
+
* Has no effect when `restoreToL2` is `true` (no eager fill happens).
|
|
871
|
+
* Has no effect on lazy L2 reads (`tryLoadFromL2`) or on the
|
|
872
|
+
* background warmer, both of which load one document at a time.
|
|
873
|
+
*
|
|
874
|
+
* Default: 256 (~25 MB transient peak per batch at 50 KB/doc).
|
|
875
|
+
*/
|
|
876
|
+
restoreBatchSize?: number;
|
|
701
877
|
/**
|
|
702
878
|
* When enabled, verifies after cache restore that the restored document
|
|
703
879
|
* index still matches the underlying local store and rebuilds metadata if a
|
|
@@ -706,6 +882,136 @@ export interface DocumentCacheConfig {
|
|
|
706
882
|
* Default: false
|
|
707
883
|
*/
|
|
708
884
|
reconcileRestoredIndexOnInit?: boolean;
|
|
885
|
+
/**
|
|
886
|
+
* When `true`, the persisted document cache is treated as the L2 tier
|
|
887
|
+
* of an L1/L2 cache split: startup does **not** eagerly materialize
|
|
888
|
+
* any cached documents into the in-memory L1 cache. Instead, the L2
|
|
889
|
+
* payloads stay on disk and individual `getDocument()` calls pull
|
|
890
|
+
* them in lazily via the L2 read path (which compares the persisted
|
|
891
|
+
* `changeSeq + automergeHeads` against the live index, applies
|
|
892
|
+
* deltas if stale, and then promotes to L1).
|
|
893
|
+
*
|
|
894
|
+
* This unlocks the "L2 much larger than L1" use case (e.g. 30k docs
|
|
895
|
+
* persisted, 128 in RAM) without burning startup time and memory on
|
|
896
|
+
* documents the user may never read.
|
|
897
|
+
*
|
|
898
|
+
* When `false` (the default), startup behavior is unchanged: cached
|
|
899
|
+
* documents are eagerly loaded into L1 up to `restoreLimit`. Even in
|
|
900
|
+
* eager mode the restore now uses the new batched `getMany` API to
|
|
901
|
+
* amortize per-key transaction overhead.
|
|
902
|
+
*/
|
|
903
|
+
restoreToL2?: boolean;
|
|
904
|
+
/**
|
|
905
|
+
* Tuning for the optional background L2 warmer.
|
|
906
|
+
*
|
|
907
|
+
* The warmer is started explicitly via `startBackgroundWarmer()` and
|
|
908
|
+
* walks the in-memory document index, ensuring every doc has an
|
|
909
|
+
* up-to-date L2 cache record (using the same `tryLoadFromL2` path
|
|
910
|
+
* foreground reads use). It yields to the host runtime between
|
|
911
|
+
* batches so it does not starve other work.
|
|
912
|
+
*/
|
|
913
|
+
warmer?: DocumentCacheWarmerConfig;
|
|
914
|
+
}
|
|
915
|
+
/**
|
|
916
|
+
* Cooperative scheduler used by the L2 background warmer to yield
|
|
917
|
+
* between batches so it does not monopolize the event loop.
|
|
918
|
+
*
|
|
919
|
+
* The default implementation uses `setTimeout(0)` which works in both
|
|
920
|
+
* Node and browsers. Embedders can plug in custom schedulers (e.g. one
|
|
921
|
+
* that yields via `requestIdleCallback` in the browser, or that
|
|
922
|
+
* coalesces yields with their own task queue).
|
|
923
|
+
*/
|
|
924
|
+
export interface WarmerScheduler {
|
|
925
|
+
/**
|
|
926
|
+
* Yield control back to the host runtime. The warmer will resume
|
|
927
|
+
* processing once the returned promise resolves.
|
|
928
|
+
*/
|
|
929
|
+
yield(): Promise<void>;
|
|
930
|
+
}
|
|
931
|
+
/**
|
|
932
|
+
* Tuning options for the background L2 warmer.
|
|
933
|
+
*/
|
|
934
|
+
export interface DocumentCacheWarmerConfig {
|
|
935
|
+
/**
|
|
936
|
+
* Number of documents to process between scheduler yields. Smaller
|
|
937
|
+
* values yield more often (better responsiveness on the foreground
|
|
938
|
+
* thread, slightly higher per-doc overhead). Larger values run faster
|
|
939
|
+
* but block the event loop in larger bursts.
|
|
940
|
+
* Default: 50
|
|
941
|
+
*/
|
|
942
|
+
batchSize?: number;
|
|
943
|
+
/**
|
|
944
|
+
* Custom scheduler implementation. Defaults to a `setTimeout(0)`-based
|
|
945
|
+
* scheduler that works in any JavaScript runtime.
|
|
946
|
+
*/
|
|
947
|
+
scheduler?: WarmerScheduler;
|
|
948
|
+
}
|
|
949
|
+
/**
|
|
950
|
+
* Lifecycle phases for a background L2 warmer pass.
|
|
951
|
+
*
|
|
952
|
+
* - `warming` - the warmer is actively processing documents; `processed`
|
|
953
|
+
* will continue to grow until it reaches `total`.
|
|
954
|
+
* - `done` - the warmer reached the end of its document snapshot; the
|
|
955
|
+
* pass terminated successfully.
|
|
956
|
+
* - `cancelled`- the warmer observed an abort signal mid-pass and exited
|
|
957
|
+
* early. `processed` reflects how far it got; the
|
|
958
|
+
* remaining `total - processed` documents were not warmed.
|
|
959
|
+
*/
|
|
960
|
+
export type BackgroundWarmerPhase = "warming" | "done" | "cancelled";
|
|
961
|
+
/**
|
|
962
|
+
* Snapshot of a background L2 warmer pass, suitable for driving a
|
|
963
|
+
* progress UI.
|
|
964
|
+
*
|
|
965
|
+
* `total` is captured once at the start of the pass (a snapshot of
|
|
966
|
+
* `index.length`); concurrent doc creations during the pass do not
|
|
967
|
+
* grow `total` so the bar can advance monotonically toward 100%.
|
|
968
|
+
*
|
|
969
|
+
* `processed` includes both docs that were warmed (an L2 record was
|
|
970
|
+
* read or refreshed) and docs that were skipped because they were
|
|
971
|
+
* already hot in L1 - in both cases the warmer is "done" with that doc.
|
|
972
|
+
*/
|
|
973
|
+
export interface BackgroundWarmerProgress {
|
|
974
|
+
/** Number of docs the warmer has finished visiting in this pass. */
|
|
975
|
+
processed: number;
|
|
976
|
+
/** Total docs the warmer intends to visit in this pass. */
|
|
977
|
+
total: number;
|
|
978
|
+
/** Lifecycle phase. See {@link BackgroundWarmerPhase}. */
|
|
979
|
+
phase: BackgroundWarmerPhase;
|
|
980
|
+
}
|
|
981
|
+
/**
|
|
982
|
+
* Options accepted by {@link MindooDB.startBackgroundWarmer}.
|
|
983
|
+
*/
|
|
984
|
+
export interface StartBackgroundWarmerOptions {
|
|
985
|
+
/**
|
|
986
|
+
* Optional `AbortSignal` that the caller can use to cancel this
|
|
987
|
+
* warmer pass without affecting any other in-flight passes.
|
|
988
|
+
* Aborting via the signal has the same effect as calling
|
|
989
|
+
* {@link MindooDB.stopBackgroundWarmer}.
|
|
990
|
+
*
|
|
991
|
+
* Note: warmer single-flight semantics mean that if a warmer is
|
|
992
|
+
* already running when `startBackgroundWarmer` is called, the
|
|
993
|
+
* existing in-flight promise is returned and the new `signal` is
|
|
994
|
+
* NOT honored (since the existing pass owns its own internal
|
|
995
|
+
* cancellation lifecycle). Callers that need precise cancellation
|
|
996
|
+
* control should call {@link MindooDB.stopBackgroundWarmer} first.
|
|
997
|
+
*/
|
|
998
|
+
signal?: AbortSignal;
|
|
999
|
+
/**
|
|
1000
|
+
* Optional progress callback invoked by the warmer once per
|
|
1001
|
+
* scheduler-yield batch (i.e. roughly every
|
|
1002
|
+
* `DocumentCacheWarmerConfig.batchSize` documents) and once more
|
|
1003
|
+
* with `phase: "done"` or `phase: "cancelled"` when the pass
|
|
1004
|
+
* settles.
|
|
1005
|
+
*
|
|
1006
|
+
* Designed for driving a progress bar / "Warming…" UI affordance.
|
|
1007
|
+
* Per-doc invocation is intentionally avoided so the callback
|
|
1008
|
+
* doesn't add measurable overhead even on warmers that walk
|
|
1009
|
+
* 30,000+ documents.
|
|
1010
|
+
*
|
|
1011
|
+
* Errors thrown from this callback are caught and logged so a buggy
|
|
1012
|
+
* progress consumer cannot break the warmer.
|
|
1013
|
+
*/
|
|
1014
|
+
onProgress?: (progress: BackgroundWarmerProgress) => void;
|
|
709
1015
|
}
|
|
710
1016
|
/**
|
|
711
1017
|
* Configuration for automatic snapshot creation.
|
|
@@ -959,24 +1265,81 @@ export interface MindooDoc {
|
|
|
959
1265
|
*/
|
|
960
1266
|
streamAttachment(attachmentId: string, startOffset?: number): AsyncGenerator<Uint8Array, void, unknown>;
|
|
961
1267
|
}
|
|
1268
|
+
/** Plain JSON-compatible document payload materialized from a MindooDoc. */
|
|
962
1269
|
export interface MindooDocPayload {
|
|
963
1270
|
[key: string]: unknown;
|
|
964
1271
|
}
|
|
1272
|
+
/**
|
|
1273
|
+
* Single text splice applied to the string at a text patch path.
|
|
1274
|
+
*
|
|
1275
|
+
* `index` is a character offset in the current text value, `deleteCount`
|
|
1276
|
+
* removes characters from that offset, and `insert` adds replacement text.
|
|
1277
|
+
*/
|
|
965
1278
|
export interface MindooTextEdit {
|
|
966
1279
|
index: number;
|
|
967
1280
|
deleteCount: number;
|
|
968
1281
|
insert?: string;
|
|
969
1282
|
}
|
|
1283
|
+
/**
|
|
1284
|
+
* Ordered text edits for one string field in a MindooDoc.
|
|
1285
|
+
*
|
|
1286
|
+
* `path` addresses the target string inside the document payload. When
|
|
1287
|
+
* supplied, `baseHeads` identifies the Automerge heads the caller based the
|
|
1288
|
+
* edit on, allowing the backend to apply order-sensitive text changes in the
|
|
1289
|
+
* intended causal context.
|
|
1290
|
+
*/
|
|
970
1291
|
export interface MindooTextPatch {
|
|
971
1292
|
path: Array<string | number>;
|
|
972
1293
|
baseHeads?: string[];
|
|
973
1294
|
edits: MindooTextEdit[];
|
|
974
1295
|
}
|
|
1296
|
+
/** Result returned after applying a text patch and materializing the document. */
|
|
975
1297
|
export interface MindooTextPatchResult {
|
|
976
1298
|
doc: MindooDoc;
|
|
977
1299
|
heads: string[];
|
|
978
1300
|
data: MindooDocPayload;
|
|
979
1301
|
}
|
|
1302
|
+
/** Sets a value at `path`, creating or replacing that payload field. */
|
|
1303
|
+
export interface MindooJsonSetPatch {
|
|
1304
|
+
path: Array<string | number>;
|
|
1305
|
+
value: unknown;
|
|
1306
|
+
}
|
|
1307
|
+
/** Removes the value at `path` from the payload object or list. */
|
|
1308
|
+
export interface MindooJsonUnsetPatch {
|
|
1309
|
+
path: Array<string | number>;
|
|
1310
|
+
}
|
|
1311
|
+
/** Inserts one or more values into the list located at `path`. */
|
|
1312
|
+
export interface MindooJsonListInsertPatch {
|
|
1313
|
+
path: Array<string | number>;
|
|
1314
|
+
index: number;
|
|
1315
|
+
values: unknown[];
|
|
1316
|
+
}
|
|
1317
|
+
/** Deletes one or more values from the list located at `path`. */
|
|
1318
|
+
export interface MindooJsonListDeletePatch {
|
|
1319
|
+
path: Array<string | number>;
|
|
1320
|
+
index: number;
|
|
1321
|
+
deleteCount: number;
|
|
1322
|
+
}
|
|
1323
|
+
/**
|
|
1324
|
+
* Granular JSON mutation batch for a MindooDoc payload.
|
|
1325
|
+
*
|
|
1326
|
+
* Operations are applied in patch order by operation group. `baseHeads` has the
|
|
1327
|
+
* same role as in text patches: it records the document heads the caller saw
|
|
1328
|
+
* before constructing operations whose order matters, such as list inserts.
|
|
1329
|
+
*/
|
|
1330
|
+
export interface MindooJsonPatch {
|
|
1331
|
+
baseHeads?: string[];
|
|
1332
|
+
set?: MindooJsonSetPatch[];
|
|
1333
|
+
unset?: MindooJsonUnsetPatch[];
|
|
1334
|
+
listInsert?: MindooJsonListInsertPatch[];
|
|
1335
|
+
listDelete?: MindooJsonListDeletePatch[];
|
|
1336
|
+
}
|
|
1337
|
+
/** Result returned after applying a JSON patch and materializing the document. */
|
|
1338
|
+
export interface MindooJsonPatchResult {
|
|
1339
|
+
doc: MindooDoc;
|
|
1340
|
+
heads: string[];
|
|
1341
|
+
data: MindooDocPayload;
|
|
1342
|
+
}
|
|
980
1343
|
export interface DirectoryUserDetails {
|
|
981
1344
|
[key: string]: string;
|
|
982
1345
|
}
|
|
@@ -1281,6 +1644,13 @@ export interface OpenDBOptions extends OpenStoreOptions {
|
|
|
1281
1644
|
* This is used for the directory database to prevent recursion and ensure security.
|
|
1282
1645
|
*/
|
|
1283
1646
|
adminOnlyDb?: boolean;
|
|
1647
|
+
/**
|
|
1648
|
+
* Optional read-only historical cutoff for opening the database.
|
|
1649
|
+
*
|
|
1650
|
+
* When set, entries with createdAt >= timeTravelDate are ignored. The
|
|
1651
|
+
* normalized value maps to store-level creationDateUntil semantics.
|
|
1652
|
+
*/
|
|
1653
|
+
timeTravelDate?: number | Date | string;
|
|
1284
1654
|
/**
|
|
1285
1655
|
* Configuration for attachment handling (chunk size, etc.)
|
|
1286
1656
|
* If not provided, defaults are used.
|
|
@@ -1341,7 +1711,7 @@ export interface PerformanceCallback {
|
|
|
1341
1711
|
* Called for bounded history/time-travel workflows.
|
|
1342
1712
|
*/
|
|
1343
1713
|
onHistoryOperation?: (metrics: {
|
|
1344
|
-
operation: 'getDocumentAtTimestamp' | 'getDocumentHistoryPage' | 'analyzeDocumentDagAtTimestamp' | 'materializeDocumentBranchAtEntry' | 'materializeDocumentBranchAtTimestamp' | 'describeDocumentDagEntry';
|
|
1714
|
+
operation: 'getDocumentAtTimestamp' | 'getDocumentHistoryPage' | 'analyzeDocumentDagAtTimestamp' | 'materializeDocumentBranchAtEntry' | 'materializeDocumentBranchAtTimestamp' | 'describeDocumentDagEntry' | 'analyzeDocumentConflicts' | 'getDocumentConflictReport' | 'getDocumentConflictBaseValues';
|
|
1345
1715
|
docId: string;
|
|
1346
1716
|
time: number;
|
|
1347
1717
|
scannedEntries: number;
|
|
@@ -1472,6 +1842,177 @@ export interface DocumentDagEntryDetails {
|
|
|
1472
1842
|
automergeHash: string | null;
|
|
1473
1843
|
decodedChange: DocumentDagDecodedChangeSummary | null;
|
|
1474
1844
|
}
|
|
1845
|
+
/**
|
|
1846
|
+
* Conflict analysis mode controls how much history the analyzer traverses.
|
|
1847
|
+
*/
|
|
1848
|
+
export type DocumentConflictAnalysisMode = "quick" | "full";
|
|
1849
|
+
/**
|
|
1850
|
+
* Conflict detail level controls whether conflicting values are summarized.
|
|
1851
|
+
*/
|
|
1852
|
+
export type DocumentConflictDetailLevel = "paths-only" | "values";
|
|
1853
|
+
/**
|
|
1854
|
+
* JSON-safe path segment returned by conflict analysis.
|
|
1855
|
+
*/
|
|
1856
|
+
export type DocumentConflictPathSegment = string | number;
|
|
1857
|
+
/**
|
|
1858
|
+
* JSON-safe value summary for one conflicting value.
|
|
1859
|
+
*
|
|
1860
|
+
* `value` is included only when it can be represented safely without exposing
|
|
1861
|
+
* CRDT-specific objects. `preview` is always intended for compact UI display.
|
|
1862
|
+
*/
|
|
1863
|
+
export interface DocumentConflictValueSummary {
|
|
1864
|
+
conflictId: string;
|
|
1865
|
+
preview: string | null;
|
|
1866
|
+
value?: unknown;
|
|
1867
|
+
isWinner: boolean;
|
|
1868
|
+
}
|
|
1869
|
+
/**
|
|
1870
|
+
* One conflicted document path detected during analysis.
|
|
1871
|
+
*/
|
|
1872
|
+
export interface DocumentConflictPath {
|
|
1873
|
+
path: DocumentConflictPathSegment[];
|
|
1874
|
+
pathString: string;
|
|
1875
|
+
values?: DocumentConflictValueSummary[];
|
|
1876
|
+
}
|
|
1877
|
+
/**
|
|
1878
|
+
* Describes where in the document DAG a conflict observation was made.
|
|
1879
|
+
*/
|
|
1880
|
+
export interface DocumentConflictLocation {
|
|
1881
|
+
kind: "entry-after" | "active-heads" | "merge-deps";
|
|
1882
|
+
entryId?: string;
|
|
1883
|
+
createdAt?: number;
|
|
1884
|
+
receiptOrder?: number;
|
|
1885
|
+
createdByPublicKey?: string;
|
|
1886
|
+
headEntryIds: string[];
|
|
1887
|
+
automergeHeads: string[];
|
|
1888
|
+
}
|
|
1889
|
+
/**
|
|
1890
|
+
* Conflict observation or resolution event for one document.
|
|
1891
|
+
*/
|
|
1892
|
+
export interface DocumentConflictSummary {
|
|
1893
|
+
docId: string;
|
|
1894
|
+
location: DocumentConflictLocation;
|
|
1895
|
+
paths: DocumentConflictPath[];
|
|
1896
|
+
}
|
|
1897
|
+
/**
|
|
1898
|
+
* Durable cursor for incremental conflict scans.
|
|
1899
|
+
*
|
|
1900
|
+
* `changeSeqAsOf` is used for cheap document-level pre-filtering through the
|
|
1901
|
+
* document index. `storeReceiptOrderAsOf` is used for per-event filtering so
|
|
1902
|
+
* late-arriving sync entries are surfaced even if their author timestamp is old.
|
|
1903
|
+
*/
|
|
1904
|
+
export interface ConflictScanCheckpoint {
|
|
1905
|
+
changeSeqAsOf: number;
|
|
1906
|
+
storeReceiptOrderAsOf?: number;
|
|
1907
|
+
takenAt: number;
|
|
1908
|
+
}
|
|
1909
|
+
/**
|
|
1910
|
+
* Options accepted by conflict analysis APIs.
|
|
1911
|
+
*/
|
|
1912
|
+
export interface DocumentConflictAnalysisOptions {
|
|
1913
|
+
mode?: DocumentConflictAnalysisMode;
|
|
1914
|
+
detail?: DocumentConflictDetailLevel;
|
|
1915
|
+
pageSize?: number;
|
|
1916
|
+
yieldEveryMs?: number;
|
|
1917
|
+
maxConflictsPerDoc?: number;
|
|
1918
|
+
since?: ConflictScanCheckpoint;
|
|
1919
|
+
includeUnresolvedFromBefore?: boolean;
|
|
1920
|
+
signal?: AbortSignal;
|
|
1921
|
+
}
|
|
1922
|
+
/**
|
|
1923
|
+
* Options accepted by the convenience report API.
|
|
1924
|
+
*/
|
|
1925
|
+
export interface DocumentConflictReportOptions extends Omit<DocumentConflictAnalysisOptions, "mode" | "maxConflictsPerDoc"> {
|
|
1926
|
+
}
|
|
1927
|
+
/**
|
|
1928
|
+
* Streaming event emitted by `analyzeDocumentConflicts()`.
|
|
1929
|
+
*/
|
|
1930
|
+
export type DocumentConflictAnalysisEvent = {
|
|
1931
|
+
type: "progress";
|
|
1932
|
+
scannedDocs: number;
|
|
1933
|
+
totalDocs: number;
|
|
1934
|
+
docId?: string;
|
|
1935
|
+
scannedEntries?: number;
|
|
1936
|
+
message: string;
|
|
1937
|
+
} | {
|
|
1938
|
+
type: "docStart";
|
|
1939
|
+
docId: string;
|
|
1940
|
+
} | {
|
|
1941
|
+
type: "conflictDetected";
|
|
1942
|
+
conflict: DocumentConflictSummary;
|
|
1943
|
+
quick: boolean;
|
|
1944
|
+
} | {
|
|
1945
|
+
type: "conflictResolved";
|
|
1946
|
+
docId: string;
|
|
1947
|
+
entryId: string;
|
|
1948
|
+
createdAt: number;
|
|
1949
|
+
receiptOrder?: number;
|
|
1950
|
+
createdByPublicKey: string;
|
|
1951
|
+
path: DocumentConflictPath;
|
|
1952
|
+
automergeHash: string | null;
|
|
1953
|
+
} | {
|
|
1954
|
+
type: "docDone";
|
|
1955
|
+
docId: string;
|
|
1956
|
+
hadConflicts: boolean;
|
|
1957
|
+
conflictsFound: number;
|
|
1958
|
+
entriesScanned: number;
|
|
1959
|
+
} | {
|
|
1960
|
+
type: "error";
|
|
1961
|
+
docId?: string;
|
|
1962
|
+
entryId?: string;
|
|
1963
|
+
error: unknown;
|
|
1964
|
+
} | {
|
|
1965
|
+
type: "scanCheckpoint";
|
|
1966
|
+
checkpoint: ConflictScanCheckpoint;
|
|
1967
|
+
};
|
|
1968
|
+
/**
|
|
1969
|
+
* Full conflict report for one document.
|
|
1970
|
+
*/
|
|
1971
|
+
export interface DocumentConflictReport {
|
|
1972
|
+
docId: string;
|
|
1973
|
+
hadConflicts: boolean;
|
|
1974
|
+
conflictsFound: number;
|
|
1975
|
+
conflicts: DocumentConflictSummary[];
|
|
1976
|
+
resolutions: Array<Extract<DocumentConflictAnalysisEvent, {
|
|
1977
|
+
type: "conflictResolved";
|
|
1978
|
+
}>>;
|
|
1979
|
+
entriesScanned: number;
|
|
1980
|
+
errors: Array<Extract<DocumentConflictAnalysisEvent, {
|
|
1981
|
+
type: "error";
|
|
1982
|
+
}>>;
|
|
1983
|
+
scanCheckpoint: ConflictScanCheckpoint | null;
|
|
1984
|
+
}
|
|
1985
|
+
/**
|
|
1986
|
+
* Request to look up the value at a conflicted path as it stood at the merge
|
|
1987
|
+
* base of the contributing branches (the "old" value before the conflict).
|
|
1988
|
+
*/
|
|
1989
|
+
export interface DocumentConflictBaseValueQuery {
|
|
1990
|
+
/** Conflict location as returned by `getDocumentConflictReport`. */
|
|
1991
|
+
location: DocumentConflictLocation;
|
|
1992
|
+
/** Structured path segments (matches `DocumentConflictPath.path`). */
|
|
1993
|
+
path: DocumentConflictPathSegment[];
|
|
1994
|
+
/** Stable string key (matches `DocumentConflictPath.pathString`). */
|
|
1995
|
+
pathString: string;
|
|
1996
|
+
}
|
|
1997
|
+
/**
|
|
1998
|
+
* Result for one base-value lookup.
|
|
1999
|
+
*
|
|
2000
|
+
* - `available`: a previous value existed at the merge base; `preview` and
|
|
2001
|
+
* `value` are populated.
|
|
2002
|
+
* - `no-prior-value`: a merge base was found but the path did not exist there
|
|
2003
|
+
* (e.g. both branches independently created the field).
|
|
2004
|
+
* - `no-base`: no shared ancestor could be determined for the contributing
|
|
2005
|
+
* heads (e.g. the conflict has only one head, or the parent set is empty).
|
|
2006
|
+
* - `missing-entry`: the conflict's `entryId` is not (or no longer) in the
|
|
2007
|
+
* local store; the base value cannot be resolved.
|
|
2008
|
+
*/
|
|
2009
|
+
export interface DocumentConflictBaseValue {
|
|
2010
|
+
pathString: string;
|
|
2011
|
+
baseEntryId: string | null;
|
|
2012
|
+
status: "available" | "no-prior-value" | "no-base" | "missing-entry";
|
|
2013
|
+
preview: string | null;
|
|
2014
|
+
value?: unknown;
|
|
2015
|
+
}
|
|
1475
2016
|
/**
|
|
1476
2017
|
* Result of reconstructing one branch-local document state for a selected DAG head.
|
|
1477
2018
|
*/
|
|
@@ -1568,6 +2109,18 @@ export interface MindooDB {
|
|
|
1568
2109
|
* @return True if admin-only mode is enabled
|
|
1569
2110
|
*/
|
|
1570
2111
|
isAdminOnlyDb(): boolean;
|
|
2112
|
+
/**
|
|
2113
|
+
* True when this database was opened with a timeTravelDate cutoff.
|
|
2114
|
+
*/
|
|
2115
|
+
isTimeTravelMode(): boolean;
|
|
2116
|
+
/**
|
|
2117
|
+
* True when mutating APIs are disabled for this database instance.
|
|
2118
|
+
*/
|
|
2119
|
+
isReadOnly(): boolean;
|
|
2120
|
+
/**
|
|
2121
|
+
* Normalized time travel cutoff in epoch milliseconds, or null for live mode.
|
|
2122
|
+
*/
|
|
2123
|
+
getTimeTravelDate(): number | null;
|
|
1571
2124
|
/**
|
|
1572
2125
|
* Get the content-addressed store that is used to store document changes for this database.
|
|
1573
2126
|
*
|
|
@@ -1580,6 +2133,9 @@ export interface MindooDB {
|
|
|
1580
2133
|
* @return The content-addressed store for attachments
|
|
1581
2134
|
*/
|
|
1582
2135
|
getAttachmentStore(): ContentAddressedStore;
|
|
2136
|
+
reclaimIncompleteAttachmentUploads?(options?: {
|
|
2137
|
+
minAgeMs?: number;
|
|
2138
|
+
}): Promise<IncompleteAttachmentUploadReclaimResult>;
|
|
1583
2139
|
/**
|
|
1584
2140
|
* Create a new document.
|
|
1585
2141
|
*
|
|
@@ -1696,6 +2252,36 @@ export interface MindooDB {
|
|
|
1696
2252
|
* Decode and summarize one DAG entry for hover/tooling use cases.
|
|
1697
2253
|
*/
|
|
1698
2254
|
describeDocumentDagEntry(docId: string, entryId: string): Promise<DocumentDagEntryDetails | null>;
|
|
2255
|
+
/**
|
|
2256
|
+
* Stream conflict analysis events for one or more documents.
|
|
2257
|
+
*
|
|
2258
|
+
* The API intentionally returns MindooDB DTOs only. It does not expose
|
|
2259
|
+
* Automerge documents, patches, or operation objects so the storage backend
|
|
2260
|
+
* can evolve without changing callers.
|
|
2261
|
+
*/
|
|
2262
|
+
analyzeDocumentConflicts(docIds: string[], options?: DocumentConflictAnalysisOptions): AsyncGenerator<DocumentConflictAnalysisEvent, void, unknown>;
|
|
2263
|
+
/**
|
|
2264
|
+
* Build a full conflict report for one document by consuming the streaming
|
|
2265
|
+
* analyzer internally.
|
|
2266
|
+
*/
|
|
2267
|
+
getDocumentConflictReport(docId: string, options?: DocumentConflictReportOptions): Promise<DocumentConflictReport>;
|
|
2268
|
+
/**
|
|
2269
|
+
* Resolve the value each conflicted path had at its merge base (the most
|
|
2270
|
+
* recent common ancestor of the branches that contributed to the conflict).
|
|
2271
|
+
*
|
|
2272
|
+
* Each query independently maps to a base value so the caller can request
|
|
2273
|
+
* lookups lazily — for example, only for the paths it currently displays.
|
|
2274
|
+
* Queries that share a merge base are coalesced internally so the
|
|
2275
|
+
* underlying document state is materialized at most once per base entry.
|
|
2276
|
+
*/
|
|
2277
|
+
getDocumentConflictBaseValues(docId: string, queries: DocumentConflictBaseValueQuery[]): Promise<DocumentConflictBaseValue[]>;
|
|
2278
|
+
/**
|
|
2279
|
+
* Return an incremental conflict-scan checkpoint for the current local view.
|
|
2280
|
+
*
|
|
2281
|
+
* Callers can persist this value after presenting scan results and pass it
|
|
2282
|
+
* back as `DocumentConflictAnalysisOptions.since` on the next run.
|
|
2283
|
+
*/
|
|
2284
|
+
getConflictScanCheckpoint(): Promise<ConflictScanCheckpoint>;
|
|
1699
2285
|
/**
|
|
1700
2286
|
* Get all non-deleted document IDs in this database.
|
|
1701
2287
|
*
|
|
@@ -1789,6 +2375,15 @@ export interface MindooDB {
|
|
|
1789
2375
|
* overwriting concurrent edits that arrived meanwhile.
|
|
1790
2376
|
*/
|
|
1791
2377
|
applyTextPatch(doc: MindooDoc, patch: MindooTextPatch): Promise<MindooTextPatchResult>;
|
|
2378
|
+
/**
|
|
2379
|
+
* Apply granular JSON edits at document paths.
|
|
2380
|
+
*
|
|
2381
|
+
* If `baseHeads` is provided, edits are applied at that historical Automerge
|
|
2382
|
+
* version using `changeAt`, then merged into the current document. This lets
|
|
2383
|
+
* apps flush buffered object/list operations based on a stale local copy
|
|
2384
|
+
* without replacing concurrent changes that arrived meanwhile.
|
|
2385
|
+
*/
|
|
2386
|
+
applyJsonPatch(doc: MindooDoc, patch: MindooJsonPatch): Promise<MindooJsonPatchResult>;
|
|
1792
2387
|
/**
|
|
1793
2388
|
* Change a document using a specific signing key.
|
|
1794
2389
|
* This is like changeDoc but allows signing with a different key than the current user's.
|
|
@@ -1850,9 +2445,87 @@ export interface MindooDB {
|
|
|
1850
2445
|
* then processes them to update the cached database documents and index.
|
|
1851
2446
|
* After processing, the new change hashes are appended to the stored list.
|
|
1852
2447
|
*
|
|
1853
|
-
*
|
|
2448
|
+
* Sync deliberately does NOT trigger the L2 background warmer. Callers
|
|
2449
|
+
* that want to warm the L2 cache after a sync (e.g. the Haven sync
|
|
2450
|
+
* page once a sync settles) should call {@link startBackgroundWarmer}
|
|
2451
|
+
* explicitly. This keeps casual `syncStoreChanges()` calls cheap and
|
|
2452
|
+
* leaves warmer scheduling to the caller, which knows whether the
|
|
2453
|
+
* cost of a full L2 walk is worth paying for the current workload.
|
|
2454
|
+
*
|
|
2455
|
+
* @return A promise that resolves when the sync is complete.
|
|
1854
2456
|
*/
|
|
1855
2457
|
syncStoreChanges(): Promise<void>;
|
|
2458
|
+
/**
|
|
2459
|
+
* Reconcile local document visibility with the current tenant KeyBag.
|
|
2460
|
+
*
|
|
2461
|
+
* Reveals documents whose decryption keys are now available, hides
|
|
2462
|
+
* documents whose keys have been removed, and purges any plaintext
|
|
2463
|
+
* caches for inaccessible documents. The method only touches in-memory
|
|
2464
|
+
* and L2 caches owned by this database instance - it does not write
|
|
2465
|
+
* synthetic store entries and is safe to call repeatedly.
|
|
2466
|
+
*
|
|
2467
|
+
* Optional so alternative database implementations (e.g. read-only
|
|
2468
|
+
* views, time-travel snapshots) can omit it.
|
|
2469
|
+
*/
|
|
2470
|
+
reconcileKeyVisibility?(): Promise<void>;
|
|
2471
|
+
/**
|
|
2472
|
+
* Start the L2 background warmer.
|
|
2473
|
+
*
|
|
2474
|
+
* Walks the in-memory document index and ensures every document has
|
|
2475
|
+
* an up-to-date L2 cache record (using the same internal load-from-L2
|
|
2476
|
+
* code path foreground reads use). Runs in batches with cooperative
|
|
2477
|
+
* yields so foreground operations are not starved.
|
|
2478
|
+
*
|
|
2479
|
+
* Intended to be called explicitly by long-lived sessions that just
|
|
2480
|
+
* finished a sync (e.g. the Haven sync page after pulling/pushing
|
|
2481
|
+
* completes) so subsequent reads - especially virtual view rebuilds
|
|
2482
|
+
* - hit the fast L2 path. Casual database opens should NOT call this;
|
|
2483
|
+
* pay the warmer cost only when the workload is about to benefit
|
|
2484
|
+
* from a fully warm L2.
|
|
2485
|
+
*
|
|
2486
|
+
* Single-flight: a second call while the warmer is already running
|
|
2487
|
+
* returns the same in-flight promise rather than starting a second
|
|
2488
|
+
* pass. The returned promise resolves when the warmer has finished
|
|
2489
|
+
* (either by visiting every document or by being cancelled via
|
|
2490
|
+
* {@link stopBackgroundWarmer} or via the optional `signal`).
|
|
2491
|
+
*
|
|
2492
|
+
* @param options See {@link StartBackgroundWarmerOptions}: optional
|
|
2493
|
+
* `signal` for per-call cancellation and `onProgress` for driving
|
|
2494
|
+
* a progress UI.
|
|
2495
|
+
*/
|
|
2496
|
+
startBackgroundWarmer?(options?: StartBackgroundWarmerOptions): Promise<void>;
|
|
2497
|
+
/**
|
|
2498
|
+
* Cancel the running background warmer (if any). Returns a promise
|
|
2499
|
+
* that resolves once the in-flight warmer pass has observed the
|
|
2500
|
+
* cancellation and returned (so callers can `await` clean shutdown).
|
|
2501
|
+
* Safe to call when no warmer is running - resolves immediately in
|
|
2502
|
+
* that case.
|
|
2503
|
+
*
|
|
2504
|
+
* Useful before initiating destructive operations (key rotation, data
|
|
2505
|
+
* wipe, etc.) so the warmer cannot race against the mutation, and at
|
|
2506
|
+
* the end of tests to ensure no background work outlives the test.
|
|
2507
|
+
*/
|
|
2508
|
+
stopBackgroundWarmer?(): Promise<void>;
|
|
2509
|
+
/**
|
|
2510
|
+
* Returns `true` while the L2 background warmer is actively
|
|
2511
|
+
* processing documents. Useful for "Warming…" UI indicators and
|
|
2512
|
+
* tests that need to coordinate with warmer progress.
|
|
2513
|
+
*/
|
|
2514
|
+
isWarmerRunning?(): boolean;
|
|
2515
|
+
/**
|
|
2516
|
+
* Snapshot of the current (or most recent) background warmer pass's
|
|
2517
|
+
* progress, or `null` if no warmer has ever run on this database
|
|
2518
|
+
* instance. Designed for UIs that mount AFTER the warmer has already
|
|
2519
|
+
* started (e.g. the user navigates back to the Sync page mid-warm)
|
|
2520
|
+
* and need to "catch up" on state without missing onProgress events.
|
|
2521
|
+
*
|
|
2522
|
+
* After a warmer settles, the returned snapshot persists with its
|
|
2523
|
+
* final `phase` (`"done"` or `"cancelled"`) so the UI can decide
|
|
2524
|
+
* whether to keep showing a "Optimized" message or fade away. The
|
|
2525
|
+
* snapshot is replaced on the next {@link startBackgroundWarmer}
|
|
2526
|
+
* call.
|
|
2527
|
+
*/
|
|
2528
|
+
getBackgroundWarmerProgress?(): BackgroundWarmerProgress | null;
|
|
1856
2529
|
/**
|
|
1857
2530
|
* Pull changes from a remote content-addressed store or another MindooDB instance.
|
|
1858
2531
|
*
|