mindoodb 0.0.50 → 0.0.53

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.
Files changed (198) hide show
  1. package/README-server.md +11 -2
  2. package/dist/appendonlystores/network/ClientNetworkContentAddressedStore.d.ts +13 -1
  3. package/dist/appendonlystores/network/ClientNetworkContentAddressedStore.d.ts.map +1 -1
  4. package/dist/appendonlystores/network/ClientNetworkContentAddressedStore.js +45 -20
  5. package/dist/appendonlystores/network/ClientNetworkContentAddressedStore.js.map +1 -1
  6. package/dist/appendonlystores/network/HttpTransport.d.ts +2 -0
  7. package/dist/appendonlystores/network/HttpTransport.d.ts.map +1 -1
  8. package/dist/appendonlystores/network/HttpTransport.js +6 -62
  9. package/dist/appendonlystores/network/HttpTransport.js.map +1 -1
  10. package/dist/appendonlystores/network/ServerNetworkContentAddressedStore.d.ts +24 -0
  11. package/dist/appendonlystores/network/ServerNetworkContentAddressedStore.d.ts.map +1 -1
  12. package/dist/appendonlystores/network/ServerNetworkContentAddressedStore.js +75 -24
  13. package/dist/appendonlystores/network/ServerNetworkContentAddressedStore.js.map +1 -1
  14. package/dist/browser/index.mjs +72 -0
  15. package/dist/core/BaseMindooDB.d.ts +89 -14
  16. package/dist/core/BaseMindooDB.d.ts.map +1 -1
  17. package/dist/core/BaseMindooDB.js +692 -201
  18. package/dist/core/BaseMindooDB.js.map +1 -1
  19. package/dist/core/BaseMindooTenant.d.ts +59 -7
  20. package/dist/core/BaseMindooTenant.d.ts.map +1 -1
  21. package/dist/core/BaseMindooTenant.js +427 -90
  22. package/dist/core/BaseMindooTenant.js.map +1 -1
  23. package/dist/core/BaseMindooTenantDirectory.d.ts +61 -9
  24. package/dist/core/BaseMindooTenantDirectory.d.ts.map +1 -1
  25. package/dist/core/BaseMindooTenantDirectory.js +363 -35
  26. package/dist/core/BaseMindooTenantDirectory.js.map +1 -1
  27. package/dist/core/BaseMindooTenantFactory.d.ts +17 -1
  28. package/dist/core/BaseMindooTenantFactory.d.ts.map +1 -1
  29. package/dist/core/BaseMindooTenantFactory.js +292 -16
  30. package/dist/core/BaseMindooTenantFactory.js.map +1 -1
  31. package/dist/core/accesscontrol/DirectoryStateNode.d.ts +68 -1
  32. package/dist/core/accesscontrol/DirectoryStateNode.d.ts.map +1 -1
  33. package/dist/core/accesscontrol/DirectoryStateNode.js +157 -4
  34. package/dist/core/accesscontrol/DirectoryStateNode.js.map +1 -1
  35. package/dist/core/accesscontrol/directoryProjection.d.ts.map +1 -1
  36. package/dist/core/accesscontrol/directoryProjection.js +14 -5
  37. package/dist/core/accesscontrol/directoryProjection.js.map +1 -1
  38. package/dist/core/accesscontrol/grantKeys.d.ts +17 -14
  39. package/dist/core/accesscontrol/grantKeys.d.ts.map +1 -1
  40. package/dist/core/accesscontrol/grantKeys.js +51 -21
  41. package/dist/core/accesscontrol/grantKeys.js.map +1 -1
  42. package/dist/core/accesscontrol/types.d.ts +13 -7
  43. package/dist/core/accesscontrol/types.d.ts.map +1 -1
  44. package/dist/core/accesscontrol/types.js +16 -10
  45. package/dist/core/accesscontrol/types.js.map +1 -1
  46. package/dist/core/appendonlystores/network/AuthenticationService.d.ts +7 -0
  47. package/dist/core/appendonlystores/network/AuthenticationService.d.ts.map +1 -1
  48. package/dist/core/appendonlystores/network/AuthenticationService.js +70 -14
  49. package/dist/core/appendonlystores/network/AuthenticationService.js.map +1 -1
  50. package/dist/core/appendonlystores/network/entryWireCodec.d.ts +51 -0
  51. package/dist/core/appendonlystores/network/entryWireCodec.d.ts.map +1 -0
  52. package/dist/core/appendonlystores/network/entryWireCodec.js +93 -0
  53. package/dist/core/appendonlystores/network/entryWireCodec.js.map +1 -0
  54. package/dist/core/builtinDbInvariants.d.ts +53 -0
  55. package/dist/core/builtinDbInvariants.d.ts.map +1 -0
  56. package/dist/core/builtinDbInvariants.js +147 -0
  57. package/dist/core/builtinDbInvariants.js.map +1 -0
  58. package/dist/core/copy/feasibility.d.ts.map +1 -1
  59. package/dist/core/copy/feasibility.js +3 -0
  60. package/dist/core/copy/feasibility.js.map +1 -1
  61. package/dist/core/copy/flatten.d.ts.map +1 -1
  62. package/dist/core/copy/flatten.js +7 -2
  63. package/dist/core/copy/flatten.js.map +1 -1
  64. package/dist/core/copy/host.d.ts +5 -0
  65. package/dist/core/copy/host.d.ts.map +1 -1
  66. package/dist/core/copy/preflight.d.ts.map +1 -1
  67. package/dist/core/copy/preflight.js +7 -1
  68. package/dist/core/copy/preflight.js.map +1 -1
  69. package/dist/core/copy/types.d.ts +8 -1
  70. package/dist/core/copy/types.d.ts.map +1 -1
  71. package/dist/core/crypto/EntrySignature.d.ts +8 -2
  72. package/dist/core/crypto/EntrySignature.d.ts.map +1 -1
  73. package/dist/core/crypto/EntrySignature.js +14 -5
  74. package/dist/core/crypto/EntrySignature.js.map +1 -1
  75. package/dist/core/crypto/MindooDocSigner.d.ts.map +1 -1
  76. package/dist/core/crypto/MindooDocSigner.js +11 -2
  77. package/dist/core/crypto/MindooDocSigner.js.map +1 -1
  78. package/dist/core/crypto/RSAEncryption.d.ts +19 -0
  79. package/dist/core/crypto/RSAEncryption.d.ts.map +1 -1
  80. package/dist/core/crypto/RSAEncryption.js +36 -3
  81. package/dist/core/crypto/RSAEncryption.js.map +1 -1
  82. package/dist/core/crypto/privateKeyEncryption.js +1 -1
  83. package/dist/core/crypto/privateKeyEncryption.js.map +1 -1
  84. package/dist/core/crypto/rsaOaep3072.d.ts +12 -0
  85. package/dist/core/crypto/rsaOaep3072.d.ts.map +1 -0
  86. package/dist/core/crypto/rsaOaep3072.js +30 -0
  87. package/dist/core/crypto/rsaOaep3072.js.map +1 -0
  88. package/dist/core/databaseIdValidation.d.ts +23 -0
  89. package/dist/core/databaseIdValidation.d.ts.map +1 -1
  90. package/dist/core/databaseIdValidation.js +59 -1
  91. package/dist/core/databaseIdValidation.js.map +1 -1
  92. package/dist/core/index.d.ts +9 -2
  93. package/dist/core/index.d.ts.map +1 -1
  94. package/dist/core/index.js +40 -4
  95. package/dist/core/index.js.map +1 -1
  96. package/dist/core/join/deviceJoinBootstrap.d.ts +23 -0
  97. package/dist/core/join/deviceJoinBootstrap.d.ts.map +1 -0
  98. package/dist/core/join/deviceJoinBootstrap.js +37 -0
  99. package/dist/core/join/deviceJoinBootstrap.js.map +1 -0
  100. package/dist/core/keys/KeyBag.d.ts +20 -2
  101. package/dist/core/keys/KeyBag.d.ts.map +1 -1
  102. package/dist/core/keys/KeyBag.js +22 -10
  103. package/dist/core/keys/KeyBag.js.map +1 -1
  104. package/dist/core/logging/MindooLogger.d.ts.map +1 -1
  105. package/dist/core/logging/MindooLogger.js +65 -40
  106. package/dist/core/logging/MindooLogger.js.map +1 -1
  107. package/dist/core/tenantIdValidation.d.ts.map +1 -1
  108. package/dist/core/tenantIdValidation.js +1 -1
  109. package/dist/core/tenantIdValidation.js.map +1 -1
  110. package/dist/core/tenantSetup.d.ts +109 -0
  111. package/dist/core/tenantSetup.d.ts.map +1 -0
  112. package/dist/core/tenantSetup.js +250 -0
  113. package/dist/core/tenantSetup.js.map +1 -0
  114. package/dist/core/types.d.ts +333 -43
  115. package/dist/core/types.d.ts.map +1 -1
  116. package/dist/core/types.js +27 -9
  117. package/dist/core/types.js.map +1 -1
  118. package/dist/core/uri/joinRequestUri.d.ts +37 -0
  119. package/dist/core/uri/joinRequestUri.d.ts.map +1 -0
  120. package/dist/core/uri/joinRequestUri.js +168 -0
  121. package/dist/core/uri/joinRequestUri.js.map +1 -0
  122. package/dist/core/userid/canonicalUsername.d.ts +66 -0
  123. package/dist/core/userid/canonicalUsername.d.ts.map +1 -0
  124. package/dist/core/userid/canonicalUsername.js +235 -0
  125. package/dist/core/userid/canonicalUsername.js.map +1 -0
  126. package/dist/core/userid/index.d.ts +9 -0
  127. package/dist/core/userid/index.d.ts.map +1 -1
  128. package/dist/core/userid/index.js +14 -0
  129. package/dist/core/userid/index.js.map +1 -1
  130. package/dist/core/userkeys/UserKeyDocument.d.ts +50 -0
  131. package/dist/core/userkeys/UserKeyDocument.d.ts.map +1 -0
  132. package/dist/core/userkeys/UserKeyDocument.js +145 -0
  133. package/dist/core/userkeys/UserKeyDocument.js.map +1 -0
  134. package/dist/core/userkeys/UserKeyManager.d.ts +170 -0
  135. package/dist/core/userkeys/UserKeyManager.d.ts.map +1 -0
  136. package/dist/core/userkeys/UserKeyManager.js +1277 -0
  137. package/dist/core/userkeys/UserKeyManager.js.map +1 -0
  138. package/dist/core/userkeys/fingerprint.d.ts +17 -0
  139. package/dist/core/userkeys/fingerprint.d.ts.map +1 -0
  140. package/dist/core/userkeys/fingerprint.js +59 -0
  141. package/dist/core/userkeys/fingerprint.js.map +1 -0
  142. package/dist/core/userkeys/index.d.ts +11 -0
  143. package/dist/core/userkeys/index.d.ts.map +1 -0
  144. package/dist/core/userkeys/index.js +49 -0
  145. package/dist/core/userkeys/index.js.map +1 -0
  146. package/dist/core/userkeys/recipients.d.ts +51 -0
  147. package/dist/core/userkeys/recipients.d.ts.map +1 -0
  148. package/dist/core/userkeys/recipients.js +292 -0
  149. package/dist/core/userkeys/recipients.js.map +1 -0
  150. package/dist/core/userkeys/resolveUserKeyDocument.d.ts +21 -0
  151. package/dist/core/userkeys/resolveUserKeyDocument.d.ts.map +1 -0
  152. package/dist/core/userkeys/resolveUserKeyDocument.js +98 -0
  153. package/dist/core/userkeys/resolveUserKeyDocument.js.map +1 -0
  154. package/dist/core/userkeys/sealedCrypto.d.ts +21 -0
  155. package/dist/core/userkeys/sealedCrypto.d.ts.map +1 -0
  156. package/dist/core/userkeys/sealedCrypto.js +79 -0
  157. package/dist/core/userkeys/sealedCrypto.js.map +1 -0
  158. package/dist/core/userkeys/sealedTypes.d.ts +72 -0
  159. package/dist/core/userkeys/sealedTypes.d.ts.map +1 -0
  160. package/dist/core/userkeys/sealedTypes.js +14 -0
  161. package/dist/core/userkeys/sealedTypes.js.map +1 -0
  162. package/dist/core/userkeys/types.d.ts +70 -0
  163. package/dist/core/userkeys/types.d.ts.map +1 -0
  164. package/dist/core/userkeys/types.js +48 -0
  165. package/dist/core/userkeys/types.js.map +1 -0
  166. package/dist/core/userkeys/validateUserKeyDocument.d.ts +19 -0
  167. package/dist/core/userkeys/validateUserKeyDocument.d.ts.map +1 -0
  168. package/dist/core/userkeys/validateUserKeyDocument.js +42 -0
  169. package/dist/core/userkeys/validateUserKeyDocument.js.map +1 -0
  170. package/dist/core/utils/idGeneration.d.ts +39 -20
  171. package/dist/core/utils/idGeneration.d.ts.map +1 -1
  172. package/dist/core/utils/idGeneration.js +82 -62
  173. package/dist/core/utils/idGeneration.js.map +1 -1
  174. package/dist/core/utils/index.d.ts +1 -1
  175. package/dist/core/utils/index.d.ts.map +1 -1
  176. package/dist/core/utils/index.js +4 -1
  177. package/dist/core/utils/index.js.map +1 -1
  178. package/dist/node/server/CapabilityMatcher.d.ts +5 -0
  179. package/dist/node/server/CapabilityMatcher.d.ts.map +1 -1
  180. package/dist/node/server/CapabilityMatcher.js +10 -1
  181. package/dist/node/server/CapabilityMatcher.js.map +1 -1
  182. package/dist/node/server/DeviceDiscoveryService.d.ts +36 -0
  183. package/dist/node/server/DeviceDiscoveryService.d.ts.map +1 -0
  184. package/dist/node/server/DeviceDiscoveryService.js +165 -0
  185. package/dist/node/server/DeviceDiscoveryService.js.map +1 -0
  186. package/dist/node/server/MindooDBServer.d.ts +13 -0
  187. package/dist/node/server/MindooDBServer.d.ts.map +1 -1
  188. package/dist/node/server/MindooDBServer.js +99 -61
  189. package/dist/node/server/MindooDBServer.js.map +1 -1
  190. package/dist/node/server/SystemAdminAuth.d.ts +7 -0
  191. package/dist/node/server/SystemAdminAuth.d.ts.map +1 -1
  192. package/dist/node/server/SystemAdminAuth.js +4 -1
  193. package/dist/node/server/SystemAdminAuth.js.map +1 -1
  194. package/dist/node/server/TenantManager.d.ts +29 -0
  195. package/dist/node/server/TenantManager.d.ts.map +1 -1
  196. package/dist/node/server/TenantManager.js +146 -7
  197. package/dist/node/server/TenantManager.js.map +1 -1
  198. package/package.json +5 -5
