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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (298) hide show
  1. package/codemods/0.4.0-pre.json +699 -0
  2. package/dist/{api-67SBPMMH.js → api-RXUMEKT3.js} +6 -6
  3. package/dist/attestation/index.js +12 -12
  4. package/dist/attestation/index.js.map +1 -1
  5. package/dist/{backup-GAYWQAFN.js → backup-AVAGHAJE.js} +25 -6
  6. package/dist/backup-AVAGHAJE.js.map +1 -0
  7. package/dist/blobs/index.js +5 -5
  8. package/dist/broker/index.js +6 -6
  9. package/dist/{bundle-handle-5OUAI7CV.js → bundle-handle-GFNHT52M.js} +2 -2
  10. package/dist/cargo/index.js +18 -18
  11. package/dist/{chunk-CYQOUTMY.js → chunk-2BMRJ6LQ.js} +2 -2
  12. package/dist/{chunk-HS7HNYBD.js → chunk-2DHSSLOD.js} +6 -6
  13. package/dist/{chunk-JH3OHQM4.js → chunk-2Z3NCLNX.js} +6 -6
  14. package/dist/{chunk-NVU7ZMPN.js → chunk-3IXIU6FP.js} +2 -2
  15. package/dist/{chunk-XBLKM73C.js → chunk-3JVXVJ7L.js} +8 -8
  16. package/dist/{chunk-FY343IZR.js → chunk-3URQC7EH.js} +3 -3
  17. package/dist/{chunk-BPTZ4K5L.js → chunk-4GZ6XOVW.js} +7 -7
  18. package/dist/{chunk-ROWL352P.js → chunk-4I72F5DF.js} +4 -4
  19. package/dist/{chunk-EK7DT5BT.js → chunk-4VUPLMZ6.js} +39 -3
  20. package/dist/chunk-4VUPLMZ6.js.map +1 -0
  21. package/dist/{chunk-LBGPO5RL.js → chunk-52JPHN5N.js} +4 -4
  22. package/dist/{chunk-27TCYH6G.js → chunk-5JY5TSVY.js} +3 -3
  23. package/dist/{chunk-27TCYH6G.js.map → chunk-5JY5TSVY.js.map} +1 -1
  24. package/dist/chunk-5O5HRRTV.js +201 -0
  25. package/dist/chunk-5O5HRRTV.js.map +1 -0
  26. package/dist/{chunk-ZXJXDHNK.js → chunk-5ZKS6ZE2.js} +2 -2
  27. package/dist/{chunk-ZXJXDHNK.js.map → chunk-5ZKS6ZE2.js.map} +1 -1
  28. package/dist/{chunk-MVOWXQHN.js → chunk-6BU3L4UE.js} +2 -2
  29. package/dist/{chunk-3IIPWA75.js → chunk-6BVER473.js} +28 -3
  30. package/dist/chunk-6BVER473.js.map +1 -0
  31. package/dist/{chunk-OSFPNKY4.js → chunk-6FJWSWFT.js} +2 -2
  32. package/dist/chunk-6FJWSWFT.js.map +1 -0
  33. package/dist/{chunk-CJ73OLMW.js → chunk-6HFM7EIT.js} +1 -1
  34. package/dist/chunk-6HFM7EIT.js.map +1 -0
  35. package/dist/{chunk-PGAPBZEK.js → chunk-6NVPFKN3.js} +4 -4
  36. package/dist/{chunk-24UICKTB.js → chunk-6SAFL5YE.js} +2 -2
  37. package/dist/chunk-6SAFL5YE.js.map +1 -0
  38. package/dist/{chunk-NQRJ5AJO.js → chunk-7H73RIE3.js} +2 -2
  39. package/dist/{chunk-NQCNSVGI.js → chunk-7MNBICB5.js} +3 -3
  40. package/dist/{chunk-T4GPR2IR.js → chunk-7TSYBD3E.js} +1 -1
  41. package/dist/chunk-7TSYBD3E.js.map +1 -0
  42. package/dist/{chunk-TLNNHG3A.js → chunk-ADW22QSB.js} +3 -3
  43. package/dist/{chunk-TLNNHG3A.js.map → chunk-ADW22QSB.js.map} +1 -1
  44. package/dist/{chunk-3737A6EA.js → chunk-BGQ63MCT.js} +74 -17
  45. package/dist/chunk-BGQ63MCT.js.map +1 -0
  46. package/dist/{chunk-TFZ7LLOQ.js → chunk-BRVW2GS5.js} +5 -5
  47. package/dist/{chunk-3UK6STWO.js → chunk-CBXHHCZT.js} +3 -3
  48. package/dist/{chunk-MXZ5TSTR.js → chunk-CCVYQFLU.js} +6 -6
  49. package/dist/{chunk-V5C5NNBR.js → chunk-CDB2HVQW.js} +3 -3
  50. package/dist/{chunk-3HYWYLXL.js → chunk-CEJWMBXO.js} +1 -1
  51. package/dist/chunk-CEJWMBXO.js.map +1 -0
  52. package/dist/{chunk-2KIV7BEK.js → chunk-FDX7OWWI.js} +1 -1
  53. package/dist/chunk-FDX7OWWI.js.map +1 -0
  54. package/dist/{chunk-4MQDV3HZ.js → chunk-FFDNKRCY.js} +2 -2
  55. package/dist/{chunk-PP5CO2PR.js → chunk-FMQJZH4R.js} +2 -2
  56. package/dist/{chunk-JSRU5W2M.js → chunk-FZ6NYJ7L.js} +3 -3
  57. package/dist/{chunk-ZGGVOADG.js → chunk-G6S5VVHP.js} +2 -2
  58. package/dist/{chunk-OMSAULZM.js → chunk-GU7A7MQA.js} +9 -9
  59. package/dist/{chunk-E6427JU2.js → chunk-H4YQSDOI.js} +17 -1
  60. package/dist/chunk-H4YQSDOI.js.map +1 -0
  61. package/dist/{chunk-JXIDGFKS.js → chunk-HPLWFNG4.js} +3 -1
  62. package/dist/chunk-HPLWFNG4.js.map +1 -0
  63. package/dist/{chunk-ZWMO5GL5.js → chunk-JJNOLSG5.js} +3 -3
  64. package/dist/{chunk-RLWY6Z44.js → chunk-JRKZTEZZ.js} +62 -6
  65. package/dist/chunk-JRKZTEZZ.js.map +1 -0
  66. package/dist/chunk-N35NC4JH.js +123 -0
  67. package/dist/chunk-N35NC4JH.js.map +1 -0
  68. package/dist/{chunk-SRGJET2F.js → chunk-NJDQ4YSV.js} +2 -2
  69. package/dist/{chunk-JEM2IGS3.js → chunk-NPP5R7FF.js} +5 -5
  70. package/dist/{chunk-DPJTDNUF.js → chunk-O2ERS4UJ.js} +5 -5
  71. package/dist/{chunk-F3GVO44K.js → chunk-PDLLCOGD.js} +3 -3
  72. package/dist/{chunk-VBY6ZLJT.js → chunk-PL2GHSCM.js} +3 -3
  73. package/dist/{chunk-DCMQR46R.js → chunk-PNKHAKQ7.js} +3 -3
  74. package/dist/{chunk-ZK4CO2KZ.js → chunk-Q6TEJXBX.js} +4 -4
  75. package/dist/{chunk-GS5RT2KK.js → chunk-QULVCV3M.js} +2 -2
  76. package/dist/chunk-QULVCV3M.js.map +1 -0
  77. package/dist/{chunk-KZ3KMDN3.js → chunk-RTAMLDWP.js} +6 -2
  78. package/dist/chunk-RTAMLDWP.js.map +1 -0
  79. package/dist/{chunk-MZ5ZFO2D.js → chunk-RXYYFSBB.js} +82 -110
  80. package/dist/chunk-RXYYFSBB.js.map +1 -0
  81. package/dist/{chunk-4VCWI42L.js → chunk-SUFG5E73.js} +2 -2
  82. package/dist/{chunk-SKONR2OL.js → chunk-U5O6GIWZ.js} +2 -2
  83. package/dist/{chunk-3CLZY46Y.js → chunk-UV4O7FAL.js} +296 -110
  84. package/dist/chunk-UV4O7FAL.js.map +1 -0
  85. package/dist/{chunk-HFKGIBMD.js → chunk-VZ3XFUQ7.js} +2 -2
  86. package/dist/{chunk-3EO7RZLJ.js → chunk-W77KZHCW.js} +4 -4
  87. package/dist/{chunk-P7NGLLUF.js → chunk-WASHZV34.js} +2 -2
  88. package/dist/{chunk-XB7LUDKM.js → chunk-WFUIE565.js} +3 -3
  89. package/dist/{chunk-RPXL6KSX.js → chunk-WLZ47GSL.js} +3 -3
  90. package/dist/{chunk-MJWCLSQL.js → chunk-X56RTUK3.js} +3 -3
  91. package/dist/{chunk-MC2LFTQM.js → chunk-XWX7GL56.js} +2 -2
  92. package/dist/{chunk-46V67XP5.js → chunk-YJ6IONGA.js} +2 -2
  93. package/dist/chunk-YJ6IONGA.js.map +1 -0
  94. package/dist/{chunk-24ZLWWEO.js → chunk-YPYHVOXP.js} +1 -1
  95. package/dist/chunk-YPYHVOXP.js.map +1 -0
  96. package/dist/{chunk-2LGDCNFJ.js → chunk-Z45YRGFO.js} +1 -1
  97. package/dist/chunk-Z45YRGFO.js.map +1 -0
  98. package/dist/classified/index.js +3 -3
  99. package/dist/{classified-marker-MH3ON5OL.js → classified-marker-2KJAXRRO.js} +3 -3
  100. package/dist/{collection-facade-AHT7FATG.js → collection-facade-QEJIM6BC.js} +8 -8
  101. package/dist/consent/index.js +4 -4
  102. package/dist/cover/index.js +2 -2
  103. package/dist/custody/index.js +6 -6
  104. package/dist/{dead-filter-U575NGSH.js → dead-filter-DCB62VWW.js} +2 -2
  105. package/dist/{delegation-PDYL6RWT.js → delegation-MO7YZYJS.js} +4 -4
  106. package/dist/derivations/index.js +6 -6
  107. package/dist/{derive-AKT4KU36.js → derive-IUA6JFLB.js} +5 -5
  108. package/dist/directory/index.js +5 -5
  109. package/dist/{dispatch-4XIJSFTT.js → dispatch-23SKSHPD.js} +5 -5
  110. package/dist/{dispatch-N5HGVUGU.js → dispatch-MJ6SHB3Y.js} +9 -9
  111. package/dist/{enclave-OPK24QDR.js → enclave-JU4YIEPB.js} +4 -4
  112. package/dist/{executor-3JZ4POTW.js → executor-FKZURXVV.js} +10 -9
  113. package/dist/{export-accessible-CPTP5STN.js → export-accessible-4S36PQNR.js} +7 -7
  114. package/dist/{extract-partition-TWXPHVU7.js → extract-partition-IO7FDZ2P.js} +10 -10
  115. package/dist/{fanout-sidecar-T2ZGLQFE.js → fanout-sidecar-NNAJQXMX.js} +4 -4
  116. package/dist/forget/index.js +4 -4
  117. package/dist/guards/index.js +1 -1
  118. package/dist/history/index.js +6 -6
  119. package/dist/i18n/index.js +6 -6
  120. package/dist/index.d.ts +3 -2
  121. package/dist/index.js +71 -65
  122. package/dist/index.js.map +1 -1
  123. package/dist/introspection/index.js +6 -6
  124. package/dist/{issue-N74C55X6.js → issue-RIVHSY2S.js} +6 -6
  125. package/dist/kernel/query/builder.d.ts +15 -2
  126. package/dist/kernel/query/join.d.ts +27 -0
  127. package/dist/kernel/secret-mode.d.ts +1 -1
  128. package/dist/kernel/types.d.ts +41 -6
  129. package/dist/kernel/vault.d.ts +19 -15
  130. package/dist/{ledger-DONWFC5M.js → ledger-AETNF4OM.js} +6 -6
  131. package/dist/liberate-GFN4C7RR.js +24 -0
  132. package/dist/{link-set-2TTP4VLO.js → link-set-E5HNY67I.js} +5 -5
  133. package/dist/{managed-secret-EAOYWRYF.js → managed-secret-CWQ6PND5.js} +3 -3
  134. package/dist/materialized-views/index.js +11 -10
  135. package/dist/money/index.js +10 -6
  136. package/dist/{noydb-6W2XGQCS.js → noydb-FYTCH2GD.js} +30 -30
  137. package/dist/overlay-views/index.js +1 -1
  138. package/dist/periods/index.js +17 -7
  139. package/dist/pod/index.js +33 -33
  140. package/dist/policy/index.js +3 -3
  141. package/dist/port/to/index.d.ts +2 -2
  142. package/dist/port/to/locator.d.ts +54 -8
  143. package/dist/port/with/collection-options.d.ts +1 -1
  144. package/dist/portability/index.js +6 -6
  145. package/dist/{post-register-ORQOQJCS.js → post-register-2XSSMGEQ.js} +4 -4
  146. package/dist/query/index.js +2 -2
  147. package/dist/{register-LHETZRJM.js → register-4EFJCVYD.js} +11 -11
  148. package/dist/{registry-JRIN447B.js → registry-4SDHHOJ7.js} +6 -6
  149. package/dist/{registry-AMAZ6QRZ.js → registry-OYTFGWVK.js} +4 -4
  150. package/dist/{request-withdrawal-2DN2RGCO.js → request-withdrawal-KGXGDPVQ.js} +9 -9
  151. package/dist/{reveal-AG4SCHUQ.js → reveal-BW36KCOQ.js} +3 -3
  152. package/dist/{revoke-ZX4NM2CJ.js → revoke-JFN773KF.js} +6 -6
  153. package/dist/sealed-record/index.js +6 -6
  154. package/dist/search/index.js +1 -1
  155. package/dist/{seed-IRCDGIRK.js → seed-GDV5PT4R.js} +6 -6
  156. package/dist/sequence/index.js +4 -4
  157. package/dist/session/index.js +3 -3
  158. package/dist/{signer-7KHD4OL2.js → signer-TA55QB6R.js} +5 -5
  159. package/dist/snapshots/index.js +5 -5
  160. package/dist/{stale-K734VACF.js → stale-4PUTWI2H.js} +5 -5
  161. package/dist/{storage-4H2GF6RQ.js → storage-V7MTFAQJ.js} +5 -5
  162. package/dist/{store-coordination-provider-4SKLSFUG.js → store-coordination-provider-GFCUOBR6.js} +3 -3
  163. package/dist/sync/index.js +5 -5
  164. package/dist/team/index.js +8 -8
  165. package/dist/tiers/index.js +4 -4
  166. package/dist/to/index.js +16 -6
  167. package/dist/to/index.js.map +1 -1
  168. package/dist/via/classified/descriptor.d.ts +1 -1
  169. package/dist/via/money/exact.d.ts +44 -0
  170. package/dist/via/money/index.d.ts +2 -0
  171. package/dist/via/money/normalize.d.ts +20 -0
  172. package/dist/{walk-MQHYNDLZ.js → walk-3ZECBFDA.js} +7 -7
  173. package/dist/with-audit/attestation/index.d.ts +1 -1
  174. package/dist/with-audit/guards/immutable-guard.d.ts +14 -0
  175. package/dist/with-audit/guards/with-guard.d.ts +1 -1
  176. package/dist/with-audit/periods/active.d.ts +28 -1
  177. package/dist/with-audit/periods/index.d.ts +4 -2
  178. package/dist/with-audit/periods/periods.d.ts +160 -5
  179. package/dist/with-audit/periods/strategy.d.ts +13 -4
  180. package/dist/with-audit/periods/vault-facade.d.ts +89 -10
  181. package/dist/with-audit/periods/window.d.ts +10 -0
  182. package/dist/with-cargo/index.d.ts +2 -2
  183. package/dist/with-commit/history/ledger/entry.d.ts +1 -1
  184. package/dist/with-commit/numbering/descriptor.d.ts +1 -1
  185. package/dist/with-formula/derivations/with-derivation.d.ts +1 -1
  186. package/dist/with-formula/materialized-views/types.d.ts +52 -0
  187. package/dist/with-formula/materialized-views/with-materialized-view.d.ts +3 -3
  188. package/dist/with-formula/overlay-views/with-overlayed-view.d.ts +1 -1
  189. package/dist/with-party/custody/index.d.ts +1 -1
  190. package/dist/with-party/directory/user-envelope/index.d.ts +1 -1
  191. package/dist/with-party/directory/user-envelope/storage.d.ts +1 -1
  192. package/dist/with-party/team/echo-ceremony.d.ts +3 -3
  193. package/dist/with-party/team/echo-secret.d.ts +2 -2
  194. package/dist/with-party/team/keyring.d.ts +10 -1
  195. package/dist/with-pod/bundle.d.ts +15 -0
  196. package/dist/with-shape/introspection/index.d.ts +2 -1
  197. package/dist/with-shape/introspection/types.d.ts +1 -1
  198. package/dist/with-shape/persisted-schemas/derive.d.ts +1 -1
  199. package/dist/with-shape/persisted-schemas/index.d.ts +1 -1
  200. package/dist/with-shape/persisted-schemas/types.d.ts +1 -1
  201. package/dist/{withdraw-accessible-JSDQHXHE.js → withdraw-accessible-7PG4DYQK.js} +8 -8
  202. package/package.json +6 -4
  203. package/dist/backup-GAYWQAFN.js.map +0 -1
  204. package/dist/chunk-24UICKTB.js.map +0 -1
  205. package/dist/chunk-24ZLWWEO.js.map +0 -1
  206. package/dist/chunk-2KIV7BEK.js.map +0 -1
  207. package/dist/chunk-2LGDCNFJ.js.map +0 -1
  208. package/dist/chunk-3737A6EA.js.map +0 -1
  209. package/dist/chunk-3CLZY46Y.js.map +0 -1
  210. package/dist/chunk-3HYWYLXL.js.map +0 -1
  211. package/dist/chunk-3IIPWA75.js.map +0 -1
  212. package/dist/chunk-46V67XP5.js.map +0 -1
  213. package/dist/chunk-CJ73OLMW.js.map +0 -1
  214. package/dist/chunk-E6427JU2.js.map +0 -1
  215. package/dist/chunk-EK7DT5BT.js.map +0 -1
  216. package/dist/chunk-GS5RT2KK.js.map +0 -1
  217. package/dist/chunk-JXIDGFKS.js.map +0 -1
  218. package/dist/chunk-KZ3KMDN3.js.map +0 -1
  219. package/dist/chunk-LTU4FLHG.js +0 -131
  220. package/dist/chunk-LTU4FLHG.js.map +0 -1
  221. package/dist/chunk-MZ5ZFO2D.js.map +0 -1
  222. package/dist/chunk-OSFPNKY4.js.map +0 -1
  223. package/dist/chunk-RLWY6Z44.js.map +0 -1
  224. package/dist/chunk-T4GPR2IR.js.map +0 -1
  225. package/dist/liberate-KICI7AJN.js +0 -24
  226. /package/dist/{api-67SBPMMH.js.map → api-RXUMEKT3.js.map} +0 -0
  227. /package/dist/{bundle-handle-5OUAI7CV.js.map → bundle-handle-GFNHT52M.js.map} +0 -0
  228. /package/dist/{chunk-CYQOUTMY.js.map → chunk-2BMRJ6LQ.js.map} +0 -0
  229. /package/dist/{chunk-HS7HNYBD.js.map → chunk-2DHSSLOD.js.map} +0 -0
  230. /package/dist/{chunk-JH3OHQM4.js.map → chunk-2Z3NCLNX.js.map} +0 -0
  231. /package/dist/{chunk-NVU7ZMPN.js.map → chunk-3IXIU6FP.js.map} +0 -0
  232. /package/dist/{chunk-XBLKM73C.js.map → chunk-3JVXVJ7L.js.map} +0 -0
  233. /package/dist/{chunk-FY343IZR.js.map → chunk-3URQC7EH.js.map} +0 -0
  234. /package/dist/{chunk-BPTZ4K5L.js.map → chunk-4GZ6XOVW.js.map} +0 -0
  235. /package/dist/{chunk-ROWL352P.js.map → chunk-4I72F5DF.js.map} +0 -0
  236. /package/dist/{chunk-LBGPO5RL.js.map → chunk-52JPHN5N.js.map} +0 -0
  237. /package/dist/{chunk-MVOWXQHN.js.map → chunk-6BU3L4UE.js.map} +0 -0
  238. /package/dist/{chunk-PGAPBZEK.js.map → chunk-6NVPFKN3.js.map} +0 -0
  239. /package/dist/{chunk-NQRJ5AJO.js.map → chunk-7H73RIE3.js.map} +0 -0
  240. /package/dist/{chunk-NQCNSVGI.js.map → chunk-7MNBICB5.js.map} +0 -0
  241. /package/dist/{chunk-TFZ7LLOQ.js.map → chunk-BRVW2GS5.js.map} +0 -0
  242. /package/dist/{chunk-3UK6STWO.js.map → chunk-CBXHHCZT.js.map} +0 -0
  243. /package/dist/{chunk-MXZ5TSTR.js.map → chunk-CCVYQFLU.js.map} +0 -0
  244. /package/dist/{chunk-V5C5NNBR.js.map → chunk-CDB2HVQW.js.map} +0 -0
  245. /package/dist/{chunk-4MQDV3HZ.js.map → chunk-FFDNKRCY.js.map} +0 -0
  246. /package/dist/{chunk-PP5CO2PR.js.map → chunk-FMQJZH4R.js.map} +0 -0
  247. /package/dist/{chunk-JSRU5W2M.js.map → chunk-FZ6NYJ7L.js.map} +0 -0
  248. /package/dist/{chunk-ZGGVOADG.js.map → chunk-G6S5VVHP.js.map} +0 -0
  249. /package/dist/{chunk-OMSAULZM.js.map → chunk-GU7A7MQA.js.map} +0 -0
  250. /package/dist/{chunk-ZWMO5GL5.js.map → chunk-JJNOLSG5.js.map} +0 -0
  251. /package/dist/{chunk-SRGJET2F.js.map → chunk-NJDQ4YSV.js.map} +0 -0
  252. /package/dist/{chunk-JEM2IGS3.js.map → chunk-NPP5R7FF.js.map} +0 -0
  253. /package/dist/{chunk-DPJTDNUF.js.map → chunk-O2ERS4UJ.js.map} +0 -0
  254. /package/dist/{chunk-F3GVO44K.js.map → chunk-PDLLCOGD.js.map} +0 -0
  255. /package/dist/{chunk-VBY6ZLJT.js.map → chunk-PL2GHSCM.js.map} +0 -0
  256. /package/dist/{chunk-DCMQR46R.js.map → chunk-PNKHAKQ7.js.map} +0 -0
  257. /package/dist/{chunk-ZK4CO2KZ.js.map → chunk-Q6TEJXBX.js.map} +0 -0
  258. /package/dist/{chunk-4VCWI42L.js.map → chunk-SUFG5E73.js.map} +0 -0
  259. /package/dist/{chunk-SKONR2OL.js.map → chunk-U5O6GIWZ.js.map} +0 -0
  260. /package/dist/{chunk-HFKGIBMD.js.map → chunk-VZ3XFUQ7.js.map} +0 -0
  261. /package/dist/{chunk-3EO7RZLJ.js.map → chunk-W77KZHCW.js.map} +0 -0
  262. /package/dist/{chunk-P7NGLLUF.js.map → chunk-WASHZV34.js.map} +0 -0
  263. /package/dist/{chunk-XB7LUDKM.js.map → chunk-WFUIE565.js.map} +0 -0
  264. /package/dist/{chunk-RPXL6KSX.js.map → chunk-WLZ47GSL.js.map} +0 -0
  265. /package/dist/{chunk-MJWCLSQL.js.map → chunk-X56RTUK3.js.map} +0 -0
  266. /package/dist/{chunk-MC2LFTQM.js.map → chunk-XWX7GL56.js.map} +0 -0
  267. /package/dist/{classified-marker-MH3ON5OL.js.map → classified-marker-2KJAXRRO.js.map} +0 -0
  268. /package/dist/{collection-facade-AHT7FATG.js.map → collection-facade-QEJIM6BC.js.map} +0 -0
  269. /package/dist/{dead-filter-U575NGSH.js.map → dead-filter-DCB62VWW.js.map} +0 -0
  270. /package/dist/{delegation-PDYL6RWT.js.map → delegation-MO7YZYJS.js.map} +0 -0
  271. /package/dist/{derive-AKT4KU36.js.map → derive-IUA6JFLB.js.map} +0 -0
  272. /package/dist/{dispatch-4XIJSFTT.js.map → dispatch-23SKSHPD.js.map} +0 -0
  273. /package/dist/{dispatch-N5HGVUGU.js.map → dispatch-MJ6SHB3Y.js.map} +0 -0
  274. /package/dist/{enclave-OPK24QDR.js.map → enclave-JU4YIEPB.js.map} +0 -0
  275. /package/dist/{executor-3JZ4POTW.js.map → executor-FKZURXVV.js.map} +0 -0
  276. /package/dist/{export-accessible-CPTP5STN.js.map → export-accessible-4S36PQNR.js.map} +0 -0
  277. /package/dist/{extract-partition-TWXPHVU7.js.map → extract-partition-IO7FDZ2P.js.map} +0 -0
  278. /package/dist/{fanout-sidecar-T2ZGLQFE.js.map → fanout-sidecar-NNAJQXMX.js.map} +0 -0
  279. /package/dist/{issue-N74C55X6.js.map → issue-RIVHSY2S.js.map} +0 -0
  280. /package/dist/{ledger-DONWFC5M.js.map → ledger-AETNF4OM.js.map} +0 -0
  281. /package/dist/{liberate-KICI7AJN.js.map → liberate-GFN4C7RR.js.map} +0 -0
  282. /package/dist/{link-set-2TTP4VLO.js.map → link-set-E5HNY67I.js.map} +0 -0
  283. /package/dist/{managed-secret-EAOYWRYF.js.map → managed-secret-CWQ6PND5.js.map} +0 -0
  284. /package/dist/{noydb-6W2XGQCS.js.map → noydb-FYTCH2GD.js.map} +0 -0
  285. /package/dist/{post-register-ORQOQJCS.js.map → post-register-2XSSMGEQ.js.map} +0 -0
  286. /package/dist/{register-LHETZRJM.js.map → register-4EFJCVYD.js.map} +0 -0
  287. /package/dist/{registry-AMAZ6QRZ.js.map → registry-4SDHHOJ7.js.map} +0 -0
  288. /package/dist/{registry-JRIN447B.js.map → registry-OYTFGWVK.js.map} +0 -0
  289. /package/dist/{request-withdrawal-2DN2RGCO.js.map → request-withdrawal-KGXGDPVQ.js.map} +0 -0
  290. /package/dist/{reveal-AG4SCHUQ.js.map → reveal-BW36KCOQ.js.map} +0 -0
  291. /package/dist/{revoke-ZX4NM2CJ.js.map → revoke-JFN773KF.js.map} +0 -0
  292. /package/dist/{seed-IRCDGIRK.js.map → seed-GDV5PT4R.js.map} +0 -0
  293. /package/dist/{signer-7KHD4OL2.js.map → signer-TA55QB6R.js.map} +0 -0
  294. /package/dist/{stale-K734VACF.js.map → stale-4PUTWI2H.js.map} +0 -0
  295. /package/dist/{storage-4H2GF6RQ.js.map → storage-V7MTFAQJ.js.map} +0 -0
  296. /package/dist/{store-coordination-provider-4SKLSFUG.js.map → store-coordination-provider-GFCUOBR6.js.map} +0 -0
  297. /package/dist/{walk-MQHYNDLZ.js.map → walk-3ZECBFDA.js.map} +0 -0
  298. /package/dist/{withdraw-accessible-JSDQHXHE.js.map → withdraw-accessible-7PG4DYQK.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/via/lookup/registry.ts","../src/via/lookup/snapshot.ts","../src/port/with/lookup-strategy.ts","../src/kernel/via/dispatch.ts"],"sourcesContent":["/**\n * Pure dict-registry helpers — extracted from `kernel/vault.ts`'s dict\n * bodies (#650 Task 1 — via-lookup extraction, phase D).\n *\n * These take the vault-resident registry Maps (and a couple of vault-bound\n * callbacks) as ARGUMENTS instead of closing over `this` — no `Vault`\n * import here, so this module stays a plain, testable function library.\n * `kernel/vault.ts` keeps the registry Maps themselves (they're populated\n * by `vault.collection()` and read by the backup path) and calls these\n * helpers through the `port/with/lookup-strategy.ts` seam.\n */\n\nimport { getAtPath } from '../../kernel/paths.js'\nimport { UnknownDictCodeError, ValidationError } from '../../kernel/errors.js'\nimport type { JoinableSource } from '../../kernel/query/index.js'\nimport type { FieldRef, ViaGraph } from '../../kernel/via/graph.js'\nimport type { StaticDictDescriptor } from '../../port/with/i18n-strategy.js'\nimport { dictCollectionName, type LookupHandle } from './handle.js'\nimport type { LookupDescriptor, OnDelete } from './descriptor.js'\n\n/**\n * Validate staticDict codes on a `put()`. For each `staticDict()` field,\n * every stored code must be a declared key of the descriptor's table, else\n * `UnknownDictCodeError`. Opt out per descriptor with `{ validateCodes:\n * false }`. Supports scalar, dotted, and `[].`-wildcard field paths via\n * `getAtPath` (same path support as i18n validation).\n *\n * `staticFields` is the collection's `field → StaticDictDescriptor` map\n * (`Vault#staticDescriptorByField.get(collectionName)`) — `undefined`/empty\n * is a no-op.\n */\nexport function enforceStaticDictOnPut(\n staticFields: Record<string, StaticDictDescriptor> | undefined,\n record: unknown,\n): void {\n if (!staticFields || Object.keys(staticFields).length === 0) return\n if (!record || typeof record !== 'object') return\n\n const obj = record as Record<string, unknown>\n for (const [field, desc] of Object.entries(staticFields)) {\n if (desc.validateCodes === false) continue\n const known = new Set<string>(desc.keys)\n const values = getAtPath(obj, field)\n for (const value of values) {\n if (value === undefined || value === null) continue\n const codes = Array.isArray(value) ? value : [value]\n for (const code of codes) {\n if (typeof code !== 'string') continue\n if (!known.has(code)) {\n throw new UnknownDictCodeError(desc.name, field, code)\n }\n }\n }\n }\n}\n\n/**\n * Build a `JoinableSource` for a dictKey field, for use in dict joins.\n * Returns a source whose snapshot contains `{ key, labels, ...labels }`\n * records — one per dictionary entry — keyed by the stable key.\n *\n * staticDict: a code-table-backed source — snapshot() materialises the\n * in-memory table into rows, mirroring `LookupHandle.snapshotEntries()`.\n * Carries `displayLocale` so a locale-less `{ by: 'label' }` query has a\n * default locale to resolve at.\n *\n * Plain dictKey: the snapshot is built synchronously from the\n * `LookupHandle`'s write-through cache, which is populated on every\n * `put()`, `rename()`, `delete()`, and `list()` call. For pre-existing\n * data not yet touched this session, call `await vault.dictionary(name).list()`\n * first to warm the cache.\n *\n * Returns `null` when `field` is not a dictKey in `leftCollection`.\n */\nexport function resolveDictSource(\n leftCollection: string,\n field: string,\n staticDescriptorByField: ReadonlyMap<string, Record<string, StaticDictDescriptor>>,\n dictKeyFieldRegistry: ReadonlyMap<string, Record<string, string>>,\n getDictionaryHandle: (name: string) => LookupHandle,\n): JoinableSource | null {\n const staticFields = staticDescriptorByField.get(leftCollection)\n if (staticFields && field in staticFields) {\n const desc = staticFields[field]!\n const rows: readonly Record<string, unknown>[] = Object.entries(desc.table).map(\n ([key, labels]) => ({ key, labels, ...(labels as Record<string, string>) }),\n )\n const source: JoinableSource = {\n snapshot(): readonly unknown[] {\n return rows\n },\n lookupById(id: string): unknown {\n return rows.find((e) => e['key'] === id)\n },\n }\n if (desc.displayLocale !== undefined) {\n ;(source as { displayLocale?: string }).displayLocale = desc.displayLocale\n }\n return source\n }\n\n const dictFields = dictKeyFieldRegistry.get(leftCollection)\n if (!dictFields || !(field in dictFields)) return null\n const dictName = dictFields[field]\n if (!dictName) return null\n const handle = getDictionaryHandle(dictName)\n return {\n snapshot(): readonly unknown[] {\n return handle.snapshotEntries()\n },\n lookupById(id: string): unknown {\n const entries = handle.snapshotEntries()\n return entries.find((e) => e['key'] === id)\n },\n }\n}\n\n/** The minimal collection surface `updateReferencingRecords` needs. */\nexport interface DictReferencingCollection {\n list(): Promise<Record<string, unknown>[]>\n put(id: string, record: Record<string, unknown>): Promise<unknown>\n}\n\n/**\n * Find and rewrite records in every registered collection whose\n * dictKeyField points at `name`, replacing `oldKey` with `newKey`. Used by\n * `LookupHandle.rename()` (the only sanctioned mass-mutation path for\n * dictKey fields) via the vault's `findAndUpdateReferences` callback.\n *\n * `registry` is `Vault#dictKeyFieldRegistry` (collection name → field name\n * → dictionary name); `getCollection` is the vault's collection accessor —\n * rewrites go through the public `coll.put()` choke point, same as before.\n */\nexport async function updateReferencingRecords(\n registry: ReadonlyMap<string, Record<string, string>>,\n getCollection: (collectionName: string) => DictReferencingCollection,\n name: string,\n oldKey: string,\n newKey: string,\n): Promise<void> {\n for (const [collectionName, dictFields] of registry) {\n // Find fields that point at this dictionary\n const fields = Object.entries(dictFields)\n .filter(([, dn]) => dn === name)\n .map(([field]) => field)\n if (fields.length === 0) continue\n\n const coll = getCollection(collectionName)\n const records = await coll.list()\n for (const record of records) {\n let changed = false\n const updated = { ...record }\n for (const field of fields) {\n if (updated[field] === oldKey) {\n updated[field] = newKey\n changed = true\n }\n }\n if (changed) {\n const id = record['id'] as string | undefined\n if (id !== undefined) {\n await coll.put(id, updated)\n }\n }\n }\n }\n}\n\n/**\n * Resolve a label from an in-memory `{ locale -> label }` map, walking the\n * same fallback chain semantics as `LookupHandle.resolveLabel` (#650 Task 2\n * — moved here from `kernel/vault.ts` so the SAME chain serves both the\n * i18n binding's `dictLabelResolver` and the lookup binding's\n * `lookupLabelResolver`, which #650 Task 2 wires to the identical closure).\n */\nexport function resolveLabelFromMap(\n labels: Readonly<Record<string, string>>,\n locale: string,\n fallback?: string | readonly string[],\n): string | undefined {\n if (labels[locale] !== undefined) return labels[locale]\n const chain = Array.isArray(fallback)\n ? (fallback as readonly string[])\n : fallback\n ? [fallback as string]\n : []\n for (const fb of chain) {\n if (fb === 'any') {\n const any = Object.values(labels)[0]\n if (any !== undefined) return any\n } else if (labels[fb] !== undefined) {\n return labels[fb]\n }\n }\n return undefined\n}\n\n/**\n * Project a native `lookup(dimension, { backing:'static', table, … })`\n * descriptor into the legacy `StaticDictDescriptor` shape — the\n * alias-equivalence compat seam (#650 Task 2) that lets a native\n * static-tier lookup field reuse the SAME vault registries\n * (`staticByName`/`staticDescriptorByField`) — and therefore the same\n * `dictLabelResolver`/`resolveDictSource` machinery — as its `staticDict()`\n * alias. `vocabulary:'closed'` maps to `validateCodes:true` (closed = only\n * declared codes are legal); `'open'` maps to `validateCodes:false`.\n * Returns `undefined` for non-static or table-less (bare `enumOf`)\n * descriptors — those have nothing to register.\n */\nexport function lookupToStaticDictCompat(desc: LookupDescriptor): StaticDictDescriptor | undefined {\n if (desc.backing !== 'static' || desc.table === undefined) return undefined\n return {\n _noydbStaticDict: true,\n _viaBrand: 'i18n',\n name: desc.dimension,\n table: desc.table,\n keys: desc.keys ?? Object.keys(desc.table),\n ...(desc.displayLocale !== undefined ? { displayLocale: desc.displayLocale } : {}),\n ...(desc.onMissing !== undefined ? { onMissing: desc.onMissing } : {}),\n ...(desc.substitute !== undefined ? { substitute: desc.substitute } : {}),\n validateCodes: desc.vocabulary === 'closed',\n }\n}\n\n/** The vault-registry entries a collection's `lookupFields` contribute — the alias-equivalence bridge (#650 Task 2). */\nexport interface LookupDictCompat {\n /** Reserved-tier fields: field name -> dimension (dictionary) name — merges into `dictKeyFieldRegistry`. */\n readonly dictFieldMap: Record<string, string>\n /** Static-tier (table-bearing) fields, projected — merges into `staticDescriptorByField`/`staticByName`. */\n readonly staticEntries: ReadonlyArray<readonly [string, StaticDictDescriptor]>\n}\n\n/**\n * Bridge a collection's `lookupFields` into the SAME shape the legacy dict\n * registries expect, so `resolveDictSource`/`dictLabelResolver` (and\n * therefore `.join()`/`orderBy({by:'label'})`) serve a native `dict()`/\n * `lookup(static)` field identically to its `dictKey()`/`staticDict()`\n * alias — the reserved-vs-first-class-backing \"matrix\" tier is NOT bridged\n * here (no vault registry backs it; Task 5/6 build its own graph edge /\n * snapshot seam).\n */\nexport function collectLookupDictCompat(\n lookupFields: Record<string, LookupDescriptor> | undefined,\n): LookupDictCompat {\n const dictFieldMap: Record<string, string> = {}\n const staticEntries: Array<readonly [string, StaticDictDescriptor]> = []\n for (const [field, desc] of Object.entries(lookupFields ?? {})) {\n if (desc.backing === 'reserved') {\n dictFieldMap[field] = desc.dimension\n } else {\n const compat = lookupToStaticDictCompat(desc)\n if (compat) staticEntries.push([field, compat])\n }\n }\n return { dictFieldMap, staticEntries }\n}\n\n/**\n * Reserved-dict deps of a set of named collections (#653) — the `_dict_*`\n * collections partial sync must auto-include alongside a `collections`\n * filter, mirroring `SyncEngine`'s existing satellite-pair expansion.\n * One hop is provably complete: `vault.collection()` refuses `_dict_*`\n * names, so a dict can never itself declare lookup fields — no\n * dict-of-dict chain to recurse through.\n */\nexport function reservedDictDepsOf(\n names: readonly string[],\n dictKeyFieldRegistry: ReadonlyMap<string, Record<string, string>>,\n): readonly string[] {\n const out = new Set<string>()\n for (const name of names) {\n const fieldMap = dictKeyFieldRegistry.get(name)\n if (!fieldMap) continue\n for (const dictName of Object.values(fieldMap)) out.add(dictCollectionName(dictName))\n }\n return [...out]\n}\n\n/**\n * A lookup dimension's sync membership/altKey table, materialized from its\n * backing rows (#650 Task 3). `keys` is every canonical key present;\n * `altIndex` maps an altKey candidate VALUE to its owning canonical key.\n */\nexport interface MaterializedBacking {\n /** Canonical key values present in the materialized rows. */\n readonly keys: ReadonlySet<string>\n /** altKey candidate value -> canonical key. */\n readonly altIndex: ReadonlyMap<string, string>\n}\n\n/**\n * Build a lookup dimension's altKey index from its backing rows, enforcing\n * declare/warm-time uniqueness across `key ∪ altKeys` values (#650 Task 3 —\n * the CHE/SWZ drift class: two different rows must never claim the same\n * candidate key). `rows` is keyed by canonical key (`row[descriptor.key]`\n * for the matrix tier; the dimension's own key for static/reserved).\n * An altKey candidate VALUE may be a string or number — both normalize via\n * `coerceLookupKey` (#651 Task 3); non-scalar/absent values are skipped.\n * Pure — no I/O. Throws `ValidationError` on collision.\n */\nexport function materializeBackingTable(\n descriptor: LookupDescriptor,\n rows: ReadonlyMap<string, Record<string, unknown>>,\n): MaterializedBacking {\n const keys = new Set<string>(rows.keys())\n // Every value that has claimed ownership so far (canonical keys seed it) —\n // the union `key ∪ altKeys` uniqueness set the spec requires.\n const owner = new Map<string, string>()\n for (const key of keys) owner.set(key, key)\n\n const altIndex = new Map<string, string>()\n const altFields = descriptor.altKeys ?? []\n for (const [canonicalKey, row] of rows) {\n for (const altField of altFields) {\n const value = coerceLookupKey(row[altField])\n if (value === undefined || value === '') continue\n const existingOwner = owner.get(value)\n if (existingOwner !== undefined && existingOwner !== canonicalKey) {\n throw new ValidationError(\n `lookup \"${descriptor.dimension}\": altKey field \"${altField}\" value \"${value}\" is claimed by ` +\n `both \"${existingOwner}\" and \"${canonicalKey}\" — key/altKey values must be unique across the dimension.`,\n )\n }\n owner.set(value, canonicalKey)\n altIndex.set(value, canonicalKey)\n }\n }\n return { keys, altIndex }\n}\n\n/**\n * Closed-vocabulary membership test for one candidate key (#650 Task 3).\n * Static tier: sync, against the in-config key set (declared `keys`, or the\n * table's own keys when table-bearing). Reserved tier: sync — the declared\n * `keys` union the reserved handle's live write-through snapshot (closes\n * #649 for the native `dict()` spelling: the declared-keys promise the old\n * `dictKey()` doc comment made falsely). Matrix (collection) tier: sync —\n * delegates to `buildLookupAltIndex` so membership is checked against the\n * SAME `row[descriptor.key]` keying the altKey index uses (review fix,\n * Important 1: an earlier PUT-id `.get(key)` scan disagreed with the\n * altIndex whenever `descriptor.key !== 'id'`, wrongly rejecting valid\n * non-id candidates and wrongly accepting an unrelated row's PUT-id).\n */\nexport function checkLookupMembership(\n descriptor: LookupDescriptor,\n key: string,\n getDictionary: (dimension: string) => LookupHandle,\n getCollection: (dimension: string) => { querySourceForJoin(): JoinableSource },\n): boolean {\n if (descriptor.backing === 'static') {\n const known = descriptor.keys ?? (descriptor.table ? Object.keys(descriptor.table) : [])\n return known.includes(key)\n }\n if (descriptor.backing === 'reserved') {\n if ((descriptor.keys ?? []).includes(key)) return true\n return getDictionary(descriptor.dimension).snapshotEntries().some((e) => e['key'] === key)\n }\n return buildLookupAltIndex(descriptor, getDictionary, getCollection).keys.has(key)\n}\n\n/**\n * The ONE guarded key coercion (#651 Task 3, dm12) — string/number values\n * coerce to their canonical `String()` form; everything else (`null`,\n * `undefined`, objects, …) coerces to `undefined`. Every consumer that turns\n * a raw record field into a lookup key routes through this, closing the\n * bare-`String()` `\"undefined\"`/`\"null\"`-key poisoning class (seam map\n * finding 6): a row whose key field is genuinely absent must never mint the\n * literal candidate string `\"undefined\"`.\n */\nexport function coerceLookupKey(raw: unknown): string | undefined {\n return typeof raw === 'string' || typeof raw === 'number' ? String(raw) : undefined\n}\n\n/**\n * Resolve a backing row's canonical key VALUE — `coerceLookupKey(row[descriptor.key])`\n * (#651 Task 3). The matrix tier's `row[descriptor.key]`, never the row's own PUT-id\n * when the two differ (`descriptor.key !== 'id'`).\n */\nexport function resolveBackingRowKey(\n descriptor: LookupDescriptor,\n row: Record<string, unknown>,\n): string | undefined {\n return coerceLookupKey(row[descriptor.key])\n}\n\n/**\n * The referencing-side match predicate — does `rec[field]` (coerced) equal an\n * already-coerced `compareKey` (#651 Task 3)? Shared by every site that scans a\n * referencing collection for rows pointing at a given backing key\n * (`with-shape/links/vault-facade.ts`'s ref-delete propagation, `kernel/via/dispatch.ts`'s\n * forget-fanout twin).\n */\nexport function matchesReferencingValue(\n rec: Record<string, unknown>,\n field: string,\n compareKey: string,\n): boolean {\n return coerceLookupKey(rec[field]) === compareKey\n}\n\n/**\n * Materialize a lookup dimension's altKey index from whatever backing data\n * is synchronously available (#650 Task 3 — the `ingest` source). Static:\n * the in-config table. Reserved: the reserved handle's live write-through\n * cache (the same warm-via-put()/list() cache `resolveDictSource` already\n * relies on). Matrix (collection): the backing collection's own in-memory\n * eager cache via `querySourceForJoin()` — already public, already the\n * mechanism `.join()` uses (`with-shape/links/vault-facade.ts`'s\n * `resolveSource`); no new I/O, no fire-and-forget warm step. Like that\n * existing join precedent, a dimension collection this vault session has\n * not yet opened/populated sees an empty snapshot (no altKey normalization\n * until it has rows) — open/populate it first for normalization to apply.\n * A matrix row whose `descriptor.key` field coerces to `undefined` (missing/\n * non-scalar) is SKIPPED — never enters the index under a poisoned\n * `\"undefined\"` key (#651 Task 3, dm12).\n */\nexport function buildLookupAltIndex(\n descriptor: LookupDescriptor,\n getDictionary: (dimension: string) => LookupHandle,\n getCollection: (dimension: string) => { querySourceForJoin(): JoinableSource },\n): MaterializedBacking {\n if (descriptor.backing === 'static') {\n return materializeBackingTable(descriptor, new Map(Object.entries(descriptor.table ?? {})))\n }\n if (descriptor.backing === 'reserved') {\n const entries = getDictionary(descriptor.dimension).snapshotEntries()\n return materializeBackingTable(descriptor, new Map(entries.map((e) => [String(e['key']), e])))\n }\n const rows = getCollection(descriptor.dimension).querySourceForJoin().snapshot()\n const keyed = new Map<string, Record<string, unknown>>()\n for (const r of rows) {\n const row = r as Record<string, unknown>\n const key = resolveBackingRowKey(descriptor, row)\n if (key !== undefined) keyed.set(key, row)\n }\n return materializeBackingTable(descriptor, keyed)\n}\n\n/** One cross-collection `'ref'` graph edge a lookup field declares (#650 Task 5). Module-private —\n * only `registerLookupRefEdges` below (the exported entry point) consumes it. */\ninterface LookupRefEdge {\n readonly referencing: FieldRef\n readonly sources: readonly FieldRef[]\n readonly onDelete: OnDelete\n /** The backing dimension's canonical-key FIELD NAME on its own row (`desc.key` — matrix tier\n * only varies this; reserved/static tiers are always `'id'`). A referencing field always\n * stores THIS field's value, never the backing row's PUT-id when the two differ. */\n readonly keyField: string\n}\n\n/**\n * Compute the cross-collection `'ref'` edges a collection's `lookupFields` declare (#650 Task 5,\n * spec §4) — one edge per non-static-backing field: target = the referencing field; sources =\n * the backing dimension's whole-collection node (`field:'*'`, the wildcard key\n * `ViaGraph.referencingEdgesOf` does its O(1) reverse lookup against) PLUS, when the descriptor\n * names a presentation field (`present.label`), that SPECIFIC field too. `foldPosture`'s\n * `DEFAULT_POSTURE` is the fold's identity element, so adding the wildcard alongside a real field\n * source changes nothing when that field is plain — but folds in a classified/money posture when\n * it isn't (taint composition, spec §4: \"a lookup edge whose source names a classified field\n * contributes that field's posture\"). Static tier (`backing:'static'`) has no backing collection/\n * dimension rows to reference-check — excluded. Pure; consumed only by `registerLookupRefEdges` below.\n */\nfunction collectLookupRefEdges(\n collectionName: string,\n lookupFields: Record<string, LookupDescriptor> | undefined,\n): readonly LookupRefEdge[] {\n const edges: LookupRefEdge[] = []\n for (const [field, desc] of Object.entries(lookupFields ?? {})) {\n if (desc.backing === 'static') continue\n const backing = desc.backing === 'reserved' ? dictCollectionName(desc.dimension) : desc.dimension\n edges.push({\n referencing: { collection: collectionName, field },\n sources: [\n { collection: backing, field: '*' },\n ...(desc.present?.label !== undefined ? [{ collection: backing, field: desc.present.label }] : []),\n ],\n onDelete: desc.onDelete,\n keyField: desc.key,\n })\n }\n return edges\n}\n\n/** Thin wrapper — `collectLookupRefEdges` + one `graph.registerDerived` call per edge. Lets\n * `vault.collection()` (kernel-surface-budgeted, #650 Task 5) register a collection's lookup-ref\n * edges with a single line, keeping the ceiling-guarded call site a thin call (route logic here). */\nexport function registerLookupRefEdges(\n graph: ViaGraph,\n collectionName: string,\n lookupFields: Record<string, LookupDescriptor> | undefined,\n): void {\n for (const e of collectLookupRefEdges(collectionName, lookupFields)) {\n graph.registerDerived(e.referencing, e.sources, 'ref', 'record', e.onDelete, e.keyField)\n }\n}\n\n/**\n * `LookupViaConfig.snapshotFor`'s vault-built row source (#650 Task 6, spec\n * §5; matrix-tier coverage added #650 Task 7, spec §6 — Task 6 deferred it,\n * see `task-6-report.md`'s Concerns #1; the reviewer's Task-7 dispatch\n * refuted the \"needs a new vault-resident registry\" premise: the descriptor\n * is already in hand at both call sites, so `snapshotFor` just needs to\n * ACCEPT it). Takes the full `descriptor` (not a bare dimension name) so it\n * can route the matrix tier's `key` field, which — unlike reserved tier's\n * hardcoded `'id'` — varies per collection. Routes on `descriptor.backing`:\n *\n * - **reserved**: rows come straight from the SAME `LookupHandle.\n * snapshotEntries()` write-through cache `dictLabelResolver`/\n * `resolveDictSource` already read (no second copy), keyed by each\n * entry's own canonical `key` (always `'id'` by construction for this\n * tier — `dict()`'s factory hardcodes it).\n * - **collection** (matrix): rows come from `getCollection(dimension).\n * querySourceForJoin().snapshot()` — the SAME sync, already-live cache\n * `buildLookupAltIndex`'s matrix branch (above, this file) and `.join()`\n * itself already read — re-keyed via `resolveBackingRowKey(descriptor, row)`,\n * NOT the row's own PUT-id (which may differ when `key !== 'id'`; the exact\n * distinction the #650 Task 3 review fix already applies to\n * `checkLookupMembership`'s matrix branch). A row whose `descriptor.key`\n * field coerces to `undefined` is skipped (#651 Task 3, dm12).\n * - **static**: never routed here — `descriptor.table` is read directly by\n * the caller (`binding.ts`'s `compareLookupOrder`/`resolveLookupOrderLabel`,\n * `snapshot.ts`'s `presentLookupForJoin`); no vault call needed.\n *\n * `isReservedDimension` is the vault's `reservedLookupCollections`\n * membership test.\n */\nexport function buildLookupSnapshotRows(\n descriptor: LookupDescriptor,\n isReservedDimension: (dimension: string) => boolean,\n getDictionary: (dimension: string) => LookupHandle,\n getCollection: (dimension: string) => { querySourceForJoin(): JoinableSource },\n): ReadonlyMap<string, Record<string, unknown>> | undefined {\n const dimension = descriptor.dimension\n if (isReservedDimension(dimension)) {\n const rows = new Map<string, Record<string, unknown>>()\n for (const entry of getDictionary(dimension).snapshotEntries()) {\n const key = entry['key']\n if (typeof key === 'string') rows.set(key, entry)\n }\n return rows\n }\n if (descriptor.backing === 'collection') {\n const rawRows = getCollection(dimension).querySourceForJoin().snapshot()\n const rows = new Map<string, Record<string, unknown>>()\n for (const r of rawRows) {\n const row = r as Record<string, unknown>\n const key = resolveBackingRowKey(descriptor, row)\n if (key !== undefined) rows.set(key, row)\n }\n return rows\n }\n return undefined\n}\n","/**\n * The sync lookup snapshot + join/locale seam (#650 Task 6, spec §5 — \"the\n * snapshot+locale seam\"). Retires the #626 kernel→via grandfather:\n * `kernel/query/join.ts` no longer imports `via/i18n/core.js` directly\n * — it calls the `presentForJoin` hook this file's `buildPresentForJoin`\n * builds instead (seam map Part 2 item 4, the #626 reviewer-spec'd shape:\n * a sync `presentI18nForJoin`-class hook on `JoinableSource`).\n *\n * `LookupSnapshot` is the sync materialized `key -> row` view over ONE\n * lookup dimension's ALREADY-LIVE backing data (the `active.ts`\n * `_syncCache`/`snapshotEntries` write-through-cache pattern — never a\n * second copy of the data: `LookupViaConfig.snapshotFor`'s vault-built\n * closure reads the SAME `LookupHandle._syncCache` /\n * first-class-collection cache every other lookup consumer\n * (`dictLabelResolver`, `resolveDictSource`, `getAltIndex`) already reads).\n * Serves (reserved AND matrix tier since #650 Task 7 — `registry.ts`'s\n * `buildLookupSnapshotRows` routes both; static tier is read straight off\n * `descriptor.table` by every consumer below, never through this cache):\n * - join dressing (`presentForJoin`, consumed by `kernel/query/join.ts`\n * via `JoinableSource.presentForJoin`)\n * - dimension sort (`compareForOrder`, consumed by\n * `via/lookup/binding.ts`'s `ViaBinding.compareForOrder` closure)\n * - per-call-locale order-label resolution (`resolveOrderLabel`, #650\n * Task 7 — the `orderBy(..., {by:'label'})` channel `compareForOrder`\n * structurally can't serve, no locale param; consumed by\n * `kernel/query/builder.ts`'s `buildOrderLabelMaps`)\n * - membership: reserved/static-tier membership (#650 Task 3,\n * `checkLookupMembership`) already reads the identical sync caches\n * directly — not re-plumbed through this file; see\n * `.superpowers/sdd/task-6-report.md`'s \"bridge disposition\" section.\n *\n * Sync end-to-end (#553) — every function here is a pure, synchronous\n * transform over already-materialized rows; no store read, no Promise.\n */\nimport type { LookupDescriptor } from './descriptor.js'\nimport { presentI18nForJoin, type I18nTextDescriptor } from '../i18n/core.js'\n\n/** A lookup dimension's sync materialized view — see file header. */\nexport interface LookupSnapshot {\n /** The full backing row for `key`, or `undefined` when `key` isn't (yet) present in the snapshot. */\n row(key: string): Record<string, unknown> | undefined\n /** The dimension's declared presentation label for `key` at `locale` — mirrors `binding.ts`'s `fetchLookupLabel` (matrix-row branch), generalized to any tier's already-materialized rows. */\n label(key: string, locale: string, fallback?: unknown): string | undefined\n /**\n * Exact ordering for two canonical keys against `descriptor.sortBy`\n * (falls back to `present.label`, then to the raw keys) at `locale`.\n * Never throws — degrades to comparing the raw keys when no sortable\n * value resolves for either side.\n */\n compareKeys(a: string, b: string, locale: string): number\n}\n\n/** Read one row field, resolving a `by`-keyed (locale-map) value when `by` is declared. */\nfunction readRowField(\n row: Record<string, unknown> | undefined,\n field: string | undefined,\n by: string | undefined,\n locale: string,\n fallback?: unknown,\n): string | undefined {\n if (!row || field === undefined) return undefined\n const raw = row[field]\n if (by === undefined) return typeof raw === 'string' ? raw : undefined\n if (!raw || typeof raw !== 'object') return undefined\n const map = raw as Record<string, unknown>\n const val = map[locale]\n if (typeof val === 'string') return val\n if (typeof fallback === 'string' && typeof map[fallback] === 'string') return map[fallback]\n return undefined\n}\n\n/**\n * Build a sync `LookupSnapshot` over one dimension's already-materialized\n * rows (canonical-key -> row, the SAME keying `materializeBackingTable`\n * (`registry.ts`, #650 Task 3) uses). Pure — never reads a store.\n */\nexport function buildLookupSnapshot(\n dimension: string,\n rows: ReadonlyMap<string, Record<string, unknown>>,\n descriptor: LookupDescriptor,\n): LookupSnapshot {\n void dimension // identity only — kept for parity with materializeBackingTable/buildLookupAltIndex's signature and future diagnostics\n return {\n row: (key) => rows.get(key),\n label: (key, locale, fallback) =>\n readRowField(rows.get(key), descriptor.present?.label, descriptor.present?.by, locale, fallback),\n compareKeys: (a, b, locale) => {\n const sortField = descriptor.sortBy ?? descriptor.present?.label\n const av = readRowField(rows.get(a), sortField, descriptor.present?.by, locale) ?? a\n const bv = readRowField(rows.get(b), sortField, descriptor.present?.by, locale) ?? b\n return av < bv ? -1 : av > bv ? 1 : 0\n },\n }\n}\n\n/**\n * The lookup-label HALF of `presentForJoin` (#626 retirement, spec §5;\n * matrix-tier coverage added #650 Task 7) — resolves `<field>Label` for\n * every declared lookup field with a `present` dressing dimension, sync,\n * from `getSnapshotRows` (the vault-built `LookupViaConfig.snapshotFor`\n * closure — now descriptor-routed, see `registry.ts`'s\n * `buildLookupSnapshotRows`; static tier reads its own in-config `table`\n * directly, no vault call — never `undefined` for a declared static table).\n * Mirrors `binding.ts`'s `runLookupPresent` (the async `present()` hook)\n * minus the array/`[].`-wildcard handling that hook needs for full-record\n * reads — join dressing only ever sees the joined RIGHT-side record's\n * scalar fields, so that complexity doesn't apply here.\n */\nfunction presentLookupForJoin(\n record: Record<string, unknown>,\n locale: string,\n lookupFields: Record<string, LookupDescriptor>,\n getSnapshotRows: (descriptor: LookupDescriptor) => ReadonlyMap<string, Record<string, unknown>> | undefined,\n): Record<string, unknown> {\n let result = record\n for (const [field, desc] of Object.entries(lookupFields)) {\n if (desc.present === undefined) continue\n const raw = record[field]\n if (typeof raw !== 'string') continue\n const rows = desc.backing === 'static'\n ? (desc.table ? new Map(Object.entries(desc.table)) : undefined)\n : getSnapshotRows(desc)\n if (!rows) continue\n const label = buildLookupSnapshot(desc.dimension, rows, desc).label(raw, locale)\n if (label === undefined) continue\n if (result === record) result = { ...record }\n result[`${field}Label`] = label\n }\n return result\n}\n\n/**\n * Build the combined sync `presentForJoin(record, locale)` hook a\n * `Collection` attaches to the `JoinableSource` it exposes\n * (`querySourceForJoin()`) — the i18n-text half (`presentI18nForJoin`, the\n * exact `applyI18nLocale(..., 'join')` partial application\n * `kernel/query/join.ts` used to call directly, #626) composed with the\n * lookup-label half above. `undefined` when the collection declares\n * neither — `JoinableSource.presentForJoin` then stays unset, matching\n * today's `i18nFields`-absent behavior exactly (#626 parity lock).\n */\nexport function buildPresentForJoin(\n i18nFields: Record<string, I18nTextDescriptor> | undefined,\n lookupFields: Record<string, LookupDescriptor> | undefined,\n getSnapshotRows: ((descriptor: LookupDescriptor) => ReadonlyMap<string, Record<string, unknown>> | undefined) | undefined,\n): ((record: unknown, locale: string) => unknown) | undefined {\n const hasI18n = i18nFields !== undefined && Object.keys(i18nFields).length > 0\n const hasLookup = lookupFields !== undefined && Object.keys(lookupFields).length > 0\n if (!hasI18n && !hasLookup) return undefined\n const resolveRows = getSnapshotRows ?? (() => undefined)\n return (record, locale) => {\n if (record === null || typeof record !== 'object') return record\n let result = record as Record<string, unknown>\n if (hasI18n) result = presentI18nForJoin(result, i18nFields, locale)\n if (hasLookup) result = presentLookupForJoin(result, locale, lookupFields, resolveRows)\n return result\n }\n}\n","/**\n * Lookup strategy seam (#650 Task 1 — via-lookup extraction, phase D of the\n * Via port; precedent: `port/with/i18n-strategy.ts`). Lives on the `/with`\n * port (the one seam the kernel spine may import statically) so `Vault` can\n * reach the dict-registry pure helpers and the `LookupHandle`/`NO_LOOKUP`\n * types without a spine→`via/` static import (Check 14 via-layering bans\n * that; `port/with/` is always allowed, Check 9's sanctioned exception).\n *\n * `kernel/vault.ts` imports ONLY this module for lookup — never\n * `via/lookup/*` directly.\n *\n * This task (#650 Task 1) is a pure move: `Vault.dictionary()` still\n * constructs its handle through `i18nStrategy.buildDictionaryHandle`\n * (`port/with/i18n-strategy.ts`), which now internally delegates to\n * `withLookup().buildLookupHandle` (same handle, new home). `LookupStrategy`\n * / `NO_LOOKUP` / `isLookupCollectionName` here are the seam later phase-D\n * tasks bind `vault.collection()`'s lookup fields onto — unused by Task 1's\n * wiring, but their exact shapes are frozen now so later tasks don't\n * re-litigate them.\n */\n\nimport type { NoydbStore, EncryptedEnvelope } from '../../kernel/types.js'\nimport type { LedgerStore } from '../../with-commit/history/ledger/store.js'\nimport type { UnlockedKeyring } from '../../with-party/team/keyring.js'\nimport type { NoydbEventEmitter } from '../../kernel/events.js'\nimport type { ViaCryptoCtx } from '../../kernel/via/index.js'\nimport type { LookupHandle, DictionaryOptions } from '../../via/lookup/handle.js'\nimport {\n enforceStaticDictOnPut,\n resolveDictSource,\n updateReferencingRecords,\n resolveLabelFromMap,\n collectLookupDictCompat,\n lookupToStaticDictCompat,\n reservedDictDepsOf,\n materializeBackingTable,\n checkLookupMembership,\n buildLookupAltIndex,\n registerLookupRefEdges,\n buildLookupSnapshotRows,\n coerceLookupKey,\n resolveBackingRowKey,\n matchesReferencingValue,\n type DictReferencingCollection,\n type LookupDictCompat,\n type MaterializedBacking,\n} from '../../via/lookup/registry.js'\nimport { buildPresentForJoin } from '../../via/lookup/snapshot.js'\nimport type { LookupDescriptor } from '../../via/lookup/descriptor.js'\n\n/**\n * Backing options for `LookupStrategy.buildLookupHandle` — same shape as\n * `DictionaryOptions` (kept as a distinct alias since the \"lookup\" name is\n * the forward-looking one; `DictionaryOptions` stays the dict-tier name).\n */\nexport type LookupBackingOptions = DictionaryOptions\n\n/**\n * Options accepted by `LookupStrategy.buildLookupHandle`. Mirrors the\n * `LookupHandle` constructor verbatim, plus the two choke-point\n * participation hooks (`onDirty`/`onRecordMutated`) #647 (Task 4) wires —\n * both `undefined` in this task (pure move, no new call sites).\n */\nexport interface BuildLookupHandleOptions<Keys extends string = string> {\n readonly adapter: NoydbStore\n readonly compartmentName: string\n readonly dimensionName: string\n readonly keyring: UnlockedKeyring\n /**\n * The `reservedEnvelopes('_dict_')` capability (#629 Task 4) — the\n * handle's sanctioned crypto door onto its `_dict_<name>` collection.\n * Bound by the Vault to its own `getDEK`, the same per-collection-name\n * DEK resolver every other collection uses.\n */\n readonly reservedEnvelopes: ReturnType<ViaCryptoCtx['reservedEnvelopes']>\n readonly encrypted: boolean\n readonly ledger: LedgerStore | undefined\n readonly options: LookupBackingOptions\n readonly findAndUpdateReferences:\n | ((dimension: string, oldKey: string, newKey: string) => Promise<void>)\n | undefined\n readonly emitter: NoydbEventEmitter\n /**\n * #647 fix wave 1 — mints a version-ordered delete-marker envelope. Bound by the Vault to the\n * real `kernel/enclave` `buildDeleteMarker` function — `LookupHandle` (`via/lookup/**`)\n * may not import `kernel/enclave/` itself (Check 11/15), so this capability is injected the\n * same way `reservedEnvelopes` above is.\n */\n readonly buildDeleteMarker: (version: number, actor: string) => EncryptedEnvelope\n /** #650 Task 4 (#647) — choke-point participation hooks. */\n readonly onDirty?: ((collection: string, id: string, action: 'put' | 'delete', version: number) => Promise<void>) | undefined\n readonly onRecordMutated?: ((collection: string, id: string, action: 'put' | 'delete', version: number) => Promise<void>) | undefined\n /**\n * #650 Task 5 (#648) — the real reference check `LookupHandle.delete()`'s strict branch calls:\n * restrict throws `DictKeyInUseError` naming the referencing collection, cascade/nullify apply\n * their propagation. Bound by the Vault (never a `Collection`/keyring/DEK reach-around); a\n * no-op when the dimension has no declared lookup-referencing edges (today's dangling behavior\n * for undeclared refs is unaffected). Return value is discarded by the handle — callers who\n * need cascade/nullify counts (forget) go through `VaultLinks` directly.\n */\n readonly checkReferencesOnDelete?: ((key: string) => Promise<unknown>) | undefined\n /**\n * Used by the active strategy to satisfy the generic-key parameter on the\n * returned handle. The NO_LOOKUP stub never reads it. Mirrors\n * `BuildDictionaryHandleOptions._keyMarker` (`port/with/i18n-strategy.ts`).\n */\n // marker generic — runtime sees no value\n _keyMarker?: Keys\n}\n\nexport interface LookupStrategy {\n /**\n * Construct a typed `LookupHandle` for the named dimension. Throws under\n * `NO_LOOKUP`.\n */\n buildLookupHandle<Keys extends string = string>(\n opts: BuildLookupHandleOptions<Keys>,\n ): LookupHandle<Keys>\n}\n\nfunction notEnabled(op: string): Error {\n return new Error(\n `${op}: the NO_LOOKUP stub was reached, which should be unreachable today — there is no ` +\n '`lookupStrategy` `createNoydb({ ... })` option yet to select this stub over the real one; ' +\n '`vault.dictionary()` always resolves through `withLookup()` (see `via/i18n/active.ts`\\'s ' +\n 'delegation). This is forward scaffolding for a later task (mirrors `NO_I18N`\\'s shape) — if you ' +\n 'hit this, it indicates a bug, not a missing opt-in.',\n )\n}\n\n/**\n * No-lookup stub. Mirrors `NO_I18N.buildDictionaryHandle`'s shape, but unlike `NO_I18N` (wired as\n * `vault.ts`'s `opts.i18nStrategy ?? NO_I18N` default), nothing selects this stub today — there is\n * no `lookupStrategy` option on `createNoydb()`; `vault.dictionary()`'s only construction path\n * (`Vault.i18nStrategy.buildDictionaryHandle` → `withLookup().buildLookupHandle`) never reaches\n * here. Kept as forward scaffolding for a later task that wires an independent lookup opt-in.\n */\nexport const NO_LOOKUP: LookupStrategy = {\n buildLookupHandle() {\n throw notEnabled('vault.dictionary()')\n },\n}\n\n/** `_dict_*` (legacy dict tier) and `_lookup_*` (the phase-D reserved backing). */\nexport const LOOKUP_COLLECTION_PREFIXES = ['_dict_', '_lookup_'] as const\n\n/** Return true when a collection name is a reserved lookup-backing collection. */\nexport function isLookupCollectionName(name: string): boolean {\n return LOOKUP_COLLECTION_PREFIXES.some((prefix) => name.startsWith(prefix))\n}\n\n// Re-exported pure registry helpers (#650 Task 1) — `kernel/vault.ts`'s\n// thin delegators call these directly; small always-on functions, not\n// behind the tree-shake seam (same bundling class as `isLookupCollectionName`\n// above, just too large to duplicate inline like that one is).\nexport { enforceStaticDictOnPut, resolveDictSource, updateReferencingRecords }\nexport type { DictReferencingCollection }\n\n// #650 Task 4 (#647) — the reserved-collection naming helper `vault.ts`'s sync-registry\n// bookkeeping needs (mapping a declared dimension name to its `_dict_<name>` collection name).\nexport { dictCollectionName } from '../../via/lookup/handle.js'\n\n// #650 Task 2 — the alias-equivalence bridge (`resolveLabelFromMap` +\n// `collectLookupDictCompat`/`lookupToStaticDictCompat`) + the runtime\n// brand/shape predicates `via/compose.ts` needs to route `'lookup'`-branded\n// descriptors, mirroring `isI18nTextDescriptor`/`isDictKeyDescriptor` below.\nexport { resolveLabelFromMap, collectLookupDictCompat, lookupToStaticDictCompat }\nexport type { LookupDictCompat }\n\n// #653 — partial-sync reserved-dict expansion: maps a set of named collections to the\n// one-hop `_dict_*` deps their lookup fields reference, off `dictKeyFieldRegistry`.\nexport { reservedDictDepsOf }\n\n// #650 Task 3 — altKeys ingest normalization + open/closed vocabulary\n// governance: the declare/warm-time altIndex builder + the membership test\n// vault.ts's `membership`/`getAltIndex` closures delegate to.\nexport { materializeBackingTable, checkLookupMembership, buildLookupAltIndex }\nexport type { MaterializedBacking }\n\n// #650 Task 5 — registers a collection's lookup-fields' cross-collection 'ref' graph edges.\nexport { registerLookupRefEdges }\n\n// #650 Task 6 — the sync snapshot+locale seam (#626 retirement, spec §5):\n// `snapshotFor`'s vault-built row source + the combined presentForJoin\n// builder `kernel/collection-config.ts` calls to build the\n// `JoinableSource.presentForJoin` hook `kernel/query/join.ts` consumes.\nexport { buildLookupSnapshotRows, buildPresentForJoin }\nexport type { LookupSnapshot } from '../../via/lookup/snapshot.js'\n\n// #651 Task 3 — the ONE descriptor-keyed key-resolution core (guarded coercion +\n// backing-row-key resolve + referencing-value match) — every consumer (vault.ts,\n// with-shape/links/vault-facade.ts, kernel/via/dispatch.ts) routes through here,\n// never a bare `String()`, ending the dm12 dialect drift.\nexport { coerceLookupKey, resolveBackingRowKey, matchesReferencingValue }\n\n/** Runtime predicate for detecting a `LookupDescriptor` (any of the three tiers). */\nexport function isLookupDescriptor(x: unknown): x is LookupDescriptor {\n return (\n typeof x === 'object' &&\n x !== null &&\n (x as { _viaBrand?: unknown })._viaBrand === 'lookup'\n )\n}\n\n/** Runtime predicate for the bare enum tier (`backing:'static'`, no in-code `table` — no label source). */\nexport function isEnumDescriptor(x: unknown): x is LookupDescriptor {\n return isLookupDescriptor(x) && x.backing === 'static' && x.table === undefined\n}\n\n/**\n * Type-only re-exports — the kernel spine imports these descriptor/handle\n * types through the port instead of reaching into `via/lookup/*` or\n * `via/i18n/*` directly. `isolatedModules: true` erases these at\n * build time — no runtime coupling.\n */\nexport type { LookupHandle, DictEntry, DictionaryOptions } from '../../via/lookup/handle.js'\nexport type { LookupDescriptor, Vocabulary, LookupBacking, OnDelete } from '../../via/lookup/descriptor.js'\nexport type { LookupViaConfig } from '../../via/lookup/binding.js'\nexport type { DictKeyDescriptor, StaticDictDescriptor } from '../../via/i18n/dictionary.js'\n","// kernel/via/dispatch.ts — the batched, origin-aware sync/cutover/restore dispatch wave\n// (Via port phase C, #638 Task 4, fixes #621).\n//\n// `Collection._onRecordMutated`'s `sync-apply`/`cutover`/`restore` cases feed touched\n// (collection, id) pairs into a per-session `GraphBatch` (owned by `Vault._collectGraphTouch`)\n// instead of dispatching inline — the `local-write` path keeps its own byte-identical inline\n// dispatch (`wave` stays `undefined` there, per the spec's behavior lock). At batch-flush time\n// `runGraphDispatchWave` decrypts each touched record (id threaded into the decrypt, matching\n// the phase-B at-rest contract) and re-runs the SAME `dispatchDerivations`/\n// `dispatchMaterializedViews` the local-write path uses, sharing one `WaveContext` so N touched\n// records feeding the SAME rollup/MV target recompute exactly once (per-target dedup).\n// See docs/superpowers/specs/2026-07-11-via-phase-c-design.md §3.\n\nimport type { ViaGraph } from './graph.js'\nimport type { Collection } from '../collection.js'\nimport type { EncryptedEnvelope } from '../types.js'\nimport { PeriodClosedError } from '../errors.js'\nimport { matchesReferencingValue } from '../../port/with/lookup-strategy.js'\n\n/** One deleted child's resolved rollup PARENT intent (#640) — ids + a field name only. A\n * resolved `parentId` is an id, same class as any touched record id — never a stored value. */\nexport interface RollupDeleteIntent {\n readonly into: string\n readonly parentId: string\n readonly field: string\n}\n\n/** One collection's batched touches this session (#640 widens the #638 `Set<string>` shape):\n * `puts` — the original semantics, unchanged; `deletes` — a deleted record's id mapped to its\n * resolved rollup-parent intents, captured PRE-invalidation by `Collection._onRecordMutated`'s\n * sync-apply delete case (the FK is only readable there — see `kernel/collection.ts\n * #_rollupDeleteIntents`). */\nexport interface GraphTouch {\n readonly puts: Set<string>\n readonly deletes: Map<string, readonly RollupDeleteIntent[]>\n}\n\n/** Per-session touched set — collection → its `GraphTouch`. Metadata only — ids (collection\n * names, record ids INCLUDING resolved rollup parent ids) and field names; NEVER record payload\n * or key material. A resolved parentId is an id, same class as the touched ids — not a stored\n * value. */\nexport type GraphBatch = Map<string, GraphTouch>\n\n/** Get-or-create `batch`'s `GraphTouch` entry for `collection` (#640) — shared by\n * `Vault._collectGraphTouch`/`_collectGraphDelete` so each stays a one-line call. */\nexport function touchFor(batch: GraphBatch, collection: string): GraphTouch {\n let t = batch.get(collection)\n if (!t) {\n t = { puts: new Set(), deletes: new Map() }\n batch.set(collection, t)\n }\n return t\n}\n\n/** #640 — sync, I/O-free: `deleted`'s resolved rollup PARENT intents (the FK is only readable\n * NOW, before the record is gone) — a pure function so `Collection._rollupDeleteIntents` stays\n * a one-line delegator under the kernel-surface ceiling. `registry` is `this.derivationSource\n * ?.registry()`; `collectionName` is `this.name` (the CHILD/`rollup.from` side). Generic over\n * the registry's own spec shape so this file never imports a `with-formula` type (port-layering\n * — via/dispatch.ts must not gain a with-* import). */\nexport function resolveRollupDeleteIntents<S extends { source: string; rollup?: { from: string; key: string; field: string } }>(\n registry: { strategiesForSource(name: string): ReadonlyArray<{ spec: S }> } | undefined,\n collectionName: string,\n deleted: Record<string, unknown>,\n): RollupDeleteIntent[] {\n if (!registry) return []\n const intents: RollupDeleteIntent[] = []\n for (const { spec } of registry.strategiesForSource(collectionName)) {\n if (!spec.rollup || spec.rollup.from !== collectionName) continue\n const kv = deleted[spec.rollup.key]\n if (typeof kv === 'string' || typeof kv === 'number') intents.push({ into: spec.source, parentId: String(kv), field: spec.rollup.field })\n }\n return intents\n}\n\n/** #640 — resolve a `RollupDeleteIntent` back to its registry `spec`. The wave's per-intent\n * driver needs `spec.rollup.compute`, which `GraphBatch`'s metadata-only pin forbids batching —\n * so it's re-resolved here, post-boundary, instead of carried across it. `undefined` if the\n * intent's originating strategy was unregistered between collect time and wave time (residual\n * gap, freshness-only). */\nexport function findRollupSpecForIntent<S extends { source: string; rollup?: { from: string; field: string } }>(\n registry: { strategiesForSource(name: string): ReadonlyArray<{ spec: S }> } | undefined,\n collectionName: string,\n intent: RollupDeleteIntent,\n): S | undefined {\n return registry?.strategiesForSource(collectionName).find((s) => s.spec.source === intent.into && s.spec.rollup?.field === intent.field && s.spec.rollup?.from === collectionName)?.spec\n}\n\n/** One dedup ledger for a single wave — a target is recomputed at most once (mark-on-check). */\nexport class WaveContext {\n private readonly _seen = new Set<string>()\n seen(targetKey: string): boolean {\n if (this._seen.has(targetKey)) return true\n this._seen.add(targetKey)\n return false\n }\n}\n\n/** The slice of `Vault` the wave needs: the shared graph (the #553 zero-cost skip) and cached-\n * collection lookup — never constructs, since a touched collection is, by construction,\n * already open (it just fired `_onRecordMutated`). */\nexport interface VaultLike {\n readonly graph: ViaGraph\n _getCollection(name: string): Collection<Record<string, unknown>> | undefined\n /** #640 (#644 item 3) — structured wave-error surfacing, additive to the existing console.warn. */\n _emit(event: string, payload: unknown): void\n}\n\n/**\n * Run ONE dispatch wave for a completed batch: for each touched (collection, id), decrypt the\n * applied envelope (id threaded), then run the SAME `dispatchDerivations` +\n * `dispatchMaterializedViews` the local-write path uses — with a shared `WaveContext` so N\n * touched records feeding the SAME target recompute once. #553: a collection with no graph\n * out-edges (e.g. money-only) is skipped before any decrypt/dispatch async work.\n */\nexport async function runGraphDispatchWave(vault: VaultLike, batch: GraphBatch): Promise<void> {\n const wave = new WaveContext()\n for (const [collectionName, touch] of batch) {\n if (vault.graph.dependentsOf(collectionName).length === 0) continue\n const coll = vault._getCollection(collectionName)\n if (!coll) continue\n for (const id of touch.puts) {\n try {\n // Decrypt is INSIDE the per-id isolation boundary (whole-branch review Important\n // finding, #638): an undecryptable synced envelope (`TamperedError`) must not\n // escape `_getStoredRecordForDispatch` and abort the wave — that would propagate\n // through `_flushGraphBatch` and reject the surrounding `SyncEngine.pull`/`push`\n // AFTER records were already applied + meta persisted, starving every other\n // touched target in the same batch.\n const stored = await coll._getStoredRecordForDispatch(id)\n if (!stored) continue\n await coll.dispatchDerivations(id, stored.record, stored.version, wave)\n await coll.dispatchMaterializedViews(id, stored.record, wave)\n } catch (err) {\n // #638 Task 5 review mandate: one touched record's recompute must not abort the\n // whole wave (starving co-batched healthy targets) or the pull/push it's nested\n // inside. `PeriodClosedError` never reaches here — `putDerivedOutput` already\n // intercepts it at every output-write call site and turns it into a skip+event.\n // Anything else (a genuine decrypt failure, a derive()/executor bug, a schema\n // violation on the output, ...) is surfaced — not silently swallowed — via the\n // SAME console.warn channel `dispatchDerivations`/the MV executor already use for\n // their own non-strict-mode output failures, then isolated to just this one id.\n // #644 item 3: ADDITIVELY (never in place of the warn) emit a structured event too,\n // so a listener doesn't have to scrape console output to react to a wave failure.\n console.warn(`[via-dispatch] wave recompute failed for ${collectionName}/${id}:`, err)\n vault._emit('derivation:wave-error', { collection: collectionName, id, error: err })\n }\n }\n // #640 — delete-kind touches: the deleted child's rollup-parent intents, resolved (sync,\n // pre-invalidation) at collect time by `Collection._rollupDeleteIntents`. Same per-id\n // isolation as the puts loop above. #658: the wave now ALSO heals MV rows and array-shape\n // derivation output rows for the deleted child — parity with the local-delete boundary\n // (`Collection._doDelete`'s `!internal` block, which already calls all three). Still never\n // routed through `dispatchDerivations` (the mutation-choke-point.test.ts:85-99 pin — sync-\n // applied deletes never RE-DERIVE); `dispatchMaterializedViewsOnDelete`/\n // `dispatchArrayDerivationsOnDelete` only need `id` (MV refresh recomputes+diffs; array-\n // derivation reads its per-source sidecar) and never call `derive()`, so the pin holds.\n for (const [id, intents] of touch.deletes) {\n try {\n await coll._recomputeDeletedRollups(intents, wave)\n // #658: record-shape same-id outputs are left untouched (eraseRecordShapeToo defaults\n // false), matching local delete — the user deletes those directly if wanted.\n // #658: TODO dedup MV refresh per wave — `dispatchMaterializedViewsOnDelete` doesn't\n // accept a `WaveContext` (unlike the put-path `dispatchMaterializedViews`), so N deleted\n // children of one eager MV in a batch each trigger a full refresh pass. Threading `wave`\n // through would touch collection.ts's zero-slack kernel-surface ceiling for a perf-only\n // win; correctness doesn't depend on it (idempotent per source-id) — left as a follow-up.\n await coll.dispatchMaterializedViewsOnDelete(id)\n await coll.dispatchArrayDerivationsOnDelete(id)\n } catch (err) {\n console.warn(`[via-dispatch] wave delete-recompute failed for ${collectionName}/${id}:`, err)\n vault._emit('derivation:wave-error', { collection: collectionName, id, error: err })\n }\n }\n }\n}\n\n/** A record's post-freeze source mutation, for the `'derivation:skipped-frozen'` event\n * and the optional audit-trail entry. See {@link putDerivedOutput}. */\nexport interface DerivationSkippedFrozen {\n readonly source: { readonly collection: string; readonly id: string }\n readonly target: { readonly collection: string; readonly id: string }\n readonly period: string\n readonly endDate: string\n}\n\n/** The minimal put-capable shape `putDerivedOutput` needs. Any `Collection<T>` structurally\n * satisfies this — its real `options` type is a superset of what's declared here. */\nexport interface CollectionLike {\n put(id: string, value: unknown, options?: { readonly source?: string }): Promise<void>\n}\n\nexport interface PutDerivedOutputCtx {\n readonly emit: (ev: string, p: unknown) => void\n readonly source: { readonly collection: string; readonly id: string }\n readonly audit?: ((e: DerivationSkippedFrozen) => Promise<void>) | undefined\n}\n\n/**\n * Attempt a dispatch-driven output write. On `PeriodClosedError` (the closed-period\n * `beforePut` gate — `freezePeriod`/`archivePeriod` add no separate gate, per seam map\n * Part 7): SKIP (no `_ts` stamped — the gate throws before any write happens), emit\n * `'derivation:skipped-frozen'` on the event bus (ALWAYS), and append an audit-trail entry\n * when the with-history ledger is active. Returns `'written' | 'skipped-frozen'`. Any OTHER\n * error propagates unchanged — this helper narrows exactly one error class. The SOURCE\n * write is never wrapped through this helper — only derived-output writes are (§7).\n */\nexport async function putDerivedOutput(\n outColl: CollectionLike, id: string, value: unknown,\n ctx: PutDerivedOutputCtx,\n options?: { readonly source?: string },\n): Promise<'written' | 'skipped-frozen'> {\n try {\n await outColl.put(id, value, options)\n return 'written'\n } catch (err) {\n if (!(err instanceof PeriodClosedError)) throw err\n // Reach-around for the target collection's private `name` — the SAME pattern\n // `with-formula/materialized-views/executor.ts`'s `listOutputIds` already uses to\n // read a `Collection`'s private `adapter`/`vault`/`name` fields from outside the class.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const targetCollection = (outColl as any).name as string\n const event: DerivationSkippedFrozen = {\n source: ctx.source,\n target: { collection: targetCollection, id },\n period: err.periodName,\n endDate: err.endDate,\n }\n ctx.emit('derivation:skipped-frozen', event)\n if (ctx.audit) await ctx.audit(event)\n return 'skipped-frozen'\n }\n}\n\n/** Structural (no static import — kernel spine may not statically reach a with-* service,\n * the S4 gate recipe `check-architecture.mjs`'s port-layering check enforces) shape of the\n * with-history `LedgerStore.append` seam this helper needs. */\ninterface AuditLedgerLike {\n append(input: {\n readonly op: 'lifecycle'\n readonly collection: string\n readonly id: string\n readonly version: number\n readonly actor: string\n readonly payloadHash: string\n readonly reason?: string\n }): Promise<unknown>\n}\n\n/** @internal — the optional with-history ledger audit hook for `putDerivedOutput`, present\n * only when the ledger is active (mirrors every other kernel event's `if (this.ledger)`\n * gate). Encoded as a `'lifecycle'` entry — the existing \"non-data audit event\" op (the\n * same convention `forget`'s JSON-summary-in-`reason` entry uses; `ledger/entry.ts:88-104`). */\nexport function ledgerAuditHook(\n ledger: AuditLedgerLike | undefined, actor: string,\n): ((e: DerivationSkippedFrozen) => Promise<void>) | undefined {\n if (!ledger) return undefined\n return async (e) => {\n await ledger.append({\n op: 'lifecycle', collection: e.target.collection, id: e.target.id, version: 0, actor, payloadHash: '',\n reason: JSON.stringify({ event: 'derivation-skipped-frozen', ...e }),\n })\n }\n}\n\n/** `recomputeRollup`/`dispatchRollupsOnDelete`'s per-target write outcome (#638 Task 6):\n * `'written'`/`'skipped-frozen'` mirror {@link putDerivedOutput}'s result; `'noop'` covers\n * no-parent/no-change/deduped-by-wave — nothing to report either way. */\nexport type RollupOutcome = 'written' | 'skipped-frozen' | 'noop'\n\n/** Mutable accumulator `forgetDerivedFanout` writes into, one per `Vault.forget()` call — keeps\n * the per-ref loop's call site to a single line under vault.ts's tight kernel-surface ceiling.\n * Maps 1:1 onto `ForgetResult`'s additive fields (`with-audit/forget/strategy.ts`). */\nexport interface ForgetFanoutStats {\n recordsErased: number\n aggregatesRecomputed: number\n readonly residueFrozen: string[]\n /** #650 Task 5 (#648) — referencing records tombstoned via a `'ref'` edge's `cascade` policy. */\n lookupReferencesCascaded: number\n /** #650 Task 5 (#648) — referencing fields cleared via a `'ref'` edge's `nullify` policy. */\n lookupReferencesNullified: number\n /** #650 Task 5 review (Important fix) — `'ref'` edges whose compare-key could NOT be resolved,\n * even from the LIVE pre-shred row (the backing row itself is unreadable) — propagation was\n * skipped for these, reported here so the skip is never silent. `backing:key:collection.field`\n * entries, one per un-propagated edge. */\n readonly lookupReferencesResidue: string[]\n /** #776/#782/#785 — `outputCollection:id` MV-output rows that survived erasure invalidation\n * (eager tombstone leg AND lazy/manual `invalidateMVAtRest`) despite belonging to the\n * forgotten subject, because the ownership stamp could not be decoded (undecodable under\n * the default DEK — e.g. elevated above tier 0 on a tiered output collection). Ownership\n * UNCONFIRMED. Never erased, but surfaced here rather than silently skipped. */\n readonly derivedResidueUndecodable: string[]\n /** #782/#785 — `outputCollection:id` MV-output rows that decoded and stamp-matched but whose\n * `_internalDelete` declined (the #718 tier-elevation gate). Ownership CONFIRMED, erasure\n * declined — a real silent survival, surfaced here rather than silently skipped. */\n readonly derivedResidueDeclined: string[]\n}\n\n/**\n * #622 — after `_writeTombstone(ref.id, actor)` erases the forgotten subject's own record, fan\n * out to its derived residue via the graph (spec §5): record-grain artifacts (MV rows,\n * array-shape derivation rows, same-id record-shape derivation copies) are ERASED through the\n * SAME `!internal` housekeeping-bypass machinery the ordinary delete path uses (no user\n * `onDelete` re-fires — the shred-is-not-a-domain-delete property `_writeTombstone` protects);\n * aggregate-grain rollups are RECOMPUTED without the forgotten contribution in open periods, or\n * skip+audit (via `putDerivedOutput`, already wired into the rollup/MV output paths) in frozen\n * ones. Mutates `stats` in place. `envelope` is `ref`'s PRE-tombstone envelope, decoded only if\n * a rollup edge is actually present — the #553 zero-cost-skip discipline: no decrypt for the\n * common case of a forgotten record with no aggregate-grain consumer, and no work at all when\n * `ref.collection` has no graph out-edges. `lookupCompareKeys` is the `'ref'` edges' compare-key\n * map, resolved from the LIVE row BEFORE any shred (`VaultLinks.checkLookupRefsRestrict`'s return\n * value — `Vault.forget()`'s pre-shred restrict check doubles as the live-resolve pass) — see\n * {@link applyLookupRefsFanout}.\n */\nexport async function forgetDerivedFanout(\n vault: VaultLike,\n ref: { readonly collection: string; readonly id: string },\n envelope: EncryptedEnvelope | null,\n stats: ForgetFanoutStats,\n lookupCompareKeys: ReadonlyMap<string, string | undefined>,\n): Promise<void> {\n const coll = vault._getCollection(ref.collection)\n\n // #761 item 4 — drive the MV arm off `dispatchMaterializedViewsOnDelete` UNCONDITIONALLY,\n // ABOVE the `edges` check below: `registry.edges()` drops the same-collection\n // partition-disjoint MV edge (registry.ts's `sources.length === 0 → continue`), so a\n // same-collection MV's source collection never appears in `vault.graph`'s derived-artifact\n // edges even though the MV IS registered — forget() would otherwise never reach it.\n // `dispatchMaterializedViewsOnDelete` self-guards O(1) via `mvsForSource` (a no-op when\n // this collection isn't an MV source), so this is safe to call unconditionally. Safe to\n // route through the eager executor's tombstone leg ONLY because that leg is now\n // stamp-scoped (#762) — before that fix this would have opened a NEW forget-time\n // data-loss path into the unscoped tombstone diff.\n if (coll) {\n const mv = await coll.dispatchMaterializedViewsOnDelete(ref.id)\n stats.recordsErased += mv.deleted\n stats.derivedResidueUndecodable.push(...mv.residueUndecodable)\n stats.derivedResidueDeclined.push(...mv.residueDeclined)\n }\n\n const edges = vault.graph.derivedArtifactsOf(ref.collection)\n if (edges.length === 0 || !coll) return\n\n // #650 Task 5 (#648) — 'ref' cascade/nullify propagate ADDITIVELY, here, AFTER the shred\n // (restrict already refused BEFORE any shred — the caller's pre-tombstone check, spec §4).\n // The I/O shell (loop shape, collection accessor) is duplicated, not imported, from\n // `VaultLinks.applyLookupRefsPropagation`/`checkLookupRefsRestrict` (with-shape/links/\n // vault-facade.ts) — the kernel spine may not statically import a with-* service\n // (port-layering, the #638 Task 5 via/dispatch.ts precedent); `vault._getCollection` is\n // cached-only while `VaultLinks`' accessor constructs. The pure match predicate itself is\n // shared through the port seam (#651 Task 3 — `matchesReferencingValue`, `port/with/\n // lookup-strategy.ts`), so only the shell, not the coercion logic, stays duplicated. A\n // referencing edge whose dimension uses a non-default `key` (matrix tier only) needs the\n // backing row's OWN value at that field, not its PUT-id — the row is ALREADY tombstoned by\n // now, so it's read from `lookupCompareKeys`, resolved by the caller from the LIVE row\n // BEFORE the shred (#650 Task 5 review, Important fix — eliminates the post-shred\n // envelope-decode dependency this used to have, which silently skipped propagation whenever\n // that decode failed).\n if (edges.some((e) => e.kind === 'ref')) {\n const { cascaded, nullified, residue } = await applyLookupRefsFanout(vault, ref.collection, ref.id, lookupCompareKeys)\n stats.lookupReferencesCascaded += cascaded\n stats.lookupReferencesNullified += nullified\n stats.lookupReferencesResidue.push(...residue)\n }\n\n if (edges.some((e) => e.kind === 'derivation')) {\n // #622 review Finding 1: count REAL erasures (dispatchArrayDerivationsOnDelete's own\n // `_internalDelete`-backed tally), not the derivation EDGE count — an edge exists whenever\n // this collection is ANY trigger (source/sources[]/triggerBy), but the same-id record-shape\n // guard only erases for `spec.source === this.name`, and `derive()` may never have produced\n // an output row (optional-skip) in the first place. Both cases must contribute 0, not +1.\n stats.recordsErased += await coll.dispatchArrayDerivationsOnDelete(ref.id, true)\n }\n\n if (envelope && edges.some((e) => e.kind === 'rollup')) {\n const priorRecord = await coll._decodeEnvelope(envelope, ref.id)\n if (priorRecord) {\n for (const r of await coll.dispatchRollupsOnDelete(ref.id, priorRecord)) {\n if (r.outcome === 'written') stats.aggregatesRecomputed += 1\n else if (r.outcome === 'skipped-frozen') stats.residueFrozen.push(`${r.into}:${r.parentId}`)\n }\n }\n }\n}\n\n/**\n * Apply `cascade`/`nullify` propagation for `backing`'s non-restrict `'ref'` edges — the\n * forget-path counterpart of `VaultLinks.applyLookupRefsPropagation` (I/O shell duplicated, not\n * imported, match predicate shared via the port — see {@link forgetDerivedFanout}'s call site\n * comment). `restrict` edges are skipped here: the\n * forget loop's `checkLookupRefsRestrict`-equivalent call already refused (or the reference no\n * longer existed) BEFORE `_writeTombstone` ran, so by the time this runs only cascade/nullify\n * remain to propagate. `compareKeys` is the non-`'id'`-`keyField` compare-value map, resolved by\n * the caller from the LIVE row BEFORE the shred (#650 Task 5 review, Important fix) — the live row\n * is already shredded by the time THIS function runs, so it can no longer resolve one itself. A\n * `keyField` absent from (or `undefined` in) the map means that live resolve failed too — the edge\n * is reported as residue instead of silently skipped (never a bare `continue` with no trace).\n */\nasync function applyLookupRefsFanout(\n vault: VaultLike,\n backing: string,\n key: string,\n compareKeys: ReadonlyMap<string, string | undefined>,\n): Promise<{ cascaded: number; nullified: number; residue: string[] }> {\n let cascaded = 0\n let nullified = 0\n const residue: string[] = []\n for (const { referencing, onDelete, keyField } of vault.graph.referencingEdgesOf(backing)) {\n if (onDelete === 'restrict') continue\n const compareKey = keyField === 'id' ? key : compareKeys.get(keyField)\n if (compareKey === undefined) {\n residue.push(`${backing}:${key}:${referencing.collection}.${referencing.field}`)\n continue\n }\n const coll = vault._getCollection(referencing.collection)\n if (!coll) continue\n const matches = (await coll.list()).filter((rec) => matchesReferencingValue(rec, referencing.field, compareKey))\n for (const rec of matches) {\n const id = rec['id'] as string | undefined\n if (id === undefined) continue\n if (onDelete === 'cascade') {\n await coll.delete(id)\n cascaded++\n } else if (onDelete === 'nullify') {\n await coll.put(id, { ...rec, [referencing.field]: null })\n nullified++\n }\n }\n }\n return { cascaded, nullified, residue }\n}\n\n/**\n * Value-equality for a single self-write reverse-denorm field. Scalars\n * compare by identity; objects by canonical JSON (denorm values should be\n * deterministically shaped). Used as the cycle guard — when every denorm\n * field already matches, no write is issued and the self-write recursion ends.\n */\nexport function selfWriteFieldEqual(a: unknown, b: unknown): boolean {\n if (a === b) return true\n if (a === null || b === null || typeof a !== 'object' || typeof b !== 'object') return false\n try {\n return JSON.stringify(a) === JSON.stringify(b)\n } catch {\n return false\n }\n}\n"],"mappings":";;;;;;;;;;;;;;AA+BO,SAAS,uBACd,cACA,QACM;AACN,MAAI,CAAC,gBAAgB,OAAO,KAAK,YAAY,EAAE,WAAW,EAAG;AAC7D,MAAI,CAAC,UAAU,OAAO,WAAW,SAAU;AAE3C,QAAM,MAAM;AACZ,aAAW,CAAC,OAAO,IAAI,KAAK,OAAO,QAAQ,YAAY,GAAG;AACxD,QAAI,KAAK,kBAAkB,MAAO;AAClC,UAAM,QAAQ,IAAI,IAAY,KAAK,IAAI;AACvC,UAAM,SAAS,UAAU,KAAK,KAAK;AACnC,eAAW,SAAS,QAAQ;AAC1B,UAAI,UAAU,UAAa,UAAU,KAAM;AAC3C,YAAM,QAAQ,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK;AACnD,iBAAW,QAAQ,OAAO;AACxB,YAAI,OAAO,SAAS,SAAU;AAC9B,YAAI,CAAC,MAAM,IAAI,IAAI,GAAG;AACpB,gBAAM,IAAI,qBAAqB,KAAK,MAAM,OAAO,IAAI;AAAA,QACvD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAoBO,SAAS,kBACd,gBACA,OACA,yBACA,sBACA,qBACuB;AACvB,QAAM,eAAe,wBAAwB,IAAI,cAAc;AAC/D,MAAI,gBAAgB,SAAS,cAAc;AACzC,UAAM,OAAO,aAAa,KAAK;AAC/B,UAAM,OAA2C,OAAO,QAAQ,KAAK,KAAK,EAAE;AAAA,MAC1E,CAAC,CAAC,KAAK,MAAM,OAAO,EAAE,KAAK,QAAQ,GAAI,OAAkC;AAAA,IAC3E;AACA,UAAM,SAAyB;AAAA,MAC7B,WAA+B;AAC7B,eAAO;AAAA,MACT;AAAA,MACA,WAAW,IAAqB;AAC9B,eAAO,KAAK,KAAK,CAAC,MAAM,EAAE,KAAK,MAAM,EAAE;AAAA,MACzC;AAAA,IACF;AACA,QAAI,KAAK,kBAAkB,QAAW;AACpC;AAAC,MAAC,OAAsC,gBAAgB,KAAK;AAAA,IAC/D;AACA,WAAO;AAAA,EACT;AAEA,QAAM,aAAa,qBAAqB,IAAI,cAAc;AAC1D,MAAI,CAAC,cAAc,EAAE,SAAS,YAAa,QAAO;AAClD,QAAM,WAAW,WAAW,KAAK;AACjC,MAAI,CAAC,SAAU,QAAO;AACtB,QAAM,SAAS,oBAAoB,QAAQ;AAC3C,SAAO;AAAA,IACL,WAA+B;AAC7B,aAAO,OAAO,gBAAgB;AAAA,IAChC;AAAA,IACA,WAAW,IAAqB;AAC9B,YAAM,UAAU,OAAO,gBAAgB;AACvC,aAAO,QAAQ,KAAK,CAAC,MAAM,EAAE,KAAK,MAAM,EAAE;AAAA,IAC5C;AAAA,EACF;AACF;AAkBA,eAAsB,yBACpB,UACA,eACA,MACA,QACA,QACe;AACf,aAAW,CAAC,gBAAgB,UAAU,KAAK,UAAU;AAEnD,UAAM,SAAS,OAAO,QAAQ,UAAU,EACrC,OAAO,CAAC,CAAC,EAAE,EAAE,MAAM,OAAO,IAAI,EAC9B,IAAI,CAAC,CAAC,KAAK,MAAM,KAAK;AACzB,QAAI,OAAO,WAAW,EAAG;AAEzB,UAAM,OAAO,cAAc,cAAc;AACzC,UAAM,UAAU,MAAM,KAAK,KAAK;AAChC,eAAW,UAAU,SAAS;AAC5B,UAAI,UAAU;AACd,YAAM,UAAU,EAAE,GAAG,OAAO;AAC5B,iBAAW,SAAS,QAAQ;AAC1B,YAAI,QAAQ,KAAK,MAAM,QAAQ;AAC7B,kBAAQ,KAAK,IAAI;AACjB,oBAAU;AAAA,QACZ;AAAA,MACF;AACA,UAAI,SAAS;AACX,cAAM,KAAK,OAAO,IAAI;AACtB,YAAI,OAAO,QAAW;AACpB,gBAAM,KAAK,IAAI,IAAI,OAAO;AAAA,QAC5B;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AASO,SAAS,oBACd,QACA,QACA,UACoB;AACpB,MAAI,OAAO,MAAM,MAAM,OAAW,QAAO,OAAO,MAAM;AACtD,QAAM,QAAQ,MAAM,QAAQ,QAAQ,IAC/B,WACD,WACE,CAAC,QAAkB,IACnB,CAAC;AACP,aAAW,MAAM,OAAO;AACtB,QAAI,OAAO,OAAO;AAChB,YAAM,MAAM,OAAO,OAAO,MAAM,EAAE,CAAC;AACnC,UAAI,QAAQ,OAAW,QAAO;AAAA,IAChC,WAAW,OAAO,EAAE,MAAM,QAAW;AACnC,aAAO,OAAO,EAAE;AAAA,IAClB;AAAA,EACF;AACA,SAAO;AACT;AAcO,SAAS,yBAAyB,MAA0D;AACjG,MAAI,KAAK,YAAY,YAAY,KAAK,UAAU,OAAW,QAAO;AAClE,SAAO;AAAA,IACL,kBAAkB;AAAA,IAClB,WAAW;AAAA,IACX,MAAM,KAAK;AAAA,IACX,OAAO,KAAK;AAAA,IACZ,MAAM,KAAK,QAAQ,OAAO,KAAK,KAAK,KAAK;AAAA,IACzC,GAAI,KAAK,kBAAkB,SAAY,EAAE,eAAe,KAAK,cAAc,IAAI,CAAC;AAAA,IAChF,GAAI,KAAK,cAAc,SAAY,EAAE,WAAW,KAAK,UAAU,IAAI,CAAC;AAAA,IACpE,GAAI,KAAK,eAAe,SAAY,EAAE,YAAY,KAAK,WAAW,IAAI,CAAC;AAAA,IACvE,eAAe,KAAK,eAAe;AAAA,EACrC;AACF;AAmBO,SAAS,wBACd,cACkB;AAClB,QAAM,eAAuC,CAAC;AAC9C,QAAM,gBAAgE,CAAC;AACvE,aAAW,CAAC,OAAO,IAAI,KAAK,OAAO,QAAQ,gBAAgB,CAAC,CAAC,GAAG;AAC9D,QAAI,KAAK,YAAY,YAAY;AAC/B,mBAAa,KAAK,IAAI,KAAK;AAAA,IAC7B,OAAO;AACL,YAAM,SAAS,yBAAyB,IAAI;AAC5C,UAAI,OAAQ,eAAc,KAAK,CAAC,OAAO,MAAM,CAAC;AAAA,IAChD;AAAA,EACF;AACA,SAAO,EAAE,cAAc,cAAc;AACvC;AAUO,SAAS,mBACd,OACA,sBACmB;AACnB,QAAM,MAAM,oBAAI,IAAY;AAC5B,aAAW,QAAQ,OAAO;AACxB,UAAM,WAAW,qBAAqB,IAAI,IAAI;AAC9C,QAAI,CAAC,SAAU;AACf,eAAW,YAAY,OAAO,OAAO,QAAQ,EAAG,KAAI,IAAI,mBAAmB,QAAQ,CAAC;AAAA,EACtF;AACA,SAAO,CAAC,GAAG,GAAG;AAChB;AAwBO,SAAS,wBACd,YACA,MACqB;AACrB,QAAM,OAAO,IAAI,IAAY,KAAK,KAAK,CAAC;AAGxC,QAAM,QAAQ,oBAAI,IAAoB;AACtC,aAAW,OAAO,KAAM,OAAM,IAAI,KAAK,GAAG;AAE1C,QAAM,WAAW,oBAAI,IAAoB;AACzC,QAAM,YAAY,WAAW,WAAW,CAAC;AACzC,aAAW,CAAC,cAAc,GAAG,KAAK,MAAM;AACtC,eAAW,YAAY,WAAW;AAChC,YAAM,QAAQ,gBAAgB,IAAI,QAAQ,CAAC;AAC3C,UAAI,UAAU,UAAa,UAAU,GAAI;AACzC,YAAM,gBAAgB,MAAM,IAAI,KAAK;AACrC,UAAI,kBAAkB,UAAa,kBAAkB,cAAc;AACjE,cAAM,IAAI;AAAA,UACR,WAAW,WAAW,SAAS,oBAAoB,QAAQ,YAAY,KAAK,yBACjE,aAAa,UAAU,YAAY;AAAA,QAChD;AAAA,MACF;AACA,YAAM,IAAI,OAAO,YAAY;AAC7B,eAAS,IAAI,OAAO,YAAY;AAAA,IAClC;AAAA,EACF;AACA,SAAO,EAAE,MAAM,SAAS;AAC1B;AAeO,SAAS,sBACd,YACA,KACA,eACA,eACS;AACT,MAAI,WAAW,YAAY,UAAU;AACnC,UAAM,QAAQ,WAAW,SAAS,WAAW,QAAQ,OAAO,KAAK,WAAW,KAAK,IAAI,CAAC;AACtF,WAAO,MAAM,SAAS,GAAG;AAAA,EAC3B;AACA,MAAI,WAAW,YAAY,YAAY;AACrC,SAAK,WAAW,QAAQ,CAAC,GAAG,SAAS,GAAG,EAAG,QAAO;AAClD,WAAO,cAAc,WAAW,SAAS,EAAE,gBAAgB,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,MAAM,GAAG;AAAA,EAC3F;AACA,SAAO,oBAAoB,YAAY,eAAe,aAAa,EAAE,KAAK,IAAI,GAAG;AACnF;AAWO,SAAS,gBAAgB,KAAkC;AAChE,SAAO,OAAO,QAAQ,YAAY,OAAO,QAAQ,WAAW,OAAO,GAAG,IAAI;AAC5E;AAOO,SAAS,qBACd,YACA,KACoB;AACpB,SAAO,gBAAgB,IAAI,WAAW,GAAG,CAAC;AAC5C;AASO,SAAS,wBACd,KACA,OACA,YACS;AACT,SAAO,gBAAgB,IAAI,KAAK,CAAC,MAAM;AACzC;AAkBO,SAAS,oBACd,YACA,eACA,eACqB;AACrB,MAAI,WAAW,YAAY,UAAU;AACnC,WAAO,wBAAwB,YAAY,IAAI,IAAI,OAAO,QAAQ,WAAW,SAAS,CAAC,CAAC,CAAC,CAAC;AAAA,EAC5F;AACA,MAAI,WAAW,YAAY,YAAY;AACrC,UAAM,UAAU,cAAc,WAAW,SAAS,EAAE,gBAAgB;AACpE,WAAO,wBAAwB,YAAY,IAAI,IAAI,QAAQ,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAAA,EAC/F;AACA,QAAM,OAAO,cAAc,WAAW,SAAS,EAAE,mBAAmB,EAAE,SAAS;AAC/E,QAAM,QAAQ,oBAAI,IAAqC;AACvD,aAAW,KAAK,MAAM;AACpB,UAAM,MAAM;AACZ,UAAM,MAAM,qBAAqB,YAAY,GAAG;AAChD,QAAI,QAAQ,OAAW,OAAM,IAAI,KAAK,GAAG;AAAA,EAC3C;AACA,SAAO,wBAAwB,YAAY,KAAK;AAClD;AA0BA,SAAS,sBACP,gBACA,cAC0B;AAC1B,QAAM,QAAyB,CAAC;AAChC,aAAW,CAAC,OAAO,IAAI,KAAK,OAAO,QAAQ,gBAAgB,CAAC,CAAC,GAAG;AAC9D,QAAI,KAAK,YAAY,SAAU;AAC/B,UAAM,UAAU,KAAK,YAAY,aAAa,mBAAmB,KAAK,SAAS,IAAI,KAAK;AACxF,UAAM,KAAK;AAAA,MACT,aAAa,EAAE,YAAY,gBAAgB,MAAM;AAAA,MACjD,SAAS;AAAA,QACP,EAAE,YAAY,SAAS,OAAO,IAAI;AAAA,QAClC,GAAI,KAAK,SAAS,UAAU,SAAY,CAAC,EAAE,YAAY,SAAS,OAAO,KAAK,QAAQ,MAAM,CAAC,IAAI,CAAC;AAAA,MAClG;AAAA,MACA,UAAU,KAAK;AAAA,MACf,UAAU,KAAK;AAAA,IACjB,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAKO,SAAS,uBACd,OACA,gBACA,cACM;AACN,aAAW,KAAK,sBAAsB,gBAAgB,YAAY,GAAG;AACnE,UAAM,gBAAgB,EAAE,aAAa,EAAE,SAAS,OAAO,UAAU,EAAE,UAAU,EAAE,QAAQ;AAAA,EACzF;AACF;AAgCO,SAAS,wBACd,YACA,qBACA,eACA,eAC0D;AAC1D,QAAM,YAAY,WAAW;AAC7B,MAAI,oBAAoB,SAAS,GAAG;AAClC,UAAM,OAAO,oBAAI,IAAqC;AACtD,eAAW,SAAS,cAAc,SAAS,EAAE,gBAAgB,GAAG;AAC9D,YAAM,MAAM,MAAM,KAAK;AACvB,UAAI,OAAO,QAAQ,SAAU,MAAK,IAAI,KAAK,KAAK;AAAA,IAClD;AACA,WAAO;AAAA,EACT;AACA,MAAI,WAAW,YAAY,cAAc;AACvC,UAAM,UAAU,cAAc,SAAS,EAAE,mBAAmB,EAAE,SAAS;AACvE,UAAM,OAAO,oBAAI,IAAqC;AACtD,eAAW,KAAK,SAAS;AACvB,YAAM,MAAM;AACZ,YAAM,MAAM,qBAAqB,YAAY,GAAG;AAChD,UAAI,QAAQ,OAAW,MAAK,IAAI,KAAK,GAAG;AAAA,IAC1C;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;;;ACnfA,SAAS,aACP,KACA,OACA,IACA,QACA,UACoB;AACpB,MAAI,CAAC,OAAO,UAAU,OAAW,QAAO;AACxC,QAAM,MAAM,IAAI,KAAK;AACrB,MAAI,OAAO,OAAW,QAAO,OAAO,QAAQ,WAAW,MAAM;AAC7D,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO;AAC5C,QAAM,MAAM;AACZ,QAAM,MAAM,IAAI,MAAM;AACtB,MAAI,OAAO,QAAQ,SAAU,QAAO;AACpC,MAAI,OAAO,aAAa,YAAY,OAAO,IAAI,QAAQ,MAAM,SAAU,QAAO,IAAI,QAAQ;AAC1F,SAAO;AACT;AAOO,SAAS,oBACd,WACA,MACA,YACgB;AAChB,OAAK;AACL,SAAO;AAAA,IACL,KAAK,CAAC,QAAQ,KAAK,IAAI,GAAG;AAAA,IAC1B,OAAO,CAAC,KAAK,QAAQ,aACnB,aAAa,KAAK,IAAI,GAAG,GAAG,WAAW,SAAS,OAAO,WAAW,SAAS,IAAI,QAAQ,QAAQ;AAAA,IACjG,aAAa,CAAC,GAAG,GAAG,WAAW;AAC7B,YAAM,YAAY,WAAW,UAAU,WAAW,SAAS;AAC3D,YAAM,KAAK,aAAa,KAAK,IAAI,CAAC,GAAG,WAAW,WAAW,SAAS,IAAI,MAAM,KAAK;AACnF,YAAM,KAAK,aAAa,KAAK,IAAI,CAAC,GAAG,WAAW,WAAW,SAAS,IAAI,MAAM,KAAK;AACnF,aAAO,KAAK,KAAK,KAAK,KAAK,KAAK,IAAI;AAAA,IACtC;AAAA,EACF;AACF;AAeA,SAAS,qBACP,QACA,QACA,cACA,iBACyB;AACzB,MAAI,SAAS;AACb,aAAW,CAAC,OAAO,IAAI,KAAK,OAAO,QAAQ,YAAY,GAAG;AACxD,QAAI,KAAK,YAAY,OAAW;AAChC,UAAM,MAAM,OAAO,KAAK;AACxB,QAAI,OAAO,QAAQ,SAAU;AAC7B,UAAM,OAAO,KAAK,YAAY,WACzB,KAAK,QAAQ,IAAI,IAAI,OAAO,QAAQ,KAAK,KAAK,CAAC,IAAI,SACpD,gBAAgB,IAAI;AACxB,QAAI,CAAC,KAAM;AACX,UAAM,QAAQ,oBAAoB,KAAK,WAAW,MAAM,IAAI,EAAE,MAAM,KAAK,MAAM;AAC/E,QAAI,UAAU,OAAW;AACzB,QAAI,WAAW,OAAQ,UAAS,EAAE,GAAG,OAAO;AAC5C,WAAO,GAAG,KAAK,OAAO,IAAI;AAAA,EAC5B;AACA,SAAO;AACT;AAYO,SAAS,oBACd,YACA,cACA,iBAC4D;AAC5D,QAAM,UAAU,eAAe,UAAa,OAAO,KAAK,UAAU,EAAE,SAAS;AAC7E,QAAM,YAAY,iBAAiB,UAAa,OAAO,KAAK,YAAY,EAAE,SAAS;AACnF,MAAI,CAAC,WAAW,CAAC,UAAW,QAAO;AACnC,QAAM,cAAc,oBAAoB,MAAM;AAC9C,SAAO,CAAC,QAAQ,WAAW;AACzB,QAAI,WAAW,QAAQ,OAAO,WAAW,SAAU,QAAO;AAC1D,QAAI,SAAS;AACb,QAAI,QAAS,UAAS,mBAAmB,QAAQ,YAAY,MAAM;AACnE,QAAI,UAAW,UAAS,qBAAqB,QAAQ,QAAQ,cAAc,WAAW;AACtF,WAAO;AAAA,EACT;AACF;;;ACuCO,SAAS,mBAAmB,GAAmC;AACpE,SACE,OAAO,MAAM,YACb,MAAM,QACL,EAA8B,cAAc;AAEjD;;;AC7JO,SAAS,SAAS,OAAmB,YAAgC;AAC1E,MAAI,IAAI,MAAM,IAAI,UAAU;AAC5B,MAAI,CAAC,GAAG;AACN,QAAI,EAAE,MAAM,oBAAI,IAAI,GAAG,SAAS,oBAAI,IAAI,EAAE;AAC1C,UAAM,IAAI,YAAY,CAAC;AAAA,EACzB;AACA,SAAO;AACT;AAQO,SAAS,2BACd,UACA,gBACA,SACsB;AACtB,MAAI,CAAC,SAAU,QAAO,CAAC;AACvB,QAAM,UAAgC,CAAC;AACvC,aAAW,EAAE,KAAK,KAAK,SAAS,oBAAoB,cAAc,GAAG;AACnE,QAAI,CAAC,KAAK,UAAU,KAAK,OAAO,SAAS,eAAgB;AACzD,UAAM,KAAK,QAAQ,KAAK,OAAO,GAAG;AAClC,QAAI,OAAO,OAAO,YAAY,OAAO,OAAO,SAAU,SAAQ,KAAK,EAAE,MAAM,KAAK,QAAQ,UAAU,OAAO,EAAE,GAAG,OAAO,KAAK,OAAO,MAAM,CAAC;AAAA,EAC1I;AACA,SAAO;AACT;AAOO,SAAS,wBACd,UACA,gBACA,QACe;AACf,SAAO,UAAU,oBAAoB,cAAc,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,WAAW,OAAO,QAAQ,EAAE,KAAK,QAAQ,UAAU,OAAO,SAAS,EAAE,KAAK,QAAQ,SAAS,cAAc,GAAG;AACtL;AAGO,IAAM,cAAN,MAAkB;AAAA,EACN,QAAQ,oBAAI,IAAY;AAAA,EACzC,KAAK,WAA4B;AAC/B,QAAI,KAAK,MAAM,IAAI,SAAS,EAAG,QAAO;AACtC,SAAK,MAAM,IAAI,SAAS;AACxB,WAAO;AAAA,EACT;AACF;AAmBA,eAAsB,qBAAqB,OAAkB,OAAkC;AAC7F,QAAM,OAAO,IAAI,YAAY;AAC7B,aAAW,CAAC,gBAAgB,KAAK,KAAK,OAAO;AAC3C,QAAI,MAAM,MAAM,aAAa,cAAc,EAAE,WAAW,EAAG;AAC3D,UAAM,OAAO,MAAM,eAAe,cAAc;AAChD,QAAI,CAAC,KAAM;AACX,eAAW,MAAM,MAAM,MAAM;AAC3B,UAAI;AAOF,cAAM,SAAS,MAAM,KAAK,4BAA4B,EAAE;AACxD,YAAI,CAAC,OAAQ;AACb,cAAM,KAAK,oBAAoB,IAAI,OAAO,QAAQ,OAAO,SAAS,IAAI;AACtE,cAAM,KAAK,0BAA0B,IAAI,OAAO,QAAQ,IAAI;AAAA,MAC9D,SAAS,KAAK;AAWZ,gBAAQ,KAAK,4CAA4C,cAAc,IAAI,EAAE,KAAK,GAAG;AACrF,cAAM,MAAM,yBAAyB,EAAE,YAAY,gBAAgB,IAAI,OAAO,IAAI,CAAC;AAAA,MACrF;AAAA,IACF;AAUA,eAAW,CAAC,IAAI,OAAO,KAAK,MAAM,SAAS;AACzC,UAAI;AACF,cAAM,KAAK,yBAAyB,SAAS,IAAI;AAQjD,cAAM,KAAK,kCAAkC,EAAE;AAC/C,cAAM,KAAK,iCAAiC,EAAE;AAAA,MAChD,SAAS,KAAK;AACZ,gBAAQ,KAAK,mDAAmD,cAAc,IAAI,EAAE,KAAK,GAAG;AAC5F,cAAM,MAAM,yBAAyB,EAAE,YAAY,gBAAgB,IAAI,OAAO,IAAI,CAAC;AAAA,MACrF;AAAA,IACF;AAAA,EACF;AACF;AAgCA,eAAsB,iBACpB,SAAyB,IAAY,OACrC,KACA,SACuC;AACvC,MAAI;AACF,UAAM,QAAQ,IAAI,IAAI,OAAO,OAAO;AACpC,WAAO;AAAA,EACT,SAAS,KAAK;AACZ,QAAI,EAAE,eAAe,mBAAoB,OAAM;AAK/C,UAAM,mBAAoB,QAAgB;AAC1C,UAAM,QAAiC;AAAA,MACrC,QAAQ,IAAI;AAAA,MACZ,QAAQ,EAAE,YAAY,kBAAkB,GAAG;AAAA,MAC3C,QAAQ,IAAI;AAAA,MACZ,SAAS,IAAI;AAAA,IACf;AACA,QAAI,KAAK,6BAA6B,KAAK;AAC3C,QAAI,IAAI,MAAO,OAAM,IAAI,MAAM,KAAK;AACpC,WAAO;AAAA,EACT;AACF;AAqBO,SAAS,gBACd,QAAqC,OACwB;AAC7D,MAAI,CAAC,OAAQ,QAAO;AACpB,SAAO,OAAO,MAAM;AAClB,UAAM,OAAO,OAAO;AAAA,MAClB,IAAI;AAAA,MAAa,YAAY,EAAE,OAAO;AAAA,MAAY,IAAI,EAAE,OAAO;AAAA,MAAI,SAAS;AAAA,MAAG;AAAA,MAAO,aAAa;AAAA,MACnG,QAAQ,KAAK,UAAU,EAAE,OAAO,6BAA6B,GAAG,EAAE,CAAC;AAAA,IACrE,CAAC;AAAA,EACH;AACF;AAmDA,eAAsB,oBACpB,OACA,KACA,UACA,OACA,mBACe;AACf,QAAM,OAAO,MAAM,eAAe,IAAI,UAAU;AAYhD,MAAI,MAAM;AACR,UAAM,KAAK,MAAM,KAAK,kCAAkC,IAAI,EAAE;AAC9D,UAAM,iBAAiB,GAAG;AAC1B,UAAM,0BAA0B,KAAK,GAAG,GAAG,kBAAkB;AAC7D,UAAM,uBAAuB,KAAK,GAAG,GAAG,eAAe;AAAA,EACzD;AAEA,QAAM,QAAQ,MAAM,MAAM,mBAAmB,IAAI,UAAU;AAC3D,MAAI,MAAM,WAAW,KAAK,CAAC,KAAM;AAiBjC,MAAI,MAAM,KAAK,CAAC,MAAM,EAAE,SAAS,KAAK,GAAG;AACvC,UAAM,EAAE,UAAU,WAAW,QAAQ,IAAI,MAAM,sBAAsB,OAAO,IAAI,YAAY,IAAI,IAAI,iBAAiB;AACrH,UAAM,4BAA4B;AAClC,UAAM,6BAA6B;AACnC,UAAM,wBAAwB,KAAK,GAAG,OAAO;AAAA,EAC/C;AAEA,MAAI,MAAM,KAAK,CAAC,MAAM,EAAE,SAAS,YAAY,GAAG;AAM9C,UAAM,iBAAiB,MAAM,KAAK,iCAAiC,IAAI,IAAI,IAAI;AAAA,EACjF;AAEA,MAAI,YAAY,MAAM,KAAK,CAAC,MAAM,EAAE,SAAS,QAAQ,GAAG;AACtD,UAAM,cAAc,MAAM,KAAK,gBAAgB,UAAU,IAAI,EAAE;AAC/D,QAAI,aAAa;AACf,iBAAW,KAAK,MAAM,KAAK,wBAAwB,IAAI,IAAI,WAAW,GAAG;AACvE,YAAI,EAAE,YAAY,UAAW,OAAM,wBAAwB;AAAA,iBAClD,EAAE,YAAY,iBAAkB,OAAM,cAAc,KAAK,GAAG,EAAE,IAAI,IAAI,EAAE,QAAQ,EAAE;AAAA,MAC7F;AAAA,IACF;AAAA,EACF;AACF;AAeA,eAAe,sBACb,OACA,SACA,KACA,aACqE;AACrE,MAAI,WAAW;AACf,MAAI,YAAY;AAChB,QAAM,UAAoB,CAAC;AAC3B,aAAW,EAAE,aAAa,UAAU,SAAS,KAAK,MAAM,MAAM,mBAAmB,OAAO,GAAG;AACzF,QAAI,aAAa,WAAY;AAC7B,UAAM,aAAa,aAAa,OAAO,MAAM,YAAY,IAAI,QAAQ;AACrE,QAAI,eAAe,QAAW;AAC5B,cAAQ,KAAK,GAAG,OAAO,IAAI,GAAG,IAAI,YAAY,UAAU,IAAI,YAAY,KAAK,EAAE;AAC/E;AAAA,IACF;AACA,UAAM,OAAO,MAAM,eAAe,YAAY,UAAU;AACxD,QAAI,CAAC,KAAM;AACX,UAAM,WAAW,MAAM,KAAK,KAAK,GAAG,OAAO,CAAC,QAAQ,wBAAwB,KAAK,YAAY,OAAO,UAAU,CAAC;AAC/G,eAAW,OAAO,SAAS;AACzB,YAAM,KAAK,IAAI,IAAI;AACnB,UAAI,OAAO,OAAW;AACtB,UAAI,aAAa,WAAW;AAC1B,cAAM,KAAK,OAAO,EAAE;AACpB;AAAA,MACF,WAAW,aAAa,WAAW;AACjC,cAAM,KAAK,IAAI,IAAI,EAAE,GAAG,KAAK,CAAC,YAAY,KAAK,GAAG,KAAK,CAAC;AACxD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,SAAO,EAAE,UAAU,WAAW,QAAQ;AACxC;AAQO,SAAS,oBAAoB,GAAY,GAAqB;AACnE,MAAI,MAAM,EAAG,QAAO;AACpB,MAAI,MAAM,QAAQ,MAAM,QAAQ,OAAO,MAAM,YAAY,OAAO,MAAM,SAAU,QAAO;AACvF,MAAI;AACF,WAAO,KAAK,UAAU,CAAC,MAAM,KAAK,UAAU,CAAC;AAAA,EAC/C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/via/lookup/registry.ts","../src/via/lookup/snapshot.ts","../src/port/with/lookup-strategy.ts","../src/kernel/via/dispatch.ts"],"sourcesContent":["/**\n * Pure dict-registry helpers — extracted from `kernel/vault.ts`'s dict\n * bodies (#650 Task 1 — via-lookup extraction, phase D).\n *\n * These take the vault-resident registry Maps (and a couple of vault-bound\n * callbacks) as ARGUMENTS instead of closing over `this` — no `Vault`\n * import here, so this module stays a plain, testable function library.\n * `kernel/vault.ts` keeps the registry Maps themselves (they're populated\n * by `vault.collection()` and read by the backup path) and calls these\n * helpers through the `port/with/lookup-strategy.ts` seam.\n */\n\nimport { getAtPath } from '../../kernel/paths.js'\nimport { UnknownDictCodeError, ValidationError } from '../../kernel/errors.js'\nimport type { JoinableSource } from '../../kernel/query/index.js'\nimport type { FieldRef, ViaGraph } from '../../kernel/via/graph.js'\nimport type { StaticDictDescriptor } from '../../port/with/i18n-strategy.js'\nimport { dictCollectionName, type LookupHandle } from './handle.js'\nimport type { LookupDescriptor, OnDelete } from './descriptor.js'\n\n/**\n * Validate staticDict codes on a `put()`. For each `staticDict()` field,\n * every stored code must be a declared key of the descriptor's table, else\n * `UnknownDictCodeError`. Opt out per descriptor with `{ validateCodes:\n * false }`. Supports scalar, dotted, and `[].`-wildcard field paths via\n * `getAtPath` (same path support as i18n validation).\n *\n * `staticFields` is the collection's `field → StaticDictDescriptor` map\n * (`Vault#staticDescriptorByField.get(collectionName)`) — `undefined`/empty\n * is a no-op.\n */\nexport function enforceStaticDictOnPut(\n staticFields: Record<string, StaticDictDescriptor> | undefined,\n record: unknown,\n): void {\n if (!staticFields || Object.keys(staticFields).length === 0) return\n if (!record || typeof record !== 'object') return\n\n const obj = record as Record<string, unknown>\n for (const [field, desc] of Object.entries(staticFields)) {\n if (desc.validateCodes === false) continue\n const known = new Set<string>(desc.keys)\n const values = getAtPath(obj, field)\n for (const value of values) {\n if (value === undefined || value === null) continue\n const codes = Array.isArray(value) ? value : [value]\n for (const code of codes) {\n if (typeof code !== 'string') continue\n if (!known.has(code)) {\n throw new UnknownDictCodeError(desc.name, field, code)\n }\n }\n }\n }\n}\n\n/**\n * Build a `JoinableSource` for a dictKey field, for use in dict joins.\n * Returns a source whose snapshot contains `{ key, labels, ...labels }`\n * records — one per dictionary entry — keyed by the stable key.\n *\n * staticDict: a code-table-backed source — snapshot() materialises the\n * in-memory table into rows, mirroring `LookupHandle.snapshotEntries()`.\n * Carries `displayLocale` so a locale-less `{ by: 'label' }` query has a\n * default locale to resolve at.\n *\n * Plain dictKey: the snapshot is built synchronously from the\n * `LookupHandle`'s write-through cache, which is populated on every\n * `put()`, `rename()`, `delete()`, and `list()` call. For pre-existing\n * data not yet touched this session, call `await vault.dictionary(name).list()`\n * first to warm the cache.\n *\n * Returns `null` when `field` is not a dictKey in `leftCollection`.\n */\nexport function resolveDictSource(\n leftCollection: string,\n field: string,\n staticDescriptorByField: ReadonlyMap<string, Record<string, StaticDictDescriptor>>,\n dictKeyFieldRegistry: ReadonlyMap<string, Record<string, string>>,\n getDictionaryHandle: (name: string) => LookupHandle,\n): JoinableSource | null {\n const staticFields = staticDescriptorByField.get(leftCollection)\n if (staticFields && field in staticFields) {\n const desc = staticFields[field]!\n const rows: readonly Record<string, unknown>[] = Object.entries(desc.table).map(\n ([key, labels]) => ({ key, labels, ...(labels as Record<string, string>) }),\n )\n const source: JoinableSource = {\n snapshot(): readonly unknown[] {\n return rows\n },\n lookupById(id: string): unknown {\n return rows.find((e) => e['key'] === id)\n },\n }\n if (desc.displayLocale !== undefined) {\n ;(source as { displayLocale?: string }).displayLocale = desc.displayLocale\n }\n return source\n }\n\n const dictFields = dictKeyFieldRegistry.get(leftCollection)\n if (!dictFields || !(field in dictFields)) return null\n const dictName = dictFields[field]\n if (!dictName) return null\n const handle = getDictionaryHandle(dictName)\n return {\n snapshot(): readonly unknown[] {\n return handle.snapshotEntries()\n },\n lookupById(id: string): unknown {\n const entries = handle.snapshotEntries()\n return entries.find((e) => e['key'] === id)\n },\n }\n}\n\n/** The minimal collection surface `updateReferencingRecords` needs. */\nexport interface DictReferencingCollection {\n list(): Promise<Record<string, unknown>[]>\n put(id: string, record: Record<string, unknown>): Promise<unknown>\n}\n\n/**\n * Find and rewrite records in every registered collection whose\n * dictKeyField points at `name`, replacing `oldKey` with `newKey`. Used by\n * `LookupHandle.rename()` (the only sanctioned mass-mutation path for\n * dictKey fields) via the vault's `findAndUpdateReferences` callback.\n *\n * `registry` is `Vault#dictKeyFieldRegistry` (collection name → field name\n * → dictionary name); `getCollection` is the vault's collection accessor —\n * rewrites go through the public `coll.put()` choke point, same as before.\n */\nexport async function updateReferencingRecords(\n registry: ReadonlyMap<string, Record<string, string>>,\n getCollection: (collectionName: string) => DictReferencingCollection,\n name: string,\n oldKey: string,\n newKey: string,\n): Promise<void> {\n for (const [collectionName, dictFields] of registry) {\n // Find fields that point at this dictionary\n const fields = Object.entries(dictFields)\n .filter(([, dn]) => dn === name)\n .map(([field]) => field)\n if (fields.length === 0) continue\n\n const coll = getCollection(collectionName)\n const records = await coll.list()\n for (const record of records) {\n let changed = false\n const updated = { ...record }\n for (const field of fields) {\n if (updated[field] === oldKey) {\n updated[field] = newKey\n changed = true\n }\n }\n if (changed) {\n const id = record['id'] as string | undefined\n if (id !== undefined) {\n await coll.put(id, updated)\n }\n }\n }\n }\n}\n\n/**\n * Resolve a label from an in-memory `{ locale -> label }` map, walking the\n * same fallback chain semantics as `LookupHandle.resolveLabel` (#650 Task 2\n * — moved here from `kernel/vault.ts` so the SAME chain serves both the\n * i18n binding's `dictLabelResolver` and the lookup binding's\n * `lookupLabelResolver`, which #650 Task 2 wires to the identical closure).\n */\nexport function resolveLabelFromMap(\n labels: Readonly<Record<string, string>>,\n locale: string,\n fallback?: string | readonly string[],\n): string | undefined {\n if (labels[locale] !== undefined) return labels[locale]\n const chain = Array.isArray(fallback)\n ? (fallback as readonly string[])\n : fallback\n ? [fallback as string]\n : []\n for (const fb of chain) {\n if (fb === 'any') {\n const any = Object.values(labels)[0]\n if (any !== undefined) return any\n } else if (labels[fb] !== undefined) {\n return labels[fb]\n }\n }\n return undefined\n}\n\n/**\n * Project a native `lookup(dimension, { backing:'static', table, … })`\n * descriptor into the legacy `StaticDictDescriptor` shape — the\n * alias-equivalence compat seam (#650 Task 2) that lets a native\n * static-tier lookup field reuse the SAME vault registries\n * (`staticByName`/`staticDescriptorByField`) — and therefore the same\n * `dictLabelResolver`/`resolveDictSource` machinery — as its `staticDict()`\n * alias. `vocabulary:'closed'` maps to `validateCodes:true` (closed = only\n * declared codes are legal); `'open'` maps to `validateCodes:false`.\n * Returns `undefined` for non-static or table-less (bare `enumOf`)\n * descriptors — those have nothing to register.\n */\nexport function lookupToStaticDictCompat(desc: LookupDescriptor): StaticDictDescriptor | undefined {\n if (desc.backing !== 'static' || desc.table === undefined) return undefined\n return {\n _noydbStaticDict: true,\n _viaBrand: 'i18n',\n name: desc.dimension,\n table: desc.table,\n keys: desc.keys ?? Object.keys(desc.table),\n ...(desc.displayLocale !== undefined ? { displayLocale: desc.displayLocale } : {}),\n ...(desc.onMissing !== undefined ? { onMissing: desc.onMissing } : {}),\n ...(desc.substitute !== undefined ? { substitute: desc.substitute } : {}),\n validateCodes: desc.vocabulary === 'closed',\n }\n}\n\n/** The vault-registry entries a collection's `lookupFields` contribute — the alias-equivalence bridge (#650 Task 2). */\nexport interface LookupDictCompat {\n /** Reserved-tier fields: field name -> dimension (dictionary) name — merges into `dictKeyFieldRegistry`. */\n readonly dictFieldMap: Record<string, string>\n /** Static-tier (table-bearing) fields, projected — merges into `staticDescriptorByField`/`staticByName`. */\n readonly staticEntries: ReadonlyArray<readonly [string, StaticDictDescriptor]>\n}\n\n/**\n * Bridge a collection's `lookupFields` into the SAME shape the legacy dict\n * registries expect, so `resolveDictSource`/`dictLabelResolver` (and\n * therefore `.join()`/`orderBy({by:'label'})`) serve a native `dict()`/\n * `lookup(static)` field identically to its `dictKey()`/`staticDict()`\n * alias — the reserved-vs-first-class-backing \"matrix\" tier is NOT bridged\n * here (no vault registry backs it; Task 5/6 build its own graph edge /\n * snapshot seam).\n */\nexport function collectLookupDictCompat(\n lookupFields: Record<string, LookupDescriptor> | undefined,\n): LookupDictCompat {\n const dictFieldMap: Record<string, string> = {}\n const staticEntries: Array<readonly [string, StaticDictDescriptor]> = []\n for (const [field, desc] of Object.entries(lookupFields ?? {})) {\n if (desc.backing === 'reserved') {\n dictFieldMap[field] = desc.dimension\n } else {\n const compat = lookupToStaticDictCompat(desc)\n if (compat) staticEntries.push([field, compat])\n }\n }\n return { dictFieldMap, staticEntries }\n}\n\n/**\n * Reserved-dict deps of a set of named collections (#653) — the `_dict_*`\n * collections partial sync must auto-include alongside a `collections`\n * filter, mirroring `SyncEngine`'s existing satellite-pair expansion.\n * One hop is provably complete: `vault.collection()` refuses `_dict_*`\n * names, so a dict can never itself declare lookup fields — no\n * dict-of-dict chain to recurse through.\n */\nexport function reservedDictDepsOf(\n names: readonly string[],\n dictKeyFieldRegistry: ReadonlyMap<string, Record<string, string>>,\n): readonly string[] {\n const out = new Set<string>()\n for (const name of names) {\n const fieldMap = dictKeyFieldRegistry.get(name)\n if (!fieldMap) continue\n for (const dictName of Object.values(fieldMap)) out.add(dictCollectionName(dictName))\n }\n return [...out]\n}\n\n/**\n * A lookup dimension's sync membership/altKey table, materialized from its\n * backing rows (#650 Task 3). `keys` is every canonical key present;\n * `altIndex` maps an altKey candidate VALUE to its owning canonical key.\n */\nexport interface MaterializedBacking {\n /** Canonical key values present in the materialized rows. */\n readonly keys: ReadonlySet<string>\n /** altKey candidate value -> canonical key. */\n readonly altIndex: ReadonlyMap<string, string>\n}\n\n/**\n * Build a lookup dimension's altKey index from its backing rows, enforcing\n * declare/warm-time uniqueness across `key ∪ altKeys` values (#650 Task 3 —\n * the CHE/SWZ drift class: two different rows must never claim the same\n * candidate key). `rows` is keyed by canonical key (`row[descriptor.key]`\n * for the matrix tier; the dimension's own key for static/reserved).\n * An altKey candidate VALUE may be a string or number — both normalize via\n * `coerceLookupKey` (#651 Task 3); non-scalar/absent values are skipped.\n * Pure — no I/O. Throws `ValidationError` on collision.\n */\nexport function materializeBackingTable(\n descriptor: LookupDescriptor,\n rows: ReadonlyMap<string, Record<string, unknown>>,\n): MaterializedBacking {\n const keys = new Set<string>(rows.keys())\n // Every value that has claimed ownership so far (canonical keys seed it) —\n // the union `key ∪ altKeys` uniqueness set the spec requires.\n const owner = new Map<string, string>()\n for (const key of keys) owner.set(key, key)\n\n const altIndex = new Map<string, string>()\n const altFields = descriptor.altKeys ?? []\n for (const [canonicalKey, row] of rows) {\n for (const altField of altFields) {\n const value = coerceLookupKey(row[altField])\n if (value === undefined || value === '') continue\n const existingOwner = owner.get(value)\n if (existingOwner !== undefined && existingOwner !== canonicalKey) {\n throw new ValidationError(\n `lookup \"${descriptor.dimension}\": altKey field \"${altField}\" value \"${value}\" is claimed by ` +\n `both \"${existingOwner}\" and \"${canonicalKey}\" — key/altKey values must be unique across the dimension.`,\n )\n }\n owner.set(value, canonicalKey)\n altIndex.set(value, canonicalKey)\n }\n }\n return { keys, altIndex }\n}\n\n/**\n * Closed-vocabulary membership test for one candidate key (#650 Task 3).\n * Static tier: sync, against the in-config key set (declared `keys`, or the\n * table's own keys when table-bearing). Reserved tier: sync — the declared\n * `keys` union the reserved handle's live write-through snapshot (closes\n * #649 for the native `dict()` spelling: the declared-keys promise the old\n * `dictKey()` doc comment made falsely). Matrix (collection) tier: sync —\n * delegates to `buildLookupAltIndex` so membership is checked against the\n * SAME `row[descriptor.key]` keying the altKey index uses (review fix,\n * Important 1: an earlier PUT-id `.get(key)` scan disagreed with the\n * altIndex whenever `descriptor.key !== 'id'`, wrongly rejecting valid\n * non-id candidates and wrongly accepting an unrelated row's PUT-id).\n */\nexport function checkLookupMembership(\n descriptor: LookupDescriptor,\n key: string,\n getDictionary: (dimension: string) => LookupHandle,\n getCollection: (dimension: string) => { querySourceForJoin(): JoinableSource },\n): boolean {\n if (descriptor.backing === 'static') {\n const known = descriptor.keys ?? (descriptor.table ? Object.keys(descriptor.table) : [])\n return known.includes(key)\n }\n if (descriptor.backing === 'reserved') {\n if ((descriptor.keys ?? []).includes(key)) return true\n return getDictionary(descriptor.dimension).snapshotEntries().some((e) => e['key'] === key)\n }\n return buildLookupAltIndex(descriptor, getDictionary, getCollection).keys.has(key)\n}\n\n/**\n * The ONE guarded key coercion (#651 Task 3, dm12) — string/number values\n * coerce to their canonical `String()` form; everything else (`null`,\n * `undefined`, objects, …) coerces to `undefined`. Every consumer that turns\n * a raw record field into a lookup key routes through this, closing the\n * bare-`String()` `\"undefined\"`/`\"null\"`-key poisoning class (seam map\n * finding 6): a row whose key field is genuinely absent must never mint the\n * literal candidate string `\"undefined\"`.\n */\nexport function coerceLookupKey(raw: unknown): string | undefined {\n return typeof raw === 'string' || typeof raw === 'number' ? String(raw) : undefined\n}\n\n/**\n * Resolve a backing row's canonical key VALUE — `coerceLookupKey(row[descriptor.key])`\n * (#651 Task 3). The matrix tier's `row[descriptor.key]`, never the row's own PUT-id\n * when the two differ (`descriptor.key !== 'id'`).\n */\nexport function resolveBackingRowKey(\n descriptor: LookupDescriptor,\n row: Record<string, unknown>,\n): string | undefined {\n return coerceLookupKey(row[descriptor.key])\n}\n\n/**\n * The referencing-side match predicate — does `rec[field]` (coerced) equal an\n * already-coerced `compareKey` (#651 Task 3)? Shared by every site that scans a\n * referencing collection for rows pointing at a given backing key\n * (`with-shape/links/vault-facade.ts`'s ref-delete propagation, `kernel/via/dispatch.ts`'s\n * forget-fanout twin).\n */\nexport function matchesReferencingValue(\n rec: Record<string, unknown>,\n field: string,\n compareKey: string,\n): boolean {\n return coerceLookupKey(rec[field]) === compareKey\n}\n\n/**\n * Materialize a lookup dimension's altKey index from whatever backing data\n * is synchronously available (#650 Task 3 — the `ingest` source). Static:\n * the in-config table. Reserved: the reserved handle's live write-through\n * cache (the same warm-via-put()/list() cache `resolveDictSource` already\n * relies on). Matrix (collection): the backing collection's own in-memory\n * eager cache via `querySourceForJoin()` — already public, already the\n * mechanism `.join()` uses (`with-shape/links/vault-facade.ts`'s\n * `resolveSource`); no new I/O, no fire-and-forget warm step. Like that\n * existing join precedent, a dimension collection this vault session has\n * not yet opened/populated sees an empty snapshot (no altKey normalization\n * until it has rows) — open/populate it first for normalization to apply.\n * A matrix row whose `descriptor.key` field coerces to `undefined` (missing/\n * non-scalar) is SKIPPED — never enters the index under a poisoned\n * `\"undefined\"` key (#651 Task 3, dm12).\n */\nexport function buildLookupAltIndex(\n descriptor: LookupDescriptor,\n getDictionary: (dimension: string) => LookupHandle,\n getCollection: (dimension: string) => { querySourceForJoin(): JoinableSource },\n): MaterializedBacking {\n if (descriptor.backing === 'static') {\n return materializeBackingTable(descriptor, new Map(Object.entries(descriptor.table ?? {})))\n }\n if (descriptor.backing === 'reserved') {\n const entries = getDictionary(descriptor.dimension).snapshotEntries()\n return materializeBackingTable(descriptor, new Map(entries.map((e) => [String(e['key']), e])))\n }\n const rows = getCollection(descriptor.dimension).querySourceForJoin().snapshot()\n const keyed = new Map<string, Record<string, unknown>>()\n for (const r of rows) {\n const row = r as Record<string, unknown>\n const key = resolveBackingRowKey(descriptor, row)\n if (key !== undefined) keyed.set(key, row)\n }\n return materializeBackingTable(descriptor, keyed)\n}\n\n/** One cross-collection `'ref'` graph edge a lookup field declares (#650 Task 5). Module-private —\n * only `registerLookupRefEdges` below (the exported entry point) consumes it. */\ninterface LookupRefEdge {\n readonly referencing: FieldRef\n readonly sources: readonly FieldRef[]\n readonly onDelete: OnDelete\n /** The backing dimension's canonical-key FIELD NAME on its own row (`desc.key` — matrix tier\n * only varies this; reserved/static tiers are always `'id'`). A referencing field always\n * stores THIS field's value, never the backing row's PUT-id when the two differ. */\n readonly keyField: string\n}\n\n/**\n * Compute the cross-collection `'ref'` edges a collection's `lookupFields` declare (#650 Task 5,\n * spec §4) — one edge per non-static-backing field: target = the referencing field; sources =\n * the backing dimension's whole-collection node (`field:'*'`, the wildcard key\n * `ViaGraph.referencingEdgesOf` does its O(1) reverse lookup against) PLUS, when the descriptor\n * names a presentation field (`present.label`), that SPECIFIC field too. `foldPosture`'s\n * `DEFAULT_POSTURE` is the fold's identity element, so adding the wildcard alongside a real field\n * source changes nothing when that field is plain — but folds in a classified/money posture when\n * it isn't (taint composition, spec §4: \"a lookup edge whose source names a classified field\n * contributes that field's posture\"). Static tier (`backing:'static'`) has no backing collection/\n * dimension rows to reference-check — excluded. Pure; consumed only by `registerLookupRefEdges` below.\n */\nfunction collectLookupRefEdges(\n collectionName: string,\n lookupFields: Record<string, LookupDescriptor> | undefined,\n): readonly LookupRefEdge[] {\n const edges: LookupRefEdge[] = []\n for (const [field, desc] of Object.entries(lookupFields ?? {})) {\n if (desc.backing === 'static') continue\n const backing = desc.backing === 'reserved' ? dictCollectionName(desc.dimension) : desc.dimension\n edges.push({\n referencing: { collection: collectionName, field },\n sources: [\n { collection: backing, field: '*' },\n ...(desc.present?.label !== undefined ? [{ collection: backing, field: desc.present.label }] : []),\n ],\n onDelete: desc.onDelete,\n keyField: desc.key,\n })\n }\n return edges\n}\n\n/** Thin wrapper — `collectLookupRefEdges` + one `graph.registerDerived` call per edge. Lets\n * `vault.collection()` (kernel-surface-budgeted, #650 Task 5) register a collection's lookup-ref\n * edges with a single line, keeping the ceiling-guarded call site a thin call (route logic here). */\nexport function registerLookupRefEdges(\n graph: ViaGraph,\n collectionName: string,\n lookupFields: Record<string, LookupDescriptor> | undefined,\n): void {\n for (const e of collectLookupRefEdges(collectionName, lookupFields)) {\n graph.registerDerived(e.referencing, e.sources, 'ref', 'record', e.onDelete, e.keyField)\n }\n}\n\n/**\n * `LookupViaConfig.snapshotFor`'s vault-built row source (#650 Task 6, spec\n * §5; matrix-tier coverage added #650 Task 7, spec §6 — Task 6 deferred it,\n * see `task-6-report.md`'s Concerns #1; the reviewer's Task-7 dispatch\n * refuted the \"needs a new vault-resident registry\" premise: the descriptor\n * is already in hand at both call sites, so `snapshotFor` just needs to\n * ACCEPT it). Takes the full `descriptor` (not a bare dimension name) so it\n * can route the matrix tier's `key` field, which — unlike reserved tier's\n * hardcoded `'id'` — varies per collection. Routes on `descriptor.backing`:\n *\n * - **reserved**: rows come straight from the SAME `LookupHandle.\n * snapshotEntries()` write-through cache `dictLabelResolver`/\n * `resolveDictSource` already read (no second copy), keyed by each\n * entry's own canonical `key` (always `'id'` by construction for this\n * tier — `dict()`'s factory hardcodes it).\n * - **collection** (matrix): rows come from `getCollection(dimension).\n * querySourceForJoin().snapshot()` — the SAME sync, already-live cache\n * `buildLookupAltIndex`'s matrix branch (above, this file) and `.join()`\n * itself already read — re-keyed via `resolveBackingRowKey(descriptor, row)`,\n * NOT the row's own PUT-id (which may differ when `key !== 'id'`; the exact\n * distinction the #650 Task 3 review fix already applies to\n * `checkLookupMembership`'s matrix branch). A row whose `descriptor.key`\n * field coerces to `undefined` is skipped (#651 Task 3, dm12).\n * - **static**: never routed here — `descriptor.table` is read directly by\n * the caller (`binding.ts`'s `compareLookupOrder`/`resolveLookupOrderLabel`,\n * `snapshot.ts`'s `presentLookupForJoin`); no vault call needed.\n *\n * `isReservedDimension` is the vault's `reservedLookupCollections`\n * membership test.\n */\nexport function buildLookupSnapshotRows(\n descriptor: LookupDescriptor,\n isReservedDimension: (dimension: string) => boolean,\n getDictionary: (dimension: string) => LookupHandle,\n getCollection: (dimension: string) => { querySourceForJoin(): JoinableSource },\n): ReadonlyMap<string, Record<string, unknown>> | undefined {\n const dimension = descriptor.dimension\n if (isReservedDimension(dimension)) {\n const rows = new Map<string, Record<string, unknown>>()\n for (const entry of getDictionary(dimension).snapshotEntries()) {\n const key = entry['key']\n if (typeof key === 'string') rows.set(key, entry)\n }\n return rows\n }\n if (descriptor.backing === 'collection') {\n const rawRows = getCollection(dimension).querySourceForJoin().snapshot()\n const rows = new Map<string, Record<string, unknown>>()\n for (const r of rawRows) {\n const row = r as Record<string, unknown>\n const key = resolveBackingRowKey(descriptor, row)\n if (key !== undefined) rows.set(key, row)\n }\n return rows\n }\n return undefined\n}\n","/**\n * The sync lookup snapshot + join/locale seam (#650 Task 6, spec §5 — \"the\n * snapshot+locale seam\"). Retires the #626 kernel→via grandfather:\n * `kernel/query/join.ts` no longer imports `via/i18n/core.js` directly\n * — it calls the `presentForJoin` hook this file's `buildPresentForJoin`\n * builds instead (seam map Part 2 item 4, the #626 reviewer-spec'd shape:\n * a sync `presentI18nForJoin`-class hook on `JoinableSource`).\n *\n * `LookupSnapshot` is the sync materialized `key -> row` view over ONE\n * lookup dimension's ALREADY-LIVE backing data (the `active.ts`\n * `_syncCache`/`snapshotEntries` write-through-cache pattern — never a\n * second copy of the data: `LookupViaConfig.snapshotFor`'s vault-built\n * closure reads the SAME `LookupHandle._syncCache` /\n * first-class-collection cache every other lookup consumer\n * (`dictLabelResolver`, `resolveDictSource`, `getAltIndex`) already reads).\n * Serves (reserved AND matrix tier since #650 Task 7 — `registry.ts`'s\n * `buildLookupSnapshotRows` routes both; static tier is read straight off\n * `descriptor.table` by every consumer below, never through this cache):\n * - join dressing (`presentForJoin`, consumed by `kernel/query/join.ts`\n * via `JoinableSource.presentForJoin`)\n * - dimension sort (`compareForOrder`, consumed by\n * `via/lookup/binding.ts`'s `ViaBinding.compareForOrder` closure)\n * - per-call-locale order-label resolution (`resolveOrderLabel`, #650\n * Task 7 — the `orderBy(..., {by:'label'})` channel `compareForOrder`\n * structurally can't serve, no locale param; consumed by\n * `kernel/query/builder.ts`'s `buildOrderLabelMaps`)\n * - membership: reserved/static-tier membership (#650 Task 3,\n * `checkLookupMembership`) already reads the identical sync caches\n * directly — not re-plumbed through this file; see\n * `.superpowers/sdd/task-6-report.md`'s \"bridge disposition\" section.\n *\n * Sync end-to-end (#553) — every function here is a pure, synchronous\n * transform over already-materialized rows; no store read, no Promise.\n */\nimport type { LookupDescriptor } from './descriptor.js'\nimport { presentI18nForJoin, type I18nTextDescriptor } from '../i18n/core.js'\n\n/** A lookup dimension's sync materialized view — see file header. */\nexport interface LookupSnapshot {\n /** The full backing row for `key`, or `undefined` when `key` isn't (yet) present in the snapshot. */\n row(key: string): Record<string, unknown> | undefined\n /** The dimension's declared presentation label for `key` at `locale` — mirrors `binding.ts`'s `fetchLookupLabel` (matrix-row branch), generalized to any tier's already-materialized rows. */\n label(key: string, locale: string, fallback?: unknown): string | undefined\n /**\n * Exact ordering for two canonical keys against `descriptor.sortBy`\n * (falls back to `present.label`, then to the raw keys) at `locale`.\n * Never throws — degrades to comparing the raw keys when no sortable\n * value resolves for either side.\n */\n compareKeys(a: string, b: string, locale: string): number\n}\n\n/** Read one row field, resolving a `by`-keyed (locale-map) value when `by` is declared. */\nfunction readRowField(\n row: Record<string, unknown> | undefined,\n field: string | undefined,\n by: string | undefined,\n locale: string,\n fallback?: unknown,\n): string | undefined {\n if (!row || field === undefined) return undefined\n const raw = row[field]\n if (by === undefined) return typeof raw === 'string' ? raw : undefined\n if (!raw || typeof raw !== 'object') return undefined\n const map = raw as Record<string, unknown>\n const val = map[locale]\n if (typeof val === 'string') return val\n if (typeof fallback === 'string' && typeof map[fallback] === 'string') return map[fallback]\n return undefined\n}\n\n/**\n * Build a sync `LookupSnapshot` over one dimension's already-materialized\n * rows (canonical-key -> row, the SAME keying `materializeBackingTable`\n * (`registry.ts`, #650 Task 3) uses). Pure — never reads a store.\n */\nexport function buildLookupSnapshot(\n dimension: string,\n rows: ReadonlyMap<string, Record<string, unknown>>,\n descriptor: LookupDescriptor,\n): LookupSnapshot {\n void dimension // identity only — kept for parity with materializeBackingTable/buildLookupAltIndex's signature and future diagnostics\n return {\n row: (key) => rows.get(key),\n label: (key, locale, fallback) =>\n readRowField(rows.get(key), descriptor.present?.label, descriptor.present?.by, locale, fallback),\n compareKeys: (a, b, locale) => {\n const sortField = descriptor.sortBy ?? descriptor.present?.label\n const av = readRowField(rows.get(a), sortField, descriptor.present?.by, locale) ?? a\n const bv = readRowField(rows.get(b), sortField, descriptor.present?.by, locale) ?? b\n return av < bv ? -1 : av > bv ? 1 : 0\n },\n }\n}\n\n/**\n * The lookup-label HALF of `presentForJoin` (#626 retirement, spec §5;\n * matrix-tier coverage added #650 Task 7) — resolves `<field>Label` for\n * every declared lookup field with a `present` dressing dimension, sync,\n * from `getSnapshotRows` (the vault-built `LookupViaConfig.snapshotFor`\n * closure — now descriptor-routed, see `registry.ts`'s\n * `buildLookupSnapshotRows`; static tier reads its own in-config `table`\n * directly, no vault call — never `undefined` for a declared static table).\n * Mirrors `binding.ts`'s `runLookupPresent` (the async `present()` hook)\n * minus the array/`[].`-wildcard handling that hook needs for full-record\n * reads — join dressing only ever sees the joined RIGHT-side record's\n * scalar fields, so that complexity doesn't apply here.\n */\nfunction presentLookupForJoin(\n record: Record<string, unknown>,\n locale: string,\n lookupFields: Record<string, LookupDescriptor>,\n getSnapshotRows: (descriptor: LookupDescriptor) => ReadonlyMap<string, Record<string, unknown>> | undefined,\n): Record<string, unknown> {\n let result = record\n for (const [field, desc] of Object.entries(lookupFields)) {\n if (desc.present === undefined) continue\n const raw = record[field]\n if (typeof raw !== 'string') continue\n const rows = desc.backing === 'static'\n ? (desc.table ? new Map(Object.entries(desc.table)) : undefined)\n : getSnapshotRows(desc)\n if (!rows) continue\n const label = buildLookupSnapshot(desc.dimension, rows, desc).label(raw, locale)\n if (label === undefined) continue\n if (result === record) result = { ...record }\n result[`${field}Label`] = label\n }\n return result\n}\n\n/**\n * Build the combined sync `presentForJoin(record, locale)` hook a\n * `Collection` attaches to the `JoinableSource` it exposes\n * (`querySourceForJoin()`) — the i18n-text half (`presentI18nForJoin`, the\n * exact `applyI18nLocale(..., 'join')` partial application\n * `kernel/query/join.ts` used to call directly, #626) composed with the\n * lookup-label half above. `undefined` when the collection declares\n * neither — `JoinableSource.presentForJoin` then stays unset, matching\n * today's `i18nFields`-absent behavior exactly (#626 parity lock).\n */\nexport function buildPresentForJoin(\n i18nFields: Record<string, I18nTextDescriptor> | undefined,\n lookupFields: Record<string, LookupDescriptor> | undefined,\n getSnapshotRows: ((descriptor: LookupDescriptor) => ReadonlyMap<string, Record<string, unknown>> | undefined) | undefined,\n): ((record: unknown, locale: string) => unknown) | undefined {\n const hasI18n = i18nFields !== undefined && Object.keys(i18nFields).length > 0\n const hasLookup = lookupFields !== undefined && Object.keys(lookupFields).length > 0\n if (!hasI18n && !hasLookup) return undefined\n const resolveRows = getSnapshotRows ?? (() => undefined)\n return (record, locale) => {\n if (record === null || typeof record !== 'object') return record\n let result = record as Record<string, unknown>\n if (hasI18n) result = presentI18nForJoin(result, i18nFields, locale)\n if (hasLookup) result = presentLookupForJoin(result, locale, lookupFields, resolveRows)\n return result\n }\n}\n","/**\n * Lookup strategy seam (#650 Task 1 — via-lookup extraction, phase D of the\n * Via port; precedent: `port/with/i18n-strategy.ts`). Lives on the `/with`\n * port (the one seam the kernel spine may import statically) so `Vault` can\n * reach the dict-registry pure helpers and the `LookupHandle`/`NO_LOOKUP`\n * types without a spine→`via/` static import (Check 14 via-layering bans\n * that; `port/with/` is always allowed, Check 9's sanctioned exception).\n *\n * `kernel/vault.ts` imports ONLY this module for lookup — never\n * `via/lookup/*` directly.\n *\n * This task (#650 Task 1) is a pure move: `Vault.dictionary()` still\n * constructs its handle through `i18nStrategy.buildDictionaryHandle`\n * (`port/with/i18n-strategy.ts`), which now internally delegates to\n * `withLookup().buildLookupHandle` (same handle, new home). `LookupStrategy`\n * / `NO_LOOKUP` / `isLookupCollectionName` here are the seam later phase-D\n * tasks bind `vault.collection()`'s lookup fields onto — unused by Task 1's\n * wiring, but their exact shapes are frozen now so later tasks don't\n * re-litigate them.\n */\n\nimport type { NoydbStore, EncryptedEnvelope } from '../../kernel/types.js'\nimport type { LedgerStore } from '../../with-commit/history/ledger/store.js'\nimport type { UnlockedKeyring } from '../../with-party/team/keyring.js'\nimport type { NoydbEventEmitter } from '../../kernel/events.js'\nimport type { ViaCryptoCtx } from '../../kernel/via/index.js'\nimport type { LookupHandle, DictionaryOptions } from '../../via/lookup/handle.js'\nimport {\n enforceStaticDictOnPut,\n resolveDictSource,\n updateReferencingRecords,\n resolveLabelFromMap,\n collectLookupDictCompat,\n lookupToStaticDictCompat,\n reservedDictDepsOf,\n materializeBackingTable,\n checkLookupMembership,\n buildLookupAltIndex,\n registerLookupRefEdges,\n buildLookupSnapshotRows,\n coerceLookupKey,\n resolveBackingRowKey,\n matchesReferencingValue,\n type DictReferencingCollection,\n type LookupDictCompat,\n type MaterializedBacking,\n} from '../../via/lookup/registry.js'\nimport { buildPresentForJoin } from '../../via/lookup/snapshot.js'\nimport type { LookupDescriptor } from '../../via/lookup/descriptor.js'\n\n/**\n * Backing options for `LookupStrategy.buildLookupHandle` — same shape as\n * `DictionaryOptions` (kept as a distinct alias since the \"lookup\" name is\n * the forward-looking one; `DictionaryOptions` stays the dict-tier name).\n */\nexport type LookupBackingOptions = DictionaryOptions\n\n/**\n * Options accepted by `LookupStrategy.buildLookupHandle`. Mirrors the\n * `LookupHandle` constructor verbatim, plus the two choke-point\n * participation hooks (`onDirty`/`onRecordMutated`) #647 (Task 4) wires —\n * both `undefined` in this task (pure move, no new call sites).\n */\nexport interface BuildLookupHandleOptions<Keys extends string = string> {\n readonly adapter: NoydbStore\n readonly compartmentName: string\n readonly dimensionName: string\n readonly keyring: UnlockedKeyring\n /**\n * The `reservedEnvelopes('_dict_')` capability (#629 Task 4) — the\n * handle's sanctioned crypto door onto its `_dict_<name>` collection.\n * Bound by the Vault to its own `getDEK`, the same per-collection-name\n * DEK resolver every other collection uses.\n */\n readonly reservedEnvelopes: ReturnType<ViaCryptoCtx['reservedEnvelopes']>\n readonly encrypted: boolean\n readonly ledger: LedgerStore | undefined\n readonly options: LookupBackingOptions\n readonly findAndUpdateReferences:\n | ((dimension: string, oldKey: string, newKey: string) => Promise<void>)\n | undefined\n readonly emitter: NoydbEventEmitter\n /**\n * #647 fix wave 1 — mints a version-ordered delete-marker envelope. Bound by the Vault to the\n * real `kernel/enclave` `buildDeleteMarker` function — `LookupHandle` (`via/lookup/**`)\n * may not import `kernel/enclave/` itself (Check 11/15), so this capability is injected the\n * same way `reservedEnvelopes` above is.\n */\n readonly buildDeleteMarker: (version: number, actor: string) => EncryptedEnvelope\n /** #650 Task 4 (#647) — choke-point participation hooks. */\n readonly onDirty?: ((collection: string, id: string, action: 'put' | 'delete', version: number) => Promise<void>) | undefined\n readonly onRecordMutated?: ((collection: string, id: string, action: 'put' | 'delete', version: number) => Promise<void>) | undefined\n /**\n * #650 Task 5 (#648) — the real reference check `LookupHandle.delete()`'s strict branch calls:\n * restrict throws `DictKeyInUseError` naming the referencing collection, cascade/nullify apply\n * their propagation. Bound by the Vault (never a `Collection`/keyring/DEK reach-around); a\n * no-op when the dimension has no declared lookup-referencing edges (today's dangling behavior\n * for undeclared refs is unaffected). Return value is discarded by the handle — callers who\n * need cascade/nullify counts (forget) go through `VaultLinks` directly.\n */\n readonly checkReferencesOnDelete?: ((key: string) => Promise<unknown>) | undefined\n /**\n * Used by the active strategy to satisfy the generic-key parameter on the\n * returned handle. The NO_LOOKUP stub never reads it. Mirrors\n * `BuildDictionaryHandleOptions._keyMarker` (`port/with/i18n-strategy.ts`).\n */\n // marker generic — runtime sees no value\n _keyMarker?: Keys\n}\n\nexport interface LookupStrategy {\n /**\n * Construct a typed `LookupHandle` for the named dimension. Throws under\n * `NO_LOOKUP`.\n */\n buildLookupHandle<Keys extends string = string>(\n opts: BuildLookupHandleOptions<Keys>,\n ): LookupHandle<Keys>\n}\n\nfunction notEnabled(op: string): Error {\n return new Error(\n `${op}: the NO_LOOKUP stub was reached, which should be unreachable today — there is no ` +\n '`lookupStrategy` `createNoydb({ ... })` option yet to select this stub over the real one; ' +\n '`vault.dictionary()` always resolves through `withLookup()` (see `via/i18n/active.ts`\\'s ' +\n 'delegation). This is forward scaffolding for a later task (mirrors `NO_I18N`\\'s shape) — if you ' +\n 'hit this, it indicates a bug, not a missing opt-in.',\n )\n}\n\n/**\n * No-lookup stub. Mirrors `NO_I18N.buildDictionaryHandle`'s shape, but unlike `NO_I18N` (wired as\n * `vault.ts`'s `opts.i18nStrategy ?? NO_I18N` default), nothing selects this stub today — there is\n * no `lookupStrategy` option on `createNoydb()`; `vault.dictionary()`'s only construction path\n * (`Vault.i18nStrategy.buildDictionaryHandle` → `withLookup().buildLookupHandle`) never reaches\n * here. Kept as forward scaffolding for a later task that wires an independent lookup opt-in.\n */\nexport const NO_LOOKUP: LookupStrategy = {\n buildLookupHandle() {\n throw notEnabled('vault.dictionary()')\n },\n}\n\n/** `_dict_*` (legacy dict tier) and `_lookup_*` (the phase-D reserved backing). */\nexport const LOOKUP_COLLECTION_PREFIXES = ['_dict_', '_lookup_'] as const\n\n/** Return true when a collection name is a reserved lookup-backing collection. */\nexport function isLookupCollectionName(name: string): boolean {\n return LOOKUP_COLLECTION_PREFIXES.some((prefix) => name.startsWith(prefix))\n}\n\n// Re-exported pure registry helpers (#650 Task 1) — `kernel/vault.ts`'s\n// thin delegators call these directly; small always-on functions, not\n// behind the tree-shake seam (same bundling class as `isLookupCollectionName`\n// above, just too large to duplicate inline like that one is).\nexport { enforceStaticDictOnPut, resolveDictSource, updateReferencingRecords }\nexport type { DictReferencingCollection }\n\n// #650 Task 4 (#647) — the reserved-collection naming helper `vault.ts`'s sync-registry\n// bookkeeping needs (mapping a declared dimension name to its `_dict_<name>` collection name).\nexport { dictCollectionName } from '../../via/lookup/handle.js'\n\n// #650 Task 2 — the alias-equivalence bridge (`resolveLabelFromMap` +\n// `collectLookupDictCompat`/`lookupToStaticDictCompat`) + the runtime\n// brand/shape predicates `via/compose.ts` needs to route `'lookup'`-branded\n// descriptors, mirroring `isI18nTextDescriptor`/`isDictKeyDescriptor` below.\nexport { resolveLabelFromMap, collectLookupDictCompat, lookupToStaticDictCompat }\nexport type { LookupDictCompat }\n\n// #653 — partial-sync reserved-dict expansion: maps a set of named collections to the\n// one-hop `_dict_*` deps their lookup fields reference, off `dictKeyFieldRegistry`.\nexport { reservedDictDepsOf }\n\n// #650 Task 3 — altKeys ingest normalization + open/closed vocabulary\n// governance: the declare/warm-time altIndex builder + the membership test\n// vault.ts's `membership`/`getAltIndex` closures delegate to.\nexport { materializeBackingTable, checkLookupMembership, buildLookupAltIndex }\nexport type { MaterializedBacking }\n\n// #650 Task 5 — registers a collection's lookup-fields' cross-collection 'ref' graph edges.\nexport { registerLookupRefEdges }\n\n// #650 Task 6 — the sync snapshot+locale seam (#626 retirement, spec §5):\n// `snapshotFor`'s vault-built row source + the combined presentForJoin\n// builder `kernel/collection-config.ts` calls to build the\n// `JoinableSource.presentForJoin` hook `kernel/query/join.ts` consumes.\nexport { buildLookupSnapshotRows, buildPresentForJoin }\nexport type { LookupSnapshot } from '../../via/lookup/snapshot.js'\n\n// #651 Task 3 — the ONE descriptor-keyed key-resolution core (guarded coercion +\n// backing-row-key resolve + referencing-value match) — every consumer (vault.ts,\n// with-shape/links/vault-facade.ts, kernel/via/dispatch.ts) routes through here,\n// never a bare `String()`, ending the dm12 dialect drift.\nexport { coerceLookupKey, resolveBackingRowKey, matchesReferencingValue }\n\n/** Runtime predicate for detecting a `LookupDescriptor` (any of the three tiers). */\nexport function isLookupDescriptor(x: unknown): x is LookupDescriptor {\n return (\n typeof x === 'object' &&\n x !== null &&\n (x as { _viaBrand?: unknown })._viaBrand === 'lookup'\n )\n}\n\n/** Runtime predicate for the bare enum tier (`backing:'static'`, no in-code `table` — no label source). */\nexport function isEnumDescriptor(x: unknown): x is LookupDescriptor {\n return isLookupDescriptor(x) && x.backing === 'static' && x.table === undefined\n}\n\n/**\n * Type-only re-exports — the kernel spine imports these descriptor/handle\n * types through the port instead of reaching into `via/lookup/*` or\n * `via/i18n/*` directly. `isolatedModules: true` erases these at\n * build time — no runtime coupling.\n */\nexport type { LookupHandle, DictEntry, DictionaryOptions } from '../../via/lookup/handle.js'\nexport type { LookupDescriptor, Vocabulary, LookupBacking, OnDelete } from '../../via/lookup/descriptor.js'\nexport type { LookupViaConfig } from '../../via/lookup/binding.js'\nexport type { DictKeyDescriptor, StaticDictDescriptor } from '../../via/i18n/dictionary.js'\n","// kernel/via/dispatch.ts — the batched, origin-aware sync/cutover/restore dispatch wave\n// (Via port phase C, #638 Task 4, fixes #621).\n//\n// `Collection._onRecordMutated`'s `sync-apply`/`cutover`/`restore` cases feed touched\n// (collection, id) pairs into a per-session `GraphBatch` (owned by `Vault._collectGraphTouch`)\n// instead of dispatching inline — the `local-write` path keeps its own byte-identical inline\n// dispatch (`wave` stays `undefined` there, per the spec's behavior lock). At batch-flush time\n// `runGraphDispatchWave` decrypts each touched record (id threaded into the decrypt, matching\n// the phase-B at-rest contract) and re-runs the SAME `dispatchDerivations`/\n// `dispatchMaterializedViews` the local-write path uses, sharing one `WaveContext` so N touched\n// records feeding the SAME rollup/MV target recompute exactly once (per-target dedup).\n// See design-history/2026-07-11-via-phase-c-design.md §3.\n\nimport type { ViaGraph } from './graph.js'\nimport type { Collection } from '../collection.js'\nimport type { EncryptedEnvelope } from '../types.js'\nimport { PeriodClosedError } from '../errors.js'\nimport { matchesReferencingValue } from '../../port/with/lookup-strategy.js'\n\n/** One deleted child's resolved rollup PARENT intent (#640) — ids + a field name only. A\n * resolved `parentId` is an id, same class as any touched record id — never a stored value. */\nexport interface RollupDeleteIntent {\n readonly into: string\n readonly parentId: string\n readonly field: string\n}\n\n/** One collection's batched touches this session (#640 widens the #638 `Set<string>` shape):\n * `puts` — the original semantics, unchanged; `deletes` — a deleted record's id mapped to its\n * resolved rollup-parent intents, captured PRE-invalidation by `Collection._onRecordMutated`'s\n * sync-apply delete case (the FK is only readable there — see `kernel/collection.ts\n * #_rollupDeleteIntents`). */\nexport interface GraphTouch {\n readonly puts: Set<string>\n readonly deletes: Map<string, readonly RollupDeleteIntent[]>\n}\n\n/** Per-session touched set — collection → its `GraphTouch`. Metadata only — ids (collection\n * names, record ids INCLUDING resolved rollup parent ids) and field names; NEVER record payload\n * or key material. A resolved parentId is an id, same class as the touched ids — not a stored\n * value. */\nexport type GraphBatch = Map<string, GraphTouch>\n\n/** Get-or-create `batch`'s `GraphTouch` entry for `collection` (#640) — shared by\n * `Vault._collectGraphTouch`/`_collectGraphDelete` so each stays a one-line call. */\nexport function touchFor(batch: GraphBatch, collection: string): GraphTouch {\n let t = batch.get(collection)\n if (!t) {\n t = { puts: new Set(), deletes: new Map() }\n batch.set(collection, t)\n }\n return t\n}\n\n/** #640 — sync, I/O-free: `deleted`'s resolved rollup PARENT intents (the FK is only readable\n * NOW, before the record is gone) — a pure function so `Collection._rollupDeleteIntents` stays\n * a one-line delegator under the kernel-surface ceiling. `registry` is `this.derivationSource\n * ?.registry()`; `collectionName` is `this.name` (the CHILD/`rollup.from` side). Generic over\n * the registry's own spec shape so this file never imports a `with-formula` type (port-layering\n * — via/dispatch.ts must not gain a with-* import). */\nexport function resolveRollupDeleteIntents<S extends { source: string; rollup?: { from: string; key: string; field: string } }>(\n registry: { strategiesForSource(name: string): ReadonlyArray<{ spec: S }> } | undefined,\n collectionName: string,\n deleted: Record<string, unknown>,\n): RollupDeleteIntent[] {\n if (!registry) return []\n const intents: RollupDeleteIntent[] = []\n for (const { spec } of registry.strategiesForSource(collectionName)) {\n if (!spec.rollup || spec.rollup.from !== collectionName) continue\n const kv = deleted[spec.rollup.key]\n if (typeof kv === 'string' || typeof kv === 'number') intents.push({ into: spec.source, parentId: String(kv), field: spec.rollup.field })\n }\n return intents\n}\n\n/** #640 — resolve a `RollupDeleteIntent` back to its registry `spec`. The wave's per-intent\n * driver needs `spec.rollup.compute`, which `GraphBatch`'s metadata-only pin forbids batching —\n * so it's re-resolved here, post-boundary, instead of carried across it. `undefined` if the\n * intent's originating strategy was unregistered between collect time and wave time (residual\n * gap, freshness-only). */\nexport function findRollupSpecForIntent<S extends { source: string; rollup?: { from: string; field: string } }>(\n registry: { strategiesForSource(name: string): ReadonlyArray<{ spec: S }> } | undefined,\n collectionName: string,\n intent: RollupDeleteIntent,\n): S | undefined {\n return registry?.strategiesForSource(collectionName).find((s) => s.spec.source === intent.into && s.spec.rollup?.field === intent.field && s.spec.rollup?.from === collectionName)?.spec\n}\n\n/** One dedup ledger for a single wave — a target is recomputed at most once (mark-on-check). */\nexport class WaveContext {\n private readonly _seen = new Set<string>()\n seen(targetKey: string): boolean {\n if (this._seen.has(targetKey)) return true\n this._seen.add(targetKey)\n return false\n }\n}\n\n/** The slice of `Vault` the wave needs: the shared graph (the #553 zero-cost skip) and cached-\n * collection lookup — never constructs, since a touched collection is, by construction,\n * already open (it just fired `_onRecordMutated`). */\nexport interface VaultLike {\n readonly graph: ViaGraph\n _getCollection(name: string): Collection<Record<string, unknown>> | undefined\n /** #640 (#644 item 3) — structured wave-error surfacing, additive to the existing console.warn. */\n _emit(event: string, payload: unknown): void\n}\n\n/**\n * Run ONE dispatch wave for a completed batch: for each touched (collection, id), decrypt the\n * applied envelope (id threaded), then run the SAME `dispatchDerivations` +\n * `dispatchMaterializedViews` the local-write path uses — with a shared `WaveContext` so N\n * touched records feeding the SAME target recompute once. #553: a collection with no graph\n * out-edges (e.g. money-only) is skipped before any decrypt/dispatch async work.\n */\nexport async function runGraphDispatchWave(vault: VaultLike, batch: GraphBatch): Promise<void> {\n const wave = new WaveContext()\n for (const [collectionName, touch] of batch) {\n if (vault.graph.dependentsOf(collectionName).length === 0) continue\n const coll = vault._getCollection(collectionName)\n if (!coll) continue\n for (const id of touch.puts) {\n try {\n // Decrypt is INSIDE the per-id isolation boundary (whole-branch review Important\n // finding, #638): an undecryptable synced envelope (`TamperedError`) must not\n // escape `_getStoredRecordForDispatch` and abort the wave — that would propagate\n // through `_flushGraphBatch` and reject the surrounding `SyncEngine.pull`/`push`\n // AFTER records were already applied + meta persisted, starving every other\n // touched target in the same batch.\n const stored = await coll._getStoredRecordForDispatch(id)\n if (!stored) continue\n await coll.dispatchDerivations(id, stored.record, stored.version, wave)\n await coll.dispatchMaterializedViews(id, stored.record, wave)\n } catch (err) {\n // #638 Task 5 review mandate: one touched record's recompute must not abort the\n // whole wave (starving co-batched healthy targets) or the pull/push it's nested\n // inside. `PeriodClosedError` never reaches here — `putDerivedOutput` already\n // intercepts it at every output-write call site and turns it into a skip+event.\n // Anything else (a genuine decrypt failure, a derive()/executor bug, a schema\n // violation on the output, ...) is surfaced — not silently swallowed — via the\n // SAME console.warn channel `dispatchDerivations`/the MV executor already use for\n // their own non-strict-mode output failures, then isolated to just this one id.\n // #644 item 3: ADDITIVELY (never in place of the warn) emit a structured event too,\n // so a listener doesn't have to scrape console output to react to a wave failure.\n console.warn(`[via-dispatch] wave recompute failed for ${collectionName}/${id}:`, err)\n vault._emit('derivation:wave-error', { collection: collectionName, id, error: err })\n }\n }\n // #640 — delete-kind touches: the deleted child's rollup-parent intents, resolved (sync,\n // pre-invalidation) at collect time by `Collection._rollupDeleteIntents`. Same per-id\n // isolation as the puts loop above. #658: the wave now ALSO heals MV rows and array-shape\n // derivation output rows for the deleted child — parity with the local-delete boundary\n // (`Collection._doDelete`'s `!internal` block, which already calls all three). Still never\n // routed through `dispatchDerivations` (the mutation-choke-point.test.ts:85-99 pin — sync-\n // applied deletes never RE-DERIVE); `dispatchMaterializedViewsOnDelete`/\n // `dispatchArrayDerivationsOnDelete` only need `id` (MV refresh recomputes+diffs; array-\n // derivation reads its per-source sidecar) and never call `derive()`, so the pin holds.\n for (const [id, intents] of touch.deletes) {\n try {\n await coll._recomputeDeletedRollups(intents, wave)\n // #658: record-shape same-id outputs are left untouched (eraseRecordShapeToo defaults\n // false), matching local delete — the user deletes those directly if wanted.\n // #658: TODO dedup MV refresh per wave — `dispatchMaterializedViewsOnDelete` doesn't\n // accept a `WaveContext` (unlike the put-path `dispatchMaterializedViews`), so N deleted\n // children of one eager MV in a batch each trigger a full refresh pass. Threading `wave`\n // through would touch collection.ts's zero-slack kernel-surface ceiling for a perf-only\n // win; correctness doesn't depend on it (idempotent per source-id) — left as a follow-up.\n await coll.dispatchMaterializedViewsOnDelete(id)\n await coll.dispatchArrayDerivationsOnDelete(id)\n } catch (err) {\n console.warn(`[via-dispatch] wave delete-recompute failed for ${collectionName}/${id}:`, err)\n vault._emit('derivation:wave-error', { collection: collectionName, id, error: err })\n }\n }\n }\n}\n\n/** A record's post-freeze source mutation, for the `'derivation:skipped-frozen'` event\n * and the optional audit-trail entry. See {@link putDerivedOutput}. */\nexport interface DerivationSkippedFrozen {\n readonly source: { readonly collection: string; readonly id: string }\n readonly target: { readonly collection: string; readonly id: string }\n readonly period: string\n readonly endDate: string\n}\n\n/** The minimal put-capable shape `putDerivedOutput` needs. Any `Collection<T>` structurally\n * satisfies this — its real `options` type is a superset of what's declared here. */\nexport interface CollectionLike {\n put(id: string, value: unknown, options?: { readonly source?: string }): Promise<void>\n}\n\nexport interface PutDerivedOutputCtx {\n readonly emit: (ev: string, p: unknown) => void\n readonly source: { readonly collection: string; readonly id: string }\n readonly audit?: ((e: DerivationSkippedFrozen) => Promise<void>) | undefined\n}\n\n/**\n * Attempt a dispatch-driven output write. On `PeriodClosedError` (the closed-period\n * `beforePut` gate — `freezePeriod`/`archivePeriod` add no separate gate, per seam map\n * Part 7): SKIP (no `_ts` stamped — the gate throws before any write happens), emit\n * `'derivation:skipped-frozen'` on the event bus (ALWAYS), and append an audit-trail entry\n * when the with-history ledger is active. Returns `'written' | 'skipped-frozen'`. Any OTHER\n * error propagates unchanged — this helper narrows exactly one error class. The SOURCE\n * write is never wrapped through this helper — only derived-output writes are (§7).\n */\nexport async function putDerivedOutput(\n outColl: CollectionLike, id: string, value: unknown,\n ctx: PutDerivedOutputCtx,\n options?: { readonly source?: string },\n): Promise<'written' | 'skipped-frozen'> {\n try {\n await outColl.put(id, value, options)\n return 'written'\n } catch (err) {\n if (!(err instanceof PeriodClosedError)) throw err\n // Reach-around for the target collection's private `name` — the SAME pattern\n // `with-formula/materialized-views/executor.ts`'s `listOutputIds` already uses to\n // read a `Collection`'s private `adapter`/`vault`/`name` fields from outside the class.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const targetCollection = (outColl as any).name as string\n const event: DerivationSkippedFrozen = {\n source: ctx.source,\n target: { collection: targetCollection, id },\n period: err.periodName,\n endDate: err.endDate,\n }\n ctx.emit('derivation:skipped-frozen', event)\n if (ctx.audit) await ctx.audit(event)\n return 'skipped-frozen'\n }\n}\n\n/** Structural (no static import — kernel spine may not statically reach a with-* service,\n * the S4 gate recipe `check-architecture.mjs`'s port-layering check enforces) shape of the\n * with-history `LedgerStore.append` seam this helper needs. */\ninterface AuditLedgerLike {\n append(input: {\n readonly op: 'lifecycle'\n readonly collection: string\n readonly id: string\n readonly version: number\n readonly actor: string\n readonly payloadHash: string\n readonly reason?: string\n }): Promise<unknown>\n}\n\n/** @internal — the optional with-history ledger audit hook for `putDerivedOutput`, present\n * only when the ledger is active (mirrors every other kernel event's `if (this.ledger)`\n * gate). Encoded as a `'lifecycle'` entry — the existing \"non-data audit event\" op (the\n * same convention `forget`'s JSON-summary-in-`reason` entry uses; `ledger/entry.ts:88-104`). */\nexport function ledgerAuditHook(\n ledger: AuditLedgerLike | undefined, actor: string,\n): ((e: DerivationSkippedFrozen) => Promise<void>) | undefined {\n if (!ledger) return undefined\n return async (e) => {\n await ledger.append({\n op: 'lifecycle', collection: e.target.collection, id: e.target.id, version: 0, actor, payloadHash: '',\n reason: JSON.stringify({ event: 'derivation-skipped-frozen', ...e }),\n })\n }\n}\n\n/** `recomputeRollup`/`dispatchRollupsOnDelete`'s per-target write outcome (#638 Task 6):\n * `'written'`/`'skipped-frozen'` mirror {@link putDerivedOutput}'s result; `'noop'` covers\n * no-parent/no-change/deduped-by-wave — nothing to report either way. */\nexport type RollupOutcome = 'written' | 'skipped-frozen' | 'noop'\n\n/** Mutable accumulator `forgetDerivedFanout` writes into, one per `Vault.forget()` call — keeps\n * the per-ref loop's call site to a single line under vault.ts's tight kernel-surface ceiling.\n * Maps 1:1 onto `ForgetResult`'s additive fields (`with-audit/forget/strategy.ts`). */\nexport interface ForgetFanoutStats {\n recordsErased: number\n aggregatesRecomputed: number\n readonly residueFrozen: string[]\n /** #650 Task 5 (#648) — referencing records tombstoned via a `'ref'` edge's `cascade` policy. */\n lookupReferencesCascaded: number\n /** #650 Task 5 (#648) — referencing fields cleared via a `'ref'` edge's `nullify` policy. */\n lookupReferencesNullified: number\n /** #650 Task 5 review (Important fix) — `'ref'` edges whose compare-key could NOT be resolved,\n * even from the LIVE pre-shred row (the backing row itself is unreadable) — propagation was\n * skipped for these, reported here so the skip is never silent. `backing:key:collection.field`\n * entries, one per un-propagated edge. */\n readonly lookupReferencesResidue: string[]\n /** #776/#782/#785 — `outputCollection:id` MV-output rows that survived erasure invalidation\n * (eager tombstone leg AND lazy/manual `invalidateMVAtRest`) despite belonging to the\n * forgotten subject, because the ownership stamp could not be decoded (undecodable under\n * the default DEK — e.g. elevated above tier 0 on a tiered output collection). Ownership\n * UNCONFIRMED. Never erased, but surfaced here rather than silently skipped. */\n readonly derivedResidueUndecodable: string[]\n /** #782/#785 — `outputCollection:id` MV-output rows that decoded and stamp-matched but whose\n * `_internalDelete` declined (the #718 tier-elevation gate). Ownership CONFIRMED, erasure\n * declined — a real silent survival, surfaced here rather than silently skipped. */\n readonly derivedResidueDeclined: string[]\n}\n\n/**\n * #622 — after `_writeTombstone(ref.id, actor)` erases the forgotten subject's own record, fan\n * out to its derived residue via the graph (spec §5): record-grain artifacts (MV rows,\n * array-shape derivation rows, same-id record-shape derivation copies) are ERASED through the\n * SAME `!internal` housekeeping-bypass machinery the ordinary delete path uses (no user\n * `onDelete` re-fires — the shred-is-not-a-domain-delete property `_writeTombstone` protects);\n * aggregate-grain rollups are RECOMPUTED without the forgotten contribution in open periods, or\n * skip+audit (via `putDerivedOutput`, already wired into the rollup/MV output paths) in frozen\n * ones. Mutates `stats` in place. `envelope` is `ref`'s PRE-tombstone envelope, decoded only if\n * a rollup edge is actually present — the #553 zero-cost-skip discipline: no decrypt for the\n * common case of a forgotten record with no aggregate-grain consumer, and no work at all when\n * `ref.collection` has no graph out-edges. `lookupCompareKeys` is the `'ref'` edges' compare-key\n * map, resolved from the LIVE row BEFORE any shred (`VaultLinks.checkLookupRefsRestrict`'s return\n * value — `Vault.forget()`'s pre-shred restrict check doubles as the live-resolve pass) — see\n * {@link applyLookupRefsFanout}.\n */\nexport async function forgetDerivedFanout(\n vault: VaultLike,\n ref: { readonly collection: string; readonly id: string },\n envelope: EncryptedEnvelope | null,\n stats: ForgetFanoutStats,\n lookupCompareKeys: ReadonlyMap<string, string | undefined>,\n): Promise<void> {\n const coll = vault._getCollection(ref.collection)\n\n // #761 item 4 — drive the MV arm off `dispatchMaterializedViewsOnDelete` UNCONDITIONALLY,\n // ABOVE the `edges` check below: `registry.edges()` drops the same-collection\n // partition-disjoint MV edge (registry.ts's `sources.length === 0 → continue`), so a\n // same-collection MV's source collection never appears in `vault.graph`'s derived-artifact\n // edges even though the MV IS registered — forget() would otherwise never reach it.\n // `dispatchMaterializedViewsOnDelete` self-guards O(1) via `mvsForSource` (a no-op when\n // this collection isn't an MV source), so this is safe to call unconditionally. Safe to\n // route through the eager executor's tombstone leg ONLY because that leg is now\n // stamp-scoped (#762) — before that fix this would have opened a NEW forget-time\n // data-loss path into the unscoped tombstone diff.\n if (coll) {\n const mv = await coll.dispatchMaterializedViewsOnDelete(ref.id)\n stats.recordsErased += mv.deleted\n stats.derivedResidueUndecodable.push(...mv.residueUndecodable)\n stats.derivedResidueDeclined.push(...mv.residueDeclined)\n }\n\n const edges = vault.graph.derivedArtifactsOf(ref.collection)\n if (edges.length === 0 || !coll) return\n\n // #650 Task 5 (#648) — 'ref' cascade/nullify propagate ADDITIVELY, here, AFTER the shred\n // (restrict already refused BEFORE any shred — the caller's pre-tombstone check, spec §4).\n // The I/O shell (loop shape, collection accessor) is duplicated, not imported, from\n // `VaultLinks.applyLookupRefsPropagation`/`checkLookupRefsRestrict` (with-shape/links/\n // vault-facade.ts) — the kernel spine may not statically import a with-* service\n // (port-layering, the #638 Task 5 via/dispatch.ts precedent); `vault._getCollection` is\n // cached-only while `VaultLinks`' accessor constructs. The pure match predicate itself is\n // shared through the port seam (#651 Task 3 — `matchesReferencingValue`, `port/with/\n // lookup-strategy.ts`), so only the shell, not the coercion logic, stays duplicated. A\n // referencing edge whose dimension uses a non-default `key` (matrix tier only) needs the\n // backing row's OWN value at that field, not its PUT-id — the row is ALREADY tombstoned by\n // now, so it's read from `lookupCompareKeys`, resolved by the caller from the LIVE row\n // BEFORE the shred (#650 Task 5 review, Important fix — eliminates the post-shred\n // envelope-decode dependency this used to have, which silently skipped propagation whenever\n // that decode failed).\n if (edges.some((e) => e.kind === 'ref')) {\n const { cascaded, nullified, residue } = await applyLookupRefsFanout(vault, ref.collection, ref.id, lookupCompareKeys)\n stats.lookupReferencesCascaded += cascaded\n stats.lookupReferencesNullified += nullified\n stats.lookupReferencesResidue.push(...residue)\n }\n\n if (edges.some((e) => e.kind === 'derivation')) {\n // #622 review Finding 1: count REAL erasures (dispatchArrayDerivationsOnDelete's own\n // `_internalDelete`-backed tally), not the derivation EDGE count — an edge exists whenever\n // this collection is ANY trigger (source/sources[]/triggerBy), but the same-id record-shape\n // guard only erases for `spec.source === this.name`, and `derive()` may never have produced\n // an output row (optional-skip) in the first place. Both cases must contribute 0, not +1.\n stats.recordsErased += await coll.dispatchArrayDerivationsOnDelete(ref.id, true)\n }\n\n if (envelope && edges.some((e) => e.kind === 'rollup')) {\n const priorRecord = await coll._decodeEnvelope(envelope, ref.id)\n if (priorRecord) {\n for (const r of await coll.dispatchRollupsOnDelete(ref.id, priorRecord)) {\n if (r.outcome === 'written') stats.aggregatesRecomputed += 1\n else if (r.outcome === 'skipped-frozen') stats.residueFrozen.push(`${r.into}:${r.parentId}`)\n }\n }\n }\n}\n\n/**\n * Apply `cascade`/`nullify` propagation for `backing`'s non-restrict `'ref'` edges — the\n * forget-path counterpart of `VaultLinks.applyLookupRefsPropagation` (I/O shell duplicated, not\n * imported, match predicate shared via the port — see {@link forgetDerivedFanout}'s call site\n * comment). `restrict` edges are skipped here: the\n * forget loop's `checkLookupRefsRestrict`-equivalent call already refused (or the reference no\n * longer existed) BEFORE `_writeTombstone` ran, so by the time this runs only cascade/nullify\n * remain to propagate. `compareKeys` is the non-`'id'`-`keyField` compare-value map, resolved by\n * the caller from the LIVE row BEFORE the shred (#650 Task 5 review, Important fix) — the live row\n * is already shredded by the time THIS function runs, so it can no longer resolve one itself. A\n * `keyField` absent from (or `undefined` in) the map means that live resolve failed too — the edge\n * is reported as residue instead of silently skipped (never a bare `continue` with no trace).\n */\nasync function applyLookupRefsFanout(\n vault: VaultLike,\n backing: string,\n key: string,\n compareKeys: ReadonlyMap<string, string | undefined>,\n): Promise<{ cascaded: number; nullified: number; residue: string[] }> {\n let cascaded = 0\n let nullified = 0\n const residue: string[] = []\n for (const { referencing, onDelete, keyField } of vault.graph.referencingEdgesOf(backing)) {\n if (onDelete === 'restrict') continue\n const compareKey = keyField === 'id' ? key : compareKeys.get(keyField)\n if (compareKey === undefined) {\n residue.push(`${backing}:${key}:${referencing.collection}.${referencing.field}`)\n continue\n }\n const coll = vault._getCollection(referencing.collection)\n if (!coll) continue\n const matches = (await coll.list()).filter((rec) => matchesReferencingValue(rec, referencing.field, compareKey))\n for (const rec of matches) {\n const id = rec['id'] as string | undefined\n if (id === undefined) continue\n if (onDelete === 'cascade') {\n await coll.delete(id)\n cascaded++\n } else if (onDelete === 'nullify') {\n await coll.put(id, { ...rec, [referencing.field]: null })\n nullified++\n }\n }\n }\n return { cascaded, nullified, residue }\n}\n\n/**\n * Value-equality for a single self-write reverse-denorm field. Scalars\n * compare by identity; objects by canonical JSON (denorm values should be\n * deterministically shaped). Used as the cycle guard — when every denorm\n * field already matches, no write is issued and the self-write recursion ends.\n */\nexport function selfWriteFieldEqual(a: unknown, b: unknown): boolean {\n if (a === b) return true\n if (a === null || b === null || typeof a !== 'object' || typeof b !== 'object') return false\n try {\n return JSON.stringify(a) === JSON.stringify(b)\n } catch {\n return false\n }\n}\n"],"mappings":"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","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  NOYDB_FORMAT_VERSION
3
- } from "./chunk-24ZLWWEO.js";
3
+ } from "./chunk-YPYHVOXP.js";
4
4
 
5
5
  // src/with-shape/schema-update/fence.ts
6
6
  var FENCE_RECORD_ID = "schema-fence";
@@ -39,4 +39,4 @@ export {
39
39
  loadFence,
40
40
  saveFence
41
41
  };
42
- //# sourceMappingURL=chunk-MVOWXQHN.js.map
42
+ //# sourceMappingURL=chunk-6BU3L4UE.js.map
@@ -1,15 +1,20 @@
1
1
  import {
2
2
  wrapDbWithPredicates
3
3
  } from "./chunk-7F4DBNSP.js";
4
+ import {
5
+ canonicalizeMoneyFieldsAsDecimal,
6
+ decodeMoneyFields,
7
+ exactMath
8
+ } from "./chunk-RXYYFSBB.js";
4
9
  import {
5
10
  groupAndReduce
6
11
  } from "./chunk-CCZJJ4I2.js";
7
12
  import {
8
13
  putDerivedOutput
9
- } from "./chunk-ZXJXDHNK.js";
14
+ } from "./chunk-5ZKS6ZE2.js";
10
15
  import {
11
16
  DEFAULT_JOIN_MAX_ROWS
12
- } from "./chunk-E6427JU2.js";
17
+ } from "./chunk-H4YQSDOI.js";
13
18
  import {
14
19
  canonicalGroupKey
15
20
  } from "./chunk-XZHEOSQ2.js";
