@noy-db/hub 0.4.0-pre.1 → 0.4.0-pre.11

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 (605) hide show
  1. package/README.md +3 -4
  2. package/dist/api-ZDKTWNBB.js +20 -0
  3. package/dist/attestation/index.js +18 -18
  4. package/dist/{backup-LU2DTZTI.js → backup-2UX7PRM5.js} +13 -13
  5. package/dist/blobs/index.js +30 -15
  6. package/dist/blobs/index.js.map +1 -1
  7. package/dist/broker/index.js +12 -12
  8. package/dist/broker/index.js.map +1 -1
  9. package/dist/cargo/index.js +53 -43
  10. package/dist/{chunk-YTGDPCPW.js → chunk-2J6UEN2V.js} +42 -18
  11. package/dist/chunk-2J6UEN2V.js.map +1 -0
  12. package/dist/{chunk-IY23KFNZ.js → chunk-35NMVJ7I.js} +3 -3
  13. package/dist/{chunk-S3BFKGET.js → chunk-3HUYRN24.js} +4 -4
  14. package/dist/chunk-3HUYRN24.js.map +1 -0
  15. package/dist/{walk-XS3PKM6I.js → chunk-3V3XR4S4.js} +4 -13
  16. package/dist/{walk-XS3PKM6I.js.map → chunk-3V3XR4S4.js.map} +1 -1
  17. package/dist/{chunk-RTEK4C4I.js → chunk-4JQK3L4V.js} +2 -2
  18. package/dist/{chunk-3ELCWU56.js → chunk-4ZKNC6A6.js} +2 -2
  19. package/dist/{chunk-VQNJ7UZL.js → chunk-55LKVALY.js} +106 -10
  20. package/dist/chunk-55LKVALY.js.map +1 -0
  21. package/dist/{chunk-VAIS3SOM.js → chunk-55LX6FSX.js} +2 -2
  22. package/dist/chunk-5D2ALSM5.js +19 -0
  23. package/dist/chunk-5D2ALSM5.js.map +1 -0
  24. package/dist/{chunk-6HPG2YNX.js → chunk-5DRROK5W.js} +2 -2
  25. package/dist/{chunk-S6Q37VGE.js → chunk-5GQEU4DN.js} +2 -2
  26. package/dist/chunk-5JOFWL4G.js +25 -0
  27. package/dist/chunk-5JOFWL4G.js.map +1 -0
  28. package/dist/{chunk-TOPYT5U5.js → chunk-63FE525P.js} +6 -6
  29. package/dist/chunk-6LJY7X5A.js +18 -0
  30. package/dist/chunk-6LJY7X5A.js.map +1 -0
  31. package/dist/{chunk-JVBO4SZL.js → chunk-6UBZ6I5Z.js} +2 -2
  32. package/dist/{chunk-BOKIKJJB.js → chunk-6ZNSB3H6.js} +5 -17
  33. package/dist/chunk-6ZNSB3H6.js.map +1 -0
  34. package/dist/{chunk-BMQWTQZ4.js → chunk-7YVBQJ7K.js} +13 -355
  35. package/dist/chunk-7YVBQJ7K.js.map +1 -0
  36. package/dist/{chunk-UFEVO57O.js → chunk-ABS7FMMD.js} +6 -6
  37. package/dist/chunk-AFHQATY4.js +47 -0
  38. package/dist/chunk-AFHQATY4.js.map +1 -0
  39. package/dist/{chunk-HOONYZY2.js → chunk-AKKRXT23.js} +7 -7
  40. package/dist/chunk-AKKRXT23.js.map +1 -0
  41. package/dist/{chunk-DDHM2TLX.js → chunk-AT2JJEKJ.js} +4 -4
  42. package/dist/chunk-AT2JJEKJ.js.map +1 -0
  43. package/dist/{chunk-M75ZZHSR.js → chunk-BLBAQRBM.js} +2 -2
  44. package/dist/{chunk-3SV2EPMN.js → chunk-BLCWSJLN.js} +88 -81
  45. package/dist/chunk-BLCWSJLN.js.map +1 -0
  46. package/dist/chunk-CADUYBQD.js +151 -0
  47. package/dist/chunk-CADUYBQD.js.map +1 -0
  48. package/dist/{chunk-G6EQYAL6.js → chunk-CI32CAFS.js} +5 -5
  49. package/dist/{chunk-FH52K7EG.js → chunk-CUZLNGD5.js} +2 -6
  50. package/dist/{chunk-FH52K7EG.js.map → chunk-CUZLNGD5.js.map} +1 -1
  51. package/dist/{chunk-2P7EGNKF.js → chunk-CXQW2NWO.js} +145 -3
  52. package/dist/chunk-CXQW2NWO.js.map +1 -0
  53. package/dist/{chunk-6B4DYGWO.js → chunk-DABACXEF.js} +3 -3
  54. package/dist/{chunk-F6T6L2UK.js → chunk-DMH3VZU5.js} +4 -4
  55. package/dist/chunk-DSDXAKIP.js +50 -0
  56. package/dist/chunk-DSDXAKIP.js.map +1 -0
  57. package/dist/{chunk-MQ6WOPSY.js → chunk-DZ2JXHWK.js} +5 -5
  58. package/dist/chunk-DZFQVICS.js +23 -0
  59. package/dist/chunk-DZFQVICS.js.map +1 -0
  60. package/dist/chunk-E23UGFVC.js +63 -0
  61. package/dist/chunk-E23UGFVC.js.map +1 -0
  62. package/dist/{chunk-UBNCR3YK.js → chunk-EE7UHLKH.js} +4 -4
  63. package/dist/chunk-EIPVYUEP.js +654 -0
  64. package/dist/chunk-EIPVYUEP.js.map +1 -0
  65. package/dist/{chunk-EGCRBCNA.js → chunk-EKRSCRNM.js} +3 -3
  66. package/dist/{chunk-YMUGBZN2.js → chunk-FQ5CHJR7.js} +1 -1
  67. package/dist/chunk-FQ5CHJR7.js.map +1 -0
  68. package/dist/{chunk-LB6OH6K2.js → chunk-FQZ6XTQ7.js} +17 -20
  69. package/dist/chunk-FQZ6XTQ7.js.map +1 -0
  70. package/dist/{chunk-IRQY7IR5.js → chunk-FRMPM7WG.js} +4 -4
  71. package/dist/{chunk-DVUZMT2W.js → chunk-G2JUIDFA.js} +9 -9
  72. package/dist/{chunk-DVUZMT2W.js.map → chunk-G2JUIDFA.js.map} +1 -1
  73. package/dist/{chunk-RND5ZPNP.js → chunk-G6WWZNJP.js} +13 -13
  74. package/dist/chunk-G6WWZNJP.js.map +1 -0
  75. package/dist/chunk-GJW4HX2O.js +1 -0
  76. package/dist/{chunk-T6GU5PPZ.js → chunk-GU3IP74F.js} +6 -6
  77. package/dist/{chunk-5OI6BR4H.js → chunk-GWWOGNBK.js} +308 -18
  78. package/dist/chunk-GWWOGNBK.js.map +1 -0
  79. package/dist/{chunk-UNCOC7QH.js → chunk-H2GPHUZD.js} +12 -13
  80. package/dist/chunk-H2GPHUZD.js.map +1 -0
  81. package/dist/{chunk-7CI6CP7Z.js → chunk-HMU5P6RL.js} +5 -5
  82. package/dist/chunk-HMU5P6RL.js.map +1 -0
  83. package/dist/{chunk-YJV2UZ7H.js → chunk-I5GEJX3R.js} +5 -5
  84. package/dist/chunk-I5GEJX3R.js.map +1 -0
  85. package/dist/{chunk-GWKAVKHI.js → chunk-IG6KUWBX.js} +2 -2
  86. package/dist/chunk-IG6KUWBX.js.map +1 -0
  87. package/dist/{chunk-MTQPRQHB.js → chunk-IPUG56GJ.js} +15 -5
  88. package/dist/{chunk-MTQPRQHB.js.map → chunk-IPUG56GJ.js.map} +1 -1
  89. package/dist/{chunk-SMIRGMS7.js → chunk-IXNCZTWA.js} +2 -2
  90. package/dist/{chunk-RM2XV574.js → chunk-IXTSNGYY.js} +3 -3
  91. package/dist/{chunk-KUPKLSX5.js → chunk-IYZISPGD.js} +7 -5
  92. package/dist/chunk-IYZISPGD.js.map +1 -0
  93. package/dist/{chunk-SMGEYW6G.js → chunk-JDOMW53O.js} +26 -16
  94. package/dist/chunk-JDOMW53O.js.map +1 -0
  95. package/dist/{chunk-PK6QCH2C.js → chunk-JJZGIE4U.js} +6 -5
  96. package/dist/{chunk-DRWBEDYO.js → chunk-JYJFGD2H.js} +2 -2
  97. package/dist/{chunk-TAGR72IR.js → chunk-KRCBZYTZ.js} +26 -177
  98. package/dist/chunk-KRCBZYTZ.js.map +1 -0
  99. package/dist/{chunk-HPUWOVR7.js → chunk-L2DGWBCT.js} +14 -14
  100. package/dist/chunk-L2DGWBCT.js.map +1 -0
  101. package/dist/{chunk-VEALDPHW.js → chunk-L3YYLT4E.js} +15 -2
  102. package/dist/chunk-L3YYLT4E.js.map +1 -0
  103. package/dist/{chunk-A7JJLVGH.js → chunk-LNPUSMZL.js} +29 -31
  104. package/dist/chunk-LNPUSMZL.js.map +1 -0
  105. package/dist/{chunk-KUIB4B5Q.js → chunk-LNZKOUJR.js} +2 -2
  106. package/dist/{chunk-IM3QVF53.js → chunk-MBKVNOJS.js} +6 -6
  107. package/dist/chunk-MCHBCNCE.js +367 -0
  108. package/dist/chunk-MCHBCNCE.js.map +1 -0
  109. package/dist/{chunk-VCBHAE4R.js → chunk-MHMLXJ3I.js} +2 -2
  110. package/dist/chunk-MHMLXJ3I.js.map +1 -0
  111. package/dist/{chunk-WNGGJWF7.js → chunk-MSMJJB4J.js} +2 -2
  112. package/dist/chunk-MSMJJB4J.js.map +1 -0
  113. package/dist/{chunk-T36RFODW.js → chunk-MXUT7FTE.js} +2 -2
  114. package/dist/chunk-MXUT7FTE.js.map +1 -0
  115. package/dist/{chunk-BGK233EA.js → chunk-N4BBNYIB.js} +11 -9
  116. package/dist/chunk-N4BBNYIB.js.map +1 -0
  117. package/dist/{chunk-3PF6CRDT.js → chunk-NFIBXF4V.js} +1082 -1583
  118. package/dist/chunk-NFIBXF4V.js.map +1 -0
  119. package/dist/{chunk-LOF2W3JU.js → chunk-NFNJLRY7.js} +368 -52
  120. package/dist/chunk-NFNJLRY7.js.map +1 -0
  121. package/dist/{chunk-N6WF5PKC.js → chunk-NFZGZ4AK.js} +2 -2
  122. package/dist/{chunk-JRBNCUNT.js → chunk-NGSJZFGL.js} +21 -4
  123. package/dist/chunk-NGSJZFGL.js.map +1 -0
  124. package/dist/chunk-NJ4DYYO5.js +81 -0
  125. package/dist/chunk-NJ4DYYO5.js.map +1 -0
  126. package/dist/{chunk-2IALOXZS.js → chunk-NM5UYF6Q.js} +2 -2
  127. package/dist/chunk-NM5UYF6Q.js.map +1 -0
  128. package/dist/{chunk-JBBSYJHP.js → chunk-NYEFP7DY.js} +4 -4
  129. package/dist/chunk-NYEFP7DY.js.map +1 -0
  130. package/dist/{chunk-CCOP5XDW.js → chunk-NZ24MX4J.js} +8 -46
  131. package/dist/chunk-NZ24MX4J.js.map +1 -0
  132. package/dist/{chunk-KWVJAOIN.js → chunk-OLEPKFTW.js} +4 -4
  133. package/dist/chunk-OLEPKFTW.js.map +1 -0
  134. package/dist/{chunk-OF75ACKS.js → chunk-PEATRIYJ.js} +9 -9
  135. package/dist/chunk-PEOZ34EM.js +13 -0
  136. package/dist/chunk-PEOZ34EM.js.map +1 -0
  137. package/dist/{chunk-UC2ETWF3.js → chunk-PTHKZWEH.js} +2 -14
  138. package/dist/{chunk-UC2ETWF3.js.map → chunk-PTHKZWEH.js.map} +1 -1
  139. package/dist/chunk-PVEWA2DU.js +23 -0
  140. package/dist/chunk-PVEWA2DU.js.map +1 -0
  141. package/dist/{chunk-LSASLXGC.js → chunk-QBAC3GXA.js} +1 -1
  142. package/dist/chunk-QBAC3GXA.js.map +1 -0
  143. package/dist/{chunk-RDXW3OBQ.js → chunk-QD46HPZG.js} +2 -2
  144. package/dist/chunk-QD46HPZG.js.map +1 -0
  145. package/dist/{chunk-N55W7KUL.js → chunk-QDIH2744.js} +2 -2
  146. package/dist/{chunk-6HY2X62D.js → chunk-QJNCB5SK.js} +2 -2
  147. package/dist/{chunk-4BRCIYFG.js → chunk-QX76XVQH.js} +6 -6
  148. package/dist/chunk-QX76XVQH.js.map +1 -0
  149. package/dist/{chunk-W2OG6JOL.js → chunk-QZWTRENR.js} +24 -7
  150. package/dist/chunk-QZWTRENR.js.map +1 -0
  151. package/dist/{chunk-6NQMXTYC.js → chunk-RO5NM6UI.js} +2 -2
  152. package/dist/chunk-RO5NM6UI.js.map +1 -0
  153. package/dist/chunk-SGDPRCC4.js +1075 -0
  154. package/dist/chunk-SGDPRCC4.js.map +1 -0
  155. package/dist/{chunk-2PCAVW2I.js → chunk-SHEEBRZ4.js} +2 -2
  156. package/dist/chunk-SMY5X46Z.js +14 -0
  157. package/dist/chunk-SMY5X46Z.js.map +1 -0
  158. package/dist/{chunk-ISMV2QVG.js → chunk-TG634KCO.js} +11 -2
  159. package/dist/chunk-TG634KCO.js.map +1 -0
  160. package/dist/{chunk-J6Q7UVQE.js → chunk-TUXQSFHZ.js} +4 -16
  161. package/dist/{chunk-J6Q7UVQE.js.map → chunk-TUXQSFHZ.js.map} +1 -1
  162. package/dist/{chunk-GULTLPFB.js → chunk-UADPR6F4.js} +3 -3
  163. package/dist/{chunk-GULTLPFB.js.map → chunk-UADPR6F4.js.map} +1 -1
  164. package/dist/{chunk-ZEQWCBCM.js → chunk-UDHBXYGG.js} +27 -5
  165. package/dist/chunk-UDHBXYGG.js.map +1 -0
  166. package/dist/{chunk-RA5VTXXG.js → chunk-V6UQZA2H.js} +2 -2
  167. package/dist/chunk-VG2ZSFYD.js +32 -0
  168. package/dist/chunk-VG2ZSFYD.js.map +1 -0
  169. package/dist/chunk-VKQCVU2Z.js +21 -0
  170. package/dist/chunk-VKQCVU2Z.js.map +1 -0
  171. package/dist/{chunk-QDPZWTN2.js → chunk-W3G5REIU.js} +2 -2
  172. package/dist/{chunk-WEYZTLXN.js → chunk-W3L64Y3J.js} +2 -2
  173. package/dist/{chunk-ONTBCHCP.js → chunk-W66AM5IB.js} +2 -2
  174. package/dist/chunk-W66AM5IB.js.map +1 -0
  175. package/dist/{chunk-A5BDDEXK.js → chunk-WBKZUO5V.js} +26 -43
  176. package/dist/chunk-WBKZUO5V.js.map +1 -0
  177. package/dist/{chunk-CBSY2N76.js → chunk-WLXMTYGO.js} +2 -2
  178. package/dist/{chunk-3U3FBR7O.js → chunk-X3F5YJG2.js} +2 -2
  179. package/dist/{chunk-GQNGCEP5.js → chunk-X45JYIAY.js} +3 -3
  180. package/dist/chunk-X45JYIAY.js.map +1 -0
  181. package/dist/{chunk-6XE5TMPR.js → chunk-X4MVWPHV.js} +3 -3
  182. package/dist/chunk-X4MVWPHV.js.map +1 -0
  183. package/dist/chunk-XZHEOSQ2.js +16 -0
  184. package/dist/chunk-XZHEOSQ2.js.map +1 -0
  185. package/dist/chunk-Y2NBBT6K.js +18 -0
  186. package/dist/chunk-Y2NBBT6K.js.map +1 -0
  187. package/dist/{chunk-DDATL6PU.js → chunk-Y2NJBNX3.js} +8 -8
  188. package/dist/{chunk-DDATL6PU.js.map → chunk-Y2NJBNX3.js.map} +1 -1
  189. package/dist/chunk-YMUFFJCO.js +23 -0
  190. package/dist/chunk-YMUFFJCO.js.map +1 -0
  191. package/dist/{chunk-O7WJ47EF.js → chunk-YWWQM7KP.js} +5 -14
  192. package/dist/chunk-YWWQM7KP.js.map +1 -0
  193. package/dist/{chunk-7O3AYBC7.js → chunk-YZJSJOUI.js} +235 -65
  194. package/dist/chunk-YZJSJOUI.js.map +1 -0
  195. package/dist/{chunk-5WZXVULX.js → chunk-ZTLOXFPB.js} +2 -2
  196. package/dist/chunk-ZTLOXFPB.js.map +1 -0
  197. package/dist/classified/index.js +5 -5
  198. package/dist/{classified-marker-WQVIJAW2.js → classified-marker-7PKJBFCG.js} +3 -3
  199. package/dist/collection-facade-6I5K5IOD.js +45 -0
  200. package/dist/{computed-DSMPXG2Y.js → computed-AB45PS4V.js} +3 -3
  201. package/dist/consent/index.js +13 -9
  202. package/dist/consent/index.js.map +1 -1
  203. package/dist/cover/index.js +37 -0
  204. package/dist/crdt/index.js +4 -0
  205. package/dist/crdt/index.js.map +1 -1
  206. package/dist/custody/index.js +26 -0
  207. package/dist/{dead-filter-2A7IAJ3D.js → dead-filter-FL3WIUZS.js} +2 -2
  208. package/dist/{chunk-GYYCX5K6.js → delegation-QXZ4MPPH.js} +12 -6
  209. package/dist/{chunk-GYYCX5K6.js.map → delegation-QXZ4MPPH.js.map} +1 -1
  210. package/dist/derivations/index.js +12 -12
  211. package/dist/derive-VGS7FKE3.js +22 -0
  212. package/dist/directory/index.js +46 -0
  213. package/dist/dispatch-EGGC7UD7.js +72 -0
  214. package/dist/dispatch-EGGC7UD7.js.map +1 -0
  215. package/dist/dispatch-GDSTUTVP.js +194 -0
  216. package/dist/dispatch-GDSTUTVP.js.map +1 -0
  217. package/dist/{enclave-7MW6ZGXW.js → enclave-SPEEDYZ4.js} +11 -11
  218. package/dist/executor-IEBLTBCW.js +9 -0
  219. package/dist/executor-OTF556PL.js +28 -0
  220. package/dist/executor-RM7XWQDU.js +9 -0
  221. package/dist/export-accessible-P42BQ4PB.js +23 -0
  222. package/dist/extract-partition-TCYXRWBN.js +38 -0
  223. package/dist/{fanout-sidecar-WDYQ77VB.js → fanout-sidecar-SSMRSC2L.js} +9 -9
  224. package/dist/find-OZMTRIK3.js +11 -0
  225. package/dist/forget/index.js +11 -11
  226. package/dist/forget/index.js.map +1 -1
  227. package/dist/guards/index.js +6 -6
  228. package/dist/history/index.js +16 -12
  229. package/dist/history/index.js.map +1 -1
  230. package/dist/i18n/index.js +16 -14
  231. package/dist/i18n/index.js.map +1 -1
  232. package/dist/index.d.ts +42 -42
  233. package/dist/index.js +330 -2106
  234. package/dist/index.js.map +1 -1
  235. package/dist/indexing/index.js +4 -2
  236. package/dist/indexing/index.js.map +1 -1
  237. package/dist/introspection/index.js +28 -0
  238. package/dist/issue-FCKN5O6C.js +19 -0
  239. package/dist/kernel/best-effort-revert.d.ts +9 -1
  240. package/dist/kernel/collection-config.d.ts +12 -70
  241. package/dist/kernel/collection.d.ts +11 -23
  242. package/dist/kernel/enclave/crypto.d.ts +8 -8
  243. package/dist/kernel/enclave/index.d.ts +3 -3
  244. package/dist/kernel/errors.d.ts +41 -22
  245. package/dist/kernel/lazy.d.ts +30 -0
  246. package/dist/kernel/noydb.d.ts +81 -124
  247. package/dist/kernel/query/builder.d.ts +10 -10
  248. package/dist/kernel/query/index.d.ts +0 -6
  249. package/dist/kernel/query/scan-builder.d.ts +4 -4
  250. package/dist/kernel/sync-policy.d.ts +76 -4
  251. package/dist/kernel/types.d.ts +146 -86
  252. package/dist/kernel/validation.d.ts +33 -33
  253. package/dist/kernel/vault.d.ts +41 -229
  254. package/dist/kernel/via/dispatch.d.ts +7 -0
  255. package/dist/{ledger-33BC4TR7.js → ledger-6XBEVWYP.js} +11 -11
  256. package/dist/liberate-CYUOS4NC.js +24 -0
  257. package/dist/{link-set-QK22TDEX.js → link-set-NK6L2A5S.js} +11 -11
  258. package/dist/materialized-views/index.js +22 -19
  259. package/dist/money/index.js +31 -0
  260. package/dist/noydb-FZZIMLCI.js +81 -0
  261. package/dist/overlay-views/index.js +4 -4
  262. package/dist/periods/index.js +15 -13
  263. package/dist/pod/index.js +26 -12
  264. package/dist/{policy-NAHB2TUT.js → policy/index.js} +6 -6
  265. package/dist/port/with/archive-strategy.d.ts +31 -0
  266. package/dist/port/with/blob-strategy.d.ts +15 -5
  267. package/dist/port/with/collection-options.d.ts +171 -0
  268. package/dist/port/with/collection-registries.d.ts +62 -0
  269. package/dist/port/with/strategies.d.ts +134 -0
  270. package/dist/port/with/team-strategy.d.ts +3 -2
  271. package/dist/portability/index.js +8 -8
  272. package/dist/{post-register-JVTMJ6OW.js → post-register-VFIYISUK.js} +6 -6
  273. package/dist/query/index.js +6 -46
  274. package/dist/{aggregate → reduce}/index.js +24 -17
  275. package/dist/reduce/index.js.map +1 -0
  276. package/dist/register-UKU2J6MN.js +25 -0
  277. package/dist/registry-2VCWVHZS.js +19 -0
  278. package/dist/registry-7Y5WF7GS.js +9 -0
  279. package/dist/{registry-VW6P6A3J.js → registry-BWD2ED52.js} +2 -2
  280. package/dist/registry-DTWRJLSF.js +18 -0
  281. package/dist/request-withdrawal-JYDZ5XY2.js +31 -0
  282. package/dist/{reveal-LGBOM2BO.js → reveal-CL2BCW6A.js} +6 -6
  283. package/dist/revoke-2TSAD2T4.js +24 -0
  284. package/dist/satellites/index.js +1 -1
  285. package/dist/schema-update/index.js +26 -0
  286. package/dist/sealed-record/index.js +12 -12
  287. package/dist/search/index.js +36 -0
  288. package/dist/{seed-PWK45HDF.js → seed-NUVJEL7T.js} +12 -12
  289. package/dist/seed-NUVJEL7T.js.map +1 -0
  290. package/dist/sequence/index.js +30 -0
  291. package/dist/session/index.js +13 -9
  292. package/dist/session/index.js.map +1 -1
  293. package/dist/shadow/index.js +6 -2
  294. package/dist/shadow/index.js.map +1 -1
  295. package/dist/signer-K7Z2EOMG.js +25 -0
  296. package/dist/snapshots/index.js +14 -10
  297. package/dist/snapshots/index.js.map +1 -1
  298. package/dist/{stale-FJED42DM.js → stale-A4J26OIC.js} +11 -10
  299. package/dist/storage-YVHZUISN.js +23 -0
  300. package/dist/store/index.js +22 -0
  301. package/dist/{store-coordination-provider-APODTV4W.js → store-coordination-provider-EWRZL7XF.js} +3 -3
  302. package/dist/sync/index.js +15 -12
  303. package/dist/sync/index.js.map +1 -1
  304. package/dist/team/index.js +33 -48
  305. package/dist/tiers/index.js +10 -10
  306. package/dist/to/index.js +1 -1
  307. package/dist/{tx → transactions}/index.js +7 -3
  308. package/dist/transactions/index.js.map +1 -0
  309. package/dist/util/index.js +1 -1
  310. package/dist/{verify-26Y5GNMK.js → verify-7XWHJWUN.js} +5 -5
  311. package/dist/via/blob/active.d.ts +23 -7
  312. package/dist/via/blob/binding.d.ts +1 -1
  313. package/dist/via/blob/index.d.ts +7 -1
  314. package/dist/via/i18n/core.d.ts +1 -1
  315. package/dist/via/i18n/index.d.ts +2 -0
  316. package/dist/via/money/money-reducer.d.ts +2 -2
  317. package/dist/walk-P5D6CF4V.js +21 -0
  318. package/dist/with-audit/consent/index.d.ts +2 -0
  319. package/dist/with-audit/forget/active.d.ts +3 -3
  320. package/dist/with-audit/forget/index.d.ts +6 -5
  321. package/dist/with-audit/forget/strategy.d.ts +3 -3
  322. package/dist/with-audit/guards/executor.d.ts +4 -4
  323. package/dist/with-audit/guards/immutable-guard.d.ts +3 -3
  324. package/dist/with-audit/guards/index.d.ts +1 -1
  325. package/dist/with-audit/guards/registry.d.ts +3 -3
  326. package/dist/with-audit/guards/transition-guard.d.ts +3 -3
  327. package/dist/with-audit/guards/types.d.ts +10 -10
  328. package/dist/with-audit/guards/with-guard.d.ts +2 -2
  329. package/dist/with-audit/periods/index.d.ts +2 -0
  330. package/dist/with-audit/periods/vault-facade.d.ts +6 -0
  331. package/dist/with-audit/portability/export-accessible.d.ts +4 -4
  332. package/dist/with-audit/portability/request-withdrawal.d.ts +3 -3
  333. package/dist/with-audit/portability/withdraw-accessible.d.ts +2 -2
  334. package/dist/with-audit/sealed-record/strategy.d.ts +1 -1
  335. package/dist/with-audit/tiers/index.d.ts +1 -0
  336. package/dist/with-cargo/adopt-partition.d.ts +7 -7
  337. package/dist/{legacy/kernel.d.ts → with-cargo/floor.d.ts} +4 -4
  338. package/dist/with-cargo/index.d.ts +9 -2
  339. package/dist/with-commit/crdt/index.d.ts +2 -0
  340. package/dist/with-commit/history/index.d.ts +2 -0
  341. package/dist/with-commit/history/time-machine.d.ts +2 -2
  342. package/dist/with-commit/numbering/descriptor.d.ts +16 -6
  343. package/dist/with-commit/tx/active.d.ts +5 -5
  344. package/dist/with-commit/tx/index.d.ts +2 -2
  345. package/dist/with-commit/tx/invariants.d.ts +1 -1
  346. package/dist/with-commit/tx/strategy.d.ts +3 -3
  347. package/dist/with-fork/shadow/index.d.ts +2 -0
  348. package/dist/with-fork/snapshots/active.d.ts +2 -2
  349. package/dist/with-fork/snapshots/index.d.ts +3 -1
  350. package/dist/with-fork/snapshots/noydb-facade.d.ts +3 -3
  351. package/dist/with-fork/snapshots/strategy.d.ts +2 -2
  352. package/dist/with-formula/derivations/dispatch.d.ts +98 -0
  353. package/dist/with-formula/derivations/executor.d.ts +2 -2
  354. package/dist/with-formula/derivations/index.d.ts +4 -1
  355. package/dist/with-formula/derivations/registry.d.ts +3 -3
  356. package/dist/with-formula/derivations/stale.d.ts +2 -2
  357. package/dist/with-formula/derivations/types.d.ts +3 -3
  358. package/dist/with-formula/derivations/with-derivation.d.ts +2 -2
  359. package/dist/with-formula/derivations/with-rollup.d.ts +15 -8
  360. package/dist/with-formula/materialized-views/dependency-analyzer.d.ts +3 -3
  361. package/dist/with-formula/materialized-views/dispatch.d.ts +75 -0
  362. package/dist/with-formula/materialized-views/index.d.ts +2 -1
  363. package/dist/with-formula/materialized-views/registry.d.ts +4 -4
  364. package/dist/with-formula/materialized-views/types.d.ts +11 -11
  365. package/dist/with-formula/materialized-views/with-materialized-view.d.ts +2 -2
  366. package/dist/with-formula/overlay-views/index.d.ts +1 -1
  367. package/dist/with-formula/overlay-views/registry.d.ts +4 -4
  368. package/dist/with-formula/overlay-views/types.d.ts +3 -3
  369. package/dist/with-formula/overlay-views/virtual-collection.d.ts +2 -2
  370. package/dist/with-formula/overlay-views/with-overlayed-view.d.ts +2 -2
  371. package/dist/with-lookup/indexing/active.d.ts +5 -5
  372. package/dist/with-lookup/indexing/index.d.ts +3 -1
  373. package/dist/with-lookup/indexing/strategy.d.ts +3 -3
  374. package/dist/with-lookup/{aggregate → reduce}/active.d.ts +8 -8
  375. package/dist/with-lookup/{aggregate → reduce}/groupby.d.ts +21 -21
  376. package/dist/with-lookup/reduce/index.d.ts +34 -0
  377. package/dist/with-lookup/{aggregate → reduce}/reducers.d.ts +11 -12
  378. package/dist/with-lookup/{aggregate/aggregation.d.ts → reduce/reduction.d.ts} +21 -21
  379. package/dist/with-lookup/{aggregate → reduce}/strategy.d.ts +15 -15
  380. package/dist/with-lookup/search/build-docs.d.ts +7 -2
  381. package/dist/with-lookup/search/index.d.ts +1 -1
  382. package/dist/with-party/broker/index.d.ts +1 -0
  383. package/dist/with-party/broker/seed.d.ts +1 -1
  384. package/dist/with-party/custody/liberate.d.ts +3 -3
  385. package/dist/with-party/directory/cover/index.d.ts +1 -5
  386. package/dist/with-party/directory/cover/schema.d.ts +0 -6
  387. package/dist/with-party/directory/cover/storage.d.ts +0 -8
  388. package/dist/with-party/directory/cover/types.d.ts +0 -21
  389. package/dist/with-party/directory/index.d.ts +2 -0
  390. package/dist/with-party/session/dev-unlock.d.ts +2 -2
  391. package/dist/with-party/session/index.d.ts +2 -0
  392. package/dist/with-party/session/session.d.ts +2 -2
  393. package/dist/with-party/team/deed.d.ts +8 -8
  394. package/dist/with-party/team/index.d.ts +4 -7
  395. package/dist/with-party/team/keyring.d.ts +83 -35
  396. package/dist/with-party/team/{managed-passphrase.d.ts → managed-secret.d.ts} +27 -27
  397. package/dist/with-party/team/noydb-facade.d.ts +43 -42
  398. package/dist/with-party/team/peer-recover.d.ts +13 -13
  399. package/dist/with-party/team/recovery.d.ts +5 -5
  400. package/dist/with-party/team/rotate-recover.d.ts +30 -30
  401. package/dist/with-pod/bundle.d.ts +30 -32
  402. package/dist/with-pod/format.d.ts +2 -2
  403. package/dist/with-pod/index.d.ts +2 -1
  404. package/dist/with-shape/blobs/blob-compaction.d.ts +43 -3
  405. package/dist/with-shape/blobs/blob-pinning.d.ts +112 -0
  406. package/dist/with-shape/blobs/blob-set.d.ts +86 -2
  407. package/dist/with-shape/introspection/index.d.ts +6 -0
  408. package/dist/with-shape/schema-update/index.d.ts +1 -0
  409. package/dist/with-store/index.d.ts +3 -2
  410. package/dist/with-store/route-store.d.ts +1 -1
  411. package/dist/{with-party/team/sync-active.d.ts → with-sync/active.d.ts} +1 -1
  412. package/dist/{with-party/team/sync-credentials.d.ts → with-sync/credentials.d.ts} +3 -3
  413. package/dist/{with-party/team/sync.d.ts → with-sync/engine.d.ts} +5 -5
  414. package/dist/{with-party/sync → with-sync}/index.d.ts +4 -2
  415. package/dist/{with-party/team/sync-period-scope.d.ts → with-sync/period-scope.d.ts} +2 -2
  416. package/dist/{with-party/team → with-sync}/presence.d.ts +2 -2
  417. package/dist/{with-party/team/sync-strategy.d.ts → with-sync/strategy.d.ts} +6 -6
  418. package/dist/{with-party/team/sync-transaction.d.ts → with-sync/transaction.d.ts} +3 -3
  419. package/dist/withdraw-accessible-A2PWF5MZ.js +28 -0
  420. package/package.json +45 -36
  421. package/dist/aggregate/index.js.map +0 -1
  422. package/dist/api-IQFZJSQO.js +0 -20
  423. package/dist/as/index.js +0 -30
  424. package/dist/at/index.js +0 -1
  425. package/dist/bundle/index.js +0 -105
  426. package/dist/by/index.js +0 -11
  427. package/dist/chunk-2IALOXZS.js.map +0 -1
  428. package/dist/chunk-2MUZ3LY6.js +0 -205
  429. package/dist/chunk-2MUZ3LY6.js.map +0 -1
  430. package/dist/chunk-2P7EGNKF.js.map +0 -1
  431. package/dist/chunk-3PF6CRDT.js.map +0 -1
  432. package/dist/chunk-3SV2EPMN.js.map +0 -1
  433. package/dist/chunk-4BRCIYFG.js.map +0 -1
  434. package/dist/chunk-5OI6BR4H.js.map +0 -1
  435. package/dist/chunk-5WZXVULX.js.map +0 -1
  436. package/dist/chunk-6NQMXTYC.js.map +0 -1
  437. package/dist/chunk-6XE5TMPR.js.map +0 -1
  438. package/dist/chunk-7CI6CP7Z.js.map +0 -1
  439. package/dist/chunk-7O3AYBC7.js.map +0 -1
  440. package/dist/chunk-A5BDDEXK.js.map +0 -1
  441. package/dist/chunk-A7JJLVGH.js.map +0 -1
  442. package/dist/chunk-BGK233EA.js.map +0 -1
  443. package/dist/chunk-BMQWTQZ4.js.map +0 -1
  444. package/dist/chunk-BOKIKJJB.js.map +0 -1
  445. package/dist/chunk-CCOP5XDW.js.map +0 -1
  446. package/dist/chunk-CHFZDSE4.js +0 -1
  447. package/dist/chunk-DDHM2TLX.js.map +0 -1
  448. package/dist/chunk-GQNGCEP5.js.map +0 -1
  449. package/dist/chunk-GVZQ4NAM.js +0 -14
  450. package/dist/chunk-GVZQ4NAM.js.map +0 -1
  451. package/dist/chunk-GWKAVKHI.js.map +0 -1
  452. package/dist/chunk-HOONYZY2.js.map +0 -1
  453. package/dist/chunk-HPUWOVR7.js.map +0 -1
  454. package/dist/chunk-ISMV2QVG.js.map +0 -1
  455. package/dist/chunk-JBBSYJHP.js.map +0 -1
  456. package/dist/chunk-JRBNCUNT.js.map +0 -1
  457. package/dist/chunk-JZWWLLVY.js +0 -99
  458. package/dist/chunk-JZWWLLVY.js.map +0 -1
  459. package/dist/chunk-KUPKLSX5.js.map +0 -1
  460. package/dist/chunk-KWVJAOIN.js.map +0 -1
  461. package/dist/chunk-LB6OH6K2.js.map +0 -1
  462. package/dist/chunk-LB7FD65R.js +0 -163
  463. package/dist/chunk-LB7FD65R.js.map +0 -1
  464. package/dist/chunk-LOF2W3JU.js.map +0 -1
  465. package/dist/chunk-LSASLXGC.js.map +0 -1
  466. package/dist/chunk-O7WJ47EF.js.map +0 -1
  467. package/dist/chunk-ONTBCHCP.js.map +0 -1
  468. package/dist/chunk-PT37L5DV.js +0 -255
  469. package/dist/chunk-PT37L5DV.js.map +0 -1
  470. package/dist/chunk-RDXW3OBQ.js.map +0 -1
  471. package/dist/chunk-RND5ZPNP.js.map +0 -1
  472. package/dist/chunk-S3BFKGET.js.map +0 -1
  473. package/dist/chunk-SMGEYW6G.js.map +0 -1
  474. package/dist/chunk-T36RFODW.js.map +0 -1
  475. package/dist/chunk-TAGR72IR.js.map +0 -1
  476. package/dist/chunk-UNCOC7QH.js.map +0 -1
  477. package/dist/chunk-VCBHAE4R.js.map +0 -1
  478. package/dist/chunk-VEALDPHW.js.map +0 -1
  479. package/dist/chunk-VQNJ7UZL.js.map +0 -1
  480. package/dist/chunk-W2OG6JOL.js.map +0 -1
  481. package/dist/chunk-WNGGJWF7.js.map +0 -1
  482. package/dist/chunk-YJV2UZ7H.js.map +0 -1
  483. package/dist/chunk-YMUGBZN2.js.map +0 -1
  484. package/dist/chunk-YTGDPCPW.js.map +0 -1
  485. package/dist/chunk-ZEQWCBCM.js.map +0 -1
  486. package/dist/collection-facade-MJXSC3Q6.js +0 -44
  487. package/dist/cover-B5SJDHR3.js +0 -52
  488. package/dist/delegation-A5A75KQO.js +0 -25
  489. package/dist/derive-HJSMH7RA.js +0 -21
  490. package/dist/executor-AXE4XMLT.js +0 -26
  491. package/dist/executor-KGNLJD6M.js +0 -9
  492. package/dist/executor-XGIS6CR7.js +0 -9
  493. package/dist/export-accessible-VVBJM3MM.js +0 -23
  494. package/dist/extract-partition-LGGBTQET.js +0 -38
  495. package/dist/find-YS6XWB46.js +0 -11
  496. package/dist/in/index.js +0 -1
  497. package/dist/issue-LSR5PS6H.js +0 -19
  498. package/dist/legacy/bundle.d.ts +0 -30
  499. package/dist/liberate-GBSAYLPJ.js +0 -24
  500. package/dist/noydb-MTUBMWFE.js +0 -70
  501. package/dist/on/index.js +0 -17
  502. package/dist/port/as/index.d.ts +0 -26
  503. package/dist/port/at/index.d.ts +0 -18
  504. package/dist/port/in/index.d.ts +0 -21
  505. package/dist/port/on/index.d.ts +0 -27
  506. package/dist/port/ui/index.d.ts +0 -21
  507. package/dist/port/with/index.d.ts +0 -18
  508. package/dist/register-X462DNDM.js +0 -23
  509. package/dist/registry-3XMCT7MQ.js +0 -18
  510. package/dist/registry-KHD2I3M2.js +0 -19
  511. package/dist/registry-NPOWJHC4.js +0 -9
  512. package/dist/request-withdrawal-U7K3JTMY.js +0 -31
  513. package/dist/revoke-OCWDSWRQ.js +0 -24
  514. package/dist/seed-PWK45HDF.js.map +0 -1
  515. package/dist/signer-3YFBLZRN.js +0 -25
  516. package/dist/storage-W3GURVFU.js +0 -23
  517. package/dist/tx/index.js.map +0 -1
  518. package/dist/ui/index.js +0 -1
  519. package/dist/with/index.js +0 -31
  520. package/dist/with-lookup/aggregate/index.d.ts +0 -23
  521. package/dist/withdraw-accessible-Y3B2535F.js +0 -28
  522. /package/dist/{api-IQFZJSQO.js.map → api-ZDKTWNBB.js.map} +0 -0
  523. /package/dist/{backup-LU2DTZTI.js.map → backup-2UX7PRM5.js.map} +0 -0
  524. /package/dist/{chunk-IY23KFNZ.js.map → chunk-35NMVJ7I.js.map} +0 -0
  525. /package/dist/{chunk-RTEK4C4I.js.map → chunk-4JQK3L4V.js.map} +0 -0
  526. /package/dist/{chunk-3ELCWU56.js.map → chunk-4ZKNC6A6.js.map} +0 -0
  527. /package/dist/{chunk-VAIS3SOM.js.map → chunk-55LX6FSX.js.map} +0 -0
  528. /package/dist/{chunk-6HPG2YNX.js.map → chunk-5DRROK5W.js.map} +0 -0
  529. /package/dist/{chunk-S6Q37VGE.js.map → chunk-5GQEU4DN.js.map} +0 -0
  530. /package/dist/{chunk-TOPYT5U5.js.map → chunk-63FE525P.js.map} +0 -0
  531. /package/dist/{chunk-JVBO4SZL.js.map → chunk-6UBZ6I5Z.js.map} +0 -0
  532. /package/dist/{chunk-UFEVO57O.js.map → chunk-ABS7FMMD.js.map} +0 -0
  533. /package/dist/{chunk-M75ZZHSR.js.map → chunk-BLBAQRBM.js.map} +0 -0
  534. /package/dist/{chunk-G6EQYAL6.js.map → chunk-CI32CAFS.js.map} +0 -0
  535. /package/dist/{chunk-6B4DYGWO.js.map → chunk-DABACXEF.js.map} +0 -0
  536. /package/dist/{chunk-F6T6L2UK.js.map → chunk-DMH3VZU5.js.map} +0 -0
  537. /package/dist/{chunk-MQ6WOPSY.js.map → chunk-DZ2JXHWK.js.map} +0 -0
  538. /package/dist/{chunk-UBNCR3YK.js.map → chunk-EE7UHLKH.js.map} +0 -0
  539. /package/dist/{chunk-EGCRBCNA.js.map → chunk-EKRSCRNM.js.map} +0 -0
  540. /package/dist/{chunk-IRQY7IR5.js.map → chunk-FRMPM7WG.js.map} +0 -0
  541. /package/dist/{as/index.js.map → chunk-GJW4HX2O.js.map} +0 -0
  542. /package/dist/{chunk-T6GU5PPZ.js.map → chunk-GU3IP74F.js.map} +0 -0
  543. /package/dist/{chunk-SMIRGMS7.js.map → chunk-IXNCZTWA.js.map} +0 -0
  544. /package/dist/{chunk-RM2XV574.js.map → chunk-IXTSNGYY.js.map} +0 -0
  545. /package/dist/{chunk-PK6QCH2C.js.map → chunk-JJZGIE4U.js.map} +0 -0
  546. /package/dist/{chunk-DRWBEDYO.js.map → chunk-JYJFGD2H.js.map} +0 -0
  547. /package/dist/{chunk-KUIB4B5Q.js.map → chunk-LNZKOUJR.js.map} +0 -0
  548. /package/dist/{chunk-IM3QVF53.js.map → chunk-MBKVNOJS.js.map} +0 -0
  549. /package/dist/{chunk-N6WF5PKC.js.map → chunk-NFZGZ4AK.js.map} +0 -0
  550. /package/dist/{chunk-OF75ACKS.js.map → chunk-PEATRIYJ.js.map} +0 -0
  551. /package/dist/{chunk-N55W7KUL.js.map → chunk-QDIH2744.js.map} +0 -0
  552. /package/dist/{chunk-6HY2X62D.js.map → chunk-QJNCB5SK.js.map} +0 -0
  553. /package/dist/{chunk-2PCAVW2I.js.map → chunk-SHEEBRZ4.js.map} +0 -0
  554. /package/dist/{chunk-RA5VTXXG.js.map → chunk-V6UQZA2H.js.map} +0 -0
  555. /package/dist/{chunk-QDPZWTN2.js.map → chunk-W3G5REIU.js.map} +0 -0
  556. /package/dist/{chunk-WEYZTLXN.js.map → chunk-W3L64Y3J.js.map} +0 -0
  557. /package/dist/{chunk-CBSY2N76.js.map → chunk-WLXMTYGO.js.map} +0 -0
  558. /package/dist/{chunk-3U3FBR7O.js.map → chunk-X3F5YJG2.js.map} +0 -0
  559. /package/dist/{classified-marker-WQVIJAW2.js.map → classified-marker-7PKJBFCG.js.map} +0 -0
  560. /package/dist/{at/index.js.map → collection-facade-6I5K5IOD.js.map} +0 -0
  561. /package/dist/{bundle/index.js.map → computed-AB45PS4V.js.map} +0 -0
  562. /package/dist/{by → cover}/index.js.map +0 -0
  563. /package/dist/{in → custody}/index.js.map +0 -0
  564. /package/dist/{dead-filter-2A7IAJ3D.js.map → dead-filter-FL3WIUZS.js.map} +0 -0
  565. /package/dist/{chunk-CHFZDSE4.js.map → derive-VGS7FKE3.js.map} +0 -0
  566. /package/dist/{on → directory}/index.js.map +0 -0
  567. /package/dist/{collection-facade-MJXSC3Q6.js.map → enclave-SPEEDYZ4.js.map} +0 -0
  568. /package/dist/{computed-DSMPXG2Y.js.map → executor-IEBLTBCW.js.map} +0 -0
  569. /package/dist/{cover-B5SJDHR3.js.map → executor-OTF556PL.js.map} +0 -0
  570. /package/dist/{delegation-A5A75KQO.js.map → executor-RM7XWQDU.js.map} +0 -0
  571. /package/dist/{derive-HJSMH7RA.js.map → export-accessible-P42BQ4PB.js.map} +0 -0
  572. /package/dist/{enclave-7MW6ZGXW.js.map → extract-partition-TCYXRWBN.js.map} +0 -0
  573. /package/dist/{fanout-sidecar-WDYQ77VB.js.map → fanout-sidecar-SSMRSC2L.js.map} +0 -0
  574. /package/dist/{executor-AXE4XMLT.js.map → find-OZMTRIK3.js.map} +0 -0
  575. /package/dist/{ui → introspection}/index.js.map +0 -0
  576. /package/dist/{executor-KGNLJD6M.js.map → issue-FCKN5O6C.js.map} +0 -0
  577. /package/dist/{executor-XGIS6CR7.js.map → ledger-6XBEVWYP.js.map} +0 -0
  578. /package/dist/{export-accessible-VVBJM3MM.js.map → liberate-CYUOS4NC.js.map} +0 -0
  579. /package/dist/{extract-partition-LGGBTQET.js.map → link-set-NK6L2A5S.js.map} +0 -0
  580. /package/dist/{with → money}/index.js.map +0 -0
  581. /package/dist/{find-YS6XWB46.js.map → noydb-FZZIMLCI.js.map} +0 -0
  582. /package/dist/{issue-LSR5PS6H.js.map → policy/index.js.map} +0 -0
  583. /package/dist/{post-register-JVTMJ6OW.js.map → post-register-VFIYISUK.js.map} +0 -0
  584. /package/dist/{ledger-33BC4TR7.js.map → register-UKU2J6MN.js.map} +0 -0
  585. /package/dist/{liberate-GBSAYLPJ.js.map → registry-2VCWVHZS.js.map} +0 -0
  586. /package/dist/{link-set-QK22TDEX.js.map → registry-7Y5WF7GS.js.map} +0 -0
  587. /package/dist/{noydb-MTUBMWFE.js.map → registry-BWD2ED52.js.map} +0 -0
  588. /package/dist/{policy-NAHB2TUT.js.map → registry-DTWRJLSF.js.map} +0 -0
  589. /package/dist/{register-X462DNDM.js.map → request-withdrawal-JYDZ5XY2.js.map} +0 -0
  590. /package/dist/{reveal-LGBOM2BO.js.map → reveal-CL2BCW6A.js.map} +0 -0
  591. /package/dist/{registry-3XMCT7MQ.js.map → revoke-2TSAD2T4.js.map} +0 -0
  592. /package/dist/{registry-KHD2I3M2.js.map → schema-update/index.js.map} +0 -0
  593. /package/dist/{registry-NPOWJHC4.js.map → search/index.js.map} +0 -0
  594. /package/dist/{registry-VW6P6A3J.js.map → sequence/index.js.map} +0 -0
  595. /package/dist/{request-withdrawal-U7K3JTMY.js.map → signer-K7Z2EOMG.js.map} +0 -0
  596. /package/dist/{revoke-OCWDSWRQ.js.map → stale-A4J26OIC.js.map} +0 -0
  597. /package/dist/{signer-3YFBLZRN.js.map → storage-YVHZUISN.js.map} +0 -0
  598. /package/dist/{stale-FJED42DM.js.map → store/index.js.map} +0 -0
  599. /package/dist/{store-coordination-provider-APODTV4W.js.map → store-coordination-provider-EWRZL7XF.js.map} +0 -0
  600. /package/dist/{verify-26Y5GNMK.js.map → verify-7XWHJWUN.js.map} +0 -0
  601. /package/dist/{storage-W3GURVFU.js.map → walk-P5D6CF4V.js.map} +0 -0
  602. /package/dist/with-lookup/{aggregate → reduce}/canonical-key.d.ts +0 -0
  603. /package/dist/{with-party → with-sync}/tab-coordination.d.ts +0 -0
  604. /package/dist/{with-party → with-sync}/tab-write-relay.d.ts +0 -0
  605. /package/dist/{withdraw-accessible-Y3B2535F.js.map → withdraw-accessible-A2PWF5MZ.js.map} +0 -0
