@noy-db/hub 0.2.0-pre.4 → 0.2.0-pre.6

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 (282) hide show
  1. package/dist/aggregate/index.cjs.map +1 -1
  2. package/dist/aggregate/index.js +4 -4
  3. package/dist/attestation/index.cjs.map +1 -1
  4. package/dist/attestation/index.d.cts +4 -4
  5. package/dist/attestation/index.d.ts +4 -4
  6. package/dist/attestation/index.js +6 -6
  7. package/dist/blobs/index.cjs.map +1 -1
  8. package/dist/blobs/index.d.cts +5 -5
  9. package/dist/blobs/index.d.ts +5 -5
  10. package/dist/blobs/index.js +5 -5
  11. package/dist/bundle/index.cjs +496 -344
  12. package/dist/bundle/index.cjs.map +1 -1
  13. package/dist/bundle/index.d.cts +17 -17
  14. package/dist/bundle/index.d.ts +17 -17
  15. package/dist/bundle/index.js +10 -10
  16. package/dist/bundle/index.js.map +1 -1
  17. package/dist/{chunk-YL2DR3HY.js → chunk-25WFLKOH.js} +2 -2
  18. package/dist/chunk-25WFLKOH.js.map +1 -0
  19. package/dist/{chunk-EMEX37ZN.js → chunk-2GMRNNI3.js} +3 -3
  20. package/dist/chunk-2GMRNNI3.js.map +1 -0
  21. package/dist/{chunk-NGSPBLLE.js → chunk-34XGYMQT.js} +3 -3
  22. package/dist/chunk-34XGYMQT.js.map +1 -0
  23. package/dist/{chunk-FXQYZNOW.js → chunk-5OVIFUQE.js} +1 -1
  24. package/dist/chunk-5OVIFUQE.js.map +1 -0
  25. package/dist/{chunk-P6256WTJ.js → chunk-5QPF2MJ5.js} +3 -3
  26. package/dist/chunk-5QPF2MJ5.js.map +1 -0
  27. package/dist/{chunk-5ZGZ6HIZ.js → chunk-5VMTAX4Y.js} +2 -2
  28. package/dist/{chunk-74JEQFMT.js → chunk-6A4AMQ2H.js} +5 -5
  29. package/dist/chunk-6A4AMQ2H.js.map +1 -0
  30. package/dist/{chunk-YDLAFP36.js → chunk-6HJ2ZALB.js} +1 -1
  31. package/dist/chunk-6HJ2ZALB.js.map +1 -0
  32. package/dist/{chunk-GDTCGIPX.js → chunk-7TX7HN42.js} +2 -2
  33. package/dist/chunk-7TX7HN42.js.map +1 -0
  34. package/dist/{chunk-EPK6A3WJ.js → chunk-A3JMGXPG.js} +2 -2
  35. package/dist/chunk-A3JMGXPG.js.map +1 -0
  36. package/dist/{chunk-75QDHSE4.js → chunk-A4JNVBPF.js} +5 -5
  37. package/dist/{chunk-IS5HWQO7.js → chunk-ARZAHCCF.js} +3 -3
  38. package/dist/{chunk-4OQWR46B.js → chunk-CCC25PA7.js} +5 -5
  39. package/dist/{chunk-NSLTPGEN.js → chunk-CGJFCT3X.js} +2 -2
  40. package/dist/{chunk-YK72A4IT.js → chunk-CKH247ZR.js} +4 -4
  41. package/dist/{chunk-HGZ7DC5H.js → chunk-DFCINPB5.js} +2 -2
  42. package/dist/chunk-DFCINPB5.js.map +1 -0
  43. package/dist/{chunk-4X2S7PBF.js → chunk-E225X5CQ.js} +3 -3
  44. package/dist/chunk-E225X5CQ.js.map +1 -0
  45. package/dist/{chunk-5YHWBPOT.js → chunk-ED3E3OLO.js} +2 -2
  46. package/dist/{chunk-UOF74WQY.js → chunk-EKTOYEZ3.js} +2 -2
  47. package/dist/{chunk-SAVQ6E2O.js → chunk-G26QAQNI.js} +2 -2
  48. package/dist/{chunk-YMYK7US4.js → chunk-HIELMTUK.js} +2 -2
  49. package/dist/{chunk-MRIBLZL3.js → chunk-ICH4AIGL.js} +1 -1
  50. package/dist/chunk-ICH4AIGL.js.map +1 -0
  51. package/dist/{chunk-KMI2NBBF.js → chunk-JICBEFBT.js} +181 -6
  52. package/dist/chunk-JICBEFBT.js.map +1 -0
  53. package/dist/{chunk-LOL725S4.js → chunk-JSYTGEX4.js} +3 -3
  54. package/dist/{chunk-FBMXWVGP.js → chunk-KGFV72WK.js} +5 -5
  55. package/dist/{chunk-GVXBHCZ2.js → chunk-LJO6Q3X6.js} +5 -5
  56. package/dist/chunk-LJO6Q3X6.js.map +1 -0
  57. package/dist/{chunk-ZC2AAE6J.js → chunk-LWFQYT4N.js} +2 -2
  58. package/dist/chunk-LWFQYT4N.js.map +1 -0
  59. package/dist/{chunk-K5PVGKE4.js → chunk-MDIC4FAU.js} +2 -2
  60. package/dist/{chunk-ZUMGGHRB.js → chunk-OPD3PZOG.js} +4 -4
  61. package/dist/{chunk-LS3JLEIB.js → chunk-PS5G6A3Y.js} +4 -4
  62. package/dist/{chunk-KYKMKLJ6.js → chunk-PX3MJ6RB.js} +3 -3
  63. package/dist/{chunk-FCDO7UAO.js → chunk-R4LTCI6O.js} +2 -2
  64. package/dist/{chunk-BFI3RS42.js → chunk-R7JTYCRX.js} +2 -2
  65. package/dist/chunk-R7JTYCRX.js.map +1 -0
  66. package/dist/{chunk-WRLHNG6H.js → chunk-RIHZBSWJ.js} +4 -4
  67. package/dist/chunk-RIHZBSWJ.js.map +1 -0
  68. package/dist/{chunk-UVPGJXVO.js → chunk-SGSHQ4PH.js} +5 -5
  69. package/dist/{chunk-TLFUDXVV.js → chunk-T6MTNGBM.js} +5 -5
  70. package/dist/chunk-T6MTNGBM.js.map +1 -0
  71. package/dist/{chunk-6S3LLAQ5.js → chunk-TNBIWSQ7.js} +2 -2
  72. package/dist/{chunk-GD3BGKAR.js → chunk-UGVDIOY7.js} +2 -2
  73. package/dist/{chunk-T6HQMVML.js → chunk-W277AG6N.js} +411 -308
  74. package/dist/chunk-W277AG6N.js.map +1 -0
  75. package/dist/{chunk-FS7A4XNF.js → chunk-WEA4TDTJ.js} +3 -3
  76. package/dist/{chunk-4UBOTYP5.js → chunk-XDW37COG.js} +5 -5
  77. package/dist/chunk-XDW37COG.js.map +1 -0
  78. package/dist/{chunk-QAU5HM6Q.js → chunk-XVJFFGTG.js} +3 -3
  79. package/dist/{chunk-2EYC3WDT.js → chunk-Y3P5DEMZ.js} +6 -6
  80. package/dist/chunk-Y3P5DEMZ.js.map +1 -0
  81. package/dist/{chunk-G7PAZ3TD.js → chunk-YEHUEUNP.js} +4 -4
  82. package/dist/chunk-YEHUEUNP.js.map +1 -0
  83. package/dist/{chunk-2XLVPKXG.js → chunk-YJ46RFCD.js} +2 -2
  84. package/dist/{chunk-NCO2JGKK.js → chunk-Z6FNBOTC.js} +1 -1
  85. package/dist/chunk-Z6FNBOTC.js.map +1 -0
  86. package/dist/{chunk-GAUBWHAF.js → chunk-ZQMYB56Z.js} +4 -4
  87. package/dist/consent/index.cjs.map +1 -1
  88. package/dist/consent/index.d.cts +5 -5
  89. package/dist/consent/index.d.ts +5 -5
  90. package/dist/consent/index.js +3 -3
  91. package/dist/{crypto-H2Y3DDFW.js → crypto-5UDZZL26.js} +3 -3
  92. package/dist/{delegation-QSC7G5QC.js → delegation-42LO4WFO.js} +5 -5
  93. package/dist/derivations/index.cjs +1 -1
  94. package/dist/derivations/index.cjs.map +1 -1
  95. package/dist/derivations/index.d.cts +8 -8
  96. package/dist/derivations/index.d.ts +8 -8
  97. package/dist/derivations/index.js +4 -4
  98. package/dist/{dev-unlock-Cf2B7Kih.d.ts → dev-unlock-Cvo-xCQC.d.ts} +1 -1
  99. package/dist/{dev-unlock-De3mjQWv.d.cts → dev-unlock-Dy1qVpkL.d.cts} +1 -1
  100. package/dist/executor-AWCHQ2KN.js +8 -0
  101. package/dist/executor-RWICJI7J.js +11 -0
  102. package/dist/executor-SOLEQVUB.js +8 -0
  103. package/dist/{fanout-sidecar-NRBWSLRK.js → fanout-sidecar-EVICRM46.js} +2 -2
  104. package/dist/fanout-sidecar-EVICRM46.js.map +1 -0
  105. package/dist/guards/index.cjs +1 -1
  106. package/dist/guards/index.cjs.map +1 -1
  107. package/dist/guards/index.d.cts +6 -6
  108. package/dist/guards/index.d.ts +6 -6
  109. package/dist/guards/index.js +4 -4
  110. package/dist/{hash-gVn_uKhp.d.ts → hash-BAlWR4WD.d.ts} +1 -1
  111. package/dist/{hash-vBCB0-Ps.d.cts → hash-BgEQklQc.d.cts} +1 -1
  112. package/dist/history/index.cjs.map +1 -1
  113. package/dist/history/index.d.cts +6 -6
  114. package/dist/history/index.d.ts +6 -6
  115. package/dist/history/index.js +6 -6
  116. package/dist/i18n/index.cjs +75 -10
  117. package/dist/i18n/index.cjs.map +1 -1
  118. package/dist/i18n/index.d.cts +5 -5
  119. package/dist/i18n/index.d.ts +5 -5
  120. package/dist/i18n/index.js +16 -14
  121. package/dist/{index-DVkvrgpm.d.cts → index-5I0MZ0jQ.d.cts} +12 -12
  122. package/dist/{index-BF1B2HB9.d.ts → index-fIPPh5dg.d.ts} +12 -12
  123. package/dist/index.cjs +538 -378
  124. package/dist/index.cjs.map +1 -1
  125. package/dist/index.d.cts +20 -22
  126. package/dist/index.d.ts +20 -22
  127. package/dist/index.js +50 -52
  128. package/dist/index.js.map +1 -1
  129. package/dist/indexing/index.cjs +1 -1
  130. package/dist/indexing/index.cjs.map +1 -1
  131. package/dist/indexing/index.d.cts +3 -3
  132. package/dist/indexing/index.d.ts +3 -3
  133. package/dist/indexing/index.js +4 -4
  134. package/dist/issue-IODMTPME.js +12 -0
  135. package/dist/{lazy-builder-Rpd-V3jP.d.ts → lazy-builder-D1MyR1qH.d.ts} +2 -2
  136. package/dist/{lazy-builder-C-rPfWG0.d.cts → lazy-builder-DXlSCNCJ.d.cts} +2 -2
  137. package/dist/{ledger-WOEJUYTP.js → ledger-UX4QIHWI.js} +6 -6
  138. package/dist/materialized-views/index.cjs.map +1 -1
  139. package/dist/materialized-views/index.d.cts +18 -18
  140. package/dist/materialized-views/index.d.ts +18 -18
  141. package/dist/materialized-views/index.js +7 -7
  142. package/dist/noydb-FY2666NY.js +34 -0
  143. package/dist/overlay-views/index.cjs +1 -1
  144. package/dist/overlay-views/index.cjs.map +1 -1
  145. package/dist/overlay-views/index.d.cts +8 -8
  146. package/dist/overlay-views/index.d.ts +8 -8
  147. package/dist/overlay-views/index.js +4 -4
  148. package/dist/periods/index.cjs.map +1 -1
  149. package/dist/periods/index.d.cts +5 -5
  150. package/dist/periods/index.d.ts +5 -5
  151. package/dist/periods/index.js +6 -6
  152. package/dist/{predicate-Dnu81tsS.d.cts → predicate-B0IKeBXx.d.cts} +1 -1
  153. package/dist/{predicate-Dnu81tsS.d.ts → predicate-B0IKeBXx.d.ts} +1 -1
  154. package/dist/{public-envelope-OHQ5UZFM.js → public-envelope-YKHKP74C.js} +4 -4
  155. package/dist/query/index.cjs +2 -2
  156. package/dist/query/index.cjs.map +1 -1
  157. package/dist/query/index.d.cts +2 -2
  158. package/dist/query/index.d.ts +2 -2
  159. package/dist/query/index.js +6 -6
  160. package/dist/registry-446I2NMN.js +8 -0
  161. package/dist/{registry-CDHASH73.js → registry-4NEW7LQY.js} +3 -3
  162. package/dist/registry-524KJZG4.js +8 -0
  163. package/dist/registry-DKEXOJVO.js +7 -0
  164. package/dist/{revoke-7JOVLZFD.js → revoke-R5NIQ74J.js} +6 -6
  165. package/dist/session/index.cjs.map +1 -1
  166. package/dist/session/index.d.cts +6 -6
  167. package/dist/session/index.d.ts +6 -6
  168. package/dist/session/index.js +3 -3
  169. package/dist/shadow/index.cjs.map +1 -1
  170. package/dist/shadow/index.d.cts +5 -5
  171. package/dist/shadow/index.d.ts +5 -5
  172. package/dist/shadow/index.js +2 -2
  173. package/dist/{signer-M4K5HBLD.js → signer-WGDJNWSU.js} +5 -5
  174. package/dist/{stale-PAGCS4K5.js → stale-74WGLVZ2.js} +2 -2
  175. package/dist/store/index.cjs.map +1 -1
  176. package/dist/store/index.d.cts +5 -5
  177. package/dist/store/index.d.ts +5 -5
  178. package/dist/store/index.js +2 -2
  179. package/dist/sync/index.cjs.map +1 -1
  180. package/dist/sync/index.d.cts +4 -4
  181. package/dist/sync/index.d.ts +4 -4
  182. package/dist/sync/index.js +4 -4
  183. package/dist/team/index.cjs +1 -1
  184. package/dist/team/index.cjs.map +1 -1
  185. package/dist/team/index.d.cts +5 -5
  186. package/dist/team/index.d.ts +5 -5
  187. package/dist/team/index.js +8 -8
  188. package/dist/tx/index.cjs +2 -2
  189. package/dist/tx/index.cjs.map +1 -1
  190. package/dist/tx/index.d.cts +5 -5
  191. package/dist/tx/index.d.ts +5 -5
  192. package/dist/tx/index.js +3 -3
  193. package/dist/tx/index.js.map +1 -1
  194. package/dist/{types-CSLcfytP.d.cts → types-DVlvNn2c.d.cts} +362 -307
  195. package/dist/{types-D9eB0Rvh.d.ts → types-DlnZh1_i.d.ts} +362 -307
  196. package/dist/{ulid-CiM2OAeM.d.ts → ulid-CzPONlhG.d.ts} +19 -19
  197. package/dist/{ulid-CG2YvAbg.d.cts → ulid-r98nkjVd.d.cts} +19 -19
  198. package/dist/util/index.cjs.map +1 -1
  199. package/dist/util/index.js +1 -1
  200. package/dist/{with-derivation-Bzpj6UTv.d.ts → with-derivation-B98shCV8.d.ts} +1 -1
  201. package/dist/{with-derivation-DWajFh4K.d.cts → with-derivation-BMQ9pIHe.d.cts} +1 -1
  202. package/dist/{with-guard-DF_Ul3DT.d.cts → with-guard-DUnC3JDN.d.cts} +1 -1
  203. package/dist/{with-guard-DR7U-l4v.d.ts → with-guard-DmT50nVG.d.ts} +1 -1
  204. package/dist/{with-materialized-view-qtoJ3xKJ.d.ts → with-materialized-view-Bp_M3sNG.d.ts} +2 -2
  205. package/dist/{with-materialized-view-_piodoIz.d.cts → with-materialized-view-eMTZ65_J.d.cts} +2 -2
  206. package/dist/{with-overlayed-view-DFaRfgMr.d.ts → with-overlayed-view-BoY6PB3n.d.cts} +2 -2
  207. package/dist/{with-overlayed-view-DwzCKxn2.d.cts → with-overlayed-view-zzSnRQmS.d.ts} +2 -2
  208. package/package.json +3 -3
  209. package/dist/chunk-2EYC3WDT.js.map +0 -1
  210. package/dist/chunk-4UBOTYP5.js.map +0 -1
  211. package/dist/chunk-4X2S7PBF.js.map +0 -1
  212. package/dist/chunk-74JEQFMT.js.map +0 -1
  213. package/dist/chunk-A6SWRXUQ.js +0 -118
  214. package/dist/chunk-A6SWRXUQ.js.map +0 -1
  215. package/dist/chunk-BFI3RS42.js.map +0 -1
  216. package/dist/chunk-EMEX37ZN.js.map +0 -1
  217. package/dist/chunk-EPK6A3WJ.js.map +0 -1
  218. package/dist/chunk-FXQYZNOW.js.map +0 -1
  219. package/dist/chunk-G7PAZ3TD.js.map +0 -1
  220. package/dist/chunk-GDTCGIPX.js.map +0 -1
  221. package/dist/chunk-GVXBHCZ2.js.map +0 -1
  222. package/dist/chunk-HGZ7DC5H.js.map +0 -1
  223. package/dist/chunk-KMI2NBBF.js.map +0 -1
  224. package/dist/chunk-MRIBLZL3.js.map +0 -1
  225. package/dist/chunk-NCO2JGKK.js.map +0 -1
  226. package/dist/chunk-NGSPBLLE.js.map +0 -1
  227. package/dist/chunk-P6256WTJ.js.map +0 -1
  228. package/dist/chunk-T6HQMVML.js.map +0 -1
  229. package/dist/chunk-TLFUDXVV.js.map +0 -1
  230. package/dist/chunk-WRLHNG6H.js.map +0 -1
  231. package/dist/chunk-YDLAFP36.js.map +0 -1
  232. package/dist/chunk-YL2DR3HY.js.map +0 -1
  233. package/dist/chunk-ZC2AAE6J.js.map +0 -1
  234. package/dist/executor-BZKFZVRC.js +0 -8
  235. package/dist/executor-GFZFDQXV.js +0 -8
  236. package/dist/executor-KT2IOZVP.js +0 -11
  237. package/dist/fanout-sidecar-NRBWSLRK.js.map +0 -1
  238. package/dist/issue-BAJ7ZB4S.js +0 -12
  239. package/dist/noydb-XNQSKXGO.js +0 -34
  240. package/dist/registry-2IEARCGT.js +0 -7
  241. package/dist/registry-EMGLZGR6.js +0 -8
  242. package/dist/registry-NQALYR77.js +0 -8
  243. /package/dist/{chunk-5ZGZ6HIZ.js.map → chunk-5VMTAX4Y.js.map} +0 -0
  244. /package/dist/{chunk-75QDHSE4.js.map → chunk-A4JNVBPF.js.map} +0 -0
  245. /package/dist/{chunk-IS5HWQO7.js.map → chunk-ARZAHCCF.js.map} +0 -0
  246. /package/dist/{chunk-4OQWR46B.js.map → chunk-CCC25PA7.js.map} +0 -0
  247. /package/dist/{chunk-NSLTPGEN.js.map → chunk-CGJFCT3X.js.map} +0 -0
  248. /package/dist/{chunk-YK72A4IT.js.map → chunk-CKH247ZR.js.map} +0 -0
  249. /package/dist/{chunk-5YHWBPOT.js.map → chunk-ED3E3OLO.js.map} +0 -0
  250. /package/dist/{chunk-UOF74WQY.js.map → chunk-EKTOYEZ3.js.map} +0 -0
  251. /package/dist/{chunk-SAVQ6E2O.js.map → chunk-G26QAQNI.js.map} +0 -0
  252. /package/dist/{chunk-YMYK7US4.js.map → chunk-HIELMTUK.js.map} +0 -0
  253. /package/dist/{chunk-LOL725S4.js.map → chunk-JSYTGEX4.js.map} +0 -0
  254. /package/dist/{chunk-FBMXWVGP.js.map → chunk-KGFV72WK.js.map} +0 -0
  255. /package/dist/{chunk-K5PVGKE4.js.map → chunk-MDIC4FAU.js.map} +0 -0
  256. /package/dist/{chunk-ZUMGGHRB.js.map → chunk-OPD3PZOG.js.map} +0 -0
  257. /package/dist/{chunk-LS3JLEIB.js.map → chunk-PS5G6A3Y.js.map} +0 -0
  258. /package/dist/{chunk-KYKMKLJ6.js.map → chunk-PX3MJ6RB.js.map} +0 -0
  259. /package/dist/{chunk-FCDO7UAO.js.map → chunk-R4LTCI6O.js.map} +0 -0
  260. /package/dist/{chunk-UVPGJXVO.js.map → chunk-SGSHQ4PH.js.map} +0 -0
  261. /package/dist/{chunk-6S3LLAQ5.js.map → chunk-TNBIWSQ7.js.map} +0 -0
  262. /package/dist/{chunk-GD3BGKAR.js.map → chunk-UGVDIOY7.js.map} +0 -0
  263. /package/dist/{chunk-FS7A4XNF.js.map → chunk-WEA4TDTJ.js.map} +0 -0
  264. /package/dist/{chunk-QAU5HM6Q.js.map → chunk-XVJFFGTG.js.map} +0 -0
  265. /package/dist/{chunk-2XLVPKXG.js.map → chunk-YJ46RFCD.js.map} +0 -0
  266. /package/dist/{chunk-GAUBWHAF.js.map → chunk-ZQMYB56Z.js.map} +0 -0
  267. /package/dist/{crypto-H2Y3DDFW.js.map → crypto-5UDZZL26.js.map} +0 -0
  268. /package/dist/{delegation-QSC7G5QC.js.map → delegation-42LO4WFO.js.map} +0 -0
  269. /package/dist/{executor-BZKFZVRC.js.map → executor-AWCHQ2KN.js.map} +0 -0
  270. /package/dist/{executor-GFZFDQXV.js.map → executor-RWICJI7J.js.map} +0 -0
  271. /package/dist/{executor-KT2IOZVP.js.map → executor-SOLEQVUB.js.map} +0 -0
  272. /package/dist/{issue-BAJ7ZB4S.js.map → issue-IODMTPME.js.map} +0 -0
  273. /package/dist/{ledger-WOEJUYTP.js.map → ledger-UX4QIHWI.js.map} +0 -0
  274. /package/dist/{noydb-XNQSKXGO.js.map → noydb-FY2666NY.js.map} +0 -0
  275. /package/dist/{public-envelope-OHQ5UZFM.js.map → public-envelope-YKHKP74C.js.map} +0 -0
  276. /package/dist/{registry-2IEARCGT.js.map → registry-446I2NMN.js.map} +0 -0
  277. /package/dist/{registry-CDHASH73.js.map → registry-4NEW7LQY.js.map} +0 -0
  278. /package/dist/{registry-EMGLZGR6.js.map → registry-524KJZG4.js.map} +0 -0
  279. /package/dist/{registry-NQALYR77.js.map → registry-DKEXOJVO.js.map} +0 -0
  280. /package/dist/{revoke-7JOVLZFD.js.map → revoke-R5NIQ74J.js.map} +0 -0
  281. /package/dist/{signer-M4K5HBLD.js.map → signer-WGDJNWSU.js.map} +0 -0
  282. /package/dist/{stale-PAGCS4K5.js.map → stale-74WGLVZ2.js.map} +0 -0