@@ -26,12 +26,30 @@ import type { VirtualViewUpdateOptions } from "./indexing/virtualviews/IVirtualV
26
26
  * KeyBag location: type "doc", id PUBLIC_INFOS_KEY_ID.
27
27
  */
28
28
  export declare const PUBLIC_INFOS_KEY_ID = "$publicinfos";
29
+ /**
30
+ * Fixed directory document id for tenant display metadata (`{ label }`).
31
+ * Encrypted under {@link PUBLIC_INFOS_KEY_ID}.
32
+ */
33
+ export declare const TENANT_SETUP_DOC_ID = "tenantsetup";
29
34
  /**
30
35
  * Well-known key ID for the tenant-wide default document encryption key.
31
36
  *
32
37
  * KeyBag location: type "doc", id DEFAULT_TENANT_KEY_ID.
33
38
  */
34
39
  export declare const DEFAULT_TENANT_KEY_ID = "default";
40
+ /**
41
+ * Well-known database id for the per-user encryption-identity directory
42
+ * (`userkey_*` documents). Protected by a builtin write invariant independent
43
+ * of the ACL master switch: the admin may create/delete, only the owning
44
+ * person may change.
45
+ */
46
+ export declare const USER_DIRECTORY_DB_ID = "userdirectory";
47
+ /**
48
+ * Well-known database id for the tenant directory (grants, policies, key
49
+ * distribution). Admin-only writes; hardcoded in several call sites as
50
+ * `"directory"` for historical reasons.
51
+ */
52
+ export declare const DIRECTORY_DB_ID = "directory";
35
53
  /**
36
54
  * JSON payload returned by `GET /.well-known/mindoodb-server-info`.
37
55
  */
