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
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 */
|
|
@@ -170,9 +241,29 @@ export interface ApproveJoinRequestOptions {
|
|
|
170
241
|
serverUrl?: string;
|
|
171
242
|
/** Optional admin username to include in the response so the joining user can display it */
|
|
172
243
|
adminUsername?: string;
|
|
244
|
+
/**
|
|
245
|
+
* Optional document key ids to share with the joining user.
|
|
246
|
+
*
|
|
247
|
+
* `$publicinfos` is always included because it is required for directory
|
|
248
|
+
* access. When this option is omitted, the response includes the historical
|
|
249
|
+
* default set: `$publicinfos` and `default`.
|
|
250
|
+
*/
|
|
251
|
+
sharedDocKeyIds?: string[];
|
|
173
252
|
/** If "uri", approveJoinRequest returns a mdb://join-response/... URI string instead of an object */
|
|
174
253
|
format?: "object" | "uri";
|
|
175
254
|
}
|
|
255
|
+
export interface JoinResponseEncryptedDocKeyVersion {
|
|
256
|
+
/** Original KeyBag creation timestamp for this key version, used for rotation ordering. */
|
|
257
|
+
createdAt?: number;
|
|
258
|
+
/** Symmetric document key version encrypted with the shared password. */
|
|
259
|
+
encryptedKey: EncryptedPrivateKey;
|
|
260
|
+
}
|
|
261
|
+
export interface JoinResponseEncryptedDocKey {
|
|
262
|
+
/** Logical document key id within the tenant, e.g. "$publicinfos", "default", or a named key. */
|
|
263
|
+
keyId: string;
|
|
264
|
+
/** Encrypted key versions, sorted newest first by createdAt when timestamps are available. */
|
|
265
|
+
versions: JoinResponseEncryptedDocKeyVersion[];
|
|
266
|
+
}
|
|
176
267
|
/**
|
|
177
268
|
* A join response is created by the admin after approving a join request.
|
|
178
269
|
* It contains encrypted symmetric keys and tenant metadata needed to join.
|
|
@@ -181,8 +272,8 @@ export interface ApproveJoinRequestOptions {
|
|
|
181
272
|
* The encrypted keys can only be unlocked with the sharePassword communicated separately.
|
|
182
273
|
*/
|
|
183
274
|
export interface JoinResponse {
|
|
184
|
-
/** Protocol version
|
|
185
|
-
v:
|
|
275
|
+
/** Protocol version. v2 carries versioned document-key bundles. */
|
|
276
|
+
v: 2;
|
|
186
277
|
/** Tenant identifier */
|
|
187
278
|
tenantId: string;
|
|
188
279
|
/** Admin's public signing key (Ed25519, PEM) — needed to open the tenant */
|
|
@@ -193,10 +284,8 @@ export interface JoinResponse {
|
|
|
193
284
|
serverUrl?: string;
|
|
194
285
|
/** Optional admin username for display purposes */
|
|
195
286
|
adminUsername?: string;
|
|
196
|
-
/**
|
|
197
|
-
|
|
198
|
-
/** $publicinfos symmetric key, encrypted with the sharePassword */
|
|
199
|
-
encryptedPublicInfosKey: EncryptedPrivateKey;
|
|
287
|
+
/** Selected tenant document keys, encrypted with the sharePassword. */
|
|
288
|
+
encryptedDocKeys: JoinResponseEncryptedDocKey[];
|
|
200
289
|
}
|
|
201
290
|
/**
|
|
202
291
|
* Options for joining a tenant with a join response.
|
|
@@ -204,13 +293,49 @@ export interface JoinResponse {
|
|
|
204
293
|
export interface JoinTenantOptions {
|
|
205
294
|
/** The user's locally-generated private identity (keys never leave this device) */
|
|
206
295
|
user: PrivateUserId;
|
|
207
|
-
/**
|
|
296
|
+
/**
|
|
297
|
+
* The password for the user's private keys.
|
|
298
|
+
*
|
|
299
|
+
* Required when neither {@link existingKeyBag} nor
|
|
300
|
+
* {@link preDecryptedUserKeys} is supplied. When `existingKeyBag` is
|
|
301
|
+
* provided the password is *not* used to construct a new KeyBag; when
|
|
302
|
+
* `preDecryptedUserKeys.signingKey` and `preDecryptedUserKeys.encryptionKey`
|
|
303
|
+
* are both supplied the password is *not* used to decrypt the user's
|
|
304
|
+
* private keys before opening the tenant. In those live-bag cases
|
|
305
|
+
* callers may pass an empty string.
|
|
306
|
+
*/
|
|
208
307
|
password: string;
|
|
209
308
|
/** The shared password used to decrypt the keys in the join response */
|
|
210
309
|
sharePassword: string;
|
|
310
|
+
/**
|
|
311
|
+
* Optional pre-existing {@link KeyBag} to extend with the joined tenant's
|
|
312
|
+
* keys. When supplied, `joinTenant` will mutate this bag in place (adding
|
|
313
|
+
* the joined tenant's shared document keys) and return
|
|
314
|
+
* the same instance in {@link JoinTenantResult.keyBag}. The caller is
|
|
315
|
+
* then responsible for persisting the bag once.
|
|
316
|
+
*
|
|
317
|
+
* When omitted, `joinTenant` constructs a fresh bag using the legacy
|
|
318
|
+
* password-based KeyBag wrapping derivation (existing behavior).
|
|
319
|
+
*/
|
|
320
|
+
existingKeyBag?: KeyBag;
|
|
321
|
+
/**
|
|
322
|
+
* Optional pre-decrypted user keys forwarded to the underlying
|
|
323
|
+
* {@link MindooTenantFactory.openTenant} call. When the joining user's
|
|
324
|
+
* signing/encryption {@link CryptoKey}s are already available
|
|
325
|
+
* (e.g. because they were unlocked once at app startup via a live
|
|
326
|
+
* Haven session) supplying them here avoids the password-based
|
|
327
|
+
* decryption + import that `openTenant` would otherwise perform on
|
|
328
|
+
* the encrypted private keys carried on the user identity.
|
|
329
|
+
*/
|
|
330
|
+
preDecryptedUserKeys?: PreDecryptedUserKeys;
|
|
211
331
|
}
|
|
212
332
|
/**
|
|
213
333
|
* Result of joining a tenant via joinTenant().
|
|
334
|
+
*
|
|
335
|
+
* When the caller provided {@link JoinTenantOptions.existingKeyBag}, the
|
|
336
|
+
* returned `keyBag` is the same instance (mutated in place with the joined
|
|
337
|
+
* tenant's keys). Callers should not double-save in that case - persist the
|
|
338
|
+
* bag once after `joinTenant` returns.
|
|
214
339
|
*/
|
|
215
340
|
export interface JoinTenantResult {
|
|
216
341
|
/** The opened tenant, ready to use */
|
|
@@ -450,6 +575,32 @@ export interface MindooTenant {
|
|
|
450
575
|
* @return The database instance
|
|
451
576
|
*/
|
|
452
577
|
openDB(id: string, options?: OpenDBOptions): Promise<MindooDB>;
|
|
578
|
+
/**
|
|
579
|
+
* Replay any pending local KeyBag mutations and refresh open live
|
|
580
|
+
* databases so document visibility matches the current key set.
|
|
581
|
+
*
|
|
582
|
+
* Implementations must be idempotent and safe to call concurrently.
|
|
583
|
+
* The optional shape allows alternative tenant implementations (e.g.
|
|
584
|
+
* server-side, test doubles) to omit visibility reconciliation when it
|
|
585
|
+
* is not applicable.
|
|
586
|
+
*/
|
|
587
|
+
reconcileKeyBagChanges?(): Promise<void>;
|
|
588
|
+
/**
|
|
589
|
+
* Return whether the current KeyBag can resolve the given document
|
|
590
|
+
* encryption key id. Implementations must not throw when the key is
|
|
591
|
+
* missing; they should return `false` instead so callers can use the
|
|
592
|
+
* result as a guard before attempting decryption.
|
|
593
|
+
*/
|
|
594
|
+
hasDecryptionKey?(decryptionKeyId: string): Promise<boolean>;
|
|
595
|
+
/**
|
|
596
|
+
* Return a stable, opaque fingerprint of the doc keys this tenant
|
|
597
|
+
* currently has access to. The fingerprint must change whenever the
|
|
598
|
+
* set of available doc keys changes for the tenant, and must be safe
|
|
599
|
+
* to persist (no raw key material). Used by databases to skip
|
|
600
|
+
* visibility reconciliation on warm starts when the KeyBag composition
|
|
601
|
+
* has not changed since the last cache flush.
|
|
602
|
+
*/
|
|
603
|
+
getDocKeyFingerprint?(): Promise<string>;
|
|
453
604
|
/**
|
|
454
605
|
* Creates a MindooDocSigner instance for signing and verifying document items.
|
|
455
606
|
* The signer uses the tenant's cryptographic infrastructure for key management.
|
|
@@ -470,7 +621,7 @@ export interface MindooTenant {
|
|
|
470
621
|
* This orchestrates:
|
|
471
622
|
* 1. Parsing the join request (object or mdb:// URI string)
|
|
472
623
|
* 2. Registering the user in the tenant directory
|
|
473
|
-
* 3. Exporting
|
|
624
|
+
* 3. Exporting selected document keys, encrypted with the sharePassword
|
|
474
625
|
* 4. Packaging everything into a JoinResponse
|
|
475
626
|
*
|
|
476
627
|
* @param joinRequest A JoinRequest object or a mdb://join-request/... URI string
|
|
@@ -512,7 +663,7 @@ export { StoreKind } from "./appendonlystores/types";
|
|
|
512
663
|
* - doc_* entries are for Automerge document operations
|
|
513
664
|
* - attachment_* entries are for file attachment storage
|
|
514
665
|
*/
|
|
515
|
-
export type StoreEntryType = "doc_create" | "doc_change" | "doc_snapshot" | "doc_delete" | "doc_undelete" | "attachment_chunk";
|
|
666
|
+
export type StoreEntryType = "doc_create" | "doc_change" | "doc_snapshot" | "doc_delete" | "doc_undelete" | "pending_attachment_upload" | "attachment_chunk";
|
|
516
667
|
/**
|
|
517
668
|
* Metadata for entries stored in the ContentAddressedStore.
|
|
518
669
|
* This contains all information except the actual encrypted payload,
|
|
@@ -580,6 +731,21 @@ export interface StoreEntryMetadata {
|
|
|
580
731
|
* must only return cursors built from entries that have a concrete value.
|
|
581
732
|
*/
|
|
582
733
|
receiptOrder?: number;
|
|
734
|
+
/**
|
|
735
|
+
* Attachment id associated with attachment chunks or pending upload ledgers.
|
|
736
|
+
* For historical safety, cleanup only acts on pending upload ledgers that
|
|
737
|
+
* prove an attachment never reached a committed document revision.
|
|
738
|
+
*/
|
|
739
|
+
attachmentId?: string;
|
|
740
|
+
/**
|
|
741
|
+
* Attachment ids committed by this document entry. Used by local recovery to
|
|
742
|
+
* distinguish never-committed uploads from attachments required by history.
|
|
743
|
+
*/
|
|
744
|
+
attachmentIds?: string[];
|
|
745
|
+
/**
|
|
746
|
+
* Start timestamp for `pending_attachment_upload` recovery ledgers.
|
|
747
|
+
*/
|
|
748
|
+
uploadStartedAt?: number;
|
|
583
749
|
/**
|
|
584
750
|
* The public signing key of the user who created this entry (Ed25519, PEM format).
|
|
585
751
|
* Used for signature verification and audit trails.
|
|
@@ -664,6 +830,13 @@ export interface AttachmentReference {
|
|
|
664
830
|
*/
|
|
665
831
|
createdBy: string;
|
|
666
832
|
}
|
|
833
|
+
export interface IncompleteAttachmentUploadReclaimResult {
|
|
834
|
+
scannedLedgers: number;
|
|
835
|
+
reclaimedUploads: number;
|
|
836
|
+
reclaimedChunks: number;
|
|
837
|
+
keptCommittedUploads: number;
|
|
838
|
+
keptRecentUploads: number;
|
|
839
|
+
}
|
|
667
840
|
/**
|
|
668
841
|
* Configuration for attachment handling in MindooDB.
|
|
669
842
|
*/
|
|
@@ -698,6 +871,27 @@ export interface DocumentCacheConfig {
|
|
|
698
871
|
* Default: same as `maxEntries`
|
|
699
872
|
*/
|
|
700
873
|
restoreLimit?: number;
|
|
874
|
+
/**
|
|
875
|
+
* Number of cached documents fetched per batch during the eager
|
|
876
|
+
* startup restore (`restoreFromCache`). Each batch issues a single
|
|
877
|
+
* `LocalCacheStore.getMany` call, so this knob trades transaction
|
|
878
|
+
* overhead for transient memory pressure:
|
|
879
|
+
*
|
|
880
|
+
* - smaller values (e.g. 32-64) reduce peak memory at the cost of
|
|
881
|
+
* more cache-store transactions; sensible on memory-constrained
|
|
882
|
+
* targets (mobile, RN) or with very large average doc bodies (e.g.
|
|
883
|
+
* attachments-as-documents),
|
|
884
|
+
* - larger values (e.g. 512-1024) amortise per-transaction overhead
|
|
885
|
+
* but hold more encrypted+decrypted byte buffers in memory at the
|
|
886
|
+
* same time.
|
|
887
|
+
*
|
|
888
|
+
* Has no effect when `restoreToL2` is `true` (no eager fill happens).
|
|
889
|
+
* Has no effect on lazy L2 reads (`tryLoadFromL2`) or on the
|
|
890
|
+
* background warmer, both of which load one document at a time.
|
|
891
|
+
*
|
|
892
|
+
* Default: 256 (~25 MB transient peak per batch at 50 KB/doc).
|
|
893
|
+
*/
|
|
894
|
+
restoreBatchSize?: number;
|
|
701
895
|
/**
|
|
702
896
|
* When enabled, verifies after cache restore that the restored document
|
|
703
897
|
* index still matches the underlying local store and rebuilds metadata if a
|
|
@@ -706,6 +900,136 @@ export interface DocumentCacheConfig {
|
|
|
706
900
|
* Default: false
|
|
707
901
|
*/
|
|
708
902
|
reconcileRestoredIndexOnInit?: boolean;
|
|
903
|
+
/**
|
|
904
|
+
* When `true`, the persisted document cache is treated as the L2 tier
|
|
905
|
+
* of an L1/L2 cache split: startup does **not** eagerly materialize
|
|
906
|
+
* any cached documents into the in-memory L1 cache. Instead, the L2
|
|
907
|
+
* payloads stay on disk and individual `getDocument()` calls pull
|
|
908
|
+
* them in lazily via the L2 read path (which compares the persisted
|
|
909
|
+
* `changeSeq + automergeHeads` against the live index, applies
|
|
910
|
+
* deltas if stale, and then promotes to L1).
|
|
911
|
+
*
|
|
912
|
+
* This unlocks the "L2 much larger than L1" use case (e.g. 30k docs
|
|
913
|
+
* persisted, 128 in RAM) without burning startup time and memory on
|
|
914
|
+
* documents the user may never read.
|
|
915
|
+
*
|
|
916
|
+
* When `false` (the default), startup behavior is unchanged: cached
|
|
917
|
+
* documents are eagerly loaded into L1 up to `restoreLimit`. Even in
|
|
918
|
+
* eager mode the restore now uses the new batched `getMany` API to
|
|
919
|
+
* amortize per-key transaction overhead.
|
|
920
|
+
*/
|
|
921
|
+
restoreToL2?: boolean;
|
|
922
|
+
/**
|
|
923
|
+
* Tuning for the optional background L2 warmer.
|
|
924
|
+
*
|
|
925
|
+
* The warmer is started explicitly via `startBackgroundWarmer()` and
|
|
926
|
+
* walks the in-memory document index, ensuring every doc has an
|
|
927
|
+
* up-to-date L2 cache record (using the same `tryLoadFromL2` path
|
|
928
|
+
* foreground reads use). It yields to the host runtime between
|
|
929
|
+
* batches so it does not starve other work.
|
|
930
|
+
*/
|
|
931
|
+
warmer?: DocumentCacheWarmerConfig;
|
|
932
|
+
}
|
|
933
|
+
/**
|
|
934
|
+
* Cooperative scheduler used by the L2 background warmer to yield
|
|
935
|
+
* between batches so it does not monopolize the event loop.
|
|
936
|
+
*
|
|
937
|
+
* The default implementation uses `setTimeout(0)` which works in both
|
|
938
|
+
* Node and browsers. Embedders can plug in custom schedulers (e.g. one
|
|
939
|
+
* that yields via `requestIdleCallback` in the browser, or that
|
|
940
|
+
* coalesces yields with their own task queue).
|
|
941
|
+
*/
|
|
942
|
+
export interface WarmerScheduler {
|
|
943
|
+
/**
|
|
944
|
+
* Yield control back to the host runtime. The warmer will resume
|
|
945
|
+
* processing once the returned promise resolves.
|
|
946
|
+
*/
|
|
947
|
+
yield(): Promise<void>;
|
|
948
|
+
}
|
|
949
|
+
/**
|
|
950
|
+
* Tuning options for the background L2 warmer.
|
|
951
|
+
*/
|
|
952
|
+
export interface DocumentCacheWarmerConfig {
|
|
953
|
+
/**
|
|
954
|
+
* Number of documents to process between scheduler yields. Smaller
|
|
955
|
+
* values yield more often (better responsiveness on the foreground
|
|
956
|
+
* thread, slightly higher per-doc overhead). Larger values run faster
|
|
957
|
+
* but block the event loop in larger bursts.
|
|
958
|
+
* Default: 50
|
|
959
|
+
*/
|
|
960
|
+
batchSize?: number;
|
|
961
|
+
/**
|
|
962
|
+
* Custom scheduler implementation. Defaults to a `setTimeout(0)`-based
|
|
963
|
+
* scheduler that works in any JavaScript runtime.
|
|
964
|
+
*/
|
|
965
|
+
scheduler?: WarmerScheduler;
|
|
966
|
+
}
|
|
967
|
+
/**
|
|
968
|
+
* Lifecycle phases for a background L2 warmer pass.
|
|
969
|
+
*
|
|
970
|
+
* - `warming` - the warmer is actively processing documents; `processed`
|
|
971
|
+
* will continue to grow until it reaches `total`.
|
|
972
|
+
* - `done` - the warmer reached the end of its document snapshot; the
|
|
973
|
+
* pass terminated successfully.
|
|
974
|
+
* - `cancelled`- the warmer observed an abort signal mid-pass and exited
|
|
975
|
+
* early. `processed` reflects how far it got; the
|
|
976
|
+
* remaining `total - processed` documents were not warmed.
|
|
977
|
+
*/
|
|
978
|
+
export type BackgroundWarmerPhase = "warming" | "done" | "cancelled";
|
|
979
|
+
/**
|
|
980
|
+
* Snapshot of a background L2 warmer pass, suitable for driving a
|
|
981
|
+
* progress UI.
|
|
982
|
+
*
|
|
983
|
+
* `total` is captured once at the start of the pass (a snapshot of
|
|
984
|
+
* `index.length`); concurrent doc creations during the pass do not
|
|
985
|
+
* grow `total` so the bar can advance monotonically toward 100%.
|
|
986
|
+
*
|
|
987
|
+
* `processed` includes both docs that were warmed (an L2 record was
|
|
988
|
+
* read or refreshed) and docs that were skipped because they were
|
|
989
|
+
* already hot in L1 - in both cases the warmer is "done" with that doc.
|
|
990
|
+
*/
|
|
991
|
+
export interface BackgroundWarmerProgress {
|
|
992
|
+
/** Number of docs the warmer has finished visiting in this pass. */
|
|
993
|
+
processed: number;
|
|
994
|
+
/** Total docs the warmer intends to visit in this pass. */
|
|
995
|
+
total: number;
|
|
996
|
+
/** Lifecycle phase. See {@link BackgroundWarmerPhase}. */
|
|
997
|
+
phase: BackgroundWarmerPhase;
|
|
998
|
+
}
|
|
999
|
+
/**
|
|
1000
|
+
* Options accepted by {@link MindooDB.startBackgroundWarmer}.
|
|
1001
|
+
*/
|
|
1002
|
+
export interface StartBackgroundWarmerOptions {
|
|
1003
|
+
/**
|
|
1004
|
+
* Optional `AbortSignal` that the caller can use to cancel this
|
|
1005
|
+
* warmer pass without affecting any other in-flight passes.
|
|
1006
|
+
* Aborting via the signal has the same effect as calling
|
|
1007
|
+
* {@link MindooDB.stopBackgroundWarmer}.
|
|
1008
|
+
*
|
|
1009
|
+
* Note: warmer single-flight semantics mean that if a warmer is
|
|
1010
|
+
* already running when `startBackgroundWarmer` is called, the
|
|
1011
|
+
* existing in-flight promise is returned and the new `signal` is
|
|
1012
|
+
* NOT honored (since the existing pass owns its own internal
|
|
1013
|
+
* cancellation lifecycle). Callers that need precise cancellation
|
|
1014
|
+
* control should call {@link MindooDB.stopBackgroundWarmer} first.
|
|
1015
|
+
*/
|
|
1016
|
+
signal?: AbortSignal;
|
|
1017
|
+
/**
|
|
1018
|
+
* Optional progress callback invoked by the warmer once per
|
|
1019
|
+
* scheduler-yield batch (i.e. roughly every
|
|
1020
|
+
* `DocumentCacheWarmerConfig.batchSize` documents) and once more
|
|
1021
|
+
* with `phase: "done"` or `phase: "cancelled"` when the pass
|
|
1022
|
+
* settles.
|
|
1023
|
+
*
|
|
1024
|
+
* Designed for driving a progress bar / "Warming…" UI affordance.
|
|
1025
|
+
* Per-doc invocation is intentionally avoided so the callback
|
|
1026
|
+
* doesn't add measurable overhead even on warmers that walk
|
|
1027
|
+
* 30,000+ documents.
|
|
1028
|
+
*
|
|
1029
|
+
* Errors thrown from this callback are caught and logged so a buggy
|
|
1030
|
+
* progress consumer cannot break the warmer.
|
|
1031
|
+
*/
|
|
1032
|
+
onProgress?: (progress: BackgroundWarmerProgress) => void;
|
|
709
1033
|
}
|
|
710
1034
|
/**
|
|
711
1035
|
* Configuration for automatic snapshot creation.
|
|
@@ -959,24 +1283,81 @@ export interface MindooDoc {
|
|
|
959
1283
|
*/
|
|
960
1284
|
streamAttachment(attachmentId: string, startOffset?: number): AsyncGenerator<Uint8Array, void, unknown>;
|
|
961
1285
|
}
|
|
1286
|
+
/** Plain JSON-compatible document payload materialized from a MindooDoc. */
|
|
962
1287
|
export interface MindooDocPayload {
|
|
963
1288
|
[key: string]: unknown;
|
|
964
1289
|
}
|
|
1290
|
+
/**
|
|
1291
|
+
* Single text splice applied to the string at a text patch path.
|
|
1292
|
+
*
|
|
1293
|
+
* `index` is a character offset in the current text value, `deleteCount`
|
|
1294
|
+
* removes characters from that offset, and `insert` adds replacement text.
|
|
1295
|
+
*/
|
|
965
1296
|
export interface MindooTextEdit {
|
|
966
1297
|
index: number;
|
|
967
1298
|
deleteCount: number;
|
|
968
1299
|
insert?: string;
|
|
969
1300
|
}
|
|
1301
|
+
/**
|
|
1302
|
+
* Ordered text edits for one string field in a MindooDoc.
|
|
1303
|
+
*
|
|
1304
|
+
* `path` addresses the target string inside the document payload. When
|
|
1305
|
+
* supplied, `baseHeads` identifies the Automerge heads the caller based the
|
|
1306
|
+
* edit on, allowing the backend to apply order-sensitive text changes in the
|
|
1307
|
+
* intended causal context.
|
|
1308
|
+
*/
|
|
970
1309
|
export interface MindooTextPatch {
|
|
971
1310
|
path: Array<string | number>;
|
|
972
1311
|
baseHeads?: string[];
|
|
973
1312
|
edits: MindooTextEdit[];
|
|
974
1313
|
}
|
|
1314
|
+
/** Result returned after applying a text patch and materializing the document. */
|
|
975
1315
|
export interface MindooTextPatchResult {
|
|
976
1316
|
doc: MindooDoc;
|
|
977
1317
|
heads: string[];
|
|
978
1318
|
data: MindooDocPayload;
|
|
979
1319
|
}
|
|
1320
|
+
/** Sets a value at `path`, creating or replacing that payload field. */
|
|
1321
|
+
export interface MindooJsonSetPatch {
|
|
1322
|
+
path: Array<string | number>;
|
|
1323
|
+
value: unknown;
|
|
1324
|
+
}
|
|
1325
|
+
/** Removes the value at `path` from the payload object or list. */
|
|
1326
|
+
export interface MindooJsonUnsetPatch {
|
|
1327
|
+
path: Array<string | number>;
|
|
1328
|
+
}
|
|
1329
|
+
/** Inserts one or more values into the list located at `path`. */
|
|
1330
|
+
export interface MindooJsonListInsertPatch {
|
|
1331
|
+
path: Array<string | number>;
|
|
1332
|
+
index: number;
|
|
1333
|
+
values: unknown[];
|
|
1334
|
+
}
|
|
1335
|
+
/** Deletes one or more values from the list located at `path`. */
|
|
1336
|
+
export interface MindooJsonListDeletePatch {
|
|
1337
|
+
path: Array<string | number>;
|
|
1338
|
+
index: number;
|
|
1339
|
+
deleteCount: number;
|
|
1340
|
+
}
|
|
1341
|
+
/**
|
|
1342
|
+
* Granular JSON mutation batch for a MindooDoc payload.
|
|
1343
|
+
*
|
|
1344
|
+
* Operations are applied in patch order by operation group. `baseHeads` has the
|
|
1345
|
+
* same role as in text patches: it records the document heads the caller saw
|
|
1346
|
+
* before constructing operations whose order matters, such as list inserts.
|
|
1347
|
+
*/
|
|
1348
|
+
export interface MindooJsonPatch {
|
|
1349
|
+
baseHeads?: string[];
|
|
1350
|
+
set?: MindooJsonSetPatch[];
|
|
1351
|
+
unset?: MindooJsonUnsetPatch[];
|
|
1352
|
+
listInsert?: MindooJsonListInsertPatch[];
|
|
1353
|
+
listDelete?: MindooJsonListDeletePatch[];
|
|
1354
|
+
}
|
|
1355
|
+
/** Result returned after applying a JSON patch and materializing the document. */
|
|
1356
|
+
export interface MindooJsonPatchResult {
|
|
1357
|
+
doc: MindooDoc;
|
|
1358
|
+
heads: string[];
|
|
1359
|
+
data: MindooDocPayload;
|
|
1360
|
+
}
|
|
980
1361
|
export interface DirectoryUserDetails {
|
|
981
1362
|
[key: string]: string;
|
|
982
1363
|
}
|
|
@@ -1281,6 +1662,13 @@ export interface OpenDBOptions extends OpenStoreOptions {
|
|
|
1281
1662
|
* This is used for the directory database to prevent recursion and ensure security.
|
|
1282
1663
|
*/
|
|
1283
1664
|
adminOnlyDb?: boolean;
|
|
1665
|
+
/**
|
|
1666
|
+
* Optional read-only historical cutoff for opening the database.
|
|
1667
|
+
*
|
|
1668
|
+
* When set, entries with createdAt >= timeTravelDate are ignored. The
|
|
1669
|
+
* normalized value maps to store-level creationDateUntil semantics.
|
|
1670
|
+
*/
|
|
1671
|
+
timeTravelDate?: number | Date | string;
|
|
1284
1672
|
/**
|
|
1285
1673
|
* Configuration for attachment handling (chunk size, etc.)
|
|
1286
1674
|
* If not provided, defaults are used.
|
|
@@ -1341,7 +1729,7 @@ export interface PerformanceCallback {
|
|
|
1341
1729
|
* Called for bounded history/time-travel workflows.
|
|
1342
1730
|
*/
|
|
1343
1731
|
onHistoryOperation?: (metrics: {
|
|
1344
|
-
operation: 'getDocumentAtTimestamp' | 'getDocumentHistoryPage' | 'analyzeDocumentDagAtTimestamp' | 'materializeDocumentBranchAtEntry' | 'materializeDocumentBranchAtTimestamp' | 'describeDocumentDagEntry';
|
|
1732
|
+
operation: 'getDocumentAtTimestamp' | 'getDocumentHistoryPage' | 'analyzeDocumentDagAtTimestamp' | 'materializeDocumentBranchAtEntry' | 'materializeDocumentBranchAtTimestamp' | 'describeDocumentDagEntry' | 'analyzeDocumentConflicts' | 'getDocumentConflictReport' | 'getDocumentConflictBaseValues';
|
|
1345
1733
|
docId: string;
|
|
1346
1734
|
time: number;
|
|
1347
1735
|
scannedEntries: number;
|
|
@@ -1472,6 +1860,177 @@ export interface DocumentDagEntryDetails {
|
|
|
1472
1860
|
automergeHash: string | null;
|
|
1473
1861
|
decodedChange: DocumentDagDecodedChangeSummary | null;
|
|
1474
1862
|
}
|
|
1863
|
+
/**
|
|
1864
|
+
* Conflict analysis mode controls how much history the analyzer traverses.
|
|
1865
|
+
*/
|
|
1866
|
+
export type DocumentConflictAnalysisMode = "quick" | "full";
|
|
1867
|
+
/**
|
|
1868
|
+
* Conflict detail level controls whether conflicting values are summarized.
|
|
1869
|
+
*/
|
|
1870
|
+
export type DocumentConflictDetailLevel = "paths-only" | "values";
|
|
1871
|
+
/**
|
|
1872
|
+
* JSON-safe path segment returned by conflict analysis.
|
|
1873
|
+
*/
|
|
1874
|
+
export type DocumentConflictPathSegment = string | number;
|
|
1875
|
+
/**
|
|
1876
|
+
* JSON-safe value summary for one conflicting value.
|
|
1877
|
+
*
|
|
1878
|
+
* `value` is included only when it can be represented safely without exposing
|
|
1879
|
+
* CRDT-specific objects. `preview` is always intended for compact UI display.
|
|
1880
|
+
*/
|
|
1881
|
+
export interface DocumentConflictValueSummary {
|
|
1882
|
+
conflictId: string;
|
|
1883
|
+
preview: string | null;
|
|
1884
|
+
value?: unknown;
|
|
1885
|
+
isWinner: boolean;
|
|
1886
|
+
}
|
|
1887
|
+
/**
|
|
1888
|
+
* One conflicted document path detected during analysis.
|
|
1889
|
+
*/
|
|
1890
|
+
export interface DocumentConflictPath {
|
|
1891
|
+
path: DocumentConflictPathSegment[];
|
|
1892
|
+
pathString: string;
|
|
1893
|
+
values?: DocumentConflictValueSummary[];
|
|
1894
|
+
}
|
|
1895
|
+
/**
|
|
1896
|
+
* Describes where in the document DAG a conflict observation was made.
|
|
1897
|
+
*/
|
|
1898
|
+
export interface DocumentConflictLocation {
|
|
1899
|
+
kind: "entry-after" | "active-heads" | "merge-deps";
|
|
1900
|
+
entryId?: string;
|
|
1901
|
+
createdAt?: number;
|
|
1902
|
+
receiptOrder?: number;
|
|
1903
|
+
createdByPublicKey?: string;
|
|
1904
|
+
headEntryIds: string[];
|
|
1905
|
+
automergeHeads: string[];
|
|
1906
|
+
}
|
|
1907
|
+
/**
|
|
1908
|
+
* Conflict observation or resolution event for one document.
|
|
1909
|
+
*/
|
|
1910
|
+
export interface DocumentConflictSummary {
|
|
1911
|
+
docId: string;
|
|
1912
|
+
location: DocumentConflictLocation;
|
|
1913
|
+
paths: DocumentConflictPath[];
|
|
1914
|
+
}
|
|
1915
|
+
/**
|
|
1916
|
+
* Durable cursor for incremental conflict scans.
|
|
1917
|
+
*
|
|
1918
|
+
* `changeSeqAsOf` is used for cheap document-level pre-filtering through the
|
|
1919
|
+
* document index. `storeReceiptOrderAsOf` is used for per-event filtering so
|
|
1920
|
+
* late-arriving sync entries are surfaced even if their author timestamp is old.
|
|
1921
|
+
*/
|
|
1922
|
+
export interface ConflictScanCheckpoint {
|
|
1923
|
+
changeSeqAsOf: number;
|
|
1924
|
+
storeReceiptOrderAsOf?: number;
|
|
1925
|
+
takenAt: number;
|
|
1926
|
+
}
|
|
1927
|
+
/**
|
|
1928
|
+
* Options accepted by conflict analysis APIs.
|
|
1929
|
+
*/
|
|
1930
|
+
export interface DocumentConflictAnalysisOptions {
|
|
1931
|
+
mode?: DocumentConflictAnalysisMode;
|
|
1932
|
+
detail?: DocumentConflictDetailLevel;
|
|
1933
|
+
pageSize?: number;
|
|
1934
|
+
yieldEveryMs?: number;
|
|
1935
|
+
maxConflictsPerDoc?: number;
|
|
1936
|
+
since?: ConflictScanCheckpoint;
|
|
1937
|
+
includeUnresolvedFromBefore?: boolean;
|
|
1938
|
+
signal?: AbortSignal;
|
|
1939
|
+
}
|
|
1940
|
+
/**
|
|
1941
|
+
* Options accepted by the convenience report API.
|
|
1942
|
+
*/
|
|
1943
|
+
export interface DocumentConflictReportOptions extends Omit<DocumentConflictAnalysisOptions, "mode" | "maxConflictsPerDoc"> {
|
|
1944
|
+
}
|
|
1945
|
+
/**
|
|
1946
|
+
* Streaming event emitted by `analyzeDocumentConflicts()`.
|
|
1947
|
+
*/
|
|
1948
|
+
export type DocumentConflictAnalysisEvent = {
|
|
1949
|
+
type: "progress";
|
|
1950
|
+
scannedDocs: number;
|
|
1951
|
+
totalDocs: number;
|
|
1952
|
+
docId?: string;
|
|
1953
|
+
scannedEntries?: number;
|
|
1954
|
+
message: string;
|
|
1955
|
+
} | {
|
|
1956
|
+
type: "docStart";
|
|
1957
|
+
docId: string;
|
|
1958
|
+
} | {
|
|
1959
|
+
type: "conflictDetected";
|
|
1960
|
+
conflict: DocumentConflictSummary;
|
|
1961
|
+
quick: boolean;
|
|
1962
|
+
} | {
|
|
1963
|
+
type: "conflictResolved";
|
|
1964
|
+
docId: string;
|
|
1965
|
+
entryId: string;
|
|
1966
|
+
createdAt: number;
|
|
1967
|
+
receiptOrder?: number;
|
|
1968
|
+
createdByPublicKey: string;
|
|
1969
|
+
path: DocumentConflictPath;
|
|
1970
|
+
automergeHash: string | null;
|
|
1971
|
+
} | {
|
|
1972
|
+
type: "docDone";
|
|
1973
|
+
docId: string;
|
|
1974
|
+
hadConflicts: boolean;
|
|
1975
|
+
conflictsFound: number;
|
|
1976
|
+
entriesScanned: number;
|
|
1977
|
+
} | {
|
|
1978
|
+
type: "error";
|
|
1979
|
+
docId?: string;
|
|
1980
|
+
entryId?: string;
|
|
1981
|
+
error: unknown;
|
|
1982
|
+
} | {
|
|
1983
|
+
type: "scanCheckpoint";
|
|
1984
|
+
checkpoint: ConflictScanCheckpoint;
|
|
1985
|
+
};
|
|
1986
|
+
/**
|
|
1987
|
+
* Full conflict report for one document.
|
|
1988
|
+
*/
|
|
1989
|
+
export interface DocumentConflictReport {
|
|
1990
|
+
docId: string;
|
|
1991
|
+
hadConflicts: boolean;
|
|
1992
|
+
conflictsFound: number;
|
|
1993
|
+
conflicts: DocumentConflictSummary[];
|
|
1994
|
+
resolutions: Array<Extract<DocumentConflictAnalysisEvent, {
|
|
1995
|
+
type: "conflictResolved";
|
|
1996
|
+
}>>;
|
|
1997
|
+
entriesScanned: number;
|
|
1998
|
+
errors: Array<Extract<DocumentConflictAnalysisEvent, {
|
|
1999
|
+
type: "error";
|
|
2000
|
+
}>>;
|
|
2001
|
+
scanCheckpoint: ConflictScanCheckpoint | null;
|
|
2002
|
+
}
|
|
2003
|
+
/**
|
|
2004
|
+
* Request to look up the value at a conflicted path as it stood at the merge
|
|
2005
|
+
* base of the contributing branches (the "old" value before the conflict).
|
|
2006
|
+
*/
|
|
2007
|
+
export interface DocumentConflictBaseValueQuery {
|
|
2008
|
+
/** Conflict location as returned by `getDocumentConflictReport`. */
|
|
2009
|
+
location: DocumentConflictLocation;
|
|
2010
|
+
/** Structured path segments (matches `DocumentConflictPath.path`). */
|
|
2011
|
+
path: DocumentConflictPathSegment[];
|
|
2012
|
+
/** Stable string key (matches `DocumentConflictPath.pathString`). */
|
|
2013
|
+
pathString: string;
|
|
2014
|
+
}
|
|
2015
|
+
/**
|
|
2016
|
+
* Result for one base-value lookup.
|
|
2017
|
+
*
|
|
2018
|
+
* - `available`: a previous value existed at the merge base; `preview` and
|
|
2019
|
+
* `value` are populated.
|
|
2020
|
+
* - `no-prior-value`: a merge base was found but the path did not exist there
|
|
2021
|
+
* (e.g. both branches independently created the field).
|
|
2022
|
+
* - `no-base`: no shared ancestor could be determined for the contributing
|
|
2023
|
+
* heads (e.g. the conflict has only one head, or the parent set is empty).
|
|
2024
|
+
* - `missing-entry`: the conflict's `entryId` is not (or no longer) in the
|
|
2025
|
+
* local store; the base value cannot be resolved.
|
|
2026
|
+
*/
|
|
2027
|
+
export interface DocumentConflictBaseValue {
|
|
2028
|
+
pathString: string;
|
|
2029
|
+
baseEntryId: string | null;
|
|
2030
|
+
status: "available" | "no-prior-value" | "no-base" | "missing-entry";
|
|
2031
|
+
preview: string | null;
|
|
2032
|
+
value?: unknown;
|
|
2033
|
+
}
|
|
1475
2034
|
/**
|
|
1476
2035
|
* Result of reconstructing one branch-local document state for a selected DAG head.
|
|
1477
2036
|
*/
|
|
@@ -1568,6 +2127,18 @@ export interface MindooDB {
|
|
|
1568
2127
|
* @return True if admin-only mode is enabled
|
|
1569
2128
|
*/
|
|
1570
2129
|
isAdminOnlyDb(): boolean;
|
|
2130
|
+
/**
|
|
2131
|
+
* True when this database was opened with a timeTravelDate cutoff.
|
|
2132
|
+
*/
|
|
2133
|
+
isTimeTravelMode(): boolean;
|
|
2134
|
+
/**
|
|
2135
|
+
* True when mutating APIs are disabled for this database instance.
|
|
2136
|
+
*/
|
|
2137
|
+
isReadOnly(): boolean;
|
|
2138
|
+
/**
|
|
2139
|
+
* Normalized time travel cutoff in epoch milliseconds, or null for live mode.
|
|
2140
|
+
*/
|
|
2141
|
+
getTimeTravelDate(): number | null;
|
|
1571
2142
|
/**
|
|
1572
2143
|
* Get the content-addressed store that is used to store document changes for this database.
|
|
1573
2144
|
*
|
|
@@ -1580,6 +2151,9 @@ export interface MindooDB {
|
|
|
1580
2151
|
* @return The content-addressed store for attachments
|
|
1581
2152
|
*/
|
|
1582
2153
|
getAttachmentStore(): ContentAddressedStore;
|
|
2154
|
+
reclaimIncompleteAttachmentUploads?(options?: {
|
|
2155
|
+
minAgeMs?: number;
|
|
2156
|
+
}): Promise<IncompleteAttachmentUploadReclaimResult>;
|
|
1583
2157
|
/**
|
|
1584
2158
|
* Create a new document.
|
|
1585
2159
|
*
|
|
@@ -1696,6 +2270,36 @@ export interface MindooDB {
|
|
|
1696
2270
|
* Decode and summarize one DAG entry for hover/tooling use cases.
|
|
1697
2271
|
*/
|
|
1698
2272
|
describeDocumentDagEntry(docId: string, entryId: string): Promise<DocumentDagEntryDetails | null>;
|
|
2273
|
+
/**
|
|
2274
|
+
* Stream conflict analysis events for one or more documents.
|
|
2275
|
+
*
|
|
2276
|
+
* The API intentionally returns MindooDB DTOs only. It does not expose
|
|
2277
|
+
* Automerge documents, patches, or operation objects so the storage backend
|
|
2278
|
+
* can evolve without changing callers.
|
|
2279
|
+
*/
|
|
2280
|
+
analyzeDocumentConflicts(docIds: string[], options?: DocumentConflictAnalysisOptions): AsyncGenerator<DocumentConflictAnalysisEvent, void, unknown>;
|
|
2281
|
+
/**
|
|
2282
|
+
* Build a full conflict report for one document by consuming the streaming
|
|
2283
|
+
* analyzer internally.
|
|
2284
|
+
*/
|
|
2285
|
+
getDocumentConflictReport(docId: string, options?: DocumentConflictReportOptions): Promise<DocumentConflictReport>;
|
|
2286
|
+
/**
|
|
2287
|
+
* Resolve the value each conflicted path had at its merge base (the most
|
|
2288
|
+
* recent common ancestor of the branches that contributed to the conflict).
|
|
2289
|
+
*
|
|
2290
|
+
* Each query independently maps to a base value so the caller can request
|
|
2291
|
+
* lookups lazily — for example, only for the paths it currently displays.
|
|
2292
|
+
* Queries that share a merge base are coalesced internally so the
|
|
2293
|
+
* underlying document state is materialized at most once per base entry.
|
|
2294
|
+
*/
|
|
2295
|
+
getDocumentConflictBaseValues(docId: string, queries: DocumentConflictBaseValueQuery[]): Promise<DocumentConflictBaseValue[]>;
|
|
2296
|
+
/**
|
|
2297
|
+
* Return an incremental conflict-scan checkpoint for the current local view.
|
|
2298
|
+
*
|
|
2299
|
+
* Callers can persist this value after presenting scan results and pass it
|
|
2300
|
+
* back as `DocumentConflictAnalysisOptions.since` on the next run.
|
|
2301
|
+
*/
|
|
2302
|
+
getConflictScanCheckpoint(): Promise<ConflictScanCheckpoint>;
|
|
1699
2303
|
/**
|
|
1700
2304
|
* Get all non-deleted document IDs in this database.
|
|
1701
2305
|
*
|
|
@@ -1789,6 +2393,15 @@ export interface MindooDB {
|
|
|
1789
2393
|
* overwriting concurrent edits that arrived meanwhile.
|
|
1790
2394
|
*/
|
|
1791
2395
|
applyTextPatch(doc: MindooDoc, patch: MindooTextPatch): Promise<MindooTextPatchResult>;
|
|
2396
|
+
/**
|
|
2397
|
+
* Apply granular JSON edits at document paths.
|
|
2398
|
+
*
|
|
2399
|
+
* If `baseHeads` is provided, edits are applied at that historical Automerge
|
|
2400
|
+
* version using `changeAt`, then merged into the current document. This lets
|
|
2401
|
+
* apps flush buffered object/list operations based on a stale local copy
|
|
2402
|
+
* without replacing concurrent changes that arrived meanwhile.
|
|
2403
|
+
*/
|
|
2404
|
+
applyJsonPatch(doc: MindooDoc, patch: MindooJsonPatch): Promise<MindooJsonPatchResult>;
|
|
1792
2405
|
/**
|
|
1793
2406
|
* Change a document using a specific signing key.
|
|
1794
2407
|
* This is like changeDoc but allows signing with a different key than the current user's.
|
|
@@ -1850,9 +2463,87 @@ export interface MindooDB {
|
|
|
1850
2463
|
* then processes them to update the cached database documents and index.
|
|
1851
2464
|
* After processing, the new change hashes are appended to the stored list.
|
|
1852
2465
|
*
|
|
1853
|
-
*
|
|
2466
|
+
* Sync deliberately does NOT trigger the L2 background warmer. Callers
|
|
2467
|
+
* that want to warm the L2 cache after a sync (e.g. the Haven sync
|
|
2468
|
+
* page once a sync settles) should call {@link startBackgroundWarmer}
|
|
2469
|
+
* explicitly. This keeps casual `syncStoreChanges()` calls cheap and
|
|
2470
|
+
* leaves warmer scheduling to the caller, which knows whether the
|
|
2471
|
+
* cost of a full L2 walk is worth paying for the current workload.
|
|
2472
|
+
*
|
|
2473
|
+
* @return A promise that resolves when the sync is complete.
|
|
1854
2474
|
*/
|
|
1855
2475
|
syncStoreChanges(): Promise<void>;
|
|
2476
|
+
/**
|
|
2477
|
+
* Reconcile local document visibility with the current tenant KeyBag.
|
|
2478
|
+
*
|
|
2479
|
+
* Reveals documents whose decryption keys are now available, hides
|
|
2480
|
+
* documents whose keys have been removed, and purges any plaintext
|
|
2481
|
+
* caches for inaccessible documents. The method only touches in-memory
|
|
2482
|
+
* and L2 caches owned by this database instance - it does not write
|
|
2483
|
+
* synthetic store entries and is safe to call repeatedly.
|
|
2484
|
+
*
|
|
2485
|
+
* Optional so alternative database implementations (e.g. read-only
|
|
2486
|
+
* views, time-travel snapshots) can omit it.
|
|
2487
|
+
*/
|
|
2488
|
+
reconcileKeyVisibility?(): Promise<void>;
|
|
2489
|
+
/**
|
|
2490
|
+
* Start the L2 background warmer.
|
|
2491
|
+
*
|
|
2492
|
+
* Walks the in-memory document index and ensures every document has
|
|
2493
|
+
* an up-to-date L2 cache record (using the same internal load-from-L2
|
|
2494
|
+
* code path foreground reads use). Runs in batches with cooperative
|
|
2495
|
+
* yields so foreground operations are not starved.
|
|
2496
|
+
*
|
|
2497
|
+
* Intended to be called explicitly by long-lived sessions that just
|
|
2498
|
+
* finished a sync (e.g. the Haven sync page after pulling/pushing
|
|
2499
|
+
* completes) so subsequent reads - especially virtual view rebuilds
|
|
2500
|
+
* - hit the fast L2 path. Casual database opens should NOT call this;
|
|
2501
|
+
* pay the warmer cost only when the workload is about to benefit
|
|
2502
|
+
* from a fully warm L2.
|
|
2503
|
+
*
|
|
2504
|
+
* Single-flight: a second call while the warmer is already running
|
|
2505
|
+
* returns the same in-flight promise rather than starting a second
|
|
2506
|
+
* pass. The returned promise resolves when the warmer has finished
|
|
2507
|
+
* (either by visiting every document or by being cancelled via
|
|
2508
|
+
* {@link stopBackgroundWarmer} or via the optional `signal`).
|
|
2509
|
+
*
|
|
2510
|
+
* @param options See {@link StartBackgroundWarmerOptions}: optional
|
|
2511
|
+
* `signal` for per-call cancellation and `onProgress` for driving
|
|
2512
|
+
* a progress UI.
|
|
2513
|
+
*/
|
|
2514
|
+
startBackgroundWarmer?(options?: StartBackgroundWarmerOptions): Promise<void>;
|
|
2515
|
+
/**
|
|
2516
|
+
* Cancel the running background warmer (if any). Returns a promise
|
|
2517
|
+
* that resolves once the in-flight warmer pass has observed the
|
|
2518
|
+
* cancellation and returned (so callers can `await` clean shutdown).
|
|
2519
|
+
* Safe to call when no warmer is running - resolves immediately in
|
|
2520
|
+
* that case.
|
|
2521
|
+
*
|
|
2522
|
+
* Useful before initiating destructive operations (key rotation, data
|
|
2523
|
+
* wipe, etc.) so the warmer cannot race against the mutation, and at
|
|
2524
|
+
* the end of tests to ensure no background work outlives the test.
|
|
2525
|
+
*/
|
|
2526
|
+
stopBackgroundWarmer?(): Promise<void>;
|
|
2527
|
+
/**
|
|
2528
|
+
* Returns `true` while the L2 background warmer is actively
|
|
2529
|
+
* processing documents. Useful for "Warming…" UI indicators and
|
|
2530
|
+
* tests that need to coordinate with warmer progress.
|
|
2531
|
+
*/
|
|
2532
|
+
isWarmerRunning?(): boolean;
|
|
2533
|
+
/**
|
|
2534
|
+
* Snapshot of the current (or most recent) background warmer pass's
|
|
2535
|
+
* progress, or `null` if no warmer has ever run on this database
|
|
2536
|
+
* instance. Designed for UIs that mount AFTER the warmer has already
|
|
2537
|
+
* started (e.g. the user navigates back to the Sync page mid-warm)
|
|
2538
|
+
* and need to "catch up" on state without missing onProgress events.
|
|
2539
|
+
*
|
|
2540
|
+
* After a warmer settles, the returned snapshot persists with its
|
|
2541
|
+
* final `phase` (`"done"` or `"cancelled"`) so the UI can decide
|
|
2542
|
+
* whether to keep showing a "Optimized" message or fade away. The
|
|
2543
|
+
* snapshot is replaced on the next {@link startBackgroundWarmer}
|
|
2544
|
+
* call.
|
|
2545
|
+
*/
|
|
2546
|
+
getBackgroundWarmerProgress?(): BackgroundWarmerProgress | null;
|
|
1856
2547
|
/**
|
|
1857
2548
|
* Pull changes from a remote content-addressed store or another MindooDB instance.
|
|
1858
2549
|
*
|