mindoodb 0.0.51 → 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 (185) 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 +57 -0
  15. package/dist/core/BaseMindooDB.d.ts +85 -10
  16. package/dist/core/BaseMindooDB.d.ts.map +1 -1
  17. package/dist/core/BaseMindooDB.js +687 -196
  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 +407 -86
  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 +286 -17
  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 +2 -1
  43. package/dist/core/accesscontrol/types.d.ts.map +1 -1
  44. package/dist/core/accesscontrol/types.js +3 -2
  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 +6 -1
  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 +7 -0
  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/index.d.ts +7 -3
  89. package/dist/core/index.d.ts.map +1 -1
  90. package/dist/core/index.js +30 -4
  91. package/dist/core/index.js.map +1 -1
  92. package/dist/core/join/deviceJoinBootstrap.d.ts +23 -0
  93. package/dist/core/join/deviceJoinBootstrap.d.ts.map +1 -0
  94. package/dist/core/join/deviceJoinBootstrap.js +37 -0
  95. package/dist/core/join/deviceJoinBootstrap.js.map +1 -0
  96. package/dist/core/keys/KeyBag.d.ts +20 -2
  97. package/dist/core/keys/KeyBag.d.ts.map +1 -1
  98. package/dist/core/keys/KeyBag.js +22 -10
  99. package/dist/core/keys/KeyBag.js.map +1 -1
  100. package/dist/core/logging/MindooLogger.d.ts.map +1 -1
  101. package/dist/core/logging/MindooLogger.js +65 -40
  102. package/dist/core/logging/MindooLogger.js.map +1 -1
  103. package/dist/core/tenantIdValidation.d.ts.map +1 -1
  104. package/dist/core/tenantIdValidation.js +1 -1
  105. package/dist/core/tenantIdValidation.js.map +1 -1
  106. package/dist/core/tenantSetup.d.ts +94 -9
  107. package/dist/core/tenantSetup.d.ts.map +1 -1
  108. package/dist/core/tenantSetup.js +208 -20
  109. package/dist/core/tenantSetup.js.map +1 -1
  110. package/dist/core/types.d.ts +295 -33
  111. package/dist/core/types.d.ts.map +1 -1
  112. package/dist/core/types.js +14 -1
  113. package/dist/core/types.js.map +1 -1
  114. package/dist/core/uri/joinRequestUri.d.ts.map +1 -1
  115. package/dist/core/uri/joinRequestUri.js +12 -3
  116. package/dist/core/uri/joinRequestUri.js.map +1 -1
  117. package/dist/core/userid/canonicalUsername.d.ts +66 -0
  118. package/dist/core/userid/canonicalUsername.d.ts.map +1 -0
  119. package/dist/core/userid/canonicalUsername.js +235 -0
  120. package/dist/core/userid/canonicalUsername.js.map +1 -0
  121. package/dist/core/userid/index.d.ts +9 -0
  122. package/dist/core/userid/index.d.ts.map +1 -1
  123. package/dist/core/userid/index.js +14 -0
  124. package/dist/core/userid/index.js.map +1 -1
  125. package/dist/core/userkeys/UserKeyDocument.d.ts +50 -0
  126. package/dist/core/userkeys/UserKeyDocument.d.ts.map +1 -0
  127. package/dist/core/userkeys/UserKeyDocument.js +145 -0
  128. package/dist/core/userkeys/UserKeyDocument.js.map +1 -0
  129. package/dist/core/userkeys/UserKeyManager.d.ts +170 -0
  130. package/dist/core/userkeys/UserKeyManager.d.ts.map +1 -0
  131. package/dist/core/userkeys/UserKeyManager.js +1277 -0
  132. package/dist/core/userkeys/UserKeyManager.js.map +1 -0
  133. package/dist/core/userkeys/fingerprint.d.ts +17 -0
  134. package/dist/core/userkeys/fingerprint.d.ts.map +1 -0
  135. package/dist/core/userkeys/fingerprint.js +59 -0
  136. package/dist/core/userkeys/fingerprint.js.map +1 -0
  137. package/dist/core/userkeys/index.d.ts +11 -0
  138. package/dist/core/userkeys/index.d.ts.map +1 -0
  139. package/dist/core/userkeys/index.js +49 -0
  140. package/dist/core/userkeys/index.js.map +1 -0
  141. package/dist/core/userkeys/recipients.d.ts +51 -0
  142. package/dist/core/userkeys/recipients.d.ts.map +1 -0
  143. package/dist/core/userkeys/recipients.js +292 -0
  144. package/dist/core/userkeys/recipients.js.map +1 -0
  145. package/dist/core/userkeys/resolveUserKeyDocument.d.ts +21 -0
  146. package/dist/core/userkeys/resolveUserKeyDocument.d.ts.map +1 -0
  147. package/dist/core/userkeys/resolveUserKeyDocument.js +98 -0
  148. package/dist/core/userkeys/resolveUserKeyDocument.js.map +1 -0
  149. package/dist/core/userkeys/sealedCrypto.d.ts +21 -0
  150. package/dist/core/userkeys/sealedCrypto.d.ts.map +1 -0
  151. package/dist/core/userkeys/sealedCrypto.js +79 -0
  152. package/dist/core/userkeys/sealedCrypto.js.map +1 -0
  153. package/dist/core/userkeys/sealedTypes.d.ts +72 -0
  154. package/dist/core/userkeys/sealedTypes.d.ts.map +1 -0
  155. package/dist/core/userkeys/sealedTypes.js +14 -0
  156. package/dist/core/userkeys/sealedTypes.js.map +1 -0
  157. package/dist/core/userkeys/types.d.ts +70 -0
  158. package/dist/core/userkeys/types.d.ts.map +1 -0
  159. package/dist/core/userkeys/types.js +48 -0
  160. package/dist/core/userkeys/types.js.map +1 -0
  161. package/dist/core/userkeys/validateUserKeyDocument.d.ts +19 -0
  162. package/dist/core/userkeys/validateUserKeyDocument.d.ts.map +1 -0
  163. package/dist/core/userkeys/validateUserKeyDocument.js +42 -0
  164. package/dist/core/userkeys/validateUserKeyDocument.js.map +1 -0
  165. package/dist/node/server/CapabilityMatcher.d.ts +5 -0
  166. package/dist/node/server/CapabilityMatcher.d.ts.map +1 -1
  167. package/dist/node/server/CapabilityMatcher.js +10 -1
  168. package/dist/node/server/CapabilityMatcher.js.map +1 -1
  169. package/dist/node/server/DeviceDiscoveryService.d.ts +36 -0
  170. package/dist/node/server/DeviceDiscoveryService.d.ts.map +1 -0
  171. package/dist/node/server/DeviceDiscoveryService.js +165 -0
  172. package/dist/node/server/DeviceDiscoveryService.js.map +1 -0
  173. package/dist/node/server/MindooDBServer.d.ts +13 -0
  174. package/dist/node/server/MindooDBServer.d.ts.map +1 -1
  175. package/dist/node/server/MindooDBServer.js +99 -61
  176. package/dist/node/server/MindooDBServer.js.map +1 -1
  177. package/dist/node/server/SystemAdminAuth.d.ts +7 -0
  178. package/dist/node/server/SystemAdminAuth.d.ts.map +1 -1
  179. package/dist/node/server/SystemAdminAuth.js +4 -1
  180. package/dist/node/server/SystemAdminAuth.js.map +1 -1
  181. package/dist/node/server/TenantManager.d.ts +29 -0
  182. package/dist/node/server/TenantManager.d.ts.map +1 -1
  183. package/dist/node/server/TenantManager.js +146 -7
  184. package/dist/node/server/TenantManager.js.map +1 -1
  185. package/package.json +5 -5
