mindoodb 0.0.24 → 0.0.32

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 (340) hide show
  1. package/README-server.md +9 -1
  2. package/README.md +5 -3
  3. package/dist/appendonlystores/network/ClientNetworkContentAddressedStore.d.ts +1 -1
  4. package/dist/appendonlystores/network/ClientNetworkContentAddressedStore.d.ts.map +1 -1
  5. package/dist/appendonlystores/network/ClientNetworkContentAddressedStore.js +24 -5
  6. package/dist/appendonlystores/network/ClientNetworkContentAddressedStore.js.map +1 -1
  7. package/dist/appendonlystores/network/HttpTransport.d.ts +14 -2
  8. package/dist/appendonlystores/network/HttpTransport.d.ts.map +1 -1
  9. package/dist/appendonlystores/network/HttpTransport.js +124 -27
  10. package/dist/appendonlystores/network/HttpTransport.js.map +1 -1
  11. package/dist/appendonlystores/network/ServerNetworkContentAddressedStore.d.ts +159 -4
  12. package/dist/appendonlystores/network/ServerNetworkContentAddressedStore.d.ts.map +1 -1
  13. package/dist/appendonlystores/network/ServerNetworkContentAddressedStore.js +334 -25
  14. package/dist/appendonlystores/network/ServerNetworkContentAddressedStore.js.map +1 -1
  15. package/dist/browser/appendonlystores/IndexedDBContentAddressedStore.d.ts +9 -0
  16. package/dist/browser/appendonlystores/IndexedDBContentAddressedStore.d.ts.map +1 -1
  17. package/dist/browser/appendonlystores/IndexedDBContentAddressedStore.js +77 -5
  18. package/dist/browser/appendonlystores/IndexedDBContentAddressedStore.js.map +1 -1
  19. package/dist/browser/index.mjs +103 -0
  20. package/dist/core/BaseMindooDB.d.ts +662 -4
  21. package/dist/core/BaseMindooDB.d.ts.map +1 -1
  22. package/dist/core/BaseMindooDB.js +2769 -144
  23. package/dist/core/BaseMindooDB.js.map +1 -1
  24. package/dist/core/BaseMindooTenant.d.ts +192 -1
  25. package/dist/core/BaseMindooTenant.d.ts.map +1 -1
  26. package/dist/core/BaseMindooTenant.js +633 -88
  27. package/dist/core/BaseMindooTenant.js.map +1 -1
  28. package/dist/core/BaseMindooTenantDirectory.d.ts +770 -10
  29. package/dist/core/BaseMindooTenantDirectory.d.ts.map +1 -1
  30. package/dist/core/BaseMindooTenantDirectory.js +2715 -292
  31. package/dist/core/BaseMindooTenantDirectory.js.map +1 -1
  32. package/dist/core/BaseMindooTenantFactory.d.ts +2 -0
  33. package/dist/core/BaseMindooTenantFactory.d.ts.map +1 -1
  34. package/dist/core/BaseMindooTenantFactory.js +20 -0
  35. package/dist/core/BaseMindooTenantFactory.js.map +1 -1
  36. package/dist/core/accesscontrol/AccessDeniedError.d.ts +22 -0
  37. package/dist/core/accesscontrol/AccessDeniedError.d.ts.map +1 -0
  38. package/dist/core/accesscontrol/AccessDeniedError.js +28 -0
  39. package/dist/core/accesscontrol/AccessDeniedError.js.map +1 -0
  40. package/dist/core/accesscontrol/DirectoryStateNode.d.ts +220 -0
  41. package/dist/core/accesscontrol/DirectoryStateNode.d.ts.map +1 -0
  42. package/dist/core/accesscontrol/DirectoryStateNode.js +297 -0
  43. package/dist/core/accesscontrol/DirectoryStateNode.js.map +1 -0
  44. package/dist/core/accesscontrol/DirectoryTimeTravelIndex.d.ts +118 -0
  45. package/dist/core/accesscontrol/DirectoryTimeTravelIndex.d.ts.map +1 -0
  46. package/dist/core/accesscontrol/DirectoryTimeTravelIndex.js +173 -0
  47. package/dist/core/accesscontrol/DirectoryTimeTravelIndex.js.map +1 -0
  48. package/dist/core/accesscontrol/directoryProjection.d.ts +26 -0
  49. package/dist/core/accesscontrol/directoryProjection.d.ts.map +1 -0
  50. package/dist/core/accesscontrol/directoryProjection.js +174 -0
  51. package/dist/core/accesscontrol/directoryProjection.js.map +1 -0
  52. package/dist/core/accesscontrol/evaluate.d.ts +77 -0
  53. package/dist/core/accesscontrol/evaluate.d.ts.map +1 -0
  54. package/dist/core/accesscontrol/evaluate.js +206 -0
  55. package/dist/core/accesscontrol/evaluate.js.map +1 -0
  56. package/dist/core/accesscontrol/grantKeys.d.ts +113 -0
  57. package/dist/core/accesscontrol/grantKeys.d.ts.map +1 -0
  58. package/dist/core/accesscontrol/grantKeys.js +302 -0
  59. package/dist/core/accesscontrol/grantKeys.js.map +1 -0
  60. package/dist/core/accesscontrol/keyBagReconciler.d.ts +22 -0
  61. package/dist/core/accesscontrol/keyBagReconciler.d.ts.map +1 -0
  62. package/dist/core/accesscontrol/keyBagReconciler.js +3 -0
  63. package/dist/core/accesscontrol/keyBagReconciler.js.map +1 -0
  64. package/dist/core/accesscontrol/materializationGuard.d.ts +89 -0
  65. package/dist/core/accesscontrol/materializationGuard.d.ts.map +1 -0
  66. package/dist/core/accesscontrol/materializationGuard.js +69 -0
  67. package/dist/core/accesscontrol/materializationGuard.js.map +1 -0
  68. package/dist/core/accesscontrol/quarantine.d.ts +65 -0
  69. package/dist/core/accesscontrol/quarantine.d.ts.map +1 -0
  70. package/dist/core/accesscontrol/quarantine.js +79 -0
  71. package/dist/core/accesscontrol/quarantine.js.map +1 -0
  72. package/dist/core/accesscontrol/receiptValidation.d.ts +113 -0
  73. package/dist/core/accesscontrol/receiptValidation.d.ts.map +1 -0
  74. package/dist/core/accesscontrol/receiptValidation.js +142 -0
  75. package/dist/core/accesscontrol/receiptValidation.js.map +1 -0
  76. package/dist/core/accesscontrol/timestamp/Ed25519WitnessProvider.d.ts +31 -0
  77. package/dist/core/accesscontrol/timestamp/Ed25519WitnessProvider.d.ts.map +1 -0
  78. package/dist/core/accesscontrol/timestamp/Ed25519WitnessProvider.js +66 -0
  79. package/dist/core/accesscontrol/timestamp/Ed25519WitnessProvider.js.map +1 -0
  80. package/dist/core/accesscontrol/timestamp/TimestampProvider.d.ts +79 -0
  81. package/dist/core/accesscontrol/timestamp/TimestampProvider.d.ts.map +1 -0
  82. package/dist/core/accesscontrol/timestamp/TimestampProvider.js +22 -0
  83. package/dist/core/accesscontrol/timestamp/TimestampProvider.js.map +1 -0
  84. package/dist/core/accesscontrol/types.d.ts +825 -0
  85. package/dist/core/accesscontrol/types.d.ts.map +1 -0
  86. package/dist/core/accesscontrol/types.js +534 -0
  87. package/dist/core/accesscontrol/types.js.map +1 -0
  88. package/dist/core/appendonlystores/InMemoryContentAddressedStore.d.ts +9 -0
  89. package/dist/core/appendonlystores/InMemoryContentAddressedStore.d.ts.map +1 -1
  90. package/dist/core/appendonlystores/InMemoryContentAddressedStore.js +54 -0
  91. package/dist/core/appendonlystores/InMemoryContentAddressedStore.js.map +1 -1
  92. package/dist/core/appendonlystores/network/AuthenticationService.d.ts +38 -2
  93. package/dist/core/appendonlystores/network/AuthenticationService.d.ts.map +1 -1
  94. package/dist/core/appendonlystores/network/AuthenticationService.js +199 -26
  95. package/dist/core/appendonlystores/network/AuthenticationService.js.map +1 -1
  96. package/dist/core/appendonlystores/network/NetworkTransport.d.ts +17 -3
  97. package/dist/core/appendonlystores/network/NetworkTransport.d.ts.map +1 -1
  98. package/dist/core/appendonlystores/network/types.d.ts +58 -4
  99. package/dist/core/appendonlystores/network/types.d.ts.map +1 -1
  100. package/dist/core/appendonlystores/network/types.js +4 -0
  101. package/dist/core/appendonlystores/network/types.js.map +1 -1
  102. package/dist/core/appendonlystores/scanUtils.d.ts +27 -0
  103. package/dist/core/appendonlystores/scanUtils.d.ts.map +1 -0
  104. package/dist/core/appendonlystores/scanUtils.js +87 -0
  105. package/dist/core/appendonlystores/scanUtils.js.map +1 -0
  106. package/dist/core/appendonlystores/types.d.ts +23 -2
  107. package/dist/core/appendonlystores/types.d.ts.map +1 -1
  108. package/dist/core/cache/CacheManager.d.ts +13 -3
  109. package/dist/core/cache/CacheManager.d.ts.map +1 -1
  110. package/dist/core/cache/CacheManager.js +7 -4
  111. package/dist/core/cache/CacheManager.js.map +1 -1
  112. package/dist/core/crypto/EntrySignature.d.ts +137 -0
  113. package/dist/core/crypto/EntrySignature.d.ts.map +1 -0
  114. package/dist/core/crypto/EntrySignature.js +210 -0
  115. package/dist/core/crypto/EntrySignature.js.map +1 -0
  116. package/dist/core/crypto/MindooDocSigner.d.ts.map +1 -1
  117. package/dist/core/crypto/MindooDocSigner.js +6 -2
  118. package/dist/core/crypto/MindooDocSigner.js.map +1 -1
  119. package/dist/core/crypto/WitnessReceipt.d.ts +137 -0
  120. package/dist/core/crypto/WitnessReceipt.d.ts.map +1 -0
  121. package/dist/core/crypto/WitnessReceipt.js +182 -0
  122. package/dist/core/crypto/WitnessReceipt.js.map +1 -0
  123. package/dist/core/crypto/encryptedFields.d.ts +27 -0
  124. package/dist/core/crypto/encryptedFields.d.ts.map +1 -0
  125. package/dist/core/crypto/encryptedFields.js +58 -0
  126. package/dist/core/crypto/encryptedFields.js.map +1 -0
  127. package/dist/core/crypto/pbkdf2Iterations.d.ts +12 -0
  128. package/dist/core/crypto/pbkdf2Iterations.d.ts.map +1 -1
  129. package/dist/core/crypto/pbkdf2Iterations.js +23 -0
  130. package/dist/core/crypto/pbkdf2Iterations.js.map +1 -1
  131. package/dist/core/crypto/privateKeyEncryption.d.ts.map +1 -1
  132. package/dist/core/crypto/privateKeyEncryption.js +3 -1
  133. package/dist/core/crypto/privateKeyEncryption.js.map +1 -1
  134. package/dist/core/databaseIdValidation.d.ts +1 -1
  135. package/dist/core/databaseIdValidation.d.ts.map +1 -1
  136. package/dist/core/databaseIdValidation.js +4 -4
  137. package/dist/core/databaseIdValidation.js.map +1 -1
  138. package/dist/core/errors.d.ts +26 -0
  139. package/dist/core/errors.d.ts.map +1 -1
  140. package/dist/core/errors.js +42 -1
  141. package/dist/core/errors.js.map +1 -1
  142. package/dist/core/expressions/builder.d.ts +102 -0
  143. package/dist/core/expressions/builder.d.ts.map +1 -0
  144. package/dist/core/expressions/builder.js +249 -0
  145. package/dist/core/expressions/builder.js.map +1 -0
  146. package/dist/core/expressions/evaluateExpression.d.ts +78 -0
  147. package/dist/core/expressions/evaluateExpression.d.ts.map +1 -0
  148. package/dist/core/expressions/evaluateExpression.js +386 -0
  149. package/dist/core/expressions/evaluateExpression.js.map +1 -0
  150. package/dist/core/expressions/formulaSource.d.ts +24 -0
  151. package/dist/core/expressions/formulaSource.d.ts.map +1 -0
  152. package/dist/core/expressions/formulaSource.js +765 -0
  153. package/dist/core/expressions/formulaSource.js.map +1 -0
  154. package/dist/core/expressions/index.d.ts +8 -0
  155. package/dist/core/expressions/index.d.ts.map +1 -0
  156. package/dist/core/expressions/index.js +46 -0
  157. package/dist/core/expressions/index.js.map +1 -0
  158. package/dist/core/expressions/metadata.d.ts +23 -0
  159. package/dist/core/expressions/metadata.d.ts.map +1 -0
  160. package/dist/core/expressions/metadata.js +191 -0
  161. package/dist/core/expressions/metadata.js.map +1 -0
  162. package/dist/core/expressions/types.d.ts +164 -0
  163. package/dist/core/expressions/types.d.ts.map +1 -0
  164. package/dist/core/expressions/types.js +3 -0
  165. package/dist/core/expressions/types.js.map +1 -0
  166. package/dist/core/extraction/types.d.ts +47 -0
  167. package/dist/core/extraction/types.d.ts.map +1 -0
  168. package/dist/core/extraction/types.js +42 -0
  169. package/dist/core/extraction/types.js.map +1 -0
  170. package/dist/core/index.d.ts +13 -3
  171. package/dist/core/index.d.ts.map +1 -1
  172. package/dist/core/index.js +113 -4
  173. package/dist/core/index.js.map +1 -1
  174. package/dist/core/indexing/createViewDataProvider.d.ts +84 -0
  175. package/dist/core/indexing/createViewDataProvider.d.ts.map +1 -0
  176. package/dist/core/indexing/createViewDataProvider.js +139 -0
  177. package/dist/core/indexing/createViewDataProvider.js.map +1 -0
  178. package/dist/core/indexing/fulltext/DocumentFullTextIndex.d.ts +180 -0
  179. package/dist/core/indexing/fulltext/DocumentFullTextIndex.d.ts.map +1 -0
  180. package/dist/core/indexing/fulltext/DocumentFullTextIndex.js +548 -0
  181. package/dist/core/indexing/fulltext/DocumentFullTextIndex.js.map +1 -0
  182. package/dist/core/indexing/fulltext/SearchEngineAdapter.d.ts +69 -0
  183. package/dist/core/indexing/fulltext/SearchEngineAdapter.d.ts.map +1 -0
  184. package/dist/core/indexing/fulltext/SearchEngineAdapter.js +183 -0
  185. package/dist/core/indexing/fulltext/SearchEngineAdapter.js.map +1 -0
  186. package/dist/core/indexing/fulltext/extractFulltextText.d.ts +34 -0
  187. package/dist/core/indexing/fulltext/extractFulltextText.d.ts.map +1 -0
  188. package/dist/core/indexing/fulltext/extractFulltextText.js +129 -0
  189. package/dist/core/indexing/fulltext/extractFulltextText.js.map +1 -0
  190. package/dist/core/indexing/fulltext/index.d.ts +5 -0
  191. package/dist/core/indexing/fulltext/index.d.ts.map +1 -0
  192. package/dist/core/indexing/fulltext/index.js +20 -0
  193. package/dist/core/indexing/fulltext/index.js.map +1 -0
  194. package/dist/core/indexing/fulltext/types.d.ts +168 -0
  195. package/dist/core/indexing/fulltext/types.d.ts.map +1 -0
  196. package/dist/core/indexing/fulltext/types.js +89 -0
  197. package/dist/core/indexing/fulltext/types.js.map +1 -0
  198. package/dist/core/indexing/summary/DocumentSummaryStore.d.ts +137 -0
  199. package/dist/core/indexing/summary/DocumentSummaryStore.d.ts.map +1 -0
  200. package/dist/core/indexing/summary/DocumentSummaryStore.js +438 -0
  201. package/dist/core/indexing/summary/DocumentSummaryStore.js.map +1 -0
  202. package/dist/core/indexing/summary/SummaryVirtualViewDataProvider.d.ts +72 -0
  203. package/dist/core/indexing/summary/SummaryVirtualViewDataProvider.d.ts.map +1 -0
  204. package/dist/core/indexing/summary/SummaryVirtualViewDataProvider.js +221 -0
  205. package/dist/core/indexing/summary/SummaryVirtualViewDataProvider.js.map +1 -0
  206. package/dist/core/indexing/summary/extractSummaryFields.d.ts +75 -0
  207. package/dist/core/indexing/summary/extractSummaryFields.d.ts.map +1 -0
  208. package/dist/core/indexing/summary/extractSummaryFields.js +266 -0
  209. package/dist/core/indexing/summary/extractSummaryFields.js.map +1 -0
  210. package/dist/core/indexing/summary/index.d.ts +5 -0
  211. package/dist/core/indexing/summary/index.d.ts.map +1 -0
  212. package/dist/core/indexing/summary/index.js +23 -0
  213. package/dist/core/indexing/summary/index.js.map +1 -0
  214. package/dist/core/indexing/summary/types.d.ts +119 -0
  215. package/dist/core/indexing/summary/types.d.ts.map +1 -0
  216. package/dist/core/indexing/summary/types.js +81 -0
  217. package/dist/core/indexing/summary/types.js.map +1 -0
  218. package/dist/core/indexing/virtualviews/IVirtualViewDataProvider.d.ts +47 -1
  219. package/dist/core/indexing/virtualviews/IVirtualViewDataProvider.d.ts.map +1 -1
  220. package/dist/core/indexing/virtualviews/MindooDBVirtualViewDataProvider.d.ts +24 -8
  221. package/dist/core/indexing/virtualviews/MindooDBVirtualViewDataProvider.d.ts.map +1 -1
  222. package/dist/core/indexing/virtualviews/MindooDBVirtualViewDataProvider.js +96 -41
  223. package/dist/core/indexing/virtualviews/MindooDBVirtualViewDataProvider.js.map +1 -1
  224. package/dist/core/indexing/virtualviews/ViewEntrySortKey.d.ts +2 -0
  225. package/dist/core/indexing/virtualviews/ViewEntrySortKey.d.ts.map +1 -1
  226. package/dist/core/indexing/virtualviews/ViewEntrySortKey.js +8 -3
  227. package/dist/core/indexing/virtualviews/ViewEntrySortKey.js.map +1 -1
  228. package/dist/core/indexing/virtualviews/VirtualView.d.ts +111 -5
  229. package/dist/core/indexing/virtualviews/VirtualView.d.ts.map +1 -1
  230. package/dist/core/indexing/virtualviews/VirtualView.js +266 -75
  231. package/dist/core/indexing/virtualviews/VirtualView.js.map +1 -1
  232. package/dist/core/indexing/virtualviews/VirtualViewColumn.d.ts +12 -0
  233. package/dist/core/indexing/virtualviews/VirtualViewColumn.d.ts.map +1 -1
  234. package/dist/core/indexing/virtualviews/VirtualViewColumn.js +1 -0
  235. package/dist/core/indexing/virtualviews/VirtualViewColumn.js.map +1 -1
  236. package/dist/core/indexing/virtualviews/VirtualViewEntryData.d.ts +12 -0
  237. package/dist/core/indexing/virtualviews/VirtualViewEntryData.d.ts.map +1 -1
  238. package/dist/core/indexing/virtualviews/VirtualViewEntryData.js +66 -5
  239. package/dist/core/indexing/virtualviews/VirtualViewEntryData.js.map +1 -1
  240. package/dist/core/indexing/virtualviews/VirtualViewFactory.d.ts +50 -6
  241. package/dist/core/indexing/virtualviews/VirtualViewFactory.d.ts.map +1 -1
  242. package/dist/core/indexing/virtualviews/VirtualViewFactory.js +54 -12
  243. package/dist/core/indexing/virtualviews/VirtualViewFactory.js.map +1 -1
  244. package/dist/core/indexing/virtualviews/index.d.ts +3 -3
  245. package/dist/core/indexing/virtualviews/index.d.ts.map +1 -1
  246. package/dist/core/indexing/virtualviews/index.js.map +1 -1
  247. package/dist/core/indexing/virtualviews/types.d.ts +6 -0
  248. package/dist/core/indexing/virtualviews/types.d.ts.map +1 -1
  249. package/dist/core/indexing/virtualviews/types.js +11 -3
  250. package/dist/core/indexing/virtualviews/types.js.map +1 -1
  251. package/dist/core/keys/KeyBag.d.ts +25 -0
  252. package/dist/core/keys/KeyBag.d.ts.map +1 -1
  253. package/dist/core/keys/KeyBag.js +37 -1
  254. package/dist/core/keys/KeyBag.js.map +1 -1
  255. package/dist/core/query/executeQuery.d.ts +18 -0
  256. package/dist/core/query/executeQuery.d.ts.map +1 -0
  257. package/dist/core/query/executeQuery.js +313 -0
  258. package/dist/core/query/executeQuery.js.map +1 -0
  259. package/dist/core/query/index.d.ts +5 -0
  260. package/dist/core/query/index.d.ts.map +1 -0
  261. package/dist/core/query/index.js +14 -0
  262. package/dist/core/query/index.js.map +1 -0
  263. package/dist/core/query/queryLive.d.ts +27 -0
  264. package/dist/core/query/queryLive.d.ts.map +1 -0
  265. package/dist/core/query/queryLive.js +104 -0
  266. package/dist/core/query/queryLive.js.map +1 -0
  267. package/dist/core/query/queryView.d.ts +156 -0
  268. package/dist/core/query/queryView.d.ts.map +1 -0
  269. package/dist/core/query/queryView.js +266 -0
  270. package/dist/core/query/queryView.js.map +1 -0
  271. package/dist/core/query/types.d.ts +121 -0
  272. package/dist/core/query/types.d.ts.map +1 -0
  273. package/dist/core/query/types.js +18 -0
  274. package/dist/core/query/types.js.map +1 -0
  275. package/dist/core/storeEntryTime.d.ts +57 -0
  276. package/dist/core/storeEntryTime.d.ts.map +1 -0
  277. package/dist/core/storeEntryTime.js +72 -0
  278. package/dist/core/storeEntryTime.js.map +1 -0
  279. package/dist/core/types.d.ts +1371 -34
  280. package/dist/core/types.d.ts.map +1 -1
  281. package/dist/core/types.js +13 -1
  282. package/dist/core/types.js.map +1 -1
  283. package/dist/core/uri/MindooURI.d.ts +53 -1
  284. package/dist/core/uri/MindooURI.d.ts.map +1 -1
  285. package/dist/core/uri/MindooURI.js +135 -0
  286. package/dist/core/uri/MindooURI.js.map +1 -1
  287. package/dist/core/utils/urlSafety.d.ts +46 -0
  288. package/dist/core/utils/urlSafety.d.ts.map +1 -0
  289. package/dist/core/utils/urlSafety.js +144 -0
  290. package/dist/core/utils/urlSafety.js.map +1 -0
  291. package/dist/node/appendonlystores/BasicOnDiskContentAddressedStore.d.ts +14 -0
  292. package/dist/node/appendonlystores/BasicOnDiskContentAddressedStore.d.ts.map +1 -1
  293. package/dist/node/appendonlystores/BasicOnDiskContentAddressedStore.js +95 -4
  294. package/dist/node/appendonlystores/BasicOnDiskContentAddressedStore.js.map +1 -1
  295. package/dist/node/server/CapabilityMatcher.d.ts +10 -0
  296. package/dist/node/server/CapabilityMatcher.d.ts.map +1 -1
  297. package/dist/node/server/CapabilityMatcher.js +14 -2
  298. package/dist/node/server/CapabilityMatcher.js.map +1 -1
  299. package/dist/node/server/MindooDBServer.d.ts.map +1 -1
  300. package/dist/node/server/MindooDBServer.js +117 -8
  301. package/dist/node/server/MindooDBServer.js.map +1 -1
  302. package/dist/node/server/PurgedDocRegistry.d.ts +32 -0
  303. package/dist/node/server/PurgedDocRegistry.d.ts.map +1 -0
  304. package/dist/node/server/PurgedDocRegistry.js +94 -0
  305. package/dist/node/server/PurgedDocRegistry.js.map +1 -0
  306. package/dist/node/server/ServerSync.d.ts.map +1 -1
  307. package/dist/node/server/ServerSync.js +5 -2
  308. package/dist/node/server/ServerSync.js.map +1 -1
  309. package/dist/node/server/SystemAdminAuth.d.ts +10 -0
  310. package/dist/node/server/SystemAdminAuth.d.ts.map +1 -1
  311. package/dist/node/server/SystemAdminAuth.js +25 -0
  312. package/dist/node/server/SystemAdminAuth.js.map +1 -1
  313. package/dist/node/server/TenantManager.d.ts +95 -1
  314. package/dist/node/server/TenantManager.d.ts.map +1 -1
  315. package/dist/node/server/TenantManager.js +382 -15
  316. package/dist/node/server/TenantManager.js.map +1 -1
  317. package/dist/node/server/config.d.ts.map +1 -1
  318. package/dist/node/server/config.js +5 -1
  319. package/dist/node/server/config.js.map +1 -1
  320. package/dist/node/server/types.d.ts +29 -3
  321. package/dist/node/server/types.d.ts.map +1 -1
  322. package/dist/node/server/types.js +12 -0
  323. package/dist/node/server/types.js.map +1 -1
  324. package/dist/node/server/validation.d.ts +6 -0
  325. package/dist/node/server/validation.d.ts.map +1 -1
  326. package/dist/node/server/validation.js +7 -1
  327. package/dist/node/server/validation.js.map +1 -1
  328. package/package.json +4 -3
  329. package/dist/appendonlystores/BasicOnDiskContentAddressedStoreFactory.d.ts +0 -8
  330. package/dist/appendonlystores/BasicOnDiskContentAddressedStoreFactory.d.ts.map +0 -1
  331. package/dist/appendonlystores/BasicOnDiskContentAddressedStoreFactory.js +0 -16
  332. package/dist/appendonlystores/BasicOnDiskContentAddressedStoreFactory.js.map +0 -1
  333. package/dist/core/appendonlystores/BasicOnDiskContentAddressedStore.d.ts +0 -68
  334. package/dist/core/appendonlystores/BasicOnDiskContentAddressedStore.d.ts.map +0 -1
  335. package/dist/core/appendonlystores/BasicOnDiskContentAddressedStore.js +0 -659
  336. package/dist/core/appendonlystores/BasicOnDiskContentAddressedStore.js.map +0 -1
  337. package/dist/node/attachments/writeAttachmentToFile.d.ts +0 -15
  338. package/dist/node/attachments/writeAttachmentToFile.d.ts.map +0 -1
  339. package/dist/node/attachments/writeAttachmentToFile.js +0 -73
  340. package/dist/node/attachments/writeAttachmentToFile.js.map +0 -1