@@ -96,6 +101,25 @@ function finalizeMappedRows(spec, unified) {
96
101
  }
97
102
  return groupAndReduce(unified, groupFields, spec.aggregate, spec.moneyFields);
98
103
  }
104
+ function applyDerive(spec, rows) {
105
+ const groupFields = new Set(
106
+ spec.groupBy === void 0 ? [] : typeof spec.groupBy === "string" ? [spec.groupBy] : spec.groupBy
107
+ );
108
+ return rows.map((row) => {
109
+ const view = spec.moneyFields ? decodeMoneyFields(row, spec.moneyFields, "raw") : row;
110
+ const patch = spec.derive(view, exactMath);
111
+ if (patch === null || patch === void 0) return row;
112
+ for (const key of Object.keys(patch)) {
113
+ if (groupFields.has(key)) {
114
+ throw new MaterializedViewConfigError(
115
+ `Materialized view "${spec.name}": derive() returned the group key "${key}". A group key is the row's identity and feeds rowKey \u2014 rewriting it would re-home the row into a bucket it was not aggregated for. Emit a differently-named field instead.`
116
+ );
117
+ }
118
+ }
119
+ const canonical = spec.moneyFields ? canonicalizeMoneyFieldsAsDecimal(patch, spec.moneyFields) : patch;
120
+ return { ...row, ...canonical };
121
+ });
122
+ }
99
123
  async function materializeProjectionResult(spec, db) {
100
124
  const projection = spec.projection;
101
125
  const coll = db.collection(projection.source);
@@ -181,6 +205,7 @@ var MaterializedViewExecutor = {
181
205
  const q = spec.query(ctxForQuery);
182
206
  rows = await materializeQueryResult(q, spec.name, spec.i18nLocale, spec.i18nFields);
183
207
  }
208
+ if (spec.derive) rows = applyDerive(spec, rows);
184
209
  rows = rows.filter((row) => {
185
210
  const stamp = row._materializedFrom;
186
211
  return stamp?.mvName !== spec.name;
@@ -282,4 +307,4 @@ async function listOutputIds(outputColl) {
282
307
  export {
283
308
  MaterializedViewExecutor
284
309
  };
285
- //# sourceMappingURL=chunk-3IIPWA75.js.map
310
+ //# sourceMappingURL=chunk-6BVER473.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/with-formula/materialized-views/executor.ts"],"sourcesContent":["import type { Collection } from '../../kernel/collection.js'\nimport type { TxContext } from '../../with-commit/tx/transaction.js'\nimport type { EncryptedEnvelope } from '../../kernel/types.js'\nimport { MaterializedViewTooLargeError, MaterializedViewConfigError, LocaleNotSpecifiedError, JoinTooLargeError } from '../../kernel/errors.js'\nimport { DEFAULT_JOIN_MAX_ROWS } from '../../kernel/query/join.js'\nimport type { MaterializedFromMeta, MVQueryContext, MaterializedViewSpec } from './types.js'\nimport type { RegisteredMV } from './registry.js'\nimport { wrapDbWithPredicates } from './registry.js'\nimport { groupAndReduce } from '../../with-lookup/reduce/groupby.js'\nimport { canonicalGroupKey } from '../../with-lookup/reduce/canonical-key.js'\nimport { applyI18nLocale, type I18nTextDescriptor } from '../../via/i18n/core.js'\nimport { canonicalizeMoneyFieldsAsDecimal, decodeMoneyFields } from '../../via/money/normalize.js'\nimport { exactMath } from '../../via/money/exact.js'\nimport { putDerivedOutput, type PutDerivedOutputCtx } from '../../kernel/via/dispatch.js'\n\n/**\n * Accessor shape passed in from the owning Vault. Mirrors v1's\n * `DerivationStaleAccessor` — provides the per-collection resolver\n * and the active TxContext so refresh writes/tombstones register on\n * `_executed` for rollback symmetry.\n */\nexport interface MVExecutorAccessor {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n getCollection(name: string): Collection<any>\n getActiveTxContext(): TxContext | null\n /**\n * Vault-shaped accessor passed to the MV's `query()` callback at\n * each refresh. Same instance the registry used at registration\n * time; threading through the executor lets the refresh path\n * re-evaluate the closure against the live vault state.\n */\n getQueryContext(): MVQueryContext\n /**\n * #638 Task 5 — ctx for `putDerivedOutput`'s frozen-period skip+audit. #641: the lazy\n * resolve-on-read caller (`stale.ts#resolveStaleMVOnRead`) now supplies one too — built at\n * the `Collection.get()`/`list()` entry point with a `'resolve-on-read'` sentinel id (no\n * real \"reacting write\" for a read-triggered materialize, mirroring `refreshView()`'s\n * `'refreshView'` sentinel). Still declared optional here since `MVExecutorAccessor` is a\n * general shape and a future caller could reasonably omit it.\n */\n dispatchCtx?: PutDerivedOutputCtx\n}\n\nexport interface RefreshResult {\n /** Rows newly written / overwritten. */\n written: number\n /** Rows tombstoned via `_internalDelete` (only when `onEmpty: 'delete'`). */\n deleted: number\n /** Failed row writes (non-strict mode). */\n failed: number\n /** #782/#785 — `outputCollection:id` entries from the tombstone pass whose ownership stamp\n * couldn't be decoded under the collection's default DEK (undecodable, mirroring\n * `invalidateMVAtRest`'s #776 posture) — ownership UNCONFIRMED. Only populated when\n * `onEmpty: 'delete'`. */\n residueUndecodable: string[]\n /** #782/#785 — `outputCollection:id` entries that decoded, stamp-matched this MV, but\n * `_internalDelete` declined (the #718 tier-elevation gate) — ownership CONFIRMED, a real\n * silent survival, surfaced rather than dropped. Only populated when `onEmpty: 'delete'`. */\n residueDeclined: string[]\n}\n\n/** Default cost ceiling — overridable per-MV via `spec.maxRows`. */\nconst DEFAULT_MAX_ROWS = 100_000\n\n/**\n * Materialize a query terminal that may be a `Query<T>` (call\n * `.toArray()`), an `Reduction<R>` (call `.run()` returning a\n * single object — wrap as a one-row array), or a `GroupedReduction<R>`\n * (call `.run()` returning an array of grouped rows). Branches on\n * available terminal at runtime — no type-discrimination at registration.\n */\nasync function materializeQueryResult(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n q: any,\n mvName: string,\n i18nLocale?: string,\n i18nFields?: Record<string, I18nTextDescriptor>,\n): Promise<ReadonlyArray<Record<string, unknown>>> {\n if (typeof q?.toArray === 'function') {\n // Query<T> — non-aggregate path. `.toArray()` returns Promise<T[]>.\n return await q.toArray()\n }\n if (typeof q?.run === 'function') {\n // Reduction<R> or GroupedReduction<R>. `.run()` is synchronous\n // and returns either a single object (Reduction) or an array of\n // rows (GroupedReduction). Promise.resolve() normalizes both\n // sync and async (future) variants.\n // Query-form MV grouping: when the MV declares i18nLocale, pass it +\n // i18nFields so a GroupedReduction resolves i18n group keys before\n // bucketing (the Reduction path ignores the extra arg).\n const runOpts = i18nLocale !== undefined ? { locale: i18nLocale, i18nFields } : undefined\n const result: unknown = await Promise.resolve(q.run(runOpts))\n if (Array.isArray(result)) {\n return result as ReadonlyArray<Record<string, unknown>>\n }\n // Single-aggregate result — wrap as one-row array. The consumer's\n // `rowKey()` should return a stable identity (often a literal\n // constant like `'total'`) since there's only one row.\n return [result as Record<string, unknown>]\n }\n throw new Error(\n `MV \"${mvName}\": query() must return a Query<T>, Reduction, or GroupedReduction. ` +\n `Got something without a .toArray() or .run() terminal.`,\n )\n}\n\n/**\n * Materialize a UNION-form MV: read every arm's source\n * collection, apply each arm's `map` to project rows into the unified\n * MV row shape, concatenate the mapped streams, then optionally run\n * `groupBy` + `aggregate` over the result.\n *\n * Modes (driven by `spec.groupBy` / `spec.aggregate`):\n *\n * - No `groupBy` → return the concatenated mapped rows unchanged.\n * - `groupBy` without `aggregate` → dedupe by composite group key,\n * keep the first row seen per key (later arms don't overwrite\n * earlier arms — Map insertion order rules).\n * - `groupBy` + `aggregate` → delegate to the shared `groupAndReduce`\n * pipeline used by `Query.groupBy().aggregate()`.\n *\n * Per-arm `map` is the schema-unification boundary; the strategy's\n * `TRow` type parameter enforces that every arm projects into the\n * same shape at compile time.\n *\n * @internal\n */\nasync function materializeUnionResult<TRow extends Record<string, unknown>>(\n spec: MaterializedViewSpec<TRow>,\n db: MVQueryContext,\n): Promise<ReadonlyArray<Record<string, unknown>>> {\n const unified: TRow[] = []\n for (const arm of spec.unionSources!) {\n const coll = db.collection<Record<string, unknown>>(arm.collection)\n // Optional per-arm FK joins: chain `.join(field, { as, ... })` for\n // each declared leg before terminating. The aliased right-side\n // record lands at `sourceRow[leg.as]`, where the arm's `map` reads\n // it. Cast to `any` because the chained join widens the row type but\n // the executor treats every row as `Record<string, unknown>` — same\n // pattern the query-form join path uses.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let q: any = coll.query()\n if (arm.join?.length) {\n for (const leg of arm.join) {\n q = q.join(leg.field, { as: leg.as, maxRows: leg.maxRows, strategy: leg.strategy })\n }\n }\n const sourceRows = q.toArray() as ReadonlyArray<Record<string, unknown>>\n for (const r of sourceRows) {\n const mapped = arm.map(r)\n // null / undefined means \"omit this source row\" — skip without\n // pushing so groupBy/aggregate never see a null entry.\n if (mapped == null) continue\n unified.push(mapped)\n }\n }\n\n return finalizeMappedRows(spec, unified)\n}\n\n/**\n * Shared post-map tail for the UNION and projection (#810) forms:\n * optional `groupBy` (+ `aggregate`) over the mapped-row stream.\n * Extracted verbatim from `materializeUnionResult` so both forms feed\n * the identical grouping pipeline — i18n group-key resolution, the\n * object-group-key guard, dedup-without-aggregate, and the shared\n * `groupAndReduce` delegate.\n *\n * @internal\n */\nfunction finalizeMappedRows<TRow extends Record<string, unknown>>(\n spec: MaterializedViewSpec<TRow>,\n unified: TRow[],\n): ReadonlyArray<Record<string, unknown>> {\n if (!spec.groupBy) return unified\n\n const groupFields: readonly string[] =\n typeof spec.groupBy === 'string' ? [spec.groupBy] : spec.groupBy\n\n // i18n-aware group keys. An `i18nText` group field carries a raw\n // `{ locale: string }` map, an unstable object key. When `i18nLocale` is\n // declared (with `i18nFields` describing those fields), resolve the declared\n // group-key i18n fields to it at the `mv` layer FIRST — the same unified-rows\n // boundary where money is threaded — so buckets are stable strings and the\n // `mv`-layer `onMissing` policy fires here.\n if (spec.i18nLocale !== undefined && spec.i18nFields !== undefined) {\n const groupI18n: Record<string, I18nTextDescriptor> = {}\n for (const f of groupFields) {\n const d = spec.i18nFields[f]\n if (d !== undefined) groupI18n[f] = d\n }\n if (Object.keys(groupI18n).length > 0) {\n for (let i = 0; i < unified.length; i++) {\n unified[i] = applyI18nLocale(unified[i] as Record<string, unknown>, groupI18n, spec.i18nLocale, undefined, 'mv') as TRow\n }\n }\n }\n // Guard (always): a remaining object-valued group key — an undeclared i18n\n // field or a locale-less MV — would bucket on a map. Refuse, don't bucket wrong.\n for (const f of groupFields) {\n for (const row of unified) {\n const v = (row as Record<string, unknown>)[f]\n if (v !== null && typeof v === 'object') {\n throw new LocaleNotSpecifiedError(\n f,\n `Materialized view \"${spec.name}\" groups by \"${f}\", whose value is a raw i18n locale map — ` +\n `an unstable object group key. Declare { i18nLocale, i18nFields } on the MV to resolve it at ` +\n `the 'mv' layer, or group by a dictKey/staticDict code (the stable key) and resolve the label at read time.`,\n )\n }\n }\n }\n\n // groupBy without aggregate — dedupe by composite key, keep first\n // seen row per key. Useful for cross-arm uniqueness (e.g. unify two\n // sibling collections, keeping one row per natural key).\n if (!spec.aggregate) {\n const seen = new Map<string, TRow>()\n for (const row of unified) {\n const k = canonicalGroupKey(groupFields, row as Record<string, unknown>)\n if (!seen.has(k)) seen.set(k, row)\n }\n return [...seen.values()]\n }\n\n // groupBy + aggregate — delegate to the shared pipeline used by\n // `Query.groupBy().aggregate()`. Result rows carry each grouped\n // field in declaration order followed by the spec's reducer outputs.\n return groupAndReduce<Record<string, unknown>>(unified, groupFields, spec.aggregate, spec.moneyFields)\n}\n\n/**\n * Apply the spec's `derive` to each finished row (#1007).\n *\n * Three rules, all of them about keeping the hook narrow enough that the\n * engine never has to reason about the function:\n *\n * - a `null` / `undefined` return leaves the row untouched;\n * - a returned key that collides with a `groupBy` field is refused — group\n * keys are the row's identity and feed `rowKey`, so letting `derive`\n * rewrite one would silently re-home the row into a different bucket than\n * the one it was aggregated for;\n * - a derived field declared in `moneyFields` is quantised through its\n * descriptor, so the stored value is exact at the declared scale instead of\n * whatever the user's arithmetic produced.\n *\n * @internal\n */\nfunction applyDerive<TRow extends Record<string, unknown>>(\n spec: MaterializedViewSpec<TRow>,\n rows: ReadonlyArray<Record<string, unknown>>,\n): ReadonlyArray<Record<string, unknown>> {\n const groupFields = new Set<string>(\n spec.groupBy === undefined ? [] : typeof spec.groupBy === 'string' ? [spec.groupBy] : spec.groupBy,\n )\n return rows.map((row) => {\n // `derive` sees the row the way a READER would: money decoded to its\n // canonical decimal form, not the scaled integer the reducer left behind.\n // Handing over `1005` where the schema says `10.05` would make every\n // derived money expression quietly wrong by a factor of the scale.\n // `'raw'` keeps it at the exact decimal rather than a locale-formatted\n // string, which is what `exact.*` consumes.\n const view = spec.moneyFields ? decodeMoneyFields(row, spec.moneyFields, 'raw') : row\n const patch = spec.derive!(view as TRow, exactMath)\n if (patch === null || patch === undefined) return row\n for (const key of Object.keys(patch)) {\n if (groupFields.has(key)) {\n throw new MaterializedViewConfigError(\n `Materialized view \"${spec.name}\": derive() returned the group key \"${key}\". ` +\n 'A group key is the row\\'s identity and feeds rowKey — rewriting it would re-home the ' +\n 'row into a bucket it was not aggregated for. Emit a differently-named field instead.',\n )\n }\n }\n // Canonicalize the PATCH only, into the DECIMAL form the money-aware\n // reducers emit — not the scaled-integer storage form a collection uses.\n // An MV row's money fields are decimal strings, so a derived field\n // quantised into storage form reads back as the scaled integer beside\n // correctly-decoded siblings: `\"1000000\"` next to `\"10000.00\"` (#1018).\n // Precision is still enforced; only the output shape differs.\n const canonical = spec.moneyFields\n ? canonicalizeMoneyFieldsAsDecimal(patch, spec.moneyFields)\n : patch\n return { ...row, ...canonical }\n })\n}\n\n/**\n * Materialize a projection-form MV (#810): hydrate the primary source\n * rows, resolve forward FK legs through the same `.join()` machinery\n * the UNION arms use, attach reverse \"collect\" legs via one\n * hash-grouped snapshot pass per leg, then run the projection `map`\n * (null / undefined omits the primary row) and the shared post-map\n * grouping tail.\n *\n * @internal\n */\nasync function materializeProjectionResult<TRow extends Record<string, unknown>>(\n spec: MaterializedViewSpec<TRow>,\n db: MVQueryContext,\n): Promise<ReadonlyArray<Record<string, unknown>>> {\n const projection = spec.projection!\n const coll = db.collection<Record<string, unknown>>(projection.source)\n // Forward legs chain through the query builder exactly like UNION arm\n // joins — ref() resolution, dangling-mode semantics, presentation\n // dressing, and ceilings all ride the existing `.join()` path. Cast to\n // `any` for the same reason `materializeUnionResult` does.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let q: any = coll.query()\n for (const leg of projection.joins) {\n if ('collect' in leg) continue\n q = q.join(leg.field, { as: leg.as, maxRows: leg.maxRows, strategy: leg.strategy })\n }\n let rows = q.toArray() as Array<Record<string, unknown>>\n for (const leg of projection.joins) {\n if (!('collect' in leg)) continue\n rows = applyCollectLeg(rows, leg, spec.name, projection.source, db)\n }\n const mapped: TRow[] = []\n for (const r of rows) {\n const m = projection.map(r)\n // null / undefined means \"omit this primary row\" — same contract\n // as the UNION arm `map`.\n if (m == null) continue\n mapped.push(m)\n }\n return finalizeMappedRows(spec, mapped)\n}\n\n/**\n * Attach one reverse \"collect\" leg (#810): every row of `leg.collect`\n * whose `leg.on` field references a primary record's id lands in a\n * possibly-empty ARRAY under `leg.as` on that primary row. One\n * snapshot pass over the collect collection, hash-grouped by the `on`\n * FK — O(N+M), mirroring the forward hash-join fallback.\n *\n * Semantic check (first materialization, not factory time — parity\n * with join-time ref errors): `leg.on` must carry a `ref()` declared\n * on the collect collection targeting the projection `source`.\n *\n * @internal\n */\nfunction applyCollectLeg(\n primaryRows: ReadonlyArray<Record<string, unknown>>,\n leg: { readonly collect: string; readonly on: string; readonly as: string; readonly maxRows?: number },\n mvName: string,\n source: string,\n db: MVQueryContext,\n): Array<Record<string, unknown>> {\n const childColl = db.collection<Record<string, unknown>>(leg.collect)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const childQ = childColl.query() as any\n const refDesc = childQ._joinContext?.()?.resolveRef(leg.on) as { target: string } | null | undefined\n if (refDesc == null) {\n throw new MaterializedViewConfigError(\n `\"${mvName}\": projection collect leg \"${leg.as}\" requires a ref() on field \"${leg.on}\" of `\n + `collection \"${leg.collect}\" targeting \"${source}\" — declare `\n + `refs: { ${leg.on}: ref('${source}') } on collection \"${leg.collect}\", then retry`,\n )\n }\n if (refDesc.target !== source) {\n throw new MaterializedViewConfigError(\n `\"${mvName}\": projection collect leg \"${leg.as}\" expects field \"${leg.on}\" of collection `\n + `\"${leg.collect}\" to reference the projection source \"${source}\", but its ref() targets `\n + `\"${refDesc.target}\"`,\n )\n }\n const maxRows = leg.maxRows ?? DEFAULT_JOIN_MAX_ROWS\n const groups = new Map<string, Array<Record<string, unknown>>>()\n for (const child of childQ.toArray() as Array<Record<string, unknown>>) {\n const key = coerceCollectKey(child[leg.on])\n // Nullish / non-scalar FK values mean \"no reference\" — same\n // narrowing as the forward join path's key coercion.\n if (key === null) continue\n const bucket = groups.get(key)\n if (bucket) bucket.push(child)\n else groups.set(key, [child])\n }\n const out: Array<Record<string, unknown>> = []\n for (const row of primaryRows) {\n const key = coerceCollectKey(row.id)\n const children = key === null ? [] : groups.get(key) ?? []\n if (children.length > maxRows) {\n throw new JoinTooLargeError({\n leftRows: primaryRows.length,\n rightRows: children.length,\n maxRows,\n side: 'right',\n message:\n `projection MV \"${mvName}\": collect leg \"${leg.as}\" gathered ${children.length} ` +\n `\"${leg.collect}\" rows for one \"${source}\" record, exceeding the ${maxRows}-row ` +\n `per-primary-row ceiling. Raise the ceiling via { maxRows } on the leg if the ` +\n `fan-out genuinely fits in memory, or restructure the child collection.`,\n })\n }\n out.push({ ...row, [leg.as]: children })\n }\n return out\n}\n\n/**\n * Coerce an unknown FK value into a collect-grouping key. Same\n * narrowing as the join path's `coerceRefKey` (not exported from\n * there): strings and numbers are legitimate ref values; anything\n * else is \"no reference\" and returns `null`.\n *\n * @internal\n */\nfunction coerceCollectKey(value: unknown): string | null {\n if (value === null || value === undefined) return null\n if (typeof value === 'string') return value\n if (typeof value === 'number' || typeof value === 'bigint') return String(value)\n return null\n}\n\n/**\n * Run an MV's `query()` and write the result rows to the output\n * collection. Same-DEK encryption: routes through the standard\n * `Collection.put` pipeline, so the output collection's DEK is what\n * gets used (matches the v2 spec's \"same DEK as the left-most source\"\n * invariant — `Collection.put` looks up the DEK by collection name,\n * and the output collection IS the MV's owned collection).\n *\n * Stamps `_materializedFrom` onto every emitted row.\n *\n * **Tombstoning:** when `spec.onEmpty: 'delete'` (default), rows\n * that existed in a prior refresh but no longer appear in the new\n * materialized result are deleted via `Collection._internalDelete` —\n * the housekeeping bypass primitive prevents user\n * `onDelete` guards on the output collection from firing on these\n * system-internal deletes. `onEmpty: 'keep'` opts out (rows from\n * prior refreshes linger even when the new result lacks them).\n *\n * **Cost ceiling:** if the materialized row count exceeds\n * `spec.maxRows` (default 100k), throws `MaterializedViewTooLargeError`\n * before any writes hit the store — so strict-mode rollback is\n * clean.\n *\n * **Strict mode:** `spec.strict === true` re-throws on any\n * row-write failure; the active TxContext registration means the\n * source-write rolls back atomically via `revertExecuted`.\n *\n * @internal\n */\nexport const MaterializedViewExecutor = {\n async refresh(\n reg: RegisteredMV,\n accessor: MVExecutorAccessor,\n ): Promise<RefreshResult> {\n const spec = reg.spec\n const outputColl = accessor.getCollection(reg.outputCollection)\n const maxRows = spec.maxRows ?? DEFAULT_MAX_ROWS\n const onEmpty = spec.onEmpty ?? 'delete'\n const strict = spec.strict ?? false\n\n // 1. Materialize the query (branches on terminal shape). If the\n // MV declared predicates, wrap the query context the same way\n // the registry did at registration time so `.wherePredicate()`\n // calls resolve to the registered functions.\n const baseCtx = accessor.getQueryContext()\n const ctxForQuery: MVQueryContext = spec.predicates\n ? wrapDbWithPredicates(baseCtx, spec.predicates)\n : baseCtx\n // UNION-form strategies: read every arm, map to the unified\n // row shape, concatenate, then optionally groupBy + aggregate.\n // Projection-form strategies (#810): hydrate the primary source,\n // attach forward + collect legs, map, then the same optional\n // grouping tail. The single-source `query()` path is untouched.\n let rows: ReadonlyArray<Record<string, unknown>>\n if (spec.unionSources) {\n rows = await materializeUnionResult(spec, ctxForQuery)\n } else if (spec.projection) {\n rows = await materializeProjectionResult(spec, ctxForQuery)\n } else {\n const q = spec.query!(ctxForQuery)\n rows = await materializeQueryResult(q, spec.name, spec.i18nLocale, spec.i18nFields)\n }\n\n // #1007 — the post-aggregate projection. Applied here, after every form has\n // produced its finished rows, so union / projection / query all get the\n // same single definition of \"last step before materialisation\".\n if (spec.derive) rows = applyDerive(spec, rows)\n\n // #777 — exclude this MV's OWN previously-stamped output rows from the\n // input scan. A same-collection Query-form MV copies the whole source row\n // verbatim into its output, so a stale output row can itself satisfy the\n // MV's own input filter (when the filter is on a field disjoint from the\n // partition field) and get re-selected as if it were live source — the\n // row self-perpetuates after its true source is gone. Prior output is\n // never this MV's own source.\n rows = rows.filter((row) => {\n const stamp = row._materializedFrom as { mvName?: string } | undefined\n return stamp?.mvName !== spec.name\n })\n\n // 2. Cost ceiling check BEFORE any writes — keeps the rollback\n // clean if the source-write is wrapped in a transaction.\n if (rows.length > maxRows) {\n throw new MaterializedViewTooLargeError(spec.name, rows.length, maxRows)\n }\n\n const txCtx = accessor.getActiveTxContext()\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const adapter = (outputColl as any).adapter as {\n get(v: string, c: string, i: string): Promise<EncryptedEnvelope | null>\n }\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const vaultName = (outputColl as any).vault as string\n\n // 3. Compute the post-refresh id set so we can diff against the\n // prior-emitted id set for tombstoning (when onEmpty === 'delete').\n const newIds = new Set<string>()\n const enrichedRows: Array<{ id: string; record: Record<string, unknown> }> = []\n for (const row of rows) {\n const id = spec.rowKey(row)\n newIds.add(id)\n const meta: MaterializedFromMeta = {\n mvName: spec.name,\n queryHash: reg.queryHash,\n sourceVersions: {},\n materializedAt: new Date().toISOString(),\n }\n enrichedRows.push({ id, record: { ...row, _materializedFrom: meta } })\n }\n\n // 4. Write the new rows.\n let written = 0\n let failed = 0\n for (const { id, record } of enrichedRows) {\n try {\n if (txCtx !== null) {\n const prior = await adapter.get(vaultName, reg.outputCollection, id)\n txCtx._executed.push({\n op: { type: 'put', vaultName, collectionName: reg.outputCollection, id },\n priorEnvelope: prior,\n })\n }\n if (accessor.dispatchCtx) {\n if (await putDerivedOutput(outputColl, id, record, accessor.dispatchCtx) === 'written') written++\n } else {\n await outputColl.put(id, record)\n written++\n }\n } catch (err) {\n failed++\n if (strict) throw err\n \n console.warn(`[mv] \"${spec.name}\" row write failed:`, err)\n }\n }\n\n // 5. Tombstone rows that existed before but don't appear now.\n // `onEmpty: 'keep'` skips this pass entirely. Uses\n // `_internalDelete` so a user-registered `onDelete` on the\n // output collection does NOT fire on housekeeping (composition fix).\n let deleted = 0\n const residueUndecodable: string[] = []\n const residueDeclined: string[] = []\n if (onEmpty === 'delete') {\n const priorIds = await listOutputIds(outputColl)\n for (const priorId of priorIds) {\n if (newIds.has(priorId)) continue\n // #762 — a same-collection partition MV (`output: { collection: <source>, partition }`,\n // the DERIV-PP30-001 shape) writes INTO its own source collection, so `listOutputIds`\n // also returns untouched USER source rows here. Decode each candidate and only\n // tombstone rows THIS MV stamped via `_materializedFrom.mvName` — the exact discipline\n // `invalidateMVAtRest` uses (stale.ts:151-162). An unstamped row, or one stamped by a\n // different MV, is never this MV's to delete.\n const priorEnvelope = await adapter.get(vaultName, reg.outputCollection, priorId)\n if (priorEnvelope === null) continue\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const priorDecoded = await (outputColl as any)._decodeEnvelope(priorEnvelope, priorId)\n if (priorDecoded === null) {\n // #782 part a — ownership unknown (undecodable, e.g. elevated above tier 0 on a\n // tiered output collection): can't rule out this being THIS MV's own stamped row.\n // Surface it rather than silently skip (mirrors invalidateMVAtRest's #776 posture —\n // previously this leg had NO residue channel at all).\n residueUndecodable.push(`${reg.outputCollection}:${priorId}`)\n continue\n }\n const priorStampedBy =\n typeof priorDecoded === 'object'\n ? (priorDecoded as Record<string, unknown>)._materializedFrom as { mvName?: string } | undefined\n : undefined\n if (priorStampedBy?.mvName !== spec.name) continue\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const outAny = outputColl as any\n if (typeof outAny._internalDelete === 'function') {\n // #776 part b — gate on the boolean, matching invalidateMVAtRest's discipline\n // (stale.ts): `_internalDelete` returns `false` for a #718 elevated-skip (no\n // erasure happened), and that must not inflate the tombstone count.\n if (await outAny._internalDelete(priorId, txCtx)) {\n deleted++\n } else {\n // #782 part b — decoded AND stamp-owned, but erasure was declined (#718\n // tier-elevation gate). Ownership IS confirmed here — a real silent survival,\n // not a legit stamp-mismatch skip. Surface it too.\n residueDeclined.push(`${reg.outputCollection}:${priorId}`)\n }\n } else {\n // Defensive fallback — should never hit in real flow since\n // every Collection has `_internalDelete`.\n await outputColl.delete(priorId)\n deleted++\n }\n } catch (err) {\n failed++\n if (strict) throw err\n\n console.warn(`[mv] \"${spec.name}\" tombstone failed for id=\"${priorId}\":`, err)\n }\n }\n }\n\n return { written, deleted, failed, residueUndecodable, residueDeclined }\n },\n}\n\n/**\n * List ids currently present in the MV's output collection via the\n * adapter directly (avoids triggering the lazy resolve-on-read path\n * we're INSIDE). Returns an empty array if the collection doesn't\n * exist or the adapter doesn't surface a list method.\n *\n * @internal\n */\nasync function listOutputIds(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n outputColl: Collection<any>,\n): Promise<string[]> {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const cAny = outputColl as any\n const adapter = cAny.adapter as { list?: (v: string, c: string) => Promise<readonly string[]> }\n const vault = cAny.vault as string\n const name = cAny.name as string\n if (typeof adapter?.list !== 'function') return []\n try {\n const ids = await adapter.list(vault, name)\n return [...ids]\n } catch {\n return []\n }\n}\n"],"mappings":"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","names":[]}
@@ -4,7 +4,7 @@ import {
4
4
  persistUserVisibility,
5
5
  readUserVisibility,
6
6
  saveUserEnvelope
7
- } from "./chunk-27TCYH6G.js";
7
+ } from "./chunk-5JY5TSVY.js";
8
8
  import {
9
9
  PolicyDeniedError
10
10
  } from "./chunk-HNGSV2YC.js";
@@ -379,4 +379,4 @@ export {
379
379
  UserApi,
380
380
  createUserApi
381
381
  };
382
- //# sourceMappingURL=chunk-OSFPNKY4.js.map
382
+ //# sourceMappingURL=chunk-6FJWSWFT.js.map