@@ -154,6 +172,14 @@ export interface PreDecryptedUserKeys {
154
172
  * `EncryptedLocalCacheStore` performs internally.
155
173
  */
156
174
  cacheEncryptionKey?: CryptoKey;
175
+ /**
176
+ * PKCS8 bytes of the identity User-Key. Live-bag hosts (Haven) decrypt this
177
+ * once at unlock and pass it here so `createTenant` / reconcile can mint and
178
+ * wrap `default` to the **identity** User-Key when `currentUserPassword` is
179
+ * empty. Without this, a failed password decrypt used to generate a second
180
+ * throwaway pair and desync `acl_keydistribution_default`.
181
+ */
182
+ userKeyPrivateBytes?: Uint8Array;
157
183
  }
158
184
  interface CreateTenantPasswords {
159
185
  /** Password for the admin user's private keys */
@@ -162,10 +188,10 @@ interface CreateTenantPasswords {
162
188
  * Password for the regular (app) user's private keys.
163
189
  *
164
190
  * When {@link existingKeyBag} **and** {@link preDecryptedAppUserKeys}
165
- * are both supplied the password is no longer needed by `createTenant`
166
- * (the bag has already been wrapped, and `openTenant` consumes the
167
- * pre-imported `CryptoKey`s directly). Callers in that live-bag mode
168
- * may pass an empty string.
191
+ * are both supplied, signing/encryption private keys skip password
192
+ * decrypt. The identity User-Key still needs either `userPassword` or
193
+ * {@link PreDecryptedUserKeys.userKeyPrivateBytes} — otherwise mint
194
+ * cannot wrap `default` to the existing pair.
169
195
  */
170
196
  userPassword: string;
171
197
  /**
@@ -200,6 +226,12 @@ interface CreateTenantPasswords {
200
226
  * (legacy behavior: v1 entries remain acceptable).
201
227
  */
202
228
  requireV2Entries?: boolean;
229
+ /**
230
+ * Optional human-readable tenant label stored in the directory document
231
+ * `tenantsetup` (doc under `$publicinfos`; label field-encrypted under
232
+ * `default`). When omitted, no setup document is written at create time.
233
+ */
234
+ tenantLabel?: string;
203
235
  }
204
236
  /**
205
237
  * Options for creating a new tenant with a single convenience call.
@@ -250,6 +282,12 @@ export interface JoinRequest {
250
282
  * Emitting `2` only for nameless requests keeps older readers from silently
251
283
  * registering an undefined username — they reject the unknown version
252
284
  * instead.
285
+ *
286
+ * The `mdb://join-request/...` transport has a third version that is not
287
+ * visible here: `v: 3` is the compact, PEM-stripped payload written by
288
+ * `encodeJoinRequestUri`. It carries the same information, and
289
+ * `decodeJoinRequestUri` normalizes it back to `1` or `2` depending on
290
+ * whether a username is present.
253
291
  */
254
292
  v: 1 | 2;
255
293
  /**
@@ -268,13 +306,20 @@ export interface JoinRequest {
268
306
  /** RSA-OAEP public encryption key (PEM format) */
269
307
  encryptionPublicKey: string;
270
308
  /**
271
- * Optional human-readable label for this device's signing/encryption key
309
+ * Human-readable label for this device's signing/encryption key
272
310
  * pair (e.g. a date or a note about the device type). Suggested by the
273
311
  * joining user; the approving admin may override it (see
274
- * {@link ApproveJoinRequestOptions.label}). Stored on the grant document's
275
- * key-pair entry and editable later (docs/accesscontrol.md §6.5).
312
+ * {@link ApproveJoinRequestOptions.label}). Required when granting access.
313
+ * Stored on the grant document's key-pair entry and editable later
314
+ * (docs/accesscontrol.md §6.5).
276
315
  */
277
316
  label?: string;
317
+ /**
318
+ * Public half of the joining device's person-bound User-Key (RSA-OAEP 3072
319
+ * PEM). The admin publishes it as a pending `userkey_*` document on approval
320
+ * and wraps `default` to it. Required for a new person's first device.
321
+ */
322
+ userPublicKey?: string;
278
323
  }
279
324
  /**
280
325
  * Options for approving a join request.
@@ -284,8 +329,12 @@ export interface ApproveJoinRequestOptions {
284
329
  adminSigningKey: EncryptedPrivateKey;
285
330
  /** The password to decrypt the admin signing key */