@@ -5,6 +5,17 @@ import { StoreKind } from "./appendonlystores/types";
5
5
  import type { ContentAddressedStore, OpenStoreOptions } from "./appendonlystores/types";
6
6
  import type { CryptoAdapter } from "./crypto/CryptoAdapter";
7
7
  import { MindooDocSigner } from "./crypto/MindooDocSigner";
8
+ import type { DefaultAccessPolicyDoc, KeyDistributionPushRecipient, KeyDistributionRequest, KeyDistributionView, KeyVersionRef, AppDistributionRequest, AppDistributionView, AppDistributionReconcilePlan, SyncSetupPolicyRequest, SyncSetupPolicyView, SyncSetupPolicyReconcilePlan, DocHistoryPurgeRequest, DocHistoryPurgeView, RuleTargets, RuleType, WithFieldClause, AclRuleDoc, AccessDecision } from "./accesscontrol/types";
9
+ import type { DirectoryStateNode } from "./accesscontrol/DirectoryStateNode";
10
+ import type { SummaryConfig } from "./indexing/summary/types";
11
+ import type { DocumentSummaryStore } from "./indexing/summary/DocumentSummaryStore";
12
+ import type { AttachmentTextExtractor, FulltextConfig, FulltextSearchOptions, FulltextSearchResult } from "./indexing/fulltext/types";
13
+ import type { DocumentFullTextIndex } from "./indexing/fulltext/DocumentFullTextIndex";
14
+ import type { ExtractionConfig } from "./extraction/types";
15
+ import type { MindooQuery, MindooQueryOptions, MindooQueryResult } from "./query/types";
16
+ import type { EphemeralSummaryView, MindooQueryViewDefinition } from "./query/queryView";
17
+ import type { MindooQuerySubscription } from "./query/queryLive";
18
+ import type { VirtualViewUpdateOptions } from "./indexing/virtualviews/IVirtualViewDataProvider";
8
19
  /**
9
20
  * Well-known key ID for access control documents (grantaccess, revokeaccess, groups).
10
21
  * All servers and clients MUST have this key in their KeyBag to verify user access.
@@ -174,6 +185,19 @@ interface CreateTenantPasswords {
174
185
  * encryption private keys is skipped entirely.
175
186
  */
176
187
  preDecryptedAppUserKeys?: PreDecryptedUserKeys;
188
+ /**
189
+ * Whether the new tenant should enforce the v2 storage format from creation:
190
+ * an admin-signed default policy is written with `requireMetadataSignatureSince`
191
+ * set to the creation time, so every entry created at/after now (locally and
192
+ * at the sync server) MUST carry the v2 metadata-binding signature and forged
193
+ * legacy (v1) entries are rejected. The policy sets
194
+ * `disableAllAccessChecksAndPolicies: true`, so this enables ONLY the
195
+ * storage-format floor — it does not turn on ACL deny-gates.
196
+ *
197
+ * Defaults to `true`. Set to `false` to create a tenant with no format floor
198
+ * (legacy behavior: v1 entries remain acceptable).
199
+ */
200
+ requireV2Entries?: boolean;
177
201
  }
178
202
  /**
179
203
  * Options for creating a new tenant with a single convenience call.
@@ -226,6 +250,14 @@ export interface JoinRequest {
226
250
  signingPublicKey: string;
227
251
  /** RSA-OAEP public encryption key (PEM format) */
228
252
  encryptionPublicKey: string;
253
+ /**
254
+ * Optional human-readable label for this device's signing/encryption key
255
+ * pair (e.g. a date or a note about the device type). Suggested by the
256
+ * joining user; the approving admin may override it (see
257
+ * {@link ApproveJoinRequestOptions.label}). Stored on the grant document's
258
+ * key-pair entry and editable later (docs/accesscontrol.md §6.5).
259
+ */
260
+ label?: string;
229
261
  }