@@ -1,89 +1,59 @@
1
1
  import {
2
- loadVaultPolicy
3
- } from "./chunk-CBSY2N76.js";
4
- import {
5
- jsonSchemaToFields
6
- } from "./chunk-VYYM3MEN.js";
7
- import {
8
- NO_SEQUENCE,
9
- SEQUENCE_COLLECTION,
10
- compileSequenceFormat,
11
- resolveSequenceKey
12
- } from "./chunk-HPUWOVR7.js";
2
+ resolveStaleOnRead
3
+ } from "./chunk-NJ4DYYO5.js";
13
4
  import {
14
5
  LinkIntegrityError,
15
6
  isLinkCollectionName,
16
7
  linkCollectionName,
17
8
  linkRowKey
18
- } from "./chunk-RTEK4C4I.js";
9
+ } from "./chunk-4JQK3L4V.js";
19
10
  import {
20
11
  hashFields,
21
12
  validateSatelliteDeclaration
22
- } from "./chunk-2PCAVW2I.js";
13
+ } from "./chunk-SHEEBRZ4.js";
23
14
  import {
24
15
  loadFence
25
- } from "./chunk-KUIB4B5Q.js";
16
+ } from "./chunk-LNZKOUJR.js";
26
17
  import {
27
- InvertedIndex,
28
- MemoryIndexStore,
29
- NO_SEARCH,
30
18
  VectorSet,
31
19
  buildPersistedIndexCallbacks,
32
20
  encodeVecId,
33
21
  syncTierSearch
34
- } from "./chunk-BMQWTQZ4.js";
22
+ } from "./chunk-7YVBQJ7K.js";
35
23
  import {
36
- derivePersistedSchema,
37
- isZod4Schema
38
- } from "./chunk-BOKIKJJB.js";
24
+ SchemaUpdateGate
25
+ } from "./chunk-6LJY7X5A.js";
39
26
  import {
40
27
  isBaseLive,
41
28
  liveBaseIdSet
42
29
  } from "./chunk-GYGLAVCX.js";
30
+ import {
31
+ NO_TIERS,
32
+ classifySealedShred,
33
+ syncDerivedOutputs
34
+ } from "./chunk-Y2NJBNX3.js";
43
35
  import {
44
36
  NO_PORTABILITY
45
- } from "./chunk-M75ZZHSR.js";
37
+ } from "./chunk-BLBAQRBM.js";
46
38
  import {
47
- CustodyApi,
48
39
  NO_CARGO,
49
- NO_CUSTODY
50
- } from "./chunk-O7WJ47EF.js";
51
- import {
52
- ServiceBus,
53
- WriteHookRegistry,
54
- assertCanExport,
55
- assertCanImport,
56
- canExport,
57
- canImport
58
- } from "./chunk-PT37L5DV.js";
59
- import {
60
40
  runDrainBarrier
61
- } from "./chunk-ISMV2QVG.js";
41
+ } from "./chunk-TG634KCO.js";
62
42
  import {
63
- OverlayedCollection
64
- } from "./chunk-5WZXVULX.js";
65
- import {
66
- NO_ATTESTATION
67
- } from "./chunk-S6Q37VGE.js";
68
- import {
69
- NO_CLASSIFIED,
70
- guardClassifiedCompat,
71
- resolveClassifiedFields
72
- } from "./chunk-UBNCR3YK.js";
43
+ resolveManagedSecret,
44
+ saveSealedSecret
45
+ } from "./chunk-FQZ6XTQ7.js";
73
46
  import {
74
- NO_TIERS,
75
- classifySealedShred,
76
- syncDerivedOutputs
77
- } from "./chunk-DDATL6PU.js";
47
+ jsonSchemaToFields
48
+ } from "./chunk-VYYM3MEN.js";
78
49
  import {
79
- TxContext,
80
- bestEffortRevert,
81
- revertExecuted
82
- } from "./chunk-JRBNCUNT.js";
50
+ derivePersistedSchema,
51
+ isZod4Schema
52
+ } from "./chunk-6ZNSB3H6.js";
83
53
  import {
84
54
  DEFAULT_POSTURE,
85
55
  ViaGraph
86
- } from "./chunk-3ELCWU56.js";
56
+ } from "./chunk-4ZKNC6A6.js";
87
57
  import {
88
58
  buildLookupAltIndex,
89
59
  buildLookupSnapshotRows,
@@ -104,24 +74,80 @@ import {
104
74
  resolveLabelFromMap,
105
75
  resolveRollupDeleteIntents,
106
76
  runGraphDispatchWave,
77
+ selfWriteFieldEqual,
107
78
  touchFor,
108
79
  updateReferencingRecords
109
- } from "./chunk-MTQPRQHB.js";
80
+ } from "./chunk-IPUG56GJ.js";
81
+ import {
82
+ OverlayedCollection
83
+ } from "./chunk-ZTLOXFPB.js";
84
+ import {
85
+ INDEXED_STORE_POLICY,
86
+ NO_SYNC
87
+ } from "./chunk-55LKVALY.js";
88
+ import {
89
+ NO_ATTESTATION
90
+ } from "./chunk-5GQEU4DN.js";
91
+ import {
92
+ NO_CLASSIFIED,
93
+ guardClassifiedCompat,
94
+ resolveClassifiedFields
95
+ } from "./chunk-EE7UHLKH.js";
96
+ import {
97
+ NO_PERIODS
98
+ } from "./chunk-UDHBXYGG.js";
99
+ import {
100
+ PERIODS_COLLECTION,
101
+ PERIOD_ARCHIVES_COLLECTION,
102
+ PERIOD_FREEZES_COLLECTION,
103
+ PERIOD_TARGET_PURGES_COLLECTION,
104
+ periodExclusiveUpperBound
105
+ } from "./chunk-NM5UYF6Q.js";
106
+ import {
107
+ NO_SHADOW
108
+ } from "./chunk-SMY5X46Z.js";
109
+ import {
110
+ NO_SNAPSHOTS
111
+ } from "./chunk-DZFQVICS.js";
112
+ import {
113
+ TxContext,
114
+ bestEffortRevert,
115
+ revertExecuted
116
+ } from "./chunk-NGSJZFGL.js";
117
+ import {
118
+ lazy
119
+ } from "./chunk-5D2ALSM5.js";
120
+ import {
121
+ InvertedIndex,
122
+ MemoryIndexStore,
123
+ NO_SEARCH
124
+ } from "./chunk-MCHBCNCE.js";
125
+ import {
126
+ NO_SEQUENCE,
127
+ SEQUENCE_COLLECTION,
128
+ compileSequenceFormat,
129
+ resolveSequenceKey
130
+ } from "./chunk-L2DGWBCT.js";
131
+ import {
132
+ CustodyApi,
133
+ NO_CUSTODY
134
+ } from "./chunk-YWWQM7KP.js";
110
135
  import {
111
- NO_AGGREGATE,
112
136
  Query,
113
137
  ScanBuilder
114
- } from "./chunk-A5BDDEXK.js";
138
+ } from "./chunk-WBKZUO5V.js";
115
139
  import {
116
140
  EXPORT_AUDIT_COLLECTION,
141
+ NO_BLOBS,
117
142
  createExportBlobsHandle,
118
143
  runCompaction
119
- } from "./chunk-2P7EGNKF.js";
144
+ } from "./chunk-CXQW2NWO.js";
120
145
  import {
121
146
  LazyQuery,
147
+ NO_INDEXING,
122
148
  decodeIdxId,
123
149
  encodeIdxId
124
- } from "./chunk-VEALDPHW.js";
150
+ } from "./chunk-L3YYLT4E.js";
125
151
  import {
126
152
  IMPLICIT_LAZY,
127
153
  Lru,
@@ -129,17 +155,22 @@ import {
129
155
  } from "./chunk-NO272T7Q.js";
130
156
  import {
131
157
  canonicalGroupKey
132
- } from "./chunk-TAGR72IR.js";
158
+ } from "./chunk-XZHEOSQ2.js";
159
+ import {
160
+ NO_REDUCE
161
+ } from "./chunk-YMUFFJCO.js";
133
162
  import {
134
163
  readPath
135
164
  } from "./chunk-IGJCYUT5.js";
136
165
  import {
137
- resolveManagedSecret,
138
- saveSealedPassphrase
139
- } from "./chunk-LB6OH6K2.js";
166
+ NO_CRDT
167
+ } from "./chunk-PVEWA2DU.js";
168
+ import {
169
+ NO_CONSENT
170
+ } from "./chunk-PEOZ34EM.js";
140
171
  import {
141
172
  dictCollectionName
142
- } from "./chunk-IRQY7IR5.js";
173
+ } from "./chunk-FRMPM7WG.js";
143
174
  import {
144
175
  NO_I18N,
145
176
  getAtPath,
@@ -147,43 +178,34 @@ import {
147
178
  isDictKeyDescriptor,
148
179
  isI18nTextDescriptor,
149
180
  isStaticDictDescriptor
150
- } from "./chunk-GULTLPFB.js";
181
+ } from "./chunk-UADPR6F4.js";
151
182
  import {
152
- installViaBinder,
153
183
  isViaInstalled,
154
184
  viaBinder
155
- } from "./chunk-JVBO4SZL.js";
185
+ } from "./chunk-6UBZ6I5Z.js";
156
186
  import {
157
187
  NO_TEAM,
188
+ describeAllUsersAuth,
189
+ describeAuthConfig,
190
+ describeUserAuth,
191
+ diagramAuthConfig,
158
192
  enrollAuthenticator,
159
193
  findAuthenticator,
160
- recoverPassphrase,
161
- recoverUser,
162
- removeAuthenticator,
163
- rotatePassphrase,
164
- updateAuthenticator,
165
- writeMagicLinkGrant
166
- } from "./chunk-LOF2W3JU.js";
167
- import {
168
194
  hasRecoveryEnrolled,
169
195
  hasStrongRecoveryEnrolled,
170
196
  loadPaperRecoveryEntries,
171
197
  loadShamirRecoveryEntries,
172
198
  mintPaperRecoveryEntry,
173
199
  mintShamirRecoveryEntry,
200
+ recoverSecret,
201
+ recoverUser,
202
+ removeAuthenticator,
203
+ rotateSecret,
174
204
  savePaperRecoveryEntries,
175
- saveShamirRecoveryEntries
176
- } from "./chunk-2MUZ3LY6.js";
177
- import {
178
- INDEXED_STORE_POLICY
179
- } from "./chunk-VQNJ7UZL.js";
180
- import {
181
- PERIODS_COLLECTION,
182
- PERIOD_ARCHIVES_COLLECTION,
183
- PERIOD_FREEZES_COLLECTION,
184
- PERIOD_TARGET_PURGES_COLLECTION,
185
- periodExclusiveUpperBound
186
- } from "./chunk-2IALOXZS.js";
205
+ saveShamirRecoveryEntries,
206
+ updateAuthenticator,
207
+ writeMagicLinkGrant
208
+ } from "./chunk-NFNJLRY7.js";
187
209
  import {
188
210
  assertKeyringOpenAllowed,
189
211
  buildRecipientKeyringFile,
@@ -191,31 +213,39 @@ import {
191
213
  createOwnerKeyring,
192
214
  ensureCollectionDEK,
193
215
  hasAccess,
216
+ hasExportCapability,
217
+ hasImportCapability,
194
218
  hasWritePermission,
195
219
  isSecretBearingReservedCollection,
196
220
  listUsers,
197
221
  loadKeyring,
198
222
  updateKeyringIdentity
199
- } from "./chunk-3SV2EPMN.js";
223
+ } from "./chunk-BLCWSJLN.js";
200
224
  import {
201
225
  persistDirectoryConfig,
202
226
  readDirectoryConfig
203
- } from "./chunk-PK6QCH2C.js";
227
+ } from "./chunk-JJZGIE4U.js";
204
228
  import {
205
229
  NO_BROKER,
206
230
  buildCredentialBrokerHandle
207
- } from "./chunk-SMIRGMS7.js";
231
+ } from "./chunk-IXNCZTWA.js";
232
+ import {
233
+ NO_SESSION
234
+ } from "./chunk-VKQCVU2Z.js";
208
235
  import {
209
236
  generateULID
210
237
  } from "./chunk-ZJADGNYF.js";