286
331
  adminPassword: string;
287
- /** A shared password for encrypting the exported keys. Must be communicated out-of-band (e.g. phone). */
288
- sharePassword: string;
332
+ /**
333
+ * @deprecated Join responses are RSA-OAEP-wrapped to the requester's
334
+ * `encryptionPublicKey` (v3). Ignored when present; kept so older callers
335
+ * that still pass a share password continue to type-check.
336
+ */
337
+ sharePassword?: string;
289
338
  /** Optional server URL to include in the response so the joining user knows where to sync */
290
339
  serverUrl?: string;
291
340
  /** Optional admin username to include in the response so the joining user can display it */
@@ -299,10 +348,11 @@ export interface ApproveJoinRequestOptions {
299
348
  */
300
349
  sharedDocKeyIds?: string[];
301
350
  /**
302
- * Optional human-readable label for the joining device's key pair. When set,
351
+ * Human-readable label for the joining device's key pair. When set,
303
352
  * it overrides any label the joining user suggested in the join request and
304
353
  * is stored on the grant document's key-pair entry (docs/accesscontrol.md
305
- * §6.5). Useful for recording a date or a note about the device type.
354
+ * §6.5). Required: the join request or this field must supply a non-empty
355
+ * label.
306
356
  */
307
357
  label?: string;
308
358
  /**
@@ -315,14 +365,28 @@ export interface ApproveJoinRequestOptions {
315
365
  * than trusting the requester's spelling (§6.5).
316
366
  */
317
367
  username?: string;
368
+ /**
369
+ * Optional tenant display label to include in the join response. When omitted,
370
+ * `approveJoinRequest` tries to decrypt it from the directory `tenantsetup`
371
+ * doc (`label_encrypted` under the tenant `default` key).
372
+ */
373
+ tenantLabel?: string;
318
374
  /** If "uri", approveJoinRequest returns a mdb://join-response/... URI string instead of an object */
319
375
  format?: "object" | "uri";
320
376
  }
321
377
  export interface JoinResponseEncryptedDocKeyVersion {
322
378
  /** Original KeyBag creation timestamp for this key version, used for rotation ordering. */
323
379
  createdAt?: number;
324
- /** Symmetric document key version encrypted with the shared password. */
325
- encryptedKey: EncryptedPrivateKey;
380
+ /**
381
+ * v2: symmetric document key version encrypted with the sharePassword.
382
+ * Absent on v3 responses.
383
+ */
384
+ encryptedKey?: EncryptedPrivateKey;
385
+ /**
386
+ * v3: raw AES key RSA-OAEP-wrapped to the join requester's
387
+ * `encryptionPublicKey` (standard base64). Absent on v2 responses.
388
+ */
389
+ wrappedKey?: string;
326
390
  }
327
391
  export interface JoinResponseEncryptedDocKey {
328
392
  /** Logical document key id within the tenant, e.g. "$publicinfos", "default", or a named key. */
@@ -335,11 +399,14 @@ export interface JoinResponseEncryptedDocKey {
335
399
  * It contains encrypted symmetric keys and tenant metadata needed to join.
336
400
  *
337
401
  * Can be serialized to a mdb://join-response/... URI for out-of-band exchange.
338
- * The encrypted keys can only be unlocked with the sharePassword communicated separately.
402
+ *
403
+ * v3 wraps each document key to the join requester's RSA encryption public
404
+ * key, so only that device can unwrap the payload — no share password.
405
+ * v2 responses (sharePassword) remain readable for backward compatibility.
339
406
  */
340
407
  export interface JoinResponse {
341
- /** Protocol version. v2 carries versioned document-key bundles. */
342
- v: 2;
408
+ /** Protocol version. v2 is password-wrapped; v3 is RSA-OAEP-wrapped to the requester. */
409
+ v: 2 | 3;
343
410
  /** Tenant identifier */
344
411
  tenantId: string;
345
412
  /** Admin's public signing key (Ed25519, PEM) — needed to open the tenant */
@@ -350,6 +417,13 @@ export interface JoinResponse {
350
417
  serverUrl?: string;
351
418
  /** Optional admin username for display purposes */
352
419
  adminUsername?: string;
420
+ /**
421
+ * Optional human-readable tenant label for display on the joining device.
422
+ * Snapshotted at approve time from `tenantsetup` (or an explicit override).
423
+ * After join, clients should prefer the live directory label (field-encrypted
424
+ * under `default`) when synced.
425
+ */
426
+ tenantLabel?: string;
353
427
  /**
354
428
  * The username the joining device was actually registered as.
355
429
  *
@@ -359,7 +433,7 @@ export interface JoinResponse {
359
433
  * requester keeps the name it chose itself.
360
434
  */
361
435
  username?: string;
362
- /** Selected tenant document keys, encrypted with the sharePassword. */
436
+ /** Selected tenant document keys. v3: RSA-wrapped; v2: sharePassword-encrypted. */
363
437
  encryptedDocKeys: JoinResponseEncryptedDocKey[];
364
438
  }
365
439
  /**
@@ -380,8 +454,11 @@ export interface JoinTenantOptions {
380
454
  * callers may pass an empty string.
381
455
  */
382
456
  password: string;
383
- /** The shared password used to decrypt the keys in the join response */
384
- sharePassword: string;
457
+ /**
458
+ * The shared password used to decrypt v2 join responses.
459
+ * Unused for v3 (RSA-wrapped) responses; callers may omit it.
460
+ */
461
+ sharePassword?: string;
385
462
  /**
386
463
  * Optional pre-existing {@link KeyBag} to extend with the joined tenant's
387
464
  * keys. When supplied, `joinTenant` will mutate this bag in place (adding
@@ -424,6 +501,58 @@ export interface JoinTenantResult {
424
501
  */
425
502
  user: PrivateUserId;
426
503
  }
504
+ /**
505
+ * One tenant delivered by `POST /device/discover` after device-key proof.
506
+ * No cleartext label or username — those arrive RSA-hybrid-wrapped to this
507
+ * device (`wrappedJoinResponse`) and/or later via `tenantsetup` under `default`.
508
+ */
509
+ export interface DeviceTenantDelivery {
510
+ tenantId: string;
511
+ adminSigningPublicKey: string;
512
+ adminEncryptionPublicKey: string;
513
+ /** AES `$publicinfos` RSA-OAEP-wrapped to this device's encryption public key (base64). */
514
+ wrappedPublicInfosKey: string;
515
+ /** All `$publicinfos` versions, oldest first. `wrappedPublicInfosKey` is the newest. */
516
+ wrappedPublicInfosKeys?: string[];
517
+ /**
518
+ * Per-device join bootstrap from the grant (`userKeyPairs[].joinResponseWrapped`):
519
+ * username + optional tenantLabel/adminUsername, RSA-hybrid-encrypted to this
520
+ * device. Opaque to the server; the joining device unwraps it locally.
521
+ */
522
+ wrappedJoinResponse?: string;
523
+ username_hash?: string;
524
+ identity_hashes?: string[];
525
+ }
526
+ export interface DiscoverTenantsOnServerOptions {
527
+ user: PrivateUserId;
528
+ password: string;
529
+ /** When set, skip password-decrypt of the signing key. */
530
+ preDecryptedUserKeys?: PreDecryptedUserKeys;
531
+ }
532
+ export interface BootstrapTenantFromDeliveryOptions {
533
+ user: PrivateUserId;
534
+ password: string;
535
+ existingKeyBag?: KeyBag;
536
+ preDecryptedUserKeys?: PreDecryptedUserKeys;
537
+ /**
538
+ * When set, pull the directory from this server URL after open and run
539
+ * key-distribution reconcile (imports `default`, may adopt username).
540
+ */
541
+ serverUrl?: string;
542
+ }
543
+ export interface BootstrapTenantFromDeliveryResult {
544
+ tenant: MindooTenant;
545
+ keyBag: KeyBag;
546
+ user: PrivateUserId;
547
+ /** Display label after `default` import + `tenantsetup` decrypt, if available. */
548
+ tenantLabel?: string;
549
+ /**
550
+ * Display name of the approving admin, snapshotted into the per-device join
551
+ * bootstrap at approve time. Absent for grants written before this field or
552
+ * when the admin approved without passing a name.
553
+ */
554
+ adminUsername?: string;
555
+ }
427
556
  /**
428
557
  * Options for publishing a tenant to a server.
429
558
  */
@@ -534,18 +663,39 @@ export interface MindooTenantFactory {
534
663
  format?: "object" | "uri";
535
664
  label?: string;
536
665
  }): JoinRequest | string;
666
+ /**
667
+ * Generate a person-bound User-Key on `user` if it does not already have one.
668
+ * The private half is password-encrypted with salt `"userkey"` and stored on
669
+ * the identity so paper backup includes it.
670
+ */
671
+ ensureUserKeyPair?(user: PrivateUserId, password: string): Promise<EncryptionKeyPair>;
537
672
  /**
538
673
  * Join a tenant using a join response from an admin.
539
674
  * This orchestrates:
540
675
  * 1. Parsing the join response (object or mdb:// URI string)
541
- * 2. Creating a new KeyBag and importing the encrypted keys
676
+ * 2. Creating a new KeyBag and importing the encrypted keys (RSA unwrap for
677
+ * v3, sharePassword for legacy v2)
542
678
  * 3. Opening the tenant with the admin public keys from the response
543
679
  *
544
680
  * @param joinResponse A JoinResponse object or a mdb://join-response/... URI string
545
- * @param options Options including the user's identity, password, and the shared password
681
+ * @param options Options including the user's identity and password
546
682
  * @return The opened tenant and KeyBag
547
683
  */
548
684
  joinTenant(joinResponse: JoinResponse | string, options: JoinTenantOptions): Promise<JoinTenantResult>;
685
+ /**
686
+ * Prove possession of the device signing key against a MindooDB server and
687
+ * receive every local tenant where that key has an active grant, each with
688
+ * RSA-wrapped `$publicinfos`, admin public keys, and the per-device join
689
+ * bootstrap (username / tenant label) when the grant carries it.
690
+ */
691
+ discoverTenantsOnServer?(serverUrl: string, options: DiscoverTenantsOnServerOptions): Promise<DeviceTenantDelivery[]>;
692
+ /**
693
+ * Bootstrap a local tenant from a {@link DeviceTenantDelivery}: unwrap
694
+ * `$publicinfos`, adopt username from `wrappedJoinResponse` when present,
695
+ * open the tenant, optionally pull the directory and reconcile key
696
+ * distributions (`default`).
697
+ */
698
+ bootstrapTenantFromDelivery?(delivery: DeviceTenantDelivery, options: BootstrapTenantFromDeliveryOptions): Promise<BootstrapTenantFromDeliveryResult>;
549
699
  }