230
262
  /**
231
263
  * Options for approving a join request.
@@ -249,6 +281,13 @@ export interface ApproveJoinRequestOptions {
249
281
  * default set: `$publicinfos` and `default`.
250
282
  */
251
283
  sharedDocKeyIds?: string[];
284
+ /**
285
+ * Optional human-readable label for the joining device's key pair. When set,
286
+ * it overrides any label the joining user suggested in the join request and
287
+ * is stored on the grant document's key-pair entry (docs/accesscontrol.md
288
+ * §6.5). Useful for recording a date or a note about the device type.
289
+ */
290
+ label?: string;
252
291
  /** If "uri", approveJoinRequest returns a mdb://join-response/... URI string instead of an object */
253
292
  format?: "object" | "uri";
254
293
  }
@@ -443,12 +482,15 @@ export interface MindooTenantFactory {
443
482
  */
444
483
  createJoinRequest(user: PrivateUserId, options?: {
445
484
  format?: "object";
485
+ label?: string;
446
486
  }): JoinRequest;
447
487
  createJoinRequest(user: PrivateUserId, options: {
448
488
  format: "uri";
489
+ label?: string;
449
490
  }): string;
450
491
  createJoinRequest(user: PrivateUserId, options?: {
451
492
  format?: "object" | "uri";
493
+ label?: string;
452
494
  }): JoinRequest | string;
453
495
  /**
454
496
  * Join a tenant using a join response from an admin.
@@ -560,12 +602,41 @@ export interface MindooTenant {
560
602
  * @return True if the signature is valid, false otherwise
561
603
  */
562
604
  verifySignature(payload: Uint8Array, signature: Uint8Array, publicKey: string): Promise<boolean>;
605
+ /**
606
+ * Verify a store entry's author signature, version-aware (audit finding #5).
607
+ *
608
+ * Confirms the author key is trusted, then verifies the strong metadata-binding
609
+ * `metadataSignature` when present (v2+) or falls back to the legacy `signature`
610
+ * over the ciphertext for v1/legacy entries. Also re-verifies that
611
+ * `SHA-256(encryptedData) === contentHash` so a relay cannot serve bytes that
612
+ * disagree with the signed/hashed metadata.
613
+ *
614
+ * @param entry The entry metadata (must include signature fields)
615
+ * @param encryptedData The entry's encrypted payload bytes
616
+ * @return True if the entry is authentic and intact, false otherwise
617
+ */
618
+ verifyEntrySignature(entry: StoreEntryMetadata, encryptedData: Uint8Array): Promise<boolean>;
563
619
  /**
564
620
  * Method to open the directory for this tenant
565
621
  *
566
622
  * @return The directory
567
623
  */
568
624
  openDirectory(): Promise<MindooTenantDirectory>;
625
+ /**
626
+ * Check whether an admin has requested a remote wipe of this device and, if
627
+ * so, delete the entire local tenant (docs/accesscontrol.md §6.5). Returns
628
+ * true if a wipe was applied. Sync the directory first so the latest directive
629
+ * is visible. Optional: not all tenant implementations support remote wipe.
630
+ */
631
+ checkAndApplyRemoteWipe?(): Promise<boolean>;
632
+ /**
633
+ * Delete all local data for this tenant from the device (docs/accesscontrol.md
634
+ * §6.5): every local database (directory + data), this tenant's KeyBag keys,
635
+ * and in-memory caches. Other tenants on the device are untouched. Optional.
636
+ *
637
+ * @param additionalDbIds Optional extra local database ids to wipe.
638
+ */
639
+ wipeLocalTenant?(additionalDbIds?: string[]): Promise<void>;
569
640
  /**
570
641
  * Opens a database for this tenant.
571
642
  * Creates the database if it doesn't exist.
@@ -585,6 +656,20 @@ export interface MindooTenant {
585
656
  * is not applicable.
586
657
  */
587
658
  reconcileKeyBagChanges?(): Promise<void>;
659
+ /**
660
+ * Reconcile this tenant's local KeyBag against the directory head for the
661
+ * current user (docs/accesscontrol.md §13): remove revoked key ids and import
662
+ * the key versions pushed to the user. The RSA-OAEP decryption key is sourced
663
+ * from the tenant's own session, so callers never supply a key. Best-effort
664
+ * and idempotent; safe to call on every directory bring-up / pull. Optional so
665
+ * alternative tenant implementations (server-side, test doubles) may omit it.
666
+ *
667
+ * @returns The key ids imported and removed.
668
+ */
669
+ reconcileKeyDistributionsForCurrentUser?(): Promise<{
670
+ imported: string[];
671
+ removed: string[];
672
+ }>;
588
673
  /**
589
674
  * Return whether the current KeyBag can resolve the given document
590
675
  * encryption key id. Implementations must not throw when the key is
@@ -664,6 +749,22 @@ export { StoreKind } from "./appendonlystores/types";
664
749
  * - attachment_* entries are for file attachment storage
665
750
  */
666
751
  export type StoreEntryType = "doc_create" | "doc_change" | "doc_snapshot" | "doc_delete" | "doc_undelete" | "pending_attachment_upload" | "attachment_chunk";
752
+ /**
753
+ * A single entry in {@link StoreEntryMetadata.attachmentRefs}: a reference to one
754
+ * attachment the document holds as of a given revision. Carries just enough for a
755
+ * keyless server to act:
756
+ * - {@link lastChunkId} resolves the full chunk chain via `resolveDependencies()`
757
+ * (liveness / GC / tiering),
758
+ * - {@link size} enables size/average statistics without fetching chunk payloads.
759
+ */
760
+ export interface StoreEntryAttachmentRef {
761
+ /** Unique id of the attachment instance (UUID7), as in `AttachmentReference`. */
762
+ attachmentId: string;
763
+ /** Entry id of the attachment's last chunk; head of the chunk dependency chain. */
764
+ lastChunkId: string;
765
+ /** Total attachment size in bytes (mirrors `AttachmentReference.size`). */
766
+ size: number;
767
+ }
667
768
  /**
668
769
  * Metadata for entries stored in the ContentAddressedStore.
669
770
  * This contains all information except the actual encrypted payload,
@@ -742,6 +843,23 @@ export interface StoreEntryMetadata {
742
843
  * distinguish never-committed uploads from attachments required by history.
743
844
  */
744
845
  attachmentIds?: string[];
846
+ /**
847
+ * Full snapshot of all attachments the document references AS OF this revision
848
+ * (`doc_create`/`doc_change`/`doc_snapshot`; `doc_undelete` restores the set).
849
+ * Empty/absent means "no live attachments" (and `doc_delete` writes an empty
850
+ * set, since a deleted document is no longer active).
851
+ *
852
+ * Unlike {@link attachmentIds} (an add-only, by-id local recovery hint, written
853
+ * only on the first entry of a change), this is the complete set of references
854
+ * after removals/appends are merged, written on every produced document entry.
855
+ *
856
+ * It is bound into {@link metadataSignature} (see `crypto/EntrySignature.ts`),
857
+ * so a relay cannot rewrite it. This lets a sync server WITHOUT decryption keys
858
+ * determine which `attachment_chunk` chains are still live (GC/tiering, by
859
+ * traversing dependencies from each {@link StoreEntryAttachmentRef.lastChunkId})
860
+ * and compute storage statistics without decrypting content.
861
+ */
862
+ attachmentRefs?: StoreEntryAttachmentRef[];
745
863
  /**
746
864
  * Start timestamp for `pending_attachment_upload` recovery ledgers.
747
865
  */
@@ -760,8 +878,24 @@ export interface StoreEntryMetadata {
760
878
  /**
761
879
  * The signature of the entry (signed with the user's signing key over the encrypted data).
762
880
  * This allows signature verification without decryption.
881
+ *
882
+ * NOTE: this LEGACY signature covers ONLY the encrypted payload bytes, so it
883
+ * does not authenticate the cleartext metadata fields. New writers additionally
884
+ * populate {@link metadataSignature} (which binds the metadata) but keep this
885
+ * field for backward/forward interop with v1 readers.
763
886
  */
764
887
  signature: Uint8Array;
888
+ /**
889
+ * Ed25519 author signature over the canonical, versioned, length-prefixed
890
+ * metadata layout defined in `crypto/EntrySignature.ts`. Unlike {@link signature}
891
+ * it binds `entryType`, `id`, `docId`, `decryptionKeyId`, `createdAt`,
892
+ * `dependencyIds`, `contentHash` and `createdByPublicKey`, preventing metadata
893
+ * tampering on un-witnessed/legacy entries (audit finding #5).
894
+ *
895
+ * Absent on v1/legacy entries written before this field existed; verifiers
896
+ * fall back to {@link signature} when it is missing (backward compatible).
897
+ */
898
+ metadataSignature?: Uint8Array;
765
899
  /**
766
900
  * Original size of the plaintext data before encryption (in bytes).
767
901
  * For doc_* entries: size of the Automerge binary change/snapshot
@@ -774,7 +908,71 @@ export interface StoreEntryMetadata {
774
908
  * Useful for download time estimation, storage space checks, and progress indicators.
775
909
  */
776
910
  encryptedSize: number;
911
+ /**
912
+ * Time the entry was accepted into the tenant by a trusted witness
913
+ * (milliseconds since Unix epoch, witness-local clock). Set once by the first
914
+ * witness that accepts the entry; never modified on subsequent syncs.
915
+ *
916
+ * The "trusted time" of an entry — used for all access-control time-travel
917
+ * evaluation — is `receivedAt` when present, otherwise `createdAt`.
918
+ * See docs/accesscontrol.md §5.1 and §8.
919
+ */
920
+ receivedAt?: number;
921
+ /**
922
+ * Ed25519 public key (PEM) of the witness (sync server) that accepted and
923
+ * stamped the entry. Receivers verify {@link receivedDateSignature} against
924
+ * the tenant's trusted-witness list using this key. See docs/accesscontrol.md §5.1.
925
+ */
926
+ receivedByPublicKey?: string;
927
+ /**
928
+ * Ed25519 signature, produced by the witness identified by
929
+ * {@link receivedByPublicKey}, over the canonical, versioned, length-prefixed
930
+ * byte layout defined in docs/accesscontrol.md §5.2. The layout binds
931
+ * `entryType`, `dbid`, `contentHash`, `id`, `docId`, `decryptionKeyId`,
932
+ * `createdAt`, `createdByPublicKey`, `receivedAt` and `receivedByPublicKey`,
933
+ * so the receipt cannot be transplanted onto a different entry, database, or
934
+ * operation type. See {@link buildWitnessSigningBytes}.
935
+ */
936
+ receivedDateSignature?: Uint8Array;
937
+ /**
938
+ * The timestamping scheme that produced this receipt (the issuing
939
+ * {@link TimestampProvider}'s `kind`), e.g. `"ed25519-witness"`. Lets a
940
+ * receiver route the receipt to the right verifier once more than one scheme
941
+ * exists (e.g. an RFC 3161 TSA, docs/accesscontrol.md §13).
942
+ *
943
+ * Absence means the default/legacy Ed25519 witness scheme — entries stamped
944
+ * before this field existed carry no value. It is intentionally NOT bound
945
+ * into {@link receivedDateSignature}: a tampered tag merely routes to the
946
+ * wrong verifier, which then fails verification (a denial, not a forgery).
947
+ */
948
+ receiptScheme?: string;
949
+ /**
950
+ * Writer-era version of this store entry, set to {@link CURRENT_STORE_ENTRY_VERSION}
951
+ * by the writer that created it. Its presence is a safe discriminator between
952
+ * pre-witness legacy entries and witness-aware entries:
953
+ *
954
+ * - **Absent (legacy / pre-feature):** the entry was written before the
955
+ * witness era. Its trusted time is stable at {@link createdAt} when
956
+ * un-witnessed — it was already synced within the tenant and will never
957
+ * receive a {@link receivedAt}.
958
+ * - **Present (witness-era):** the entry was written by a witness-aware
959
+ * client. While un-witnessed its trusted time stays provisional at the
960
+ * wall-clock `now` (it is "waiting to be pushed" and will eventually be
961
+ * witnessed), so it cannot claim a historical time slot.
962
+ *
963
+ * See {@link entryTrustedTime} / {@link isProvisional}. Like
964
+ * {@link receiptScheme}, this is intentionally NOT bound into
965
+ * {@link receivedDateSignature} (it describes the local writer, not the
966
+ * witness attestation, and keeps existing receipts stable).
967
+ */
968
+ entryVersion?: number;
777
969
  }
970
+ /**
971
+ * Version stamped onto every newly created store entry's {@link StoreEntryMetadata.entryVersion}.
972
+ * Marks the entry as written in the witness-aware era; see that field for the
973
+ * trusted-time semantics its presence/absence selects.
974
+ */
975
+ export declare const CURRENT_STORE_ENTRY_VERSION = 2;
778
976
  /**
779
977
  * A complete entry stored in the ContentAddressedStore.
780
978
  * Extends StoreEntryMetadata with the actual encrypted payload.
@@ -829,7 +1027,35 @@ export interface AttachmentReference {
829
1027
  * Public signing key of the user who created this attachment (Ed25519, PEM format)
830
1028
  */
831
1029
  createdBy: string;
1030
+ /**
1031
+ * Plain text extracted from the attachment content (capped at
1032
+ * {@link ATTACHMENT_EXTRACTED_TEXT_MAX_CHARS}).
1033
+ */
1034
+ extractedText?: string;
1035
+ /** Outcome of the last extraction attempt for this attachment. */
1036
+ extractionStatus?: AttachmentExtractionStatus;
1037
+ /**
1038
+ * Identifier of the extraction engine/config that produced the result
1039
+ * (e.g. "tesseract.js@7:deu+eng"). Lets services re-extract when the
1040
+ * engine or language set changes.
1041
+ */
1042
+ extractionEngine?: string;
1043
+ /** Timestamp of the last extraction attempt (ms since Unix epoch). */
1044
+ extractedAt?: number;
832
1045
  }