238
+ import {
239
+ NO_HISTORY
240
+ } from "./chunk-AFHQATY4.js";
211
241
  import {
212
242
  assertCutoverTierSafe,
213
243
  assertTierWritable,
214
244
  liveRecordIsElevated
215
- } from "./chunk-DRWBEDYO.js";
245
+ } from "./chunk-JYJFGD2H.js";
216
246
  import {
217
247
  sha256Hex
218
- } from "./chunk-RM2XV574.js";
248
+ } from "./chunk-IXTSNGYY.js";
219
249
  import {
220
250
  NO_FORGET,
221
251
  addSubjectRef,
@@ -224,10 +254,10 @@ import {
224
254
  readDottedPath,
225
255
  rebuildSubjectIndex,
226
256
  removeSubjectRef
227
- } from "./chunk-KWVJAOIN.js";
257
+ } from "./chunk-OLEPKFTW.js";
228
258
  import {
229
259
  NO_SEALED_RECORD
230
- } from "./chunk-RDXW3OBQ.js";
260
+ } from "./chunk-QD46HPZG.js";
231
261
  import {
232
262
  RecordCodec,
233
263
  SEALED_CEK_NS,
@@ -238,20 +268,20 @@ import {
238
268
  queryByDet,
239
269
  resolveStableCek,
240
270
  validateSchemaInput
241
- } from "./chunk-DVUZMT2W.js";
271
+ } from "./chunk-G2JUIDFA.js";
242
272
  import {
243
273
  buildDeleteMarker,
244
274
  buildTombstone,
245
275
  isDeleteMarker,
246
276
  isTombstone
247
- } from "./chunk-WEYZTLXN.js";
277
+ } from "./chunk-W3L64Y3J.js";
248
278
  import {
249
279
  encrypt
250
- } from "./chunk-HOONYZY2.js";
280
+ } from "./chunk-AKKRXT23.js";
251
281
  import {
252
282
  NOYDB_FORMAT_VERSION,
253
283
  SealedHandle
254
- } from "./chunk-LSASLXGC.js";
284
+ } from "./chunk-QBAC3GXA.js";
255
285
  import {
256
286
  AlreadyElevatedError,
257
287
  AttestationError,
@@ -260,11 +290,12 @@ import {
260
290
  ClassifiedVerifyError,
261
291
  ConflictError,
262
292
  DebugPlaintextError,
263
- DerivationCapExceededError,
264
293
  DictKeyInUseError,
265
294
  ElevationExpiredError,
295
+ ExportCapabilityError,
266
296
  FieldNotQueryableError,
267
297
  ForgetStrategyNotConfiguredError,
298
+ ImportCapabilityError,
268
299
  IndexWriteFailureError,
269
300
  InvalidKeyError,
270
301
  KeyringCorruptError,
@@ -291,14 +322,127 @@ import {
291
322
  UnsupportedIndexOptionError,
292
323
  UnsupportedTierCompositionError,
293
324
  ValidationError
294
- } from "./chunk-W2OG6JOL.js";
325
+ } from "./chunk-QZWTRENR.js";
326
+
327
+ // src/with-commit/tx/strategy.ts
328
+ var NOT_ENABLED = new Error(
329
+ 'Multi-record transactions require the tx strategy. Import `{ withTransactions }` from "@noy-db/hub/transactions" and pass it to `createNoydb({ transactionsStrategy: withTransactions() })`.'
330
+ );
331
+ var NO_TRANSACTIONS = {
332
+ async runTransaction(_db, _fn, _options, _txInvariants) {
333
+ throw NOT_ENABLED;
334
+ },
335
+ async runDryRun() {
336
+ throw NOT_ENABLED;
337
+ }
338
+ };
339
+
340
+ // src/port/with/archive-strategy.ts
341
+ var ARCHIVE_NOT_ENABLED = "vault.archive/restore/listArchived require `archiveStrategy: withArchive({ store })` in createNoydb";
342
+ var NO_ARCHIVE = {
343
+ get store() {
344
+ throw new Error(ARCHIVE_NOT_ENABLED);
345
+ }
346
+ };
347
+
348
+ // src/port/with/strategies.ts
349
+ var STRATEGY_DEFAULTS = {
350
+ reduce: NO_REDUCE,
351
+ archive: NO_ARCHIVE,
352
+ attestation: NO_ATTESTATION,
353
+ blobs: NO_BLOBS,
354
+ broker: NO_BROKER,
355
+ cargo: NO_CARGO,
356
+ classified: NO_CLASSIFIED,
357
+ consent: NO_CONSENT,
358
+ crdt: NO_CRDT,
359
+ custody: NO_CUSTODY,
360
+ forget: NO_FORGET,
361
+ history: NO_HISTORY,
362
+ i18n: NO_I18N,
363
+ indexing: NO_INDEXING,
364
+ lazy: IMPLICIT_LAZY,
365
+ periods: NO_PERIODS,
366
+ portability: NO_PORTABILITY,
367
+ sealedRecord: NO_SEALED_RECORD,
368
+ search: NO_SEARCH,
369
+ sequence: NO_SEQUENCE,
370
+ session: NO_SESSION,
371
+ shadow: NO_SHADOW,
372
+ snapshots: NO_SNAPSHOTS,
373
+ sync: NO_SYNC,
374
+ team: NO_TEAM,
375
+ tiers: NO_TIERS,
376
+ transactions: NO_TRANSACTIONS
377
+ };
378
+ var STRATEGY_KEYS = Object.keys(STRATEGY_DEFAULTS);
379
+ function resolveStrategies(options) {
380
+ const provided = options;
381
+ const resolved = { ...STRATEGY_DEFAULTS };
382
+ for (const key of STRATEGY_KEYS) {
383
+ const value = provided[`${key}Strategy`];
384
+ if (value !== void 0) resolved[key] = value;
385
+ }
386
+ return resolved;
387
+ }
295
388
 
296
389
  // src/port/by/default-provider.ts
297
390
  async function createDefaultCoordinationProvider(store) {
298
- const { StoreCoordinationProvider } = await import("./store-coordination-provider-APODTV4W.js");
391
+ const { StoreCoordinationProvider } = await import("./store-coordination-provider-EWRZL7XF.js");
299
392
  return new StoreCoordinationProvider(store);
300
393
  }
301
394
 
395
+ // src/port/with/collection-registries.ts
396
+ function populateCollectionRegistries(r, collectionName, options, effectiveViaFields) {
397
+ if (options?.refs) {
398
+ r.refRegistry.register(collectionName, options.refs);
399
+ }
400
+ if (effectiveViaFields.i18nFields) {
401
+ r.i18nFieldRegistry.set(collectionName, effectiveViaFields.i18nFields);
402
+ }
403
+ if (options?.blobFields) {
404
+ r.blobFieldsRegistry.set(collectionName, options.blobFields);
405
+ }
406
+ if (options?.archive) {
407
+ r.archiveRegistry.set(collectionName, options.archive);
408
+ }
409
+ if (options?.attestation !== void 0) {
410
+ r.attestation.register(collectionName, options.attestation);
411
+ }
412
+ if (effectiveViaFields.dictKeyFields || effectiveViaFields.lookupFields) {
413
+ const dictFieldMap = {};
414
+ const staticFieldMap = {};
415
+ for (const [field, desc] of Object.entries(effectiveViaFields.dictKeyFields ?? {})) {
416
+ if (isStaticDictDescriptor(desc)) {
417
+ staticFieldMap[field] = desc;
418
+ r.staticDictNames.add(desc.name);
419
+ r.staticByName.set(desc.name, desc);
420
+ } else {
421
+ dictFieldMap[field] = desc.name;
422
+ }
423
+ }
424
+ const lookupCompat = collectLookupDictCompat(effectiveViaFields.lookupFields);
425
+ Object.assign(dictFieldMap, lookupCompat.dictFieldMap);
426
+ for (const [field, desc] of lookupCompat.staticEntries) {
427
+ staticFieldMap[field] = desc;
428
+ r.staticDictNames.add(desc.name);
429
+ r.staticByName.set(desc.name, desc);
430
+ }
431
+ if (Object.keys(dictFieldMap).length > 0) {
432
+ r.dictKeyFieldRegistry.set(collectionName, dictFieldMap);
433
+ for (const dictName of new Set(Object.values(dictFieldMap))) {
434
+ r.reservedLookupCollections.set(dictCollectionName(dictName), dictName);
435
+ }
436
+ }
437
+ if (Object.keys(staticFieldMap).length > 0) {
438
+ r.staticDescriptorByField.set(collectionName, staticFieldMap);
439
+ }
440
+ }
441
+ if ((options?.schemaUpdate?.length ?? 0) > 0) {
442
+ r.schemaUpdateNames.set(collectionName, (options.schemaUpdate ?? []).map((s) => s.name));
443
+ }
444
+ }
445
+
302
446
  // src/kernel/via/pipeline.ts
303
447
  var ViaPipeline = class _ViaPipeline {
304
448
  constructor(bindings, taint) {
@@ -792,7 +936,7 @@ async function reconcileIndex(ctx, field, opts = {}) {
792
936
  const persisted = ctx.persistedIndexes;
793
937
  if (!persisted) {
794
938
  throw new Error(
795
- `Collection "${ctx.name}": indexing is disabled on this Noydb instance. Pass \`withIndexing()\` from "@noy-db/hub/indexing" to \`createNoydb({ indexStrategy })\`.`
939
+ `Collection "${ctx.name}": indexing is disabled on this Noydb instance. Pass \`withIndexing()\` from "@noy-db/hub/indexing" to \`createNoydb({ indexingStrategy })\`.`
796
940
  );
797
941
  }
798
942
  if (!persisted.has(field)) {
@@ -964,61 +1108,6 @@ async function resolveTierSyncPrior(ctx, id, priorEnvelope) {
964
1108
  return await ctx.codec.decryptRecord(priorEnvelope, { skipValidation: true, id });
965
1109
  }
966
1110
 
967
- // src/with-commit/history/strategy.ts
968
- function notEnabled(op) {
969
- return new Error(
970
- `${op} requires the history strategy. Import \`{ withHistory }\` from "@noy-db/hub/history" and pass it to \`createNoydb({ historyStrategy: withHistory() })\`.`
971
- );
972
- }
973
- var NO_HISTORY = {
974
- async saveHistory() {
975
- },
976
- async getHistoryEntries() {
977
- throw notEnabled("collection.history()");
978
- },
979
- async getVersionEnvelope() {
980
- throw notEnabled("collection.getVersion()");
981
- },
982
- async pruneHistory() {
983
- return 0;
984
- },
985
- async clearHistory() {
986
- return 0;
987
- },
988
- async tombstoneHistory() {
989
- return 0;
990
- },
991
- async rewrapHistory() {
992
- },
993
- async envelopePayloadHash() {
994
- return "";
995
- },
996
- computePatch() {
997
- return [];
998
- },
999
- diff() {
1000
- throw notEnabled("collection.diff()");
1001
- },
1002
- buildLedger() {
1003
- return null;
1004
- },
1005
- buildVaultInstant() {
1006
- throw notEnabled("vault.at() / vault.timeMachine()");
1007
- }
1008
- };
1009
-
1010
- // src/with-lookup/indexing/strategy.ts
1011
- var NO_INDEXING = {
1012
- createState() {
1013
- return DISABLED_STATE;
1014
- }
1015
- };
1016
- var DISABLED_STATE = {
1017
- isEnabled: false,
1018
- getEagerIndexes: () => null,
1019
- getPersistedIndexes: () => null
1020
- };
1021
-
1022
1111
  // src/with-lookup/search/serialize.ts
1023
1112
  function serializeIndex(idx) {
1024
1113
  return JSON.stringify(idx.toSnapshot());
@@ -1621,164 +1710,6 @@ function buildDescription(input) {
1621
1710
  };
1622
1711
  }
1623
1712
 
1624
- // src/via/blob/binding.ts
1625
- async function eraseBlobs(ctx, cfg) {
1626
- if (cfg.purgeBlobsForRecord) return cfg.purgeBlobsForRecord(ctx.id);
1627
- return { shredded: 0, residue: [] };
1628
- }
1629
- function buildBlobDescribeFragment(fields) {
1630
- return {
1631
- blobFields: Object.fromEntries(
1632
- Object.entries(fields).map(([field, p]) => [field, {
1633
- ...p.retainDays !== void 0 ? { retainDays: p.retainDays } : {},
1634
- ...p.evictWhen !== void 0 ? { evictWhen: true } : {},
1635
- ...p.legalHold !== void 0 ? { legalHold: true } : {},
1636
- ...p.retainUntil !== void 0 ? { retainUntil: true } : {},
1637
- ...p.external === true ? { external: true } : {},
1638
- ...p.public === true ? { public: true } : {},
1639
- ...p.backlink !== void 0 ? { backlink: p.backlink } : {}
1640
- }])
1641
- )
1642
- };
1643
- }
1644
- function blobBinding(cfg) {
1645
- return {
1646
- brand: "blob",
1647
- // encryptedAtRest: 'envelope' — blob chunks are AEAD-encrypted envelopes
1648
- // in `_blob_chunks` (service-side), not sealed record fields; queryable:
1649
- // 'none' — nothing indexes blob content; exportable — vault.exportBlobs()
1650
- // is a first-class door; forgettable — shredAllForRecord participates in
1651
- // vault.forget().
1652
- posture: { encryptedAtRest: "envelope", queryable: "none", exportable: true, forgettable: true },
1653
- covers: (field) => field in cfg.fields,
1654
- erase: (ctx) => eraseBlobs(ctx, cfg),
1655
- describeFragment: () => buildBlobDescribeFragment(cfg.fields)
1656
- };
1657
- }
1658
- function linkBlobVia() {
1659
- installViaBinder("blob", (c) => blobBinding(c));
1660
- }
1661
-
1662
- // src/port/with/blob-strategy.ts
1663
- linkBlobVia();
1664
- var NO_BLOBS = {
1665
- openSlot() {
1666
- throw new Error(
1667
- 'Blob storage is not enabled on this Noydb instance. Import `{ withBlobs }` from "@noy-db/hub/blobs" and pass `withBlobs()` to `createNoydb({ blobStrategy: withBlobs() })`.'
1668
- );
1669
- }
1670
- };
1671
-
1672
- // src/with-formula/derivations/stale.ts
1673
- var _staleByRegistry = /* @__PURE__ */ new WeakMap();
1674
- var keyFor = (source, sourceId) => `${source}/${sourceId}`;
1675
- async function markStale(registry, strategy, sourceId) {
1676
- let map = _staleByRegistry.get(registry);
1677
- if (!map) {
1678
- map = /* @__PURE__ */ new Map();
1679
- _staleByRegistry.set(registry, map);
1680
- }
1681
- const k = keyFor(strategy.source, sourceId);
1682
- let set = map.get(k);
1683
- if (!set) {
1684
- set = /* @__PURE__ */ new Set();
1685
- map.set(k, set);
1686
- }
1687
- set.add(strategy);
1688
- }
1689
- async function resolveStaleOnRead(accessor, outputCollection, id) {
1690
- const registry = accessor.registry();
1691
- const producers = registry.strategiesProducingOutput(outputCollection);
1692
- if (producers.length === 0) return;
1693
- const map = _staleByRegistry.get(registry);
1694
- if (!map) return;
1695
- let DerivationExecutor = null;
1696
- for (const { spec, strategyHash } of producers) {
1697
- const k = keyFor(spec.source, id);
1698
- const pending = map.get(k);
1699
- if (!pending || !pending.has(spec)) continue;
1700
- const sourceColl = accessor.getCollection(spec.source);
1701
- const source = await sourceColl.get(id);
1702
- if (!source) {
1703
- pending.delete(spec);
1704
- continue;
1705
- }
1706
- const sourceWithId = { ...source, id };
1707
- if (DerivationExecutor === null) {
1708
- ({ DerivationExecutor } = await import("./executor-XGIS6CR7.js"));
1709
- }
1710
- const ctx = { vault: accessor.getReadOnlyFacade() };
1711
- const result = await DerivationExecutor.run(spec, sourceWithId, 0, strategyHash, ctx);
1712
- for (const key of Object.keys(spec.outputs)) {
1713
- const out = result.outputs[key];
1714
- if (!out) continue;
1715
- if (out.kind === "failed") {
1716
- const err = out.error;
1717
- if (spec.strict) {
1718
- throw err;
1719
- }
1720
- console.warn(
1721
- `[derivation] lazy output "${key}" for source "${spec.source}" id="${id}" failed:`,
1722
- err
1723
- );
1724
- continue;
1725
- }
1726
- if (out.kind === "array") {
1727
- console.warn(
1728
- `[derivation] unexpected array-shape output "${key}" in lazy resolve path; array-shape derivations require lifecycle: "eager".`
1729
- );
1730
- continue;
1731
- }
1732
- const outSpec = spec.outputs[key];
1733
- if (!outSpec) continue;
1734
- const outputColl = accessor.getCollection(outSpec.collection);
1735
- if (out.skipped === true) {
1736
- await outputColl._internalDelete(id, accessor.getActiveTxContext());
1737
- continue;
1738
- }
1739
- await outputColl.put(id, out.value);
1740
- }
1741
- pending.delete(spec);
1742
- }
1743
- }
1744
-
1745
- // src/with-commit/crdt/strategy.ts
1746
- var NOT_ENABLED = new Error(
1747
- 'CRDT mode requires the CRDT strategy. Import `{ withCrdt }` from "@noy-db/hub/crdt" and pass it to `createNoydb({ crdtStrategy: withCrdt() })`.'
1748
- );
1749
- var NO_CRDT = {
1750
- buildLwwMapState() {
1751
- throw NOT_ENABLED;
1752
- },
1753
- buildRgaState() {
1754
- throw NOT_ENABLED;
1755
- },
1756
- mergeCrdtStates() {
1757
- throw NOT_ENABLED;
1758
- },
1759
- resolveCrdtSnapshot() {
1760
- throw NOT_ENABLED;
1761
- }
1762
- };
1763
-
1764
- // src/with-party/team/sync-strategy.ts
1765
- function notEnabled2(op) {
1766
- return new Error(
1767
- `${op} requires the sync strategy. Import \`{ withSync }\` from "@noy-db/hub/sync" and pass it to \`createNoydb({ syncStrategy: withSync() })\`.`
1768
- );
1769
- }
1770
- var NO_SYNC = {
1771
- buildSyncEngine() {
1772
- throw notEnabled2("SyncEngine");
1773
- },
1774
- buildSyncTransaction() {
1775
- throw notEnabled2("SyncTransaction");
1776
- },
1777
- buildPresence() {
1778
- throw notEnabled2("collection.presence()");
1779
- }
1780
- };
1781
-
1782
1713
  // src/kernel/via/compose.ts
1783
1714
  function via(...descriptors) {
1784
1715
  if (descriptors.length === 0) {
@@ -1942,7 +1873,7 @@ function compileViaBindings(opts, classifiedGuardCtx, eraseCfgOut) {
1942
1873
  ...i18nFields !== void 0 ? { i18nFields } : {},
1943
1874
  ...dictKeyFields !== void 0 ? { dictKeyFields } : {},
1944
1875
  ...i18nDensifyFields !== void 0 ? { i18nDensifyFields } : {},
1945
- strategy: opts.i18nStrategy ?? NO_I18N,
1876
+ strategy: opts.strategies.i18n,
1946
1877
  ...opts.defaultLocale !== void 0 ? { defaultLocale: opts.defaultLocale } : {},
1947
1878
  ...opts.autoTranslateHook !== void 0 ? { autoTranslateHook: opts.autoTranslateHook } : {},
1948
1879
  ...opts.dictLabelResolver !== void 0 ? { dictLabelResolver: opts.dictLabelResolver } : {},
@@ -2056,6 +1987,11 @@ function resolveCollectionConfig(opts) {
2056
1987
  `Collection "${opts.name}": embeddings are not supported on CRDT collections (L2). Use a non-CRDT collection for semantic search.`
2057
1988
  );
2058
1989
  }
1990
+ if (opts.sensitive && opts.sensitive.length > 0 && opts.crdt) {
1991
+ throw new Error(
1992
+ `Collection "${opts.name}": sensitive (structural group-encryption) is not supported on CRDT collections \u2014 the CRDT write path bypasses per-field sealing, so the fields would be stored in the ordinary encrypted body with no \`_sealed\` slot and no per-field key. Use a non-CRDT collection for sealed fields.`
1993
+ );
1994
+ }
2059
1995
  if (opts.tiers && opts.tiers.length > 0 && opts.blobFields !== void 0 && Object.keys(opts.blobFields).length > 0 && opts.perRecordKeys !== true) {
2060
1996
  throw new UnsupportedTierCompositionError(
2061
1997
  "blobs",
@@ -2172,14 +2108,9 @@ function resolveCollectionConfig(opts) {
2172
2108
  writeHooks: opts.writeHooks,
2173
2109
  subsystemBus: opts.subsystemBus,
2174
2110
  activeTxId: opts.activeTxId,
2175
- blobStrategy: opts.blobStrategy ?? NO_BLOBS,
2111
+ strategies: opts.strategies,
2176
2112
  objectStore: opts.objectStore,
2177
2113
  blobFields: opts.blobFields,
2178
- aggregateStrategy: opts.aggregateStrategy ?? NO_AGGREGATE,
2179
- crdtStrategy: opts.crdtStrategy ?? NO_CRDT,
2180
- historyStrategy: opts.historyStrategy ?? NO_HISTORY,
2181
- i18nStrategy: opts.i18nStrategy ?? NO_I18N,
2182
- syncStrategy: opts.syncStrategy ?? NO_SYNC,
2183
2114
  reconcileOnOpen: opts.reconcileOnOpen ?? "off",
2184
2115
  getDEK: opts.getDEK,
2185
2116
  onDirty: opts.onDirty,
@@ -2208,7 +2139,6 @@ function resolveCollectionConfig(opts) {
2208
2139
  moneyFields: effectiveViaFields.moneyFields,
2209
2140
  classified: resolvedClassified,
2210
2141
  classifiedGuardCtx,
2211
- classifiedStrategy: opts.classifiedStrategy ?? NO_CLASSIFIED,
2212
2142
  computed: mergedComputed,
2213
2143
  computedEdges,
2214
2144
  viaDepsEdges,
@@ -2230,8 +2160,6 @@ function resolveCollectionConfig(opts) {
2230
2160
  materializedViewSource: opts.materializedViewSource,
2231
2161
  graphDispatch: opts.graphDispatch,
2232
2162
  tiers: opts.tiers && opts.tiers.length > 0 ? new Set(opts.tiers) : null,
2233
- tiersStrategy: opts.tiersStrategy ?? NO_TIERS,
2234
- searchStrategy: opts.searchStrategy ?? NO_SEARCH,
2235
2163
  tierMode: opts.tierMode ?? "invisibility",
2236
2164
  blobTierPolicy: opts.blobTierPolicy ?? "isolate",
2237
2165
  onCrossTierAccess: opts.onCrossTierAccess,
@@ -2246,22 +2174,12 @@ function resolveCollectionConfig(opts) {
2246
2174
  }
2247
2175
 
2248
2176
  // src/with-formula/computed/lazy.ts
2249
- var fn = null;
2177
+ var loadComputed = lazy(() => import("./computed-AB45PS4V.js"));
2250
2178
  async function loadEvalComputedFields() {
2251
- fn ??= (await import("./computed-DSMPXG2Y.js")).evalComputedFields;
2252
- return fn;
2179
+ return (await loadComputed()).evalComputedFields;
2253
2180
  }
2254
2181
 
2255
2182
  // src/kernel/collection.ts
2256
- function selfWriteFieldEqual(a, b) {
2257
- if (a === b) return true;
2258
- if (a === null || b === null || typeof a !== "object" || typeof b !== "object") return false;
2259
- try {
2260
- return JSON.stringify(a) === JSON.stringify(b);
2261
- } catch {
2262
- return false;
2263
- }
2264
- }
2265
2183
  var fallbackWarned = /* @__PURE__ */ new Set();
2266
2184
  function warnOnceFallback(adapterName) {
2267
2185
  if (fallbackWarned.has(adapterName)) return;
@@ -2293,25 +2211,20 @@ var Collection = class {
2293
2211
  /** True when the caller explicitly provided a `historyConfig` option (vs. inheriting the vault default). */
2294
2212
  historyConfigExplicit;
2295
2213
  /**
2296
- * tree-shake seam — the strategy that backs `collection.blob(id)`.
2297
- * Defaults to `NO_BLOBS`, a ~10-line stub that throws with an actionable
2298
- * message. Consumers opt into real blob storage by importing
2299
- * `{ blobs }` from `@noy-db/hub/blobs` and passing the returned
2300
- * strategy to `createNoydb({ blobStrategy: blobs() })`. With the
2301
- * default stub, none of the BlobSet / chunk / MIME-magic machinery
2302
- * reaches the bundle.
2214
+ * Every opt-in service, resolved once by `createNoydb` (#838) and shared by
2215
+ * reference with the owning `Vault` and `Noydb`.
2216
+ *
2217
+ * Each entry is a tree-shake seam. An un-opted-in service resolves to its
2218
+ * `NO_*` stub — a tiny module that throws with an actionable message —
2219
+ * so, for example, none of the BlobSet / chunk / MIME-magic machinery
2220
+ * reaches the bundle unless the consumer imports `@noy-db/hub/blobs` and
2221
+ * passes `blobsStrategy: blobs()` to `createNoydb`.
2303
2222
  */
2304
- blobStrategy;
2223
+ strategies;
2305
2224
  objectStore;
2306
2225
  blobFields;
2307
2226
  blobTierPolicy;
2308
2227
  // #724 T2/T3
2309
- aggregateStrategy;
2310
- crdtStrategy;
2311
- tiersStrategy;
2312
- searchStrategy;
2313
- historyStrategy;
2314
- syncStrategy;
2315
2228
  // In-memory cache of decrypted records (eager mode only). Lazy mode
2316
2229
  // uses `lru` instead. Both fields exist so a single Collection instance
2317
2230
  // doesn't need a runtime branch on every cache access.
@@ -2347,7 +2260,7 @@ var Collection = class {
2347
2260
  lru;
2348
2261
  /**
2349
2262
  * tree-shake seam — per-Collection indexing state. Owned by the
2350
- * `IndexStrategy` passed through from `createNoydb({ indexStrategy })`.
2263
+ * `IndexingStrategy` passed through from `createNoydb({ indexingStrategy })`.
2351
2264
  * Defaults to a disabled state (both accessors return null) so the
2352
2265
  * `CollectionIndexes` / `PersistedCollectionIndex` / `LazyQuery`
2353
2266
  * classes never reach the bundle when indexing is unused.
@@ -2481,12 +2394,6 @@ var Collection = class {
2481
2394
  /** C-A/R10 memoization: marker declared-set lookup (undefined=unresolved) + classified-handle persist-once flag. */
2482
2395
  _markerDigestOnlyCache = void 0;
2483
2396
  _markerPersisted = false;
2484
- /**
2485
- * Tree-shake seam for `reveal()` — defaults to `NO_CLASSIFIED`, which
2486
- * throws `ClassifiedNotEnabledError`. Set via the `classifiedStrategy`
2487
- * `createNoydb()` option (opt in with `withClassified()`).
2488
- */
2489
- classifiedStrategy;
2490
2397
  /** Async callback provided by the Vault to open a dynamic dictionary handle (for label-map pre-computation in the search index). Only used in `resolveDictLabelMaps()`; static dicts bypass this entirely. Mutable, assign-once — see {@link _reconcileReadState} (#671 item 1). */
2491
2398
  getDictionary;
2492
2399
  /**
@@ -2635,16 +2542,10 @@ var Collection = class {
2635
2542
  this.writeHooks = cfg.writeHooks;
2636
2543
  this.subsystemBus = cfg.subsystemBus;
2637
2544
  this.activeTxId = cfg.activeTxId;
2638
- this.blobStrategy = cfg.blobStrategy;
2545
+ this.strategies = cfg.strategies;
2639
2546
  this.objectStore = cfg.objectStore;
2640
2547
  this.blobFields = cfg.blobFields;
2641
2548
  this.blobTierPolicy = cfg.blobTierPolicy ?? "isolate";
2642
- this.aggregateStrategy = cfg.aggregateStrategy;
2643
- this.crdtStrategy = cfg.crdtStrategy;
2644
- this.tiersStrategy = cfg.tiersStrategy;
2645
- this.searchStrategy = cfg.searchStrategy;
2646
- this.historyStrategy = cfg.historyStrategy;
2647
- this.syncStrategy = cfg.syncStrategy;
2648
2549
  this.reconcileOnOpen = cfg.reconcileOnOpen;
2649
2550
  this.getDEK = cfg.getDEK;
2650
2551
  this.onDirty = cfg.onDirty;
@@ -2671,7 +2572,6 @@ var Collection = class {
2671
2572
  this.classified = cfg.classified;
2672
2573
  this.classifiedGuardCtx = cfg.classifiedGuardCtx;
2673
2574
  this.vdigFields = cfg.vdigFields;
2674
- this.classifiedStrategy = cfg.classifiedStrategy;
2675
2575
  this.computed = cfg.computed;
2676
2576
  this.getDictionary = cfg.getDictionary;
2677
2577
  this.defaultLocale = cfg.defaultLocale;
@@ -2719,7 +2619,7 @@ var Collection = class {
2719
2619
  deterministicFields: this.deterministicFields,
2720
2620
  vdigFields: this.vdigFields,
2721
2621
  crdtMode: this.crdtMode,
2722
- crdtStrategy: this.crdtStrategy,
2622
+ crdtStrategy: this.strategies.crdt,
2723
2623
  schema: this.schema,
2724
2624
  getDEK: (collection) => this.getDEK(collection ?? this.name),
2725
2625
  cekCache: this.cekCache,
@@ -2737,7 +2637,7 @@ var Collection = class {
2737
2637
  const remoteJson = await this.codec.decryptJsonString(remote, id);
2738
2638
  if (localJson === null) return local;
2739
2639
  if (remoteJson === null) return remote;
2740
- const merged = this.crdtStrategy.mergeCrdtStates(JSON.parse(localJson), JSON.parse(remoteJson));
2640
+ const merged = this.strategies.crdt.mergeCrdtStates(JSON.parse(localJson), JSON.parse(remoteJson));
2741
2641
  const mergedVersion = Math.max(local._v, remote._v) + 1;
2742
2642
  const cek = this.perRecordCek ? await this.resolveRecordCek(id) : void 0;
2743
2643
  return this.codec.encryptJsonString(JSON.stringify(merged), mergedVersion, cek);
@@ -2795,12 +2695,12 @@ var Collection = class {
2795
2695
  }
2796
2696
  this.lazy = opts.prefetch === false;
2797
2697
  if (this.lazy) {
2798
- this.lru = (opts.lazyStrategy ?? IMPLICIT_LAZY).createCache(this.name, opts.cache);
2698
+ this.lru = opts.strategies.lazy.createCache(this.name, opts.cache);
2799
2699
  this.hydrated = true;
2800
2700
  } else {
2801
2701
  this.lru = null;
2802
2702
  }
2803
- const strategy = opts.indexStrategy ?? NO_INDEXING;
2703
+ const strategy = opts.strategies.indexing;
2804
2704
  this.indexState = strategy.createState({
2805
2705
  defs: opts.indexes ?? [],
2806
2706
  lazy: this.lazy
@@ -2955,7 +2855,7 @@ var Collection = class {
2955
2855
  if (spec.storage === "digest-only") {
2956
2856
  throw new ClassifiedRevealError(this.name, field, `storage:'digest-only' \u2014 verify-only; nothing recoverable to reveal`);
2957
2857
  }
2958
- return this.classifiedStrategy.reveal({
2858
+ return this.strategies.classified.reveal({
2959
2859
  collection: this.name,
2960
2860
  spec,
2961
2861
  encrypted: this.storeCiphertext,
@@ -2975,7 +2875,7 @@ var Collection = class {
2975
2875
  throw new ClassifiedVerifyError(this.name, field, `storage:'never' \u2014 nothing is stored to verify against`);
2976
2876
  }
2977
2877
  const ctx = this._classifiedVerifyCtx(spec);
2978
- return spec.storage === "digest-only" ? this.classifiedStrategy.verify(ctx, id, field, candidate) : this.classifiedStrategy.verifyText(ctx, id, field, candidate);
2878
+ return spec.storage === "digest-only" ? this.strategies.classified.verify(ctx, id, field, candidate) : this.strategies.classified.verifyText(ctx, id, field, candidate);
2979
2879
  }
2980
2880
  /** k-of-n challenge over the collection's secretAnswer members. Requires withClassified(). */
2981
2881
  async verifyGroup(id, answers, opts) {
@@ -2984,7 +2884,7 @@ var Collection = class {
2984
2884
  throw new ClassifiedVerifyError(this.name, "*", "no groupable digest-only (secretAnswer) fields declared");
2985
2885
  }
2986
2886
  const ctx = { ...this._classifiedVerifyCtx(members[0].spec), groupMembers: members };
2987
- return this.classifiedStrategy.matchGroup(ctx, id, answers, opts);
2887
+ return this.strategies.classified.matchGroup(ctx, id, answers, opts);
2988
2888
  }
2989
2889
  _classifiedVerifyCtx(spec) {
2990
2890
  return {
@@ -3039,7 +2939,7 @@ var Collection = class {
3039
2939
  if (typeof candidate !== "string") {
3040
2940
  throw new ClassifiedVerifyError(this.name, "*", "candidate must be a string");
3041
2941
  }
3042
- const target = await this.classifiedStrategy.computeTarget(this._classifiedVerifyCtx(spec), field, candidate);
2942
+ const target = await this.strategies.classified.computeTarget(this._classifiedVerifyCtx(spec), field, candidate);
3043
2943
  const ids = await this.adapter.list(this.vault, this.name);
3044
2944
  const hits = [];
3045
2945
  const hitMap = /* @__PURE__ */ new Map();
@@ -3052,7 +2952,7 @@ var Collection = class {
3052
2952
  }
3053
2953
  await this.onAccess?.("find", "*");
3054
2954
  if (hits.length === 0) return [];
3055
- const { verifyDigestField } = await import("./verify-26Y5GNMK.js");
2955
+ const { verifyDigestField } = await import("./verify-7XWHJWUN.js");
3056
2956
  const policy = {
3057
2957
  normalize: spec.verifyNormalize ?? "password",
3058
2958
  notLastN: spec.notLastN ?? 0,
@@ -3126,7 +3026,7 @@ var Collection = class {
3126
3026
  id,
3127
3027
  version: scrubbed._v,
3128
3028
  actor: this.keyring.userId,
3129
- payloadHash: await this.historyStrategy.envelopePayloadHash(scrubbed),
3029
+ payloadHash: await this.strategies.history.envelopePayloadHash(scrubbed),
3130
3030
  reason: "classified:scrub-equatable-tags"
3131
3031
  });
3132
3032
  }
@@ -3258,7 +3158,7 @@ var Collection = class {
3258
3158
  }
3259
3159
  }
3260
3160
  if (this.materializedViewSource !== void 0) {
3261
- const { resolveStaleMVOnRead } = await import("./stale-FJED42DM.js");
3161
+ const { resolveStaleMVOnRead } = await import("./stale-A4J26OIC.js");
3262
3162
  await resolveStaleMVOnRead(this.materializedViewSource, this.name, this.#dispatchCtx({ collection: this.name, id: "resolve-on-read" }));
3263
3163
  }
3264
3164
  let record;
@@ -3352,7 +3252,7 @@ var Collection = class {
3352
3252
  if (this.syncAdapter !== void 0) presenceOpts.syncAdapter = this.syncAdapter;
3353
3253
  if (opts?.staleMs !== void 0) presenceOpts.staleMs = opts.staleMs;
3354
3254
  if (opts?.pollIntervalMs !== void 0) presenceOpts.pollIntervalMs = opts.pollIntervalMs;
3355
- return this.syncStrategy.buildPresence(presenceOpts);
3255
+ return this.strategies.sync.buildPresence(presenceOpts);
3356
3256
  }
3357
3257
  /**
3358
3258
  * Create or update a record. Runs inside the hub's write-queue tracker
@@ -3514,6 +3414,103 @@ var Collection = class {
3514
3414
  return clone;
3515
3415
  }
3516
3416
  /** @internal Untracked put body — call {@link put}, not this. */
3417
+ /**
3418
+ * Decode a prior envelope's CRDT state, or `undefined` when there is no
3419
+ * usable prior: no envelope, a shredded body decrypting to `null`, or a
3420
+ * payload that is not a CRDT state. The `lww-map` and `rga` branches each
3421
+ * carried a copy, byte-identical apart from the cast (#842).
3422
+ */
3423
+ async #decodePriorCrdtState(envelope) {
3424
+ if (!envelope) return void 0;
3425
+ const prevJson = await this.codec.decryptJsonString(envelope);
3426
+ if (prevJson === null) return void 0;
3427
+ const prevParsed = JSON.parse(prevJson);
3428
+ if (prevParsed === null || typeof prevParsed !== "object" || !("_crdt" in prevParsed)) {
3429
+ return void 0;
3430
+ }
3431
+ return prevParsed;
3432
+ }
3433
+ /**
3434
+ * Record a write on the active transaction so a mid-batch failure rolls it
3435
+ * back. Four sites in the derivation/MV dispatch hand-built this literal (#842).
3436
+ */
3437
+ #trackPut(txCtx, collectionName, id, priorEnvelope) {
3438
+ txCtx._executed.push({
3439
+ op: { type: "put", vaultName: this.vault, collectionName, id },
3440
+ priorEnvelope
3441
+ });
3442
+ }
3443
+ /**
3444
+ * Snapshot the PRIOR version into history, emit, and prune.
3445
+ *
3446
+ * Deliberately does NOT carry `source` from the current write — a history
3447
+ * entry describes the version being replaced, not the one replacing it.
3448
+ *
3449
+ * Kept OUT of {@link #commitWriteTail} because the two paths call it at
3450
+ * different points: the normal path snapshots BEFORE `adapter.put` (so a
3451
+ * history failure leaves no write behind), while the CRDT path must merge
3452
+ * and persist first to resolve the prior record at all. Folding it into the
3453
+ * tail would silently reorder one of them (#842).
3454
+ */
3455
+ async #savePriorHistory(id, prior, cek, vdigCtx) {
3456
+ if (this.historyConfig.enabled === false) return;
3457
+ await this.strategies.history.saveHistory(
3458
+ this.adapter,
3459
+ this.vault,
3460
+ this.name,
3461
+ id,
3462
+ await this.codec.encryptRecord(prior.record, prior.version, cek, void 0, void 0, vdigCtx, id)
3463
+ );
3464
+ this.emitter.emit("history:save", { vault: this.vault, collection: this.name, id, version: prior.version });
3465
+ if (this.historyConfig.maxVersions) {
3466
+ await this.strategies.history.pruneHistory(this.adapter, this.vault, this.name, id, { keepVersions: this.historyConfig.maxVersions });
3467
+ }
3468
+ }
3469
+ /**
3470
+ * Everything both write paths do once the envelope is on the adapter:
3471
+ * classified marker, embedding sidecar, ledger append, cache/index
3472
+ * maintenance, and the mutation event that drives derivation dispatch.
3473
+ *
3474
+ * The CRDT branch used to re-implement all of it, and in doing so skipped
3475
+ * `_ensureClassifiedMarker`, the unique-constraint upsert and
3476
+ * `_toCacheableRecord` (#835). All three were unreachable — each blocked by
3477
+ * a config-time refusal on CRDT collections — but only by accident of what
3478
+ * that copy happened to omit. One tail makes the divergence unrepresentable
3479
+ * rather than merely unreachable; on a CRDT collection the extra steps are
3480
+ * provably no-ops (classified/unique + crdt are refused at construction, and
3481
+ * a CRDT body never produces a `_sealed` slot, so `_toCacheableRecord` is
3482
+ * the identity).
3483
+ */
3484
+ async #commitWriteTail(args) {
3485
+ const { id, envelope, version, indexed, event, prior, reason } = args;
3486
+ await this._ensureClassifiedMarker();
3487
+ if (this.embeddings) {
3488
+ await this.strategies.search.embedOnWrite(this.searchContext(), id, indexed, version);
3489
+ }
3490
+ if (this.ledger) {
3491
+ const appendInput = {
3492
+ op: "put",
3493
+ collection: this.name,
3494
+ id,
3495
+ version,
3496
+ actor: this.keyring.userId,
3497
+ payloadHash: await this.strategies.history.envelopePayloadHash(envelope)
3498
+ };
3499
+ if (prior) appendInput.delta = this.strategies.history.computePatch(indexed, prior.record);
3500
+ if (reason !== void 0) appendInput.reason = reason;
3501
+ await this.ledger.append(appendInput);
3502
+ }
3503
+ const cacheable = await this._toCacheableRecord(indexed, envelope, id);
3504
+ if (this.lazy && this.lru) {
3505
+ this.lru.set(id, { record: cacheable, version }, estimateRecordBytes(indexed));
3506
+ await this.maintainPersistedIndexesOnPut(id, indexed, prior ? prior.record : null, version);
3507
+ } else {
3508
+ this.cache.set(id, { record: cacheable, version });
3509
+ this.indexes?.upsert(id, indexed, prior ? prior.record : null);
3510
+ this.uniqueConstraints?.upsert(id, indexed, prior?.record);
3511
+ }
3512
+ await this._onRecordMutated(id, "put", "local-write", { record: event, version });
3513
+ }
3517
3514
  async _putInternal(id, record, options) {
3518
3515
  if (!hasWritePermission(this.keyring, this.name)) {
3519
3516
  throw new ReadOnlyError();
@@ -3562,29 +3559,11 @@ var Collection = class {
3562
3559
  const now = (/* @__PURE__ */ new Date()).toISOString();
3563
3560
  let crdtState;
3564
3561
  if (this.crdtMode === "lww-map") {
3565
- let existingState;
3566
- if (existingEnvelope) {
3567
- const prevJson = await this.codec.decryptJsonString(existingEnvelope);
3568
- if (prevJson !== null) {
3569
- const prevParsed = JSON.parse(prevJson);
3570
- if (prevParsed !== null && typeof prevParsed === "object" && "_crdt" in prevParsed) {
3571
- existingState = prevParsed;
3572
- }
3573
- }
3574
- }
3575
- crdtState = this.crdtStrategy.buildLwwMapState(record, existingState, now);
3562
+ const existingState = await this.#decodePriorCrdtState(existingEnvelope);
3563
+ crdtState = this.strategies.crdt.buildLwwMapState(record, existingState, now);
3576
3564
  } else if (this.crdtMode === "rga") {
3577
- let existingState;
3578
- if (existingEnvelope) {
3579
- const prevJson = await this.codec.decryptJsonString(existingEnvelope);
3580
- if (prevJson !== null) {
3581
- const prevParsed = JSON.parse(prevJson);
3582
- if (prevParsed !== null && typeof prevParsed === "object" && "_crdt" in prevParsed) {
3583
- existingState = prevParsed;
3584
- }
3585
- }
3586
- }
3587
- crdtState = this.crdtStrategy.buildRgaState(Array.isArray(record) ? record : [record], existingState, generateULID);
3565
+ const existingState = await this.#decodePriorCrdtState(existingEnvelope);
3566
+ crdtState = this.strategies.crdt.buildRgaState(Array.isArray(record) ? record : [record], existingState, generateULID);
3588
3567
  } else {
3589
3568
  crdtState = { _crdt: "yjs", update: record };
3590
3569
  }
@@ -3592,42 +3571,21 @@ var Collection = class {
3592
3571
  const cek2 = this.perRecordCek ? await this.resolveRecordCek(id) : void 0;
3593
3572
  const envelope2 = await this.codec.encryptJsonString(JSON.stringify(crdtState), version2, cek2, options?.source, options?.sourceTs);
3594
3573
  await this.adapter.put(this.vault, this.name, id, envelope2);
3595
- const resolvedRecord = this.crdtStrategy.resolveCrdtSnapshot(crdtState);
3574
+ const resolvedRecord = this.strategies.crdt.resolveCrdtSnapshot(crdtState);
3596
3575
  const existingResolvedRecord = existingEnvelope ? await this.codec.decryptRecord(existingEnvelope, { skipValidation: true }) : null;
3597
3576
  const existingResolved = existingResolvedRecord !== null ? { record: existingResolvedRecord, version: existingVersion } : void 0;
3598
- if (existingResolved && this.historyConfig.enabled !== false) {
3599
- await this.historyStrategy.saveHistory(this.adapter, this.vault, this.name, id, await this.codec.encryptRecord(existingResolved.record, existingResolved.version, cek2, void 0, void 0, this.vdigFields !== null ? { id, prev: existingEnvelope } : void 0, id));
3600
- this.emitter.emit("history:save", { vault: this.vault, collection: this.name, id, version: existingResolved.version });
3601
- if (this.historyConfig.maxVersions) {
3602
- await this.historyStrategy.pruneHistory(this.adapter, this.vault, this.name, id, { keepVersions: this.historyConfig.maxVersions });
3603
- }
3577
+ if (existingResolved) {
3578
+ await this.#savePriorHistory(id, existingResolved, cek2, this.vdigFields !== null ? { id, prev: existingEnvelope } : void 0);
3604
3579
  }
3605
- if (this.ledger) {
3606
- const appendInput = {
3607
- op: "put",
3608
- collection: this.name,
3609
- id,
3610
- version: version2,
3611
- actor: this.keyring.userId,
3612
- payloadHash: await this.historyStrategy.envelopePayloadHash(envelope2)
3613
- };
3614
- if (existingResolved) appendInput.delta = this.historyStrategy.computePatch(resolvedRecord, existingResolved.record);
3615
- if (options?.reason !== void 0) appendInput.reason = options.reason;
3616
- await this.ledger.append(appendInput);
3617
- }
3618
- if (this.lazy && this.lru) {
3619
- this.lru.set(id, { record: resolvedRecord, version: version2 }, estimateRecordBytes(resolvedRecord));
3620
- await this.maintainPersistedIndexesOnPut(
3621
- id,
3622
- resolvedRecord,
3623
- existingResolved ? existingResolved.record : null,
3624
- version2
3625
- );
3626
- } else {
3627
- this.cache.set(id, { record: resolvedRecord, version: version2 });
3628
- this.indexes?.upsert(id, resolvedRecord, existingResolved ? existingResolved.record : null);
3629
- }
3630
- await this._onRecordMutated(id, "put", "local-write", { record, version: version2 });
3580
+ await this.#commitWriteTail({
3581
+ id,
3582
+ envelope: envelope2,
3583
+ version: version2,
3584
+ indexed: resolvedRecord,
3585
+ event: record,
3586
+ prior: existingResolved,
3587
+ reason: options?.reason
3588
+ });
3631
3589
  return;
3632
3590
  }
3633
3591
  let existing;
@@ -3657,47 +3615,19 @@ var Collection = class {
3657
3615
  this.uniqueConstraints?.check(id, record);
3658
3616
  const cek = this.perRecordCek ? await this.resolveRecordCek(id) : void 0;
3659
3617
  const vdigCtx = this.vdigFields !== null ? { id, prev: await this.adapter.get(this.vault, this.name, id) } : void 0;
3660
- if (existing && this.historyConfig.enabled !== false) {
3661
- await this.historyStrategy.saveHistory(this.adapter, this.vault, this.name, id, await this.codec.encryptRecord(existing.record, existing.version, cek, void 0, void 0, vdigCtx, id));
3662
- this.emitter.emit("history:save", {
3663
- vault: this.vault,
3664
- collection: this.name,
3665
- id,
3666
- version: existing.version
3667
- });
3668
- if (this.historyConfig.maxVersions) await this.historyStrategy.pruneHistory(this.adapter, this.vault, this.name, id, { keepVersions: this.historyConfig.maxVersions });
3669
- }
3618
+ if (existing) await this.#savePriorHistory(id, existing, cek, vdigCtx);
3670
3619
  const envelope = await this.codec.encryptRecord(record, version, cek, options?.source, options?.sourceTs, vdigCtx, id);
3671
3620
  await this.adapter.put(this.vault, this.name, id, envelope);
3672
3621
  this.markerIds.delete(id);
3673
- await this._ensureClassifiedMarker();
3674
- if (this.embeddings) {
3675
- await this.searchStrategy.embedOnWrite(this.searchContext(), id, record, version);
3676
- }
3677
- if (this.ledger) {
3678
- const appendInput = {
3679
- op: "put",
3680
- collection: this.name,
3681
- id,
3682
- version,
3683
- actor: this.keyring.userId,
3684
- payloadHash: await this.historyStrategy.envelopePayloadHash(envelope)
3685
- };
3686
- if (existing) {
3687
- appendInput.delta = this.historyStrategy.computePatch(record, existing.record);
3688
- }
3689
- if (options?.reason !== void 0) appendInput.reason = options.reason;
3690
- await this.ledger.append(appendInput);
3691
- }
3692
- if (this.lazy && this.lru) {
3693
- this.lru.set(id, { record: await this._toCacheableRecord(record, envelope, id), version }, estimateRecordBytes(record));
3694
- await this.maintainPersistedIndexesOnPut(id, record, existing ? existing.record : null, version);
3695
- } else {
3696
- this.cache.set(id, { record: await this._toCacheableRecord(record, envelope, id), version });
3697
- this.indexes?.upsert(id, record, existing ? existing.record : null);
3698
- this.uniqueConstraints?.upsert(id, record, existing?.record);
3699
- }
3700
- await this._onRecordMutated(id, "put", "local-write", { record, version });
3622
+ await this.#commitWriteTail({
3623
+ id,
3624
+ envelope,
3625
+ version,
3626
+ indexed: record,
3627
+ event: record,
3628
+ prior: existing,
3629
+ reason: options?.reason
3630
+ });
3701
3631
  }
3702
3632
  /**
3703
3633
  * Fire registered MV strategies whose dependency set includes this
@@ -3714,34 +3644,8 @@ var Collection = class {
3714
3644
  */
3715
3645
  async dispatchMaterializedViews(id, record, wave) {
3716
3646
  if (this.materializedViewSource === void 0) return;
3717
- const incoming = record;
3718
- if (incoming && typeof incoming === "object" && "_materializedFrom" in incoming) return;
3719
- const registry = this.materializedViewSource.registry();
3720
- const mvs = registry.mvsForSource(this.name);
3721
- if (mvs.length === 0) return;
3722
- let executor = null;
3723
- let staleHelpers = null;
3724
- for (const reg of mvs) {
3725
- const mode = reg.spec.refresh;
3726
- if (mode === "eager") {
3727
- if (wave?.seen(`mv\0${reg.spec.name}`)) continue;
3728
- if (executor === null) {
3729
- ;
3730
- ({ MaterializedViewExecutor: executor } = await import("./executor-AXE4XMLT.js"));
3731
- }
3732
- await executor.refresh(reg, {
3733
- getCollection: (name) => this.materializedViewSource.getCollection(name),
3734
- getActiveTxContext: () => this.materializedViewSource.getActiveTxContext(),
3735
- getQueryContext: () => this.materializedViewSource.getQueryContext(),
3736
- dispatchCtx: this.#dispatchCtx({ collection: this.name, id })
3737
- });
3738
- } else if (mode === "lazy") {
3739
- if (staleHelpers === null) {
3740
- staleHelpers = await import("./stale-FJED42DM.js");
3741
- }
3742
- staleHelpers.markMVStale(registry, reg.spec.name);
3743
- }
3744
- }
3647
+ const { dispatchMaterializedViews } = await import("./dispatch-EGGC7UD7.js");
3648
+ return dispatchMaterializedViews(this.#mvDispatchCtx(this.materializedViewSource), id, record, wave);
3745
3649
  }
3746
3650
  /**
3747
3651
  * Fire registered derivation strategies for this source collection.
@@ -3829,6 +3733,32 @@ var Collection = class {
3829
3733
  return out;
3830
3734
  }
3831
3735
  /** @internal — ctx for `putDerivedOutput`'s frozen-period skip+audit (#638 Task 5). */
3736
+ /** What `with-formula/materialized-views/dispatch.ts` needs from this collection (#842). */
3737
+ #mvDispatchCtx(materializedViewSource) {
3738
+ return {
3739
+ materializedViewSource,
3740
+ collectionName: this.name,
3741
+ dispatchCtx: (source) => this.#dispatchCtx(source)
3742
+ };
3743
+ }
3744
+ /**
3745
+ * What `with-formula/derivations/dispatch.ts` needs from this collection (#842).
3746
+ *
3747
+ * The return type is inferred, not annotated: importing `DerivationDeleteCtx`
3748
+ * would be a STATIC spine→service import, which `port-layering` rejects even
3749
+ * when it is type-only — the guard scans import statements, not their
3750
+ * erasure. The dynamic `import()` at the call site still types the argument.
3751
+ */
3752
+ #derivationDeleteCtx(derivationSource) {
3753
+ return {
3754
+ derivationSource,
3755
+ collectionName: this.name,
3756
+ adapter: this.adapter,
3757
+ vault: this.vault,
3758
+ getDEK: this.getDEK,
3759
+ storeCiphertext: this.storeCiphertext
3760
+ };
3761
+ }
3832
3762
  #dispatchCtx(source) {
3833
3763
  return { emit: (e, p) => this.emitter.emit(e, p), source, audit: ledgerAuditHook(this.ledger, this.keyring.userId) };
3834
3764
  }
@@ -3854,11 +3784,7 @@ var Collection = class {
3854
3784
  const patched = { ...base, [field]: newValue };
3855
3785
  const txCtx = this.derivationSource.getActiveTxContext();
3856
3786
  if (txCtx !== null) {
3857
- const prior = await this.adapter.get(this.vault, into, parentId);
3858
- txCtx._executed.push({
3859
- op: { type: "put", vaultName: this.vault, collectionName: into, id: parentId },
3860
- priorEnvelope: prior
3861
- });
3787
+ this.#trackPut(txCtx, into, parentId, await this.adapter.get(this.vault, into, parentId));
3862
3788
  }
3863
3789
  return putDerivedOutput(intoColl, parentId, patched, this.#dispatchCtx(source));
3864
3790
  }
@@ -3891,150 +3817,14 @@ var Collection = class {
3891
3817
  * dispatch wave's per-target dedup; `undefined` on the local-write path (byte-identical). */
3892
3818
  async dispatchDerivations(id, record, version, wave) {
3893
3819
  if (this.derivationSource === void 0) return;
3894
- const incoming = this.via ? this.via.canonicalizeStored(record) : record;
3895
- if (incoming && typeof incoming === "object" && "_derivedFrom" in incoming) return;
3896
- const registry = this.derivationSource.registry();
3897
- const strategies = registry.strategiesForSource(this.name);
3898
- if (strategies.length === 0) return;
3899
- let DerivationExecutor = null;
3900
- for (const { spec, strategyHash } of strategies) {
3901
- const mode = typeof spec.lifecycle === "string" ? spec.lifecycle : spec.lifecycle.mode;
3902
- if (spec.rollup) {
3903
- if (mode !== "eager") continue;
3904
- let parentId;
3905
- if (this.name === spec.rollup.from) {
3906
- const kv = incoming[spec.rollup.key];
3907
- parentId = typeof kv === "string" || typeof kv === "number" ? String(kv) : null;
3908
- } else {
3909
- parentId = id;
3910
- }
3911
- if (parentId !== null) await this.recomputeRollup(spec, parentId, { collection: this.name, id }, wave);
3912
- continue;
3913
- }
3914
- const isSource = spec.source === this.name;
3915
- const isSibling = !isSource && (spec.sources?.includes(this.name) ?? false);
3916
- const trigger = !isSource && !isSibling ? spec.triggerBy?.find((t) => t.collection === this.name) : void 0;
3917
- const runs = [];
3918
- if (isSource) {
3919
- runs.push({ input: { ...incoming, id }, base: incoming, runId: id, version });
3920
- } else if (isSibling) {
3921
- const p = await this.derivationSource.getCollection(spec.source).get(id);
3922
- if (p !== null && p !== void 0) {
3923
- const raw = await this.derivationSource.getCollection(spec.source)._getStoredRecord(id);
3924
- runs.push({ input: { ...p, id }, base: raw ?? p, runId: id, version: 0 });
3925
- }
3926
- } else if (trigger) {
3927
- const srcColl = this.derivationSource.getCollection(spec.source);
3928
- const ids = await srcColl._findMatchingIds(trigger.on, id);
3929
- if (trigger.maxFanout !== void 0 && ids.length > trigger.maxFanout) {
3930
- throw new DerivationCapExceededError(`triggerBy ${this.name}\u2192${spec.source}`, ids.length, trigger.maxFanout);
3931
- }
3932
- for (const sid of ids) {
3933
- const raw = await srcColl._getStoredRecord(sid);
3934
- if (raw === null) continue;
3935
- runs.push({ input: { ...raw, id: sid }, base: raw, runId: sid, version: 0 });
3936
- }
3937
- }
3938
- if (runs.length === 0) continue;
3939
- if (mode !== "eager") {
3940
- for (const run of runs) await markStale(registry, spec, run.runId);
3941
- continue;
3942
- }
3943
- if (DerivationExecutor === null) {
3944
- ({ DerivationExecutor } = await import("./executor-XGIS6CR7.js"));
3945
- }
3946
- for (const run of runs) {
3947
- const ctx = { vault: this.derivationSource.getReadOnlyFacade() };
3948
- const outCtx = this.#dispatchCtx({ collection: spec.source, id: run.runId });
3949
- const result = await DerivationExecutor.run(spec, run.input, run.version, strategyHash, ctx);
3950
- for (const key of Object.keys(spec.outputs)) {
3951
- const out = result.outputs[key];
3952
- if (!out) continue;
3953
- if (out.kind === "failed") {
3954
- const err = out.error;
3955
- if (spec.strict) throw err;
3956
- console.warn(`[derivation] output "${key}" for source "${spec.source}" id="${run.runId}" failed:`, err);
3957
- continue;
3958
- }
3959
- const outSpec = spec.outputs[key];
3960
- if (!outSpec) continue;
3961
- const outputCollection = this.derivationSource.getCollection(outSpec.collection);
3962
- const txCtx = this.derivationSource.getActiveTxContext();
3963
- if (out.kind === "array") {
3964
- const { loadFanoutSidecar, saveFanoutSidecar } = await import("./fanout-sidecar-WDYQ77VB.js");
3965
- const prior = await loadFanoutSidecar(this.adapter, this.vault, spec.source, run.runId, key, this.getDEK, this.storeCiphertext);
3966
- const prevKeys = new Set(prior?.keys ?? []);
3967
- const newKeysList = out.entries.map((e) => e.key);
3968
- const newKeysSet = new Set(newKeysList);
3969
- for (const k of prevKeys) {
3970
- if (newKeysSet.has(k)) continue;
3971
- await outputCollection._internalDelete(k, txCtx);
3972
- }
3973
- for (const entry of out.entries) {
3974
- if (txCtx !== null) {
3975
- const priorEnvelope = await this.adapter.get(this.vault, outSpec.collection, entry.key);
3976
- txCtx._executed.push({
3977
- op: {
3978
- type: "put",
3979
- vaultName: this.vault,
3980
- collectionName: outSpec.collection,
3981
- id: entry.key
3982
- },
3983
- priorEnvelope
3984
- });
3985
- }
3986
- await putDerivedOutput(outputCollection, entry.key, entry.value, outCtx, { source: "derived" });
3987
- }
3988
- await saveFanoutSidecar(this.adapter, this.vault, {
3989
- source: spec.source,
3990
- sourceId: run.runId,
3991
- outputKey: key,
3992
- outputCollection: outSpec.collection,
3993
- keys: newKeysList
3994
- }, this.getDEK, this.storeCiphertext);
3995
- continue;
3996
- }
3997
- if (out.skipped === true) {
3998
- await outputCollection._internalDelete(run.runId, txCtx);
3999
- continue;
4000
- }
4001
- if (outSpec.shape === "record" && outSpec.denorm !== void 0 && outSpec.collection === spec.source) {
4002
- const value = out.value;
4003
- const patched = { ...run.base };
4004
- let changed = false;
4005
- for (const f of outSpec.denorm) {
4006
- if (!selfWriteFieldEqual(run.base[f], value[f])) {
4007
- patched[f] = value[f];
4008
- changed = true;
4009
- }
4010
- }
4011
- if (!changed) continue;
4012
- if (txCtx !== null) {
4013
- const prior = await this.adapter.get(this.vault, outSpec.collection, run.runId);
4014
- txCtx._executed.push({
4015
- op: { type: "put", vaultName: this.vault, collectionName: outSpec.collection, id: run.runId },
4016
- priorEnvelope: prior
4017
- });
4018
- }
4019
- await putDerivedOutput(outputCollection, run.runId, patched, outCtx, { source: "derived" });
4020
- continue;
4021
- }
4022
- if (txCtx !== null) {
4023
- const prior = await this.adapter.get(this.vault, outSpec.collection, run.runId);
4024
- txCtx._executed.push({
4025
- op: {
4026
- type: "put",
4027
- vaultName: this.vault,
4028
- collectionName: outSpec.collection,
4029
- id: run.runId
4030
- },
4031
- priorEnvelope: prior
4032
- });
4033
- }
4034
- await putDerivedOutput(outputCollection, run.runId, out.value, outCtx, { source: "derived" });
4035
- }
4036
- }
4037
- }
3820
+ const { dispatchDerivations } = await import("./dispatch-GDSTUTVP.js");
3821
+ return dispatchDerivations({
3822
+ ...this.#derivationDeleteCtx(this.derivationSource),
3823
+ via: this.via,
3824
+ recomputeRollup: (spec, parentId, source, w) => this.recomputeRollup(spec, parentId, source, w),
3825
+ dispatchCtx: (source) => this.#dispatchCtx(source),
3826
+ trackPut: (txCtx, collectionName, rid, prior) => this.#trackPut(txCtx, collectionName, rid, prior)
3827
+ }, id, record, version, wave);
4038
3828
  }
4039
3829
  /**
4040
3830
  * Delete a record by ID. Runs inside the hub's write-queue tracker
@@ -4203,10 +3993,10 @@ var Collection = class {
4203
3993
  if (existing && this.historyConfig.enabled !== false) {
4204
3994
  const cek = this.perRecordCek ? await this.resolveRecordCek(id) : void 0;
4205
3995
  const prevForVdig = this.vdigFields !== null ? await this.adapter.get(this.vault, this.name, id) : null;
4206
- await this.historyStrategy.saveHistory(this.adapter, this.vault, this.name, id, await this.codec.encryptRecord(existing.record, existing.version, cek, void 0, void 0, this.vdigFields !== null ? { id, prev: prevForVdig } : void 0, id));
3996
+ await this.strategies.history.saveHistory(this.adapter, this.vault, this.name, id, await this.codec.encryptRecord(existing.record, existing.version, cek, void 0, void 0, this.vdigFields !== null ? { id, prev: prevForVdig } : void 0, id));
4207
3997
  }
4208
3998
  const previousEnvelope = await this.adapter.get(this.vault, this.name, id);
4209
- const previousPayloadHash = await this.historyStrategy.envelopePayloadHash(previousEnvelope);
3999
+ const previousPayloadHash = await this.strategies.history.envelopePayloadHash(previousEnvelope);
4210
4000
  let markerVersion;
4211
4001
  if (this.onDirty) {
4212
4002
  const live = previousEnvelope;
@@ -4304,33 +4094,8 @@ var Collection = class {
4304
4094
  */
4305
4095
  async dispatchArrayDerivationsOnDelete(id, eraseRecordShapeToo = false) {
4306
4096
  if (this.derivationSource === void 0) return 0;
4307
- const registry = this.derivationSource.registry();
4308
- const strategies = registry.strategiesForSource(this.name);
4309
- if (strategies.length === 0) return 0;
4310
- let helpers = null;
4311
- const txCtx = this.derivationSource.getActiveTxContext();
4312
- let erased = 0;
4313
- for (const { spec } of strategies) {
4314
- for (const [outputKey, outSpec] of Object.entries(spec.outputs)) {
4315
- if (outSpec.shape === "record") {
4316
- if (eraseRecordShapeToo && spec.source === this.name && outSpec.collection !== this.name) {
4317
- if (await this.derivationSource.getCollection(outSpec.collection)._internalDelete(id, txCtx)) erased += 1;
4318
- }
4319
- continue;
4320
- }
4321
- if (helpers === null) {
4322
- helpers = await import("./fanout-sidecar-WDYQ77VB.js");
4323
- }
4324
- const sidecar = await helpers.loadFanoutSidecar(this.adapter, this.vault, spec.source, id, outputKey, this.getDEK, this.storeCiphertext);
4325
- if (!sidecar) continue;
4326
- const outputCollection = this.derivationSource.getCollection(outSpec.collection);
4327
- for (const derivedId of sidecar.keys) {
4328
- if (await outputCollection._internalDelete(derivedId, txCtx)) erased += 1;
4329
- }
4330
- await helpers.deleteFanoutSidecar(this.adapter, this.vault, spec.source, id, outputKey);
4331
- }
4332
- }
4333
- return erased;
4097
+ const { dispatchArrayDerivationsOnDelete } = await import("./dispatch-GDSTUTVP.js");
4098
+ return dispatchArrayDerivationsOnDelete(this.#derivationDeleteCtx(this.derivationSource), id, eraseRecordShapeToo);
4334
4099
  }
4335
4100
  /**
4336
4101
  * Mirror of {@link dispatchMaterializedViews} for the delete/forget path — no `_materializedFrom`
@@ -4343,41 +4108,8 @@ var Collection = class {
4343
4108
  */
4344
4109
  async dispatchMaterializedViewsOnDelete(id) {
4345
4110
  if (this.materializedViewSource === void 0) return { deleted: 0, residueUndecodable: [], residueDeclined: [] };
4346
- const registry = this.materializedViewSource.registry();
4347
- const mvs = registry.mvsForSource(this.name);
4348
- if (mvs.length === 0) return { deleted: 0, residueUndecodable: [], residueDeclined: [] };
4349
- let executor = null;
4350
- let staleHelpers = null;
4351
- let deleted = 0;
4352
- const residueUndecodable = [];
4353
- const residueDeclined = [];
4354
- for (const reg of mvs) {
4355
- const mode = reg.spec.refresh;
4356
- if (mode === "eager") {
4357
- if (executor === null) {
4358
- ;
4359
- ({ MaterializedViewExecutor: executor } = await import("./executor-AXE4XMLT.js"));
4360
- }
4361
- const rr = await executor.refresh(reg, {
4362
- getCollection: (name) => this.materializedViewSource.getCollection(name),
4363
- getActiveTxContext: () => this.materializedViewSource.getActiveTxContext(),
4364
- getQueryContext: () => this.materializedViewSource.getQueryContext(),
4365
- dispatchCtx: this.#dispatchCtx({ collection: this.name, id })
4366
- });
4367
- deleted += rr.deleted;
4368
- residueUndecodable.push(...rr.residueUndecodable);
4369
- residueDeclined.push(...rr.residueDeclined);
4370
- } else {
4371
- if (staleHelpers === null) {
4372
- staleHelpers = await import("./stale-FJED42DM.js");
4373
- }
4374
- const inv = await staleHelpers.invalidateMVAtRest(this.materializedViewSource, reg, mode);
4375
- deleted += inv.deleted;
4376
- residueUndecodable.push(...inv.residueUndecodable.map((rid) => `${reg.outputCollection}:${rid}`));
4377
- residueDeclined.push(...inv.residueDeclined.map((rid) => `${reg.outputCollection}:${rid}`));
4378
- }
4379
- }
4380
- return { deleted, residueUndecodable, residueDeclined };
4111
+ const { dispatchMaterializedViewsOnDelete } = await import("./dispatch-EGGC7UD7.js");
4112
+ return dispatchMaterializedViewsOnDelete(this.#mvDispatchCtx(this.materializedViewSource), id);
4381
4113
  }
4382
4114
  /**
4383
4115
  * List all records in the collection.
@@ -4396,7 +4128,7 @@ var Collection = class {
4396
4128
  );
4397
4129
  }
4398
4130
  if (this.materializedViewSource !== void 0) {
4399
- const { resolveStaleMVOnRead } = await import("./stale-FJED42DM.js");
4131
+ const { resolveStaleMVOnRead } = await import("./stale-A4J26OIC.js");
4400
4132
  await resolveStaleMVOnRead(this.materializedViewSource, this.name, this.#dispatchCtx({ collection: this.name, id: "resolve-on-read" }));
4401
4133
  }
4402
4134
  await this.ensureHydrated();
@@ -4417,28 +4149,28 @@ var Collection = class {
4417
4149
  * see `src/search/tokenize.ts` for the Thai/CJK caveat.
4418
4150
  */
4419
4151
  search(field, query, opts = {}) {
4420
- return this.searchStrategy.search(this.searchContext(), field, query, opts);
4152
+ return this.strategies.search.search(this.searchContext(), field, query, opts);
4421
4153
  }
4422
4154
  /** Force-persist the lexical index now — gated behind `searchStrategy: withSearch()`. */
4423
4155
  flushIndex() {
4424
- return this.searchStrategy.flushIndex(this.searchContext());
4156
+ return this.strategies.search.flushIndex(this.searchContext());
4425
4157
  }
4426
4158
  /** Pre-build the lexical index — gated behind `searchStrategy: withSearch()`. */
4427
4159
  warmIndex() {
4428
- return this.searchStrategy.warmIndex(this.searchContext());
4160
+ return this.strategies.search.warmIndex(this.searchContext());
4429
4161
  }
4430
4162
  /** Retrieval (lexical | semantic | hybrid) — gated behind `searchStrategy: withSearch()`. */
4431
4163
  retrieve(query, opts = {}) {
4432
- return this.searchStrategy.retrieve(this.searchContext(), query, opts);
4164
+ return this.strategies.search.retrieve(this.searchContext(), query, opts);
4433
4165
  }
4434
4166
  /** Raw-vector kNN — gated behind `searchStrategy: withSearch()`. */
4435
4167
  similarTo(vector, opts = {}) {
4436
- return this.searchStrategy.similarTo(this.searchContext(), vector, opts);
4168
+ return this.strategies.search.similarTo(this.searchContext(), vector, opts);
4437
4169
  }
4438
4170
  /** Opt-in bulk `_vec` re-derive (#788) — a plain collection has nothing to rebuild; gated behind `searchStrategy: withSearch()` otherwise. */
4439
4171
  rebuildEmbeddings() {
4440
4172
  if (!this.embeddings) return Promise.resolve({ rebuilt: 0, skipped: 0 });
4441
- return this.searchStrategy.rebuildEmbeddings(this.searchContext());
4173
+ return this.strategies.search.rebuildEmbeddings(this.searchContext());
4442
4174
  }
4443
4175
  /**
4444
4176
  * Bind the {@link SearchContext} the search/retrieval surface needs. The
@@ -4648,7 +4380,7 @@ var Collection = class {
4648
4380
  ...this.defaultLocale !== void 0 ? { defaultLocale: this.defaultLocale } : {},
4649
4381
  ...resolver.resolveDictSource ? { resolveDictSource: (field) => resolver.resolveDictSource(leftCollection, field) } : {}
4650
4382
  } : void 0;
4651
- return new Query(source, void 0, joinContext, this.aggregateStrategy);
4383
+ return new Query(source, void 0, joinContext, this.strategies.reduce);
4652
4384
  }
4653
4385
  /**
4654
4386
  * Subscribe to every put/delete on this collection. Returns an
@@ -4762,7 +4494,7 @@ var Collection = class {
4762
4494
  // ─── History Methods ────────────────────────────────────────────
4763
4495
  /** Get version history for a record, newest first. */
4764
4496
  async history(id, options) {
4765
- const envelopes = await this.historyStrategy.getHistoryEntries(
4497
+ const envelopes = await this.strategies.history.getHistoryEntries(
4766
4498
  this.adapter,
4767
4499
  this.vault,
4768
4500
  this.name,
@@ -4794,7 +4526,7 @@ var Collection = class {
4794
4526
  * and re-put the records through the normal `put()` path.
4795
4527
  */
4796
4528
  async getVersion(id, version) {
4797
- const envelope = await this.historyStrategy.getVersionEnvelope(
4529
+ const envelope = await this.strategies.history.getVersionEnvelope(
4798
4530
  this.adapter,
4799
4531
  this.vault,
4800
4532
  this.name,
@@ -4819,7 +4551,7 @@ var Collection = class {
4819
4551
  */
4820
4552
  async diff(id, versionA, versionB) {
4821
4553
  const recordA = versionA === 0 ? null : await this.resolveVersion(id, versionA);
4822
- return this.historyStrategy.diff(recordA, versionB === void 0 || versionB === 0 ? versionB === 0 ? null : await this.resolveCurrentOrVersion(id) : await this.resolveVersion(id, versionB));
4554
+ return this.strategies.history.diff(recordA, versionB === void 0 || versionB === 0 ? versionB === 0 ? null : await this.resolveCurrentOrVersion(id) : await this.resolveVersion(id, versionB));
4823
4555
  }
4824
4556
  /** Resolve a version: try history first, then check if it's the current version. */
4825
4557
  async resolveVersion(id, version) {
@@ -4836,7 +4568,7 @@ var Collection = class {
4836
4568
  }
4837
4569
  /** Prune history entries for a record (or all records if id is undefined). */
4838
4570
  async pruneRecordHistory(id, options) {
4839
- const pruned = await this.historyStrategy.pruneHistory(
4571
+ const pruned = await this.strategies.history.pruneHistory(
4840
4572
  this.adapter,
4841
4573
  this.vault,
4842
4574
  this.name,
@@ -4855,7 +4587,7 @@ var Collection = class {
4855
4587
  }
4856
4588
  /** Clear all history for this collection (or a specific record). */
4857
4589
  async clearHistory(id) {
4858
- return this.historyStrategy.clearHistory(this.adapter, this.vault, this.name, id);
4590
+ return this.strategies.history.clearHistory(this.adapter, this.vault, this.name, id);
4859
4591
  }
4860
4592
  // ─── Core Methods ─────────────────────────────────────────────
4861
4593
  /**
@@ -5277,7 +5009,7 @@ var Collection = class {
5277
5009
  * vault-shared `_blob` DEK (enabling cross-collection deduplication).
5278
5010
  */
5279
5011
  blob(id) {
5280
- return this.blobStrategy.openSlot({
5012
+ return this.strategies.blobs.openSlot({
5281
5013
  store: this.adapter,
5282
5014
  vault: this.vault,
5283
5015
  collection: this.name,
@@ -5510,7 +5242,7 @@ var Collection = class {
5510
5242
  const persisted = this.persistedIndexes;
5511
5243
  if (!persisted) {
5512
5244
  throw new Error(
5513
- `Collection "${this.name}": lazyQuery() requires indexing to be enabled. Pass \`withIndexing()\` from "@noy-db/hub/indexing" to \`createNoydb({ indexStrategy: withIndexing() })\`.`
5245
+ `Collection "${this.name}": lazyQuery() requires indexing to be enabled. Pass \`withIndexing()\` from "@noy-db/hub/indexing" to \`createNoydb({ indexingStrategy: withIndexing() })\`.`
5514
5246
  );
5515
5247
  }
5516
5248
  if (persisted.fields().length === 0) {
@@ -5549,14 +5281,14 @@ var Collection = class {
5549
5281
  /** C-A/R10: persist the classified marker once per classified handle (store I/O in config-drift.ts). */
5550
5282
  async _ensureClassifiedMarker() {
5551
5283
  if (this._markerPersisted || this.vdigFields === null) return;
5552
- const { persistClassifiedMarkerForFields } = await import("./classified-marker-WQVIJAW2.js");
5284
+ const { persistClassifiedMarkerForFields } = await import("./classified-marker-7PKJBFCG.js");
5553
5285
  await persistClassifiedMarkerForFields(this.adapter, this.vault, this.name, this.vdigFields, await this.getDEK(this.name));
5554
5286
  this._markerPersisted = true;
5555
5287
  }
5556
5288
  /** C-A/R10 drift signal — the marker's declared digest-only set, memoized to one store read per handle (see config-drift.ts). */
5557
5289
  async _classifiedMarkerDigestOnly() {
5558
5290
  if (this._markerDigestOnlyCache !== void 0) return this._markerDigestOnlyCache;
5559
- const { readClassifiedMarkerDigestOnly } = await import("./classified-marker-WQVIJAW2.js");
5291
+ const { readClassifiedMarkerDigestOnly } = await import("./classified-marker-7PKJBFCG.js");
5560
5292
  this._markerDigestOnlyCache = await readClassifiedMarkerDigestOnly(this.adapter, this.vault, this.name, await this.getDEK(this.name));
5561
5293
  return this._markerDigestOnlyCache;
5562
5294
  }
@@ -5598,23 +5330,23 @@ var Collection = class {
5598
5330
  // ─── Hierarchical Access ──────────────────────────
5599
5331
  /** tier-aware put — gated behind `tiersStrategy: withTiers()`. `searchResidue: true` = stuck search compensation (#774, mirroring #764's elevate/demote posture); the write itself always completes. */
5600
5332
  putAtTier(id, record, tier, opts) {
5601
- return this.tiersStrategy.putAtTier(this.tiersContext(), id, record, tier, opts);
5333
+ return this.strategies.tiers.putAtTier(this.tiersContext(), id, record, tier, opts);
5602
5334
  }
5603
5335
  /** tier-aware get — gated behind `tiersStrategy: withTiers()`. */
5604
5336
  getAtTier(id) {
5605
- return this.tiersStrategy.getAtTier(this.tiersContext(), id);
5337
+ return this.strategies.tiers.getAtTier(this.tiersContext(), id);
5606
5338
  }
5607
5339
  /** list ids grouped by the caller's readability — gated behind `withTiers()`. */
5608
5340
  listAtTier() {
5609
- return this.tiersStrategy.listAtTier(this.tiersContext());
5341
+ return this.strategies.tiers.listAtTier(this.tiersContext());
5610
5342
  }
5611
5343
  /** elevate a record to a higher tier — gated behind `withTiers()`. `searchResidue: true` = stuck search compensation (#764); the move itself always completes. */
5612
5344
  elevate(id, toTier) {
5613
- return this.tiersStrategy.elevate(this.tiersContext(), id, toTier);
5345
+ return this.strategies.tiers.elevate(this.tiersContext(), id, toTier);
5614
5346
  }
5615
5347
  /** demote a record to a lower tier — gated behind `withTiers()`. Same `searchResidue` posture as {@link elevate} (#764). */
5616
5348
  demote(id, toTier) {
5617
- return this.tiersStrategy.demote(this.tiersContext(), id, toTier);
5349
+ return this.strategies.tiers.demote(this.tiersContext(), id, toTier);
5618
5350
  }
5619
5351
  /**
5620
5352
  * Emit a cross-tier access event. The subscriber sink stays collection-resident (it captures `onCrossTierAccess`); the tiers module reaches it via the {@link TiersContext.emitCrossTierEvent} callback.
@@ -5675,16 +5407,16 @@ var Collection = class {
5675
5407
  },
5676
5408
  syncIndexes: (id, rec, version, priorEnvelope) => syncTierIndexes(this.indexingContext(), id, rec, version, priorEnvelope),
5677
5409
  syncSearch: (id, rec, version) => syncTierSearch(this.searchContext(), id, rec, version),
5678
- syncHistory: async (id, fromDek, toDek) => this.historyStrategy.rewrapHistory(this.adapter, this.vault, this.name, id, fromDek, toDek, await this.getDEK(this.name)),
5410
+ syncHistory: async (id, fromDek, toDek) => this.strategies.history.rewrapHistory(this.adapter, this.vault, this.name, id, fromDek, toDek, await this.getDEK(this.name)),
5679
5411
  saveHistorySnapshot: async (id, envelope) => {
5680
5412
  if (this.historyConfig.enabled === false) return;
5681
- await this.historyStrategy.saveHistory(this.adapter, this.vault, this.name, id, envelope);
5413
+ await this.strategies.history.saveHistory(this.adapter, this.vault, this.name, id, envelope);
5682
5414
  this.emitter.emit("history:save", { vault: this.vault, collection: this.name, id, version: envelope._v });
5683
- if (this.historyConfig.maxVersions) await this.historyStrategy.pruneHistory(this.adapter, this.vault, this.name, id, { keepVersions: this.historyConfig.maxVersions });
5415
+ if (this.historyConfig.maxVersions) await this.strategies.history.pruneHistory(this.adapter, this.vault, this.name, id, { keepVersions: this.historyConfig.maxVersions });
5684
5416
  },
5685
- historyEnabled: this.historyConfig.enabled !== false && this.historyStrategy !== NO_HISTORY,
5417
+ historyEnabled: this.historyConfig.enabled !== false && this.strategies.history !== NO_HISTORY,
5686
5418
  // #728/#737: lets putAtTier skip decrypting `existing` when no real history strategy is wired
5687
- syncBlobs: (id, fromTier, toTier) => this.blobStrategy !== NO_BLOBS ? this.blob(id).syncTierMove(fromTier, toTier, this.blobTierPolicy) : Promise.resolve(),
5419
+ syncBlobs: (id, fromTier, toTier) => this.strategies.blobs !== NO_BLOBS ? this.blob(id).syncTierMove(fromTier, toTier, this.blobTierPolicy) : Promise.resolve(),
5688
5420
  // #724 I1: gate on blob storage enabled (not on declared blobFields) so undeclared-field blobs still rehome; #746: syncTierMove mints/resumes the rehome journal marker; self-no-ops on an empty slot map
5689
5421
  syncLedger: async (id) => {
5690
5422
  await this.ledger?.purgeRecordDeltas(this.name, id);
@@ -5727,6 +5459,64 @@ var Collection = class {
5727
5459
  }
5728
5460
  };
5729
5461
 
5462
+ // src/port/with/capabilities.ts
5463
+ function assertCanExport(keyring, tier, format) {
5464
+ if (tier === "plaintext") {
5465
+ if (format === void 0) {
5466
+ throw new Error("vault.assertCanExport: plaintext tier requires a format");
5467
+ }
5468
+ if (!hasExportCapability(keyring, "plaintext", format)) {
5469
+ throw new ExportCapabilityError({
5470
+ tier: "plaintext",
5471
+ userId: keyring.userId,
5472
+ format
5473
+ });
5474
+ }
5475
+ return;
5476
+ }
5477
+ if (!hasExportCapability(keyring, "bundle")) {
5478
+ throw new ExportCapabilityError({
5479
+ tier: "bundle",
5480
+ userId: keyring.userId
5481
+ });
5482
+ }
5483
+ }
5484
+ function assertCanImport(keyring, tier, format) {
5485
+ if (tier === "plaintext") {
5486
+ if (format === void 0) {
5487
+ throw new Error("vault.assertCanImport: plaintext tier requires a format");
5488
+ }
5489
+ if (!hasImportCapability(keyring, "plaintext", format)) {
5490
+ throw new ImportCapabilityError({
5491
+ tier: "plaintext",
5492
+ userId: keyring.userId,
5493
+ format
5494
+ });
5495
+ }
5496
+ return;
5497
+ }
5498
+ if (!hasImportCapability(keyring, "bundle")) {
5499
+ throw new ImportCapabilityError({
5500
+ tier: "bundle",
5501
+ userId: keyring.userId
5502
+ });
5503
+ }
5504
+ }
5505
+ function canExport(keyring, tier, format) {
5506
+ if (tier === "plaintext") {
5507
+ if (format === void 0) return false;
5508
+ return hasExportCapability(keyring, "plaintext", format);
5509
+ }
5510
+ return hasExportCapability(keyring, "bundle");
5511
+ }
5512
+ function canImport(keyring, tier, format) {
5513
+ if (tier === "plaintext") {
5514
+ if (format === void 0) return false;
5515
+ return hasImportCapability(keyring, "plaintext", format);
5516
+ }
5517
+ return hasImportCapability(keyring, "bundle");
5518
+ }
5519
+
5730
5520
  // src/with-commit/tx/elevated-handle.ts
5731
5521
  var ELEVATION_AUDIT_COLLECTION = "_elevation_audit";
5732
5522
  var ElevatedHandle = class {
@@ -6008,47 +5798,7 @@ var DeferredNumberingStore = class {
6008
5798
  this.waiters.delete(id);
6009
5799
  }
6010
5800
  }
6011
- return assignments;
6012
- }
6013
- };
6014
-
6015
- // src/with-fork/shadow/strategy.ts
6016
- var NOT_ENABLED2 = new Error(
6017
- 'VaultFrame requires the shadow strategy. Import `{ withShadow }` from "@noy-db/hub/shadow" and pass it to `createNoydb({ shadowStrategy: withShadow() })`.'
6018
- );
6019
- var NO_SHADOW = {
6020
- buildFrame() {
6021
- throw NOT_ENABLED2;
6022
- }
6023
- };
6024
-
6025
- // src/with-audit/consent/strategy.ts
6026
- var NO_CONSENT = {
6027
- async write() {
6028
- },
6029
- async read() {
6030
- return [];
6031
- }
6032
- };
6033
-
6034
- // src/with-audit/periods/strategy.ts
6035
- var NOT_ENABLED3 = new Error(
6036
- 'Accounting periods require the periods strategy. Import `{ withPeriods }` from "@noy-db/hub/periods" and pass it to `createNoydb({ periodsStrategy: withPeriods() })`.'
6037
- );
6038
- var NO_PERIODS = {
6039
- async loadPeriods() {
6040
- return [];
6041
- },
6042
- async chainAnchor() {
6043
- return { priorPeriodHash: "" };
6044
- },
6045
- assertTsWritable() {
6046
- },
6047
- validatePeriodName() {
6048
- throw NOT_ENABLED3;
6049
- },
6050
- async appendPeriodLedgerEntry() {
6051
- throw NOT_ENABLED3;
5801
+ return assignments;
6052
5802
  }
6053
5803
  };
6054
5804
 
@@ -6390,6 +6140,9 @@ var VaultPeriods = class {
6390
6140
  };
6391
6141
  }
6392
6142
  await this.deps.adapter.put(this.deps.vault, collection, key, envelope);
6143
+ if (collection === PERIODS_COLLECTION && this.deps.onDirty) {
6144
+ await this.deps.onDirty(collection, key, "put", envelope._v);
6145
+ }
6393
6146
  return envelope;
6394
6147
  }
6395
6148
  /** Generic reserved-collection reader — serves `_period_freezes` companion reads. */
@@ -6978,7 +6731,7 @@ var VaultLinks = class {
6978
6731
  // src/with-shape/links/lazy-handle.ts
6979
6732
  function makeLazyLinkSetHandle(d) {
6980
6733
  let engine = null;
6981
- const load = () => engine ??= import("./link-set-QK22TDEX.js").then(
6734
+ const load = () => engine ??= import("./link-set-NK6L2A5S.js").then(
6982
6735
  ({ LinkSet }) => new LinkSet(d.adapter, d.vault, d.name, d.spec, d.encrypted, d.getDEK, d.actor, d.emitter, d.endpointExists)
6983
6736
  );
6984
6737
  return {
@@ -7461,7 +7214,7 @@ var SatelliteRegistry = class {
7461
7214
  if (reason !== void 0) throw new SatelliteConfigError(reason);
7462
7215
  }
7463
7216
  /** Per-base async mutex: chains sections on a stored promise tail. */
7464
- async withPairLock(base, fn2) {
7217
+ async withPairLock(base, fn) {
7465
7218
  const tail = this.locks.get(base) ?? Promise.resolve();
7466
7219
  let release;
7467
7220
  const gate = new Promise((res) => {
@@ -7470,7 +7223,7 @@ var SatelliteRegistry = class {
7470
7223
  this.locks.set(base, tail.then(() => gate));
7471
7224
  await tail;
7472
7225
  try {
7473
- return await fn2();
7226
+ return await fn();
7474
7227
  } finally {
7475
7228
  release();
7476
7229
  }
@@ -7516,7 +7269,7 @@ function declareSatellite(ctx, collectionName, options, existingRegistry) {
7516
7269
  ctx.forEachSyncEngine((e) => e.remirrorPairResolvers([spec.base, spec.satellite]));
7517
7270
  const registry = reg;
7518
7271
  const baseSchema = ctx.getBaseSchema(spec.base);
7519
- void import("./post-register-JVTMJ6OW.js").then((m) => m.postRegister(ctx.adapter, ctx.vaultName, spec, ctx.getDEK, baseSchema, registry)).catch(() => {
7272
+ void import("./post-register-VFIYISUK.js").then((m) => m.postRegister(ctx.adapter, ctx.vaultName, spec, ctx.getDEK, baseSchema, registry)).catch(() => {
7520
7273
  });
7521
7274
  return reg;
7522
7275
  }
@@ -7847,20 +7600,6 @@ async function migrateSatelliteCek(name, coll) {
7847
7600
  return { migrated };
7848
7601
  }
7849
7602
 
7850
- // src/with-shape/schema-update/gate.ts
7851
- var SchemaUpdateGate = class {
7852
- #decision;
7853
- constructor(decision) {
7854
- this.#decision = decision.catch(() => null);
7855
- }
7856
- async assertWritable() {
7857
- const decision = await this.#decision;
7858
- if (decision && decision.action === "reject") {
7859
- throw decision.error;
7860
- }
7861
- }
7862
- };
7863
-
7864
7603
  // src/with-shape/schema-update/fence-controller.ts
7865
7604
  var SchemaFenceController = class {
7866
7605
  #coordination;
@@ -8033,6 +7772,43 @@ var VaultAttestation = class {
8033
7772
  };
8034
7773
 
8035
7774
  // src/kernel/vault.ts
7775
+ var COLLECTION_PASSTHROUGH_KEYS = [
7776
+ "indexes",
7777
+ "reconcileOnOpen",
7778
+ "prefetch",
7779
+ "cache",
7780
+ "schema",
7781
+ "conflictPolicy",
7782
+ "crdt",
7783
+ "deterministicFields",
7784
+ "acknowledgeDeterministicRisk",
7785
+ "acknowledgeEquatableRisk",
7786
+ "sensitive",
7787
+ "perRecordKeys",
7788
+ "provenance",
7789
+ "ramCiphertext",
7790
+ "tiers",
7791
+ "tierMode",
7792
+ "blobTierPolicy",
7793
+ "i18nFields",
7794
+ "embeddings",
7795
+ "textIndexes",
7796
+ "warmIndexOnOpen",
7797
+ "textIndexPersist",
7798
+ "moneyFields",
7799
+ "viaFields",
7800
+ "computed",
7801
+ "classifiedFields",
7802
+ "fieldMeta",
7803
+ "meta"
7804
+ ];
7805
+ function copyDefined(dst, src, keys) {
7806
+ if (src === void 0) return;
7807
+ for (const key of keys) {
7808
+ const value = src[key];
7809
+ if (value !== void 0) dst[key] = value;
7810
+ }
7811
+ }
8036
7812
  var Vault = class {
8037
7813
  adapter;
8038
7814
  /** The vault's name as passed to `openVault()`. Stable for the instance lifetime. */
@@ -8050,36 +7826,22 @@ var Vault = class {
8050
7826
  syncAdapter;
8051
7827
  getPurgeableTargets;
8052
7828
  historyConfig;
8053
- /** tree-shake seam for the optional blob service; `undefined` means "blobs are off for this
8054
- * vault" — every `collection.blob(id)` call throws with a pointer at `@noy-db/hub/blobs`. */
8055
- blobStrategy;
7829
+ /**
7830
+ * Every opt-in service, resolved once by `createNoydb` (#838). Shared by
7831
+ * reference with the owning `Noydb` and with every `Collection` this vault
7832
+ * opens, so all three always agree about which services are enabled.
7833
+ */
7834
+ strategies;
8056
7835
  objectStore;
8057
- /** Cold-storage archival strategy (the archive target store). */
8058
- archiveStrategy;
8059
7836
  /** Per-collection record archival policies. Indexed by collection name. */
8060
7837
  archiveRegistry = /* @__PURE__ */ new Map();
8061
- indexStrategy;
8062
- lazyStrategy;
8063
- aggregateStrategy;
8064
- crdtStrategy;
8065
- tiersStrategy;
8066
- searchStrategy;
8067
- /** Cargo (partition extraction) strategy — `NO_CARGO` (throwing) unless `withCargo()` was passed.
8068
- * Public so the `extractPartition` free function (which takes a `Vault`) routes through it. */
8069
- cargoStrategy;
8070
- brokerStrategy;
8071
- sealedRecordStrategy;
8072
- portabilityStrategy;
8073
- sequenceStrategy;
8074
- consentStrategy;
8075
7838
  periods;
8076
7839
  linksEnforcer;
8077
- shadowStrategy;
8078
- historyStrategy;
8079
- forgetStrategy;
8080
- i18nStrategy;
8081
- syncStrategy;
8082
- classifiedStrategy;
7840
+ /** Cargo (partition extraction) strategy — `NO_CARGO` (throwing) unless `withCargo()` was passed.
7841
+ * Public so the `extractPartition` free function (which takes a `Vault`) routes through it. */
7842
+ get cargoStrategy() {
7843
+ return this.strategies.cargo;
7844
+ }
8083
7845
  /** Per-vault guard registry; `null` until `_initGuards()` runs (or for vaults that never register
8084
7846
  * one) — the runtime class is dynamic-imported on demand to keep it out of the floor bundle. */
8085
7847
  guardRegistry = null;
@@ -8128,7 +7890,7 @@ var Vault = class {
8128
7890
  * @see docs/superpowers/specs/2026-06-17-fr6-deed-custodian-liberate-design.md
8129
7891
  */
8130
7892
  custody;
8131
- /** Re-derives an UnlockedKeyring from the adapter using the active user's passphrase; called by
7893
+ /** Re-derives an UnlockedKeyring from the adapter using the active user's secret; called by
8132
7894
  * `load()` after the on-disk keyring file has been replaced. Provided by Noydb at openVault()
8133
7895
  * time; `undefined` in tests that construct Vault directly (load() then skips the refresh). */
8134
7896
  reloadKeyring;
@@ -8261,23 +8023,10 @@ var Vault = class {
8261
8023
  this.onRegisterConflictResolver = opts.onRegisterConflictResolver;
8262
8024
  this.syncAdapter = opts.syncAdapter;
8263
8025
  this.getPurgeableTargets = opts.getPurgeableTargets ?? (() => []);
8264
- this.blobStrategy = opts.blobStrategy;
8026
+ this.strategies = opts.strategies;
8265
8027
  this.objectStore = opts.objectStore;
8266
- this.archiveStrategy = opts.archiveStrategy;
8267
- this.indexStrategy = opts.indexStrategy;
8268
- this.lazyStrategy = opts.lazyStrategy;
8269
- this.aggregateStrategy = opts.aggregateStrategy;
8270
- this.crdtStrategy = opts.crdtStrategy;
8271
- this.tiersStrategy = opts.tiersStrategy;
8272
- this.searchStrategy = opts.searchStrategy;
8273
- this.cargoStrategy = opts.cargoStrategy ?? NO_CARGO;
8274
- this.brokerStrategy = opts.brokerStrategy ?? NO_BROKER;
8275
- this.sealedRecordStrategy = opts.sealedRecordStrategy ?? NO_SEALED_RECORD;
8276
- this.portabilityStrategy = opts.portabilityStrategy ?? NO_PORTABILITY;
8277
- this.sequenceStrategy = opts.sequenceStrategy ?? NO_SEQUENCE;
8278
- this.consentStrategy = opts.consentStrategy ?? NO_CONSENT;
8279
8028
  this.periods = new VaultPeriods({
8280
- strategy: opts.periodsStrategy ?? NO_PERIODS,
8029
+ strategy: this.strategies.periods,
8281
8030
  adapter: this.adapter,
8282
8031
  vault: this.name,
8283
8032
  encrypted: this.encrypted,
@@ -8287,7 +8036,9 @@ var Vault = class {
8287
8036
  collection: (name) => this.collection(name),
8288
8037
  purgeDeleteMarkers: (before) => this._purgeDeleteMarkers(before),
8289
8038
  archiveRecords: (before) => this._archiveClosedPeriod(before),
8290
- purgeTargets: (before) => this._purgePeriodTargets(before)
8039
+ purgeTargets: (before) => this._purgePeriodTargets(before),
8040
+ // #822: push symmetry for the period summaries — see writeReserved.
8041
+ onDirty: this.onDirty
8291
8042
  });
8292
8043
  this.linksEnforcer = new VaultLinks({
8293
8044
  refRegistry: this.refRegistry,
@@ -8300,12 +8051,6 @@ var Vault = class {
8300
8051
  getActiveTxContext: () => this.noydb._activeTxContextOrNull,
8301
8052
  emitter: this.emitter
8302
8053
  });
8303
- this.shadowStrategy = opts.shadowStrategy ?? NO_SHADOW;
8304
- this.historyStrategy = opts.historyStrategy ?? NO_HISTORY;
8305
- this.forgetStrategy = opts.forgetStrategy ?? NO_FORGET;
8306
- this.i18nStrategy = opts.i18nStrategy ?? NO_I18N;
8307
- this.syncStrategy = opts.syncStrategy ?? NO_SYNC;
8308
- this.classifiedStrategy = opts.classifiedStrategy ?? NO_CLASSIFIED;
8309
8054
  this.graph = new ViaGraph();
8310
8055
  void opts.guardStrategies;
8311
8056
  this.historyConfig = opts.historyConfig ?? { enabled: true };
@@ -8320,19 +8065,19 @@ var Vault = class {
8320
8065
  getDEK: (collection) => this.getDEK(collection),
8321
8066
  role: () => this.keyring.role,
8322
8067
  getRawRecord: async (collection, recId) => await this.collection(collection).get(recId, { locale: "raw" })
8323
- }, opts.attestationStrategy ?? NO_ATTESTATION);
8068
+ }, this.strategies.attestation);
8324
8069
  this.user = this.noydb.userApiFactory({
8325
8070
  adapter: this.adapter,
8326
8071
  vaultName: this.name,
8327
8072
  writerKeyringId: this.keyring.userId,
8328
8073
  getDek: () => this.getDEK(USER_ENVELOPE_COLLECTION),
8329
8074
  checkGate: (gate, presented) => this.noydb.checkGate(this.name, gate, presented),
8330
- exportAccessible: (opts2) => this.portabilityStrategy.exportAccessibleData(this, opts2),
8331
- unilateralWithdraw: (opts2) => this.portabilityStrategy.withdrawAccessibleData(this, opts2),
8332
- requestWithdraw: (opts2) => this.portabilityStrategy.requestWithdrawal(this, opts2),
8333
- listWithdrawals: (opts2) => this.portabilityStrategy.listWithdrawalRequests(this, opts2),
8334
- approveWithdraw: (requestId, opts2) => this.portabilityStrategy.approveWithdrawal(this, requestId, opts2),
8335
- rejectWithdraw: (requestId, opts2) => this.portabilityStrategy.rejectWithdrawal(this, requestId, opts2)
8075
+ exportAccessible: (opts2) => this.strategies.portability.exportAccessibleData(this, opts2),
8076
+ unilateralWithdraw: (opts2) => this.strategies.portability.withdrawAccessibleData(this, opts2),
8077
+ requestWithdraw: (opts2) => this.strategies.portability.requestWithdrawal(this, opts2),
8078
+ listWithdrawals: (opts2) => this.strategies.portability.listWithdrawalRequests(this, opts2),
8079
+ approveWithdraw: (requestId, opts2) => this.strategies.portability.approveWithdrawal(this, requestId, opts2),
8080
+ rejectWithdraw: (requestId, opts2) => this.strategies.portability.rejectWithdrawal(this, requestId, opts2)
8336
8081
  });
8337
8082
  this.custody = new CustodyApi(
8338
8083
  (options, factors) => this.noydb.grantCustodian(this.name, options, factors),
@@ -8390,7 +8135,7 @@ var Vault = class {
8390
8135
  * dispatch reads/writes — from this vault's OWN privates, rather than passing `this` itself. */
8391
8136
  _viaReconcileCtx() {
8392
8137
  return {
8393
- i18nStrategy: this.i18nStrategy,
8138
+ i18nStrategy: this.strategies.i18n,
8394
8139
  locale: this.locale,
8395
8140
  translateText: this.translateText,
8396
8141
  i18nFieldRegistry: this.i18nFieldRegistry,
@@ -8406,6 +8151,22 @@ var Vault = class {
8406
8151
  enforceStaticDictOnPut: (collectionName, record) => this.enforceStaticDictOnPut(collectionName, record)
8407
8152
  };
8408
8153
  }
8154
+ /** The registries `populateCollectionRegistries` writes into (#841). */
8155
+ #registries() {
8156
+ return {
8157
+ refRegistry: this.refRegistry,
8158
+ i18nFieldRegistry: this.i18nFieldRegistry,
8159
+ blobFieldsRegistry: this.blobFieldsRegistry,
8160
+ archiveRegistry: this.archiveRegistry,
8161
+ attestation: this.attestation,
8162
+ dictKeyFieldRegistry: this.dictKeyFieldRegistry,
8163
+ staticDictNames: this.staticDictNames,
8164
+ staticByName: this.staticByName,
8165
+ staticDescriptorByField: this.staticDescriptorByField,
8166
+ reservedLookupCollections: this.reservedLookupCollections,
8167
+ schemaUpdateNames: this.#schemaUpdateNames
8168
+ };
8169
+ }
8409
8170
  collection(collectionName, options) {
8410
8171
  const overlayRegistry = this.overlayedViewRegistry;
8411
8172
  if (overlayRegistry !== null && overlayRegistry.isOverlay(collectionName)) {
@@ -8431,7 +8192,7 @@ var Vault = class {
8431
8192
  this.satelliteRegistry = declareSatellite({
8432
8193
  adapter: this.adapter,
8433
8194
  vaultName: this.name,
8434
- forgetSubjects: this.forgetStrategy.subjects,
8195
+ forgetSubjects: this.strategies.forget.subjects,
8435
8196
  getDEK: this.getDEK,
8436
8197
  getBaseSchema: (base) => this.collectionCache.get(base)?.getSchema(),
8437
8198
  getBaseCrdt: (base) => this.collectionCache.get(base)?.getConfig()?.crdt,
@@ -8439,8 +8200,8 @@ var Vault = class {
8439
8200
  registerPoisonHook: (hook) => {
8440
8201
  this.noydb._writeHooks.onBeforeWrite(hook);
8441
8202
  },
8442
- forEachSyncEngine: (fn2) => {
8443
- this.noydb._forEachSyncEngine(this.name, fn2);
8203
+ forEachSyncEngine: (fn) => {
8204
+ this.noydb._forEachSyncEngine(this.name, fn);
8444
8205
  }
8445
8206
  }, collectionName, { ...options, satelliteOf: options.satelliteOf }, this.satelliteRegistry);
8446
8207
  }
@@ -8457,60 +8218,14 @@ var Vault = class {
8457
8218
  });
8458
8219
  }
8459
8220
  if (!coll) {
8460
- if (options?.refs) {
8461
- this.refRegistry.register(collectionName, options.refs);
8462
- }
8463
- if (effectiveViaFields.i18nFields) {
8464
- this.i18nFieldRegistry.set(collectionName, effectiveViaFields.i18nFields);
8465
- }
8466
- if (options?.blobFields) {
8467
- this.blobFieldsRegistry.set(collectionName, options.blobFields);
8468
- }
8469
- if (options?.archive) {
8470
- this.archiveRegistry.set(collectionName, options.archive);
8471
- }
8472
- if (options?.attestation !== void 0) {
8473
- this.attestation.register(collectionName, options.attestation);
8474
- }
8475
- if (effectiveViaFields.dictKeyFields || effectiveViaFields.lookupFields) {
8476
- const dictFieldMap = {};
8477
- const staticFieldMap = {};
8478
- for (const [field, desc] of Object.entries(effectiveViaFields.dictKeyFields ?? {})) {
8479
- if (isStaticDictDescriptor(desc)) {
8480
- staticFieldMap[field] = desc;
8481
- this.staticDictNames.add(desc.name);
8482
- this.staticByName.set(desc.name, desc);
8483
- } else {
8484
- dictFieldMap[field] = desc.name;
8485
- }
8486
- }
8487
- const lookupCompat = collectLookupDictCompat(effectiveViaFields.lookupFields);
8488
- Object.assign(dictFieldMap, lookupCompat.dictFieldMap);
8489
- for (const [field, desc] of lookupCompat.staticEntries) {
8490
- staticFieldMap[field] = desc;
8491
- this.staticDictNames.add(desc.name);
8492
- this.staticByName.set(desc.name, desc);
8493
- }
8494
- if (Object.keys(dictFieldMap).length > 0) {
8495
- this.dictKeyFieldRegistry.set(collectionName, dictFieldMap);
8496
- for (const dictName of new Set(Object.values(dictFieldMap))) {
8497
- this.reservedLookupCollections.set(dictCollectionName(dictName), dictName);
8498
- }
8499
- }
8500
- if (Object.keys(staticFieldMap).length > 0) {
8501
- this.staticDescriptorByField.set(collectionName, staticFieldMap);
8502
- }
8503
- }
8504
- if ((options?.schemaUpdate?.length ?? 0) > 0) {
8505
- this.#schemaUpdateNames.set(collectionName, (options.schemaUpdate ?? []).map((s) => s.name));
8506
- }
8221
+ populateCollectionRegistries(this.#registries(), collectionName, options, effectiveViaFields);
8507
8222
  let schemaUpdateGate;
8508
8223
  if (options?.persistJsonSchema === true && options.schema !== void 0 && (options.schemaUpdate?.length ?? 0) > 0) {
8509
8224
  const validator = options.schema;
8510
8225
  const strategies = options.schemaUpdate ?? [];
8511
8226
  const work = (async () => {
8512
8227
  const dek = await this.getDEK(collectionName);
8513
- const { persistSchemaIfNeeded } = await import("./register-X462DNDM.js");
8228
+ const { persistSchemaIfNeeded } = await import("./register-UKU2J6MN.js");
8514
8229
  const result = await persistSchemaIfNeeded({
8515
8230
  store: this.adapter,
8516
8231
  vault: this.name,
@@ -8551,22 +8266,9 @@ var Vault = class {
8551
8266
  // #693: re-create gate fallback
8552
8267
  historyConfig: effectiveHistoryConfig,
8553
8268
  historyConfigExplicit: options?.historyConfig !== void 0,
8554
- // thread the vault-wide blob strategy into every
8555
- // collection. `undefined` is intentionally preserved so the
8556
- // Collection constructor uses its NO_BLOBS default.
8557
- ...this.blobStrategy !== void 0 ? { blobStrategy: this.blobStrategy } : {},
8558
8269
  ...this.objectStore !== void 0 ? { objectStore: this.objectStore } : {},
8559
8270
  ...options?.blobFields !== void 0 ? { blobFields: options.blobFields } : {},
8560
- ...this.indexStrategy !== void 0 ? { indexStrategy: this.indexStrategy } : {},
8561
- ...this.lazyStrategy !== void 0 ? { lazyStrategy: this.lazyStrategy } : {},
8562
- ...this.aggregateStrategy !== void 0 ? { aggregateStrategy: this.aggregateStrategy } : {},
8563
- ...this.crdtStrategy !== void 0 ? { crdtStrategy: this.crdtStrategy } : {},
8564
- ...this.tiersStrategy !== void 0 ? { tiersStrategy: this.tiersStrategy } : {},
8565
- ...this.searchStrategy !== void 0 ? { searchStrategy: this.searchStrategy } : {},
8566
- historyStrategy: this.historyStrategy,
8567
- i18nStrategy: this.i18nStrategy,
8568
- syncStrategy: this.syncStrategy,
8569
- classifiedStrategy: this.classifiedStrategy,
8271
+ strategies: this.strategies,
8570
8272
  // Per-collection ledger opt-out: when this collection sets
8571
8273
  // `historyConfig.ledger: false`, withhold the ledger reference so all
8572
8274
  // four `if (this.ledger)` append sites in Collection no-op. The chain
@@ -8604,31 +8306,12 @@ var Vault = class {
8604
8306
  }
8605
8307
  } : {}
8606
8308
  };
8607
- if (options?.indexes !== void 0) collOpts.indexes = options.indexes;
8608
- if (options?.reconcileOnOpen !== void 0) collOpts.reconcileOnOpen = options.reconcileOnOpen;
8609
- if (options?.prefetch !== void 0) collOpts.prefetch = options.prefetch;
8610
- if (options?.cache !== void 0) collOpts.cache = options.cache;
8611
- if (options?.schema !== void 0) collOpts.schema = options.schema;
8612
- if (options?.conflictPolicy !== void 0) collOpts.conflictPolicy = options.conflictPolicy;
8613
- if (options?.crdt !== void 0) collOpts.crdt = options.crdt;
8614
- if (options?.deterministicFields !== void 0) {
8615
- collOpts.deterministicFields = options.deterministicFields;
8616
- }
8617
- if (options?.acknowledgeDeterministicRisk !== void 0) {
8618
- collOpts.acknowledgeDeterministicRisk = options.acknowledgeDeterministicRisk;
8619
- }
8620
- if (options?.acknowledgeEquatableRisk !== void 0) {
8621
- collOpts.acknowledgeEquatableRisk = options.acknowledgeEquatableRisk;
8622
- }
8623
- if (options?.sensitive !== void 0) {
8624
- collOpts.sensitive = options.sensitive;
8625
- }
8626
- if (options?.perRecordKeys !== void 0) collOpts.perRecordKeys = options.perRecordKeys;
8627
- const subjectKey = this.forgetStrategy.subjects[collectionName];
8309
+ copyDefined(collOpts, options, COLLECTION_PASSTHROUGH_KEYS);
8310
+ const subjectKey = this.strategies.forget.subjects[collectionName];
8628
8311
  if (subjectKey !== void 0) {
8629
8312
  if (options?.perRecordKeys === false) {
8630
8313
  console.warn(
8631
- `[noy-db] Collection "${collectionName}" is declared in withForgetCascade but opened with perRecordKeys: false. Forcing perRecordKeys: true \u2014 GDPR crypto-shred requires per-record CEKs.`
8314
+ `[noy-db] Collection "${collectionName}" is declared in withForget but opened with perRecordKeys: false. Forcing perRecordKeys: true \u2014 GDPR crypto-shred requires per-record CEKs.`
8632
8315
  );
8633
8316
  }
8634
8317
  collOpts.perRecordKeys = true;
@@ -8638,22 +8321,8 @@ var Vault = class {
8638
8321
  if (value !== void 0 && value !== null) await this._addSubjectRef(coerceSubjectId(value), { collection: collectionName, id });
8639
8322
  };
8640
8323
  }
8641
- if (options?.provenance !== void 0) collOpts.provenance = options.provenance;
8642
- if (options?.ramCiphertext !== void 0) collOpts.ramCiphertext = options.ramCiphertext;
8643
- if (options?.tiers !== void 0) collOpts.tiers = options.tiers;
8644
- if (options?.tierMode !== void 0) collOpts.tierMode = options.tierMode;
8645
- if (options?.blobTierPolicy !== void 0) collOpts.blobTierPolicy = options.blobTierPolicy;
8646
8324
  collOpts.onCrossTierAccess = (event) => this.emitCrossTier(event);
8647
8325
  if (this.syncAdapter !== void 0) collOpts.syncAdapter = this.syncAdapter;
8648
- if (options?.i18nFields !== void 0) collOpts.i18nFields = options.i18nFields;
8649
- if (options?.embeddings !== void 0) collOpts.embeddings = options.embeddings;
8650
- if (options?.textIndexes !== void 0) collOpts.textIndexes = options.textIndexes;
8651
- if (options?.warmIndexOnOpen !== void 0) collOpts.warmIndexOnOpen = options.warmIndexOnOpen;
8652
- if (options?.textIndexPersist !== void 0) collOpts.textIndexPersist = options.textIndexPersist;
8653
- if (options?.moneyFields !== void 0) collOpts.moneyFields = options.moneyFields;
8654
- if (options?.viaFields !== void 0) collOpts.viaFields = options.viaFields;
8655
- if (options?.computed !== void 0) collOpts.computed = options.computed;
8656
- if (options?.classifiedFields !== void 0) collOpts.classifiedFields = options.classifiedFields;
8657
8326
  if (effectiveViaFields.dictKeyFields !== void 0 || effectiveViaFields.lookupFields !== void 0) {
8658
8327
  collOpts.dictLabelResolver = async (dictName, key, locale, fallback) => {
8659
8328
  const stat = this.staticByName.get(dictName);
@@ -8687,10 +8356,6 @@ var Vault = class {
8687
8356
  if (effectiveViaFields.i18nFields !== void 0 && this.translateText) {
8688
8357
  collOpts.autoTranslateHook = this.translateText;
8689
8358
  }
8690
- if (options?.fieldMeta !== void 0) {
8691
- collOpts.fieldMeta = options.fieldMeta;
8692
- }
8693
- if (options?.meta !== void 0) collOpts.meta = options.meta;
8694
8359
  if (options?.refs !== void 0) {
8695
8360
  collOpts.declaredRefs = this.refRegistry.getOutbound(collectionName);
8696
8361
  }
@@ -8709,7 +8374,7 @@ var Vault = class {
8709
8374
  const work = (async () => {
8710
8375
  try {
8711
8376
  const dek = await this.getDEK(collectionName);
8712
- await (await import("./register-X462DNDM.js")).persistSchemaIfNeeded({
8377
+ await (await import("./register-UKU2J6MN.js")).persistSchemaIfNeeded({
8713
8378
  store: this.adapter,
8714
8379
  vault: this.name,
8715
8380
  collectionName,
@@ -9005,7 +8670,7 @@ var Vault = class {
9005
8670
  const values = getAtPath(obj, field);
9006
8671
  for (const value of values) {
9007
8672
  if (value === void 0 || value === null) continue;
9008
- this.i18nStrategy.validateI18nTextValue(value, field, descriptor);
8673
+ this.strategies.i18n.validateI18nTextValue(value, field, descriptor);
9009
8674
  }
9010
8675
  }
9011
8676
  }
@@ -9046,7 +8711,7 @@ var Vault = class {
9046
8711
  this.reservedLookupCollections.set(dictCollectionName(name), name);
9047
8712
  let handle = this.dictionaryCache.get(name);
9048
8713
  if (!handle) {
9049
- handle = this.i18nStrategy.buildDictionaryHandle({
8714
+ handle = this.strategies.i18n.buildDictionaryHandle({
9050
8715
  adapter: this.adapter,
9051
8716
  compartmentName: this.name,
9052
8717
  dictionaryName: name,
@@ -9207,7 +8872,7 @@ var Vault = class {
9207
8872
  * is re-keyed for distinct recipients.
9208
8873
  *
9209
8874
  * Each recipient becomes its own `KeyringFile` sealed with that
9210
- * recipient's passphrase. The DEKs wrapped into each slot are
8875
+ * recipient's secret. The DEKs wrapped into each slot are
9211
8876
  * exactly those the recipient's role + permissions justify, and
9212
8877
  * never wider than the source keyring's own DEK set
9213
8878
  * (privilege-escalation check).
@@ -9259,7 +8924,7 @@ var Vault = class {
9259
8924
  };
9260
8925
  }
9261
8926
  if (!this.sequenceStore) {
9262
- this.sequenceStore = this.sequenceStrategy.createStore({
8927
+ this.sequenceStore = this.strategies.sequence.createStore({
9263
8928
  adapter: this.adapter,
9264
8929
  vault: this.name,
9265
8930
  encrypted: this.encrypted,
@@ -9332,7 +8997,9 @@ var Vault = class {
9332
8997
  deleteSlot: async (name, id, slotName) => {
9333
8998
  const coll = this.collection(name);
9334
8999
  await coll.blob(id).delete(slotName);
9335
- }
9000
+ },
9001
+ dropLocalCache: async (name, id, slotName) => this.collection(name).blob(id).dropLocalCache(slotName)
9002
+ // #808: budget pass drops device-local external cache copies
9336
9003
  }, options);
9337
9004
  }
9338
9005
  /**
@@ -9355,7 +9022,7 @@ var Vault = class {
9355
9022
  return runListArchived(this._archiveContext(), collection);
9356
9023
  }
9357
9024
  _archiveContext() {
9358
- const strategy = this.archiveStrategy;
9025
+ const strategy = this.strategies.archive;
9359
9026
  if (!strategy) {
9360
9027
  throw new Error(
9361
9028
  "vault.archive/restore/listArchived require `archiveStrategy: withArchive({ store })` in createNoydb"
@@ -9522,7 +9189,7 @@ var Vault = class {
9522
9189
  */
9523
9190
  getLedgerOrNull() {
9524
9191
  if (!this.ledgerStore) {
9525
- this.ledgerStore = this.historyStrategy.buildLedger({
9192
+ this.ledgerStore = this.strategies.history.buildLedger({
9526
9193
  adapter: this.adapter,
9527
9194
  vault: this.name,
9528
9195
  encrypted: this.encrypted,
@@ -9547,7 +9214,7 @@ var Vault = class {
9547
9214
  * number of distinct subjects re-indexed.
9548
9215
  */
9549
9216
  async rebuildSubjectIndex() {
9550
- if (Object.keys(this.forgetStrategy.subjects).length === 0) {
9217
+ if (Object.keys(this.strategies.forget.subjects).length === 0) {
9551
9218
  throw new ForgetStrategyNotConfiguredError();
9552
9219
  }
9553
9220
  return rebuildSubjectIndex(
@@ -9555,7 +9222,7 @@ var Vault = class {
9555
9222
  this.name,
9556
9223
  this.getDEK,
9557
9224
  this.encrypted,
9558
- this.forgetStrategy.subjects,
9225
+ this.strategies.forget.subjects,
9559
9226
  async (collectionName, id, env) => {
9560
9227
  const coll = this.collection(collectionName);
9561
9228
  return coll._decodeEnvelope(env, id);
@@ -9577,10 +9244,10 @@ var Vault = class {
9577
9244
  * stay decryptable; migrate, then re-forget) and `blobResidueCollections` (blob attachments, keyed
9578
9245
  * off a separate `_blob` DEK, out of scope here).
9579
9246
  *
9580
- * @throws ForgetStrategyNotConfiguredError when no `withForgetCascade` was set.
9247
+ * @throws ForgetStrategyNotConfiguredError when no `withForget` was set.
9581
9248
  */
9582
9249
  async forget(subjectId) {
9583
- if (Object.keys(this.forgetStrategy.subjects).length === 0) {
9250
+ if (Object.keys(this.strategies.forget.subjects).length === 0) {
9584
9251
  throw new ForgetStrategyNotConfiguredError();
9585
9252
  }
9586
9253
  const ledger = this.getLedgerOrNull();
@@ -9602,17 +9269,17 @@ var Vault = class {
9602
9269
  const sealedResidue = [];
9603
9270
  const indexResidue = [];
9604
9271
  const ledgerDeltaResidue = [];
9605
- const blobsEnabled = this.blobStrategy !== void 0;
9272
+ const blobsEnabled = this.strategies.blobs !== NO_BLOBS;
9606
9273
  const actor = this.keyring.userId;
9607
9274
  const fanoutStats = { recordsErased: 0, aggregatesRecomputed: 0, residueFrozen: [], lookupReferencesCascaded: 0, lookupReferencesNullified: 0, lookupReferencesResidue: [], derivedResidueUndecodable: [], derivedResidueDeclined: [] };
9608
9275
  const { partitionSealedCekKeys, shouldSkipBlobScan, bumpResidueCount, residueNoticesFromMap } = await import("./purge-scope-FGNNLWHD.js");
9609
- const scopedPurge = this.forgetStrategy.scopedPurge === true;
9276
+ const scopedPurge = this.strategies.forget.scopedPurge === true;
9610
9277
  const sealedCekScopedSkipped = /* @__PURE__ */ new Map();
9611
9278
  const blobScopedSkipped = /* @__PURE__ */ new Map();
9612
9279
  for (const ref2 of allRefs) {
9613
9280
  const coll = this.collection(ref2.collection);
9614
9281
  const satelliteOf = ref2.satelliteOf;
9615
- const perRecordKeys = this.forgetStrategy.subjects[satelliteOf ?? ref2.collection] !== void 0;
9282
+ const perRecordKeys = this.strategies.forget.subjects[satelliteOf ?? ref2.collection] !== void 0;
9616
9283
  const lookupCompareKeys = await this.linksEnforcer.checkLookupRefsRestrict(this.graph, ref2.collection, ref2.collection, ref2.id);
9617
9284
  const live = await this.adapter.get(this.name, ref2.collection, ref2.id);
9618
9285
  if (perRecordKeys && live && live._data && !hasPerRecordKey(live)) {
@@ -9672,7 +9339,7 @@ var Vault = class {
9672
9339
  collections.add(ref2.collection);
9673
9340
  await forgetDerivedFanout(this, { collection: ref2.collection, id: ref2.id }, live, fanoutStats, lookupCompareKeys);
9674
9341
  }
9675
- historyVersionsShredded += await this.historyStrategy.tombstoneHistory(
9342
+ historyVersionsShredded += await this.strategies.history.tombstoneHistory(
9676
9343
  this.adapter,
9677
9344
  this.name,
9678
9345
  ref2.collection,
@@ -9802,7 +9469,7 @@ var Vault = class {
9802
9469
  * `<collection>/<id>/<pid>` key the delivery envelope was written under.
9803
9470
  */
9804
9471
  async sealRecordToHost(collection, id, hostSealer, opts) {
9805
- return this.sealedRecordStrategy.sealRecordToHost(this._sealingContext(), collection, id, hostSealer, opts);
9472
+ return this.strategies.sealedRecord.sealRecordToHost(this._sealingContext(), collection, id, hostSealer, opts);
9806
9473
  }
9807
9474
  /**
9808
9475
  * Revoke a sealed-CEK grant. **Default is SOFT**: deletes the `pid` delivery
@@ -9812,7 +9479,7 @@ var Vault = class {
9812
9479
  * longer open the record. See `revokeSealedRecord` in `record-keys/sealing.ts`.
9813
9480
  */
9814
9481
  async revokeSealedRecord(collection, id, pid, opts) {
9815
- return this.sealedRecordStrategy.revokeSealedRecord(this._sealingContext(), collection, id, pid, opts);
9482
+ return this.strategies.sealedRecord.revokeSealedRecord(this._sealingContext(), collection, id, pid, opts);
9816
9483
  }
9817
9484
  /**
9818
9485
  * HARD-rotate a record's CEK: decrypt the live body under the old CEK,
@@ -9832,7 +9499,7 @@ var Vault = class {
9832
9499
  * @throws {@link RecordCekNotFoundError} if the record is missing or has no `_cek`.
9833
9500
  */
9834
9501
  async rotateRecordCek(collection, id) {
9835
- return this.sealedRecordStrategy.rotateRecordCek(this._sealingContext(), collection, id);
9502
+ return this.strategies.sealedRecord.rotateRecordCek(this._sealingContext(), collection, id);
9836
9503
  }
9837
9504
  /**
9838
9505
  * Build the {@link SealingContext} the record-keys grantor functions need:
@@ -9866,7 +9533,7 @@ var Vault = class {
9866
9533
  async _initGuards(handles) {
9867
9534
  if (handles.length === 0) return;
9868
9535
  const [{ GuardRegistry }, { ReadOnlyVaultFacade }] = await Promise.all([
9869
- import("./registry-VW6P6A3J.js"),
9536
+ import("./registry-BWD2ED52.js"),
9870
9537
  import("./read-only-facade-CHCKSEPD.js")
9871
9538
  ]);
9872
9539
  const registry = new GuardRegistry();
@@ -9894,7 +9561,7 @@ var Vault = class {
9894
9561
  async _initDerivations(handles) {
9895
9562
  if (handles.length === 0) return;
9896
9563
  const [{ DerivationRegistry }, { ReadOnlyVaultFacade }] = await Promise.all([
9897
- import("./registry-3XMCT7MQ.js"),
9564
+ import("./registry-DTWRJLSF.js"),
9898
9565
  import("./read-only-facade-CHCKSEPD.js")
9899
9566
  ]);
9900
9567
  const registry = new DerivationRegistry();
@@ -9926,7 +9593,7 @@ var Vault = class {
9926
9593
  */
9927
9594
  async _initMaterializedViews(handles) {
9928
9595
  if (handles.length === 0) return;
9929
- const { MaterializedViewRegistry } = await import("./registry-KHD2I3M2.js");
9596
+ const { MaterializedViewRegistry } = await import("./registry-2VCWVHZS.js");
9930
9597
  const registry = new MaterializedViewRegistry();
9931
9598
  this.materializedViewRegistry = registry;
9932
9599
  const db = this;
@@ -9951,7 +9618,7 @@ var Vault = class {
9951
9618
  */
9952
9619
  async _initOverlayedViews(handles) {
9953
9620
  if (handles.length === 0) return;
9954
- const { OverlayedViewRegistry } = await import("./registry-NPOWJHC4.js");
9621
+ const { OverlayedViewRegistry } = await import("./registry-7Y5WF7GS.js");
9955
9622
  const registry = new OverlayedViewRegistry();
9956
9623
  const mvRegistry = this.materializedViewRegistry;
9957
9624
  const overlayNames = /* @__PURE__ */ new Set();
@@ -9998,14 +9665,14 @@ var Vault = class {
9998
9665
  if (!reg) {
9999
9666
  throw new Error(`refreshView: no MV registered with name "${name}"`);
10000
9667
  }
10001
- const { MaterializedViewExecutor } = await import("./executor-AXE4XMLT.js");
9668
+ const { MaterializedViewExecutor } = await import("./executor-OTF556PL.js");
10002
9669
  const result = await MaterializedViewExecutor.refresh(reg, {
10003
9670
  getCollection: (n) => this.collection(n),
10004
9671
  getActiveTxContext: () => this.noydb._activeTxContextOrNull,
10005
9672
  getQueryContext: () => this,
10006
9673
  dispatchCtx: this._dispatchCtx({ collection: name, id: "refreshView" })
10007
9674
  });
10008
- const { clearMVStaleFully } = await import("./stale-FJED42DM.js");
9675
+ const { clearMVStaleFully } = await import("./stale-A4J26OIC.js");
10009
9676
  await clearMVStaleFully(this.adapter, this.name, registry, name);
10010
9677
  return result;
10011
9678
  }
@@ -10018,7 +9685,7 @@ var Vault = class {
10018
9685
  if (registry === null) return { derived: 0, failed: 0, skippedFrozen: 0 };
10019
9686
  const strategies = registry.strategiesForSource(sourceCollection);
10020
9687
  if (strategies.length === 0) return { derived: 0, failed: 0, skippedFrozen: 0 };
10021
- const { DerivationExecutor } = await import("./executor-XGIS6CR7.js");
9688
+ const { DerivationExecutor } = await import("./executor-IEBLTBCW.js");
10022
9689
  const sourceColl = this.collection(sourceCollection);
10023
9690
  const records = await sourceColl.list();
10024
9691
  const ctx = { vault: this.derivationFacade ?? new (await import("./read-only-facade-CHCKSEPD.js")).ReadOnlyVaultFacade(this, "derivation") };
@@ -10045,7 +9712,7 @@ var Vault = class {
10045
9712
  if (!outSpec) continue;
10046
9713
  const outputColl = this.collection(outSpec.collection);
10047
9714
  if (out.kind === "array") {
10048
- const { loadFanoutSidecar, saveFanoutSidecar } = await import("./fanout-sidecar-WDYQ77VB.js");
9715
+ const { loadFanoutSidecar, saveFanoutSidecar } = await import("./fanout-sidecar-SSMRSC2L.js");
10049
9716
  const prior = await loadFanoutSidecar(this.adapter, this.name, spec.source, id, key, this.getDEK, this.encrypted);
10050
9717
  const prevKeys = new Set(prior?.keys ?? []);
10051
9718
  const newKeysList = out.entries.map((e) => e.key);
@@ -10139,7 +9806,7 @@ var Vault = class {
10139
9806
  */
10140
9807
  at(timestamp) {
10141
9808
  const iso = timestamp instanceof Date ? timestamp.toISOString() : timestamp;
10142
- return this.historyStrategy.buildVaultInstant(
9809
+ return this.strategies.history.buildVaultInstant(
10143
9810
  {
10144
9811
  adapter: this.adapter,
10145
9812
  name: this.name,
@@ -10171,11 +9838,11 @@ var Vault = class {
10171
9838
  *.
10172
9839
  */
10173
9840
  frame() {
10174
- return this.shadowStrategy.buildFrame(this);
9841
+ return this.strategies.shadow.buildFrame(this);
10175
9842
  }
10176
9843
  /** Credential-broker handle (#479); `NO_BROKER` throws unless `brokerStrategy: withBroker(config)` was passed to createNoydb(). */
10177
9844
  broker() {
10178
- return buildCredentialBrokerHandle(this.brokerStrategy, this.adapter, this.name, () => this.keyring);
9845
+ return buildCredentialBrokerHandle(this.strategies.broker, this.adapter, this.name, () => this.keyring);
10179
9846
  }
10180
9847
  /**
10181
9848
  * Run `fn` under a consent scope. Every `get` / `put` / `delete`
@@ -10200,11 +9867,11 @@ var Vault = class {
10200
9867
  *
10201
9868
  *.
10202
9869
  */
10203
- async withConsent(ctx, fn2) {
9870
+ async withConsent(ctx, fn) {
10204
9871
  const prior = this.consentContext;
10205
9872
  this.consentContext = ctx;
10206
9873
  try {
10207
- return await fn2();
9874
+ return await fn();
10208
9875
  } finally {
10209
9876
  this.consentContext = prior;
10210
9877
  }
@@ -10217,7 +9884,7 @@ var Vault = class {
10217
9884
  *.
10218
9885
  */
10219
9886
  async consentAudit(filter = {}) {
10220
- return this.consentStrategy.read(this.adapter, this.name, this.encrypted, this.getDEK, filter);
9887
+ return this.strategies.consent.read(this.adapter, this.name, this.encrypted, this.getDEK, filter);
10221
9888
  }
10222
9889
  /**
10223
9890
  * Called by Collection after every access when a consent scope is
@@ -10228,7 +9895,7 @@ var Vault = class {
10228
9895
  async _logConsent(op, collection, recordId) {
10229
9896
  const ctx = this.consentContext;
10230
9897
  if (!ctx) return;
10231
- await this.consentStrategy.write(
9898
+ await this.strategies.consent.write(
10232
9899
  this.adapter,
10233
9900
  this.name,
10234
9901
  this.encrypted,
@@ -10272,10 +9939,10 @@ var Vault = class {
10272
9939
  * collection.
10273
9940
  */
10274
9941
  async delegate(opts) {
10275
- const { issueDelegation, DELEGATIONS_COLLECTION } = await import("./delegation-A5A75KQO.js");
9942
+ const { issueDelegation, DELEGATIONS_COLLECTION } = await import("./delegation-QXZ4MPPH.js");
10276
9943
  if (!this.keyring.kek) {
10277
9944
  throw new ValidationError(
10278
- "issueDelegation: keyring.kek is null \u2014 issuing a delegation requires a tier-1 unlock. Re-authenticate at tier 1 (passphrase) first."
9945
+ "issueDelegation: keyring.kek is null \u2014 issuing a delegation requires a tier-1 unlock. Re-authenticate at tier 1 (secret) first."
10279
9946
  );
10280
9947
  }
10281
9948
  const targetKek = this.keyring.kek;
@@ -10294,7 +9961,7 @@ var Vault = class {
10294
9961
  * if the id does not exist.
10295
9962
  */
10296
9963
  async revokeDelegation(id) {
10297
- const { revokeDelegation, DELEGATIONS_COLLECTION } = await import("./delegation-A5A75KQO.js");
9964
+ const { revokeDelegation, DELEGATIONS_COLLECTION } = await import("./delegation-QXZ4MPPH.js");
10298
9965
  await revokeDelegation(this.adapter, this.name, id);
10299
9966
  void DELEGATIONS_COLLECTION;
10300
9967
  }
@@ -10542,7 +10209,7 @@ var Vault = class {
10542
10209
  * @see docs/superpowers/specs/2026-05-22-schema-dump-design.md
10543
10210
  */
10544
10211
  async dumpSchema(opts = {}) {
10545
- const { dumpVaultSchema } = await import("./walk-XS3PKM6I.js");
10212
+ const { dumpVaultSchema } = await import("./walk-P5D6CF4V.js");
10546
10213
  return dumpVaultSchema(this, opts);
10547
10214
  }
10548
10215
  /**
@@ -10677,13 +10344,9 @@ var Vault = class {
10677
10344
  * @see https://github.com/vLannaAi/noy-db-docs/blob/main/content/docs/services/public-envelope.md
10678
10345
  */
10679
10346
  async getCover(opts = {}) {
10680
- const { readCover } = await import("./cover-B5SJDHR3.js");
10347
+ const { readCover } = await import("./cover/index.js");
10681
10348
  return readCover(this.adapter, this.name, opts);
10682
10349
  }
10683
- /** @deprecated Use {@link Vault.getCover} (#799 rename). */
10684
- async getPublicEnvelope(opts = {}) {
10685
- return this.getCover(opts);
10686
- }
10687
10350
  /**
10688
10351
  * Dump vault as a verifiable encrypted JSON backup string.
10689
10352
  *
@@ -10696,7 +10359,7 @@ var Vault = class {
10696
10359
  * both modes round-trip cleanly.
10697
10360
  */
10698
10361
  async dump() {
10699
- const { dumpVault } = await import("./backup-LU2DTZTI.js");
10362
+ const { dumpVault } = await import("./backup-2UX7PRM5.js");
10700
10363
  return dumpVault(this.backupContext());
10701
10364
  }
10702
10365
  /**
@@ -10711,7 +10374,7 @@ var Vault = class {
10711
10374
  vault: this.name,
10712
10375
  userId: () => this.keyring.userId,
10713
10376
  getLedgerOrNull: () => this.getLedgerOrNull(),
10714
- envelopePayloadHash: (envelope) => this.historyStrategy.envelopePayloadHash(envelope),
10377
+ envelopePayloadHash: (envelope) => this.strategies.history.envelopePayloadHash(envelope),
10715
10378
  reloadKeyringAndRebuildDEK: async () => {
10716
10379
  if (this.reloadKeyring) {
10717
10380
  this.keyring = await this.reloadKeyring();
@@ -10748,7 +10411,7 @@ var Vault = class {
10748
10411
  * — there's no chain to verify against.
10749
10412
  */
10750
10413
  async load(backupJson) {
10751
- const { loadVault } = await import("./backup-LU2DTZTI.js");
10414
+ const { loadVault } = await import("./backup-2UX7PRM5.js");
10752
10415
  return loadVault(this.backupContext(), backupJson);
10753
10416
  }
10754
10417
  /**
@@ -10780,7 +10443,7 @@ var Vault = class {
10780
10443
  * way to detect tampering of an in-place vault.
10781
10444
  */
10782
10445
  async verifyBackupIntegrity() {
10783
- const { verifyBackupIntegrity } = await import("./backup-LU2DTZTI.js");
10446
+ const { verifyBackupIntegrity } = await import("./backup-2UX7PRM5.js");
10784
10447
  return verifyBackupIntegrity(this.backupContext());
10785
10448
  }
10786
10449
  /**
@@ -10998,7 +10661,7 @@ var Vault = class {
10998
10661
  * is the live validator object, not a serialization of it).
10999
10662
  */
11000
10663
  async exportJSON(opts = {}) {
11001
- const { exportVaultJSON } = await import("./backup-LU2DTZTI.js");
10664
+ const { exportVaultJSON } = await import("./backup-2UX7PRM5.js");
11002
10665
  return exportVaultJSON(this.backupContext(), opts);
11003
10666
  }
11004
10667
  };
@@ -11075,10 +10738,10 @@ var WriteQueueTracker = class {
11075
10738
  * (success or failure). The fn's resolved value is returned; a thrown
11076
10739
  * error is re-thrown after the queue is decremented.
11077
10740
  */
11078
- async track(fn2) {
10741
+ async track(fn) {
11079
10742
  this.begin();
11080
10743
  try {
11081
- const value = await fn2();
10744
+ const value = await fn();
11082
10745
  this.settle();
11083
10746
  return value;
11084
10747
  } catch (error) {
@@ -11101,7 +10764,184 @@ var WriteQueueTracker = class {
11101
10764
  }
11102
10765
  };
11103
10766
 
11104
- // src/with-party/tab-coordination.ts
10767
+ // src/port/with/write-hooks.ts
10768
+ var WriteHookRegistry = class {
10769
+ #before = [];
10770
+ #after = [];
10771
+ #suppressed = false;
10772
+ /** True while handlers are running — used by the write path to skip nested firing. */
10773
+ get suppressed() {
10774
+ return this.#suppressed;
10775
+ }
10776
+ /** True when any hook is registered (cheap gate for the write path). */
10777
+ get hasHandlers() {
10778
+ return this.#before.length > 0 || this.#after.length > 0;
10779
+ }
10780
+ onBeforeWrite(handler) {
10781
+ this.#before.push(handler);
10782
+ return () => {
10783
+ const i = this.#before.indexOf(handler);
10784
+ if (i >= 0) this.#before.splice(i, 1);
10785
+ };
10786
+ }
10787
+ onAfterWrite(handler) {
10788
+ this.#after.push(handler);
10789
+ return () => {
10790
+ const i = this.#after.indexOf(handler);
10791
+ if (i >= 0) this.#after.splice(i, 1);
10792
+ };
10793
+ }
10794
+ /** Run before-hooks (awaited, in order). A throw propagates and aborts the write. */
10795
+ async runBefore(event) {
10796
+ if (this.#before.length === 0) return;
10797
+ this.#suppressed = true;
10798
+ try {
10799
+ for (const h of this.#before.slice()) await h(event);
10800
+ } finally {
10801
+ this.#suppressed = false;
10802
+ }
10803
+ }
10804
+ /** Run after-hooks (awaited, in order). Per-handler errors are warned, not thrown. */
10805
+ async runAfter(event) {
10806
+ if (this.#after.length === 0) return;
10807
+ this.#suppressed = true;
10808
+ try {
10809
+ for (const h of this.#after.slice()) {
10810
+ try {
10811
+ await h(event);
10812
+ } catch (err) {
10813
+ console.warn(
10814
+ `[noy-db] onAfterWrite handler failed for ${event.collection}/${event.docId}: ` + (err instanceof Error ? err.message : String(err))
10815
+ );
10816
+ }
10817
+ }
10818
+ } finally {
10819
+ this.#suppressed = false;
10820
+ }
10821
+ }
10822
+ };
10823
+
10824
+ // src/port/with/service-bus.ts
10825
+ var ServiceBus = class {
10826
+ #handlers = /* @__PURE__ */ new Map();
10827
+ #gateHandlers = /* @__PURE__ */ new Map();
10828
+ #depth = 0;
10829
+ /** Register a handler for an observe point. Returns an unsubscribe fn. */
10830
+ register(point, handler) {
10831
+ let arr = this.#handlers.get(point);
10832
+ if (!arr) {
10833
+ arr = [];
10834
+ this.#handlers.set(point, arr);
10835
+ }
10836
+ arr.push(handler);
10837
+ return () => {
10838
+ const a = this.#handlers.get(point);
10839
+ if (!a) return;
10840
+ const i = a.indexOf(handler);
10841
+ if (i >= 0) a.splice(i, 1);
10842
+ };
10843
+ }
10844
+ /** Cheap gate for the write path — true when any handler is registered for the point. */
10845
+ hasHandlers(point) {
10846
+ const a = this.#handlers.get(point);
10847
+ return a !== void 0 && a.length > 0;
10848
+ }
10849
+ /**
10850
+ * True while one or more dispatches are in flight. Backed by a depth counter
10851
+ * so that two concurrent async dispatches (`Promise.all([put('a'), put('b')])`
10852
+ * each captured `busAfterPut=true` at their respective put() tops while depth
10853
+ * was 0) both proceed independently — the counter stays > 0 until BOTH finish,
10854
+ * so any nested write attempted by a handler still sees `dispatching === true`
10855
+ * and is suppressed by the write-path gate in `collection.ts`
10856
+ * (`busAfterPut = hasHandlers('afterPut') && !dispatching`). Re-entrancy
10857
+ * suppression lives exclusively on that write-path gate; concurrent independent
10858
+ * dispatches must not drop each other's events.
10859
+ */
10860
+ get dispatching() {
10861
+ return this.#depth > 0;
10862
+ }
10863
+ /**
10864
+ * Dispatch in registration order, awaited. Per-handler errors are warned, not
10865
+ * thrown — an observe handler must never abort a completed write. A
10866
+ * re-entrancy guard suppresses nested firing so a handler that itself writes
10867
+ * cannot loop (same rationale as WriteHookRegistry.#suppressed).
10868
+ */
10869
+ async dispatch(point, event) {
10870
+ const a = this.#handlers.get(point);
10871
+ if (!a || a.length === 0) return;
10872
+ this.#depth++;
10873
+ try {
10874
+ for (const h of a.slice()) {
10875
+ try {
10876
+ await h(event);
10877
+ } catch (err) {
10878
+ console.warn(
10879
+ `[noy-db] service observe handler failed at ${point}: ` + (err instanceof Error ? err.message : String(err))
10880
+ );
10881
+ }
10882
+ }
10883
+ } finally {
10884
+ this.#depth--;
10885
+ }
10886
+ }
10887
+ /**
10888
+ * Register a write-gating handler. A throw from the handler ABORTS the
10889
+ * write. Returns an unsubscribe fn. See {@link GateRegisterOptions} for
10890
+ * the `needsPrior` prior-read declaration (#267).
10891
+ */
10892
+ registerGate(point, handler, opts) {
10893
+ let arr = this.#gateHandlers.get(point);
10894
+ if (!arr) {
10895
+ arr = [];
10896
+ this.#gateHandlers.set(point, arr);
10897
+ }
10898
+ const entry = { fn: handler, needsPrior: opts?.needsPrior !== false };
10899
+ arr.push(entry);
10900
+ return () => {
10901
+ const a = this.#gateHandlers.get(point);
10902
+ if (!a) return;
10903
+ const i = a.indexOf(entry);
10904
+ if (i >= 0) a.splice(i, 1);
10905
+ };
10906
+ }
10907
+ /** Cheap gate for the write path — true when any gate handler is registered for the point. */
10908
+ hasGateHandlers(point) {
10909
+ const a = this.#gateHandlers.get(point);
10910
+ return a !== void 0 && a.length > 0;
10911
+ }
10912
+ /**
10913
+ * True when at least one gate handler at `point` needs the prior record
10914
+ * (the default). False when the point has no handlers or every handler
10915
+ * registered with `needsPrior: false` — the write path then skips the
10916
+ * prior-read before dispatching (#267 prior-read elision).
10917
+ */
10918
+ gateNeedsPrior(point) {
10919
+ const a = this.#gateHandlers.get(point);
10920
+ if (!a) return false;
10921
+ return a.some((e) => e.needsPrior);
10922
+ }
10923
+ /**
10924
+ * Run gate handlers in registration order, awaited. Unlike `dispatch`
10925
+ * (observe), a handler throw is NOT swallowed — it PROPAGATES, aborting the
10926
+ * write before it reaches the store. The first throw stops the remaining
10927
+ * handlers (fail-fast). This is the seam guards/periods migrate onto.
10928
+ *
10929
+ * Note: gate handlers are validators that read, not write. A gate handler
10930
+ * that writes back into the same collection would re-enter the write path
10931
+ * and re-dispatch this point; loop-suppression for that case is deferred to
10932
+ * the migration slice (contract: gate handlers must not perform writes that
10933
+ * re-trigger their own point).
10934
+ */
10935
+ async dispatchGate(point, event) {
10936
+ const a = this.#gateHandlers.get(point);
10937
+ if (!a || a.length === 0) return;
10938
+ for (const e of a.slice()) {
10939
+ await e.fn(event);
10940
+ }
10941
+ }
10942
+ };
10943
+
10944
+ // src/with-sync/tab-coordination.ts
11105
10945
  var TabCoordinator = class {
11106
10946
  tabId;
11107
10947
  role = "unknown";
@@ -11163,13 +11003,13 @@ var TabCoordinator = class {
11163
11003
  const out = [self, ...[...this.#peers.values()].filter((p) => p.lastSeen >= cutoff)];
11164
11004
  return out.sort((a, b) => a.tabId.localeCompare(b.tabId));
11165
11005
  }
11166
- onTabRoleChange(fn2) {
11167
- this.#roleHandlers.add(fn2);
11168
- return () => this.#roleHandlers.delete(fn2);
11006
+ onTabRoleChange(fn) {
11007
+ this.#roleHandlers.add(fn);
11008
+ return () => this.#roleHandlers.delete(fn);
11169
11009
  }
11170
- onActiveTabsChange(fn2) {
11171
- this.#tabsHandlers.add(fn2);
11172
- return () => this.#tabsHandlers.delete(fn2);
11010
+ onActiveTabsChange(fn) {
11011
+ this.#tabsHandlers.add(fn);
11012
+ return () => this.#tabsHandlers.delete(fn);
11173
11013
  }
11174
11014
  dispose() {
11175
11015
  if (this.#disposed) return;
@@ -11282,7 +11122,7 @@ function defaultChannel(name = "noydb:tabs") {
11282
11122
  };
11283
11123
  }
11284
11124
 
11285
- // src/with-party/tab-write-relay.ts
11125
+ // src/with-sync/tab-write-relay.ts
11286
11126
  var CrossTabWriteRelay = class {
11287
11127
  #channel;
11288
11128
  #writerId;
@@ -11396,25 +11236,6 @@ var QuickUnlockStore = class {
11396
11236
  }
11397
11237
  };
11398
11238
 
11399
- // src/with-fork/snapshots/strategy.ts
11400
- var NOT_ENABLED4 = new Error(
11401
- 'Snapshots require the snapshot strategy. Import `{ withSnapshots }` from "@noy-db/hub/snapshots" and pass it to `createNoydb({ snapshotStrategy: withSnapshots({ store }) })`.'
11402
- );
11403
- var NO_SNAPSHOTS = {
11404
- async snapshot() {
11405
- throw NOT_ENABLED4;
11406
- },
11407
- async listSnapshots() {
11408
- throw NOT_ENABLED4;
11409
- },
11410
- async restoreSnapshot() {
11411
- throw NOT_ENABLED4;
11412
- },
11413
- async autoSnapshot() {
11414
- throw NOT_ENABLED4;
11415
- }
11416
- };
11417
-
11418
11239
  // src/with-fork/snapshots/scheduler.ts
11419
11240
  var SnapshotScheduler = class {
11420
11241
  policy;
@@ -11536,7 +11357,7 @@ var NoydbSnapshots = class {
11536
11357
  dirtyVaults = /* @__PURE__ */ new Set();
11537
11358
  /**
11538
11359
  * Take an on-demand checkpoint of the given vault.
11539
- * Requires `snapshotStrategy: withSnapshots({ store })` in `createNoydb`.
11360
+ * Requires `snapshotsStrategy: withSnapshots({ store })` in `createNoydb`.
11540
11361
  * @throws ValidationError when the vault is not open
11541
11362
  */
11542
11363
  async snapshot(vault, opts) {
@@ -11615,19 +11436,6 @@ var NoydbSnapshots = class {
11615
11436
  }
11616
11437
  };
11617
11438
 
11618
- // src/with-commit/tx/strategy.ts
11619
- var NOT_ENABLED5 = new Error(
11620
- 'Multi-record transactions require the tx strategy. Import `{ withTransactions }` from "@noy-db/hub/tx" and pass it to `createNoydb({ txStrategy: withTransactions() })`.'
11621
- );
11622
- var NO_TX = {
11623
- async runTransaction(_db, _fn, _options, _txInvariants) {
11624
- throw NOT_ENABLED5;
11625
- },
11626
- async runDryRun() {
11627
- throw NOT_ENABLED5;
11628
- }
11629
- };
11630
-
11631
11439
  // src/kernel/memory-store.ts
11632
11440
  function memoryStore() {
11633
11441
  const store = /* @__PURE__ */ new Map();
@@ -11711,146 +11519,6 @@ function memoryStore() {
11711
11519
  };
11712
11520
  }
11713
11521
 
11714
- // src/with-party/session/strategy.ts
11715
- function notEnabled3(op) {
11716
- return new Error(
11717
- `${op} requires the session strategy. Import \`{ withSession }\` from "@noy-db/hub/session" and pass it to \`createNoydb({ sessionStrategy: withSession() })\`.`
11718
- );
11719
- }
11720
- var NO_SESSION = {
11721
- validateSessionPolicy() {
11722
- throw notEnabled3("sessionPolicy");
11723
- },
11724
- createEnforcer() {
11725
- throw notEnabled3("session policy enforcement");
11726
- },
11727
- revokeAllSessions() {
11728
- }
11729
- };
11730
-
11731
- // src/with-party/auth-introspection/index.ts
11732
- async function describeAuthConfig(store, vault) {
11733
- const policy = await loadVaultPolicy(store, vault) ?? defaultPolicySnapshot();
11734
- const recoveryProfiles = await listRecoveryProfilesEnrolled(store, vault);
11735
- const lines = [];
11736
- lines.push(`Vault "${vault}" \u2014 three-tier authentication`);
11737
- lines.push("");
11738
- lines.push("Tier 1 \u2014 Passphrase (master)");
11739
- lines.push(` Phrase format: ${policy.passphrase?.minWords ?? 6}+ words, lowercase letters, \u2265${policy.passphrase?.minWordLength ?? 3} chars/word`);
11740
- lines.push(" Strength validator: enforced (override available for tests only)");
11741
- lines.push("");
11742
- lines.push("Tier 2 \u2014 Authenticate (routine login)");
11743
- lines.push(" Allowed methods: WebAuthn (passkey), OIDC, Password");
11744
- lines.push(" Slots per user: unlimited");
11745
- lines.push("");
11746
- lines.push("Tier 3 \u2014 Unlock (quick resume)");
11747
- lines.push(" Method: PIN (per-app configurable)");
11748
- lines.push("");
11749
- lines.push(`Recovery profiles enrolled: ${recoveryProfiles.length === 0 ? "none" : recoveryProfiles.join(", ")}`);
11750
- lines.push("Managed-passphrase mode: off (post-1.0)");
11751
- lines.push("");
11752
- lines.push("Sensitive-action gates:");
11753
- for (const [gate, gp] of Object.entries(policy.gates)) {
11754
- lines.push(` ${gate} \u2014 ${describeGatePolicy(gp)}`);
11755
- }
11756
- return lines.join("\n");
11757
- }
11758
- async function diagramAuthConfig(store, vault) {
11759
- const policy = await loadVaultPolicy(store, vault) ?? defaultPolicySnapshot();
11760
- const lines = [];
11761
- lines.push("flowchart TB");
11762
- lines.push(` vault["Vault: ${escapeMermaid(vault)}"]`);
11763
- lines.push(' tier1["Tier 1<br/>Passphrase"]');
11764
- lines.push(' tier2["Tier 2<br/>Multi-slot Authenticate"]');
11765
- lines.push(' tier3["Tier 3<br/>PIN / Quick-resume"]');
11766
- lines.push(" vault --> tier1");
11767
- lines.push(" tier1 --> tier2");
11768
- lines.push(" tier2 --> tier3");
11769
- for (const [gateName, gp] of Object.entries(policy.gates)) {
11770
- if (gp.enabled === false) continue;
11771
- const id = sanitizeId(gateName);
11772
- const label = `${gateName}<br/>tier \u2265 ${gp.minTier}`;
11773
- lines.push(` ${id}["${escapeMermaid(label)}"]`);
11774
- const tierNode = gp.minTier === 1 ? "tier1" : gp.minTier === 2 ? "tier2" : "tier3";
11775
- lines.push(` ${tierNode} --> ${id}`);
11776
- }
11777
- return lines.join("\n");
11778
- }
11779
- async function describeUserAuth(store, vault, userId) {
11780
- const env = await store.get(vault, "_keyring", userId);
11781
- if (!env) return "";
11782
- const file = JSON.parse(env._data);
11783
- const lines = [];
11784
- lines.push(
11785
- `User: ${file.user_id} (joined ${file.created_at.slice(0, 10)}, role: ${file.role})`
11786
- );
11787
- lines.push("");
11788
- lines.push("Tier 2 enrollments:");
11789
- if (!file.authenticators || file.authenticators.length === 0) {
11790
- lines.push(" (none enrolled)");
11791
- } else {
11792
- for (const slot of file.authenticators) {
11793
- lines.push(` - ${describeSlot(slot)}`);
11794
- }
11795
- }
11796
- return lines.join("\n");
11797
- }
11798
- async function describeAllUsersAuth(store, vault) {
11799
- const ids = await store.list(vault, "_keyring");
11800
- const results = [];
11801
- for (const userId of ids) {
11802
- const description = await describeUserAuth(store, vault, userId);
11803
- if (description !== "") results.push({ userId, description });
11804
- }
11805
- return results;
11806
- }
11807
- var SLOT_FIELD_ALLOWLIST = [
11808
- "id",
11809
- "method",
11810
- "enrolled_at",
11811
- "enrolled_via_tier"
11812
- ];
11813
- function describeSlot(slot) {
11814
- const sanitized = {};
11815
- for (const key of SLOT_FIELD_ALLOWLIST) {
11816
- if (key in slot) {
11817
- sanitized[key] = slot[key];
11818
- }
11819
- }
11820
- const date = (sanitized.enrolled_at ?? "").slice(0, 10);
11821
- return `${sanitized.method ?? "?"} (id=${sanitized.id ?? "?"}, enrolled ${date}, via tier ${sanitized.enrolled_via_tier ?? "?"})`;
11822
- }
11823
- function describeGatePolicy(gp) {
11824
- if (gp.enabled === false) return "disabled";
11825
- const parts = [];
11826
- parts.push(`tier ${gp.minTier}`);
11827
- if (gp.factors && gp.factors.length > 0) {
11828
- for (const f of gp.factors) {
11829
- parts.push(`+ ${f.count ?? 1}\xD7 ${f.anyOf.join("|")}`);
11830
- }
11831
- }
11832
- if (gp.warn?.sharedDevice === "block") parts.push("block-on-shared-device");
11833
- return parts.join(" ");
11834
- }
11835
- function defaultPolicySnapshot() {
11836
- return {
11837
- passphrase: { minWords: 6, minWordLength: 3, rejectRepeatedAdjacent: true },
11838
- gates: {}
11839
- };
11840
- }
11841
- async function listRecoveryProfilesEnrolled(store, vault) {
11842
- const enrolled = [];
11843
- const paper = await loadPaperRecoveryEntries(store, vault);
11844
- if (paper.length > 0) enrolled.push(`paper (${paper.length} codes)`);
11845
- return enrolled;
11846
- }
11847
- function escapeMermaid(s) {
11848
- return s.replace(/"/g, '\\"').replace(/\n/g, " ");
11849
- }
11850
- function sanitizeId(s) {
11851
- return s.replace(/[^a-zA-Z0-9]/g, "_");
11852
- }
11853
-
11854
11522
  // src/with-party/team/noydb-facade.ts
11855
11523
  var TeamFacade = class {
11856
11524
  constructor(deps) {
@@ -11892,8 +11560,9 @@ var TeamFacade = class {
11892
11560
  async runRotate(engine, vault, collections) {
11893
11561
  this.deps.checkPolicyOperation(vault, "rotate");
11894
11562
  const keyring = await this.deps.getKeyringInternal(vault);
11895
- await engine(this.deps.options.store, vault, keyring, collections);
11563
+ const result = await engine(this.deps.options.store, vault, keyring, { collections });
11896
11564
  this.deps.keyringCache.set(vault, keyring);
11565
+ return result;
11897
11566
  }
11898
11567
  // ─── Tier-2 enroll / remove ─────────────────────────────────────
11899
11568
  /**
@@ -11984,7 +11653,7 @@ var TeamFacade = class {
11984
11653
  * ```ts
11985
11654
  * import { enrollWebAuthn } from '@noy-db/on-webauthn'
11986
11655
  *
11987
- * await db.enrollWebAuthn('demo', async (keyring) => {
11656
+ * await db.team.enrollWebAuthn('demo', async (keyring) => {
11988
11657
  * const e = await enrollWebAuthn(keyring, 'demo', { rp: {...} })
11989
11658
  * return {
11990
11659
  * id: `webauthn-${e.credentialId.slice(0, 8)}`,
@@ -12013,7 +11682,7 @@ var TeamFacade = class {
12013
11682
  const slotOptions = await ceremony(keyring);
12014
11683
  if (slotOptions.method !== "webauthn") {
12015
11684
  throw new ValidationError(
12016
- `enrollWebAuthn: ceremony returned method "${slotOptions.method}"; expected "webauthn". Use db.enrollAuthenticator() for non-webauthn methods.`
11685
+ `enrollWebAuthn: ceremony returned method "${slotOptions.method}"; expected "webauthn". Use db.team.enrollAuthenticator() for non-webauthn methods.`
12017
11686
  );
12018
11687
  }
12019
11688
  const credentialId = slotOptions.meta.credentialId;
@@ -12091,44 +11760,44 @@ var TeamFacade = class {
12091
11760
  }
12092
11761
  // ─── Tier-1 change flows ────────────────────────────────────────
12093
11762
  /**
12094
- * Rotate the user's passphrase (user remembers old). Validates the
12095
- * new phrase against the configured `passphrase` policy, runs the
12096
- * `rotate-passphrase` gate, then re-derives + re-wraps every DEK.
11763
+ * Rotate the user's secret (user remembers old). Validates the
11764
+ * new phrase against the configured `secret` policy, runs the
11765
+ * `rotate-secret` gate, then re-derives + re-wraps every DEK.
12097
11766
  *
12098
11767
  * Tier-2 authenticator slots are dropped — each slot wraps the old
12099
11768
  * KEK and would need its derivation key to be re-presented. Re-enrol
12100
11769
  * via `db.enrollAuthenticator` after rotation.
12101
11770
  *
12102
- * @throws `WeakPassphraseError` on a weak new phrase.
11771
+ * @throws `WeakSecretError` on a weak new phrase.
12103
11772
  * @throws `PolicyDeniedError` when the gate denies (missing factor, …).
12104
- * @throws `InvalidKeyError` when `oldPassphrase` is wrong.
11773
+ * @throws `InvalidKeyError` when `oldSecret` is wrong.
12105
11774
  */
12106
- async rotatePassphrase(vault, input, factors) {
12107
- if (this.deps.options.passphraseMode === "managed") {
11775
+ async rotateSecret(vault, input, factors) {
11776
+ if (this.deps.options.secretMode === "managed") {
12108
11777
  throw new PolicyDeniedError(
12109
- "rotate-passphrase",
11778
+ "rotate-secret",
12110
11779
  "disabled",
12111
11780
  { minTier: 1, enabled: false },
12112
- "Managed-passphrase mode (#14): the passphrase is hub-generated and sealed under the SealingKeyProvider \u2014 there is no plaintext to rotate. Use the recovery flow (follow-up issue) to mint a fresh sealed passphrase."
11781
+ "Managed-secret mode (#14): the secret is hub-generated and sealed under the SealingKeyProvider \u2014 there is no plaintext to rotate. Use the recovery flow (follow-up issue) to mint a fresh sealed secret."
12113
11782
  );
12114
11783
  }
12115
- await this.deps.checkGate(vault, "rotate-passphrase", factors);
11784
+ await this.deps.checkGate(vault, "rotate-secret", factors);
12116
11785
  const userId = this.deps.options.user;
12117
- const next = await rotatePassphrase(this.deps.options.store, vault, userId, input);
11786
+ const next = await rotateSecret(this.deps.options.store, vault, userId, input);
12118
11787
  this.deps.keyringCache.set(vault, next);
12119
11788
  }
12120
11789
  /**
12121
- * Reset the passphrase using a recovery proof (user forgot the old).
11790
+ * Reset the secret using a recovery proof (user forgot the old).
12122
11791
  * Currently supports the `'paper'` profile end-to-end; the
12123
11792
  * other profiles throw {@link RecoveryProfileNotImplementedError}.
12124
11793
  *
12125
11794
  * Burns the used recovery entry on success.
12126
11795
  */
12127
- async recoverPassphrase(vault, input, factors) {
12128
- await this.deps.checkGate(vault, "recover-passphrase", factors);
11796
+ async recoverSecret(vault, input, factors) {
11797
+ await this.deps.checkGate(vault, "recover-secret", factors);
12129
11798
  const userId = this.deps.options.user;
12130
11799
  const entriesBeforeRecovery = await loadPaperRecoveryEntries(this.deps.options.store, vault);
12131
- const next = await recoverPassphrase(this.deps.options.shamirRecovery, this.deps.options.store, vault, userId, input);
11800
+ const next = await recoverSecret(this.deps.options.shamirRecovery, this.deps.options.store, vault, userId, input);
12132
11801
  this.deps.keyringCache.set(vault, next);
12133
11802
  const rotateRemaining = input.rotateRemainingCodes ?? true;
12134
11803
  const remainingAfterBurn = Math.max(0, entriesBeforeRecovery.length - 1);
@@ -12150,15 +11819,15 @@ var TeamFacade = class {
12150
11819
  }
12151
11820
  /**
12152
11821
  * Deliberate paper-recovery-code regeneration. User knows their
12153
- * passphrase but wants a fresh sheet — they lost the printout or
11822
+ * secret but wants a fresh sheet — they lost the printout or
12154
11823
  * suspect compromise of the off-site copy.
12155
11824
  *
12156
- * Symmetric to {@link rotatePassphrase} for the recovery profile:
11825
+ * Symmetric to {@link rotateSecret} for the recovery profile:
12157
11826
  * gated, audit-trackable, ergonomic. Replaces (not appends) the
12158
11827
  * paper sheet under `_meta/recovery-paper` in a single envelope `put`.
12159
11828
  *
12160
11829
  * Gated by the `rotate-recovery` policy gate:
12161
- * - PERSONAL_POLICY: `{ minTier: 1 }` — knowing the passphrase
11830
+ * - PERSONAL_POLICY: `{ minTier: 1 }` — knowing the secret
12162
11831
  * suffices, matching the lower-level flow's bar.
12163
11832
  * - STRICT_POLICY: `{ minTier: 1, factors: [{ anyOf: ['totp',
12164
11833
  * 'email-otp', 'webauthn-roaming'] }] }` — rotation is an
@@ -12178,13 +11847,13 @@ var TeamFacade = class {
12178
11847
  *
12179
11848
  * @example Default count + show-once UI
12180
11849
  * ```ts
12181
- * const { newCodes } = await db.rotateRecovery('acme', { profile: 'paper' })
11850
+ * const { newCodes } = await db.team.rotateRecovery('acme', { profile: 'paper' })
12182
11851
  * showCodesToUser(newCodes)
12183
11852
  * ```
12184
11853
  *
12185
11854
  * @example STRICT-policy site with TOTP factor proof
12186
11855
  * ```ts
12187
- * await db.rotateRecovery(
11856
+ * await db.team.rotateRecovery(
12188
11857
  * 'acme',
12189
11858
  * { profile: 'paper', count: 10 },
12190
11859
  * { factors: [{ kind: 'totp', proof: '123456' }] },
@@ -12208,7 +11877,7 @@ var TeamFacade = class {
12208
11877
  const existing = await loadPaperRecoveryEntries(this.deps.options.store, vault);
12209
11878
  if (existing.length === 0) {
12210
11879
  throw new Error(
12211
- `db.rotateRecovery: no recovery codes are enrolled for vault "${vault}". Call db.enrollRecovery({ profile: 'paper', entries }) first; rotateRecovery replaces an existing sheet rather than minting one from scratch.`
11880
+ `db.rotateRecovery: no recovery codes are enrolled for vault "${vault}". Call db.team.enrollRecovery({ profile: 'paper', entries }) first; rotateRecovery replaces an existing sheet rather than minting one from scratch.`
12212
11881
  );
12213
11882
  }
12214
11883
  const keyring = await this.getKeyring(vault);
@@ -12230,7 +11899,7 @@ var TeamFacade = class {
12230
11899
  const existing = await loadShamirRecoveryEntries(this.deps.options.store, vault);
12231
11900
  if (existing.length === 0) {
12232
11901
  throw new Error(
12233
- `db.rotateRecovery: no Shamir recovery entry is enrolled for vault "${vault}". Call db.enrollRecovery({ profile: 'shamir', k, n }) first; rotateRecovery replaces an existing entry rather than minting one from scratch.`
11902
+ `db.rotateRecovery: no Shamir recovery entry is enrolled for vault "${vault}". Call db.team.enrollRecovery({ profile: 'shamir', k, n }) first; rotateRecovery replaces an existing entry rather than minting one from scratch.`
12234
11903
  );
12235
11904
  }
12236
11905
  let targetEntryId;
@@ -12267,7 +11936,7 @@ var TeamFacade = class {
12267
11936
  * **Atomic create-and-enroll for managed-mode vaults.**
12268
11937
  *
12269
11938
  * Bootstraps a managed-mode vault and enrolls strong recovery in
12270
- * a single ceremony. Under `passphraseMode: 'managed'`, every
11939
+ * a single ceremony. Under `secretMode: 'managed'`, every
12271
11940
  * `openVault` call requires a strong recovery profile (Shamir
12272
11941
  * today) to be enrolled — otherwise it throws
12273
11942
  * {@link ManagedRecoveryNotEnrolledError}. This method bypasses
@@ -12286,11 +11955,11 @@ var TeamFacade = class {
12286
11955
  * ```ts
12287
11956
  * const db = await createNoydb({
12288
11957
  * store, user: 'alice',
12289
- * passphraseMode: 'managed',
11958
+ * secretMode: 'managed',
12290
11959
  * sealingKey: macosKeychainSealingProvider({ ... }),
12291
11960
  * })
12292
11961
  *
12293
- * const { vault, recoveryEnrollments } = await db.openVaultAndEnrollRecovery('acme', {
11962
+ * const { vault, recoveryEnrollments } = await db.team.openVaultAndEnrollRecovery('acme', {
12294
11963
  * recovery: [{ profile: 'shamir', k: 2, n: 3 }],
12295
11964
  * })
12296
11965
  * for (const r of recoveryEnrollments) {
@@ -12307,11 +11976,11 @@ var TeamFacade = class {
12307
11976
  "openVaultAndEnrollRecovery: at least one recovery enrollment is required."
12308
11977
  );
12309
11978
  }
12310
- if (this.deps.options.passphraseMode === "managed") {
11979
+ if (this.deps.options.secretMode === "managed") {
12311
11980
  const hasStrong = opts.recovery.some((r) => r.profile === "shamir");
12312
11981
  if (!hasStrong) {
12313
11982
  throw new ValidationError(
12314
- 'openVaultAndEnrollRecovery: managed-mode vaults require at least one strong recovery profile in the `recovery` array. Paper alone is not strong under managed mode (no user passphrase to fall back on). Include { profile: "shamir", k, n } in `recovery`.'
11983
+ 'openVaultAndEnrollRecovery: managed-mode vaults require at least one strong recovery profile in the `recovery` array. Paper alone is not strong under managed mode (no user secret to fall back on). Include { profile: "shamir", k, n } in `recovery`.'
12315
11984
  );
12316
11985
  }
12317
11986
  }
@@ -12326,7 +11995,7 @@ var TeamFacade = class {
12326
11995
  for (const enrollment of opts.recovery) {
12327
11996
  recoveryEnrollments.push(await this.enrollRecovery(vault, enrollment));
12328
11997
  }
12329
- if (this.deps.options.passphraseMode === "managed") {
11998
+ if (this.deps.options.secretMode === "managed") {
12330
11999
  const policy = this.deps.policyCache.get(vault);
12331
12000
  if (policy) {
12332
12001
  await this.deps.assertRecoveryEnrolled(vault, policy);
@@ -12335,20 +12004,20 @@ var TeamFacade = class {
12335
12004
  return { vault: vaultHandle, recoveryEnrollments };
12336
12005
  }
12337
12006
  /**
12338
- * **Recovery flow under managed-passphrase mode.**
12007
+ * **Recovery flow under managed-secret mode.**
12339
12008
  *
12340
- * Replaces the sealed passphrase of a managed-mode vault with a
12009
+ * Replaces the sealed secret of a managed-mode vault with a
12341
12010
  * fresh 256-bit random, sealed under the configured
12342
- * `SealingKeyProvider`. The user never sees the new passphrase.
12011
+ * `SealingKeyProvider`. The user never sees the new secret.
12343
12012
  *
12344
12013
  * Internally:
12345
12014
  * 1. Verify the recovery proof (Shamir today) and unwrap the
12346
12015
  * DEK set.
12347
- * 2. Mint a fresh 256-bit random as the new effective passphrase.
12016
+ * 2. Mint a fresh 256-bit random as the new effective secret.
12348
12017
  * 3. Rewrap the DEK set under a fresh KEK derived from the new
12349
- * passphrase (via the existing `recoverPassphrase` path).
12018
+ * secret (via the existing `recoverSecret` path).
12350
12019
  * 4. Seal the random bytes under the provider and overwrite
12351
- * `_meta/sealed-passphrase`.
12020
+ * `_meta/sealed-secret`.
12352
12021
  * 5. Drop the keyring cache so the next operation re-derives.
12353
12022
  *
12354
12023
  * The vault's strong-recovery enrollment is preserved across
@@ -12356,40 +12025,40 @@ var TeamFacade = class {
12356
12025
  *
12357
12026
  * @throws ValidationError if the Noydb instance is not in managed mode.
12358
12027
  */
12359
- async recoverManagedPassphrase(vault, options) {
12360
- if (this.deps.options.passphraseMode !== "managed") {
12028
+ async recoverManagedSecret(vault, options) {
12029
+ if (this.deps.options.secretMode !== "managed") {
12361
12030
  throw new ValidationError(
12362
- "recoverManagedPassphrase: this method only applies to vaults opened in managed-passphrase mode. For standard mode, use db.recoverPassphrase."
12031
+ "recoverManagedSecret: this method only applies to vaults opened in managed-secret mode. For standard mode, use db.recoverSecret."
12363
12032
  );
12364
12033
  }
12365
12034
  const provider = this.deps.options.sealingKey;
12366
12035
  if (!provider) {
12367
12036
  throw new ValidationError(
12368
- 'recoverManagedPassphrase: createNoydb({ passphraseMode: "managed" }) requires `sealingKey` to be supplied; without it the new sealed passphrase cannot be persisted.'
12037
+ 'recoverManagedSecret: createNoydb({ secretMode: "managed" }) requires `sealingKey` to be supplied; without it the new sealed secret cannot be persisted.'
12369
12038
  );
12370
12039
  }
12371
12040
  const randomBytes = new Uint8Array(32);
12372
12041
  globalThis.crypto.getRandomValues(randomBytes);
12373
12042
  let binary = "";
12374
12043
  for (let i = 0; i < randomBytes.length; i++) binary += String.fromCharCode(randomBytes[i]);
12375
- const newPassphrase = btoa(binary);
12044
+ const newSecret = btoa(binary);
12376
12045
  try {
12377
12046
  const sealed = await provider.seal(randomBytes);
12378
- await recoverPassphrase(
12047
+ await recoverSecret(
12379
12048
  this.deps.options.shamirRecovery,
12380
12049
  this.deps.options.store,
12381
12050
  vault,
12382
12051
  this.deps.options.user,
12383
12052
  {
12384
- newPassphrase,
12053
+ newSecret,
12385
12054
  recoveryProof: options.recoveryProof,
12386
- // The new passphrase IS 256 bits of random; policy gates on
12055
+ // The new secret IS 256 bits of random; policy gates on
12387
12056
  // length/entropy don't apply.
12388
- allowWeakPassphrase: true,
12389
- ...options.passphrasePolicy !== void 0 ? { passphrasePolicy: options.passphrasePolicy } : {}
12057
+ allowWeakSecret: true,
12058
+ ...options.secretPolicy !== void 0 ? { secretPolicy: options.secretPolicy } : {}
12390
12059
  }
12391
12060
  );
12392
- await saveSealedPassphrase(this.deps.options.store, vault, {
12061
+ await saveSealedSecret(this.deps.options.store, vault, {
12393
12062
  providerId: provider.id,
12394
12063
  sealed
12395
12064
  });
@@ -12400,7 +12069,7 @@ var TeamFacade = class {
12400
12069
  }
12401
12070
  /**
12402
12071
  * Atomic peer-recovery — re-wraps an EXISTING user's keyring under
12403
- * a fresh temp passphrase in a single store write. Closes the
12072
+ * a fresh temp secret in a single store write. Closes the
12404
12073
  * partial-failure window (the previous compose-from-primitives
12405
12074
  * pattern was `db.revoke + db.grant`, two writes — if the issuer
12406
12075
  * cancelled between them the target was locked out entirely).
@@ -12419,17 +12088,17 @@ var TeamFacade = class {
12419
12088
  * recovery / TOTP / email-OTP factor proof at the moment of
12420
12089
  * recovery, so the issuer affirmatively re-asserts identity.
12421
12090
  *
12422
- * The recipient should call `db.rotatePassphrase` on first session
12091
+ * The recipient should call `db.rotateSecret` on first session
12423
12092
  * to choose their own phrase — the temp acts as a single-use
12424
12093
  * bridge.
12425
12094
  *
12426
12095
  * ```ts
12427
- * await db.recoverUser('acme', {
12096
+ * await db.team.recoverUser('acme', {
12428
12097
  * userId: 'bob',
12429
- * passphrase: 'temporary-correct-horse-battery-staple-printer',
12098
+ * secret: 'temporary-correct-horse-battery-staple-printer',
12430
12099
  * }, { factors: [{ kind: 'recovery' }] })
12431
12100
  * // Bob opens createNoydb({ user: 'bob', secret: tempPhrase })
12432
- * // and immediately calls db.rotatePassphrase to set his own.
12101
+ * // and immediately calls db.rotateSecret to set his own.
12433
12102
  * ```
12434
12103
  *
12435
12104
  * @throws `NoAccessError` when no keyring exists for the target.
@@ -12455,17 +12124,17 @@ var TeamFacade = class {
12455
12124
  * The hub wraps the user's DEK set (not the KEK) under a code-derived
12456
12125
  * AES-GCM key — see `team/recovery.ts` for the rationale. The mint
12457
12126
  * helper {@link mintPaperRecoveryEntry} is the canonical primitive;
12458
- * pair it with `db.getKeyring(vault)` to obtain the live DEK set:
12127
+ * pair it with `db.team.getKeyring(vault)` to obtain the live DEK set:
12459
12128
  *
12460
12129
  * ```ts
12461
12130
  * import { mintPaperRecoveryEntry } from '@noy-db/hub'
12462
12131
  *
12463
- * const keyring = await db.getKeyring('acme')
12132
+ * const keyring = await db.team.getKeyring('acme')
12464
12133
  * const codes: string[] = ['CORRECT-HORSE-1', 'BATTERY-STAPLE-2', ...]
12465
12134
  * const entries = await Promise.all(
12466
12135
  * codes.map((code, i) => mintPaperRecoveryEntry(keyring.deks, code, `code-${i}`)),
12467
12136
  * )
12468
- * await db.enrollRecovery('acme', { profile: 'paper', entries })
12137
+ * await db.team.enrollRecovery('acme', { profile: 'paper', entries })
12469
12138
  * showCodesToUser(codes)
12470
12139
  * ```
12471
12140
  *
@@ -12476,7 +12145,7 @@ var TeamFacade = class {
12476
12145
  * ```ts
12477
12146
  * import { generateRecoveryCodeSet } from '@noy-db/on-recovery'
12478
12147
  * const { codes, entries } = await generateRecoveryCodeSet({ deks: keyring.deks, count: 8 })
12479
- * await db.enrollRecovery('acme', { profile: 'paper', entries })
12148
+ * await db.team.enrollRecovery('acme', { profile: 'paper', entries })
12480
12149
  * ```
12481
12150
  */
12482
12151
  async enrollRecovery(vault, enrollment) {
@@ -12576,7 +12245,7 @@ var TeamFacade = class {
12576
12245
  * and no `secret` / `getKeyring` is configured.
12577
12246
  *
12578
12247
  * ```ts
12579
- * const keyring = await db.getKeyring('acme')
12248
+ * const keyring = await db.team.getKeyring('acme')
12580
12249
  * // keyring.deks: Map<collection, CryptoKey>
12581
12250
  * // keyring.kek: CryptoKey | null (null for tier-3 / wrap-DEKs sessions)
12582
12251
  * // keyring.role / .permissions / .authenticators
@@ -12653,7 +12322,7 @@ var Noydb = class {
12653
12322
  keyringCache = /* @__PURE__ */ new Map();
12654
12323
  syncEngines = /* @__PURE__ */ new Map();
12655
12324
  /**
12656
- * Per-vault active session tier — defaults to `1` after a passphrase
12325
+ * Per-vault active session tier — defaults to `1` after a secret
12657
12326
  * unlock; tier-2 / tier-3 unlocks downgrade it. Used by
12658
12327
  * {@link checkGate} to evaluate `gate.minTier`.
12659
12328
  */
@@ -12681,26 +12350,43 @@ var Noydb = class {
12681
12350
  writeRelay;
12682
12351
  /** Per-vault policy enforcers. */
12683
12352
  policyEnforcers = /* @__PURE__ */ new Map();
12684
- txStrategy;
12685
- forgetStrategy;
12686
12353
  /**
12687
- * Opt-in sovereign-custody (FR-6) strategy — `NO_CUSTODY` (throwing) unless
12688
- * `withCustody()` was passed. Public so `Vault` routes `vault.custody.liberate`
12689
- * through it; grant/revoke route through it from this class. @internal
12354
+ * Every opt-in service, resolved once (#838). Shared by reference with each
12355
+ * `Vault` this instance opens and, through them, every `Collection` — so
12356
+ * there is exactly one resolution and no construction path can disagree
12357
+ * about which services are enabled (the #834 bug class).
12690
12358
  */
12691
- custodyStrategy;
12359
+ strategies;
12692
12360
  /**
12693
- * Opt-in multi-user team strategy (#267 keyring-grant → team split) —
12694
- * `NO_TEAM` (throwing) unless `withTeam()` was passed; the keyring
12695
- * engines are linked only by the active strategy, not by this file. */
12696
- teamStrategy;
12697
- sessionStrategy;
12698
- syncStrategy;
12361
+ * Opt-in sovereign-custody (FR-6) strategy — `NO_CUSTODY` (throwing) unless
12362
+ * `withCustody()` was passed. Kept as a public accessor because `Vault`
12363
+ * routes `vault.custody.liberate` through `this.noydb.custodyStrategy`.
12364
+ * @internal
12365
+ */
12366
+ get custodyStrategy() {
12367
+ return this.strategies.custody;
12368
+ }
12699
12369
  snapshots;
12700
12370
  policyManager;
12701
12371
  /** Pre-resolved policy-gate engine function (mirrors `coordinationProvider`/`userApiFactory` above). */
12702
12372
  policyCheckGate;
12703
- team;
12373
+ /**
12374
+ * Credential and multi-user operations — enrolment, secret rotation,
12375
+ * recovery, quick-unlock (#846).
12376
+ *
12377
+ * Public because 23 methods on this class did nothing but restate a
12378
+ * TeamFacade signature and forward to it, so every signature had to be
12379
+ * hand-kept in sync with its counterpart. `db.team.rotateSecret(…)`
12380
+ * reads the same and has one source of truth.
12381
+ *
12382
+ * A getter, not a field, so it appears in the prototype-based kernel API
12383
+ * manifest — an instance field is invisible to it (the same reason
12384
+ * `custodyStrategy` became one in #838).
12385
+ */
12386
+ get team() {
12387
+ return this.#team;
12388
+ }
12389
+ #team;
12704
12390
  /**
12705
12391
  * Currently-running multi-record transaction, set by
12706
12392
  * `runTransaction` at the start of Phase 2 (commit) and cleared in
@@ -12739,14 +12425,9 @@ var Noydb = class {
12739
12425
  this.userApiFactory = options.userApiFactory;
12740
12426
  if (!options.policyFactory || !options.policyCheckGateFn) throw new ValidationError("Noydb must be constructed via createNoydb(), which resolves the default policy service.");
12741
12427
  this.policyCheckGate = options.policyCheckGateFn;
12742
- this.txStrategy = options.txStrategy ?? NO_TX;
12743
- this.forgetStrategy = options.forgetStrategy ?? NO_FORGET;
12744
- this.custodyStrategy = options.custodyStrategy ?? NO_CUSTODY;
12745
- this.teamStrategy = options.teamStrategy ?? NO_TEAM;
12746
- this.sessionStrategy = options.sessionStrategy ?? NO_SESSION;
12747
- this.syncStrategy = options.syncStrategy ?? NO_SYNC;
12428
+ this.strategies = resolveStrategies(options);
12748
12429
  this.snapshots = new NoydbSnapshots({
12749
- strategy: options.snapshotStrategy ?? NO_SNAPSHOTS,
12430
+ strategy: this.strategies.snapshots,
12750
12431
  user: options.user,
12751
12432
  isClosed: () => this.closed,
12752
12433
  getVault: (name) => this.vaultCache.get(name),
@@ -12767,7 +12448,7 @@ var Noydb = class {
12767
12448
  this.vaultCache.delete(vault);
12768
12449
  }
12769
12450
  });
12770
- this.team = new TeamFacade({
12451
+ this.#team = new TeamFacade({
12771
12452
  options: this.options,
12772
12453
  keyringCache: this.keyringCache,
12773
12454
  activeTier: this.activeTier,
@@ -12783,7 +12464,7 @@ var Noydb = class {
12783
12464
  }
12784
12465
  });
12785
12466
  if (options.sessionPolicy) {
12786
- this.sessionStrategy.validateSessionPolicy(options.sessionPolicy);
12467
+ this.strategies.session.validateSessionPolicy(options.sessionPolicy);
12787
12468
  }
12788
12469
  this.#registerGuardGate();
12789
12470
  this.#registerPeriodGate();
@@ -12792,9 +12473,9 @@ var Noydb = class {
12792
12473
  }
12793
12474
  /** @internal — resolved forget strategy (NO_FORGET when not configured). */
12794
12475
  get _forgetStrategy() {
12795
- return this.forgetStrategy;
12476
+ return this.strategies.forget;
12796
12477
  }
12797
- // GDPR subject-index maintenance. When `withForgetCascade` declares
12478
+ // GDPR subject-index maintenance. When `withForget` declares
12798
12479
  // any subject fields, keep the encrypted `_subject_index` in lock-step with
12799
12480
  // writes so `vault.forget(subjectId)` can find every record for a subject.
12800
12481
  //
@@ -12805,7 +12486,7 @@ var Noydb = class {
12805
12486
  // does NOT) — drop the ref so a deleted record never lingers in the
12806
12487
  // index (RISK #2). Without it, forget() would try to shred a ghost.
12807
12488
  #registerForgetHooks() {
12808
- const subjects = this.forgetStrategy.subjects;
12489
+ const subjects = this.strategies.forget.subjects;
12809
12490
  if (Object.keys(subjects).length === 0) return;
12810
12491
  const subjectFieldFor = (collection) => subjects[collection];
12811
12492
  this.writeHooks.onAfterWrite(async (event) => {
@@ -12869,7 +12550,7 @@ var Noydb = class {
12869
12550
  if (!facade) return;
12870
12551
  const ctx = { existing, vault: facade, userId: e.userId, role: e.role };
12871
12552
  await registry.runChecks(e.collection, incoming, ctx);
12872
- const { GuardExecutor } = await import("./executor-KGNLJD6M.js");
12553
+ const { GuardExecutor } = await import("./executor-RM7XWQDU.js");
12873
12554
  for (const g of guards) {
12874
12555
  await GuardExecutor.checkFrozenFields(g, e.docId, existing, incoming, e.computedFieldNames);
12875
12556
  }
@@ -12993,8 +12674,9 @@ var Noydb = class {
12993
12674
  const targets = normalizeSyncTargets(this.options.sync);
12994
12675
  if (targets.length > 0) {
12995
12676
  const primary = targets.find((t) => t.role === "sync-peer") ?? targets[0];
12996
- const effectivePolicy = this.options.syncPolicy ?? primary.policy ?? INDEXED_STORE_POLICY;
12997
- syncEngine = this.syncStrategy.buildSyncEngine({
12677
+ const declaredPolicy = this.options.syncPolicy ?? primary.policy;
12678
+ const effectivePolicy = declaredPolicy ?? INDEXED_STORE_POLICY;
12679
+ syncEngine = this.strategies.sync.buildSyncEngine({
12998
12680
  local: this.options.store,
12999
12681
  remote: primary.store,
13000
12682
  vault: name,
@@ -13005,10 +12687,11 @@ var Noydb = class {
13005
12687
  ...primary.label !== void 0 ? { label: primary.label } : {}
13006
12688
  });
13007
12689
  this.syncEngines.set(name, syncEngine);
12690
+ if (declaredPolicy) syncEngine.startScheduler();
13008
12691
  for (const target of targets) {
13009
12692
  if (target === primary) continue;
13010
12693
  const targetPolicy = target.policy ?? this.options.syncPolicy ?? INDEXED_STORE_POLICY;
13011
- const engine = this.syncStrategy.buildSyncEngine({
12694
+ const engine = this.strategies.sync.buildSyncEngine({
13012
12695
  local: this.options.store,
13013
12696
  remote: target.store,
13014
12697
  vault: name,
@@ -13020,6 +12703,7 @@ var Noydb = class {
13020
12703
  });
13021
12704
  const key = `${name}::${target.label ?? target.role}`;
13022
12705
  this.syncEngines.set(key, engine);
12706
+ if (target.policy ?? this.options.syncPolicy) engine.startScheduler();
13023
12707
  }
13024
12708
  }
13025
12709
  const comp = new Vault({
@@ -13041,31 +12725,14 @@ var Noydb = class {
13041
12725
  syncAdapter: targets.length > 0 ? targets[0].store : void 0,
13042
12726
  getPurgeableTargets: () => targets.filter((t) => t.role === "backup" || t.role === "archive").map((t) => ({ store: t.store, role: t.role, ...t.label !== void 0 ? { label: t.label } : {} })),
13043
12727
  historyConfig: this.options.history,
13044
- ...this.options.blobStrategy !== void 0 ? { blobStrategy: this.options.blobStrategy } : {},
12728
+ // #838 — the 21 conditional strategy spreads that used to live here are
12729
+ // one shared reference. This block is where #834's drift happened: a
12730
+ // copy of it silently omitted six strategies, and there was nothing to
12731
+ // catch that. There is no longer a per-service line to omit.
12732
+ strategies: this.strategies,
13045
12733
  ...this.options.objectStore !== void 0 ? { objectStore: this.options.objectStore } : {},
13046
- ...this.options.archiveStrategy !== void 0 ? { archiveStrategy: this.options.archiveStrategy } : {},
13047
- ...this.options.indexStrategy !== void 0 ? { indexStrategy: this.options.indexStrategy } : {},
13048
- ...this.options.lazyStrategy !== void 0 ? { lazyStrategy: this.options.lazyStrategy } : {},
13049
- ...this.options.aggregateStrategy !== void 0 ? { aggregateStrategy: this.options.aggregateStrategy } : {},
13050
- ...this.options.crdtStrategy !== void 0 ? { crdtStrategy: this.options.crdtStrategy } : {},
13051
- ...this.options.tiersStrategy !== void 0 ? { tiersStrategy: this.options.tiersStrategy } : {},
13052
- ...this.options.searchStrategy !== void 0 ? { searchStrategy: this.options.searchStrategy } : {},
13053
- ...this.options.cargoStrategy !== void 0 ? { cargoStrategy: this.options.cargoStrategy } : {},
13054
- ...this.options.brokerStrategy !== void 0 ? { brokerStrategy: this.options.brokerStrategy } : {},
13055
- ...this.options.consentStrategy !== void 0 ? { consentStrategy: this.options.consentStrategy } : {},
13056
- ...this.options.periodsStrategy !== void 0 ? { periodsStrategy: this.options.periodsStrategy } : {},
13057
- ...this.options.shadowStrategy !== void 0 ? { shadowStrategy: this.options.shadowStrategy } : {},
13058
- ...this.options.historyStrategy !== void 0 ? { historyStrategy: this.options.historyStrategy } : {},
13059
- ...this.options.i18nStrategy !== void 0 ? { i18nStrategy: this.options.i18nStrategy } : {},
13060
- ...this.options.syncStrategy !== void 0 ? { syncStrategy: this.options.syncStrategy } : {},
13061
12734
  ...this.options.guardStrategies !== void 0 ? { guardStrategies: this.options.guardStrategies } : {},
13062
12735
  ...this.options.numbering !== void 0 ? { numberingConfigs: this.options.numbering } : {},
13063
- forgetStrategy: this.forgetStrategy,
13064
- ...this.options.attestationStrategy !== void 0 ? { attestationStrategy: this.options.attestationStrategy } : {},
13065
- ...this.options.classifiedStrategy !== void 0 ? { classifiedStrategy: this.options.classifiedStrategy } : {},
13066
- ...this.options.sealedRecordStrategy !== void 0 ? { sealedRecordStrategy: this.options.sealedRecordStrategy } : {},
13067
- ...this.options.portabilityStrategy !== void 0 ? { portabilityStrategy: this.options.portabilityStrategy } : {},
13068
- ...this.options.sequenceStrategy !== void 0 ? { sequenceStrategy: this.options.sequenceStrategy } : {},
13069
12736
  locale: opts?.locale,
13070
12737
  ...opts?.meta !== void 0 ? { meta: opts.meta } : {},
13071
12738
  // Thread the translator hook so Collection.put() can invoke it
@@ -13077,12 +12744,10 @@ var Noydb = class {
13077
12744
  // compartments leave it null and load() skips the refresh.
13078
12745
  reloadKeyring: this.options.encrypt !== false && this.options.secret ? async () => {
13079
12746
  this.keyringCache.delete(name);
13080
- const refreshed = await loadKeyring(
13081
- this.options.store,
13082
- name,
13083
- this.options.user,
13084
- this.options.secret
13085
- );
12747
+ const refreshed = await loadKeyring(this.options.store, name, {
12748
+ userId: this.options.user,
12749
+ secret: this.options.secret
12750
+ });
13086
12751
  this.keyringCache.set(name, refreshed);
13087
12752
  return refreshed;
13088
12753
  } : void 0
@@ -13102,85 +12767,25 @@ var Noydb = class {
13102
12767
  this.vaultCache.set(name, comp);
13103
12768
  return comp;
13104
12769
  }
13105
- /** Synchronous vault access (must call openVault first, or auto-opens). */
12770
+ /**
12771
+ * Synchronous access to an ALREADY-OPEN vault.
12772
+ *
12773
+ * Returns the instance `openVault()` produced, or throws — it never
12774
+ * constructs. It used to fall back to building a Vault itself (once for
12775
+ * plaintext, once for encrypted-with-cached-keyring), and those copies
12776
+ * drifted from the real open path: the encrypted one silently omitted six
12777
+ * strategies, so a vault reached this way threw `*NotEnabledError` for
12778
+ * services the caller had configured (#834). Both fallbacks also skipped
12779
+ * the async registry init and schema-fence snapshot that `openVault`
12780
+ * performs, which a synchronous method cannot await. One construction
12781
+ * path is the only way that divergence stays fixed.
12782
+ */
13106
12783
  vault(name) {
13107
12784
  const cached = this.vaultCache.get(name);
13108
12785
  if (cached) return cached;
13109
- if (this.options.encrypt === false) {
13110
- const keyring2 = createPlaintextKeyring(this.options.user, this.options.debugPlaintext === true);
13111
- const comp2 = new Vault({
13112
- adapter: this.options.store,
13113
- name,
13114
- noydb: this,
13115
- keyring: keyring2,
13116
- encrypted: false,
13117
- emitter: this.emitter,
13118
- historyConfig: this.options.history,
13119
- ...this.options.blobStrategy !== void 0 ? { blobStrategy: this.options.blobStrategy } : {},
13120
- ...this.options.objectStore !== void 0 ? { objectStore: this.options.objectStore } : {},
13121
- ...this.options.archiveStrategy !== void 0 ? { archiveStrategy: this.options.archiveStrategy } : {},
13122
- ...this.options.indexStrategy !== void 0 ? { indexStrategy: this.options.indexStrategy } : {},
13123
- ...this.options.lazyStrategy !== void 0 ? { lazyStrategy: this.options.lazyStrategy } : {},
13124
- ...this.options.aggregateStrategy !== void 0 ? { aggregateStrategy: this.options.aggregateStrategy } : {},
13125
- ...this.options.crdtStrategy !== void 0 ? { crdtStrategy: this.options.crdtStrategy } : {},
13126
- ...this.options.tiersStrategy !== void 0 ? { tiersStrategy: this.options.tiersStrategy } : {},
13127
- ...this.options.searchStrategy !== void 0 ? { searchStrategy: this.options.searchStrategy } : {},
13128
- ...this.options.cargoStrategy !== void 0 ? { cargoStrategy: this.options.cargoStrategy } : {},
13129
- ...this.options.brokerStrategy !== void 0 ? { brokerStrategy: this.options.brokerStrategy } : {},
13130
- ...this.options.consentStrategy !== void 0 ? { consentStrategy: this.options.consentStrategy } : {},
13131
- ...this.options.periodsStrategy !== void 0 ? { periodsStrategy: this.options.periodsStrategy } : {},
13132
- ...this.options.shadowStrategy !== void 0 ? { shadowStrategy: this.options.shadowStrategy } : {},
13133
- ...this.options.historyStrategy !== void 0 ? { historyStrategy: this.options.historyStrategy } : {},
13134
- ...this.options.i18nStrategy !== void 0 ? { i18nStrategy: this.options.i18nStrategy } : {},
13135
- ...this.options.syncStrategy !== void 0 ? { syncStrategy: this.options.syncStrategy } : {},
13136
- ...this.options.guardStrategies !== void 0 ? { guardStrategies: this.options.guardStrategies } : {},
13137
- ...this.options.numbering !== void 0 ? { numberingConfigs: this.options.numbering } : {},
13138
- forgetStrategy: this.forgetStrategy,
13139
- ...this.options.attestationStrategy !== void 0 ? { attestationStrategy: this.options.attestationStrategy } : {},
13140
- ...this.options.classifiedStrategy !== void 0 ? { classifiedStrategy: this.options.classifiedStrategy } : {},
13141
- ...this.options.sealedRecordStrategy !== void 0 ? { sealedRecordStrategy: this.options.sealedRecordStrategy } : {},
13142
- ...this.options.portabilityStrategy !== void 0 ? { portabilityStrategy: this.options.portabilityStrategy } : {},
13143
- ...this.options.sequenceStrategy !== void 0 ? { sequenceStrategy: this.options.sequenceStrategy } : {}
13144
- });
13145
- this.vaultCache.set(name, comp2);
13146
- return comp2;
13147
- }
13148
- const keyring = this.keyringCache.get(name);
13149
- if (!keyring) {
13150
- throw new ValidationError(
13151
- `Vault "${name}" not opened. Use await db.openVault("${name}") first.`
13152
- );
13153
- }
13154
- const comp = new Vault({
13155
- adapter: this.options.store,
13156
- name,
13157
- noydb: this,
13158
- keyring,
13159
- encrypted: true,
13160
- historyConfig: this.options.history,
13161
- ...this.options.blobStrategy !== void 0 ? { blobStrategy: this.options.blobStrategy } : {},
13162
- ...this.options.objectStore !== void 0 ? { objectStore: this.options.objectStore } : {},
13163
- ...this.options.archiveStrategy !== void 0 ? { archiveStrategy: this.options.archiveStrategy } : {},
13164
- ...this.options.indexStrategy !== void 0 ? { indexStrategy: this.options.indexStrategy } : {},
13165
- ...this.options.lazyStrategy !== void 0 ? { lazyStrategy: this.options.lazyStrategy } : {},
13166
- ...this.options.aggregateStrategy !== void 0 ? { aggregateStrategy: this.options.aggregateStrategy } : {},
13167
- ...this.options.crdtStrategy !== void 0 ? { crdtStrategy: this.options.crdtStrategy } : {},
13168
- ...this.options.tiersStrategy !== void 0 ? { tiersStrategy: this.options.tiersStrategy } : {},
13169
- ...this.options.searchStrategy !== void 0 ? { searchStrategy: this.options.searchStrategy } : {},
13170
- ...this.options.cargoStrategy !== void 0 ? { cargoStrategy: this.options.cargoStrategy } : {},
13171
- ...this.options.brokerStrategy !== void 0 ? { brokerStrategy: this.options.brokerStrategy } : {},
13172
- ...this.options.consentStrategy !== void 0 ? { consentStrategy: this.options.consentStrategy } : {},
13173
- ...this.options.periodsStrategy !== void 0 ? { periodsStrategy: this.options.periodsStrategy } : {},
13174
- ...this.options.shadowStrategy !== void 0 ? { shadowStrategy: this.options.shadowStrategy } : {},
13175
- ...this.options.historyStrategy !== void 0 ? { historyStrategy: this.options.historyStrategy } : {},
13176
- ...this.options.i18nStrategy !== void 0 ? { i18nStrategy: this.options.i18nStrategy } : {},
13177
- ...this.options.syncStrategy !== void 0 ? { syncStrategy: this.options.syncStrategy } : {},
13178
- ...this.options.guardStrategies !== void 0 ? { guardStrategies: this.options.guardStrategies } : {},
13179
- ...this.options.numbering !== void 0 ? { numberingConfigs: this.options.numbering } : {},
13180
- emitter: this.emitter
13181
- });
13182
- this.vaultCache.set(name, comp);
13183
- return comp;
12786
+ throw new ValidationError(
12787
+ `Vault "${name}" is not open. Call \`await db.openVault("${name}")\` first \u2014 vault() only returns an already-open vault, because opening involves async work (registry init, schema fence) that a sync accessor cannot do.`
12788
+ );
13184
12789
  }
13185
12790
  /**
13186
12791
  * Grant access to a user for a vault.
@@ -13194,7 +12799,7 @@ var Noydb = class {
13194
12799
  * Opt-in (#267): throws {@link TeamNotEnabledError} without `withTeam()`.
13195
12800
  */
13196
12801
  async grant(vault, options, factors) {
13197
- return this.teamStrategy.grant(this.team, vault, options, factors);
12802
+ return this.strategies.team.grant(this.team, vault, options, factors);
13198
12803
  }
13199
12804
  /**
13200
12805
  * Revoke a user's access to a vault.
@@ -13207,7 +12812,7 @@ var Noydb = class {
13207
12812
  * Opt-in (#267): throws {@link TeamNotEnabledError} without `withTeam()`.
13208
12813
  */
13209
12814
  async revoke(vault, options, factors) {
13210
- return this.teamStrategy.revoke(this.team, vault, options, factors);
12815
+ return this.strategies.team.revoke(this.team, vault, options, factors);
13211
12816
  }
13212
12817
  /**
13213
12818
  * Grant the FR-6 `custodian` role to a user (owner-only custody API).
@@ -13220,7 +12825,7 @@ var Noydb = class {
13220
12825
  * owner-only invariant even if a host mis-configures the gate.
13221
12826
  */
13222
12827
  async grantCustodian(vault, options, factors) {
13223
- return this.custodyStrategy.grantCustodian(this, vault, options, factors);
12828
+ return this.strategies.custody.grantCustodian(this, vault, options, factors);
13224
12829
  }
13225
12830
  /** @internal — grant-custodian engine, reached only via withCustody(); the
13226
12831
  * keyring engine arrives as an argument so the floor never carries it (#267). */
@@ -13239,7 +12844,7 @@ var Noydb = class {
13239
12844
  * 'owner'` check, so an admin cannot unwind a custodianship.
13240
12845
  */
13241
12846
  async revokeCustodian(vault, options, factors) {
13242
- return this.custodyStrategy.revokeCustodian(this, vault, options, factors);
12847
+ return this.strategies.custody.revokeCustodian(this, vault, options, factors);
13243
12848
  }
13244
12849
  /** @internal — revoke-custodian engine, reached only via withCustody().
13245
12850
  * Mirrors `_grantCustodianImpl` (#267: engine passed in). */
@@ -13301,16 +12906,26 @@ var Noydb = class {
13301
12906
  /**
13302
12907
  * Rotate the DEKs for the given collections in a vault.
13303
12908
  *
13304
- * Generates fresh DEKs, re-encrypts every record in each collection,
13305
- * and re-wraps the new DEKs into every remaining user's keyring. The
13306
- * old DEKs become unreachable — useful as a defense-in-depth measure
13307
- * after a suspected key leak, or as the scheduled half of a
13308
- * key-rotation policy.
12909
+ * Generates fresh DEKs and re-encrypts every record in each collection.
12910
+ * The old DEKs become unreachable — useful as a defense-in-depth measure
12911
+ * after a suspected key leak, or as the scheduled half of a key-rotation
12912
+ * policy.
13309
12913
  *
13310
- * Unlike `revoke({ rotateKeys: true })`, this call does NOT remove
13311
- * any users — every current member keeps access, but with fresh
13312
- * keys. This is the "just rotate" path; the "revoke and rotate"
13313
- * path still lives in `revoke()`.
12914
+ * ## Other members LOSE access to the rotated collections (#854)
12915
+ *
12916
+ * A member's DEKs are wrapped under that member's KEK, and a KEK derives
12917
+ * only from that member's secret. The caller cannot derive anyone else's
12918
+ * KEK, so re-wrapping a fresh DEK for them is impossible — that is the
12919
+ * zero-knowledge property working as designed. Rotation therefore DROPS
12920
+ * the rotated collections from every other member's keyring.
12921
+ *
12922
+ * The returned {@link RotateResult.needsRegrant} names each (member,
12923
+ * collection) pair that was dropped. Re-run `grant()` for those pairs, or
12924
+ * they stay locked out.
12925
+ *
12926
+ * Unlike `revoke({ rotateKeys: true })`, this call does not REMOVE any
12927
+ * user from the vault — they keep membership and their other collections.
12928
+ * This is the "just rotate" path; "revoke and rotate" lives in `revoke()`.
13314
12929
  *
13315
12930
  * Exposed on Noydb (rather than only on the lower-level keyring
13316
12931
  * module) so CLI and admin tooling can trigger rotation without
@@ -13318,7 +12933,7 @@ var Noydb = class {
13318
12933
  * Opt-in (#267): throws {@link TeamNotEnabledError} without `withTeam()`.
13319
12934
  */
13320
12935
  async rotate(vault, collections) {
13321
- return this.teamStrategy.rotate(this.team, vault, collections);
12936
+ return this.strategies.team.rotate(this.team, vault, collections);
13322
12937
  }
13323
12938
  /** List all users with access to a vault. */
13324
12939
  async listUsers(vault) {
@@ -13331,9 +12946,9 @@ var Noydb = class {
13331
12946
  *
13332
12947
  * The walk is a two-step pipeline: first ask the adapter for the
13333
12948
  * universe of compartments it stores, then for each one attempt to
13334
- * load the calling user's keyring with the in-memory passphrase.
12949
+ * load the calling user's keyring with the in-memory secret.
13335
12950
  * Compartments where the user has no keyring file (`NoAccessError`)
13336
- * or where the passphrase doesn't unwrap (`InvalidKeyError`) are
12951
+ * or where the secret doesn't unwrap (`InvalidKeyError`) are
13337
12952
  * silently dropped from the result — the existence of those
13338
12953
  * compartments is **not** confirmed in the return value.
13339
12954
  *
@@ -13354,15 +12969,15 @@ var Noydb = class {
13354
12969
  * **Known edge case.** A vault whose keyring file
13355
12970
  * happens to have an empty wrapped-DEKs map (because the owner
13356
12971
  * granted access before any collection was created) will pass the
13357
- * `loadKeyring` probe with *any* passphrase — there are no DEKs to
12972
+ * `loadKeyring` probe with *any* secret — there are no DEKs to
13358
12973
  * unwrap, so the integrity-checked unwrap that normally rejects
13359
- * wrong passphrases never runs. The result is that an unrelated
12974
+ * wrong secrets never runs. The result is that an unrelated
13360
12975
  * principal who happens to know the user-id and the vault
13361
12976
  * name can show up in `listAccessibleVaults()` as having
13362
12977
  * access to that empty vault. They cannot read any actual
13363
12978
  * data (their DEK set is empty), so this is a metadata leak
13364
12979
  * (vault name + user-id), not a content leak. Hardening this
13365
- * via a passphrase canary in the keyring file is a deferred
12980
+ * via a secret canary in the keyring file is a deferred
13366
12981
  * follow-up.
13367
12982
  *
13368
12983
  * **Cost.** O(compartments × keyring-load) — one `loadKeyring`
@@ -13403,7 +13018,7 @@ var Noydb = class {
13403
13018
  }
13404
13019
  if (!this.options.secret) {
13405
13020
  throw new ValidationError(
13406
- "Noydb.listAccessibleVaults(): a secret (passphrase) is required when encryption is enabled."
13021
+ "Noydb.listAccessibleVaults(): a secret (secret) is required when encryption is enabled."
13407
13022
  );
13408
13023
  }
13409
13024
  const minRank = ROLE_RANK[options.minRole ?? "client"];
@@ -13412,12 +13027,10 @@ var Noydb = class {
13412
13027
  for (const vault of universe) {
13413
13028
  let keyring;
13414
13029
  try {
13415
- keyring = await loadKeyring(
13416
- adapter,
13417
- vault,
13418
- this.options.user,
13419
- this.options.secret
13420
- );
13030
+ keyring = await loadKeyring(adapter, vault, {
13031
+ userId: this.options.user,
13032
+ secret: this.options.secret
13033
+ });
13421
13034
  } catch (err) {
13422
13035
  if (err instanceof NoAccessError || err instanceof InvalidKeyError || err instanceof KeyringCorruptError) {
13423
13036
  continue;
@@ -13478,7 +13091,7 @@ var Noydb = class {
13478
13091
  * })
13479
13092
  * ```
13480
13093
  */
13481
- async queryAcross(vaultIds, fn2, options = {}) {
13094
+ async queryAcross(vaultIds, fn, options = {}) {
13482
13095
  if (this.closed) throw new ValidationError("Instance is closed");
13483
13096
  this.resetSessionTimer();
13484
13097
  const concurrency = Math.max(1, options.concurrency ?? 1);
@@ -13492,7 +13105,7 @@ var Noydb = class {
13492
13105
  const task = (async () => {
13493
13106
  try {
13494
13107
  const comp = await this.openVault(vaultId, { create: options.create !== false });
13495
- const result = await fn2(comp);
13108
+ const result = await fn(comp);
13496
13109
  results[idx] = { vault: vaultId, result };
13497
13110
  } catch (err) {
13498
13111
  results[idx] = {
@@ -13542,23 +13155,20 @@ var Noydb = class {
13542
13155
  return store.resolveBackend ? store.resolveBackend(vaultId) : this.options.store;
13543
13156
  }
13544
13157
  /**
13545
- * Change the current user's passphrase for a vault.
13158
+ * Change the current user's secret for a vault.
13546
13159
  *
13547
- * Validates the new passphrase against the strength rules. Pass
13548
- * `{ allowWeakPassphrase: true }` to skip — typically only useful for
13549
- * fixtures and migrations. Pass a `PassphrasePolicy` to override the
13160
+ * Validates the new secret against the strength rules. Pass
13161
+ * `{ allowWeakSecret: true }` to skip — typically only useful for
13162
+ * fixtures and migrations. Pass a `SecretPolicy` to override the
13550
13163
  * default rules (e.g. consumer-tunable `pattern` / `customValidator`).
13551
13164
  */
13552
- async changeSecret(vault, newPassphrase, options) {
13165
+ async changeSecret(vault, newSecret, options) {
13553
13166
  this.checkPolicyOperation(vault, "changeSecret");
13554
13167
  const keyring = await this._getKeyringInternal(vault);
13555
- const updated = await changeSecret(
13556
- this.options.store,
13557
- vault,
13558
- keyring,
13559
- newPassphrase,
13560
- options
13561
- );
13168
+ const updated = await changeSecret(this.options.store, vault, keyring, {
13169
+ ...options,
13170
+ newSecret
13171
+ });
13562
13172
  this.keyringCache.set(vault, updated);
13563
13173
  }
13564
13174
  // ─── Sync ──────────────────────────────────────────────────────
@@ -13608,7 +13218,7 @@ var Noydb = class {
13608
13218
  }
13609
13219
  transaction(arg, maybeFn) {
13610
13220
  if (typeof arg === "function") {
13611
- return this.txStrategy.runTransaction(this, arg);
13221
+ return this.strategies.transactions.runTransaction(this, arg);
13612
13222
  }
13613
13223
  if (typeof arg === "object" && arg !== null && arg.dryRun === true) {
13614
13224
  if (typeof maybeFn !== "function") {
@@ -13616,7 +13226,7 @@ var Noydb = class {
13616
13226
  "db.transaction({ dryRun: true }, fn) requires the callback as the second argument."
13617
13227
  );
13618
13228
  }
13619
- return this.txStrategy.runDryRun(this, maybeFn);
13229
+ return this.strategies.transactions.runDryRun(this, maybeFn);
13620
13230
  }
13621
13231
  if (typeof arg === "object" && arg !== null && arg.amendment === true) {
13622
13232
  if (typeof maybeFn !== "function") {
@@ -13624,7 +13234,7 @@ var Noydb = class {
13624
13234
  "db.transaction({ amendment: true }, fn) requires the callback as the second argument."
13625
13235
  );
13626
13236
  }
13627
- return this.txStrategy.runTransaction(this, maybeFn, arg);
13237
+ return this.strategies.transactions.runTransaction(this, maybeFn, arg);
13628
13238
  }
13629
13239
  const vault = arg;
13630
13240
  const comp = this.vaultCache.get(vault);
@@ -13634,7 +13244,7 @@ var Noydb = class {
13634
13244
  );
13635
13245
  }
13636
13246
  const engine = this.getSyncEngine(vault);
13637
- return this.syncStrategy.buildSyncTransaction(comp, engine);
13247
+ return this.strategies.sync.buildSyncTransaction(comp, engine);
13638
13248
  }
13639
13249
  /**
13640
13250
  * Internal accessor for the primary store — used by the tx
@@ -13714,8 +13324,8 @@ var Noydb = class {
13714
13324
  }
13715
13325
  return engine;
13716
13326
  }
13717
- _forEachSyncEngine(vault, fn2) {
13718
- for (const [key, engine] of this.syncEngines) if (key === vault || key.startsWith(`${vault}::`)) fn2(engine);
13327
+ _forEachSyncEngine(vault, fn) {
13328
+ for (const [key, engine] of this.syncEngines) if (key === vault || key.startsWith(`${vault}::`)) fn(engine);
13719
13329
  }
13720
13330
  // ─── Events ────────────────────────────────────────────────────
13721
13331
  on(event, handler) {
@@ -13759,9 +13369,9 @@ var Noydb = class {
13759
13369
  return this.writeHooks.onAfterWrite(handler);
13760
13370
  }
13761
13371
  /** Subscribe to cross-tab write conflicts. Returns an unsubscribe. */
13762
- onWriteConflict(fn2) {
13763
- this.on("write:conflict", fn2);
13764
- return () => this.off("write:conflict", fn2);
13372
+ onWriteConflict(fn) {
13373
+ this.on("write:conflict", fn);
13374
+ return () => this.off("write:conflict", fn);
13765
13375
  }
13766
13376
  /**
13767
13377
  * Enable same-device multi-tab coordination: primary/secondary
@@ -13835,12 +13445,12 @@ var Noydb = class {
13835
13445
  activeTabs() {
13836
13446
  return this.tabCoordinator?.activeTabs() ?? [];
13837
13447
  }
13838
- onTabRoleChange(fn2) {
13839
- return this.tabCoordinator?.onTabRoleChange(fn2) ?? (() => {
13448
+ onTabRoleChange(fn) {
13449
+ return this.tabCoordinator?.onTabRoleChange(fn) ?? (() => {
13840
13450
  });
13841
13451
  }
13842
- onActiveTabsChange(fn2) {
13843
- return this.tabCoordinator?.onActiveTabsChange(fn2) ?? (() => {
13452
+ onActiveTabsChange(fn) {
13453
+ return this.tabCoordinator?.onActiveTabsChange(fn) ?? (() => {
13844
13454
  });
13845
13455
  }
13846
13456
  /** @internal The write-hook registry, threaded into each Collection. */
@@ -13907,6 +13517,7 @@ var Noydb = class {
13907
13517
  close() {
13908
13518
  this.closed = true;
13909
13519
  this.snapshots.stop();
13520
+ for (const engine of this.syncEngines.values()) engine.stopScheduler();
13910
13521
  if (this.sessionTimer) {
13911
13522
  clearTimeout(this.sessionTimer);
13912
13523
  this.sessionTimer = null;
@@ -13915,7 +13526,7 @@ var Noydb = class {
13915
13526
  enforcer.destroy();
13916
13527
  }
13917
13528
  this.policyEnforcers.clear();
13918
- this.sessionStrategy.revokeAllSessions();
13529
+ this.strategies.session.revokeAllSessions();
13919
13530
  for (const engine of this.syncEngines.values()) {
13920
13531
  engine.stopAutoSync();
13921
13532
  }
@@ -14037,7 +13648,7 @@ var Noydb = class {
14037
13648
  * denial; resolves with `void` on success.
14038
13649
  *
14039
13650
  * @param vault The vault whose policy applies.
14040
- * @param gate Gate name — built-in (e.g. `'rotate-passphrase'`)
13651
+ * @param gate Gate name — built-in (e.g. `'rotate-secret'`)
14041
13652
  * or app-defined (`app:*`).
14042
13653
  * @param presented Caller-supplied factor proofs.
14043
13654
  */
@@ -14062,12 +13673,12 @@ var Noydb = class {
14062
13673
  * Two enforcement modes:
14063
13674
  *
14064
13675
  * 1. **Managed-mode mandatory strong-recovery.** When
14065
- * `passphraseMode === 'managed'`, the vault MUST have at least
13676
+ * `secretMode === 'managed'`, the vault MUST have at least
14066
13677
  * one **strong** recovery profile (Shamir today). Paper alone is
14067
13678
  * rejected because under managed mode the user has no memorized
14068
- * passphrase, so losing the paper sheet = losing every record.
13679
+ * secret, so losing the paper sheet = losing every record.
14069
13680
  * This check is unconditional — independent of `requireRecovery`
14070
- * and the `recover-passphrase` gate.
13681
+ * and the `recover-secret` gate.
14071
13682
  *
14072
13683
  * 2. **Opt-in strict mandatory-recovery.** When
14073
13684
  * `requireRecovery: true` is set on createNoydb (and the gate is
@@ -14081,14 +13692,14 @@ var Noydb = class {
14081
13692
  */
14082
13693
  async assertRecoveryEnrolled(vault, policy, opts) {
14083
13694
  const skipManaged = (opts?.skipManagedCheck ?? false) || this._skipNextManagedRecoveryCheck;
14084
- if (this.options.passphraseMode === "managed" && !skipManaged) {
13695
+ if (this.options.secretMode === "managed" && !skipManaged) {
14085
13696
  const enrolled2 = await hasStrongRecoveryEnrolled(this.options.store, vault);
14086
13697
  if (!enrolled2) {
14087
13698
  throw new ManagedRecoveryNotEnrolledError(vault);
14088
13699
  }
14089
13700
  }
14090
13701
  if (this.options.requireRecovery !== true) return;
14091
- const gate = policy.gates["recover-passphrase"];
13702
+ const gate = policy.gates["recover-secret"];
14092
13703
  if (gate?.enabled === false) return;
14093
13704
  const enrolled = await hasRecoveryEnrolled(this.options.store, vault);
14094
13705
  if (enrolled) return;
@@ -14103,34 +13714,6 @@ var Noydb = class {
14103
13714
  this.activeTier.set(vault, tier);
14104
13715
  }
14105
13716
  // ─── Tier-2 enroll / remove ─────────────────────────────────────
14106
- /** Add a tier-2 authenticator slot — see {@link TeamFacade.enrollAuthenticator}. */
14107
- async enrollAuthenticator(vault, options, factors) {
14108
- return this.team.enrollAuthenticator(vault, options, factors);
14109
- }
14110
- /** Remove a tier-2 authenticator slot — see {@link TeamFacade.removeAuthenticator}. */
14111
- async removeAuthenticator(vault, slotId, factors) {
14112
- return this.team.removeAuthenticator(vault, slotId, factors);
14113
- }
14114
- /** Read the slot list for a vault — see {@link TeamFacade.listAuthenticators}. */
14115
- async listAuthenticators(vault) {
14116
- return this.team.listAuthenticators(vault);
14117
- }
14118
- /** Mutate an authenticator slot's `meta` — see {@link TeamFacade.updateAuthenticator}. */
14119
- async updateAuthenticator(vault, slotId, options, factors) {
14120
- return this.team.updateAuthenticator(vault, slotId, options, factors);
14121
- }
14122
- /** Native WebAuthn enrollment — see {@link TeamFacade.enrollWebAuthn}. */
14123
- async enrollWebAuthn(vault, ceremony, factors) {
14124
- return this.team.enrollWebAuthn(vault, ceremony, factors);
14125
- }
14126
- /** List webauthn-method slots — see {@link TeamFacade.listWebAuthnSlots}. */
14127
- async listWebAuthnSlots(vault) {
14128
- return this.team.listWebAuthnSlots(vault);
14129
- }
14130
- /** Unlock via a tier-2 authenticator slot — see {@link TeamFacade.unlockViaAuthenticator}. */
14131
- async unlockViaAuthenticator(vault, slotId, verify) {
14132
- return this.team.unlockViaAuthenticator(vault, slotId, verify);
14133
- }
14134
13717
  // ─── Cover (https://github.com/vLannaAi/noy-db-docs/blob/main/content/docs/services/public-envelope.md) ──────
14135
13718
  /**
14136
13719
  * Set the owner-curated cover for a vault. Throws
@@ -14148,13 +13731,13 @@ var Noydb = class {
14148
13731
  * value, absent ones are preserved, `null` deletes (#800).
14149
13732
  */
14150
13733
  async setCover(vault, input) {
14151
- const coverOption = this.options.cover ?? this.options.publicEnvelope;
13734
+ const coverOption = this.options.cover;
14152
13735
  if (!coverOption) {
14153
13736
  throw new ValidationError(
14154
13737
  "setCover: the cover feature is not enabled. Pass `cover: true` (or a schema object) to `createNoydb`."
14155
13738
  );
14156
13739
  }
14157
- const { loadCover, saveCover, resolveSchema, validateCoverInput, mergeCustom, validateCoverSize } = await import("./cover-B5SJDHR3.js");
13740
+ const { loadCover, saveCover, resolveSchema, validateCoverInput, mergeCustom, validateCoverSize } = await import("./cover/index.js");
14158
13741
  const schema = resolveSchema(coverOption);
14159
13742
  validateCoverInput(input, schema);
14160
13743
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -14186,84 +13769,12 @@ var Noydb = class {
14186
13769
  * regardless).
14187
13770
  */
14188
13771
  async getCover(vault, opts = {}) {
14189
- const { readCover } = await import("./cover-B5SJDHR3.js");
13772
+ const { readCover } = await import("./cover/index.js");
14190
13773
  return readCover(this.options.store, vault, opts);
14191
13774
  }
14192
- /** @deprecated Use {@link Noydb.setCover} (#799 rename). */
14193
- async setPublicEnvelope(vault, input) {
14194
- return this.setCover(vault, input);
14195
- }
14196
- /** @deprecated Use {@link Noydb.getCover} (#799 rename). */
14197
- async getPublicEnvelope(vault, opts = {}) {
14198
- return this.getCover(vault, opts);
14199
- }
14200
13775
  // ─── Auth introspection ─────────────────────────────────────────
14201
- /** English summary of the configured auth model — see {@link TeamFacade.describeAuthConfig}. */
14202
- async describeAuthConfig(vault) {
14203
- return this.team.describeAuthConfig(vault);
14204
- }
14205
- /** Mermaid `flowchart TB` source for the auth graph — see {@link TeamFacade.diagramAuthConfig}. */
14206
- async diagramAuthConfig(vault) {
14207
- return this.team.diagramAuthConfig(vault);
14208
- }
14209
- /** Per-user enrollment summary — see {@link TeamFacade.describeUserAuth}. */
14210
- async describeUserAuth(vault, userId, factors) {
14211
- return this.team.describeUserAuth(vault, userId, factors);
14212
- }
14213
- /** Bulk per-user enrollment summary — see {@link TeamFacade.describeAllUsersAuth}. */
14214
- async describeAllUsersAuth(vault, factors) {
14215
- return this.team.describeAllUsersAuth(vault, factors);
14216
- }
14217
13776
  // ─── Tier-1 change flows ────────────────────────────────────────
14218
- /** Rotate the user's passphrase (user remembers old) — see {@link TeamFacade.rotatePassphrase}. */
14219
- async rotatePassphrase(vault, input, factors) {
14220
- return this.team.rotatePassphrase(vault, input, factors);
14221
- }
14222
- /** Reset the passphrase using a recovery proof — see {@link TeamFacade.recoverPassphrase}. */
14223
- async recoverPassphrase(vault, input, factors) {
14224
- return this.team.recoverPassphrase(vault, input, factors);
14225
- }
14226
- /** Deliberate paper/Shamir recovery-code regeneration — see {@link TeamFacade.rotateRecovery}. */
14227
- async rotateRecovery(vault, options, factors) {
14228
- return this.team.rotateRecovery(vault, options, factors);
14229
- }
14230
- /** Atomic create-and-enroll for managed-mode vaults — see {@link TeamFacade.openVaultAndEnrollRecovery}. */
14231
- async openVaultAndEnrollRecovery(vault, opts) {
14232
- return this.team.openVaultAndEnrollRecovery(vault, opts);
14233
- }
14234
- /** Recovery flow under managed-passphrase mode — see {@link TeamFacade.recoverManagedPassphrase}. */
14235
- async recoverManagedPassphrase(vault, options) {
14236
- return this.team.recoverManagedPassphrase(vault, options);
14237
- }
14238
- /** Atomic peer-recovery of an existing user's keyring — see {@link TeamFacade.recoverUser}. */
14239
- async recoverUser(vault, options, factors) {
14240
- return this.team.recoverUser(vault, options, factors);
14241
- }
14242
- /** Persist a recovery enrollment (paper or Shamir) — see {@link TeamFacade.enrollRecovery}. */
14243
- async enrollRecovery(vault, enrollment) {
14244
- return this.team.enrollRecovery(vault, enrollment);
14245
- }
14246
- /** Read the persisted recovery entries (paper + Shamir) — see {@link TeamFacade.listRecoveryEntries}. */
14247
- async listRecoveryEntries(vault) {
14248
- return this.team.listRecoveryEntries(vault);
14249
- }
14250
13777
  // ─── Tier-3 enroll / unlock ─────────────────────────────────────
14251
- /** Register a tier-3 quick-unlock state — see {@link TeamFacade.enrollUnlock}. */
14252
- async enrollUnlock(vault, state, factors) {
14253
- return this.team.enrollUnlock(vault, state, factors);
14254
- }
14255
- /** Resume a session via the registered tier-3 state — see {@link TeamFacade.unlockViaPin}. */
14256
- async unlockViaPin(vault, resume) {
14257
- return this.team.unlockViaPin(vault, resume);
14258
- }
14259
- /** Drop the tier-3 state for a vault — see {@link TeamFacade.clearQuickUnlock}. */
14260
- clearQuickUnlock(vault) {
14261
- this.team.clearQuickUnlock(vault);
14262
- }
14263
- /** Public defensive-copy accessor for the unlocked keyring — see {@link TeamFacade.getKeyring}. */
14264
- async getKeyring(vault) {
14265
- return this.team.getKeyring(vault);
14266
- }
14267
13778
  /**
14268
13779
  * Live-reference variant used by the hub's own code paths. Internal
14269
13780
  * mutations on `deks` (e.g. {@link ensureCollectionDEK} adding a
@@ -14284,7 +13795,7 @@ var Noydb = class {
14284
13795
  }
14285
13796
  await assertKeyringOpenAllowed(this.options.store, vault, this.options.user, opts.create);
14286
13797
  let effectiveSecret;
14287
- if (this.options.passphraseMode === "managed") {
13798
+ if (this.options.secretMode === "managed") {
14288
13799
  effectiveSecret = await resolveManagedSecret(
14289
13800
  this.options.store,
14290
13801
  vault,
@@ -14294,37 +13805,29 @@ var Noydb = class {
14294
13805
  effectiveSecret = this.options.secret;
14295
13806
  }
14296
13807
  if (!effectiveSecret) {
14297
- throw new ValidationError("A secret (passphrase) or getKeyring callback is required when encryption is enabled");
13808
+ throw new ValidationError("A secret (secret) or getKeyring callback is required when encryption is enabled");
14298
13809
  }
14299
13810
  let keyring;
14300
13811
  try {
14301
- keyring = await loadKeyring(this.options.store, vault, this.options.user, effectiveSecret);
13812
+ keyring = await loadKeyring(this.options.store, vault, { userId: this.options.user, secret: effectiveSecret });
14302
13813
  } catch (err) {
14303
13814
  if (err instanceof NoAccessError) {
14304
- keyring = await createOwnerKeyring(
14305
- this.options.store,
14306
- vault,
14307
- this.options.user,
14308
- effectiveSecret,
14309
- {
14310
- // Managed mode generates 256-bit base64 strings that don't satisfy
14311
- // the human-passphrase strength rules (no spaces, no "words").
14312
- // Skip validation in managed mode — the entropy floor is already
14313
- // 256 bits by construction.
14314
- validate: this.options.passphraseMode === "managed" ? false : this.options.validatePassphrase === true
14315
- }
14316
- );
13815
+ keyring = await createOwnerKeyring(this.options.store, vault, {
13816
+ userId: this.options.user,
13817
+ secret: effectiveSecret,
13818
+ // Managed mode generates 256-bit base64 strings that don't satisfy
13819
+ // the human-secret strength rules (no spaces, no "words").
13820
+ // Skip validation in managed mode — the entropy floor is already
13821
+ // 256 bits by construction.
13822
+ validate: this.options.secretMode === "managed" ? false : this.options.validateSecret === true
13823
+ });
14317
13824
  } else if (err instanceof InvalidKeyError && this.options.onInvalidKey === "reset") {
14318
13825
  await this.options.store.delete(vault, "_keyring", this.options.user);
14319
- keyring = await createOwnerKeyring(
14320
- this.options.store,
14321
- vault,
14322
- this.options.user,
14323
- effectiveSecret,
14324
- {
14325
- validate: this.options.passphraseMode === "managed" ? false : this.options.validatePassphrase === true
14326
- }
14327
- );
13826
+ keyring = await createOwnerKeyring(this.options.store, vault, {
13827
+ userId: this.options.user,
13828
+ secret: effectiveSecret,
13829
+ validate: this.options.secretMode === "managed" ? false : this.options.validateSecret === true
13830
+ });
14328
13831
  } else {
14329
13832
  throw err;
14330
13833
  }
@@ -14334,7 +13837,7 @@ var Noydb = class {
14334
13837
  }
14335
13838
  /**
14336
13839
  * Take an on-demand checkpoint of the given vault.
14337
- * Requires `snapshotStrategy: withSnapshots({ store })` in `createNoydb`.
13840
+ * Requires `snapshotsStrategy: withSnapshots({ store })` in `createNoydb`.
14338
13841
  * @throws ValidationError when the vault is not open
14339
13842
  */
14340
13843
  async snapshot(vault, opts) {
@@ -14360,34 +13863,34 @@ var Noydb = class {
14360
13863
  async function createNoydb(options) {
14361
13864
  if (!options.store) options = { ...options, store: memoryStore() };
14362
13865
  const encrypted = options.encrypt !== false;
14363
- const managed = options.passphraseMode === "managed";
13866
+ const managed = options.secretMode === "managed";
14364
13867
  if (options.secret && options.getKeyring) {
14365
13868
  throw new ValidationError("Provide either `secret` or `getKeyring`, not both");
14366
13869
  }
14367
13870
  if (managed) {
14368
13871
  if (options.secret) {
14369
13872
  throw new ValidationError(
14370
- '`passphraseMode: "managed"` is mutually exclusive with `secret` \u2014 managed mode generates the passphrase itself. Drop `secret`.'
13873
+ '`secretMode: "managed"` is mutually exclusive with `secret` \u2014 managed mode generates the secret itself. Drop `secret`.'
14371
13874
  );
14372
13875
  }
14373
13876
  if (options.getKeyring) {
14374
13877
  throw new ValidationError(
14375
- '`passphraseMode: "managed"` is mutually exclusive with `getKeyring` \u2014 a custom unlock callback would bypass the sealing flow. Drop `getKeyring`.'
13878
+ '`secretMode: "managed"` is mutually exclusive with `getKeyring` \u2014 a custom unlock callback would bypass the sealing flow. Drop `getKeyring`.'
14376
13879
  );
14377
13880
  }
14378
13881
  if (!options.sealingKey) {
14379
13882
  throw new ValidationError(
14380
- '`passphraseMode: "managed"` requires `sealingKey: SealingKeyProvider` (see @noy-db/seal-macos-keychain / @noy-db/seal-aws-kms / etc.).'
13883
+ '`secretMode: "managed"` requires `sealingKey: SealingKeyProvider` (see @noy-db/seal-macos-keychain / @noy-db/seal-aws-kms / etc.).'
14381
13884
  );
14382
13885
  }
14383
13886
  }
14384
13887
  if (encrypted && !managed && !options.secret && !options.getKeyring) {
14385
- throw new ValidationError("A secret (passphrase) or getKeyring callback is required when encryption is enabled");
13888
+ throw new ValidationError("A secret (secret) or getKeyring callback is required when encryption is enabled");
14386
13889
  }
14387
13890
  if (!options.coordinationStrategy) options = { ...options, coordinationStrategy: await createDefaultCoordinationProvider(options.store) };
14388
- if (!options.userApiFactory) options = { ...options, userApiFactory: (await import("./api-IQFZJSQO.js")).createUserApi };
13891
+ if (!options.userApiFactory) options = { ...options, userApiFactory: (await import("./api-ZDKTWNBB.js")).createUserApi };
14389
13892
  if (!options.policyFactory) {
14390
- const policyModule = await import("./policy-NAHB2TUT.js");
13893
+ const policyModule = await import("./policy/index.js");
14391
13894
  options = { ...options, policyFactory: policyModule.createNoydbPolicy, policyCheckGateFn: policyModule.checkGate };
14392
13895
  }
14393
13896
  return new Noydb(options);
@@ -14417,11 +13920,7 @@ export {
14417
13920
  RefRegistry,
14418
13921
  Vault,
14419
13922
  QuickUnlockStore,
14420
- describeAuthConfig,
14421
- diagramAuthConfig,
14422
- describeUserAuth,
14423
- describeAllUsersAuth,
14424
13923
  Noydb,
14425
13924
  createNoydb
14426
13925
  };
14427
- //# sourceMappingURL=chunk-3PF6CRDT.js.map
13926
+ //# sourceMappingURL=chunk-NFIBXF4V.js.map