550
700
  /**
551
701
  * A MindooTenant contains multiple MindooDB in an organization. One MindooDB is a mandatory part
@@ -564,7 +714,7 @@ export interface MindooTenant {
564
714
  */
565
715
  getFactory(): MindooTenantFactory;
566
716
  /**
567
- * Get the ID of the tenant (UUID7 format)
717
+ * Get the ID of the tenant (lowercase MongoDB-style ObjectId when auto-generated)
568
718
  *
569
719
  * @return The ID of the tenant
570
720
  */
@@ -629,10 +779,16 @@ export interface MindooTenant {
629
779
  * This is used for operations that need to sign with a different key than the current user's,
630
780
  * such as directory operations that must be signed with the administration key.
631
781
  *
782
+ * After signing, the signature is verified against `signingKeyPair.publicKey`.
783
+ * A mismatch (claimed admin PEM + unrelated private key) throws — this is what
784
+ * keeps admin-only directory writes from succeeding locally when the wrong
785
+ * identity is supplied.
786
+ *
632
787
  * @param payload The payload to sign (binary data)
633
788
  * @param signingKeyPair The signing key pair to use (Ed25519)
634
789
  * @param password The password to decrypt the signing private key
635
790
  * @return The signature (Ed25519 signature as Uint8Array)
791
+ * @throws when the decrypted private key does not correspond to `publicKey`
636
792
  */
637
793
  signPayloadWithKey(payload: Uint8Array, signingKeyPair: SigningKeyPair, password: string): Promise<Uint8Array>;
638
794
  /**
@@ -759,6 +915,7 @@ export interface MindooTenant {
759
915
  reconcileKeyDistributionsForCurrentUser?(): Promise<{
760
916
  imported: string[];
761
917
  removed: string[];
918
+ adoptedUsername?: string;
762
919
  }>;
763
920
  /**
764
921
  * Return whether the current KeyBag can resolve the given document
@@ -767,6 +924,13 @@ export interface MindooTenant {
767
924
  * result as a guard before attempting decryption.
768
925
  */
769
926
  hasDecryptionKey?(decryptionKeyId: string): Promise<boolean>;
927
+ rememberSealedGenerations?(keyId: string, generations: Uint8Array[]): void;
928
+ getSealedGenerations?(keyId: string): Uint8Array[];
929
+ ingestSealedRecipients?(keyId: string, recipients: import("./userkeys/sealedTypes").EntryRecipients): Promise<void>;
930
+ ingestSealedFromEntries?(keyId: string, entries: Array<{
931
+ recipients?: import("./userkeys/sealedTypes").EntryRecipients;
932
+ createdAt: number;
933
+ }>): Promise<void>;
770
934
  /**
771
935
  * Return a stable, opaque fingerprint of the doc keys this tenant
772
936
  * currently has access to. The fingerprint must change whenever the
@@ -796,17 +960,36 @@ export interface MindooTenant {
796
960
  * This orchestrates:
797
961
  * 1. Parsing the join request (object or mdb:// URI string)
798
962
  * 2. Registering the user in the tenant directory
799
- * 3. Exporting selected document keys, encrypted with the sharePassword
800
- * 4. Packaging everything into a JoinResponse
963
+ * 3. Exporting selected document keys, RSA-OAEP-wrapped to the requester
964
+ * 4. Packaging everything into a JoinResponse (v3)
801
965
  *
802
966
  * @param joinRequest A JoinRequest object or a mdb://join-request/... URI string
803
- * @param options Options including admin key, share password, and optional server URL
967
+ * @param options Options including admin key and optional server URL
804
968
  * @return A JoinResponse object, or a mdb://join-response/... URI string if format is "uri"
805
969
  */
806
970
  approveJoinRequest(joinRequest: JoinRequest | string, options: ApproveJoinRequestOptions & {
807
971
  format: "uri";
808
972
  }): Promise<string>;
809
973
  approveJoinRequest(joinRequest: JoinRequest | string, options: ApproveJoinRequestOptions): Promise<JoinResponse>;
974
+ /** Devices on this person's grant that still need a User-Key wrap. */
975
+ listPendingUserKeyDevices?(): Promise<import("./userkeys/types").PendingUserKeyDevice[]>;
976
+ listUserKeyDevices?(): Promise<import("./userkeys/types").UserKeyDeviceRow[]>;
977
+ approveUserKeyDevice?(fingerprint: string): Promise<void>;
978
+ declineUserKeyDevice?(fingerprint: string): Promise<void>;
979
+ undoDeclineUserKeyDevice?(fingerprint: string): Promise<void>;
980
+ rotateUserKey?(): Promise<void>;
981
+ reconcileUserKeys?(options?: {
982
+ allowSelfCreate?: boolean;
983
+ }): Promise<import("./userkeys/types").UserKeyEnrollmentStatus>;
984
+ getUserKeyEnrollmentStatus?(): Promise<import("./userkeys/types").UserKeyEnrollmentStatus>;
985
+ noteUserDirectoryFetched?(): void;
986
+ noteUserDirectoryFetchFailed?(error: unknown): void;
987
+ ensureLocalUserKeyPair?(): Promise<void>;
988
+ getUserKeyManager(): import("./userkeys/UserKeyManager").UserKeyManager;
989
+ isDatabaseOpen?(dbId: string): boolean;
990
+ isDatabaseReady?(dbId: string): boolean;
991
+ scheduleUserKeyReconcile?(): void;
992
+ reconcileUserKeysSafe?(): Promise<void>;
810
993
  /**
811
994
  * Publish (register) this tenant on a MindooDB server.
812
995
  * Sends an HTTP POST to the server's /admin/register-tenant endpoint
@@ -868,7 +1051,7 @@ export interface StoreEntryMetadata {
868
1051
  /**
869
1052
  * Unique identifier for this entry (primary key in the store).
870
1053
  * - For doc_* entries: "<docId>_d_<depsFingerprint>_<automergeHash>"
871
- * - For attachment_chunk: "<docId>_a_<fileUuid7>_<base62ChunkUuid7>"
1054
+ * - For attachment_chunk: "<docId>_a_<fileUuid7>_<chunkObjectId>"
872
1055
  *
873
1056
  * The structured ID format enables:
874
1057
  * - Guaranteed uniqueness across documents
@@ -1001,6 +1184,18 @@ export interface StoreEntryMetadata {
1001
1184
  * on-disk, IndexedDB and network serializers without per-field binary handling.
1002
1185
  */
1003
1186
  provenance?: EntryProvenance;
1187
+ /**
1188
+ * Sealed-document recipient block (docs/userkeys.md §9.7). Present only on
1189
+ * entries that change the recipient set. Bound into `metadataSignature` as
1190
+ * tagged trailing block `0x03`.
1191
+ *
1192
+ * Plain JSON (wraps carry base64 ciphertext) so it survives the on-disk,
1193
+ * IndexedDB and network serializers without per-field binary handling. The
1194
+ * HTTP codec MUST include this field: dropping it on the wire makes the
1195
+ * server rebuild signing bytes without the recipients block and reject the
1196
+ * entry as an invalid author signature.
1197
+ */
1198
+ recipients?: import("./userkeys/sealedTypes").EntryRecipients;
1004
1199
  /**
1005
1200
  * Original size of the plaintext data before encryption (in bytes).
1006
1201
  * For doc_* entries: size of the Automerge binary change/snapshot
@@ -1386,17 +1581,17 @@ export interface SnapshotConfig {
1386
1581
  /**
1387
1582
  * Regex used to validate caller-provided MindooDoc IDs.
1388
1583
  *
1389
- * The first character must be an ASCII letter; subsequent characters may be
1390
- * ASCII letters, ASCII digits, or `_`. This keeps caller-provided IDs safe to
1391
- * use unmodified in content-addressed store entry IDs and on disk.
1584
+ * The first character must be an ASCII lowercase letter; subsequent characters
1585
+ * may be ASCII lowercase letters, ASCII digits, or `_`. Lowercase-only keeps
1586
+ * caller-provided IDs safe on case-insensitive filesystems (Windows / APFS).
1392
1587
  */
1393
1588
  export declare const CUSTOM_DOC_ID_REGEX: RegExp;
1394
1589
  /**
1395
1590
  * Regex used to validate `CreateOptions.idPrefix`.
1396
1591
  *
1397
- * A prefix is a short (1–10 chars) ASCII-alphanumeric tag starting with a
1398
- * letter, e.g. `"cls"`. It must NOT contain `_` — MindooDB appends the `_`
1399
- * separator itself when building the final id `<prefix>_<22-char-base62>`.
1592
+ * A prefix is a short (1–10 chars) ASCII-alphanumeric lowercase tag starting
1593
+ * with a letter, e.g. `"cls"`. It must NOT contain `_` — MindooDB appends the
1594
+ * `_` separator itself when building the final id `<prefix>_<24-char-objectid>`.
1400
1595
  */
1401
1596
  export declare const DOC_ID_PREFIX_REGEX: RegExp;
1402
1597
  /**
@@ -1405,7 +1600,7 @@ export declare const DOC_ID_PREFIX_REGEX: RegExp;
1405
1600
  export interface CreateOptions {
1406
1601
  /**
1407
1602
  * Caller-provided document ID. When provided it must match
1408
- * `^[A-Za-z][A-Za-z0-9_]*$` (see `CUSTOM_DOC_ID_REGEX`). When omitted, a fresh
1603
+ * `^[a-z][a-z0-9_]*$` (see `CUSTOM_DOC_ID_REGEX`). When omitted, a fresh
1409
1604
  * time-sortable ID is generated (see `idPrefix` for the format).
1410
1605
  *
1411
1606
  * If a document with this ID already exists locally, `createDocument()`
@@ -1435,10 +1630,10 @@ export interface CreateOptions {
1435
1630
  */
1436
1631
  assumeUniqueId?: boolean;
1437
1632
  /**
1438
- * Optional short prefix (1–10 ASCII-alphanumeric chars, starting with a
1439
- * letter; see `DOC_ID_PREFIX_REGEX`) for a MindooDB-generated document ID.
1440
- * The final ID is `<idPrefix>_<22-char-base62(uuidv7)>`, e.g.
1441
- * `cls_0BqXa9yTFn2M4kVzR1sWpq` — time-sortable within the same prefix.
1633
+ * Optional short lowercase prefix (1–10 ASCII-alphanumeric chars, starting
1634
+ * with a letter; see `DOC_ID_PREFIX_REGEX`) for a MindooDB-generated document
1635
+ * ID. The final ID is `<idPrefix>_<24-char-objectid>`, e.g.
1636
+ * `cls_507f1f77bcf86cd799439011` — time-sortable within the same prefix.
1442
1637
  *
1443
1638
  * Unlike a custom `id`, uniqueness is guaranteed by MindooDB itself, so the
1444
1639
  * create follows the generated-ID code path: a single `doc_create` entry
@@ -1453,6 +1648,17 @@ export interface CreateOptions {
1453
1648
  * (the tenant key). Replaces `createEncryptedDocument(decryptionKeyId)`.
1454
1649
  */
1455
1650
  decryptionKeyId?: string;
1651
+ /**
1652
+ * Readers of this document. Mutually exclusive with `decryptionKeyId`.
1653
+ * A fresh document key is generated and sealed to each recipient. User
1654
+ * names are canonicalized (`CN=alice/O=contoso`, case-insensitive) and
1655
+ * must include `O=` — the tenant id is not substituted for the organization.
1656
+ * Directory groups are not a recipient target: list the people who should
1657
+ * read the document so `_encryptFor` stays an explicit, queryable set.
1658
+ * The author is included unless `recipientOptions.includeSelf` is false.
1659
+ */
1660
+ recipients?: import("./userkeys/sealedTypes").RecipientSpec[];
1661
+ recipientOptions?: import("./userkeys/sealedTypes").RecipientOptions;
1456
1662
  /**
1457
1663
  * Optional signing key pair to sign the initial document entry with. When
1458
1664
  * provided, `signingKeyPassword` must be provided as well. Replaces
@@ -1547,7 +1753,7 @@ export interface ListDocumentIdsOptions {
1547
1753
  /**
1548
1754
  * Restrict the result to documents whose id matches this prefix. Matching is
1549
1755
  * boundary-aware: an id matches when it equals `idPrefix` exactly or begins
1550
- * with `<idPrefix>_`, mirroring the `<prefix>_<base62>` id scheme produced by
1756
+ * with `<idPrefix>_`, mirroring the `<prefix>_<objectId>` id scheme produced by
1551
1757
  * `createDocument({ idPrefix })`. So `"cls"` matches `cls_…` documents but not
1552
1758
  * an unrelated `classroom_…` id. Omit (or pass an empty string) for no filter.
1553
1759
  */
@@ -1685,6 +1891,16 @@ export interface MindooDoc {
1685
1891
  * inaccessible-key tombstone.
1686
1892
  */
1687
1893
  isAccessible(): boolean;
1894
+ isSealed(): boolean;
1895
+ getRecipients(): import("./userkeys/sealedTypes").ResolvedRecipient[];
1896
+ getRecipientEpoch(): number;
1897
+ /**
1898
+ * True when this document uses a per-document sealed key (`$sealed:…`) and
1899
+ * every listed user has an active `_encryptFor` entry with a DEK wrap.
1900
+ * Usernames are matched case-insensitively after canonicalization
1901
+ * (`CN=alice/O=contoso`) and must include `O=`.
1902
+ */
1903
+ isEncryptedFor(users: string | string[]): boolean;
1688
1904
  /**
1689
1905
  * Whether this document is still "awaiting witness": it has at least one
1690
1906
  * versioned store entry (written in the witness-aware era) that has not yet
@@ -2164,6 +2380,14 @@ export interface DirectoryUserLookup {
2164
2380
  * flag the grant for backfill.
2165
2381
  */
2166
2382
  identityHashesV?: number;
2383
+ /**
2384
+ * RSA-hybrid ciphertext of `{ username, tenantLabel?, adminUsername? }`
2385
+ * wrapped to this device's encryption public key. `$publicinfos`-readable
2386
+ * (the server forwards it during discovery) but not decryptable without the
2387
+ * device private key. Absent on grants written before per-device join
2388
+ * bootstrap.
2389
+ */
2390
+ joinResponseWrapped?: string;
2167
2391
  }
2168
2392
  /**
2169
2393
  * A single device's key pair on a grant document (docs/accesscontrol.md §6.5).
@@ -2188,6 +2412,13 @@ export interface GrantKeyPair {
2188
2412
  encryptionPublicKey: string;
2189
2413
  /** Optional human-readable label for this device/key pair. */
2190
2414
  label?: string;
2415
+ /**
2416
+ * Trusted-time (ms since Unix epoch) at which this device was added to the
2417
+ * grant (first registration or later multi-device append). Retained when the
2418
+ * device is revoked so admin UIs can still show when it was granted. Optional
2419
+ * for legacy grants written before this field existed.
2420
+ */
2421
+ addedAt?: number;
2191
2422
  /**
2192
2423
  * When true, this device's access has been revoked but the pair is RETAINED
2193
2424
  * on the grant document (docs/accesscontrol.md §6.5) so admin UIs can list
@@ -2201,6 +2432,13 @@ export interface GrantKeyPair {
2201
2432
  * together with {@link revoked}; cleared when the device is restored.
2202
2433
  */
2203
2434
  revokedAt?: number;
2435
+ /**
2436
+ * RSA-hybrid ciphertext of `{ username, tenantLabel?, adminUsername? }`
2437
+ * wrapped to this device's encryption public key. Lives on the `$publicinfos`
2438
+ * grant envelope so discovery can deliver the registered name without
2439
+ * `default`.
2440
+ */
2441
+ joinResponseWrapped?: string;
2204
2442
  }