@@ -37,6 +37,19 @@ export declare const TENANT_SETUP_DOC_ID = "tenantsetup";
37
37
  * KeyBag location: type "doc", id DEFAULT_TENANT_KEY_ID.
38
38
  */
39
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";
40
53
  /**
41
54
  * JSON payload returned by `GET /.well-known/mindoodb-server-info`.
42
55
  */
@@ -159,6 +172,14 @@ export interface PreDecryptedUserKeys {
159
172
  * `EncryptedLocalCacheStore` performs internally.
160
173
  */
161
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;
162
183
  }
163
184
  interface CreateTenantPasswords {
164
185
  /** Password for the admin user's private keys */
@@ -167,10 +188,10 @@ interface CreateTenantPasswords {
167
188
  * Password for the regular (app) user's private keys.
168
189
  *
169
190
  * When {@link existingKeyBag} **and** {@link preDecryptedAppUserKeys}
170
- * are both supplied the password is no longer needed by `createTenant`
171
- * (the bag has already been wrapped, and `openTenant` consumes the
172
- * pre-imported `CryptoKey`s directly). Callers in that live-bag mode
173
- * 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.
174
195
  */
175
196
  userPassword: string;
176
197
  /**
@@ -207,8 +228,8 @@ interface CreateTenantPasswords {
207
228
  requireV2Entries?: boolean;
208
229
  /**
209
230
  * Optional human-readable tenant label stored in the directory document
210
- * `tenantsetup` (encrypted under `$publicinfos`). When omitted, no setup
211
- * document is written at create time.
231
+ * `tenantsetup` (doc under `$publicinfos`; label field-encrypted under
232
+ * `default`). When omitted, no setup document is written at create time.
212
233
  */
213
234
  tenantLabel?: string;
214
235
  }
@@ -285,13 +306,20 @@ export interface JoinRequest {
285
306
  /** RSA-OAEP public encryption key (PEM format) */
286
307
  encryptionPublicKey: string;
287
308
  /**
288
- * Optional human-readable label for this device's signing/encryption key
309
+ * Human-readable label for this device's signing/encryption key
289
310
  * pair (e.g. a date or a note about the device type). Suggested by the
290
311
  * joining user; the approving admin may override it (see
291
- * {@link ApproveJoinRequestOptions.label}). Stored on the grant document's
292
- * 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).
293
315
  */
294
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;
295
323
  }
296
324
  /**
297
325
  * Options for approving a join request.
@@ -301,8 +329,12 @@ export interface ApproveJoinRequestOptions {
301
329
  adminSigningKey: EncryptedPrivateKey;
302
330
  /** The password to decrypt the admin signing key */
303
331
  adminPassword: string;
304
- /** A shared password for encrypting the exported keys. Must be communicated out-of-band (e.g. phone). */
305
- 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;
306
338
  /** Optional server URL to include in the response so the joining user knows where to sync */
307
339
  serverUrl?: string;
308
340
  /** Optional admin username to include in the response so the joining user can display it */
@@ -316,10 +348,11 @@ export interface ApproveJoinRequestOptions {
316
348
  */
317
349
  sharedDocKeyIds?: string[];
318
350
  /**
319
- * 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,
320
352
  * it overrides any label the joining user suggested in the join request and
321
353
  * is stored on the grant document's key-pair entry (docs/accesscontrol.md
322
- * §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.
323
356
  */
324
357
  label?: string;
325
358
  /**
@@ -334,7 +367,8 @@ export interface ApproveJoinRequestOptions {
334
367
  username?: string;
335
368
  /**
336
369
  * Optional tenant display label to include in the join response. When omitted,
337
- * `approveJoinRequest` tries to read it from the directory `tenantsetup` doc.
370
+ * `approveJoinRequest` tries to decrypt it from the directory `tenantsetup`
371
+ * doc (`label_encrypted` under the tenant `default` key).
338
372
  */
339
373
  tenantLabel?: string;
340
374
  /** If "uri", approveJoinRequest returns a mdb://join-response/... URI string instead of an object */
@@ -343,8 +377,16 @@ export interface ApproveJoinRequestOptions {
343
377
  export interface JoinResponseEncryptedDocKeyVersion {
344
378
  /** Original KeyBag creation timestamp for this key version, used for rotation ordering. */
345
379
  createdAt?: number;
346
- /** Symmetric document key version encrypted with the shared password. */
347
- 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;
348
390
  }
349
391
  export interface JoinResponseEncryptedDocKey {
350
392
  /** Logical document key id within the tenant, e.g. "$publicinfos", "default", or a named key. */
@@ -357,11 +399,14 @@ export interface JoinResponseEncryptedDocKey {
357
399
  * It contains encrypted symmetric keys and tenant metadata needed to join.
358
400
  *
359
401
  * Can be serialized to a mdb://join-response/... URI for out-of-band exchange.
360
- * 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.
361
406
  */
362
407
  export interface JoinResponse {
363
- /** Protocol version. v2 carries versioned document-key bundles. */
364
- v: 2;
408
+ /** Protocol version. v2 is password-wrapped; v3 is RSA-OAEP-wrapped to the requester. */
409
+ v: 2 | 3;
365
410
  /** Tenant identifier */
366
411
  tenantId: string;
367
412
  /** Admin's public signing key (Ed25519, PEM) — needed to open the tenant */
@@ -375,7 +420,8 @@ export interface JoinResponse {
375
420
  /**
376
421
  * Optional human-readable tenant label for display on the joining device.
377
422
  * Snapshotted at approve time from `tenantsetup` (or an explicit override).
378
- * After join, clients should prefer the live directory label when synced.
423
+ * After join, clients should prefer the live directory label (field-encrypted
424
+ * under `default`) when synced.
379
425
  */
380
426
  tenantLabel?: string;
381
427
  /**
@@ -387,7 +433,7 @@ export interface JoinResponse {
387
433
  * requester keeps the name it chose itself.
388
434
  */
389
435
  username?: string;
390
- /** Selected tenant document keys, encrypted with the sharePassword. */
436
+ /** Selected tenant document keys. v3: RSA-wrapped; v2: sharePassword-encrypted. */
391
437
  encryptedDocKeys: JoinResponseEncryptedDocKey[];
392
438
  }
393
439
  /**
@@ -408,8 +454,11 @@ export interface JoinTenantOptions {
408
454
  * callers may pass an empty string.
409
455
  */
410
456
  password: string;
411
- /** The shared password used to decrypt the keys in the join response */
412
- 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;
413
462
  /**
414
463
  * Optional pre-existing {@link KeyBag} to extend with the joined tenant's
415
464
  * keys. When supplied, `joinTenant` will mutate this bag in place (adding
@@ -452,6 +501,58 @@ export interface JoinTenantResult {
452
501
  */
453
502
  user: PrivateUserId;
454
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
+ }
455
556
  /**
456
557
  * Options for publishing a tenant to a server.
457
558
  */
@@ -562,18 +663,39 @@ export interface MindooTenantFactory {
562
663
  format?: "object" | "uri";
563
664
  label?: string;
564
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>;
565
672
  /**
566
673
  * Join a tenant using a join response from an admin.
567
674
  * This orchestrates:
568
675
  * 1. Parsing the join response (object or mdb:// URI string)
569
- * 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)
570
678
  * 3. Opening the tenant with the admin public keys from the response
571
679
  *
572
680
  * @param joinResponse A JoinResponse object or a mdb://join-response/... URI string
573
- * @param options Options including the user's identity, password, and the shared password
681
+ * @param options Options including the user's identity and password
574
682
  * @return The opened tenant and KeyBag
575
683
  */
576
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>;
577
699
  }
578
700
  /**
579
701
  * A MindooTenant contains multiple MindooDB in an organization. One MindooDB is a mandatory part
@@ -657,10 +779,16 @@ export interface MindooTenant {
657
779
  * This is used for operations that need to sign with a different key than the current user's,
658
780
  * such as directory operations that must be signed with the administration key.
659
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
+ *
660
787
  * @param payload The payload to sign (binary data)
661
788
  * @param signingKeyPair The signing key pair to use (Ed25519)
662
789
  * @param password The password to decrypt the signing private key
663
790
  * @return The signature (Ed25519 signature as Uint8Array)
791
+ * @throws when the decrypted private key does not correspond to `publicKey`
664
792
  */
665
793
  signPayloadWithKey(payload: Uint8Array, signingKeyPair: SigningKeyPair, password: string): Promise<Uint8Array>;
666
794
  /**
@@ -787,6 +915,7 @@ export interface MindooTenant {
787
915
  reconcileKeyDistributionsForCurrentUser?(): Promise<{
788
916
  imported: string[];
789
917
  removed: string[];
918
+ adoptedUsername?: string;
790
919
  }>;
791
920
  /**
792
921
  * Return whether the current KeyBag can resolve the given document
@@ -795,6 +924,13 @@ export interface MindooTenant {
795
924
  * result as a guard before attempting decryption.
796
925
  */
797
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>;
798
934
  /**
799
935
  * Return a stable, opaque fingerprint of the doc keys this tenant
800
936
  * currently has access to. The fingerprint must change whenever the
@@ -824,17 +960,36 @@ export interface MindooTenant {
824
960
  * This orchestrates:
825
961
  * 1. Parsing the join request (object or mdb:// URI string)
826
962
  * 2. Registering the user in the tenant directory
827
- * 3. Exporting selected document keys, encrypted with the sharePassword
828
- * 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)
829
965
  *
830
966
  * @param joinRequest A JoinRequest object or a mdb://join-request/... URI string
831
- * @param options Options including admin key, share password, and optional server URL
967
+ * @param options Options including admin key and optional server URL
832
968
  * @return A JoinResponse object, or a mdb://join-response/... URI string if format is "uri"
833
969
  */
834
970
  approveJoinRequest(joinRequest: JoinRequest | string, options: ApproveJoinRequestOptions & {
835
971
  format: "uri";
836
972
  }): Promise<string>;
837
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>;
838
993
  /**
839
994
  * Publish (register) this tenant on a MindooDB server.
840
995
  * Sends an HTTP POST to the server's /admin/register-tenant endpoint
@@ -1029,6 +1184,18 @@ export interface StoreEntryMetadata {
1029
1184
  * on-disk, IndexedDB and network serializers without per-field binary handling.
1030
1185
  */
1031
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;
1032
1199
  /**
1033
1200
  * Original size of the plaintext data before encryption (in bytes).
1034
1201
  * For doc_* entries: size of the Automerge binary change/snapshot
@@ -1481,6 +1648,17 @@ export interface CreateOptions {
1481
1648
  * (the tenant key). Replaces `createEncryptedDocument(decryptionKeyId)`.
1482
1649
  */
1483
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;
1484
1662
  /**
1485
1663
  * Optional signing key pair to sign the initial document entry with. When
1486
1664
  * provided, `signingKeyPassword` must be provided as well. Replaces
@@ -1713,6 +1891,16 @@ export interface MindooDoc {
1713
1891
  * inaccessible-key tombstone.
1714
1892
  */
1715
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;
1716
1904
  /**
1717
1905
  * Whether this document is still "awaiting witness": it has at least one
1718
1906
  * versioned store entry (written in the witness-aware era) that has not yet
@@ -2192,6 +2380,14 @@ export interface DirectoryUserLookup {
2192
2380
  * flag the grant for backfill.
2193
2381
  */
2194
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;
2195
2391
  }
2196
2392
  /**
2197
2393
  * A single device's key pair on a grant document (docs/accesscontrol.md §6.5).
@@ -2216,6 +2412,13 @@ export interface GrantKeyPair {
2216
2412
  encryptionPublicKey: string;
2217
2413
  /** Optional human-readable label for this device/key pair. */
2218
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;
2219
2422
  /**
2220
2423
  * When true, this device's access has been revoked but the pair is RETAINED
2221
2424
  * on the grant document (docs/accesscontrol.md §6.5) so admin UIs can list
@@ -2229,6 +2432,13 @@ export interface GrantKeyPair {
2229
2432
  * together with {@link revoked}; cleared when the device is restored.
2230
2433
  */
2231
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;
2232
2442
  }
2233
2443
  /** A {@link GrantKeyPair} enriched with its current remote-wipe status (§6.5). */
2234
2444
  export interface GrantKeyPairInfo extends GrantKeyPair {
@@ -2250,10 +2460,13 @@ export interface MindooTenantDirectory {
2250
2460
  * @param administrationPrivateKey The administration private key to sign the registration operation with (signing only)
2251
2461
  * @param administrationPrivateKeyPassword The password to decrypt the administration private key
2252
2462
  * @param userDetails The user details to register (ignored when appending a device to an existing grant)
2253
- * @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}.
2254
2465
  * @return A promise that resolves when the user is registered
2255
2466
  */
2256
- 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>;
2257
2470
  /**
2258
2471
  * Revokes a user's access by removing their keys from the grant document
2259
2472
  * (docs/accesscontrol.md §6.5). Revocation is an in-place edit of the grant
@@ -2563,6 +2776,27 @@ export interface MindooTenantDirectory {
2563
2776
  beforeDoc: Record<string, unknown> | null;
2564
2777
  afterDoc: Record<string, unknown> | null;
2565
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>;
2566
2800
  /**
2567
2801
  * Whether a Tier 2 (`withfields`) content rule exists for `op` on `dbid` at
2568
2802
  * the current head state. Lets callers skip materializing before/after
@@ -2599,6 +2833,7 @@ export interface MindooTenantDirectory {
2599
2833
  * @returns The salted, normalized username hash.
2600
2834
  */
2601
2835
  getUsernameHash?(username: string): Promise<string>;
2836
+ getUsernameHashCandidates?(username: string): Promise<string[]>;
2602
2837
  /**
2603
2838
  * All ACTIVE (non-revoked) RSA encryption public keys (PEM) for `username` —
2604
2839
  * one per active device. Used to wrap a key for every device of a recipient.
@@ -2618,6 +2853,13 @@ export interface MindooTenantDirectory {
2618
2853
  * @returns The recipient's wrapped device material.
2619
2854
  */
2620
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>;
2621
2863
  /**
2622
2864
  * The version manifest (`{createdAt, fingerprint}`) of `keyId` from the
2623
2865
  * caller's KeyBag — the source of truth for a distribution's `keyVersions`.
@@ -2790,6 +3032,7 @@ export interface MindooTenantDirectory {
2790
3032
  encryptionPublicKey: string;
2791
3033
  details?: DirectoryUserDetails | null;
2792
3034
  } | null>;
3035
+ findGrantAccessDocuments?(username: string): Promise<MindooDoc[]>;
2793
3036
  /**
2794
3037
  * Look up a user by their public signing key.
2795
3038
  * This is useful for reverse-resolving historical change authors to friendly labels.
@@ -2911,10 +3154,10 @@ export interface MindooTenantDirectory {
2911
3154
  * Returns the database IDs currently known to the directory.
2912
3155
  *
2913
3156
  * This is intended for admin tooling and overview UIs. The result always includes
2914
- * `"directory"` and will also include `"main"` as the conventional default app DB.
2915
- * 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.
2916
3159
  *
2917
- * @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"`).
2918
3161
  */
2919
3162
  listKnownDBIds(): Promise<string[]>;
2920
3163
  /**
@@ -4167,6 +4410,25 @@ export interface MindooDB {
4167
4410
  * @param signingKeyPair Optional custom signing key (matches `changeDoc`).
4168
4411
  */
4169
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>;
4170
4432
  /**
4171
4433
  * Predict whether deleting `doc` via `deleteDocument` would be allowed by the
4172
4434
  * active write policy, without writing.