1046
+ /**
1047
+ * Outcome of an attachment text extraction attempt (see
1048
+ * {@link MindooDoc.setAttachmentExtractedText}). "failed"/"skipped" markers
1049
+ * are persisted so other devices do not retry a broken or deliberately
1050
+ * skipped attachment over and over.
1051
+ */
1052
+ export type AttachmentExtractionStatus = "done" | "failed" | "skipped";
1053
+ /**
1054
+ * Upper bound on persisted extracted text per attachment. The text lives
1055
+ * inside the synced CRDT document, so a single giant scan must not bloat
1056
+ * the document and every future sync delta.
1057
+ */
1058
+ export declare const ATTACHMENT_EXTRACTED_TEXT_MAX_CHARS = 100000;
833
1059
  export interface IncompleteAttachmentUploadReclaimResult {
834
1060
  scannedLedgers: number;
835
1061
  reclaimedUploads: number;
@@ -1086,6 +1312,31 @@ export interface CreateOptions {
1086
1312
  * `signingKeyPair` is provided.
1087
1313
  */
1088
1314
  signingKeyPassword?: string;
1315
+ /**
1316
+ * Optional initial field values applied within the document's very first
1317
+ * Automerge change (the `doc_create` entry).
1318
+ *
1319
+ * This matters for access control: a `doc_create` Tier 2 rule (e.g. "the
1320
+ * creator must add themselves to `myeditors`") is evaluated against the
1321
+ * document's "after" state — the state produced by the create. Seeding those
1322
+ * values here lets the create entry itself satisfy the rule, instead of
1323
+ * requiring a separate follow-up change (docs/accesscontrol.md §6.3, §9).
1324
+ *
1325
+ * Reserved/internal fields (e.g. `_attachments`) are managed by MindooDB and
1326
+ * must not be supplied here. Custom-ID documents still receive their seeded
1327
+ * ancestry change; initial values are applied on top of it.
1328
+ */
1329
+ initialValues?: Record<string, unknown>;
1330
+ /**
1331
+ * Skip the synchronous client-side write-policy precheck (Tier 1 + Tier 2)
1332
+ * that would otherwise throw {@link AccessDeniedError} when the create
1333
+ * violates the active access control rules (docs/accesscontrol.md §9).
1334
+ *
1335
+ * For trusted/bulk paths only. This does NOT weaken security: the server
1336
+ * witness (Tier 1) and quarantine-on-materialization (Tier 2) still enforce
1337
+ * the rules. Defaults to `false`.
1338
+ */
1339
+ bypassAccessControlPrecheck?: boolean;
1089
1340
  }
1090
1341
  /**
1091
1342
  * Options accepted by `MindooDB.deleteDocument()`.
@@ -1102,6 +1353,15 @@ export interface DeleteOptions {
1102
1353
  * `signingKeyPair` is provided.
1103
1354
  */
1104
1355
  signingKeyPassword?: string;
1356
+ /**
1357
+ * Skip the synchronous client-side write-policy precheck (Tier 1 + Tier 2)
1358
+ * that would otherwise throw {@link AccessDeniedError} when the delete
1359
+ * violates the active access control rules (docs/accesscontrol.md §9).
1360
+ *
1361
+ * For trusted/bulk paths only; the server witness and
1362
+ * quarantine-on-materialization still enforce the rules. Defaults to `false`.
1363
+ */
1364
+ bypassAccessControlPrecheck?: boolean;
1105
1365
  }
1106
1366
  /**
1107
1367
  * Options accepted by `MindooDB.undeleteDocument()`.
@@ -1117,6 +1377,15 @@ export interface UndeleteOptions {
1117
1377
  * `signingKeyPair` is provided.
1118
1378
  */
1119
1379
  signingKeyPassword?: string;
1380
+ /**
1381
+ * Skip the synchronous client-side write-policy precheck (Tier 1 + Tier 2)
1382
+ * that would otherwise throw {@link AccessDeniedError} when the undelete
1383
+ * violates the active access control rules (docs/accesscontrol.md §9).
1384
+ *
1385
+ * For trusted/bulk paths only; the server witness and
1386
+ * quarantine-on-materialization still enforce the rules. Defaults to `false`.
1387
+ */
1388
+ bypassAccessControlPrecheck?: boolean;
1120
1389
  }
1121
1390
  /**
1122
1391
  * Options accepted by `MindooDB.changeDoc()`.
@@ -1133,6 +1402,15 @@ export interface ChangeOptions {
1133
1402
  * `signingKeyPair` is provided.
1134
1403
  */
1135
1404
  signingKeyPassword?: string;
1405
+ /**
1406
+ * Skip the synchronous client-side write-policy precheck (Tier 1 + Tier 2)
1407
+ * that would otherwise throw {@link AccessDeniedError} when the change
1408
+ * violates the active access control rules (docs/accesscontrol.md §9).
1409
+ *
1410
+ * For trusted/bulk paths only; the server witness and
1411
+ * quarantine-on-materialization still enforce the rules. Defaults to `false`.
1412
+ */
1413
+ bypassAccessControlPrecheck?: boolean;
1136
1414
  }
1137
1415
  /**
1138
1416
  * A MindooDoc is a document that is stored in the MindooDB.
@@ -1173,6 +1451,53 @@ export interface MindooDoc {
1173
1451
  * @return True if the document has been deleted, false otherwise
1174
1452
  */
1175
1453
  isDeleted(): boolean;
1454
+ /**
1455
+ * Whether the current KeyBag can decrypt this document (docs/accesscontrol.md
1456
+ * §13). `true` for normally-loaded documents. `false` only for changefeed
1457
+ * tombstones emitted by {@link MindooDB.iterateChangesSince} for a document
1458
+ * that was readable before but whose decryption key the local KeyBag no longer
1459
+ * holds (e.g. a revoked key). Such a tombstone also reports
1460
+ * {@link isDeleted} `=== true` so legacy consumers still drop it; pair the two
1461
+ * to distinguish a genuine deletion (`isDeleted && isAccessible`) from a
1462
+ * missing-key situation (`isDeleted && !isAccessible`). Its {@link getData}
1463
+ * returns `{}` (the plaintext is purged, never materialized).
1464
+ *
1465
+ * @return True when the document's key is available, false for an
1466
+ * inaccessible-key tombstone.
1467
+ */
1468
+ isAccessible(): boolean;
1469
+ /**
1470
+ * Whether this document is still "awaiting witness": it has at least one
1471
+ * versioned store entry (written in the witness-aware era) that has not yet
1472
+ * been witnessed by a trusted server (no `receivedAt`) — i.e. it was created
1473
+ * or edited locally and is still waiting to be pushed and stamped with a
1474
+ * provable receipt. Built on the same `isProvisional` predicate as the
1475
+ * version-aware trusted-time rule (see `core/storeEntryTime.ts`), so it can
1476
+ * never diverge from it.
1477
+ *
1478
+ * Legacy documents (whose entries predate the witness era and carry no
1479
+ * `entryVersion`) are never awaiting witness. Once every entry of a document
1480
+ * has a `receivedAt`, the flag clears.
1481
+ *
1482
+ * @return True if any of the document's entries is versioned-but-un-witnessed.
1483
+ */
1484
+ isAwaitingWitness(): boolean;
1485
+ /**
1486
+ * Whether this document has been witnessed by a trusted server: it is
1487
+ * witness-era (has at least one versioned store entry) AND every versioned
1488
+ * entry now carries a `receivedAt`. Mutually exclusive with
1489
+ * {@link isAwaitingWitness}: a versioned document starts out awaiting witness
1490
+ * and flips to witnessed once its entries are stamped with a provable receipt.
1491
+ *
1492
+ * Legacy documents (whose entries predate the witness era and carry no
1493
+ * `entryVersion`) are never witnessed — they return `false` here and from
1494
+ * {@link isAwaitingWitness}. Built on the same `isVersioned`/`isProvisional`
1495
+ * predicates as the version-aware trusted-time rule (see
1496
+ * `core/storeEntryTime.ts`), so it can never diverge from it.
1497
+ *
1498
+ * @return True for a witness-era document whose entries are all witnessed.
1499
+ */
1500
+ isWitnessed(): boolean;
1176
1501
  getData(): MindooDocPayload;
1177
1502
  /**
1178
1503
  * Get the current Automerge heads for this document.
@@ -1232,6 +1557,32 @@ export interface MindooDoc {
1232
1557
  * @throws Error if called outside of changeDoc() callback or if attachment not found
1233
1558
  */
1234
1559
  appendToAttachment(attachmentId: string, data: Uint8Array): Promise<void>;
1560
+ /**
1561
+ * Persist extracted plain text (e.g. from OCR) at the attachment it
1562
+ * belongs to. The text is stored as optional fields on the attachment's
1563
+ * `_attachments` entry, syncs with the document, and disappears together
1564
+ * with the attachment on removeAttachment(). The full-text index picks
1565
+ * persisted text up automatically (synthetic `_attachments` field) —
1566
+ * no extractor run needed.
1567
+ *
1568
+ * This method only works within the changeDoc() callback. `_`-prefixed
1569
+ * fields are managed by MindooDB; this is the sanctioned write path for
1570
+ * extraction results.
1571
+ *
1572
+ * @param attachmentId The ID of the attachment the text was extracted from
1573
+ * @param result Extraction outcome: `text` is capped at
1574
+ * {@link ATTACHMENT_EXTRACTED_TEXT_MAX_CHARS}; pass `text: null` to
1575
+ * clear a previous result (e.g. before re-extraction). `status`
1576
+ * defaults to "done" when text is provided. `engine`/`extractedAt`
1577
+ * let services detect stale results after engine upgrades.
1578
+ * @throws Error if called outside of changeDoc() callback or if attachment not found
1579
+ */
1580
+ setAttachmentExtractedText(attachmentId: string, result: {
1581
+ text: string | null;
1582
+ status?: AttachmentExtractionStatus;
1583
+ engine?: string;
1584
+ extractedAt?: number;
1585
+ }): void;
1235
1586
  /**
1236
1587
  * Get all attachment references for this document.
1237
1588
  *
@@ -1578,6 +1929,64 @@ export interface DirectoryUserLookup {
1578
1929
  signingPublicKey: string;
1579
1930
  encryptionPublicKey: string;
1580
1931
  details: DirectoryUserDetails | null;
1932
+ /**
1933
+ * Precomputed `$publicinfos`-readable identity-hash bundle for the grant
1934
+ * (docs/accesscontrol.md §6.5): the v1+v2 hashes of every DN-hierarchy
1935
+ * username variant, computed from the cleartext name at grant time. Lets the
1936
+ * server resolve wildcard/group read rules purely in hash space, without ever
1937
+ * needing the cleartext username. Absent on legacy grants written before the
1938
+ * bundle existed (treated as version 0, exact-match only).
1939
+ */
1940
+ identityHashes?: string[];
1941
+ /**
1942
+ * Version of the variant-generation algorithm used to compute
1943
+ * {@link identityHashes}. `0`/absent means the bundle is missing (legacy
1944
+ * grant) and the reader must degrade to exact `username_hash` matching and
1945
+ * flag the grant for backfill.
1946
+ */
1947
+ identityHashesV?: number;
1948
+ }
1949
+ /**
1950
+ * A single device's key pair on a grant document (docs/accesscontrol.md §6.5).
1951
+ *
1952
+ * Newer grants store an array of these objects (`userKeyPairs`) instead of two
1953
+ * parallel `userSigningPublicKeys` / `userEncryptionPublicKeys` arrays, so that
1954
+ * each device's signing and encryption keys stay paired and can carry an
1955
+ * optional human-readable `label` (e.g. a date or a note about the device
1956
+ * type). Readers remain backward-compatible with the older array/scalar forms.
1957
+ *
1958
+ * On disk, active and revoked devices live in two separate lists: `userKeyPairs`
1959
+ * holds the ACTIVE devices, and `revokedUserKeyPairs` holds the RETAINED revoked
1960
+ * devices (docs/accesscontrol.md §6.5). The {@link revoked}/{@link revokedAt}
1961
+ * fields below are the in-memory representation produced by the grant-key
1962
+ * extractors regardless of which list a pair came from; writers partition pairs
1963
+ * back into the two lists by their {@link revoked} flag.
1964
+ */
1965
+ export interface GrantKeyPair {
1966
+ /** Ed25519 signing public key (PEM) — the device's identity. */
1967
+ signingPublicKey: string;
1968
+ /** RSA-OAEP encryption public key (PEM) paired with the signing key. */
1969
+ encryptionPublicKey: string;
1970
+ /** Optional human-readable label for this device/key pair. */
1971
+ label?: string;
1972
+ /**
1973
+ * When true, this device's access has been revoked but the pair is RETAINED
1974
+ * on the grant document (docs/accesscontrol.md §6.5) so admin UIs can list
1975
+ * revoked devices and optionally restore them. Revoked pairs are excluded
1976
+ * from the active key arrays the server/auth read, so they cannot
1977
+ * authenticate or decrypt new data. Absent/false means active.
1978
+ */
1979
+ revoked?: boolean;
1980
+ /**
1981
+ * Trusted-time (ms since Unix epoch) at which this device was revoked. Set
1982
+ * together with {@link revoked}; cleared when the device is restored.
1983
+ */
1984
+ revokedAt?: number;
1985
+ }
1986
+ /** A {@link GrantKeyPair} enriched with its current remote-wipe status (§6.5). */
1987
+ export interface GrantKeyPairInfo extends GrantKeyPair {
1988
+ /** True when this device's signing key is flagged for a remote wipe. */
1989
+ wipeRequested: boolean;
1581
1990
  }