2205
2443
  /** A {@link GrantKeyPair} enriched with its current remote-wipe status (§6.5). */
2206
2444
  export interface GrantKeyPairInfo extends GrantKeyPair {
@@ -2222,10 +2460,13 @@ export interface MindooTenantDirectory {
2222
2460
  * @param administrationPrivateKey The administration private key to sign the registration operation with (signing only)
2223
2461
  * @param administrationPrivateKeyPassword The password to decrypt the administration private key
2224
2462
  * @param userDetails The user details to register (ignored when appending a device to an existing grant)
2225
- * @param label Optional device label for this key pair (§6.5)
2463
+ * @param label Device label for this key pair (§6.5). Optional for existing
2464
+ * test/register paths; required when granting access via {@link MindooTenant.approveJoinRequest}.
2226
2465
  * @return A promise that resolves when the user is registered
2227
2466
  */
2228
- registerUser(userId: PublicUserId, administrationPrivateKey: EncryptedPrivateKey, administrationPrivateKeyPassword: string, userDetails?: DirectoryUserDetails, label?: string): Promise<void>;
2467
+ registerUser(userId: PublicUserId, administrationPrivateKey: EncryptedPrivateKey, administrationPrivateKeyPassword: string, userDetails?: DirectoryUserDetails, label?: string, options?: {
2468
+ distributeKeyIds?: string[];
2469
+ }): Promise<void>;
2229
2470
  /**
2230
2471
  * Revokes a user's access by removing their keys from the grant document
2231
2472
  * (docs/accesscontrol.md §6.5). Revocation is an in-place edit of the grant
@@ -2535,6 +2776,27 @@ export interface MindooTenantDirectory {
2535
2776
  beforeDoc: Record<string, unknown> | null;
2536
2777
  afterDoc: Record<string, unknown> | null;
2537
2778
  }): Promise<AccessDecision>;
2779
+ /**
2780
+ * Whether two signing keys belong to the same person (same `username_hash`
2781
+ * grant) when resolved at the given trusted times. Used to evaluate `$author`
2782
+ * at grant level rather than device-key equality.
2783
+ *
2784
+ * The creator is resolved at `creatorTrustedTime` (typically the trusted time
2785
+ * of the `doc_create` entry) so authorship survives retirement of the
2786
+ * creating device. The signer is resolved at `signerTrustedTime` so a
2787
+ * revoked device cannot act as `$author`.
2788
+ */
2789
+ isSamePerson?(input: {
2790
+ creatorSigningKey: string;
2791
+ signerSigningKey: string;
2792
+ creatorTrustedTime: number;
2793
+ signerTrustedTime: number;
2794
+ }): Promise<boolean>;
2795
+ /**
2796
+ * The `username_hash` of the grant that contained `signingKey` at trusted
2797
+ * time `T`, or `null` when the key was not an active grant member then.
2798
+ */
2799
+ resolveUsernameHashForSigningKey?(signingKey: string, trustedTime: number): Promise<string | null>;
2538
2800
  /**
2539
2801
  * Whether a Tier 2 (`withfields`) content rule exists for `op` on `dbid` at
2540
2802
  * the current head state. Lets callers skip materializing before/after
@@ -2571,6 +2833,7 @@ export interface MindooTenantDirectory {
2571
2833
  * @returns The salted, normalized username hash.
2572
2834
  */
2573
2835
  getUsernameHash?(username: string): Promise<string>;
2836
+ getUsernameHashCandidates?(username: string): Promise<string[]>;
2574
2837
  /**
2575
2838
  * All ACTIVE (non-revoked) RSA encryption public keys (PEM) for `username` —
2576
2839
  * one per active device. Used to wrap a key for every device of a recipient.
@@ -2590,6 +2853,13 @@ export interface MindooTenantDirectory {
2590
2853
  * @returns The recipient's wrapped device material.
2591
2854
  */
2592
2855
  wrapKeyForUserDevices?(keyId: string, username: string): Promise<KeyDistributionPushRecipient>;
2856
+ wrapKeyForUser?(keyId: string, username: string, publicKeyOverride?: string): Promise<KeyDistributionPushRecipient | null>;
2857
+ /**
2858
+ * Merge `username` into each listed key-distribution document, wrapping to
2859
+ * the person's published User-Key. Users without a published User-Key are
2860
+ * skipped (pending), not wrapped to device keys.
2861
+ */
2862
+ autoDistributeKeysToUser?(username: string, keyIds: string[], administrationPrivateKey: EncryptedPrivateKey, administrationPrivateKeyPassword: string, publicKeyOverride?: string): Promise<void>;
2593
2863
  /**
2594
2864
  * The version manifest (`{createdAt, fingerprint}`) of `keyId` from the
2595
2865
  * caller's KeyBag — the source of truth for a distribution's `keyVersions`.
@@ -2762,6 +3032,7 @@ export interface MindooTenantDirectory {
2762
3032
  encryptionPublicKey: string;
2763
3033
  details?: DirectoryUserDetails | null;
2764
3034
  } | null>;
3035
+ findGrantAccessDocuments?(username: string): Promise<MindooDoc[]>;
2765
3036
  /**
2766
3037
  * Look up a user by their public signing key.
2767
3038
  * This is useful for reverse-resolving historical change authors to friendly labels.
@@ -2883,10 +3154,10 @@ export interface MindooTenantDirectory {
2883
3154
  * Returns the database IDs currently known to the directory.
2884
3155
  *
2885
3156
  * This is intended for admin tooling and overview UIs. The result always includes
2886
- * `"directory"` and will also include `"main"` as the conventional default app DB.
2887
- * Additional DBs are discovered from `dbsettings` documents stored in the directory.
3157
+ * `"directory"`. Additional DBs are discovered from `dbsettings` documents stored
3158
+ * in the directory.
2888
3159
  *
2889
- * @returns The database ids known to the directory (always including `"directory"` and `"main"`).
3160
+ * @returns The database ids known to the directory (always including `"directory"`).
2890
3161
  */
2891
3162
  listKnownDBIds(): Promise<string[]>;
2892
3163
  /**
@@ -4139,6 +4410,25 @@ export interface MindooDB {
4139
4410
  * @param signingKeyPair Optional custom signing key (matches `changeDoc`).
4140
4411
  */
4141
4412
  canChange(doc: MindooDoc, candidateAfter: Record<string, unknown>, signingKeyPair?: SigningKeyPair): Promise<AccessDecision>;
4413
+ /**
4414
+ * Add readers to a sealed document. Cheap: one RSA wrap per new user, no
4415
+ * rotation. The new readers can decrypt the whole history. Names are
4416
+ * canonicalized (`CN=alice/O=contoso`) and matched case-insensitively;
4417
+ * they must include `O=`.
4418
+ */
4419
+ addRecipients(doc: MindooDoc, recipients: import("./userkeys/sealedTypes").RecipientSpec[], options?: import("./userkeys/sealedTypes").RecipientChangeOptions): Promise<import("./userkeys/sealedTypes").RecipientChangeResult>;
4420
+ /**
4421
+ * Drop readers from a sealed document. Rotates the document key: removed
4422
+ * readers keep what they already have, and cannot read later changes.
4423
+ * Names are canonicalized and matched case-insensitively.
4424
+ */
4425
+ removeRecipients(doc: MindooDoc, recipients: import("./userkeys/sealedTypes").RecipientSpec[], options?: import("./userkeys/sealedTypes").RecipientChangeOptions): Promise<import("./userkeys/sealedTypes").RecipientChangeResult>;
4426
+ /**
4427
+ * Replace the recipient list. Diffs against the current set: additions wrap,
4428
+ * removals rotate. The author stays on the list unless `includeSelf: false`.
4429
+ */
4430
+ setRecipients(doc: MindooDoc, recipients: import("./userkeys/sealedTypes").RecipientSpec[], options?: import("./userkeys/sealedTypes").RecipientChangeOptions): Promise<import("./userkeys/sealedTypes").RecipientChangeResult>;
4431
+ canChangeRecipients(doc: MindooDoc, next: import("./userkeys/sealedTypes").RecipientSpec[]): Promise<AccessDecision>;
4142
4432
  /**
4143
4433
  * Predict whether deleting `doc` via `deleteDocument` would be allowed by the
4144
4434
  * active write policy, without writing.