@@ -4,34 +4,36 @@ import {
4
4
  import {
5
5
  TxContext,
6
6
  revertExecuted
7
- } from "./chunk-GVXBHCZ2.js";
7
+ } from "./chunk-LJO6Q3X6.js";
8
8
  import {
9
9
  OverlayedCollection
10
- } from "./chunk-NGSPBLLE.js";
10
+ } from "./chunk-34XGYMQT.js";
11
11
  import {
12
12
  LazyQuery,
13
13
  decodeIdxId,
14
14
  encodeIdxId
15
- } from "./chunk-WRLHNG6H.js";
15
+ } from "./chunk-RIHZBSWJ.js";
16
16
  import {
17
17
  SCHEMAS_COLLECTION,
18
18
  loadPersistedSchema,
19
19
  resolveManagedSecret,
20
20
  savePersistedSchema,
21
21
  saveSealedPassphrase
22
- } from "./chunk-4X2S7PBF.js";
22
+ } from "./chunk-E225X5CQ.js";
23
23
  import {
24
24
  loadPublicEnvelope,
25
25
  readPublicEnvelope,
26
26
  savePublicEnvelope,
27
27
  validatePublicEnvelopeInput
28
- } from "./chunk-FS7A4XNF.js";
28
+ } from "./chunk-WEA4TDTJ.js";
29
29
  import {
30
30
  PERIODS_COLLECTION
31
- } from "./chunk-GAUBWHAF.js";
31
+ } from "./chunk-ZQMYB56Z.js";
32
32
  import {
33
- isDictCollectionName
34
- } from "./chunk-KMI2NBBF.js";
33
+ getAtPath,
34
+ isDictCollectionName,
35
+ setAtPathInPlace
36
+ } from "./chunk-JICBEFBT.js";
35
37
  import {
36
38
  ManagedRecoveryNotEnrolledError,
37
39
  PolicyDeniedError,
@@ -53,11 +55,11 @@ import {
53
55
  saveShamirRecoveryEntries,
54
56
  updateAuthenticator,
55
57
  writeMagicLinkGrant
56
- } from "./chunk-2EYC3WDT.js";
58
+ } from "./chunk-Y3P5DEMZ.js";
57
59
  import {
58
60
  assertTierAccess,
59
61
  dekKey
60
- } from "./chunk-6S3LLAQ5.js";
62
+ } from "./chunk-TNBIWSQ7.js";
61
63
  import {
62
64
  USER_ENVELOPE_COLLECTION,
63
65
  buildRecipientKeyringFile,
@@ -81,7 +83,7 @@ import {
81
83
  rotateKeys,
82
84
  saveUserEnvelope,
83
85
  updateKeyringIdentity
84
- } from "./chunk-TLFUDXVV.js";
86
+ } from "./chunk-T6MTNGBM.js";
85
87
  import {
86
88
  INDEXED_STORE_POLICY
87
89
  } from "./chunk-2QR2PQTT.js";
@@ -91,30 +93,30 @@ import {
91
93
  import {
92
94
  LEDGER_COLLECTION,
93
95
  LEDGER_DELTAS_COLLECTION
94
- } from "./chunk-74JEQFMT.js";
96
+ } from "./chunk-6A4AMQ2H.js";
95
97
  import {
96
98
  sha256Hex as sha256Hex2
97
- } from "./chunk-NCO2JGKK.js";
99
+ } from "./chunk-Z6FNBOTC.js";
98
100
  import {
99
101
  NO_AGGREGATE,
100
102
  Query,
101
103
  ScanBuilder
102
- } from "./chunk-4UBOTYP5.js";
104
+ } from "./chunk-XDW37COG.js";
103
105
  import {
104
106
  EXPORT_AUDIT_COLLECTION,
105
107
  createExportBlobsHandle,
106
108
  runCompaction
107
- } from "./chunk-LOL725S4.js";
109
+ } from "./chunk-JSYTGEX4.js";
108
110
  import {
109
111
  NOYDB_BACKUP_VERSION,
110
112
  NOYDB_FORMAT_VERSION
111
- } from "./chunk-FXQYZNOW.js";
113
+ } from "./chunk-5OVIFUQE.js";
112
114
  import {
113
115
  decrypt,
114
116
  encrypt,
115
117
  encryptDeterministic,
116
118
  sha256Hex
117
- } from "./chunk-UOF74WQY.js";
119
+ } from "./chunk-EKTOYEZ3.js";
118
120
  import {
119
121
  AlreadyElevatedError,
120
122
  AttestationError,
@@ -141,7 +143,7 @@ import {
141
143
  TierNotGrantedError,
142
144
  TranslatorNotConfiguredError,
143
145
  ValidationError
144
- } from "./chunk-YDLAFP36.js";
146
+ } from "./chunk-6HJ2ZALB.js";
145
147
 
146
148
  // src/policy/storage.ts
147
149
  var META_COLLECTION = "_meta";
@@ -644,7 +646,7 @@ async function resolveStaleOnRead(accessor, outputCollection, id) {
644
646
  }
645
647
  const sourceWithId = { ...source, id };