1582
1991
  export interface MindooTenantDirectory {
1583
1992
  /**
@@ -1587,29 +1996,535 @@ export interface MindooTenantDirectory {
1587
1996
  * @param userId The user ID to register
1588
1997
  * @param administrationPrivateKey The administration private key to sign the registration operation with (signing only)
1589
1998
  * @param administrationPrivateKeyPassword The password to decrypt the administration private key
1999
+ * @param userDetails The user details to register
2000
+ * @param label The label to register the user with
1590
2001
  * @return A promise that resolves when the user is registered
1591
2002
  */
1592
- registerUser(userId: PublicUserId, administrationPrivateKey: EncryptedPrivateKey, administrationPrivateKeyPassword: string, userDetails?: DirectoryUserDetails): Promise<void>;
2003
+ registerUser(userId: PublicUserId, administrationPrivateKey: EncryptedPrivateKey, administrationPrivateKeyPassword: string, userDetails?: DirectoryUserDetails, label?: string): Promise<void>;
1593
2004
  /**
1594
- * Revokes a user's access to the tenant by adding a revocation record to the directory.
1595
- * This prevents the user from decrypting future changes, but they retain access to previously
1596
- * decrypted changes (append-only limitation).
2005
+ * Revokes a user's access by removing their keys from the grant document
2006
+ * (docs/accesscontrol.md §6.5). Revocation is an in-place edit of the grant
2007
+ * document's key arrays; there is no separate revocation document. This
2008
+ * prevents the user from decrypting future changes, but they retain access to
2009
+ * previously decrypted changes (append-only limitation).
2010
+ *
2011
+ * By default (no `options.signingKeys`) the user is fully revoked: all of
2012
+ * their signing and encryption keys are removed. To revoke a single
2013
+ * device/key, pass the specific keys to remove.
1597
2014
  *
1598
- * @param username The username of the user to revoke (format: "CN=<username>/O=<tenantId>")
1599
- * @param requestDataWipe If true, the next time the user syncs the directory, the locally cached data on the user's machine will be wiped.
1600
- * @param administrationPrivateKey The administration private key to sign the revocation (signing only)
2015
+ * BREAKING CHANGE: the previous signature took a positional `requestDataWipe`
2016
+ * boolean. It now takes an options object so that specific keys can be
2017
+ * targeted instead of always removing all access.
2018
+ *
2019
+ * @param username The username to revoke (format: "CN=<username>/O=<tenantId>")
2020
+ * @param options.signingKeys Specific signing keys to remove; omit/empty to fully revoke the user.
2021
+ * @param options.encryptionKeys Specific encryption keys to remove; ignored on a full revocation (all are removed).
2022
+ * @param options.requestDataWipe If true, the removed devices are flagged for a remote wipe so their locally cached data is deleted on next sync.
2023
+ * @param administrationPrivateKey The administration private key to sign the change (signing only)
1601
2024
  * @param administrationPrivateKeyPassword The password to decrypt the administration private key
1602
2025
  * @return A promise that resolves when the user is revoked
1603
2026
  */
1604
- revokeUser(username: string, requestDataWipe: boolean, administrationPrivateKey: EncryptedPrivateKey, administrationPrivateKeyPassword: string): Promise<void>;
2027
+ revokeUser(username: string, options: {
2028
+ signingKeys?: string[];
2029
+ encryptionKeys?: string[];
2030
+ requestDataWipe?: boolean;
2031
+ }, administrationPrivateKey: EncryptedPrivateKey, administrationPrivateKeyPassword: string): Promise<void>;
1605
2032
  /**
1606
2033
  * Validates a public signing key by checking if it belongs to a trusted user in the tenant.
1607
2034
  * This is used for signature verification when loading changes from the append-only store.
1608
2035
  *
1609
2036
  * @param publicKey The public signing key to validate (Ed25519, PEM format)
2037
+ * @param opts.forceRefresh When true, bypass the trust-cache refresh interval
2038
+ * and synchronize the directory state before validating. Used on the server
2039
+ * push path so a freshly revoked key cannot still be accepted for up to
2040
+ * `DIRECTORY_SYNC_INTERVAL_MS` (audit #4, revocation lag).
1610
2041
  * @return True if the public key belongs to a trusted (registered and not revoked) user, false otherwise
1611
2042
  */
1612
- validatePublicSigningKey(publicKey: string): Promise<boolean>;
2043
+ validatePublicSigningKey(publicKey: string, opts?: {
2044
+ forceRefresh?: boolean;
2045
+ }): Promise<boolean>;
2046
+ /**
2047
+ * Create or update the tenant-wide default access policy
2048
+ * (docs/accesscontrol.md §6.1). Creating this document is what activates
2049
+ * access control for the tenant. Only the supplied fields are written.
2050
+ *
2051
+ * @param policy The policy fields to write (omitted fields keep their stored value / take their documented default).
2052
+ * @param administrationPrivateKey The administration private key to sign the change (signing only).
2053
+ * @param administrationPrivateKeyPassword The password to decrypt the administration private key.
2054
+ * @returns A promise that resolves when the policy has been written.
2055
+ */
2056
+ setDefaultAccessPolicy?(policy: Partial<Omit<DefaultAccessPolicyDoc, "form" | "type">>, administrationPrivateKey: EncryptedPrivateKey, administrationPrivateKeyPassword: string): Promise<void>;
2057
+ /**
2058
+ * Create or update a per-database access policy override (§6.2). Fields set
2059
+ * here override the tenant default for `dbid`; unset fields inherit it.
2060
+ *
2061
+ * @param dbid The database the policy override applies to.
2062
+ * @param policy The policy fields to write (omitted fields inherit the tenant default for `dbid`).
2063
+ * @param administrationPrivateKey The administration private key to sign the change (signing only).
2064
+ * @param administrationPrivateKeyPassword The password to decrypt the administration private key.
2065
+ * @returns A promise that resolves when the policy override has been written.
2066
+ */
2067
+ setDatabaseAccessPolicy?(dbid: string, policy: Partial<Omit<DefaultAccessPolicyDoc, "form" | "type">>, administrationPrivateKey: EncryptedPrivateKey, administrationPrivateKeyPassword: string): Promise<void>;
2068
+ /**
2069
+ * Create or replace an access-control rule (§6.3). A rule carrying
2070
+ * `withfields` is Tier 2 (client-enforced); otherwise it is Tier 1
2071
+ * (server-enforced).
2072
+ *
2073
+ * @param rule The rule definition.
2074
+ * @param rule.ruleId Stable rule id; surfaced in `AccessDecision.matchedRuleId` and used to replace an existing rule.
2075
+ * @param rule.type The operation the rule governs (`doc_create`, `doc_change`, …).
2076
+ * @param rule.dbid The database the rule applies to, or `"*"` for all databases (defaults to `"*"` when omitted).
2077
+ * @param rule.action Whether the rule grants (`"allow"`) or revokes (`"deny"`) access (deny overrides allow).
2078
+ * @param rule.users_hashes Precomputed user/group hashes plus pseudo-tokens (`$everyone`, `$admin`, `$author`) the rule targets.
2079
+ * @param rule.usernames Cleartext usernames to target; hashed and stored, and kept (encrypted) for admin-UI display.
2080
+ * @param rule.groups Cleartext group names to target; hashed and stored alongside `usernames`.
2081
+ * @param rule.withfields Tier 2 content clauses; their presence makes the rule client-enforced only.
2082
+ * @param rule.description Optional human-readable description for admin UIs.
2083
+ * @param administrationPrivateKey The administration private key to sign the change (signing only).
2084
+ * @param administrationPrivateKeyPassword The password to decrypt the administration private key.
2085
+ * @returns A promise that resolves when the rule has been written.
2086
+ */
2087
+ createAccessRule?(rule: {
2088
+ ruleId: string;
2089
+ type: RuleType;
2090
+ dbid?: string;
2091
+ action?: "allow" | "deny";
2092
+ users_hashes?: string[];
2093
+ usernames?: string[];
2094
+ groups?: string[];
2095
+ withfields?: WithFieldClause[];
2096
+ description?: string;
2097
+ }, administrationPrivateKey: EncryptedPrivateKey, administrationPrivateKeyPassword: string): Promise<void>;
2098
+ /**
2099
+ * List access-control rules in effect (§9), optionally filtered. Each rule
2100
+ * may carry decrypted `targets` (usernames/groups) for admin-UI display when
2101
+ * the rule was authored with cleartext names and the caller holds the tenant
2102
+ * default key; otherwise only the raw `users_hashes` are available.
2103
+ *
2104
+ * @param filter Optional narrowing by rule `type` and/or `dbid`.
2105
+ * @returns The matching rules, each optionally augmented with decrypted `targets`.
2106
+ */
2107
+ listRules?(filter?: {
2108
+ type?: RuleType;
2109
+ dbid?: string;
2110
+ }): Promise<Array<AclRuleDoc & {
2111
+ targets?: RuleTargets;
2112
+ }>>;
2113
+ /**
2114
+ * Delete an access-control rule by id (§9).
2115
+ *
2116
+ * @param ruleId The id of the rule to delete.
2117
+ * @param administrationPrivateKey The administration private key to sign the change (signing only).
2118
+ * @param administrationPrivateKeyPassword The password to decrypt the administration private key.
2119
+ * @returns A promise that resolves when the rule has been deleted.
2120
+ */
2121
+ deleteRule?(ruleId: string, administrationPrivateKey: EncryptedPrivateKey, administrationPrivateKeyPassword: string): Promise<void>;
2122
+ /**
2123
+ * Add (or refresh) a trusted witness (§6.4).
2124
+ *
2125
+ * @param witness The witness to trust.
2126
+ * @param witness.witnessPublicKey The witness's Ed25519 signing public key (PEM).
2127
+ * @param witness.serverUrl Optional URL of the witness/sync server, for display.
2128
+ * @param administrationPrivateKey The administration private key to sign the change (signing only).
2129
+ * @param administrationPrivateKeyPassword The password to decrypt the administration private key.
2130
+ * @returns A promise that resolves when the witness has been written.
2131
+ */
2132
+ addTrustedWitness?(witness: {
2133
+ witnessPublicKey: string;
2134
+ serverUrl?: string;
2135
+ }, administrationPrivateKey: EncryptedPrivateKey, administrationPrivateKeyPassword: string): Promise<void>;
2136
+ /**
2137
+ * Remove a trusted witness by its public key (§6.4).
2138
+ *
2139
+ * @param witnessPublicKey The Ed25519 signing public key (PEM) of the witness to remove.
2140
+ * @param administrationPrivateKey The administration private key to sign the change (signing only).
2141
+ * @param administrationPrivateKeyPassword The password to decrypt the administration private key.
2142
+ * @returns A promise that resolves when the witness has been removed.
2143
+ */
2144
+ removeTrustedWitness?(witnessPublicKey: string, administrationPrivateKey: EncryptedPrivateKey, administrationPrivateKeyPassword: string): Promise<void>;
2145
+ /**
2146
+ * Add device key pairs to a user's grant (§6.5 key rollover / new device).
2147
+ *
2148
+ * BREAKING CHANGE: previously took parallel `signingKeys` / `encryptionKeys`
2149
+ * string arrays. It now takes an array of {@link GrantKeyPair} objects so the
2150
+ * signing and encryption keys stay paired and can carry an optional `label`.
2151
+ * Existing pairs are merged by signing key (a new entry with the same signing
2152
+ * key updates its encryption key/label).
2153
+ *
2154
+ * @param username The user whose grant to add device key pairs to (format: "CN=<username>/O=<tenantId>").
2155
+ * @param keyPairs The device key pairs (paired signing + encryption keys, optional `label`) to add or merge.
2156
+ * @param administrationPrivateKey The administration private key to sign the change (signing only).
2157
+ * @param administrationPrivateKeyPassword The password to decrypt the administration private key.
2158
+ * @returns A promise that resolves when the keys have been added.
2159
+ */
2160
+ addUserKeys?(username: string, keyPairs: GrantKeyPair[], administrationPrivateKey: EncryptedPrivateKey, administrationPrivateKeyPassword: string): Promise<void>;
2161
+ /**
2162
+ * Remove keys from a user's grant by signing key (and optionally encryption
2163
+ * key) (§6.5 revoke a device/key). Removing a signing key removes its entire
2164
+ * paired entry.
2165
+ *
2166
+ * @param username The user whose keys to remove (format: "CN=<username>/O=<tenantId>").
2167
+ * @param signingKeys The signing public keys whose paired entries to remove.
2168
+ * @param encryptionKeys The encryption public keys to remove (typically the pairs of `signingKeys`).
2169
+ * @param administrationPrivateKey The administration private key to sign the change (signing only).
2170
+ * @param administrationPrivateKeyPassword The password to decrypt the administration private key.
2171
+ * @returns A promise that resolves when the keys have been removed.
2172
+ */
2173
+ removeUserKeys?(username: string, signingKeys: string[], encryptionKeys: string[], administrationPrivateKey: EncryptedPrivateKey, administrationPrivateKeyPassword: string): Promise<void>;
2174
+ /**
2175
+ * Set or clear the human-readable label of a device's key pair, identified by
2176
+ * its signing public key (§6.5). Pass an empty/whitespace label to clear it.
2177
+ * No-op if the user has no key pair with that signing key.
2178
+ *
2179
+ * @param username The user whose device label to set (format: "CN=<username>/O=<tenantId>").
2180
+ * @param signingPublicKey The signing public key identifying the device key pair to label.
2181
+ * @param label The new label; empty/whitespace clears the existing label.
2182
+ * @param administrationPrivateKey The administration private key to sign the change (signing only).
2183
+ * @param administrationPrivateKeyPassword The password to decrypt the administration private key.
2184
+ * @returns A promise that resolves when the label has been written.
2185
+ */
2186
+ setKeyPairLabel?(username: string, signingPublicKey: string, label: string, administrationPrivateKey: EncryptedPrivateKey, administrationPrivateKeyPassword: string): Promise<void>;
2187
+ /**
2188
+ * List a user's currently-granted device key pairs (§6.5), each with its
2189
+ * optional label and current remote-wipe status. Returns one entry per
2190
+ * signing key; revoked keys (removed from the grant) are not included.
2191
+ * Useful for admin UIs that let an operator pick specific devices to revoke
2192
+ * or relabel.
2193
+ *
2194
+ * @param username The user whose active device key pairs to list (format: "CN=<username>/O=<tenantId>").
2195
+ * @returns The user's active device key pairs, each with its label and remote-wipe status.
2196
+ */
2197
+ getUserKeyPairs?(username: string): Promise<GrantKeyPairInfo[]>;
2198
+ /**
2199
+ * Read a user's grant overview for an admin "manage user" UI (§6.5): the
2200
+ * decrypted user-details payload, the active device key pairs, and the
2201
+ * retained revoked device key pairs (each with `revokedAt` + remote-wipe
2202
+ * status). Requires the tenant default key to decrypt details.
2203
+ *
2204
+ * @param username The user whose grant overview to read (format: "CN=<username>/O=<tenantId>").
2205
+ * @returns The decrypted `details` (or null), the `activeDevices`, and the retained `revokedDevices` (each with remote-wipe status).
2206
+ */
2207
+ getUserGrantOverview?(username: string): Promise<{
2208
+ details: DirectoryUserDetails | null;
2209
+ activeDevices: GrantKeyPairInfo[];
2210
+ revokedDevices: Array<GrantKeyPair & {
2211
+ wipeRequested: boolean;
2212
+ }>;
2213
+ }>;
2214
+ /**
2215
+ * Apply a batch of admin-signed edits to a user's grant in a single change per
2216
+ * grant document (§6.5): rewrite `details`, recompute the `identity_hashes`
2217
+ * bundle, set per-device labels, revoke/restore devices (retaining revoked
2218
+ * pairs with `revoked`/`revokedAt`), and set the remote-wipe set. Backs the
2219
+ * Haven "Manage user" dialog's batched Save.
2220
+ *
2221
+ * @param username The user whose grant to update (format: "CN=<username>/O=<tenantId>").
2222
+ * @param changes The batched edits to apply.
2223
+ * @param changes.details Rewritten user-details payload (also recomputes the `identity_hashes` bundle).
2224
+ * @param changes.deviceLabels Map of signing public key → new label for the user's devices.
2225
+ * @param changes.revokeSigningKeys Signing keys whose devices to revoke (moved to the revoked list with `revokedAt`).
2226
+ * @param changes.restoreSigningKeys Signing keys whose previously-revoked devices to restore to active.
2227
+ * @param changes.wipeSigningKeys Signing keys whose devices to flag for remote wipe.
2228
+ * @param administrationPrivateKey The administration private key to sign the change (signing only).
2229
+ * @param administrationPrivateKeyPassword The password to decrypt the administration private key.
2230
+ * @returns A promise that resolves when the grant has been updated.
2231
+ */
2232
+ updateUserGrant?(username: string, changes: {
2233
+ details?: DirectoryUserDetails;
2234
+ deviceLabels?: Record<string, string>;
2235
+ revokeSigningKeys?: string[];
2236
+ restoreSigningKeys?: string[];
2237
+ wipeSigningKeys?: string[];
2238
+ }, administrationPrivateKey: EncryptedPrivateKey, administrationPrivateKeyPassword: string): Promise<void>;
2239
+ /**
2240
+ * Request a remote wipe of specific devices by signing public key (§6.5).
2241
+ *
2242
+ * @param username The user who owns the devices (format: "CN=<username>/O=<tenantId>").
2243
+ * @param signingKeys The signing public keys of the devices to flag for remote wipe.
2244
+ * @param administrationPrivateKey The administration private key to sign the change (signing only).
2245
+ * @param administrationPrivateKeyPassword The password to decrypt the administration private key.
2246
+ * @returns A promise that resolves when the wipe directive has been written.
2247
+ */
2248
+ requestDeviceWipe?(username: string, signingKeys: string[], administrationPrivateKey: EncryptedPrivateKey, administrationPrivateKeyPassword: string): Promise<void>;
2249
+ /**
2250
+ * Cancel a previously-requested device wipe (§6.5).
2251
+ *
2252
+ * @param username The user who owns the devices (format: "CN=<username>/O=<tenantId>").
2253
+ * @param signingKeys The signing public keys whose pending wipe directive to clear.
2254
+ * @param administrationPrivateKey The administration private key to sign the change (signing only).
2255
+ * @param administrationPrivateKeyPassword The password to decrypt the administration private key.
2256
+ * @returns A promise that resolves when the wipe directive has been cleared.
2257
+ */
2258
+ cancelDeviceWipe?(username: string, signingKeys: string[], administrationPrivateKey: EncryptedPrivateKey, administrationPrivateKeyPassword: string): Promise<void>;
2259
+ /**
2260
+ * Whether access control is currently active for this tenant (§6.1, §7).
2261
+ *
2262
+ * @returns `true` when a default policy exists and the master kill-switch is not engaged, otherwise `false`.
2263
+ */
2264
+ isAccessControlActive?(): Promise<boolean>;
2265
+ /**
2266
+ * Predict whether the current user may perform `op` on `dbid` (§9).
2267
+ *
2268
+ * @param op The write operation to predict (`doc_create`, `doc_change`, …).
2269
+ * @param dbid The database the operation would target.
2270
+ * @param candidateDoc Optional candidate document content, for evaluating Tier 2 (`withfields`) content rules.
2271
+ * @returns The {@link AccessDecision} that would result for the current user.
2272
+ */
2273
+ canDo?(op: RuleType, dbid: string, candidateDoc?: Record<string, unknown>): Promise<AccessDecision>;
2274
+ /**
2275
+ * Audit: was `username` allowed to perform `op` on `dbid` at trusted time
2276
+ * `at`? (§9) Evaluates against the directory state as it was at `at`, so
2277
+ * historical decisions can be explained.
2278
+ *
2279
+ * @param op The write operation to evaluate (`doc_create`, `doc_change`, …).
2280
+ * @param username The user whose access to evaluate (format: "CN=<username>/O=<tenantId>").
2281
+ * @param dbid The database the operation targets.
2282
+ * @param at The trusted time (ms epoch) selecting the historical directory-state node to evaluate against.
2283
+ * @param candidateDoc Optional candidate document content, for evaluating Tier 2 (`withfields`) content rules.
2284
+ * @returns The {@link AccessDecision} that applied at `at`.
2285
+ */
2286
+ wasAllowedAt?(op: RuleType, username: string, dbid: string, at: number, candidateDoc?: Record<string, unknown>): Promise<AccessDecision>;
2287
+ /**
2288
+ * Evaluate the full client-side write ruleset (Tier 1 + Tier 2) for a
2289
+ * candidate write at `trustedTime` (docs/accesscontrol.md §7, §9.1).
2290
+ * `beforeDoc`/`afterDoc` are only consulted by Tier 2 (`withfields`) content
2291
+ * rules. Used by the SDK write prechecks and by materialization-time
2292
+ * enforcement.
2293
+ *
2294
+ * @param input The candidate write to evaluate.
2295
+ * @param input.op The write operation being evaluated (`doc_create`, `doc_change`, …).
2296
+ * @param input.dbid The database the write targets.
2297
+ * @param input.signingKey The author's Ed25519 signing public key (PEM); resolved to a user identity for rule matching.
2298
+ * @param input.trustedTime The entry's trusted time (ms epoch) — selects the directory-state node the rules are evaluated against (§8).
2299
+ * @param input.isAuthor Whether the signer is the original creator of the target document, for `$author` ownership rules.
2300
+ * @param input.beforeDoc The document state before the change (for `when: "before"` clauses), or `null` when unavailable/not needed.
2301
+ * @param input.afterDoc The document state with the candidate change applied (for `when: "after"` clauses), or `null` when unavailable/not needed.
2302
+ * @returns The {@link AccessDecision} (allow/deny, deciding rule id, and tier).
2303
+ */
2304
+ evaluateClientAccess?(input: {
2305
+ op: RuleType;
2306
+ dbid: string;
2307
+ signingKey: string;
2308
+ trustedTime: number;
2309
+ isAuthor: boolean;
2310
+ beforeDoc: Record<string, unknown> | null;
2311
+ afterDoc: Record<string, unknown> | null;
2312
+ }): Promise<AccessDecision>;
2313
+ /**
2314
+ * Whether a Tier 2 (`withfields`) content rule exists for `op` on `dbid` at
2315
+ * the current head state. Lets callers skip materializing before/after
2316
+ * documents when only Tier 1 checks apply (§9.1).
2317
+ *
2318
+ * @param op The write operation to check for content rules.
2319
+ * @param dbid The database to check (a rule with `dbid: "*"` also matches).
2320
+ * @returns `true` if at least one matching Tier 2 (`withfields`) rule exists, otherwise `false`.
2321
+ */
2322
+ hasWriteContentRules?(op: RuleType, dbid: string): Promise<boolean>;
2323
+ /**
2324
+ * The effective `defaultCreateKeyId` for `dbid` at the current head state, or
2325
+ * `undefined` when unconstrained (§6.7). A create-time convenience used to
2326
+ * resolve the key a `doc_create` uses when the caller does not pass one.
2327
+ *
2328
+ * @param dbid The database whose effective default create-key to resolve (per-DB policy overrides the tenant default).
2329
+ * @returns The configured default `decryptionKeyId`, or `undefined` when no policy applies, the master switch is engaged, or no default is set (callers fall back to `"default"`).
2330
+ */
2331
+ getEffectiveDefaultCreateKeyId?(dbid: string): Promise<string | undefined>;
2332
+ /**
2333
+ * The set of trusted witness signing keys (PEM) as of trusted time `T` (§5,
2334
+ * §6.4). Used to verify witness receipts during materialization.
2335
+ *
2336
+ * @param T The trusted time (ms epoch) selecting the directory-state node to read the trusted-witness list from.
2337
+ * @returns The set of trusted witness Ed25519 signing public keys (PEM) in effect at `T`.
2338
+ */
2339
+ getTrustedWitnessKeysAt?(T: number): Promise<Set<string>>;
2340
+ /**
2341
+ * The canonical write-time hash for `username` (the value stored in a
2342
+ * distribution's `pushto`/`pullfrom` hash lists). Used to build `pullfrom`
2343
+ * entries when removing a user.
2344
+ *
2345
+ * @param username The user to hash (format: "CN=<username>/O=<tenantId>").
2346
+ * @returns The salted, normalized username hash.
2347
+ */
2348
+ getUsernameHash?(username: string): Promise<string>;
2349
+ /**
2350
+ * All ACTIVE (non-revoked) RSA encryption public keys (PEM) for `username` —
2351
+ * one per active device. Used to wrap a key for every device of a recipient.
2352
+ *
2353
+ * @param username The user to resolve (format: "CN=<username>/O=<tenantId>").
2354
+ * @returns The de-duplicated active encryption public keys.
2355
+ */
2356
+ getUserEncryptionPublicKeys?(username: string): Promise<string[]>;
2357
+ /**
2358
+ * Wrap every stored version of `keyId` (from the caller's KeyBag) to ALL
2359
+ * active encryption devices of `username`, producing the `pushto` device-map
2360
+ * shape used by the distribution doc and request URI. Throws if the caller
2361
+ * lacks the key or the recipient has no active encryption device.
2362
+ *
2363
+ * @param keyId The symmetric key (in the caller's KeyBag) to wrap.
2364
+ * @param username The recipient (format: "CN=<username>/O=<tenantId>").
2365
+ * @returns The recipient's wrapped device material.
2366
+ */
2367
+ wrapKeyForUserDevices?(keyId: string, username: string): Promise<KeyDistributionPushRecipient>;
2368
+ /**
2369
+ * The version manifest (`{createdAt, fingerprint}`) of `keyId` from the
2370
+ * caller's KeyBag — the source of truth for a distribution's `keyVersions`.
2371
+ *
2372
+ * @param keyId The symmetric key to read versions for.
2373
+ * @returns The version manifest (empty when the key is not held).
2374
+ */
2375
+ getKeyVersionManifest?(keyId: string): Promise<KeyVersionRef[]>;
2376
+ /**
2377
+ * Admin-sign and upsert the singleton `acl_keydistribution_<keyId>` document
2378
+ * from a request (built in-dialog or decoded from a request URI).
2379
+ *
2380
+ * @param request The full desired distribution state.
2381
+ * @param administrationPrivateKey The administration private key to sign the change (signing only).
2382
+ * @param administrationPrivateKeyPassword The password to decrypt the administration private key.
2383
+ */
2384
+ publishKeyDistribution?(request: KeyDistributionRequest, administrationPrivateKey: EncryptedPrivateKey, administrationPrivateKeyPassword: string): Promise<void>;
2385
+ /**
2386
+ * List all key-distribution documents at the directory head, decrypting
2387
+ * display fields when the tenant default key is held.
2388
+ *
2389
+ * @returns The distribution views.
2390
+ */
2391
+ listKeyDistributions?(): Promise<KeyDistributionView[]>;
2392
+ /**
2393
+ * Delete the singleton distribution document for `keyId` (admin-signed).
2394
+ *
2395
+ * @param keyId The distributed key id.
2396
+ * @param administrationPrivateKey The administration private key to sign the change.
2397
+ * @param administrationPrivateKeyPassword The password to decrypt the administration private key.
2398
+ */
2399
+ deleteKeyDistribution?(keyId: string, administrationPrivateKey: EncryptedPrivateKey, administrationPrivateKeyPassword: string): Promise<void>;
2400
+ /**
2401
+ * The key ids managed by a distribution at the directory head where `username`
2402
+ * is in the `pushto` list (managed status is derived, never persisted).
2403
+ *
2404
+ * @param username The user to resolve managed keys for.
2405
+ * @returns The managed key ids.
2406
+ */
2407
+ getManagedKeyIds?(username: string): Promise<string[]>;
2408
+ /**
2409
+ * The decryption key ids revoked for `username` at the directory head (every
2410
+ * `acl_keydistribution_<keyId>` whose `pullfrom` list matches the user).
2411
+ * Protected ids are never reported. Used client-side to bulk-remove revoked
2412
+ * keys from the KeyBag, and as the basis for the server's pull/push blacklist.
2413
+ * Optional.
2414
+ *
2415
+ * @param username The user to resolve revoked keys for.
2416
+ * @returns The revoked decryption key ids.
2417
+ */
2418
+ getRevokedDecryptionKeyIdsForUser?(username: string): Promise<string[]>;
2419
+ /**
2420
+ * Signing-key variant of {@link getRevokedDecryptionKeyIdsForUser} for the
2421
+ * sync server, which authenticates principals by signing public key. Resolves
2422
+ * the key to its user, then derives the revoked ids in hash space. The tenant
2423
+ * admin and non-user (service) keys are never revoked. Optional.
2424
+ *
2425
+ * @param signingKey The principal's signing public key (Ed25519, PEM).
2426
+ * @returns The revoked decryption key ids for that principal.
2427
+ */
2428
+ getRevokedDecryptionKeyIdsForSigningKey?(signingKey: string): Promise<string[]>;
2429
+ /**
2430
+ * Admin-sign and upsert the singleton `acl_appdistribution_<appId>` document
2431
+ * from a request (built in-dialog or decoded from a request URI). The payload
2432
+ * is a Haven application registration; recipient lists support users and
2433
+ * groups (docs/accesscontrol.md §13).
2434
+ *
2435
+ * @param request The full desired distribution state.
2436
+ * @param administrationPrivateKey The administration private key to sign the change (signing only).
2437
+ * @param administrationPrivateKeyPassword The password to decrypt the administration private key.
2438
+ */
2439
+ publishAppDistribution?(request: AppDistributionRequest, administrationPrivateKey: EncryptedPrivateKey, administrationPrivateKeyPassword: string): Promise<void>;
2440
+ /**
2441
+ * List all app-distribution documents at the directory head, decrypting
2442
+ * display + payload fields when the tenant default key is held.
2443
+ *
2444
+ * @returns The app-distribution views.
2445
+ */
2446
+ listAppDistributions?(): Promise<AppDistributionView[]>;
2447
+ /**
2448
+ * Delete the singleton app-distribution document for `appId` (admin-signed).
2449
+ *
2450
+ * @param appId The distributed app id.
2451
+ * @param administrationPrivateKey The administration private key to sign the change.
2452
+ * @param administrationPrivateKeyPassword The password to decrypt the administration private key.
2453
+ */
2454
+ deleteAppDistribution?(appId: string, administrationPrivateKey: EncryptedPrivateKey, administrationPrivateKeyPassword: string): Promise<void>;
2455
+ /**
2456
+ * The per-user app-distribution reconcile plan at the directory head: `have`
2457
+ * is every app the user is entitled to (pushto user/group, pull wins), and
2458
+ * `notHave` is every other distributed app id. Drives the Haven post-sync
2459
+ * install/update/remove pass (docs/accesscontrol.md §13).
2460
+ *
2461
+ * @param username The user to resolve the plan for.
2462
+ * @returns The reconcile plan.
2463
+ */
2464
+ getAppDistributionsForCurrentUser?(username: string): Promise<AppDistributionReconcilePlan>;
2465
+ /**
2466
+ * The app ids `username` is entitled to receive via `pushto` at the directory
2467
+ * head (managed status is derived, never persisted).
2468
+ *
2469
+ * @param username The user to resolve managed apps for.
2470
+ * @returns The managed app ids.
2471
+ */
2472
+ getManagedAppIds?(username: string): Promise<string[]>;
2473
+ /**
2474
+ * Admin-sign and upsert the `acl_syncsetuppolicy_<policyId>` document from a
2475
+ * sync setup policy request. Pre-configures (and optionally permanently
2476
+ * enforces) a set of databases on the targeted users'/groups' Haven Sync page.
2477
+ *
2478
+ * @param request The sync setup policy request (built in-dialog or decoded from a request URI).
2479
+ * @param administrationPrivateKey The administration private key to sign the change (signing only).
2480
+ * @param administrationPrivateKeyPassword The password to decrypt the administration private key.
2481
+ */
2482
+ publishSyncSetupPolicy?(request: SyncSetupPolicyRequest, administrationPrivateKey: EncryptedPrivateKey, administrationPrivateKeyPassword: string): Promise<void>;
2483
+ /**
2484
+ * List all sync-setup-policy documents at the directory head as views
2485
+ * (decrypting display fields when the tenant default key is held).
2486
+ *
2487
+ * @returns The sync setup policy views.
2488
+ */
2489
+ listSyncSetupPolicies?(): Promise<SyncSetupPolicyView[]>;
2490
+ /**
2491
+ * Delete the sync-setup-policy document for `policyId` (admin-signed).
2492
+ *
2493
+ * @param policyId The sync setup policy id.
2494
+ * @param administrationPrivateKey The administration private key to sign the change.
2495
+ * @param administrationPrivateKeyPassword The password to decrypt the administration private key.
2496
+ */
2497
+ deleteSyncSetupPolicy?(policyId: string, administrationPrivateKey: EncryptedPrivateKey, administrationPrivateKeyPassword: string): Promise<void>;
2498
+ /**
2499
+ * The per-user sync-setup reconcile plan at the directory head: the union of
2500
+ * databases the user is targeted for across all policies, each carrying the
2501
+ * effective lock state (locked when a `permanent` policy targets it and the
2502
+ * user is not released via `pullfrom`). Drives the Haven post-sync Sync-page
2503
+ * seed/lock pass.
2504
+ *
2505
+ * @param username The user to resolve the plan for.
2506
+ * @returns The reconcile plan.
2507
+ */
2508
+ getSyncSetupForCurrentUser?(username: string): Promise<SyncSetupPolicyReconcilePlan>;
2509
+ /**
2510
+ * Audit / time travel (§8): the head time-travel directory-state node ("now"),
2511
+ * after bringing the directory-state chain up to date. Carries the default
2512
+ * policy, per-database policies, rules, groups, user grants, and trusted
2513
+ * witnesses as they stand now. Used to drive the Haven directory-history UI.
2514
+ *
2515
+ * @returns The head {@link DirectoryStateNode} covering the current time.
2516
+ */
2517
+ getDirectoryStateHead?(): Promise<DirectoryStateNode>;
2518
+ /**
2519
+ * Audit / time travel (§8): the directory-state node covering trusted time
2520
+ * `T` — the directory exactly as it was at that point in time. Lets the Haven
2521
+ * directory-history UI inspect and diff users/groups/policies at any past
2522
+ * point between the collected trusted times of directory changes.
2523
+ *
2524
+ * @param T The trusted time (ms epoch) to resolve the directory state at.
2525
+ * @returns The {@link DirectoryStateNode} covering trusted time `T`.
2526
+ */
2527
+ getDirectoryStateAt?(T: number): Promise<DirectoryStateNode>;
1613
2528
  /**
1614
2529
  * Get a user's public keys from the directory.
1615
2530
  * Used for authentication (signature verification) and encryption (transport encryption).
@@ -1630,6 +2545,29 @@ export interface MindooTenantDirectory {
1630
2545
  * @return The matching user record, or null if no registration is known
1631
2546
  */
1632
2547
  getUserBySigningPublicKey(publicKey: string): Promise<DirectoryUserLookup | null>;
2548
+ /**
2549
+ * Resolve the signing keys relevant to authenticating a device for `username`
2550
+ * (docs/accesscontrol.md §6.5): currently-granted (`active`) keys and keys an
2551
+ * admin has targeted for remote wipe (`wipeRequested`). The two are
2552
+ * independent. Optional: directories without remote-wipe support omit it.
2553
+ *
2554
+ * @param username The user whose signing-key universe to resolve (format: "CN=<username>/O=<tenantId>").
2555
+ * @returns The `active` (currently-granted) and `wipeRequested` (remote-wipe-targeted) signing public keys.
2556
+ */
2557
+ getUserSigningKeyUniverse?(username: string): Promise<{
2558
+ active: string[];
2559
+ wipeRequested: string[];
2560
+ }>;
2561
+ /**
2562
+ * If `signingKey` is the target of an admin-requested remote wipe (§6.5),
2563
+ * return the id of the admin-signed grant document carrying the directive
2564
+ * (else null). Used by the sync server to serve only that document to the
2565
+ * targeted device. Optional.
2566
+ *
2567
+ * @param signingKey The device signing public key (PEM) to check for a pending wipe directive.
2568
+ * @returns The grant document id carrying the wipe directive, or `null` when the key is not wipe-targeted.
2569
+ */
2570
+ getWipeGrantDocId?(signingKey: string): Promise<string | null>;
1633
2571
  /**
1634
2572
  * Check if a user has been revoked.
1635
2573
  *
@@ -1638,34 +2576,50 @@ export interface MindooTenantDirectory {
1638
2576
  */
1639
2577
  isUserRevoked(username: string): Promise<boolean>;
1640
2578
  /**
1641
- * Requests that a document's change history be purged from all client stores.
1642
- * Creates a purge request record in the directory that clients will process when they
1643
- * sync directory changes. Clients receiving this directory update will purge all
1644
- * changes for the specified document from their local stores.
2579
+ * Admin-sign and write a document-history purge request to the directory from
2580
+ * a request (built in-dialog or decoded from an `mdb://doc-history-purge/...`
2581
+ * URI). Stored at the fixed id `acl_dochistorypurge_<requestId>` (one doc per
2582
+ * request; append-only audit record). The doc shell is `$publicinfos`-readable
2583
+ * so the sync server can read the cleartext `dbId` + `docIds` routing fields
2584
+ * and execute the purge; only `reason` is encrypted with the tenant default
2585
+ * key. Clients (and the server) process the request after a directory sync and
2586
+ * purge the requested documents from their stores (docs/accesscontrol.md §13).
1645
2587
  *
1646
- * This is useful for GDPR compliance (right to be forgotten) and other scenarios
1647
- * where document data must be removed from all systems.
2588
+ * This is useful for GDPR compliance (right to be forgotten) and other
2589
+ * scenarios where document data must be removed from all systems.
1648
2590
  *
1649
- * @param dbId The database ID containing the document
1650
- * @param docId The document ID whose change history should be purged
1651
- * @param reason Optional reason for the purge request (e.g., "GDPR right to be forgotten")
1652
- * @param administrationPrivateKey The administration private key to sign the request
1653
- * @param administrationPrivateKeyPassword The password to decrypt the administration private key
1654
- * @return A promise that resolves when the purge request record is created
2591
+ * @param request The full unsigned purge request (db + doc ids + optional reason).
2592
+ * @param administrationPrivateKey The administration private key to sign the request.
2593
+ * @param administrationPrivateKeyPassword The password to decrypt the administration private key.
2594
+ * @return A promise that resolves when the purge request record is created.
2595
+ */
2596
+ publishDocHistoryPurge?(request: DocHistoryPurgeRequest, administrationPrivateKey: EncryptedPrivateKey, administrationPrivateKeyPassword: string): Promise<void>;
2597
+ /**
2598
+ * List all purge-request documents at the directory head, decrypting `reason`
2599
+ * when the tenant default key is held.
2600
+ *
2601
+ * @returns The purge-request views.
1655
2602
  */
1656
- requestDocHistoryPurge(dbId: string, docId: string, reason: string | undefined, administrationPrivateKey: EncryptedPrivateKey, administrationPrivateKeyPassword: string): Promise<void>;
2603
+ listDocHistoryPurges?(): Promise<DocHistoryPurgeView[]>;
1657
2604
  /**
1658
- * Get all pending document history purge requests that clients should process.
1659
- * Returns purge requests with verified admin signatures that clients have not yet processed.
2605
+ * Delete a still-pending purge request document (admin-signed).
1660
2606
  *
1661
- * Clients should call this method periodically (e.g., after directory sync) and
1662
- * purge the requested documents from their local stores.
2607
+ * @param requestId The purge request id.
2608
+ * @param administrationPrivateKey The administration private key to sign the change.
2609
+ * @param administrationPrivateKeyPassword The password to decrypt the administration private key.
2610
+ */
2611
+ deleteDocHistoryPurge?(requestId: string, administrationPrivateKey: EncryptedPrivateKey, administrationPrivateKeyPassword: string): Promise<void>;
2612
+ /**
2613
+ * Get all document history purge requests that clients (and the server) should
2614
+ * process. Returns the requests' routing info; clients/servers purge the
2615
+ * requested documents from their stores after a directory sync.
1663
2616
  *
1664
- * @return Array of purge request records with verified admin signatures
2617
+ * @return Array of purge request records.
1665
2618
  */
1666
2619
  getRequestedDocHistoryPurges(): Promise<Array<{
2620
+ requestId: string;
1667
2621
  dbId: string;
1668
- docId: string;
2622
+ docIds: string[];
1669
2623
  reason?: string;
1670
2624
  requestedAt: number;
1671
2625
  purgeRequestDocId: string;
@@ -1706,8 +2660,60 @@ export interface MindooTenantDirectory {
1706
2660
  * This is intended for admin tooling and overview UIs. The result always includes
1707
2661
  * `"directory"` and will also include `"main"` as the conventional default app DB.
1708
2662
  * Additional DBs are discovered from `dbsettings` documents stored in the directory.
2663
+ *
2664
+ * @returns The database ids known to the directory (always including `"directory"` and `"main"`).
1709
2665
  */
1710
2666
  listKnownDBIds(): Promise<string[]>;
2667
+ /**
2668
+ * Returns the tenant-wide database-open policy from the access-control default
2669
+ * policy document.
2670
+ *
2671
+ * In `"open"` mode (the default, and whenever access control is off) any valid
2672
+ * database id may be opened/synced. In `"directory-restricted"` mode only
2673
+ * `"directory"` (always implicitly allowed) and the returned `allowedDbIds`
2674
+ * may be opened/synced; the tenant admin is exempt.
2675
+ *
2676
+ * Optional capability: implementations that predate this policy may omit it.
2677
+ *
2678
+ * @returns The current database-open policy mode and the allowlist.
2679
+ */
2680
+ getDatabaseCreationPolicy?(): Promise<{
2681
+ mode: "open" | "directory-restricted";
2682
+ allowedDbIds: string[];
2683
+ }>;
2684
+ /**
2685
+ * The tenant-wide storage-format floor: the trusted-time cutoff (ms since
2686
+ * epoch) at/after which a store entry MUST carry the v2 metadata-binding
2687
+ * author signature, or `undefined` when no floor is configured. Read from the
2688
+ * access-control default policy (`requireMetadataSignatureSince`).
2689
+ *
2690
+ * Optional capability: implementations that predate this policy may omit it.
2691
+ */
2692
+ getRequireMetadataSignatureSince?(): Promise<number | undefined>;
2693
+ /**
2694
+ * Whether the given database id may be opened/synced under the current
2695
+ * database-open policy. Always true for `"directory"` and in `"open"` mode.
2696
+ *
2697
+ * Optional capability: implementations that predate this policy may omit it.
2698
+ *
2699
+ * @param dbId The database id to check.
2700
+ * @returns True when the database id may be opened/synced.
2701
+ */
2702
+ isDatabaseAllowed?(dbId: string): Promise<boolean>;
2703
+ /**
2704
+ * Whether the current user may open and sync `dbId` under the database read
2705
+ * gate (`doc_read`, §6.6). Evaluates the read policy for the current user
2706
+ * against the directory head. Always true for `"directory"` and for the
2707
+ * tenant admin. Independent of {@link isDatabaseAllowed} (the database-id
2708
+ * allowlist) — callers that gate opening enforce both.
2709
+ *
2710
+ * Optional capability: implementations that predate read access control may
2711
+ * omit it.
2712
+ *
2713
+ * @param dbId The database id to check read access for.
2714
+ * @returns True when the current user may open/sync the database.
2715
+ */
2716
+ canReadDatabase?(dbId: string): Promise<boolean>;
1711
2717
  /**
1712
2718
  * Create or update database-specific settings.
1713
2719
  * Automatically uses the cached settings document for the given dbId if it exists, or creates a new one.
@@ -1728,16 +2734,13 @@ export interface MindooTenantDirectory {
1728
2734
  * @return names
1729
2735
  */
1730
2736
  getGroups(): Promise<string[]>;
1731
- /**
1732
- * Looks up the members of a group by name.
1733
- *
1734
- * @param groupName The name of the group to look up (case-insensitive, converted to lowercase)
1735
- * @return The members of the group
1736
- */
1737
2737
  /**
1738
2738
  * Get the decrypted member names for a group.
1739
2739
  * Entries that cannot be decrypted are skipped so callers can still work with
1740
2740
  * the readable subset of the group.
2741
+ *
2742
+ * @param groupName The name of the group to look up (case-insensitive, converted to lowercase).
2743
+ * @returns The decrypted member names (the readable subset; undecryptable entries are skipped).
1741
2744
  */
1742
2745
  getGroupMembers(groupName: string): Promise<string[]>;
1743
2746
  /**
@@ -1864,6 +2867,80 @@ export interface DocumentHistoryResult {
1864
2867
  */
1865
2868
  changeCreatedByPublicKey: string;
1866
2869
  }
2870
+ /**
2871
+ * Resumable position in a revision-grain changefeed
2872
+ * ({@link MindooDB.iterateChangeRevisionsSince}).
2873
+ *
2874
+ * The feed discovers entries in the store's local `(receiptOrder, id)` order
2875
+ * (the gap-free, append-stable order of {@link ContentAddressedStore.scanEntriesSince}),
2876
+ * so the cursor is a store scan position. It points at the witnessed stable
2877
+ * prefix: it does not advance past the earliest un-witnessed entry, so
2878
+ * un-witnessed entries (whose trusted time is provisional) are re-evaluated as a
2879
+ * head overlay on every resume. Passing the cursor back resumes discovery
2880
+ * strictly after that position.
2881
+ *
2882
+ * Note: revisions are *materialized and projected* in trusted-time order
2883
+ * (`receivedAt` for witnessed entries, the current wall clock for un-witnessed
2884
+ * local entries), which is distinct from the receiptOrder discovery order; see
2885
+ * {@link ChangeRevisionResult.trustedTime}.
2886
+ */
2887
+ export interface RevisionCursor {
2888
+ /** Store receipt-order watermark of the witnessed stable prefix. */
2889
+ receiptOrder: number;
2890
+ /** Store entry id at the watermark (tie-breaker within a receiptOrder). */
2891
+ id: string;
2892
+ }
2893
+ /**
2894
+ * Result yielded by the revision-grain changefeed generators
2895
+ * ({@link MindooDB.iterateChangeRevisionsSince} /
2896
+ * {@link MindooDB.iterateDocRevisionsSince}).
2897
+ *
2898
+ * Unlike {@link ProcessChangesResult} (one merged head per document), this is
2899
+ * emitted once per persisted change entry: it carries the document's merged
2900
+ * state as of that revision's trusted-time frontier, so consumers can rebuild a
2901
+ * true per-revision history (e.g. the access-control time-travel chain, §8).
2902
+ */
2903
+ export interface ChangeRevisionResult {
2904
+ /** Document this revision belongs to. */
2905
+ docId: string;
2906
+ /**
2907
+ * Store entry id of the change this revision corresponds to. Stable across
2908
+ * re-emissions, so consumers key revisions by it (replacing a prior emission
2909
+ * when a concurrent sibling arrives or the entry is later witnessed).
2910
+ */
2911
+ entryId: string;
2912
+ /**
2913
+ * The document's merged state including every change to `docId` whose trusted
2914
+ * time is `<= trustedTime`. An independent clone, safe to retain.
2915
+ */
2916
+ doc: MindooDoc;
2917
+ /** The store entry type of this revision (`doc_create`/`doc_change`/...). */
2918
+ entryType: StoreEntryType;
2919
+ /**
2920
+ * Trusted time of this revision: the witness `receivedAt` for witnessed
2921
+ * entries, or the current wall clock for un-witnessed local entries (which
2922
+ * therefore always sit at the provisional head of the timeline). The
2923
+ * document's merged state is bounded by this time.
2924
+ */
2925
+ trustedTime: number;
2926
+ /**
2927
+ * True when `trustedTime` came from a witness `receivedAt`; false for an
2928
+ * un-witnessed local entry whose trusted time is the (provisional) current
2929
+ * wall clock. Consumers treat un-witnessed revisions as a recomputed head
2930
+ * overlay until the entry is witnessed.
2931
+ */
2932
+ witnessed: boolean;
2933
+ /** Ed25519 public key (PEM) of the change author. */
2934
+ createdByPublicKey: string;
2935
+ /**
2936
+ * Resumable discovery cursor (the witnessed stable-prefix watermark). The same
2937
+ * watermark is stamped on every revision in a batch; consumers persist it to
2938
+ * resume the next scan. `null` when there is no witnessed stable prefix yet
2939
+ * (e.g. the only entries so far are un-witnessed local ones), meaning the next
2940
+ * resume re-scans from the beginning.
2941
+ */
2942
+ cursor: RevisionCursor | null;
2943
+ }
1867
2944
  /**
1868
2945
  * Options for opening a database
1869
2946
  */
@@ -2325,6 +3402,25 @@ export interface SyncResult {
2325
3402
  scannedEntries: number;
2326
3403
  cancelled: boolean;
2327
3404
  }
3405
+ /** One changed document in a {@link DbChangeEvent} (lightweight metadata only). */
3406
+ export interface DbChange {
3407
+ docId: string;
3408
+ isDeleted: boolean;
3409
+ lastModified: number;
3410
+ }
3411
+ /**
3412
+ * Coalesced change notification emitted to {@link DbChangeListener}s.
3413
+ *
3414
+ * The event is a "there is news up to `cursor`" signal, not a replay
3415
+ * mechanism: listeners registered late simply miss earlier events, and
3416
+ * consumers that need completeness read `iterateChangesSince` from their
3417
+ * own persisted cursor (which stays correct regardless of missed events).
3418
+ */
3419
+ export interface DbChangeEvent {
3420
+ changes: DbChange[];
3421
+ cursor: ProcessChangesCursor | null;
3422
+ }
3423
+ export type DbChangeListener = (event: DbChangeEvent) => void;
2328
3424
  export interface MindooDB {
2329
3425
  /**
2330
3426
  * Get the tenant that this database belongs to
@@ -2387,6 +3483,30 @@ export interface MindooDB {
2387
3483
  * @return The new (or, if `options.id` already exists locally, existing) document.
2388
3484
  */
2389
3485
  createDocument(options?: CreateOptions): Promise<MindooDoc>;
3486
+ /**
3487
+ * Bulk-create documents in a single append-only store write.
3488
+ *
3489
+ * Semantically equivalent to calling `createDocument()` once per input, but
3490
+ * all produced store entries are persisted through one `putEntries()` batch
3491
+ * (a single readwrite transaction on IndexedDB-backed stores), which is
3492
+ * dramatically faster for large imports.
3493
+ *
3494
+ * Unlike the single-create path, a custom `id` MAY be combined with
3495
+ * `initialValues`: the values are applied as a follow-up `doc_change` entry
3496
+ * on top of the deterministic seed change, and both entries land in the same
3497
+ * batch. Existing custom-id documents keep the idempotent create semantics
3498
+ * (the existing document is returned and `initialValues` are applied as a
3499
+ * regular change).
3500
+ *
3501
+ * Fail-fast: invalid inputs are rejected up front, and a denied
3502
+ * access-control precheck rejects the whole call before any fresh document
3503
+ * is written.
3504
+ *
3505
+ * @param inputs One `CreateOptions` per document to create.
3506
+ * @return The created (or, for existing custom ids, existing) documents in
3507
+ * input order.
3508
+ */
3509
+ createDocuments(inputs: CreateOptions[]): Promise<MindooDoc[]>;
2390
3510
  /**
2391
3511
  * Create a new document with optional encryption using a named symmetric key.
2392
3512
  *
@@ -2450,6 +3570,33 @@ export interface MindooDB {
2450
3570
  * @return An async generator that yields DocumentHistoryResult objects containing the document state and change metadata, in chronological order from oldest to newest
2451
3571
  */
2452
3572
  iterateDocumentHistory(docId: string): AsyncGenerator<DocumentHistoryResult, void, unknown>;
3573
+ /**
3574
+ * Iterate the database's changes at **revision grain** in trusted-time order.
3575
+ *
3576
+ * Unlike {@link iterateChangesSince} (which yields one merged head per
3577
+ * document), this yields once per persisted change entry across all
3578
+ * documents, ordered by `(trustedTime, id)` where `trustedTime` is the
3579
+ * access-control trusted time (`receivedAt ?? createdAt`). Each result carries
3580
+ * the document's merged state as of that revision's trusted-time frontier, so
3581
+ * intermediate states of in-place-edited documents are preserved.
3582
+ *
3583
+ * This powers the access-control time-travel directory-state chain
3584
+ * (docs/accesscontrol.md §8), which must observe every policy/grant revision
3585
+ * — not just the final merged document.
3586
+ *
3587
+ * @param cursor Resume position; `null` to start from the beginning.
3588
+ */
3589
+ iterateChangeRevisionsSince(cursor: RevisionCursor | null): AsyncGenerator<ChangeRevisionResult, void, unknown>;
3590
+ /**
3591
+ * Like {@link iterateChangeRevisionsSince} but restricted to a single
3592
+ * document, with the `docId` filter pushed down to the store scan so
3593
+ * unrelated entries are never loaded or decrypted. Useful for a
3594
+ * trusted-time-ordered per-document history view.
3595
+ *
3596
+ * @param docId The document whose revisions to iterate.
3597
+ * @param cursor Resume position; `null` to start from the beginning.
3598
+ */
3599
+ iterateDocRevisionsSince(docId: string, cursor: RevisionCursor | null): AsyncGenerator<ChangeRevisionResult, void, unknown>;
2453
3600
  /**
2454
3601
  * Return bounded history metadata for a document without materializing every
2455
3602
  * historical document state.
@@ -2551,6 +3698,21 @@ export interface MindooDB {
2551
3698
  * @return A promise that resolves when the document is deleted
2552
3699
  */
2553
3700
  deleteDocument(docId: string, options?: DeleteOptions): Promise<void>;
3701
+ /**
3702
+ * Bulk-delete documents in a single append-only store write.
3703
+ *
3704
+ * Semantically equivalent to calling `deleteDocument()` once per id, but all
3705
+ * `doc_delete` lifecycle entries are persisted through one `putEntries()`
3706
+ * batch (a single readwrite transaction on IndexedDB-backed stores).
3707
+ *
3708
+ * Documents that are missing or already deleted are skipped (idempotent bulk
3709
+ * semantics). Any other failure, including a denied access-control precheck,
3710
+ * rejects the whole call before anything is written.
3711
+ *
3712
+ * @param docIds IDs of the documents to delete.
3713
+ * @param options Optional signing options applied to every delete entry.
3714
+ */
3715
+ deleteDocuments(docIds: string[], options?: DeleteOptions): Promise<void>;
2554
3716
  /**
2555
3717
  * Delete a document using a specific signing key.
2556
3718
  * This is like deleteDocument but allows signing with a different key than the current user's.
@@ -2596,6 +3758,43 @@ export interface MindooDB {
2596
3758
  * @return A promise that resolves when the document is changed
2597
3759
  */
2598
3760
  changeDoc(doc: MindooDoc, changeFunc: (doc: MindooDoc) => void | Promise<void>, options?: ChangeOptions): Promise<void>;
3761
+ /**
3762
+ * Predict whether a `createDocument` with these options would be allowed by
3763
+ * the active access control write policy, without writing anything
3764
+ * (docs/accesscontrol.md §9). Lets a UI disable a Save action and surface the
3765
+ * reason up front. When access control is not enforced, returns an
3766
+ * `allowed: true` decision. The actual `createDocument` throws
3767
+ * {@link AccessDeniedError} for the same denial.
3768
+ *
3769
+ * @param options The same options that would be passed to `createDocument`.
3770
+ * Only `initialValues`, `decryptionKeyId`, and the signing key are used.
3771
+ */
3772
+ canCreate(options?: CreateOptions): Promise<AccessDecision>;
3773
+ /**
3774
+ * Predict whether applying `candidateAfter` as `doc`'s next state via
3775
+ * `changeDoc` would be allowed by the active write policy, without writing.
3776
+ *
3777
+ * @param doc The document that would be changed.
3778
+ * @param candidateAfter The intended full "after" document state.
3779
+ * @param signingKeyPair Optional custom signing key (matches `changeDoc`).
3780
+ */
3781
+ canChange(doc: MindooDoc, candidateAfter: Record<string, unknown>, signingKeyPair?: SigningKeyPair): Promise<AccessDecision>;
3782
+ /**
3783
+ * Predict whether deleting `doc` via `deleteDocument` would be allowed by the
3784
+ * active write policy, without writing.
3785
+ *
3786
+ * @param doc The document that would be deleted.
3787
+ * @param signingKeyPair Optional custom signing key (matches `deleteDocument`).
3788
+ */
3789
+ canDelete(doc: MindooDoc, signingKeyPair?: SigningKeyPair): Promise<AccessDecision>;
3790
+ /**
3791
+ * Predict whether undeleting `doc` via `undeleteDocument` would be allowed by
3792
+ * the active write policy, without writing.
3793
+ *
3794
+ * @param doc The document that would be undeleted.
3795
+ * @param signingKeyPair Optional custom signing key (matches `undeleteDocument`).
3796
+ */
3797
+ canUndelete(doc: MindooDoc, signingKeyPair?: SigningKeyPair): Promise<AccessDecision>;
2599
3798
  /**
2600
3799
  * Apply granular text edits at a document path.
2601
3800
  *
@@ -2722,6 +3921,144 @@ export interface MindooDB {
2722
3921
  * change index. Returns `null` when the database has no indexed changes yet.
2723
3922
  */
2724
3923
  getLatestChangeCursor?(): ProcessChangesCursor | null;
3924
+ /**
3925
+ * Count the number of changefeed entries after the given cursor without
3926
+ * iterating them (O(log n) binary search on the internal change index).
3927
+ *
3928
+ * Useful for progress reporting before/while consuming
3929
+ * {@link iterateChangesSince} — e.g. "processed X of Y documents".
3930
+ *
3931
+ * @param cursor The cursor to count from. Use `null` to count all entries.
3932
+ */
3933
+ countChangesSince?(cursor: ProcessChangesCursor | null): number;
3934
+ /**
3935
+ * Get (lazily creating) the document summary buffer for this database —
3936
+ * the changefeed-maintained field-value index backing ad-hoc queries and
3937
+ * summary-based views (see docs/adhoc-queries.md).
3938
+ *
3939
+ * @param config Optional summary configuration. On a later call with a
3940
+ * different configuration, a resumable backfill re-extracts all
3941
+ * documents (documents themselves are never rewritten).
3942
+ */
3943
+ getSummaryStore?(config?: SummaryConfig): DocumentSummaryStore;
3944
+ /**
3945
+ * Read the summary configuration from the synced setup document
3946
+ * (`dbsetup`, field `summarySetup`). Returns `null` when no setup
3947
+ * document or no configuration exists. See docs/adhoc-queries.md.
3948
+ */
3949
+ getSummarySetup?(): Promise<SummaryConfig | null>;
3950
+ /**
3951
+ * Write the summary configuration into the synced setup document
3952
+ * (created idempotently when missing). `null` removes the configuration
3953
+ * (fallback to the default auto-include config). Summary stores without
3954
+ * an explicit code-provided configuration follow this document via the
3955
+ * changefeed and re-extract through a resumable backfill.
3956
+ */
3957
+ setSummarySetup?(config: SummaryConfig | null): Promise<void>;
3958
+ /**
3959
+ * Enable/disable summary auto-follow (default: enabled). When enabled,
3960
+ * the summary buffer catches up in the background after every coalesced
3961
+ * change event (one run per sync batch / event-loop turn), so queries
3962
+ * don't stall after receiving many documents.
3963
+ */
3964
+ setSummaryAutoUpdateEnabled?(enabled: boolean): void;
3965
+ /**
3966
+ * Get (lazily creating) the full-text index for this database — a
3967
+ * changefeed-maintained, encrypted-at-rest search index over extracted
3968
+ * document text (see docs/fulltext-search.md). Indexing is OPT-IN:
3969
+ * without `enabled: true` (setup document or explicit `config`) the
3970
+ * index stays empty.
3971
+ *
3972
+ * @param config Optional full-text configuration. On a later call with
3973
+ * a different configuration, the engine is recreated and a resumable
3974
+ * backfill re-indexes all documents.
3975
+ */
3976
+ getFullTextIndex?(config?: FulltextConfig): DocumentFullTextIndex;
3977
+ /**
3978
+ * Read the full-text configuration from the synced setup document
3979
+ * (`dbsetup`, field `fulltextSetup`). Returns `null` when no setup
3980
+ * document or no configuration exists. See docs/fulltext-search.md.
3981
+ */
3982
+ getFulltextSetup?(): Promise<FulltextConfig | null>;
3983
+ /**
3984
+ * Write the full-text configuration into the synced setup document
3985
+ * (created idempotently when missing). `null` removes the configuration
3986
+ * (indexing falls back to disabled). Indexes without an explicit
3987
+ * code-provided configuration follow this document via the changefeed
3988
+ * and re-index through a resumable backfill.
3989
+ */
3990
+ setFulltextSetup?(config: FulltextConfig | null): Promise<void>;
3991
+ /**
3992
+ * Register an attachment text extractor for full-text indexing.
3993
+ * Host environments call this when opening the database; extraction
3994
+ * only happens for databases whose `fulltextSetup` has
3995
+ * `attachments: true`.
3996
+ *
3997
+ * @returns An unregister function.
3998
+ */
3999
+ registerAttachmentTextExtractor?(extractor: AttachmentTextExtractor): () => void;
4000
+ /**
4001
+ * Read the attachment extraction configuration from the synced setup
4002
+ * document (`dbsetup`, field `extractionSetup`). Configures host-side
4003
+ * extraction services (e.g. OCR) that persist results at the attachment
4004
+ * entry via {@link MindooDoc.setAttachmentExtractedText}. Returns `null`
4005
+ * when no setup document or no configuration exists.
4006
+ */
4007
+ getExtractionSetup?(): Promise<ExtractionConfig | null>;
4008
+ /**
4009
+ * Write the attachment extraction configuration into the synced setup
4010
+ * document (created idempotently when missing). `null` removes the
4011
+ * configuration (extraction services stay idle). Idempotent: writing an
4012
+ * unchanged configuration produces no new document revision.
4013
+ */
4014
+ setExtractionSetup?(config: ExtractionConfig | null): Promise<void>;
4015
+ /**
4016
+ * Full-text search over the document full-text index (see
4017
+ * docs/fulltext-search.md). Brings the index up to date first, then
4018
+ * returns matching documents best-score-first. Results are
4019
+ * device-specific under E2EE: documents whose decryption keys are
4020
+ * missing locally are not indexed and cannot match.
4021
+ *
4022
+ * @throws Error when full-text indexing is not enabled for this database.
4023
+ */
4024
+ searchText?(query: string, options?: FulltextSearchOptions): Promise<FulltextSearchResult>;
4025
+ /**
4026
+ * Enable/disable full-text auto-follow (default: enabled). Mirrors
4027
+ * {@link setSummaryAutoUpdateEnabled} for the full-text index; only
4028
+ * databases with an ACTIVE full-text index pay any cost.
4029
+ */
4030
+ setFulltextAutoUpdateEnabled?(enabled: boolean): void;
4031
+ /**
4032
+ * Run an ad-hoc query against the document summary buffer (see
4033
+ * docs/adhoc-queries.md). The filter is a MindooDB expression-language
4034
+ * expression; documents are never materialized unless
4035
+ * `options.allowFullScan` is set.
4036
+ */
4037
+ query?(query: MindooQuery, options?: MindooQueryOptions): Promise<MindooQueryResult>;
4038
+ /**
4039
+ * Build an ephemeral, summary-backed VirtualView (categories, sorting,
4040
+ * totals as usual — fed from the summary buffer, no document
4041
+ * materialization). Not cached; call `dispose()` when done.
4042
+ */
4043
+ queryView?(definition: MindooQueryViewDefinition, options?: VirtualViewUpdateOptions): Promise<EphemeralSummaryView>;
4044
+ /**
4045
+ * Register a listener notified after documents change (local writes,
4046
+ * sync ingest, access flips, witness updates). Events are coalesced —
4047
+ * one event per sync batch / local commit — and carry only lightweight
4048
+ * metadata; consumers needing full replay semantics should read
4049
+ * {@link iterateChangesSince} from their own cursor instead.
4050
+ *
4051
+ * @returns An unsubscribe function.
4052
+ */
4053
+ addChangeListener?(listener: DbChangeListener): () => void;
4054
+ /**
4055
+ * Live query: delivers the initial result asynchronously, re-evaluates
4056
+ * after coalesced change events, and calls `onResult` only when the
4057
+ * result actually changed.
4058
+ */
4059
+ queryLive?(query: MindooQuery, onResult: (result: MindooQueryResult) => void, options?: MindooQueryOptions & {
4060
+ onError?: (error: unknown) => void;
4061
+ }): MindooQuerySubscription;
2725
4062
  /**
2726
4063
  * Sync changes from the append-only store by finding new changes and processing them.
2727
4064
  * This method can be called multiple times to incrementally sync new changes.