646
648
  if (DerivationExecutor === null) {
647
- ({ DerivationExecutor } = await import("./executor-GFZFDQXV.js"));
649
+ ({ DerivationExecutor } = await import("./executor-SOLEQVUB.js"));
648
650
  }
649
651
  const ctx = { vault: accessor.getReadOnlyFacade() };
650
652
  const result = await DerivationExecutor.run(spec, sourceWithId, 0, strategyHash, ctx);
@@ -664,7 +666,7 @@ async function resolveStaleOnRead(accessor, outputCollection, id) {
664
666
  }
665
667
  if (out.kind === "array") {
666
668
  console.warn(
667
- `[derivation] unexpected array-shape output "${key}" in lazy resolve path; array-shape derivations require lifecycle: "eager" (#200 slice 1).`
669
+ `[derivation] unexpected array-shape output "${key}" in lazy resolve path; array-shape derivations require lifecycle: "eager".`
668
670
  );
669
671
  continue;
670
672
  }
@@ -702,6 +704,7 @@ var Collection = class {
702
704
  schemaUpdateGate;
703
705
  schemaFence;
704
706
  writeHooks;
707
+ subsystemBus;
705
708
  activeTxId;
706
709
  getDEK;
707
710
  onDirty;
@@ -890,42 +893,14 @@ var Collection = class {
890
893
  syncAdapter;
891
894
  /** — consent-audit hook, no-op when no scope is active. */
892
895
  onAccess;
893
- /**
894
- * accounting-period write guard. Called BEFORE any
895
- * adapter write with:
896
- * - `existing` — the prior envelope's `_ts` and decrypted record
897
- * (or `null` if no prior envelope exists)
898
- * - `incoming` — the record being written (or `null` for delete)
899
- *
900
- * Throws `PeriodClosedError` if either side falls inside a closed
901
- * period. Installed by Vault; no-op when no period has been closed.
902
- * Async so the Vault can lazy-load the period list from the
903
- * adapter on first use.
904
- */
905
- periodGuard;
906
- /**
907
- * Optional back-reference to the owning vault's guard registry + a
908
- * read-only vault facade. When present, `Collection.put` and
909
- * `Collection.delete` consult the registry for guards declared
910
- * against this collection and run their `check` + `frozenFields`
911
- * before the adapter write. Absent in unit tests that construct
912
- * a Collection directly; production code always sets it via
913
- * `Vault.collection()`.
914
- *
915
- * Typed structurally rather than as `Vault` to avoid a circular
916
- * import (mirrors the `refEnforcer` / `joinResolver` pattern).
917
- */
918
- guardSource;
919
896
  /**
920
897
  * Vault-internal hook for derivation dispatch. When set,
921
898
  * `Collection.put` consults the registry after the source-write
922
899
  * commits and writes derived outputs through `getCollection(name).put`.
923
- * Same structural-interface pattern as `guardSource` to avoid a
924
- * circular Vault import.
925
900
  */
926
901
  derivationSource;
927
902
  /**
928
- * Vault-internal hook for materialized-view dispatch (#143/#150).
903
+ * Vault-internal hook for materialized-view dispatch.
929
904
  * Parallel to `derivationSource` — when set, `Collection.put` fires
930
905
  * `MaterializedViewRegistry.onSourceWrite` after the source-write
931
906
  * commits + after `dispatchDerivations` has run.
@@ -981,6 +956,7 @@ var Collection = class {
981
956
  this.schemaUpdateGate = opts.schemaUpdateGate;
982
957
  this.schemaFence = opts.schemaFence;
983
958
  this.writeHooks = opts.writeHooks;
959
+ this.subsystemBus = opts.subsystemBus;
984
960
  this.activeTxId = opts.activeTxId;
985
961
  this.blobStrategy = opts.blobStrategy ?? NO_BLOBS;
986
962
  this.aggregateStrategy = opts.aggregateStrategy ?? NO_AGGREGATE;
@@ -1005,8 +981,6 @@ var Collection = class {
1005
981
  this.crdtMode = opts.crdt;
1006
982
  this.syncAdapter = opts.syncAdapter;
1007
983
  this.onAccess = opts.onAccess;
1008
- this.periodGuard = opts.periodGuard;
1009
- this.guardSource = opts.guardSource;
1010
984
  this.derivationSource = opts.derivationSource;
1011
985
  this.materializedViewSource = opts.materializedViewSource;
1012
986
  this.tiers = opts.tiers && opts.tiers.length > 0 ? new Set(opts.tiers) : null;
@@ -1140,7 +1114,7 @@ var Collection = class {
1140
1114
  }
1141
1115
  }
1142
1116
  if (this.materializedViewSource !== void 0) {
1143
- const { resolveStaleMVOnRead } = await import("./stale-PAGCS4K5.js");
1117
+ const { resolveStaleMVOnRead } = await import("./stale-74WGLVZ2.js");
1144
1118
  await resolveStaleMVOnRead(this.materializedViewSource, this.name);
1145
1119
  }
1146
1120
  let record;
@@ -1208,21 +1182,23 @@ var Collection = class {
1208
1182
  }
1209
1183
  /**
1210
1184
  * Create or update a record. Runs inside the hub's write-queue tracker
1211
- * (#227) so `hub.writeQueue.pending` reflects this write.
1185
+ * so `hub.writeQueue.pending` reflects this write.
1212
1186
  *
1213
1187
  * @param id Record identifier.
1214
1188
  * @param record The record body (validated by the collection's schema
1215
1189
  * if one was attached at `vault.collection(...)` time).
1216
1190
  * @param options Optional metadata for audit + import workflows.
1217
1191
  * `reason` is stamped onto the resulting ledger entry
1218
- * (see #1) so audit consumers can filter via
1192
+ * so audit consumers can filter via
1219
1193
  * `entries.filter(e => e.reason?.startsWith('import:'))`.
1220
1194
  */
1221
1195
  async put(id, record, options) {
1222
1196
  await this.schemaUpdateGate?.assertWritable();
1223
1197
  await this.schemaFence?.assertWritable(this.name);
1198
+ const hooksActive = this.#hooksActive();
1199
+ const busAfterPut = (this.subsystemBus?.hasHandlers("afterPut") ?? false) && !(this.subsystemBus?.dispatching ?? false);
1224
1200
  let event;
1225
- if (this.#hooksActive()) {
1201
+ if (hooksActive || busAfterPut) {
1226
1202
  const prior = await this.#priorForHook(id);
1227
1203
  event = {
1228
1204
  op: prior.record === null ? "create" : "update",
@@ -1237,23 +1213,26 @@ var Collection = class {
1237
1213
  baseVersion: prior.version,
1238
1214
  version: prior.version + 1
1239
1215
  };
1240
- await this.writeHooks.runBefore(event);
1216
+ if (hooksActive) await this.writeHooks.runBefore(event);
1241
1217
  }
1242
1218
  if (this.writeQueue) await this.writeQueue.track(() => this.putInternal(id, record, options));
1243
1219
  else await this.putInternal(id, record, options);
1244
- if (event) await this.writeHooks.runAfter(event);
1220
+ if (event) {
1221
+ if (hooksActive) await this.writeHooks.runAfter(event);
1222
+ if (busAfterPut) await this.subsystemBus.dispatch("afterPut", event);
1223
+ }
1245
1224
  }
1246
- /** @internal #230 — true when hooks should fire for this write (handlers exist, not re-entrant). */
1225
+ /** @internal — true when hooks should fire for this write (handlers exist, not re-entrant). */
1247
1226
  #hooksActive() {
1248
1227
  return this.writeHooks !== void 0 && this.writeHooks.hasHandlers && !this.writeHooks.suppressed;
1249
1228
  }
1250
1229
  /**
1251
- * @internal #230/#228c — resolve the prior record for a hook's `before` and
1230
+ * @internal — resolve the prior record for a hook's `before` and
1252
1231
  * its version. Critically, this uses the SAME basis `putInternal` writes from
1253
1232
  * (the in-memory cache in eager mode; lru-then-adapter in lazy) — NOT a fresh
1254
1233
  * store read — so `baseVersion`/`version` match the version actually written.
1255
1234
  * A separate store read would diverge once another tab has advanced the shared
1256
- * store past this tab's cache, breaking #228c conflict detection.
1235
+ * store past this tab's cache, breaking cross-tab conflict detection.
1257
1236
  */
1258
1237
  async #priorForHook(id) {
1259
1238
  if (this.lazy && this.lru) {
@@ -1275,52 +1254,28 @@ var Collection = class {
1275
1254
  if (!hasWritePermission(this.keyring, this.name)) {
1276
1255
  throw new ReadOnlyError();
1277
1256
  }
1278
- if (this.guardSource) {
1279
- const registry = this.guardSource.registry();
1280
- const guards = registry.guardsFor(this.name);
1281
- if (guards.length > 0) {
1282
- const existingEnv = await this.adapter.get(this.vault, this.name, id);
1283
- let existingRecord = null;
1284
- if (existingEnv) {
1285
- try {
1286
- existingRecord = await this.decryptRecord(existingEnv, { skipValidation: true });
1287
- } catch {
1288
- existingRecord = null;
1289
- }
1290
- }
1291
- const incomingRecord = record;
1292
- const ctx = {
1293
- existing: existingRecord,
1294
- vault: this.guardSource.readOnlyVault(),
1295
- userId: this.keyring.userId,
1296
- role: this.keyring.role
1297
- };
1298
- if (registry.isAmendmentActive()) {
1299
- const vBefore = existingEnv?._v ?? 0;
1300
- registry.collectChange(this.name, id, existingRecord, incomingRecord, vBefore, vBefore + 1);
1301
- } else {
1302
- await registry.runChecks(this.name, incomingRecord, ctx);
1303
- const { GuardExecutor } = await import("./executor-BZKFZVRC.js");
1304
- for (const g of guards) {
1305
- await GuardExecutor.checkFrozenFields(g, id, existingRecord, incomingRecord);
1306
- }
1307
- }
1308
- }
1309
- }
1310
- if (this.periodGuard !== void 0) {
1257
+ if (this.subsystemBus?.hasGateHandlers("beforePut")) {
1311
1258
  const existingEnv = await this.adapter.get(this.vault, this.name, id);
1312
- let priorRecord = null;
1259
+ let existingRecord = null;
1313
1260
  if (existingEnv) {
1314
1261
  try {
1315
- priorRecord = await this.decryptRecord(existingEnv, { skipValidation: true });
1262
+ existingRecord = await this.decryptRecord(existingEnv, { skipValidation: true });
1316
1263
  } catch {
1317
- priorRecord = null;
1264
+ existingRecord = null;
1318
1265
  }
1319
1266
  }
1320
- await this.periodGuard(
1321
- existingEnv ? { ts: existingEnv._ts, record: priorRecord } : null,
1322
- record
1323
- );
1267
+ await this.subsystemBus.dispatchGate("beforePut", {
1268
+ op: existingEnv ? "update" : "create",
1269
+ vault: this.vault,
1270
+ collection: this.name,
1271
+ docId: id,
1272
+ incoming: record,
1273
+ existing: existingRecord,
1274
+ existingVersion: existingEnv?._v ?? 0,
1275
+ existingTs: existingEnv?._ts,
1276
+ userId: this.keyring.userId,
1277
+ role: this.keyring.role
1278
+ });
1324
1279
  }
1325
1280
  if (this.schema !== void 0) {
1326
1281
  record = await validateSchemaInput(this.schema, record, `put(${id})`);
@@ -1329,7 +1284,9 @@ var Collection = class {
1329
1284
  const obj = record;
1330
1285
  for (const [field, descriptor] of Object.entries(this.i18nFields)) {
1331
1286
  if (!descriptor.options.autoTranslate) continue;
1332
- const value = obj[field];
1287
+ const leafValues = getAtPath(obj, field);
1288
+ if (leafValues.length !== 1) continue;
1289
+ const value = leafValues[0];
1333
1290
  if (!value || typeof value !== "object" || Array.isArray(value)) continue;
1334
1291
  const map = value;
1335
1292
  const { languages, required } = descriptor.options;
@@ -1353,8 +1310,7 @@ var Collection = class {
1353
1310
  this.name
1354
1311
  );
1355
1312
  }
1356
- ;
1357
- record[field] = translated;
1313
+ setAtPathInPlace(obj, field, translated);
1358
1314
  }
1359
1315
  }
1360
1316
  if (this.i18nPutValidator !== void 0) {
@@ -1506,7 +1462,7 @@ var Collection = class {
1506
1462
  * Fire registered MV strategies whose dependency set includes this
1507
1463
  * collection. Eager-mode MVs re-materialize inline via
1508
1464
  * `MaterializedViewExecutor.refresh`; lazy / manual modes are
1509
- * no-ops in the foundation (subtask #150) wired in #151.
1465
+ * no-ops in the foundation; wired in the lazy-mode implementation.
1510
1466
  *
1511
1467
  * Skips entirely when the record being written is itself an
1512
1468
  * MV-emitted row (carries `_materializedFrom`) — defensive guard
@@ -1529,7 +1485,7 @@ var Collection = class {
1529
1485
  if (mode === "eager") {
1530
1486
  if (executor === null) {
1531
1487
  ;
1532
- ({ MaterializedViewExecutor: executor } = await import("./executor-KT2IOZVP.js"));
1488
+ ({ MaterializedViewExecutor: executor } = await import("./executor-RWICJI7J.js"));
1533
1489
  }
1534
1490
  await executor.refresh(reg, {
1535
1491
  getCollection: (name) => this.materializedViewSource.getCollection(name),
@@ -1538,7 +1494,7 @@ var Collection = class {
1538
1494
  });
1539
1495
  } else if (mode === "lazy") {
1540
1496
  if (staleHelpers === null) {
1541
- staleHelpers = await import("./stale-PAGCS4K5.js");
1497
+ staleHelpers = await import("./stale-74WGLVZ2.js");
1542
1498
  }
1543
1499
  staleHelpers.markMVStale(registry, reg.spec.name);
1544
1500
  }
@@ -1567,7 +1523,7 @@ var Collection = class {
1567
1523
  const mode = typeof spec.lifecycle === "string" ? spec.lifecycle : spec.lifecycle.mode;
1568
1524
  if (mode === "eager") {
1569
1525
  if (DerivationExecutor === null) {
1570
- ({ DerivationExecutor } = await import("./executor-GFZFDQXV.js"));
1526
+ ({ DerivationExecutor } = await import("./executor-SOLEQVUB.js"));
1571
1527
  }
1572
1528
  const sourceWithId = { ...incoming, id };
1573
1529
  const ctx = { vault: this.derivationSource.getReadOnlyFacade() };
@@ -1586,7 +1542,7 @@ var Collection = class {
1586
1542
  const outputCollection = this.derivationSource.getCollection(outSpec.collection);
1587
1543
  const txCtx = this.derivationSource.getActiveTxContext();
1588
1544
  if (out.kind === "array") {
1589
- const { loadFanoutSidecar, saveFanoutSidecar } = await import("./fanout-sidecar-NRBWSLRK.js");
1545
+ const { loadFanoutSidecar, saveFanoutSidecar } = await import("./fanout-sidecar-EVICRM46.js");
1590
1546
  const prior = await loadFanoutSidecar(
1591
1547
  this.adapter,
1592
1548
  this.vault,
@@ -1650,13 +1606,15 @@ var Collection = class {
1650
1606
  }
1651
1607
  /**
1652
1608
  * Delete a record by ID. Runs inside the hub's write-queue tracker
1653
- * (#227) so `hub.writeQueue.pending` reflects this write.
1609
+ * so `hub.writeQueue.pending` reflects this write.
1654
1610
  */
1655
1611
  async delete(id) {
1656
1612
  await this.schemaUpdateGate?.assertWritable();
1657
1613
  await this.schemaFence?.assertWritable(this.name);
1614
+ const hooksActive = this.#hooksActive();
1615
+ const busAfterDelete = (this.subsystemBus?.hasHandlers("afterDelete") ?? false) && !(this.subsystemBus?.dispatching ?? false);
1658
1616
  let event;
1659
- if (this.#hooksActive()) {
1617
+ if (hooksActive || busAfterDelete) {
1660
1618
  const prior = await this.#priorForHook(id);
1661
1619
  event = {
1662
1620
  op: "delete",
@@ -1671,14 +1629,17 @@ var Collection = class {
1671
1629
  baseVersion: prior.version,
1672
1630
  version: prior.version + 1
1673
1631
  };
1674
- await this.writeHooks.runBefore(event);
1632
+ if (hooksActive) await this.writeHooks.runBefore(event);
1675
1633
  }
1676
1634
  if (this.writeQueue) await this.writeQueue.track(() => this.deleteInternal(id));
1677
1635
  else await this.deleteInternal(id);
1678
- if (event) await this.writeHooks.runAfter(event);
1636
+ if (event) {
1637
+ if (hooksActive) await this.writeHooks.runAfter(event);
1638
+ if (busAfterDelete) await this.subsystemBus.dispatch("afterDelete", event);
1639
+ }
1679
1640
  }
1680
1641
  /**
1681
- * @internal #232 — bulk-rewrite every record through a cutover transform.
1642
+ * @internal — bulk-rewrite every record through a cutover transform.
1682
1643
  * Raw adapter path (bypasses the write gate + guards — the transform is
1683
1644
  * trusted and runs only during the `migrating` phase). Bumps each
1684
1645
  * record's `_v` and appends a ledger `op:'migration'` entry.
@@ -1717,8 +1678,7 @@ var Collection = class {
1717
1678
  }
1718
1679
  /**
1719
1680
  * @internal — system-internal delete that bypasses user-facing
1720
- * delete hooks (`onDelete`, accounting-period guard, FK ref
1721
- * enforcer). Used by derivation tombstones (#144) and MV refresh
1681
+ * delete hooks (`onDelete`, FK ref enforcer). Used by derivation tombstones and MV refresh
1722
1682
  * (Dim 14 v2) — system housekeeping shouldn't trip user invariants
1723
1683
  * registered against the output collection. The ledger entry and
1724
1684
  * history snapshot still fire so backup integrity and time-travel
@@ -1730,7 +1690,7 @@ var Collection = class {
1730
1690
  *
1731
1691
  * When a `txCtx` is supplied, the prior envelope is captured and
1732
1692
  * pushed onto `txCtx._executed` BEFORE the delete fires — mirrors
1733
- * the #133 rollback hardening for puts. Callers outside a
1693
+ * the rollback hardening for puts. Callers outside a
1734
1694
  * multi-record transaction pass `null` and skip the tracking.
1735
1695
  *
1736
1696
  * Amendment composition: if `_internalDelete` runs while a vault's
@@ -1773,58 +1733,27 @@ var Collection = class {
1773
1733
  if (!hasWritePermission(this.keyring, this.name)) {
1774
1734
  throw new ReadOnlyError();
1775
1735
  }
1776
- if (this.guardSource) {
1777
- const registry = this.guardSource.registry();
1778
- const guards = registry.guardsFor(this.name);
1779
- if (guards.length > 0) {
1780
- const existingEnv = await this.adapter.get(this.vault, this.name, id);
1781
- if (existingEnv) {
1782
- let existingRecord = null;
1783
- try {
1784
- existingRecord = await this.decryptRecord(existingEnv, { skipValidation: true });
1785
- } catch {
1786
- existingRecord = null;
1787
- }
1788
- if (registry.isAmendmentActive()) {
1789
- const vBefore = existingEnv._v;
1790
- registry.collectChange(
1791
- this.name,
1792
- id,
1793
- existingRecord,
1794
- null,
1795
- vBefore,
1796
- vBefore
1797
- );
1798
- } else if (!internal) {
1799
- const ctx = {
1800
- existing: existingRecord,
1801
- vault: this.guardSource.readOnlyVault(),
1802
- userId: this.keyring.userId,
1803
- role: this.keyring.role
1804
- };
1805
- await registry.runOnDelete(
1806
- this.name,
1807
- existingRecord ?? {},
1808
- ctx
1809
- );
1810
- }
1811
- }
1812
- }
1813
- }
1814
- if (!internal && this.periodGuard !== void 0) {
1736
+ if (this.subsystemBus?.hasGateHandlers("beforeDelete")) {
1815
1737
  const existingEnv = await this.adapter.get(this.vault, this.name, id);
1816
- let priorRecord = null;
1817
1738
  if (existingEnv) {
1739
+ let existingRecord = null;
1818
1740
  try {
1819
- priorRecord = await this.decryptRecord(existingEnv, { skipValidation: true });
1741
+ existingRecord = await this.decryptRecord(existingEnv, { skipValidation: true });
1820
1742
  } catch {
1821
- priorRecord = null;
1743
+ existingRecord = null;
1822
1744
  }
1745
+ await this.subsystemBus.dispatchGate("beforeDelete", {
1746
+ vault: this.vault,
1747
+ collection: this.name,
1748
+ docId: id,
1749
+ existing: existingRecord,
1750
+ existingVersion: existingEnv._v,
1751
+ existingTs: existingEnv._ts,
1752
+ internal,
1753
+ userId: this.keyring.userId,
1754
+ role: this.keyring.role
1755
+ });
1823
1756
  }
1824
- await this.periodGuard(
1825
- existingEnv ? { ts: existingEnv._ts, record: priorRecord } : null,
1826
- null
1827
- );
1828
1757
  }
1829
1758
  if (!internal && this.refEnforcer !== void 0) {
1830
1759
  await this.refEnforcer.enforceRefsOnDelete(this.name, id);
@@ -1885,7 +1814,7 @@ var Collection = class {
1885
1814
  }
1886
1815
  /**
1887
1816
  * Cascade deletes of array-shape derived rows when a source row is
1888
- * deleted (#200). Reads each registered strategy's fanout sidecar
1817
+ * deleted. Reads each registered strategy's fanout sidecar
1889
1818
  * for this source id, deletes every listed derived row, then
1890
1819
  * deletes the sidecar itself.
1891
1820
  *
@@ -1905,7 +1834,7 @@ var Collection = class {
1905
1834
  for (const [outputKey, outSpec] of Object.entries(spec.outputs)) {
1906
1835
  if (outSpec.shape !== "array") continue;
1907
1836
  if (helpers === null) {
1908
- helpers = await import("./fanout-sidecar-NRBWSLRK.js");
1837
+ helpers = await import("./fanout-sidecar-EVICRM46.js");
1909
1838
  }
1910
1839
  const sidecar = await helpers.loadFanoutSidecar(
1911
1840
  this.adapter,
@@ -1924,8 +1853,8 @@ var Collection = class {
1924
1853
  }
1925
1854
  }
1926
1855
  /**
1927
- * Mirror of {@link dispatchMaterializedViews} for the delete path
1928
- * (#181). No record content is available (it's gone), so the
1856
+ * Mirror of {@link dispatchMaterializedViews} for the delete path.
1857
+ * No record content is available (it's gone), so the
1929
1858
  * `_materializedFrom` skip used by the put-side dispatch doesn't
1930
1859
  * apply here — instead, the recursion guard is the `internal` gate
1931
1860
  * at the `_doDelete` call site above.
@@ -1945,7 +1874,7 @@ var Collection = class {
1945
1874
  if (mode === "eager") {
1946
1875
  if (executor === null) {
1947
1876
  ;
1948
- ({ MaterializedViewExecutor: executor } = await import("./executor-KT2IOZVP.js"));
1877
+ ({ MaterializedViewExecutor: executor } = await import("./executor-RWICJI7J.js"));
1949
1878
  }
1950
1879
  await executor.refresh(reg, {
1951
1880
  getCollection: (name) => this.materializedViewSource.getCollection(name),
@@ -1954,7 +1883,7 @@ var Collection = class {
1954
1883
  });
1955
1884
  } else if (mode === "lazy") {
1956
1885
  if (staleHelpers === null) {
1957
- staleHelpers = await import("./stale-PAGCS4K5.js");
1886
+ staleHelpers = await import("./stale-74WGLVZ2.js");
1958
1887
  }
1959
1888
  staleHelpers.markMVStale(registry, reg.spec.name);
1960
1889
  }
@@ -1977,7 +1906,7 @@ var Collection = class {
1977
1906
  );
1978
1907
  }
1979
1908
  if (this.materializedViewSource !== void 0) {
1980
- const { resolveStaleMVOnRead } = await import("./stale-PAGCS4K5.js");
1909
+ const { resolveStaleMVOnRead } = await import("./stale-74WGLVZ2.js");
1981
1910
  await resolveStaleMVOnRead(this.materializedViewSource, this.name);
1982
1911
  }
1983
1912
  await this.ensureHydrated();
@@ -2455,7 +2384,7 @@ var Collection = class {
2455
2384
  * .aggregate({ total: sum('amount'), n: count() })
2456
2385
  * ```
2457
2386
  *
2458
- * **Lazy-MV gap (#157):** `scan()` is synchronous-build and does
2387
+ * **Lazy-MV gap:** `scan()` is synchronous-build and does
2459
2388
  * NOT trigger lazy materialized-view resolve-on-read. For lazy
2460
2389
  * MVs, call `list()` (which DOES resolve) or `vault.refreshView(name)`
2461
2390
  * before scanning. Same shape as the `query()` limitation.
@@ -2536,7 +2465,7 @@ var Collection = class {
2536
2465
  this.indexes?.upsert(id, record, previous ? previous.record : null);
2537
2466
  }
2538
2467
  /**
2539
- * #228b — apply a peer tab's committed write to THIS tab's in-memory view:
2468
+ * Apply a peer tab's committed write to THIS tab's in-memory view:
2540
2469
  * re-read the (already-persisted) envelope from the shared store + refresh
2541
2470
  * cache/indexes, then emit a `change` event so reactive consumers re-render.
2542
2471
  * Never writes to the store and never fires write hooks, so it cannot loop.
@@ -2545,7 +2474,7 @@ var Collection = class {
2545
2474
  await this._invalidateCacheEntry(id);
2546
2475
  this.emitter.emit("change", { vault: this.vault, collection: this.name, id, action });
2547
2476
  }
2548
- /** @internal #228c — the current in-memory record without a store read (for conflict capture). */
2477
+ /** @internal — the current in-memory record without a store read (for conflict capture). */
2549
2478
  _peekCached(id) {
2550
2479
  const entry = this.lazy && this.lru ? this.lru.get(id) : this.cache.get(id);
2551
2480
  return entry ? entry.record : null;
@@ -3648,7 +3577,7 @@ var UserApi = class {
3648
3577
  * the envelope on first call. Optimistic-concurrency safe — a stale
3649
3578
  * `_v` (parallel writer on another device) throws `ConflictError`.
3650
3579
  *
3651
- * Patch semantics (#57):
3580
+ * Patch semantics:
3652
3581
  * - `undefined` (or omitted key) — skip; existing value preserved
3653
3582
  * - `null` — delete the field from the merged result
3654
3583
  * - any other value — overwrite (deep-merge for plain objects,
@@ -3704,7 +3633,7 @@ var UserApi = class {
3704
3633
  this.fireChange(this.writerKeyringId, written);
3705
3634
  return written;
3706
3635
  }
3707
- // ─── Visibility (#122) ───────────────────────────────────────────────
3636
+ // ─── Visibility ──────────────────────────────────────────────────────
3708
3637
  /**
3709
3638
  * Read the current user's visibility flag from
3710
3639
  * `_meta/visibility/<keyringId>`. Returns `{ hidden: false }` when no
@@ -4554,23 +4483,23 @@ var Vault = class {
4554
4483
  * `null` for vaults that never register any guard strategy. The
4555
4484
  * runtime class is dynamic-imported on demand so consumers that
4556
4485
  * never use guards don't pull `GuardRegistry`/`GuardExecutor` into
4557
- * their bundle (#130).
4486
+ * their bundle.
4558
4487
  */
4559
4488
  guardRegistry = null;
4560
4489
  /**
4561
4490
  * Per-vault derivation registry. Same lazy-load contract as
4562
4491
  * `guardRegistry` — `null` until `_initDerivations()` runs with at
4563
- * least one strategy handle. See #130 for the bundle motivation.
4492
+ * least one strategy handle.
4564
4493
  */
4565
4494
  derivationRegistry = null;
4566
4495
  /**
4567
- * Per-vault materialized-view registry (#143/#150). Same lazy-load
4496
+ * Per-vault materialized-view registry. Same lazy-load
4568
4497
  * contract as `derivationRegistry` — `null` until
4569
4498
  * `_initMaterializedViews()` runs with at least one MV handle.
4570
4499
  */
4571
4500
  materializedViewRegistry = null;
4572
4501
  /**
4573
- * Per-vault overlay registry (#154). Same lazy-load contract as
4502
+ * Per-vault overlay registry. Same lazy-load contract as
4574
4503
  * `materializedViewRegistry` — `null` until `_initOverlayedViews()`
4575
4504
  * runs with at least one handle.
4576
4505
  */
@@ -4591,7 +4520,7 @@ var Vault = class {
4591
4520
  * target this vault session's keyringId. There is no method to write
4592
4521
  * another principal's envelope (own-only write rule, structural).
4593
4522
  * - Read-anyone: `get(keyringId)`, `list()` — read other principals'
4594
- * envelopes, subject to the `view-team-profiles` policy gate (#22).
4523
+ * envelopes, subject to the `view-team-profiles` policy gate.
4595
4524
  * - Reactive: `subscribe(id, cb)`, `live(id)` — fire on local writes.
4596
4525
  *
4597
4526
  * @see docs/superpowers/specs/2026-05-05-user-envelope-design.md
@@ -4611,12 +4540,12 @@ var Vault = class {
4611
4540
  */
4612
4541
  reloadKeyring;
4613
4542
  collectionCache = /* @__PURE__ */ new Map();
4614
- /** #232 — vault-level schema cutover fence/controller. */
4543
+ /** Vault-level schema cutover fence/controller. */
4615
4544
  schemaFence;
4616
- /** #232 — per-client heartbeat/watcher; started lazily on cutover registration. */
4545
+ /** Per-client heartbeat/watcher; started lazily on cutover registration. */
4617
4546
  #fenceWatcher;
4618
4547
  #fenceCoordinationStarted = false;
4619
- /** #229 — per-collection registered schema-update strategy names. */
4548
+ /** Per-collection registered schema-update strategy names. */
4620
4549
  #schemaUpdateNames = /* @__PURE__ */ new Map();
4621
4550
  /**
4622
4551
  * per-collection `blobFields` retention/TTL config.
@@ -4690,8 +4619,7 @@ var Vault = class {
4690
4619
  * Cache of closed/opened accounting periods.
4691
4620
  * Populated on first `closePeriod` / `openPeriod` / `listPeriods` /
4692
4621
  * per-collection write call. Kept in memory as an ordered list (by
4693
- * `closedAt`) so the `periodGuard` hook runs synchronously against
4694
- * each collection's put/delete path.
4622
+ * `closedAt`) so period checks run fast when the gate bus fires.
4695
4623
  *
4696
4624
  * Sentinel `null` means "not yet loaded" — the first consumer
4697
4625
  * triggers a one-time `loadPeriods()` pass. Every subsequent
@@ -4886,6 +4814,7 @@ var Vault = class {
4886
4814
  emitter: this.emitter,
4887
4815
  writeQueue: this.noydb._writeQueueTracker,
4888
4816
  writeHooks: this.noydb._writeHooks,
4817
+ subsystemBus: this.noydb._subsystemBus,
4889
4818
  activeTxId: () => this.noydb._activeTxContextOrNull?.txId ?? null,
4890
4819
  schemaUpdateGate,
4891
4820
  schemaFence: this.schemaFence,
@@ -4908,18 +4837,12 @@ var Vault = class {
4908
4837
  defaultLocale: this.locale,
4909
4838
  onRegisterConflictResolver: this.onRegisterConflictResolver,
4910
4839
  onAccess: (op, id) => this._logConsent(op, collectionName, id),
4911
- periodGuard: (existing, incoming) => this._assertTsWritable(existing, incoming),
4912
- // Guard / derivation sources are only wired when the
4913
- // corresponding registry has been initialised. Vaults without
4914
- // guards/derivations skip this entirely so `Collection.put`'s
4915
- // `if (this.guardSource)` / `if (this.derivationSource)`
4916
- // branches no-op without ever touching the subsystem code.
4917
- ...this.guardRegistry !== null ? {
4918
- guardSource: {
4919
- registry: () => this.guardRegistry,
4920
- readOnlyVault: () => this._ensureReadOnlyFacade()
4921
- }
4922
- } : {},
4840
+ // Derivation source is only wired when the corresponding registry
4841
+ // has been initialised. Guard source was removed in Track A slice 3b
4842
+ // guards now run via the gate bus in Noydb.#registerGuardGate.
4843
+ // Vaults without derivations skip this so `Collection.put`'s
4844
+ // `if (this.derivationSource)` branch no-ops without touching the
4845
+ // derivation subsystem code.
4923
4846
  ...this.derivationRegistry !== null ? {
4924
4847
  derivationSource: {
4925
4848
  registry: () => this.derivationRegistry,
@@ -5009,7 +4932,7 @@ var Vault = class {
5009
4932
  await Promise.allSettled(pending);
5010
4933
  }
5011
4934
  /**
5012
- * Run a coordinated schema cutover (#232). Drains pending writes, waits
4935
+ * Run a coordinated schema cutover. Drains pending writes, waits
5013
4936
  * for the active client set to quiesce (the ack-barrier), applies every
5014
4937
  * pending collection transform in bulk, bumps the vault schema generation,
5015
4938
  * and clears the fence. Returns the count of collections migrated.
@@ -5027,9 +4950,9 @@ var Vault = class {
5027
4950
  await coll._applyCutoverTransform(transform);
5028
4951
  }
5029
4952
  /**
5030
- * #228b — refresh a loaded collection's view of one document from a peer
4953
+ * Refresh a loaded collection's view of one document from a peer
5031
4954
  * tab's broadcast. No-op when the collection isn't loaded in this tab
5032
- * (it will read fresh on next open). Mirrors #runCutoverTransform's guard.
4955
+ * (it will read fresh on next open). Mirrors `#runCutoverTransform`'s guard.
5033
4956
  */
5034
4957
  async _applyRemoteWrite(collectionName, docId, action) {
5035
4958
  const coll = this.collectionCache.get(collectionName);
@@ -5037,9 +4960,9 @@ var Vault = class {
5037
4960
  await coll._applyRemoteChange(docId, action);
5038
4961
  }
5039
4962
  /**
5040
- * #228c — for a detected conflict: capture this tab's clobbered record,
4963
+ * For a detected conflict: capture this tab's clobbered record,
5041
4964
  * read the common ancestor from history, converge the cache to the store's
5042
- * authoritative value (the (b) re-read), and return all three for the
4965
+ * authoritative value (the re-read), and return all three for the
5043
4966
  * WriteConflict payload. Returns null when the collection isn't loaded.
5044
4967
  */
5045
4968
  async _captureAndConverge(collectionName, docId, action, baseV) {
@@ -5056,15 +4979,15 @@ var Vault = class {
5056
4979
  const remote = await coll.get(docId);
5057
4980
  return { local, remote, base };
5058
4981
  }
5059
- /** Recover a stuck cutover fence (#232) — reset to normal without bumping. */
4982
+ /** Recover a stuck cutover fence — reset to normal without bumping. */
5060
4983
  async abortSchemaCutover() {
5061
4984
  await this.schemaFence.abort();
5062
4985
  }
5063
- /** Current schema-cutover fence state for this vault (#232/#233). Thin live read. */
4986
+ /** Current schema-cutover fence state for this vault. Thin live read. */
5064
4987
  async schemaFenceState() {
5065
4988
  return loadFence(this.adapter, this.name);
5066
4989
  }
5067
- /** @internal Start the per-client heartbeat + fence watcher once a cutover is registered (#232). */
4990
+ /** @internal Start the per-client heartbeat + fence watcher once a cutover is registered. */
5068
4991
  _ensureFenceCoordination() {
5069
4992
  if (this.#fenceCoordinationStarted) return;
5070
4993
  this.#fenceCoordinationStarted = true;
@@ -5100,9 +5023,11 @@ var Vault = class {
5100
5023
  if (!record || typeof record !== "object") return;
5101
5024
  const obj = record;
5102
5025
  for (const [field, descriptor] of Object.entries(i18nFields)) {
5103
- const value = obj[field];
5104
- if (value === void 0 || value === null) continue;
5105
- this.i18nStrategy.validateI18nTextValue(value, field, descriptor);
5026
+ const values = getAtPath(obj, field);
5027
+ for (const value of values) {
5028
+ if (value === void 0 || value === null) continue;
5029
+ this.i18nStrategy.validateI18nTextValue(value, field, descriptor);
5030
+ }
5106
5031
  }
5107
5032
  }
5108
5033
  /**
@@ -5414,12 +5339,12 @@ var Vault = class {
5414
5339
  if (!fieldSchema) {
5415
5340
  throw new AttestationError(`issueAttestation: collection '${collectionName}' has no attestation field-schema. Declare it via vault.collection('${collectionName}', { attestation: { fields: [...] } }).`);
5416
5341
  }
5417
- const { issueAttestationCore } = await import("./issue-BAJ7ZB4S.js");
5342
+ const { issueAttestationCore } = await import("./issue-IODMTPME.js");
5418
5343
  const out = await issueAttestationCore(this.makeIssueContext(), { collection: collectionName, id, fieldSchema });
5419
5344
  return { docId: out.docId, qr: out.qr, keyId: out.keyId, publicKeyB64: out.publicKeyB64 };
5420
5345
  }
5421
5346
  async getDocumentSigningPublicKey() {
5422
- const { loadSigner, loadOrCreateSigner } = await import("./signer-M4K5HBLD.js");
5347
+ const { loadSigner, loadOrCreateSigner } = await import("./signer-WGDJNWSU.js");
5423
5348
  const existing = await loadSigner(this.adapter, this.name, this.getDEK);
5424
5349
  if (existing) return { keyId: existing.keyId, publicKeyB64: existing.publicKeyB64 };
5425
5350
  if (this.keyring.role !== "owner") {
@@ -5445,19 +5370,19 @@ var Vault = class {
5445
5370
  };
5446
5371
  }
5447
5372
  async revokeAttestation(docId) {
5448
- const { revokeDocCore } = await import("./revoke-7JOVLZFD.js");
5373
+ const { revokeDocCore } = await import("./revoke-R5NIQ74J.js");
5449
5374
  await revokeDocCore(this.makeRevokeContext(), docId);
5450
5375
  }
5451
5376
  async unrevokeAttestation(docId) {
5452
- const { unrevokeDocCore } = await import("./revoke-7JOVLZFD.js");
5377
+ const { unrevokeDocCore } = await import("./revoke-R5NIQ74J.js");
5453
5378
  await unrevokeDocCore(this.makeRevokeContext(), docId);
5454
5379
  }
5455
5380
  async getRevokedDocIds() {
5456
- const { getRevokedDocIdsCore } = await import("./revoke-7JOVLZFD.js");
5381
+ const { getRevokedDocIdsCore } = await import("./revoke-R5NIQ74J.js");
5457
5382
  return getRevokedDocIdsCore(this.makeRevokeContext());
5458
5383
  }
5459
5384
  async publishRevocationList() {
5460
- const { publishRevocationListCore } = await import("./revoke-7JOVLZFD.js");
5385
+ const { publishRevocationListCore } = await import("./revoke-R5NIQ74J.js");
5461
5386
  return publishRevocationListCore(this.makeRevokeContext());
5462
5387
  }
5463
5388
  makeRevokeContext() {
@@ -5737,7 +5662,7 @@ var Vault = class {
5737
5662
  * Dynamic-imports `GuardRegistry` + `ReadOnlyVaultFacade` and seeds
5738
5663
  * the registry with the supplied strategy handles. No-op when the
5739
5664
  * handles array is empty — keeps the guard subsystem out of the
5740
- * floor bundle for consumers that don't use guards (#130).
5665
+ * floor bundle for consumers that don't use guards.
5741
5666
  *
5742
5667
  * The read-only facade is eagerly instantiated here so the sync
5743
5668
  * accessor `_getReadOnlyFacade()` (called from the tx amendment
@@ -5746,7 +5671,7 @@ var Vault = class {
5746
5671
  async _initGuards(handles) {
5747
5672
  if (handles.length === 0) return;
5748
5673
  const [{ GuardRegistry }, { ReadOnlyVaultFacade }] = await Promise.all([
5749
- import("./registry-2IEARCGT.js"),
5674
+ import("./registry-DKEXOJVO.js"),
5750
5675
  import("./read-only-facade-ITU6L7BL.js")
5751
5676
  ]);
5752
5677
  const registry = new GuardRegistry();
@@ -5755,10 +5680,9 @@ var Vault = class {
5755
5680
  this.readOnlyFacade = new ReadOnlyVaultFacade(this);
5756
5681
  }
5757
5682
  /**
5758
- * @internal — Collection.put calls into this. Returns `null` for
5759
- * vaults that never registered any guard strategy. Callers MUST
5760
- * gate on null (the existing `if (this.guardSource)` branches in
5761
- * `Collection` already do this transitively).
5683
+ * @internal — The gate handler in Noydb.#registerGuardGate calls into
5684
+ * this. Returns `null` for vaults that never registered any guard
5685
+ * strategy. Callers MUST gate on null.
5762
5686
  */
5763
5687
  _getGuardRegistry() {
5764
5688
  return this.guardRegistry;
@@ -5769,13 +5693,13 @@ var Vault = class {
5769
5693
  * derivation strategies (async because `strategyHash` computation
5770
5694
  * goes through `crypto.subtle.digest`). No-op when the handles
5771
5695
  * array is empty — keeps the derivation subsystem out of the floor
5772
- * bundle for consumers that don't use derivations (#130). Throws
5696
+ * bundle for consumers that don't use derivations. Throws
5773
5697
  * `DerivationCycleError` if a cycle is detected after registration.
5774
5698
  */
5775
5699
  async _initDerivations(handles) {
5776
5700
  if (handles.length === 0) return;
5777
5701
  const [{ DerivationRegistry }, { ReadOnlyVaultFacade }] = await Promise.all([
5778
- import("./registry-EMGLZGR6.js"),
5702
+ import("./registry-446I2NMN.js"),
5779
5703
  import("./read-only-facade-ITU6L7BL.js")
5780
5704
  ]);
5781
5705
  const registry = new DerivationRegistry();
@@ -5801,12 +5725,12 @@ var Vault = class {
5801
5725
  * MV spec (which invokes its `query()` once for dependency
5802
5726
  * analysis), then runs the unified cycle detection across the MV +
5803
5727
  * derivation graphs. No-op when the handles array is empty — keeps
5804
- * the MV subsystem out of the floor bundle (mirrors v1 #130).
5728
+ * the MV subsystem out of the floor bundle (mirrors the derivation lazy-import pattern).
5805
5729
  * Throws `MaterializedViewCycleError` if a cycle is detected.
5806
5730
  */
5807
5731
  async _initMaterializedViews(handles) {
5808
5732
  if (handles.length === 0) return;
5809
- const { MaterializedViewRegistry } = await import("./registry-CDHASH73.js");
5733
+ const { MaterializedViewRegistry } = await import("./registry-4NEW7LQY.js");
5810
5734
  const registry = new MaterializedViewRegistry();
5811
5735
  this.materializedViewRegistry = registry;
5812
5736
  const db = this;
@@ -5830,7 +5754,7 @@ var Vault = class {
5830
5754
  */
5831
5755
  async _initOverlayedViews(handles) {
5832
5756
  if (handles.length === 0) return;
5833
- const { OverlayedViewRegistry } = await import("./registry-NQALYR77.js");
5757
+ const { OverlayedViewRegistry } = await import("./registry-524KJZG4.js");
5834
5758
  const registry = new OverlayedViewRegistry();
5835
5759
  const mvRegistry = this.materializedViewRegistry;
5836
5760
  const overlayNames = /* @__PURE__ */ new Set();
@@ -5858,13 +5782,13 @@ var Vault = class {
5858
5782
  return this.overlayedViewRegistry;
5859
5783
  }
5860
5784
  /**
5861
- * Manual re-materialize for a single registered MV (#151). Useful
5785
+ * Manual re-materialize for a single registered MV. Useful
5862
5786
  * for `refresh: 'manual'` MVs (whose consumer drives refreshes
5863
5787
  * externally), for stale-bit recovery on vault re-open, and as the
5864
5788
  * explicit bulk-recompute escape hatch after a strategy change.
5865
5789
  *
5866
- * Returns `{ written, deleted, failed }`. `deleted` is always 0 in
5867
- * foundation + this sub-issue — tombstoning lands in #152.
5790
+ * Returns `{ written, deleted, failed }`. `deleted` is always 0
5791
+ * when tombstoning is not enabled.
5868
5792
  *
5869
5793
  * Throws if `name` is not a registered MV.
5870
5794
  */
@@ -5877,13 +5801,13 @@ var Vault = class {
5877
5801
  if (!reg) {
5878
5802
  throw new Error(`refreshView: no MV registered with name "${name}"`);
5879
5803
  }
5880
- const { MaterializedViewExecutor } = await import("./executor-KT2IOZVP.js");
5804
+ const { MaterializedViewExecutor } = await import("./executor-RWICJI7J.js");
5881
5805
  const result = await MaterializedViewExecutor.refresh(reg, {
5882
5806
  getCollection: (n) => this.collection(n),
5883
5807
  getActiveTxContext: () => this.noydb._activeTxContextOrNull,
5884
5808
  getQueryContext: () => this
5885
5809
  });
5886
- const { clearMVStale } = await import("./stale-PAGCS4K5.js");
5810
+ const { clearMVStale } = await import("./stale-74WGLVZ2.js");
5887
5811
  clearMVStale(registry, name);
5888
5812
  return result;
5889
5813
  }
@@ -5899,7 +5823,7 @@ var Vault = class {
5899
5823
  if (registry === null) return { derived: 0, failed: 0 };
5900
5824
  const strategies = registry.strategiesForSource(sourceCollection);
5901
5825
  if (strategies.length === 0) return { derived: 0, failed: 0 };
5902
- const { DerivationExecutor } = await import("./executor-GFZFDQXV.js");
5826
+ const { DerivationExecutor } = await import("./executor-SOLEQVUB.js");
5903
5827
  const sourceColl = this.collection(sourceCollection);
5904
5828
  const records = await sourceColl.list();
5905
5829
  const ctx = { vault: this.readOnlyFacade ?? new (await import("./read-only-facade-ITU6L7BL.js")).ReadOnlyVaultFacade(this) };
@@ -5924,7 +5848,7 @@ var Vault = class {
5924
5848
  if (!outSpec) continue;
5925
5849
  const outputColl = this.collection(outSpec.collection);
5926
5850
  if (out.kind === "array") {
5927
- const { loadFanoutSidecar, saveFanoutSidecar } = await import("./fanout-sidecar-NRBWSLRK.js");
5851
+ const { loadFanoutSidecar, saveFanoutSidecar } = await import("./fanout-sidecar-EVICRM46.js");
5928
5852
  const prior = await loadFanoutSidecar(this.adapter, this.name, spec.source, id, key);
5929
5853
  const prevKeys = new Set(prior?.keys ?? []);
5930
5854
  const newKeysList = out.entries.map((e) => e.key);
@@ -5960,22 +5884,19 @@ var Vault = class {
5960
5884
  /**
5961
5885
  * @internal — exposed for `runTransaction({ amendment: true })` so
5962
5886
  * the amendment invariant runner can pass the SAME read-only vault
5963
- * facade that the per-record `Collection.put` guard hook uses
5964
- * (`guardSource.readOnlyVault()` above). Eagerly instantiated by
5965
- * `_initGuards()` so this accessor stays synchronous; returns
5966
- * `null` for vaults that never registered any guard (amendments
5967
- * require at least one guard, so the caller should never see null).
5887
+ * facade that the gate handler in Noydb.#registerGuardGate uses.
5888
+ * Eagerly instantiated by `_initGuards()` so this accessor stays
5889
+ * synchronous; returns `null` for vaults that never registered any
5890
+ * guard (amendments require at least one guard, so the caller should
5891
+ * never see null).
5968
5892
  */
5969
5893
  _getReadOnlyFacade() {
5970
5894
  return this.readOnlyFacade;
5971
5895
  }
5972
5896
  /**
5973
- * Internal lazy-allocator for the read-only facade. Used by the
5974
- * per-collection `guardSource.readOnlyVault` callback when guards
5975
- * ARE configured but `_initGuards()` raced with the first guard
5976
- * invocation (theoretically impossible — `Noydb.openVault` awaits
5977
- * `_initGuards` before returning — but we keep the defensive lazy
5978
- * path so the closure's contract stays "always returns a facade").
5897
+ * Internal lazy-allocator for the read-only facade. Used as a
5898
+ * defensive fallback; in practice `_initGuards()` eagerly
5899
+ * instantiates this, so the lazy path is a no-op.
5979
5900
  */
5980
5901
  _ensureReadOnlyFacade() {
5981
5902
  if (this.readOnlyFacade !== null) return this.readOnlyFacade;
@@ -6148,7 +6069,7 @@ var Vault = class {
6148
6069
  * collection.
6149
6070
  */
6150
6071
  async delegate(opts) {
6151
- const { issueDelegation, DELEGATIONS_COLLECTION } = await import("./delegation-QSC7G5QC.js");
6072
+ const { issueDelegation, DELEGATIONS_COLLECTION } = await import("./delegation-42LO4WFO.js");
6152
6073
  if (!this.keyring.kek) {
6153
6074
  throw new ValidationError(
6154
6075
  "issueDelegation: keyring.kek is null \u2014 issuing a delegation requires a tier-1 unlock. Re-authenticate at tier 1 (passphrase) first."
@@ -6170,7 +6091,7 @@ var Vault = class {
6170
6091
  * if the id does not exist.
6171
6092
  */
6172
6093
  async revokeDelegation(id) {
6173
- const { revokeDelegation, DELEGATIONS_COLLECTION } = await import("./delegation-QSC7G5QC.js");
6094
+ const { revokeDelegation, DELEGATIONS_COLLECTION } = await import("./delegation-42LO4WFO.js");
6174
6095
  await revokeDelegation(this.adapter, this.name, id);
6175
6096
  void DELEGATIONS_COLLECTION;
6176
6097
  }
@@ -6430,7 +6351,7 @@ var Vault = class {
6430
6351
  const all = await this._loadPeriodsCache();
6431
6352
  return all.find((p) => p.name === name) ?? null;
6432
6353
  }
6433
- /** @internal — periodGuard callback installed on every Collection. */
6354
+ /** @internal — called by the gate bus before put/delete. */
6434
6355
  async _assertTsWritable(existing, incoming) {
6435
6356
  if (existing === null && incoming === null) return;
6436
6357
  if (this.periodCache === null) {
@@ -6518,7 +6439,7 @@ var Vault = class {
6518
6439
  return dumpVaultSchema(this, opts);
6519
6440
  }
6520
6441
  /**
6521
- * Lightweight read of the vault's registered schema (#229): collections
6442
+ * Lightweight read of the vault's registered schema: collections
6522
6443
  * (+ doc counts), guards, materialized views, schema-update strategies,
6523
6444
  * and the unlocked user's grants. Cheap — one `adapter.list` per
6524
6445
  * collection, no decryption. For a full snapshot + stats use dumpSchema().
@@ -6639,7 +6560,7 @@ var Vault = class {
6639
6560
  * @see docs/subsystems/public-envelope.md
6640
6561
  */
6641
6562
  async getPublicEnvelope(opts = {}) {
6642
- const { readPublicEnvelope: readPublicEnvelope2 } = await import("./public-envelope-OHQ5UZFM.js");
6563
+ const { readPublicEnvelope: readPublicEnvelope2 } = await import("./public-envelope-YKHKP74C.js");
6643
6564
  return readPublicEnvelope2(this.adapter, this.name, opts);
6644
6565
  }
6645
6566
  /**
@@ -7305,6 +7226,110 @@ var WriteHookRegistry = class {
7305
7226
  }
7306
7227
  };
7307
7228
 
7229
+ // src/subsystem-bus.ts
7230
+ var SubsystemBus = class {
7231
+ #handlers = /* @__PURE__ */ new Map();
7232
+ #gateHandlers = /* @__PURE__ */ new Map();
7233
+ #depth = 0;
7234
+ /** Register a handler for an observe point. Returns an unsubscribe fn. */
7235
+ register(point, handler) {
7236
+ let arr = this.#handlers.get(point);
7237
+ if (!arr) {
7238
+ arr = [];
7239
+ this.#handlers.set(point, arr);
7240
+ }
7241
+ arr.push(handler);
7242
+ return () => {
7243
+ const a = this.#handlers.get(point);
7244
+ if (!a) return;
7245
+ const i = a.indexOf(handler);
7246
+ if (i >= 0) a.splice(i, 1);
7247
+ };
7248
+ }
7249
+ /** Cheap gate for the write path — true when any handler is registered for the point. */
7250
+ hasHandlers(point) {
7251
+ const a = this.#handlers.get(point);
7252
+ return a !== void 0 && a.length > 0;
7253
+ }
7254
+ /**
7255
+ * True while one or more dispatches are in flight. Backed by a depth counter
7256
+ * so that two concurrent async dispatches (`Promise.all([put('a'), put('b')])`
7257
+ * each captured `busAfterPut=true` at their respective put() tops while depth
7258
+ * was 0) both proceed independently — the counter stays > 0 until BOTH finish,
7259
+ * so any nested write attempted by a handler still sees `dispatching === true`
7260
+ * and is suppressed by the write-path gate in `collection.ts`
7261
+ * (`busAfterPut = hasHandlers('afterPut') && !dispatching`). Re-entrancy
7262
+ * suppression lives exclusively on that write-path gate; concurrent independent
7263
+ * dispatches must not drop each other's events.
7264
+ */
7265
+ get dispatching() {
7266
+ return this.#depth > 0;
7267
+ }
7268
+ /**
7269
+ * Dispatch in registration order, awaited. Per-handler errors are warned, not
7270
+ * thrown — an observe handler must never abort a completed write. A
7271
+ * re-entrancy guard suppresses nested firing so a handler that itself writes
7272
+ * cannot loop (same rationale as WriteHookRegistry.#suppressed).
7273
+ */
7274
+ async dispatch(point, event) {
7275
+ const a = this.#handlers.get(point);
7276
+ if (!a || a.length === 0) return;
7277
+ this.#depth++;
7278
+ try {
7279
+ for (const h of a.slice()) {
7280
+ try {
7281
+ await h(event);
7282
+ } catch (err) {
7283
+ console.warn(
7284
+ `[noy-db] subsystem observe handler failed at ${point}: ` + (err instanceof Error ? err.message : String(err))
7285
+ );
7286
+ }
7287
+ }
7288
+ } finally {
7289
+ this.#depth--;
7290
+ }
7291
+ }
7292
+ /** Register a write-gating handler. A throw from the handler ABORTS the write. Returns an unsubscribe fn. */
7293
+ registerGate(point, handler) {
7294
+ let arr = this.#gateHandlers.get(point);
7295
+ if (!arr) {
7296
+ arr = [];
7297
+ this.#gateHandlers.set(point, arr);
7298
+ }
7299
+ arr.push(handler);
7300
+ return () => {
7301
+ const a = this.#gateHandlers.get(point);
7302
+ if (!a) return;
7303
+ const i = a.indexOf(handler);
7304
+ if (i >= 0) a.splice(i, 1);
7305
+ };
7306
+ }
7307
+ /** Cheap gate for the write path — true when any gate handler is registered for the point. */
7308
+ hasGateHandlers(point) {
7309
+ const a = this.#gateHandlers.get(point);
7310
+ return a !== void 0 && a.length > 0;
7311
+ }
7312
+ /**
7313
+ * Run gate handlers in registration order, awaited. Unlike `dispatch`
7314
+ * (observe), a handler throw is NOT swallowed — it PROPAGATES, aborting the
7315
+ * write before it reaches the store. The first throw stops the remaining
7316
+ * handlers (fail-fast). This is the seam guards/periods migrate onto.
7317
+ *
7318
+ * Note: gate handlers are validators that read, not write. A gate handler
7319
+ * that writes back into the same collection would re-enter the write path
7320
+ * and re-dispatch this point; loop-suppression for that case is deferred to
7321
+ * the migration slice (contract: gate handlers must not perform writes that
7322
+ * re-trigger their own point).
7323
+ */
7324
+ async dispatchGate(point, event) {
7325
+ const a = this.#gateHandlers.get(point);
7326
+ if (!a || a.length === 0) return;
7327
+ for (const h of a.slice()) {
7328
+ await h(event);
7329
+ }
7330
+ }
7331
+ };
7332
+
7308
7333
  // src/tab-coordination.ts
7309
7334
  var TabCoordinator = class {
7310
7335
  tabId;
@@ -7661,9 +7686,9 @@ var PERSONAL_POLICY = Object.freeze({
7661
7686
  minTier: 1,
7662
7687
  enabled: true
7663
7688
  },
7664
- // rotate-recovery (#121): deliberate paper-sheet regeneration
7665
- // when the user remembers their passphrase. PERSONAL matches the
7666
- // pre-#121 low-level flow's bar — knowing the passphrase is enough.
7689
+ // rotate-recovery: deliberate paper-sheet regeneration
7690
+ // when the user remembers their passphrase. PERSONAL allows tier-1 —
7691
+ // knowing the passphrase is enough.
7667
7692
  "rotate-recovery": { minTier: 1 },
7668
7693
  "enroll-authenticator": { minTier: 1 },
7669
7694
  "remove-authenticator": { minTier: 1 },
@@ -7697,7 +7722,7 @@ var PERSONAL_POLICY = Object.freeze({
7697
7722
  minTier: 1,
7698
7723
  enabled: false
7699
7724
  },
7700
- // ─── User envelope gates (#22) ────────────────────────────────────
7725
+ // ─── User envelope gates ──────────────────────────────────────────
7701
7726
  // edit-own-profile: tier 3 floor — any active session can edit their
7702
7727
  // own profile/preferences. Tightening to require a TOTP for
7703
7728
  // profile changes is a one-line override.
@@ -7724,7 +7749,7 @@ var STRICT_POLICY = Object.freeze({
7724
7749
  minTier: 1,
7725
7750
  enabled: true
7726
7751
  },
7727
- // rotate-recovery (#121): STRICT requires an off-device factor —
7752
+ // rotate-recovery: STRICT requires an off-device factor —
7728
7753
  // rotating recovery is an off-site-trust event; a stolen unlocked
7729
7754
  // laptop must not be able to silently mint a new sheet for the
7730
7755
  // attacker. Matches the `peer-recover-user` STRICT default.
@@ -7797,7 +7822,7 @@ var STRICT_POLICY = Object.freeze({
7797
7822
  minTier: 1,
7798
7823
  enabled: false
7799
7824
  },
7800
- // ─── User envelope gates (#22) ────────────────────────────────────
7825
+ // ─── User envelope gates ──────────────────────────────────────────
7801
7826
  // STRICT: profile edits require a TOTP/email-OTP factor (typical
7802
7827
  // shared-workstation hardening — your name/avatar shouldn't change
7803
7828
  // without a fresh second-factor proof).
@@ -7908,13 +7933,14 @@ var Noydb = class {
7908
7933
  emitter = new NoydbEventEmitter();
7909
7934
  writeQueueTracker = new WriteQueueTracker();
7910
7935
  writeHooks = new WriteHookRegistry();
7936
+ subsystemBus = new SubsystemBus();
7911
7937
  clientId = generateULID();
7912
7938
  vaultCache = /* @__PURE__ */ new Map();
7913
7939
  keyringCache = /* @__PURE__ */ new Map();
7914
7940
  syncEngines = /* @__PURE__ */ new Map();
7915
7941
  /**
7916
7942
  * Per-vault active session tier — defaults to `1` after a passphrase
7917
- * unlock; tier-2 / tier-3 unlocks (issue #11) downgrade it. Used by
7943
+ * unlock; tier-2 / tier-3 unlocks downgrade it. Used by
7918
7944
  * {@link checkGate} to evaluate `gate.minTier`.
7919
7945
  */
7920
7946
  activeTier = /* @__PURE__ */ new Map();
@@ -7924,14 +7950,14 @@ var Noydb = class {
7924
7950
  */
7925
7951
  policyCache = /* @__PURE__ */ new Map();
7926
7952
  /**
7927
- * One-shot bypass for the managed-mode strong-recovery check (#195).
7953
+ * One-shot bypass for the managed-mode strong-recovery check.
7928
7954
  * Set true by {@link openVaultAndEnrollRecovery} for the duration of
7929
7955
  * the bootstrap window so the keyring can be created before the
7930
7956
  * strong recovery is enrolled. Always cleared (try/finally).
7931
7957
  * @internal
7932
7958
  */
7933
7959
  _skipNextManagedRecoveryCheck = false;
7934
- /** Per-vault tier-3 (PIN / quick-resume) state — issue #11. */
7960
+ /** Per-vault tier-3 (PIN / quick-resume) state. */
7935
7961
  quickUnlock = new QuickUnlockStore();
7936
7962
  /**
7937
7963
  * Resolved public-envelope schema. Lazily computed once from
@@ -7941,9 +7967,9 @@ var Noydb = class {
7941
7967
  publicEnvelopeSchema;
7942
7968
  closed = false;
7943
7969
  sessionTimer = null;
7944
- /** Same-device multi-tab coordinator (#228); created on `enableTabCoordination()`. */
7970
+ /** Same-device multi-tab coordinator; created on `enableTabCoordination()`. */
7945
7971
  tabCoordinator;
7946
- /** Cross-tab write relay (#228b); created on `enableTabCoordination()`. */
7972
+ /** Cross-tab write relay; created on `enableTabCoordination()`. */
7947
7973
  writeRelay;
7948
7974
  /** Per-vault policy enforcers. */
7949
7975
  policyEnforcers = /* @__PURE__ */ new Map();
@@ -7956,8 +7982,8 @@ var Noydb = class {
7956
7982
  * the same function's `finally` block. Side-effect writes triggered
7957
7983
  * during a staged op's `Collection.put` (today: eager derivation
7958
7984
  * outputs) register their pre-write envelope on `_executed` here so
7959
- * a mid-batch failure rolls them back alongside the main staged ops
7960
- * (#133). `null` outside of Phase 2.
7985
+ * a mid-batch failure rolls them back alongside the main staged ops.
7986
+ * `null` outside of Phase 2.
7961
7987
  * @internal
7962
7988
  */
7963
7989
  _activeTxContext = null;
@@ -7978,8 +8004,95 @@ var Noydb = class {
7978
8004
  if (options.sessionPolicy) {
7979
8005
  this.sessionStrategy.validateSessionPolicy(options.sessionPolicy);
7980
8006
  }
8007
+ this.#registerGuardGate();
8008
+ this.#registerPeriodGate();
7981
8009
  this.resetSessionTimer();
7982
8010
  }
8011
+ // Track A — guards migration. Registers record-lock / field-freeze / onDelete
8012
+ // / amendment-collect as gate-bus handlers (only when guards are opted in, so
8013
+ // the write path is zero-cost otherwise). Resolves the live vault's
8014
+ // GuardRegistry per dispatch. Registered BEFORE the period gate so guard
8015
+ // checks run first. The amendment branch is a side-effect (collectChange),
8016
+ // NOT a throw — and runs even for internal deletes (an amendment invariant
8017
+ // must see system housekeeping tombstones); onDelete/checks run only for
8018
+ // user (non-internal) operations.
8019
+ #registerGuardGate() {
8020
+ if (this.options.guardStrategies === void 0) return;
8021
+ this.subsystemBus.registerGate("beforePut", async (e) => {
8022
+ const v = this.vaultCache.get(e.vault);
8023
+ if (!v) return;
8024
+ const registry = v._getGuardRegistry();
8025
+ if (!registry) return;
8026
+ const guards = registry.guardsFor(e.collection);
8027
+ if (guards.length === 0) return;
8028
+ const existing = e.existing ?? null;
8029
+ const incoming = e.incoming;
8030
+ if (registry.isAmendmentActive()) {
8031
+ registry.collectChange(e.collection, e.docId, existing, incoming, e.existingVersion, e.existingVersion + 1);
8032
+ return;
8033
+ }
8034
+ const facade = v._getReadOnlyFacade();
8035
+ if (!facade) return;
8036
+ const ctx = { existing, vault: facade, userId: e.userId, role: e.role };
8037
+ await registry.runChecks(e.collection, incoming, ctx);
8038
+ const { GuardExecutor } = await import("./executor-AWCHQ2KN.js");
8039
+ for (const g of guards) {
8040
+ await GuardExecutor.checkFrozenFields(g, e.docId, existing, incoming);
8041
+ }
8042
+ });
8043
+ this.subsystemBus.registerGate("beforeDelete", async (e) => {
8044
+ const v = this.vaultCache.get(e.vault);
8045
+ if (!v) return;
8046
+ const registry = v._getGuardRegistry();
8047
+ if (!registry) return;
8048
+ const guards = registry.guardsFor(e.collection);
8049
+ if (guards.length === 0) return;
8050
+ const existing = e.existing ?? null;
8051
+ if (registry.isAmendmentActive()) {
8052
+ registry.collectChange(e.collection, e.docId, existing, null, e.existingVersion, e.existingVersion);
8053
+ return;
8054
+ }
8055
+ if (e.internal) return;
8056
+ const facade = v._getReadOnlyFacade();
8057
+ if (!facade) return;
8058
+ const ctx = { existing, vault: facade, userId: e.userId, role: e.role };
8059
+ await registry.runOnDelete(e.collection, existing ?? {}, ctx);
8060
+ });
8061
+ }
8062
+ /**
8063
+ * Register closed-period write guards on the subsystem bus when a
8064
+ * periodsStrategy is configured. Handlers resolve the live Vault from
8065
+ * vaultCache so they always use the up-to-date period cache.
8066
+ */
8067
+ // Track A — periods migration. Registers the closed-period write guard as a
8068
+ // gate-bus handler (only when periods is opted in, so the write path is
8069
+ // zero-cost otherwise). Each handler resolves the LIVE vault from the cache
8070
+ // per dispatch and delegates to its `_assertTsWritable`, which owns all
8071
+ // period logic. Resolving the live vault makes eviction/re-creation
8072
+ // transparent. Semantics note: if a write reaches the gate through a retained
8073
+ // collection handle whose vault has been evicted from `vaultCache` (e.g. a
8074
+ // post-revocation write on a stale handle), the period check is skipped — the
8075
+ // guard binds to the live vault, not a captured instance. Periods is a
8076
+ // write-integrity guard, not a security boundary, and a re-open reloads the
8077
+ // period cache; the trade-off is intentional.
8078
+ #registerPeriodGate() {
8079
+ if (this.options.periodsStrategy === void 0) return;
8080
+ this.subsystemBus.registerGate("beforePut", async (e) => {
8081
+ const v = this.vaultCache.get(e.vault);
8082
+ if (!v) return;
8083
+ const existing = e.op === "create" ? null : { ts: e.existingTs ?? null, record: e.existing ?? null };
8084
+ await v._assertTsWritable(existing, e.incoming);
8085
+ });
8086
+ this.subsystemBus.registerGate("beforeDelete", async (e) => {
8087
+ if (e.internal) return;
8088
+ const v = this.vaultCache.get(e.vault);
8089
+ if (!v) return;
8090
+ await v._assertTsWritable(
8091
+ { ts: e.existingTs ?? null, record: e.existing ?? null },
8092
+ null
8093
+ );
8094
+ });
8095
+ }
7983
8096
  resetSessionTimer() {
7984
8097
  if (this.sessionTimer) clearTimeout(this.sessionTimer);
7985
8098
  const idleMs = this.options.sessionPolicy?.idleTimeoutMs ?? this.options.sessionTimeout;
@@ -8269,8 +8382,6 @@ var Noydb = class {
8269
8382
  * @throws `NoAccessError` when no keyring exists for the target.
8270
8383
  * @throws `PermissionDeniedError` when the role hierarchy rejects.
8271
8384
  * @throws `ValidationError` when no field is provided.
8272
- *
8273
- * @see #54
8274
8385
  */
8275
8386
  async updateUser(vault, options, factors) {
8276
8387
  await this.checkGate(vault, "update-user", factors);
@@ -8606,7 +8717,7 @@ var Noydb = class {
8606
8717
  * Phase 2. `Collection.dispatchDerivations` consults this so a
8607
8718
  * recursive derived-output write inside `Collection.put` can register
8608
8719
  * its envelope onto `ctx._executed` and roll back with the main
8609
- * staged ops on mid-batch failure (#133).
8720
+ * staged ops on mid-batch failure.
8610
8721
  *
8611
8722
  * @internal
8612
8723
  */
@@ -8635,7 +8746,7 @@ var Noydb = class {
8635
8746
  * `Collection.putManyAtomic` (via `derivationSource.createTxContext`)
8636
8747
  * to publish an active context for the duration of its bulk-atomic
8637
8748
  * Phase 2 loop, so recursive derivation-output writes register on
8638
- * `ctx._executed` and roll back together with the source ops (#133).
8749
+ * `ctx._executed` and roll back together with the source ops.
8639
8750
  *
8640
8751
  * @internal
8641
8752
  */
@@ -8706,26 +8817,26 @@ var Noydb = class {
8706
8817
  return this.writeQueueTracker;
8707
8818
  }
8708
8819
  /**
8709
- * Register a hook that runs before each write (#230). Awaited; a throw
8820
+ * Register a hook that runs before each write. Awaited; a throw
8710
8821
  * aborts the write. Returns an unsubscribe function.
8711
8822
  */
8712
8823
  onBeforeWrite(handler) {
8713
8824
  return this.writeHooks.onBeforeWrite(handler);
8714
8825
  }
8715
8826
  /**
8716
- * Register a hook that runs after each committed write (#230). Awaited;
8827
+ * Register a hook that runs after each committed write. Awaited;
8717
8828
  * a handler error is warned, never rolled back. Returns an unsubscribe fn.
8718
8829
  */
8719
8830
  onAfterWrite(handler) {
8720
8831
  return this.writeHooks.onAfterWrite(handler);
8721
8832
  }
8722
- /** Subscribe to cross-tab write conflicts (#228c). Returns an unsubscribe. */
8833
+ /** Subscribe to cross-tab write conflicts. Returns an unsubscribe. */
8723
8834
  onWriteConflict(fn) {
8724
8835
  this.on("write:conflict", fn);
8725
8836
  return () => this.off("write:conflict", fn);
8726
8837
  }
8727
8838
  /**
8728
- * Enable same-device multi-tab coordination (#228): primary/secondary
8839
+ * Enable same-device multi-tab coordination: primary/secondary
8729
8840
  * election + presence. Browser-only — a graceful no-op (role 'unknown')
8730
8841
  * when Web Locks / BroadcastChannel are unavailable and nothing is
8731
8842
  * injected. Idempotent; returns a disposer.
@@ -8808,7 +8919,11 @@ var Noydb = class {
8808
8919
  get _writeHooks() {
8809
8920
  return this.writeHooks;
8810
8921
  }
8811
- /** @internal Stable per-instance id for schema-cutover coordination (#232). */
8922
+ /** @internal The observe bus, threaded into every Collection. */
8923
+ get _subsystemBus() {
8924
+ return this.subsystemBus;
8925
+ }
8926
+ /** @internal Stable per-instance id for schema-cutover coordination. */
8812
8927
  get _clientId() {
8813
8928
  return this.clientId;
8814
8929
  }
@@ -8828,10 +8943,6 @@ var Noydb = class {
8828
8943
  * survives lock; nothing about it changes when DEKs are scrubbed).
8829
8944
  *
8830
8945
  * No-op when `vault` is not currently in cache (idempotent).
8831
- *
8832
- * Unblocks vLannaAi/niwat#33.
8833
- *
8834
- * @see #17
8835
8946
  */
8836
8947
  lockVault(vault) {
8837
8948
  this.syncEngines.get(vault)?.stopAutoSync();
@@ -8946,7 +9057,7 @@ var Noydb = class {
8946
9057
  return merged;
8947
9058
  }
8948
9059
  /**
8949
- * Read the current vault-level user-directory toggle (#122). Returns
9060
+ * Read the current vault-level user-directory toggle. Returns
8950
9061
  * the default-on shape (`{ enabled: true }`) when no `_meta/directory`
8951
9062
  * document has been persisted yet.
8952
9063
  *
@@ -8958,7 +9069,7 @@ var Noydb = class {
8958
9069
  return persisted?.enabled ?? true;
8959
9070
  }
8960
9071
  /**
8961
- * Toggle the vault's user-directory listing on or off (#122).
9072
+ * Toggle the vault's user-directory listing on or off.
8962
9073
  * Owner-only. When disabled, `listUsersWithEnvelopes()` throws
8963
9074
  * {@link import('./errors.js').DirectoryDisabledError} for callers
8964
9075
  * whose role is neither `owner` nor `admin`.
@@ -9018,7 +9129,7 @@ var Noydb = class {
9018
9129
  *
9019
9130
  * Two enforcement modes:
9020
9131
  *
9021
- * 1. **Managed-mode mandatory strong-recovery (#195).** When
9132
+ * 1. **Managed-mode mandatory strong-recovery.** When
9022
9133
  * `passphraseMode === 'managed'`, the vault MUST have at least
9023
9134
  * one **strong** recovery profile (Shamir today). Paper alone is
9024
9135
  * rejected because under managed mode the user has no memorized
@@ -9052,14 +9163,14 @@ var Noydb = class {
9052
9163
  throw new RecoveryNotEnrolledError();
9053
9164
  }
9054
9165
  /**
9055
- * Internal accessor used by tier-2/tier-3 unlock paths (issue #11)
9166
+ * Internal accessor used by tier-2/tier-3 unlock paths
9056
9167
  * to mark the active session tier.
9057
9168
  * @internal
9058
9169
  */
9059
9170
  _setActiveTier(vault, tier) {
9060
9171
  this.activeTier.set(vault, tier);
9061
9172
  }
9062
- // ─── Tier-2 enroll / remove (issue #11) ────────────────────────
9173
+ // ─── Tier-2 enroll / remove ─────────────────────────────────────
9063
9174
  /**
9064
9175
  * Add a tier-2 authenticator slot to the calling user's keyring.
9065
9176
  * Each slot independently wraps the SAME KEK under a method-specific
@@ -9089,7 +9200,7 @@ var Noydb = class {
9089
9200
  const next = await removeAuthenticator(this.options.store, vault, keyring, slotId);
9090
9201
  this.keyringCache.set(vault, next);
9091
9202
  }
9092
- /** Read the slot list for a vault. Internal — `describeAuthConfig` (#13) consumes this. */
9203
+ /** Read the slot list for a vault. Internal — `describeAuthConfig` consumes this. */
9093
9204
  async listAuthenticators(vault) {
9094
9205
  const keyring = await this.getKeyringInternal(vault);
9095
9206
  return keyring.authenticators;
@@ -9101,7 +9212,7 @@ var Noydb = class {
9101
9212
  * are immutable through this method. Anti-slot-swap is structural,
9102
9213
  * not gate-driven.
9103
9214
  *
9104
- * `meta` patch semantics (#57-aligned):
9215
+ * `meta` patch semantics (top-level merge):
9105
9216
  * - Top-level merge — absent keys preserved
9106
9217
  * - `null` value — delete that meta key
9107
9218
  * - Other values — replace verbatim
@@ -9119,8 +9230,6 @@ var Noydb = class {
9119
9230
  *
9120
9231
  * @throws `NoAccessError` when no slot with the given id exists.
9121
9232
  * @throws `ValidationError` when no patch field is provided.
9122
- *
9123
- * @see #55
9124
9233
  */
9125
9234
  async updateAuthenticator(vault, slotId, options, factors) {
9126
9235
  await this.checkGate(vault, "update-authenticator", factors);
@@ -9129,7 +9238,7 @@ var Noydb = class {
9129
9238
  this.keyringCache.set(vault, next);
9130
9239
  }
9131
9240
  /**
9132
- * Native WebAuthn enrollment using the **real** internal keyring (#16).
9241
+ * Native WebAuthn enrollment using the **real** internal keyring.
9133
9242
  *
9134
9243
  * Why this exists: when a consumer is using `createNoydb({ secret })`,
9135
9244
  * they cannot reach the live `UnlockedKeyring` to feed it to
@@ -9172,8 +9281,6 @@ var Noydb = class {
9172
9281
  * a server-side allowlist).
9173
9282
  *
9174
9283
  * Gated by `enroll-authenticator` like `enrollAuthenticator()` itself.
9175
- *
9176
- * @see #16
9177
9284
  */
9178
9285
  async enrollWebAuthn(vault, ceremony, factors) {
9179
9286
  await this.checkGate(vault, "enroll-authenticator", factors);
@@ -9200,8 +9307,6 @@ var Noydb = class {
9200
9307
  * deciding when a new device prompt should appear. Identity is
9201
9308
  * `id` + `enrolled_at`; the `meta.credentialId` (base64) is used by
9202
9309
  * `allowCredentials` at unlock time.
9203
- *
9204
- * @see #16
9205
9310
  */
9206
9311
  async listWebAuthnSlots(vault) {
9207
9312
  const keyring = await this.getKeyringInternal(vault);
@@ -9283,7 +9388,7 @@ var Noydb = class {
9283
9388
  async getPublicEnvelope(vault, opts = {}) {
9284
9389
  return readPublicEnvelope(this.options.store, vault, opts);
9285
9390
  }
9286
- // ─── Auth introspection (issue #13) ────────────────────────────
9391
+ // ─── Auth introspection ─────────────────────────────────────────
9287
9392
  /** English summary of the configured auth model. */
9288
9393
  async describeAuthConfig(vault) {
9289
9394
  return describeAuthConfig(this.options.store, vault);
@@ -9306,7 +9411,7 @@ var Noydb = class {
9306
9411
  await this.checkGate(vault, "view-user-auth", factors);
9307
9412
  return describeAllUsersAuth(this.options.store, vault);
9308
9413
  }
9309
- // ─── Tier-1 change flows (issue #10) ───────────────────────────
9414
+ // ─── Tier-1 change flows ────────────────────────────────────────
9310
9415
  /**
9311
9416
  * Rotate the user's passphrase (user remembers old). Validates the
9312
9417
  * new phrase against the configured `passphrase` policy, runs the
@@ -9314,8 +9419,7 @@ var Noydb = class {
9314
9419
  *
9315
9420
  * Tier-2 authenticator slots are dropped — each slot wraps the old
9316
9421
  * KEK and would need its derivation key to be re-presented. Re-enrol
9317
- * via `db.enrollAuthenticator` after rotation. Tracked as a
9318
- * v0.1.0-pre.5 limitation.
9422
+ * via `db.enrollAuthenticator` after rotation.
9319
9423
  *
9320
9424
  * @throws `WeakPassphraseError` on a weak new phrase.
9321
9425
  * @throws `PolicyDeniedError` when the gate denies (missing factor, …).
@@ -9337,8 +9441,8 @@ var Noydb = class {
9337
9441
  }
9338
9442
  /**
9339
9443
  * Reset the passphrase using a recovery proof (user forgot the old).
9340
- * v0.1.0-pre.5 supports the `'paper'` profile end-to-end; the
9341
- * other three profiles throw {@link RecoveryProfileNotImplementedError}.
9444
+ * Currently supports the `'paper'` profile end-to-end; the
9445
+ * other profiles throw {@link RecoveryProfileNotImplementedError}.
9342
9446
  *
9343
9447
  * Burns the used recovery entry on success.
9344
9448
  */
@@ -9367,7 +9471,7 @@ var Noydb = class {
9367
9471
  return { newCodes: codes };
9368
9472
  }
9369
9473
  /**
9370
- * Deliberate paper-recovery-code regeneration (#121). User knows their
9474
+ * Deliberate paper-recovery-code regeneration. User knows their
9371
9475
  * passphrase but wants a fresh sheet — they lost the printout or
9372
9476
  * suspect compromise of the off-site copy.
9373
9477
  *
@@ -9377,7 +9481,7 @@ var Noydb = class {
9377
9481
  *
9378
9482
  * Gated by the `rotate-recovery` policy gate:
9379
9483
  * - PERSONAL_POLICY: `{ minTier: 1 }` — knowing the passphrase
9380
- * suffices, matching the pre-#121 low-level flow's bar.
9484
+ * suffices, matching the lower-level flow's bar.
9381
9485
  * - STRICT_POLICY: `{ minTier: 1, factors: [{ anyOf: ['totp',
9382
9486
  * 'email-otp', 'webauthn-roaming'] }] }` — rotation is an
9383
9487
  * off-site-trust event; require an off-device factor so a
@@ -9482,7 +9586,7 @@ var Noydb = class {
9482
9586
  return { newShares: shareStrings, entryId: targetEntryId };
9483
9587
  }
9484
9588
  /**
9485
- * **Atomic create-and-enroll for managed-mode vaults (#195).**
9589
+ * **Atomic create-and-enroll for managed-mode vaults.**
9486
9590
  *
9487
9591
  * Bootstraps a managed-mode vault and enrolls strong recovery in
9488
9592
  * a single ceremony. Under `passphraseMode: 'managed'`, every
@@ -9553,7 +9657,7 @@ var Noydb = class {
9553
9657
  return { vault: vaultHandle, recoveryEnrollments };
9554
9658
  }
9555
9659
  /**
9556
- * **Recovery flow under managed-passphrase mode (#195).**
9660
+ * **Recovery flow under managed-passphrase mode.**
9557
9661
  *
9558
9662
  * Replaces the sealed passphrase of a managed-mode vault with a
9559
9663
  * fresh 256-bit random, sealed under the configured
@@ -9570,7 +9674,7 @@ var Noydb = class {
9570
9674
  * 5. Drop the keyring cache so the next operation re-derives.
9571
9675
  *
9572
9676
  * The vault's strong-recovery enrollment is preserved across
9573
- * recovery (Shamir entries are not burned on use — see #196).
9677
+ * recovery (Shamir entries are not burned on use).
9574
9678
  *
9575
9679
  * @throws ValidationError if the Noydb instance is not in managed mode.
9576
9680
  */
@@ -9618,7 +9722,7 @@ var Noydb = class {
9618
9722
  }
9619
9723
  /**
9620
9724
  * Atomic peer-recovery — re-wraps an EXISTING user's keyring under
9621
- * a fresh temp passphrase in a single store write. Closes #34's
9725
+ * a fresh temp passphrase in a single store write. Closes the
9622
9726
  * partial-failure window (the previous compose-from-primitives
9623
9727
  * pattern was `db.revoke + db.grant`, two writes — if the issuer
9624
9728
  * cancelled between them the target was locked out entirely).
@@ -9628,7 +9732,7 @@ var Noydb = class {
9628
9732
  * - Same `userId`, role, permissions, capabilities preserved.
9629
9733
  * - DEKs unchanged → every other principal in the vault keeps
9630
9734
  * access. No key rotation.
9631
- * - Allows owner→owner natively (#33). The existing
9735
+ * - Allows owner→owner natively. The existing
9632
9736
  * `db.revoke` retains its block — peer-recovery is a separate,
9633
9737
  * intentionally-named operation.
9634
9738
  * - Tier-2 slots dropped (they wrap the old KEK).
@@ -9657,7 +9761,6 @@ var Noydb = class {
9657
9761
  * @throws `PrivilegeEscalationError` when the caller lacks a DEK
9658
9762
  * the target previously had access to.
9659
9763
  *
9660
- * @see #33 #34 — the issues this method closes.
9661
9764
  */
9662
9765
  async recoverUser(vault, options, factors) {
9663
9766
  await this.checkGate(vault, "peer-recover-user", factors);
@@ -9668,7 +9771,7 @@ var Noydb = class {
9668
9771
  }
9669
9772
  }
9670
9773
  /**
9671
- * Persist a recovery enrollment. v0.1.0-pre.5 accepts the `'paper'`
9774
+ * Persist a recovery enrollment. Accepts the `'paper'`
9672
9775
  * profile.
9673
9776
  *
9674
9777
  * The hub wraps the user's DEK set (not the KEK) under a code-derived
@@ -9688,7 +9791,7 @@ var Noydb = class {
9688
9791
  * showCodesToUser(codes)
9689
9792
  * ```
9690
9793
  *
9691
- * As of pre.8, `@noy-db/on-recovery`'s `generateRecoveryCodeSet`
9794
+ * `@noy-db/on-recovery`'s `generateRecoveryCodeSet`
9692
9795
  * delegates to `mintPaperRecoveryEntry` internally — its output is
9693
9796
  * fed directly to this API. Pick whichever fits your code-gen layer:
9694
9797
  *
@@ -9728,13 +9831,13 @@ var Noydb = class {
9728
9831
  "#196"
9729
9832
  );
9730
9833
  }
9731
- /** Read the persisted recovery entries (paper + Shamir). Used by `describeAuthConfig` (#13). */
9834
+ /** Read the persisted recovery entries (paper + Shamir). Used by `describeAuthConfig`. */
9732
9835
  async listRecoveryEntries(vault) {
9733
9836
  const paper = await loadPaperRecoveryEntries(this.options.store, vault);
9734
9837
  const shamir = await loadShamirRecoveryEntries(this.options.store, vault);
9735
9838
  return { paper, shamir };
9736
9839
  }
9737
- // ─── Tier-3 enroll / unlock (issue #11) ────────────────────────
9840
+ // ─── Tier-3 enroll / unlock ─────────────────────────────────────
9738
9841
  /**
9739
9842
  * Register a tier-3 quick-unlock state for the vault. The state is
9740
9843
  * an opaque blob produced by `@noy-db/on-pin/enrollPin` (or any
@@ -9770,11 +9873,11 @@ var Noydb = class {
9770
9873
  this.quickUnlock.delete(vault);
9771
9874
  }
9772
9875
  /**
9773
- * Public accessor for the unlocked keyring of a vault — issue #28.
9876
+ * Public accessor for the unlocked keyring of a vault.
9774
9877
  *
9775
9878
  * Returns a **defensive shallow copy** so consumers can read the DEK
9776
9879
  * map and authenticator list without the risk of mutating the hub's
9777
- * internal cache (#88). Internal hub code paths use a live reference
9880
+ * internal cache. Internal hub code paths use a live reference
9778
9881
  * via `getKeyringInternal`; ceremonies and external consumers always
9779
9882
  * get a snapshot.
9780
9883
  *
@@ -9957,4 +10060,4 @@ export {
9957
10060
  Noydb,
9958
10061
  createNoydb
9959
10062
  };
9960
- //# sourceMappingURL=chunk-T6HQMVML.js.map
10063
+ //# sourceMappingURL=chunk-W277AG6N.js.map