@noy-db/hub 0.7.1-pre.0 → 0.8.0

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 (812) hide show
  1. package/CHANGELOG.md +147 -14
  2. package/LICENSE +202 -21
  3. package/NOTICE +1 -0
  4. package/README.md +5 -5
  5. package/codemods/0.8.0-pre.json +61 -0
  6. package/dist/api-OS747DS4.js +18 -0
  7. package/dist/as/index.js +11 -12
  8. package/dist/as/index.js.map +1 -1
  9. package/dist/at/index.js +9 -10
  10. package/dist/attestation/index.js +37 -26
  11. package/dist/attestation/index.js.map +1 -1
  12. package/dist/{backup-XKCXVKV3.js → backup-YE2VQ26S.js} +15 -16
  13. package/dist/backup-YE2VQ26S.js.map +1 -0
  14. package/dist/blobs/index.js +13 -14
  15. package/dist/blobs/index.js.map +1 -1
  16. package/dist/broker/index.js +12 -13
  17. package/dist/broker/index.js.map +1 -1
  18. package/dist/by/index.js +2 -2
  19. package/dist/capsule/contract.d.ts +159 -0
  20. package/dist/capsule/contract.js +95 -0
  21. package/dist/capsule/enclave-aes/bound.d.ts +52 -0
  22. package/dist/capsule/enclave-aes/capabilities.d.ts +2 -0
  23. package/dist/capsule/enclave-aes/classify/compare.d.ts +20 -0
  24. package/dist/{kernel/enclave → capsule/enclave-aes}/classify/find.d.ts +1 -1
  25. package/dist/{kernel/enclave → capsule/enclave-aes}/classify/reveal.d.ts +1 -1
  26. package/dist/{kernel/enclave → capsule/enclave-aes}/classify/verify.d.ts +2 -2
  27. package/dist/{kernel/enclave → capsule/enclave-aes}/classify/write.d.ts +1 -1
  28. package/dist/{kernel/enclave → capsule/enclave-aes}/crypto.d.ts +33 -129
  29. package/dist/capsule/enclave-aes/index.d.ts +113 -0
  30. package/dist/capsule/enclave-aes/index.js +335 -0
  31. package/dist/capsule/enclave-aes/index.js.map +1 -0
  32. package/dist/capsule/enclave-aes/primitives.d.ts +29 -0
  33. package/dist/capsule/index.d.ts +27 -0
  34. package/dist/capsule/plumbing/ct-equal.d.ts +11 -0
  35. package/dist/{kernel/enclave/record-keys → capsule/plumbing}/deterministic.d.ts +8 -21
  36. package/dist/capsule/plumbing/digest.d.ts +122 -0
  37. package/dist/{kernel/enclave/record-keys → capsule/plumbing}/envelope-body.d.ts +44 -48
  38. package/dist/capsule/plumbing/index.d.ts +100 -0
  39. package/dist/capsule/plumbing/lifecycle.d.ts +50 -0
  40. package/dist/{kernel/enclave/record-keys → capsule/plumbing}/record-codec.d.ts +80 -20
  41. package/dist/{kernel/enclave → capsule/plumbing}/record-envelope.d.ts +1 -1
  42. package/dist/capsule/plumbing/rekey-blob.d.ts +33 -0
  43. package/dist/capsule/plumbing/rekey.d.ts +44 -0
  44. package/dist/capsule/plumbing/sealed-slot.d.ts +22 -0
  45. package/dist/capsule/plumbing/sealed-slots.d.ts +37 -0
  46. package/dist/capsule/plumbing/sealing.d.ts +29 -0
  47. package/dist/capsule/plumbing/sign.d.ts +9 -0
  48. package/dist/{kernel/enclave/record-keys → capsule/plumbing}/tombstone.d.ts +2 -2
  49. package/dist/capsule-VOLX3QRQ.js +209 -0
  50. package/dist/cargo/index.js +39 -36
  51. package/dist/{chunk-Q2MPFCQ7.js → chunk-23D6M6VM.js} +5 -5
  52. package/dist/chunk-23D6M6VM.js.map +1 -0
  53. package/dist/{chunk-R7BX2NB3.js → chunk-244QBK7Z.js} +4 -4
  54. package/dist/chunk-244QBK7Z.js.map +1 -0
  55. package/dist/chunk-2AFX33YA.js +936 -0
  56. package/dist/chunk-2AFX33YA.js.map +1 -0
  57. package/dist/{chunk-MVMXZYXT.js → chunk-2GHDLTPE.js} +2 -2
  58. package/dist/{chunk-GYGLAVCX.js → chunk-2MG3SW7Q.js} +6 -2
  59. package/dist/chunk-2MG3SW7Q.js.map +1 -0
  60. package/dist/{chunk-XLMEZIAJ.js → chunk-2ODVB6LZ.js} +2 -2
  61. package/dist/{chunk-HJUWN7JN.js → chunk-2PVXF5CS.js} +33 -8
  62. package/dist/chunk-2PVXF5CS.js.map +1 -0
  63. package/dist/{chunk-YJRT5UQM.js → chunk-2RH777HH.js} +21 -20
  64. package/dist/{chunk-YJRT5UQM.js.map → chunk-2RH777HH.js.map} +1 -1
  65. package/dist/{chunk-7O3Y4PPD.js → chunk-37EPTBBR.js} +153 -16
  66. package/dist/chunk-37EPTBBR.js.map +1 -0
  67. package/dist/{chunk-2ENE6445.js → chunk-3A5DUZ56.js} +102 -16
  68. package/dist/chunk-3A5DUZ56.js.map +1 -0
  69. package/dist/chunk-3EWS67C7.js +461 -0
  70. package/dist/chunk-3EWS67C7.js.map +1 -0
  71. package/dist/{chunk-SGZAIJCV.js → chunk-3L2NBKDR.js} +4 -8
  72. package/dist/chunk-3L2NBKDR.js.map +1 -0
  73. package/dist/{chunk-YMUFFJCO.js → chunk-3TDUWVWB.js} +5 -2
  74. package/dist/chunk-3TDUWVWB.js.map +1 -0
  75. package/dist/{chunk-4GVM6QZA.js → chunk-3XJQBBZD.js} +26 -28
  76. package/dist/chunk-3XJQBBZD.js.map +1 -0
  77. package/dist/{chunk-4ZS56W5S.js → chunk-42ALPZ2B.js} +672 -664
  78. package/dist/chunk-42ALPZ2B.js.map +1 -0
  79. package/dist/chunk-4CIQDWRB.js +524 -0
  80. package/dist/chunk-4CIQDWRB.js.map +1 -0
  81. package/dist/{chunk-RMS3NEA3.js → chunk-4JPMZTJY.js} +2 -2
  82. package/dist/{chunk-P3MG6QCN.js → chunk-4T3SE27M.js} +5 -9
  83. package/dist/chunk-4T3SE27M.js.map +1 -0
  84. package/dist/chunk-4V3Q35WG.js +204 -0
  85. package/dist/chunk-4V3Q35WG.js.map +1 -0
  86. package/dist/{chunk-NQKIUNW5.js → chunk-52MGURXO.js} +2 -2
  87. package/dist/{chunk-EQEYOJBM.js → chunk-5A4345TG.js} +4 -4
  88. package/dist/chunk-5A4345TG.js.map +1 -0
  89. package/dist/{chunk-334WSVOW.js → chunk-5FE75J4S.js} +6 -6
  90. package/dist/chunk-5FE75J4S.js.map +1 -0
  91. package/dist/chunk-5KC7QYEC.js +565 -0
  92. package/dist/chunk-5KC7QYEC.js.map +1 -0
  93. package/dist/{chunk-RSGLUIO6.js → chunk-5UMK7GRI.js} +13 -12
  94. package/dist/chunk-5UMK7GRI.js.map +1 -0
  95. package/dist/chunk-5WWDGFOS.js +275 -0
  96. package/dist/chunk-5WWDGFOS.js.map +1 -0
  97. package/dist/{chunk-QPQUVOZ2.js → chunk-6QVKPHBF.js} +3 -5
  98. package/dist/chunk-6QVKPHBF.js.map +1 -0
  99. package/dist/{chunk-ACAQ2DSG.js → chunk-747G6CT3.js} +2 -2
  100. package/dist/chunk-747G6CT3.js.map +1 -0
  101. package/dist/{chunk-QTQUH4DS.js → chunk-7R2Q7CPL.js} +16 -16
  102. package/dist/chunk-7R2Q7CPL.js.map +1 -0
  103. package/dist/{chunk-UGTBXF5U.js → chunk-7XMHMVTS.js} +3 -3
  104. package/dist/{chunk-YJX7EOJD.js → chunk-A4XMIZT3.js} +6 -6
  105. package/dist/{chunk-YJX7EOJD.js.map → chunk-A4XMIZT3.js.map} +1 -1
  106. package/dist/{chunk-A66I4JOA.js → chunk-AEQGFRU4.js} +4 -4
  107. package/dist/chunk-AEQGFRU4.js.map +1 -0
  108. package/dist/chunk-AL6ML4LA.js +1558 -0
  109. package/dist/chunk-AL6ML4LA.js.map +1 -0
  110. package/dist/{chunk-BZ3534YM.js → chunk-AUKKUPVB.js} +2 -2
  111. package/dist/{chunk-CUZLNGD5.js → chunk-B2YY6WDD.js} +1 -1
  112. package/dist/chunk-B2YY6WDD.js.map +1 -0
  113. package/dist/chunk-BKT776R5.js +1 -0
  114. package/dist/chunk-BNWA3WG5.js +22 -0
  115. package/dist/chunk-BNWA3WG5.js.map +1 -0
  116. package/dist/{chunk-VXANTWBJ.js → chunk-BPWYQ25R.js} +92 -6
  117. package/dist/{chunk-VXANTWBJ.js.map → chunk-BPWYQ25R.js.map} +1 -1
  118. package/dist/{chunk-6LKOJBV6.js → chunk-BVCUTXE3.js} +2 -2
  119. package/dist/chunk-CY2CYVWZ.js +41 -0
  120. package/dist/chunk-CY2CYVWZ.js.map +1 -0
  121. package/dist/{chunk-M4YPHYEH.js → chunk-DHHGL42E.js} +70 -25
  122. package/dist/chunk-DHHGL42E.js.map +1 -0
  123. package/dist/{chunk-VTFVLCUH.js → chunk-DIZLQVAA.js} +2 -2
  124. package/dist/{chunk-G73UVHCA.js → chunk-DLD5LGDS.js} +11 -12
  125. package/dist/chunk-DLD5LGDS.js.map +1 -0
  126. package/dist/{chunk-WQBG4SZS.js → chunk-DQESF6RP.js} +60 -49
  127. package/dist/chunk-DQESF6RP.js.map +1 -0
  128. package/dist/{chunk-LWBCUYZW.js → chunk-E2N2T5ZO.js} +2 -2
  129. package/dist/{chunk-3PGS7TYR.js → chunk-EGVJ7TM4.js} +29 -32
  130. package/dist/chunk-EGVJ7TM4.js.map +1 -0
  131. package/dist/{chunk-JVIBCBC7.js → chunk-EJLV62NI.js} +2 -2
  132. package/dist/{chunk-KKEESNPE.js → chunk-EYG2CY2X.js} +126 -19
  133. package/dist/chunk-EYG2CY2X.js.map +1 -0
  134. package/dist/{enclave-55PAM4YO.js → chunk-EZGV6F47.js} +83 -56
  135. package/dist/chunk-EZGV6F47.js.map +1 -0
  136. package/dist/{chunk-CHQCZZWC.js → chunk-EZOAKKTB.js} +36 -27
  137. package/dist/chunk-EZOAKKTB.js.map +1 -0
  138. package/dist/chunk-F6NCB7KT.js +13 -0
  139. package/dist/chunk-F6NCB7KT.js.map +1 -0
  140. package/dist/chunk-FFJFE4T7.js +100 -0
  141. package/dist/chunk-FFJFE4T7.js.map +1 -0
  142. package/dist/{chunk-JMGDHKQF.js → chunk-FLPCETP6.js} +2 -2
  143. package/dist/chunk-FOEDQATO.js +53 -0
  144. package/dist/chunk-FOEDQATO.js.map +1 -0
  145. package/dist/{chunk-DGOZ4UZD.js → chunk-FVH5QYY2.js} +2 -2
  146. package/dist/{chunk-HIWCKBEY.js → chunk-G2MVBDFP.js} +54 -28
  147. package/dist/chunk-G2MVBDFP.js.map +1 -0
  148. package/dist/chunk-GMKGGY7V.js +234 -0
  149. package/dist/chunk-GMKGGY7V.js.map +1 -0
  150. package/dist/{chunk-EIPVYUEP.js → chunk-GQ4MF3CM.js} +3 -3
  151. package/dist/chunk-GQ4MF3CM.js.map +1 -0
  152. package/dist/{chunk-PEOZ34EM.js → chunk-GSAK56VF.js} +1 -1
  153. package/dist/chunk-GSAK56VF.js.map +1 -0
  154. package/dist/{chunk-5VCRVKOZ.js → chunk-GUZET4SG.js} +12 -4
  155. package/dist/chunk-GUZET4SG.js.map +1 -0
  156. package/dist/{chunk-JBDFMYKQ.js → chunk-GZT3NQRA.js} +2 -2
  157. package/dist/{chunk-K23VKTN4.js → chunk-H23XHRTT.js} +19 -34
  158. package/dist/chunk-H23XHRTT.js.map +1 -0
  159. package/dist/{chunk-TFR7DSOV.js → chunk-H427H63K.js} +2 -2
  160. package/dist/{chunk-DFMWUOU5.js → chunk-H7JBY4P7.js} +23 -32
  161. package/dist/chunk-H7JBY4P7.js.map +1 -0
  162. package/dist/{chunk-SKGMN35F.js → chunk-HS554XAF.js} +3 -3
  163. package/dist/chunk-HS554XAF.js.map +1 -0
  164. package/dist/{chunk-HK67PX4J.js → chunk-HW7CMKUG.js} +1 -1
  165. package/dist/chunk-HW7CMKUG.js.map +1 -0
  166. package/dist/{chunk-3BVH633C.js → chunk-IMQKWR46.js} +5 -7
  167. package/dist/chunk-IMQKWR46.js.map +1 -0
  168. package/dist/{chunk-R42NSZI6.js → chunk-IUBMZPHM.js} +7 -7
  169. package/dist/chunk-IUBMZPHM.js.map +1 -0
  170. package/dist/{chunk-CUQPWYRX.js → chunk-IUT3GWP3.js} +75 -386
  171. package/dist/chunk-IUT3GWP3.js.map +1 -0
  172. package/dist/{chunk-RF6D3Y5E.js → chunk-JDEYF3PJ.js} +4 -8
  173. package/dist/{chunk-RF6D3Y5E.js.map → chunk-JDEYF3PJ.js.map} +1 -1
  174. package/dist/{chunk-PPTHY5QO.js → chunk-JIBUPZHA.js} +99 -8
  175. package/dist/chunk-JIBUPZHA.js.map +1 -0
  176. package/dist/{chunk-SMH6SRX7.js → chunk-JOSPH3E5.js} +2 -2
  177. package/dist/chunk-JQYKPKG6.js +193 -0
  178. package/dist/chunk-JQYKPKG6.js.map +1 -0
  179. package/dist/{chunk-7APJ6CO6.js → chunk-JSMTXZR3.js} +45 -13
  180. package/dist/chunk-JSMTXZR3.js.map +1 -0
  181. package/dist/chunk-JWWYRR4Q.js +12 -0
  182. package/dist/chunk-JWWYRR4Q.js.map +1 -0
  183. package/dist/{chunk-BVN6KXL2.js → chunk-KZXDLBY6.js} +14 -9
  184. package/dist/chunk-KZXDLBY6.js.map +1 -0
  185. package/dist/chunk-LGNDFRYC.js +23 -0
  186. package/dist/chunk-LGNDFRYC.js.map +1 -0
  187. package/dist/{chunk-XKWGNJ26.js → chunk-LIOVX5TJ.js} +7 -11
  188. package/dist/chunk-LIOVX5TJ.js.map +1 -0
  189. package/dist/{chunk-AYX7AINO.js → chunk-LNSVGRHO.js} +5 -7
  190. package/dist/chunk-LNSVGRHO.js.map +1 -0
  191. package/dist/chunk-M5B2W6YY.js +293 -0
  192. package/dist/chunk-M5B2W6YY.js.map +1 -0
  193. package/dist/chunk-MBMTND6D.js +456 -0
  194. package/dist/chunk-MBMTND6D.js.map +1 -0
  195. package/dist/{chunk-3BZZJJMQ.js → chunk-MILI22XQ.js} +3 -3
  196. package/dist/{chunk-A2HKRLPV.js → chunk-MXKI4ABF.js} +18 -59
  197. package/dist/chunk-MXKI4ABF.js.map +1 -0
  198. package/dist/{chunk-ZYIYHJ5R.js → chunk-MXOQ5JCG.js} +869 -238
  199. package/dist/chunk-MXOQ5JCG.js.map +1 -0
  200. package/dist/{chunk-V7ZRRCRJ.js → chunk-N7EVQD5S.js} +9 -13
  201. package/dist/chunk-N7EVQD5S.js.map +1 -0
  202. package/dist/chunk-N7UDP5VU.js +757 -0
  203. package/dist/chunk-N7UDP5VU.js.map +1 -0
  204. package/dist/chunk-NBQ3KK6X.js +270 -0
  205. package/dist/chunk-NBQ3KK6X.js.map +1 -0
  206. package/dist/{chunk-ZORTV6NH.js → chunk-NCO25JZO.js} +88 -4
  207. package/dist/chunk-NCO25JZO.js.map +1 -0
  208. package/dist/chunk-NH2UOV3B.js +18 -0
  209. package/dist/chunk-NH2UOV3B.js.map +1 -0
  210. package/dist/chunk-NYMLINRP.js +28 -0
  211. package/dist/chunk-NYMLINRP.js.map +1 -0
  212. package/dist/{chunk-YYP7WSEB.js → chunk-O2IMQSNA.js} +2 -2
  213. package/dist/chunk-O46CHQT7.js +215 -0
  214. package/dist/chunk-O46CHQT7.js.map +1 -0
  215. package/dist/chunk-OIEO4WDL.js +27 -0
  216. package/dist/chunk-OIEO4WDL.js.map +1 -0
  217. package/dist/{chunk-TRGTKX5E.js → chunk-OKSTSITU.js} +27 -4
  218. package/dist/chunk-OKSTSITU.js.map +1 -0
  219. package/dist/chunk-OYW3I5M4.js +31 -0
  220. package/dist/chunk-OYW3I5M4.js.map +1 -0
  221. package/dist/{chunk-Q7HZX3IF.js → chunk-PD64727P.js} +2 -2
  222. package/dist/chunk-PD64727P.js.map +1 -0
  223. package/dist/{chunk-FET5XCAT.js → chunk-PP3K67AJ.js} +34 -6
  224. package/dist/chunk-PP3K67AJ.js.map +1 -0
  225. package/dist/chunk-Q2XRFWOI.js +40 -0
  226. package/dist/chunk-Q2XRFWOI.js.map +1 -0
  227. package/dist/{chunk-QIZPZMUI.js → chunk-Q4UHJ5SN.js} +2 -2
  228. package/dist/{chunk-FAHMLERK.js → chunk-QBLT6POL.js} +2 -2
  229. package/dist/chunk-QMWY2FDS.js +157 -0
  230. package/dist/chunk-QMWY2FDS.js.map +1 -0
  231. package/dist/{chunk-LH5A3ZPG.js → chunk-RB4DOPGZ.js} +150 -22
  232. package/dist/chunk-RB4DOPGZ.js.map +1 -0
  233. package/dist/chunk-RHVMZSUU.js +7 -0
  234. package/dist/chunk-RHVMZSUU.js.map +1 -0
  235. package/dist/{chunk-BUE2D7PX.js → chunk-SMV2HRDU.js} +2 -2
  236. package/dist/chunk-SUZKW6UR.js +25 -0
  237. package/dist/chunk-SUZKW6UR.js.map +1 -0
  238. package/dist/{chunk-7MG7SJT7.js → chunk-SV2PM2OY.js} +1 -1
  239. package/dist/chunk-SV2PM2OY.js.map +1 -0
  240. package/dist/{chunk-UXVWEX5L.js → chunk-SYNY3VB5.js} +6 -2
  241. package/dist/chunk-SYNY3VB5.js.map +1 -0
  242. package/dist/{chunk-4GFX6MPA.js → chunk-TEHHROZL.js} +6 -8
  243. package/dist/chunk-TEHHROZL.js.map +1 -0
  244. package/dist/chunk-TKVUE4JF.js +1289 -0
  245. package/dist/chunk-TKVUE4JF.js.map +1 -0
  246. package/dist/{chunk-SFAWCTEM.js → chunk-TZZBXPZK.js} +2 -2
  247. package/dist/{chunk-F3W6YMDC.js → chunk-U2FZNEWJ.js} +4 -4
  248. package/dist/chunk-U2FZNEWJ.js.map +1 -0
  249. package/dist/{chunk-BLN54W3L.js → chunk-UA372JHH.js} +56 -3
  250. package/dist/chunk-UA372JHH.js.map +1 -0
  251. package/dist/{chunk-6YXCPL4T.js → chunk-UEFOQH74.js} +2 -2
  252. package/dist/chunk-UEFOQH74.js.map +1 -0
  253. package/dist/{chunk-2N5ML6HT.js → chunk-UIYESRD6.js} +9 -11
  254. package/dist/chunk-UIYESRD6.js.map +1 -0
  255. package/dist/{chunk-UHHPLO3I.js → chunk-V3RWOOSO.js} +4 -4
  256. package/dist/{chunk-KTFRCC5C.js → chunk-V7ADQF5O.js} +82 -8
  257. package/dist/chunk-V7ADQF5O.js.map +1 -0
  258. package/dist/{chunk-453F654R.js → chunk-VAORSCSU.js} +3 -3
  259. package/dist/chunk-VAORSCSU.js.map +1 -0
  260. package/dist/{chunk-GPNTB4Y7.js → chunk-VFHCKG5M.js} +6 -10
  261. package/dist/chunk-VFHCKG5M.js.map +1 -0
  262. package/dist/{chunk-2577DKXB.js → chunk-VHBKYN2J.js} +3 -3
  263. package/dist/chunk-VHBKYN2J.js.map +1 -0
  264. package/dist/chunk-VHM7HCKB.js +220 -0
  265. package/dist/chunk-VHM7HCKB.js.map +1 -0
  266. package/dist/{chunk-ZHKOPKE3.js → chunk-VKI2EB3N.js} +3 -3
  267. package/dist/chunk-VKI2EB3N.js.map +1 -0
  268. package/dist/{chunk-UDHWDSRL.js → chunk-VMV5SBE4.js} +16 -17
  269. package/dist/chunk-VMV5SBE4.js.map +1 -0
  270. package/dist/{chunk-SPYWXKJN.js → chunk-VQDZYB2B.js} +3 -3
  271. package/dist/chunk-VQDZYB2B.js.map +1 -0
  272. package/dist/{chunk-Q2PU57HC.js → chunk-VVOLDVIR.js} +2 -2
  273. package/dist/{chunk-3VF3WQ4F.js → chunk-WPOYWFSE.js} +7 -7
  274. package/dist/{chunk-3VF3WQ4F.js.map → chunk-WPOYWFSE.js.map} +1 -1
  275. package/dist/{chunk-OTQZ7ZWU.js → chunk-WXE4W2U6.js} +7 -11
  276. package/dist/chunk-WXE4W2U6.js.map +1 -0
  277. package/dist/chunk-XBKH4FOC.js +195 -0
  278. package/dist/chunk-XBKH4FOC.js.map +1 -0
  279. package/dist/{chunk-TUFM4UZP.js → chunk-XQRFSKYM.js} +2 -2
  280. package/dist/{chunk-3V4KWFX7.js → chunk-XSPFDUDG.js} +58 -53
  281. package/dist/chunk-XSPFDUDG.js.map +1 -0
  282. package/dist/{chunk-GY4WYNNG.js → chunk-Y2RKVFKR.js} +2 -2
  283. package/dist/{chunk-UP4BECPY.js → chunk-Y3LPTBG7.js} +89 -27
  284. package/dist/chunk-Y3LPTBG7.js.map +1 -0
  285. package/dist/{chunk-4OZNXTO4.js → chunk-YRXFFWG4.js} +2 -2
  286. package/dist/classified/index.js +5 -5
  287. package/dist/{classified-marker-BWOFVYAC.js → classified-marker-SIYKUU5L.js} +3 -3
  288. package/dist/classified-marker-SIYKUU5L.js.map +1 -0
  289. package/dist/collection-facade-CS7CA2XO.js +47 -0
  290. package/dist/{computed-VPOKQK4N.js → computed-FAD7SED4.js} +3 -3
  291. package/dist/consent/index.js +10 -11
  292. package/dist/consent/index.js.map +1 -1
  293. package/dist/cover/index.js +10 -11
  294. package/dist/coverage/index.js +306 -0
  295. package/dist/coverage/index.js.map +1 -0
  296. package/dist/custody/index.js +12 -13
  297. package/dist/{dead-filter-PKQDLOT4.js → dead-filter-4F3LWYKH.js} +11 -3
  298. package/dist/dead-filter-4F3LWYKH.js.map +1 -0
  299. package/dist/debug/index.js +11 -2
  300. package/dist/debug/index.js.map +1 -1
  301. package/dist/{delegation-DS5NRILW.js → delegation-NANZDG4N.js} +13 -16
  302. package/dist/delegation-NANZDG4N.js.map +1 -0
  303. package/dist/derivations/index.js +25 -23
  304. package/dist/derive-XLOJVXPU.js +20 -0
  305. package/dist/directory/index.js +10 -11
  306. package/dist/{dispatch-IEPAVQUM.js → dispatch-H4HV32AM.js} +5 -5
  307. package/dist/{dispatch-Q6MWLOJY.js → dispatch-JDZNGEB3.js} +20 -21
  308. package/dist/dispatch-JDZNGEB3.js.map +1 -0
  309. package/dist/executor-FMPVN6DT.js +35 -0
  310. package/dist/executor-LBBBRTN5.js +8 -0
  311. package/dist/executor-OSRZST2U.js +8 -0
  312. package/dist/export-accessible-RAOJAAU5.js +22 -0
  313. package/dist/extract-partition-JD5CUSTG.js +37 -0
  314. package/dist/{fanout-sidecar-S3QL53YX.js → fanout-sidecar-L7NHPIOC.js} +13 -15
  315. package/dist/fanout-sidecar-L7NHPIOC.js.map +1 -0
  316. package/dist/find-JRN4RNQ5.js +10 -0
  317. package/dist/forget/index.js +9 -10
  318. package/dist/forget/index.js.map +1 -1
  319. package/dist/guards/index.js +4 -4
  320. package/dist/history/index.js +13 -14
  321. package/dist/history/index.js.map +1 -1
  322. package/dist/i18n/index.js +14 -15
  323. package/dist/i18n/index.js.map +1 -1
  324. package/dist/index.d.ts +36 -14
  325. package/dist/index.js +970 -163
  326. package/dist/index.js.map +1 -1
  327. package/dist/indexing/index.js +13 -5
  328. package/dist/indexing/index.js.map +1 -1
  329. package/dist/introspection/index.js +11 -12
  330. package/dist/issue-YIVBZUTH.js +19 -0
  331. package/dist/ivf-flat-UZ6DQDLS.js +314 -0
  332. package/dist/ivf-flat-UZ6DQDLS.js.map +1 -0
  333. package/dist/{json-schema-V3M5MUCM.js → json-schema-3SHX72CC.js} +2 -1
  334. package/dist/json-schema-3SHX72CC.js.map +1 -0
  335. package/dist/kernel/attestation-types.d.ts +62 -0
  336. package/dist/kernel/collection-config.d.ts +5 -68
  337. package/dist/kernel/collection.d.ts +30 -9
  338. package/dist/kernel/cutover-transform.d.ts +1 -1
  339. package/dist/kernel/errors.d.ts +257 -38
  340. package/dist/kernel/generation-map.d.ts +48 -0
  341. package/dist/kernel/merge-authority.d.ts +1 -1
  342. package/dist/kernel/noydb.d.ts +6 -1
  343. package/dist/kernel/paths.d.ts +29 -5
  344. package/dist/kernel/prepared-write.d.ts +1 -1
  345. package/dist/kernel/present-cache.d.ts +58 -0
  346. package/dist/kernel/query/all.d.ts +7 -0
  347. package/dist/kernel/query/builder.d.ts +601 -270
  348. package/dist/kernel/query/civil-date.d.ts +64 -0
  349. package/dist/kernel/query/cursor.d.ts +40 -0
  350. package/dist/kernel/query/distinct-key.d.ts +98 -0
  351. package/dist/kernel/query/hydration.d.ts +76 -0
  352. package/dist/kernel/query/index.d.ts +31 -15
  353. package/dist/kernel/query/internal/core.d.ts +30 -0
  354. package/dist/kernel/query/internal/hooks.d.ts +22 -0
  355. package/dist/kernel/query/internal/maintenance.d.ts +43 -0
  356. package/dist/kernel/query/live/incremental.d.ts +314 -0
  357. package/dist/kernel/query/live/index.d.ts +22 -0
  358. package/dist/kernel/query/live/install.d.ts +2 -0
  359. package/dist/kernel/query/{live.d.ts → live/live.d.ts} +39 -9
  360. package/dist/kernel/query/live/methods.d.ts +107 -0
  361. package/dist/kernel/query/predicate.d.ts +119 -1
  362. package/dist/kernel/query/reduce/date-trunc.d.ts +75 -0
  363. package/dist/kernel/query/reduce/index.d.ts +36 -0
  364. package/dist/kernel/query/reduce/install.d.ts +2 -0
  365. package/dist/kernel/query/reduce/methods.d.ts +259 -0
  366. package/dist/kernel/query/reduce/scan-methods.d.ts +121 -0
  367. package/dist/kernel/query/relate/explain.d.ts +199 -0
  368. package/dist/kernel/query/relate/index.d.ts +48 -0
  369. package/dist/kernel/query/relate/install.d.ts +2 -0
  370. package/dist/kernel/query/relate/join-on.d.ts +126 -0
  371. package/dist/kernel/query/relate/join-reduce.d.ts +16 -0
  372. package/dist/kernel/query/relate/join.d.ts +452 -0
  373. package/dist/kernel/query/relate/methods.d.ts +426 -0
  374. package/dist/kernel/query/relate/partition.d.ts +87 -0
  375. package/dist/kernel/query/relate/scan-methods.d.ts +163 -0
  376. package/dist/kernel/query/relate/traverse.d.ts +109 -0
  377. package/dist/kernel/query/scan-builder.d.ts +79 -176
  378. package/dist/kernel/query/sort-key.d.ts +52 -0
  379. package/dist/kernel/secret-mode.d.ts +1 -1
  380. package/dist/kernel/tx-write-gate.d.ts +77 -0
  381. package/dist/kernel/types.d.ts +113 -8
  382. package/dist/kernel/validation.d.ts +27 -10
  383. package/dist/kernel/vault.d.ts +11 -6
  384. package/dist/kernel/via/compose.d.ts +3 -0
  385. package/dist/kernel/via/index.d.ts +56 -0
  386. package/dist/kernel/via/pipeline.d.ts +48 -0
  387. package/dist/kernel/write-queue.d.ts +17 -0
  388. package/dist/{ledger-EDXFFZQL.js → ledger-5ZMGE44K.js} +11 -12
  389. package/dist/liberate-WZSZM2W6.js +24 -0
  390. package/dist/link-set-MFXC24VK.js +29 -0
  391. package/dist/{managed-secret-NCWEMPUQ.js → managed-secret-MFTFT22X.js} +10 -11
  392. package/dist/materialized-views/index.js +30 -24
  393. package/dist/{migrate-cek-5ENH64AA.js → migrate-cek-DZRFFOHW.js} +2 -2
  394. package/dist/money/index.js +5 -5
  395. package/dist/noydb-ITIGNKUF.js +96 -0
  396. package/dist/overlay-views/index.js +4 -4
  397. package/dist/periods/index.js +12 -13
  398. package/dist/pod/index.js +74 -67
  399. package/dist/{pod-handle-ECVCDIXW.js → pod-handle-A3LET7NO.js} +10 -11
  400. package/dist/pod-handle-A3LET7NO.js.map +1 -0
  401. package/dist/policy/index.js +10 -11
  402. package/dist/port/on/index.d.ts +1 -1
  403. package/dist/port/to/index.d.ts +1 -1
  404. package/dist/port/with/blob-strategy.d.ts +10 -1
  405. package/dist/port/with/classified-strategy.d.ts +1 -1
  406. package/dist/port/with/collection-options.d.ts +6 -1
  407. package/dist/port/with/collection-registries.d.ts +1 -1
  408. package/dist/port/with/coverage-strategy.d.ts +83 -0
  409. package/dist/port/with/lookup-strategy.d.ts +2 -2
  410. package/dist/port/with/service-bus.d.ts +46 -0
  411. package/dist/port/with/strategies.d.ts +2 -0
  412. package/dist/portability/index.js +8 -8
  413. package/dist/{post-register-3IPCSG6Q.js → post-register-7ND27CF2.js} +6 -6
  414. package/dist/post-register-7ND27CF2.js.map +1 -0
  415. package/dist/query/all/index.js +31 -0
  416. package/dist/query/index.js +20 -32
  417. package/dist/query/live/index.js +21 -0
  418. package/dist/query/live/index.js.map +1 -0
  419. package/dist/query/reduce/index.js +33 -0
  420. package/dist/query/reduce/index.js.map +1 -0
  421. package/dist/query/relate/index.js +56 -0
  422. package/dist/query/relate/index.js.map +1 -0
  423. package/dist/reduce/index.js +72 -18
  424. package/dist/reduce/index.js.map +1 -1
  425. package/dist/register-DT5HZ2LZ.js +30 -0
  426. package/dist/registry-BHRZGZHF.js +8 -0
  427. package/dist/registry-ET6ZFFWA.js +34 -0
  428. package/dist/registry-HXFGLGTG.js +8 -0
  429. package/dist/registry-THCPDEOD.js +23 -0
  430. package/dist/request-withdrawal-AV2MJJKY.js +30 -0
  431. package/dist/{reveal-QZDHSGD4.js → reveal-B2TLP4JQ.js} +10 -9
  432. package/dist/reveal-B2TLP4JQ.js.map +1 -0
  433. package/dist/revoke-6DWIEOCV.js +24 -0
  434. package/dist/satellites/index.js +1 -1
  435. package/dist/schema-update/index.js +2 -2
  436. package/dist/sealed-record/index.js +16 -18
  437. package/dist/sealed-record/index.js.map +1 -1
  438. package/dist/search/index.js +11 -5
  439. package/dist/{seed-X5CC22CQ.js → seed-XNSE4U3S.js} +15 -18
  440. package/dist/seed-XNSE4U3S.js.map +1 -0
  441. package/dist/sequence/index.js +9 -10
  442. package/dist/session/index.js +9 -10
  443. package/dist/session/index.js.map +1 -1
  444. package/dist/shadow/index.js +2 -2
  445. package/dist/signer-MHGW3OIL.js +23 -0
  446. package/dist/snapshots/index.js +11 -11
  447. package/dist/stale-6GCFMOOR.js +28 -0
  448. package/dist/storage-BYN5LO6Z.js +21 -0
  449. package/dist/storage-BYN5LO6Z.js.map +1 -0
  450. package/dist/store/index.js +1 -1
  451. package/dist/{store-coordination-provider-4WZAIRHC.js → store-coordination-provider-C4BPT5XF.js} +11 -12
  452. package/dist/store-coordination-provider-C4BPT5XF.js.map +1 -0
  453. package/dist/sync/index.js +10 -11
  454. package/dist/sync/index.js.map +1 -1
  455. package/dist/team/index.js +17 -16
  456. package/dist/tiers/index.js +13 -12
  457. package/dist/to/index.js +2 -2
  458. package/dist/transactions/index.js +3 -3
  459. package/dist/util/index.js +1 -1
  460. package/dist/vault-head/index.js +11 -14
  461. package/dist/vault-head/index.js.map +1 -1
  462. package/dist/{verify-6MDTIUEV.js → verify-UKALW7C2.js} +14 -12
  463. package/dist/verify-UKALW7C2.js.map +1 -0
  464. package/dist/via/blob/index.d.ts +1 -0
  465. package/dist/via/classified/binding.d.ts +2 -2
  466. package/dist/via/classified/config-drift.d.ts +2 -2
  467. package/dist/via/classified/errors.d.ts +1 -1
  468. package/dist/via/geo/binding.d.ts +31 -0
  469. package/dist/via/geo/descriptor.d.ts +54 -0
  470. package/dist/via/geo/geohash.d.ts +95 -0
  471. package/dist/via/geo/index.d.ts +13 -0
  472. package/dist/via/geo/where.d.ts +50 -0
  473. package/dist/via/i18n/core.d.ts +1 -1
  474. package/dist/via/lookup/handle.d.ts +4 -4
  475. package/dist/via/lookup/registry.d.ts +1 -1
  476. package/dist/via/lookup/snapshot.d.ts +3 -3
  477. package/dist/walk-4VPK7AS4.js +20 -0
  478. package/dist/walk-4VPK7AS4.js.map +1 -0
  479. package/dist/with-audit/attestation/index.d.ts +2 -1
  480. package/dist/with-audit/attestation/issue.d.ts +2 -2
  481. package/dist/with-audit/attestation/revoke.d.ts +2 -2
  482. package/dist/with-audit/attestation/scheme.d.ts +7 -0
  483. package/dist/with-audit/attestation/signer.d.ts +1 -1
  484. package/dist/with-audit/attestation/strategy.d.ts +2 -2
  485. package/dist/with-audit/attestation/types.d.ts +10 -0
  486. package/dist/with-audit/attestation/vault-facade.d.ts +2 -2
  487. package/dist/with-audit/attestation/verifier.d.ts +6 -0
  488. package/dist/with-audit/consent/consent.d.ts +1 -1
  489. package/dist/with-audit/consent/strategy.d.ts +1 -1
  490. package/dist/with-audit/coverage/accounting.d.ts +112 -0
  491. package/dist/with-audit/coverage/active.d.ts +29 -0
  492. package/dist/with-audit/coverage/index.d.ts +61 -0
  493. package/dist/with-audit/coverage/sketch.d.ts +75 -0
  494. package/dist/with-audit/forget/subject-index.d.ts +1 -1
  495. package/dist/with-audit/periods/periods.d.ts +55 -7
  496. package/dist/with-audit/periods/reserved-collections.d.ts +3 -0
  497. package/dist/with-audit/periods/vault-facade.d.ts +18 -1
  498. package/dist/with-audit/sealed-record/index.d.ts +2 -2
  499. package/dist/with-audit/sealed-record/strategy.d.ts +1 -1
  500. package/dist/with-audit/tiers/index.d.ts +53 -2
  501. package/dist/with-audit/tiers/strategy.d.ts +8 -0
  502. package/dist/with-cargo/adopt-partition.d.ts +1 -1
  503. package/dist/with-cargo/extract-partition.d.ts +1 -1
  504. package/dist/with-cargo/floor.d.ts +3 -3
  505. package/dist/with-commit/history/history.d.ts +2 -2
  506. package/dist/with-commit/history/index.d.ts +1 -1
  507. package/dist/with-commit/history/ledger/store.d.ts +1 -1
  508. package/dist/with-commit/history/strategy.d.ts +1 -1
  509. package/dist/with-commit/history/time-machine.d.ts +1 -1
  510. package/dist/with-commit/numbering/index.d.ts +1 -1
  511. package/dist/with-commit/sequence/index.d.ts +1 -1
  512. package/dist/with-commit/tx/invariants.d.ts +1 -1
  513. package/dist/with-commit/tx/transaction.d.ts +13 -3
  514. package/dist/with-commit/vault-head/head.d.ts +1 -1
  515. package/dist/with-commit/vault-head/index.d.ts +1 -1
  516. package/dist/with-commit/vault-head/strategy.d.ts +1 -1
  517. package/dist/with-commit/vault-head/verify.d.ts +1 -1
  518. package/dist/with-formula/derivations/dispatch.d.ts +1 -1
  519. package/dist/with-formula/derivations/fanout-sidecar.d.ts +1 -1
  520. package/dist/with-formula/materialized-views/dependency-analyzer.d.ts +4 -3
  521. package/dist/with-formula/materialized-views/emit-memo.d.ts +40 -0
  522. package/dist/with-formula/materialized-views/executor.d.ts +8 -0
  523. package/dist/with-formula/materialized-views/index.d.ts +1 -1
  524. package/dist/with-formula/materialized-views/registry.d.ts +15 -0
  525. package/dist/with-formula/materialized-views/types.d.ts +106 -14
  526. package/dist/with-formula/materialized-views/window-stage.d.ts +11 -0
  527. package/dist/with-formula/overlay-views/types.d.ts +1 -1
  528. package/dist/with-formula/overlay-views/virtual-collection.d.ts +13 -4
  529. package/dist/with-lookup/embeddings/chunks.d.ts +79 -0
  530. package/dist/with-lookup/embeddings/descriptor.d.ts +21 -0
  531. package/dist/with-lookup/embeddings/index.d.ts +3 -0
  532. package/dist/with-lookup/embeddings/ivf-flat.d.ts +93 -0
  533. package/dist/with-lookup/embeddings/vector-index.d.ts +73 -0
  534. package/dist/with-lookup/embeddings/vector-set.d.ts +94 -1
  535. package/dist/with-lookup/embeddings/with-vector-index.d.ts +67 -0
  536. package/dist/with-lookup/indexing/collection-facade.d.ts +86 -3
  537. package/dist/with-lookup/indexing/compound-indexes.d.ts +129 -0
  538. package/dist/with-lookup/indexing/eager-indexes.d.ts +170 -1
  539. package/dist/with-lookup/indexing/index-snapshot.d.ts +62 -0
  540. package/dist/with-lookup/indexing/lazy-builder.d.ts +33 -0
  541. package/dist/with-lookup/indexing/persisted-field-indexes.d.ts +104 -0
  542. package/dist/with-lookup/indexing/persisted-indexes.d.ts +12 -0
  543. package/dist/with-lookup/indexing/sorted-indexes.d.ts +117 -0
  544. package/dist/with-lookup/indexing/unique-constraints.d.ts +106 -23
  545. package/dist/with-lookup/reduce/active.d.ts +2 -24
  546. package/dist/with-lookup/reduce/group-core.d.ts +43 -0
  547. package/dist/with-lookup/reduce/groupby.d.ts +195 -36
  548. package/dist/with-lookup/reduce/incremental-group.d.ts +153 -0
  549. package/dist/with-lookup/reduce/index.d.ts +26 -5
  550. package/dist/with-lookup/reduce/reducers.d.ts +255 -1
  551. package/dist/with-lookup/reduce/reduction.d.ts +44 -13
  552. package/dist/with-lookup/reduce/strategy.d.ts +43 -3
  553. package/dist/with-lookup/reduce/window.d.ts +262 -0
  554. package/dist/with-lookup/search/collection-facade.d.ts +45 -9
  555. package/dist/with-lookup/search/index-store.d.ts +5 -3
  556. package/dist/with-lookup/search/index.d.ts +4 -2
  557. package/dist/with-lookup/search/inverted-index.d.ts +38 -2
  558. package/dist/with-lookup/search/persisted-index-store.d.ts +5 -2
  559. package/dist/with-lookup/search/phrase.d.ts +28 -0
  560. package/dist/with-lookup/search/retrieve-types.d.ts +57 -1
  561. package/dist/with-lookup/search/serialize.d.ts +29 -3
  562. package/dist/with-lookup/search/strategy.d.ts +2 -6
  563. package/dist/with-party/broker/index.d.ts +3 -3
  564. package/dist/with-party/directory/cover/index.d.ts +1 -1
  565. package/dist/with-party/directory/cover/storage.d.ts +1 -1
  566. package/dist/with-party/directory/cover/types.d.ts +1 -1
  567. package/dist/with-party/directory/index.d.ts +1 -1
  568. package/dist/with-party/directory/types.d.ts +1 -1
  569. package/dist/with-party/directory/user-envelope/api.d.ts +1 -1
  570. package/dist/with-party/directory/user-envelope/storage.d.ts +1 -1
  571. package/dist/with-party/policy/engine.d.ts +1 -1
  572. package/dist/with-party/policy/index.d.ts +1 -1
  573. package/dist/with-party/policy/presets.d.ts +1 -1
  574. package/dist/with-party/team/authenticators.d.ts +91 -1
  575. package/dist/with-party/team/delegation.d.ts +1 -1
  576. package/dist/with-party/team/echo-secret.d.ts +2 -2
  577. package/dist/with-party/team/index.d.ts +4 -3
  578. package/dist/with-party/team/keyring.d.ts +2 -2
  579. package/dist/with-party/team/magic-link-grant.d.ts +1 -1
  580. package/dist/with-party/team/managed-secret.d.ts +1 -1
  581. package/dist/with-party/team/noydb-facade.d.ts +12 -3
  582. package/dist/with-party/team/recovery.d.ts +1 -1
  583. package/dist/with-party/team/roster-tag.d.ts +1 -1
  584. package/dist/with-party/team/rotate-recover.d.ts +1 -1
  585. package/dist/with-party/team/wrapped-deks.d.ts +1 -1
  586. package/dist/with-pod/format.d.ts +1 -1
  587. package/dist/with-pod/index.d.ts +1 -1
  588. package/dist/with-pod/pod.d.ts +1 -1
  589. package/dist/with-shape/blobs/blob-compaction.d.ts +17 -1
  590. package/dist/with-shape/blobs/blob-intent.d.ts +1 -1
  591. package/dist/with-shape/blobs/blob-set.d.ts +23 -4
  592. package/dist/with-shape/blobs/legacy-sweep.d.ts +35 -0
  593. package/dist/with-shape/introspection/describe.d.ts +7 -1
  594. package/dist/with-shape/introspection/field-meta.d.ts +18 -0
  595. package/dist/with-shape/introspection/types.d.ts +57 -1
  596. package/dist/with-shape/introspection/walk.d.ts +1 -1
  597. package/dist/with-shape/links/lazy-handle.d.ts +1 -1
  598. package/dist/with-shape/links/link-set.d.ts +1 -1
  599. package/dist/with-shape/links/vault-facade.d.ts +1 -1
  600. package/dist/with-shape/manifest/derive.d.ts +1 -1
  601. package/dist/with-shape/manifest/storage.d.ts +1 -1
  602. package/dist/with-shape/persisted-schemas/register.d.ts +1 -1
  603. package/dist/with-shape/persisted-schemas/storage.d.ts +1 -1
  604. package/dist/with-shape/satellites/dead-filter.d.ts +1 -1
  605. package/dist/with-shape/satellites/declare.d.ts +1 -1
  606. package/dist/with-shape/satellites/marker.d.ts +1 -1
  607. package/dist/with-shape/satellites/post-register.d.ts +1 -1
  608. package/dist/with-store/partitioned/index.d.ts +337 -0
  609. package/dist/with-sync/change-broadcast.d.ts +153 -0
  610. package/dist/with-sync/presence.d.ts +5 -10
  611. package/dist/withdraw-accessible-HL7GACUE.js +27 -0
  612. package/dist/withdraw-accessible-HL7GACUE.js.map +1 -0
  613. package/package.json +48 -12
  614. package/dist/api-WYW4YEQG.js +0 -19
  615. package/dist/backup-XKCXVKV3.js.map +0 -1
  616. package/dist/chunk-2577DKXB.js.map +0 -1
  617. package/dist/chunk-2ENE6445.js.map +0 -1
  618. package/dist/chunk-2N5ML6HT.js.map +0 -1
  619. package/dist/chunk-334WSVOW.js.map +0 -1
  620. package/dist/chunk-3BVH633C.js.map +0 -1
  621. package/dist/chunk-3PGS7TYR.js.map +0 -1
  622. package/dist/chunk-3V4KWFX7.js.map +0 -1
  623. package/dist/chunk-453F654R.js.map +0 -1
  624. package/dist/chunk-4GFX6MPA.js.map +0 -1
  625. package/dist/chunk-4GVM6QZA.js.map +0 -1
  626. package/dist/chunk-4ZS56W5S.js.map +0 -1
  627. package/dist/chunk-5VCRVKOZ.js.map +0 -1
  628. package/dist/chunk-6YXCPL4T.js.map +0 -1
  629. package/dist/chunk-7APJ6CO6.js.map +0 -1
  630. package/dist/chunk-7MG2LHO5.js +0 -1616
  631. package/dist/chunk-7MG2LHO5.js.map +0 -1
  632. package/dist/chunk-7MG7SJT7.js.map +0 -1
  633. package/dist/chunk-7O3Y4PPD.js.map +0 -1
  634. package/dist/chunk-A2HKRLPV.js.map +0 -1
  635. package/dist/chunk-A66I4JOA.js.map +0 -1
  636. package/dist/chunk-ACAQ2DSG.js.map +0 -1
  637. package/dist/chunk-ATL3ZVXT.js +0 -151
  638. package/dist/chunk-ATL3ZVXT.js.map +0 -1
  639. package/dist/chunk-AYX7AINO.js.map +0 -1
  640. package/dist/chunk-BLN54W3L.js.map +0 -1
  641. package/dist/chunk-BRLKZUBT.js +0 -95
  642. package/dist/chunk-BRLKZUBT.js.map +0 -1
  643. package/dist/chunk-BTDR2PXY.js +0 -29
  644. package/dist/chunk-BTDR2PXY.js.map +0 -1
  645. package/dist/chunk-BVN6KXL2.js.map +0 -1
  646. package/dist/chunk-CHQCZZWC.js.map +0 -1
  647. package/dist/chunk-CUQPWYRX.js.map +0 -1
  648. package/dist/chunk-CUZLNGD5.js.map +0 -1
  649. package/dist/chunk-DFMWUOU5.js.map +0 -1
  650. package/dist/chunk-EIPVYUEP.js.map +0 -1
  651. package/dist/chunk-EQEYOJBM.js.map +0 -1
  652. package/dist/chunk-F3W6YMDC.js.map +0 -1
  653. package/dist/chunk-FET5XCAT.js.map +0 -1
  654. package/dist/chunk-G73UVHCA.js.map +0 -1
  655. package/dist/chunk-GPNTB4Y7.js.map +0 -1
  656. package/dist/chunk-GYGLAVCX.js.map +0 -1
  657. package/dist/chunk-HIWCKBEY.js.map +0 -1
  658. package/dist/chunk-HJUWN7JN.js.map +0 -1
  659. package/dist/chunk-HK67PX4J.js.map +0 -1
  660. package/dist/chunk-HPVZCW43.js +0 -479
  661. package/dist/chunk-HPVZCW43.js.map +0 -1
  662. package/dist/chunk-I3ISCYT7.js +0 -159
  663. package/dist/chunk-I3ISCYT7.js.map +0 -1
  664. package/dist/chunk-K23VKTN4.js.map +0 -1
  665. package/dist/chunk-KKEESNPE.js.map +0 -1
  666. package/dist/chunk-KTFRCC5C.js.map +0 -1
  667. package/dist/chunk-LH5A3ZPG.js.map +0 -1
  668. package/dist/chunk-LP7BEXCT.js +0 -32
  669. package/dist/chunk-LP7BEXCT.js.map +0 -1
  670. package/dist/chunk-M4YPHYEH.js.map +0 -1
  671. package/dist/chunk-NSITFOCJ.js +0 -99
  672. package/dist/chunk-NSITFOCJ.js.map +0 -1
  673. package/dist/chunk-OTQZ7ZWU.js.map +0 -1
  674. package/dist/chunk-P3MG6QCN.js.map +0 -1
  675. package/dist/chunk-PEOZ34EM.js.map +0 -1
  676. package/dist/chunk-PPTHY5QO.js.map +0 -1
  677. package/dist/chunk-Q2MPFCQ7.js.map +0 -1
  678. package/dist/chunk-Q7HZX3IF.js.map +0 -1
  679. package/dist/chunk-QPQUVOZ2.js.map +0 -1
  680. package/dist/chunk-QTQUH4DS.js.map +0 -1
  681. package/dist/chunk-R42NSZI6.js.map +0 -1
  682. package/dist/chunk-R7BX2NB3.js.map +0 -1
  683. package/dist/chunk-RSGLUIO6.js.map +0 -1
  684. package/dist/chunk-RTBJ5IOO.js +0 -87
  685. package/dist/chunk-RTBJ5IOO.js.map +0 -1
  686. package/dist/chunk-SGZAIJCV.js.map +0 -1
  687. package/dist/chunk-SKGMN35F.js.map +0 -1
  688. package/dist/chunk-SPYWXKJN.js.map +0 -1
  689. package/dist/chunk-SZJ3DLZA.js +0 -66
  690. package/dist/chunk-SZJ3DLZA.js.map +0 -1
  691. package/dist/chunk-TRGTKX5E.js.map +0 -1
  692. package/dist/chunk-UDHWDSRL.js.map +0 -1
  693. package/dist/chunk-UP4BECPY.js.map +0 -1
  694. package/dist/chunk-UXVWEX5L.js.map +0 -1
  695. package/dist/chunk-V7ZRRCRJ.js.map +0 -1
  696. package/dist/chunk-WQBG4SZS.js.map +0 -1
  697. package/dist/chunk-XKWGNJ26.js.map +0 -1
  698. package/dist/chunk-YMUFFJCO.js.map +0 -1
  699. package/dist/chunk-ZHKOPKE3.js.map +0 -1
  700. package/dist/chunk-ZN4FD4PE.js +0 -364
  701. package/dist/chunk-ZN4FD4PE.js.map +0 -1
  702. package/dist/chunk-ZORTV6NH.js.map +0 -1
  703. package/dist/chunk-ZYIYHJ5R.js.map +0 -1
  704. package/dist/classified-marker-BWOFVYAC.js.map +0 -1
  705. package/dist/collection-facade-JSJYIKS4.js +0 -45
  706. package/dist/dead-filter-PKQDLOT4.js.map +0 -1
  707. package/dist/delegation-DS5NRILW.js.map +0 -1
  708. package/dist/derive-E642AOUB.js +0 -21
  709. package/dist/dispatch-Q6MWLOJY.js.map +0 -1
  710. package/dist/executor-5NIMLSKZ.js +0 -8
  711. package/dist/executor-7UQ3BZ4F.js +0 -29
  712. package/dist/executor-AQVXV5GZ.js +0 -8
  713. package/dist/export-accessible-ORMKLA3E.js +0 -22
  714. package/dist/extract-partition-NKYO3WNG.js +0 -37
  715. package/dist/fanout-sidecar-S3QL53YX.js.map +0 -1
  716. package/dist/find-NOGJ25VX.js +0 -10
  717. package/dist/issue-3DTQ7VJJ.js +0 -18
  718. package/dist/json-schema-V3M5MUCM.js.map +0 -1
  719. package/dist/kernel/enclave/classify/compare.d.ts +0 -10
  720. package/dist/kernel/enclave/index.d.ts +0 -87
  721. package/dist/kernel/enclave/record-keys/lifecycle.d.ts +0 -124
  722. package/dist/kernel/enclave/record-keys/rekey-blob.d.ts +0 -88
  723. package/dist/kernel/enclave/record-keys/rekey.d.ts +0 -91
  724. package/dist/kernel/enclave/record-keys/sealed-slot.d.ts +0 -14
  725. package/dist/kernel/enclave/record-keys/sealed-slots.d.ts +0 -123
  726. package/dist/kernel/enclave/record-keys/sealing.d.ts +0 -70
  727. package/dist/kernel/query/join.d.ts +0 -232
  728. package/dist/liberate-V35QUHJP.js +0 -24
  729. package/dist/link-set-2TTM3IZC.js +0 -30
  730. package/dist/noydb-62MX4QUG.js +0 -90
  731. package/dist/pod-handle-ECVCDIXW.js.map +0 -1
  732. package/dist/post-register-3IPCSG6Q.js.map +0 -1
  733. package/dist/register-HHLXEQDN.js +0 -31
  734. package/dist/registry-23WF3TGH.js +0 -8
  735. package/dist/registry-4AYVUNXK.js +0 -8
  736. package/dist/registry-JS3YFQQM.js +0 -18
  737. package/dist/registry-XX2Z7B46.js +0 -32
  738. package/dist/request-withdrawal-CHPATE4G.js +0 -30
  739. package/dist/reveal-QZDHSGD4.js.map +0 -1
  740. package/dist/revoke-7M2VW4ON.js +0 -23
  741. package/dist/seed-X5CC22CQ.js.map +0 -1
  742. package/dist/signer-SJQJVSM6.js +0 -24
  743. package/dist/stale-BZS6H2RY.js +0 -29
  744. package/dist/storage-RW4QBS23.js +0 -22
  745. package/dist/store-coordination-provider-4WZAIRHC.js.map +0 -1
  746. package/dist/verify-6MDTIUEV.js.map +0 -1
  747. package/dist/walk-ZURCH6RZ.js +0 -21
  748. package/dist/withdraw-accessible-PXR4IXDX.js +0 -27
  749. /package/dist/{api-WYW4YEQG.js.map → api-OS747DS4.js.map} +0 -0
  750. /package/dist/{computed-VPOKQK4N.js.map → capsule/contract.js.map} +0 -0
  751. /package/dist/{kernel/enclave → capsule/enclave-aes}/broker/proof.d.ts +0 -0
  752. /package/dist/{kernel/enclave → capsule/enclave-aes}/classify/bidx.d.ts +0 -0
  753. /package/dist/{kernel/enclave → capsule/enclave-aes}/classify/digest.d.ts +0 -0
  754. /package/dist/{kernel/enclave → capsule/enclave-aes}/classify/vdig.d.ts +0 -0
  755. /package/dist/{kernel/enclave/classify → capsule/plumbing}/kofn.d.ts +0 -0
  756. /package/dist/{kernel/enclave/classify → capsule/plumbing}/normalize.d.ts +0 -0
  757. /package/dist/{kernel/enclave → capsule/plumbing}/record-aad.d.ts +0 -0
  758. /package/dist/{collection-facade-JSJYIKS4.js.map → capsule-VOLX3QRQ.js.map} +0 -0
  759. /package/dist/{chunk-MVMXZYXT.js.map → chunk-2GHDLTPE.js.map} +0 -0
  760. /package/dist/{chunk-XLMEZIAJ.js.map → chunk-2ODVB6LZ.js.map} +0 -0
  761. /package/dist/{chunk-RMS3NEA3.js.map → chunk-4JPMZTJY.js.map} +0 -0
  762. /package/dist/{chunk-NQKIUNW5.js.map → chunk-52MGURXO.js.map} +0 -0
  763. /package/dist/{chunk-UGTBXF5U.js.map → chunk-7XMHMVTS.js.map} +0 -0
  764. /package/dist/{chunk-BZ3534YM.js.map → chunk-AUKKUPVB.js.map} +0 -0
  765. /package/dist/{derive-E642AOUB.js.map → chunk-BKT776R5.js.map} +0 -0
  766. /package/dist/{chunk-6LKOJBV6.js.map → chunk-BVCUTXE3.js.map} +0 -0
  767. /package/dist/{chunk-VTFVLCUH.js.map → chunk-DIZLQVAA.js.map} +0 -0
  768. /package/dist/{chunk-LWBCUYZW.js.map → chunk-E2N2T5ZO.js.map} +0 -0
  769. /package/dist/{chunk-JVIBCBC7.js.map → chunk-EJLV62NI.js.map} +0 -0
  770. /package/dist/{chunk-JMGDHKQF.js.map → chunk-FLPCETP6.js.map} +0 -0
  771. /package/dist/{chunk-DGOZ4UZD.js.map → chunk-FVH5QYY2.js.map} +0 -0
  772. /package/dist/{chunk-JBDFMYKQ.js.map → chunk-GZT3NQRA.js.map} +0 -0
  773. /package/dist/{chunk-TFR7DSOV.js.map → chunk-H427H63K.js.map} +0 -0
  774. /package/dist/{chunk-SMH6SRX7.js.map → chunk-JOSPH3E5.js.map} +0 -0
  775. /package/dist/{chunk-3BZZJJMQ.js.map → chunk-MILI22XQ.js.map} +0 -0
  776. /package/dist/{chunk-YYP7WSEB.js.map → chunk-O2IMQSNA.js.map} +0 -0
  777. /package/dist/{chunk-QIZPZMUI.js.map → chunk-Q4UHJ5SN.js.map} +0 -0
  778. /package/dist/{chunk-FAHMLERK.js.map → chunk-QBLT6POL.js.map} +0 -0
  779. /package/dist/{chunk-BUE2D7PX.js.map → chunk-SMV2HRDU.js.map} +0 -0
  780. /package/dist/{chunk-SFAWCTEM.js.map → chunk-TZZBXPZK.js.map} +0 -0
  781. /package/dist/{chunk-UHHPLO3I.js.map → chunk-V3RWOOSO.js.map} +0 -0
  782. /package/dist/{chunk-Q2PU57HC.js.map → chunk-VVOLDVIR.js.map} +0 -0
  783. /package/dist/{chunk-TUFM4UZP.js.map → chunk-XQRFSKYM.js.map} +0 -0
  784. /package/dist/{chunk-GY4WYNNG.js.map → chunk-Y2RKVFKR.js.map} +0 -0
  785. /package/dist/{chunk-4OZNXTO4.js.map → chunk-YRXFFWG4.js.map} +0 -0
  786. /package/dist/{enclave-55PAM4YO.js.map → collection-facade-CS7CA2XO.js.map} +0 -0
  787. /package/dist/{executor-5NIMLSKZ.js.map → computed-FAD7SED4.js.map} +0 -0
  788. /package/dist/{executor-7UQ3BZ4F.js.map → derive-XLOJVXPU.js.map} +0 -0
  789. /package/dist/{dispatch-IEPAVQUM.js.map → dispatch-H4HV32AM.js.map} +0 -0
  790. /package/dist/{executor-AQVXV5GZ.js.map → executor-FMPVN6DT.js.map} +0 -0
  791. /package/dist/{export-accessible-ORMKLA3E.js.map → executor-LBBBRTN5.js.map} +0 -0
  792. /package/dist/{extract-partition-NKYO3WNG.js.map → executor-OSRZST2U.js.map} +0 -0
  793. /package/dist/{find-NOGJ25VX.js.map → export-accessible-RAOJAAU5.js.map} +0 -0
  794. /package/dist/{issue-3DTQ7VJJ.js.map → extract-partition-JD5CUSTG.js.map} +0 -0
  795. /package/dist/{ledger-EDXFFZQL.js.map → find-JRN4RNQ5.js.map} +0 -0
  796. /package/dist/{liberate-V35QUHJP.js.map → issue-YIVBZUTH.js.map} +0 -0
  797. /package/dist/{link-set-2TTM3IZC.js.map → ledger-5ZMGE44K.js.map} +0 -0
  798. /package/dist/{managed-secret-NCWEMPUQ.js.map → liberate-WZSZM2W6.js.map} +0 -0
  799. /package/dist/{noydb-62MX4QUG.js.map → link-set-MFXC24VK.js.map} +0 -0
  800. /package/dist/{register-HHLXEQDN.js.map → managed-secret-MFTFT22X.js.map} +0 -0
  801. /package/dist/{migrate-cek-5ENH64AA.js.map → migrate-cek-DZRFFOHW.js.map} +0 -0
  802. /package/dist/{registry-23WF3TGH.js.map → noydb-ITIGNKUF.js.map} +0 -0
  803. /package/dist/{registry-4AYVUNXK.js.map → query/all/index.js.map} +0 -0
  804. /package/dist/{registry-JS3YFQQM.js.map → register-DT5HZ2LZ.js.map} +0 -0
  805. /package/dist/{registry-XX2Z7B46.js.map → registry-BHRZGZHF.js.map} +0 -0
  806. /package/dist/{request-withdrawal-CHPATE4G.js.map → registry-ET6ZFFWA.js.map} +0 -0
  807. /package/dist/{revoke-7M2VW4ON.js.map → registry-HXFGLGTG.js.map} +0 -0
  808. /package/dist/{signer-SJQJVSM6.js.map → registry-THCPDEOD.js.map} +0 -0
  809. /package/dist/{stale-BZS6H2RY.js.map → request-withdrawal-AV2MJJKY.js.map} +0 -0
  810. /package/dist/{storage-RW4QBS23.js.map → revoke-6DWIEOCV.js.map} +0 -0
  811. /package/dist/{walk-ZURCH6RZ.js.map → signer-MHGW3OIL.js.map} +0 -0
  812. /package/dist/{withdraw-accessible-PXR4IXDX.js.map → stale-6GCFMOOR.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/kernel/query/relate/explain.ts","../src/kernel/query/relate/traverse.ts","../src/kernel/query/relate/methods.ts","../src/kernel/query/relate/scan-methods.ts","../src/kernel/query/relate/install.ts"],"sourcesContent":["/**\n * `Query.explain()` — a readable execution plan (#1348).\n *\n * `toPlan()` answers *what* the query is; this answers *how it would run*:\n * the dispatch per clause (`index:hash` vs `scan`), row estimates taken from\n * real index cardinalities, join strategy and side sizes against the row\n * ceiling, whether ordering/pagination lands pre- or post-join, and which\n * cardinality caps are close to tripping.\n *\n * ⛔ PURELY OBSERVATIONAL. Every read here is a size probe or an index\n * bucket lookup — both pure. `explain()` must never execute the plan, and a\n * terminal must return the same thing whether or not it was called. The\n * guarantee is pinned by `__tests__/query-explain.test.ts`\n * (\"results are identical whether or not explain() was called\").\n *\n * ⚠️ DISPATCH SELECTION IS MIRRORED, NOT SHARED. `indexDispatchFor` below\n * reproduces `candidateRecords()` in `builder.ts` — deliberately, so this\n * file stays out of the executor's way. That mirror is not left to trust:\n * the index path never calls `source.snapshot()` and the scan path always\n * does, so a snapshot-call counter is an executor-side witness of dispatch,\n * and the suite asserts the two agree. **A new index kind must land in BOTH\n * places** — a branch here and the matching branch in `candidateRecords` —\n * plus a label on {@link ExplainDispatch}.\n *\n * ⭐ #1375 — THE MIRROR IS NOW POLICED EXHAUSTIVELY, and that is the durable\n * half of the fix. `__tests__/query-explain.test.ts` carries a TABLE of query\n * shapes spanning every dispatch kind and asserts, for each, that the label\n * `explain()` claims agrees with an executor-side observation. Add a shape to\n * that table when you add an index kind, and a kind that forgets this file\n * fails a test instead of silently reporting the previous era's answer — which\n * is exactly what #1344 and #1345 did to the pre-#1344 `explain()`.\n *\n * ⚠️ The observation is \"did the executor READ RECORDS OUT OF the snapshot\",\n * not \"did it CALL `snapshot()`\". #1344's `orderedIndexRows` and #1345's\n * `compoundCandidates` both call `snapshot()` for their coverage check and\n * read only its `.length`, so the original call-counter witness would now\n * report a scan for two paths that never touch a record.\n */\n\nimport type { Clause } from '../predicate.js'\nimport type { QueryPlan } from '../builder.js'\nimport { DEFAULT_CROSS_JOIN_MAX_ROWS } from './join.js'\nimport {\n indexableClauses,\n isRangeOperator,\n pickCompound,\n pickCompoundOrder,\n viaOrdersField,\n} from '../builder.js'\nimport type { JoinContext, JoinLeg } from './join.js'\nimport { DEFAULT_JOIN_MAX_ROWS, joinsDropLeftRows, orderReferencesJoinAlias, splitAroundJoins } from './join.js'\nimport { describeJoinOn, joinOnDispatch } from './join-on.js'\nimport type { ViaPipeline } from '../../via/pipeline.js'\nimport { isViaPrefixProbe } from '../../via/index.js'\n\n/**\n * How a node is executed. An OPEN label set on purpose — a consumer reads\n * these as strings, so a build that knows a dispatch this one does not still\n * type-checks. A new index kind adds its label here, its branch in\n * {@link indexDispatchFor} (or {@link orderedIndexPick} when it replaces the\n * `sort` node's dispatch), AND a row in the witness table named in this file's\n * header. No consumer shape moves.\n */\nexport type ExplainDispatch =\n | 'source'\n | 'index:hash'\n /** #1344 — a sorted index served `<` `<=` `>` `>=` `between` `startsWith`. */\n | 'index:range'\n /** #1345 — a compound tuple served an equality prefix (+ an optional range). */\n | 'index:compound'\n /**\n * #1355 — a sorted index served a UNION of `startsWith` slices named by a\n * Via binding's prefix probe (`geo()`'s `near`). Unlike every other index\n * label, the clause is NOT consumed: the cover is a superset and the\n * binding's predicate still runs over the candidates, so `estimatedRows`\n * here is the candidate count, not the answer's.\n */\n | 'index:prefix'\n /**\n * #1344 / #1345 — an ordered index walk answered `orderBy(f).limit(n)`\n * outright: no sort runs, and only the page's worth of records is read.\n */\n | 'index:ordered'\n | 'scan'\n | 'join:nested'\n | 'join:hash'\n | 'join:reverse-index'\n /** #1339 — a declared composite `on`, hashed over a tuple key. */\n | 'join:composite-hash'\n /** #1339 — a declared range `on`, nested-loop over a sorted right side. */\n | 'join:sorted-range'\n | 'crossJoin'\n | 'sort'\n | 'page'\n /**\n * #1342 — a partitioned union read every declared partition, because the\n * predicate proved no narrowing. The SOUND default: everything that is not\n * on `resolvePartitionScope`'s whitelist lands here.\n */\n | 'partitions:all'\n /**\n * #1342 — a top-level AND-ed `==`/`in` on the declared partition key\n * narrowed the set, so the excluded members were never asked for.\n *\n * ⚠️ Unlike every other label in this union, this one is NOT decided in\n * this file. `resolvePartitionScope` (`query/partition.ts`) is called by\n * the executor and by `explain()`, so there is nothing to keep in step —\n * see that module's header for why a third mirror site was refused.\n */\n | 'partitions:pruned'\n // Keeps the labels above as autocomplete hints while leaving the type open\n // for a dispatch this build does not know about yet.\n | (string & {})\n\n/** One line of the plan. */\nexport interface ExplainNode {\n /** Pipeline stage: 'source' | 'where' | 'group' | 'filter' | 'wherePredicate' | 'crossJoin' | 'join' | 'orderBy' | 'page'. */\n readonly op: string\n /** How this stage runs. */\n readonly dispatch: ExplainDispatch\n /** One-line, no-op-prefix description, e.g. `status == \"open\"`. */\n readonly detail: string\n /**\n * Rows this stage is expected to emit. Exact where an index or a snapshot\n * size supplies it; an upper bound (carried through unchanged) where only a\n * scan can answer — the accompanying note says which.\n */\n readonly estimatedRows: number | undefined\n /** Why this dispatch, and anything about to trip. */\n readonly notes: readonly string[]\n /** Sub-clauses of an `and`/`or` group. Empty for every other node. */\n readonly children: readonly ExplainNode[]\n}\n\n/** A cardinality ceiling this plan runs against. */\nexport interface ExplainCap {\n /** e.g. `join:client:right`, `crossJoin:lines`. */\n readonly name: string\n /** The ceiling that would throw. */\n readonly limit: number\n /** The size measured (or estimated) against it. */\n readonly observed: number\n /** `warn` mirrors the executor's 80%-of-ceiling warning; `exceeded` would throw. */\n readonly status: 'ok' | 'warn' | 'exceeded'\n}\n\n/** The result of {@link explainPlan}. */\nexport interface QueryExplanation {\n /** The plan tree, in execution order. */\n readonly nodes: readonly ExplainNode[]\n /** Every cardinality ceiling this plan runs against. */\n readonly caps: readonly ExplainCap[]\n /**\n * Fields this query references whose Via binding rewrites aggregate\n * reducers — money's exact-BigInt sum being the one that ships. Applies to\n * `.aggregate()`/`.groupBy()` over these fields, not to the row pipeline.\n */\n readonly reducerRewrite: readonly { readonly brand: string; readonly field: string }[]\n /** One line per node, depth-indented. Stable for a given plan. */\n readonly text: string\n}\n\n/**\n * The slice of a query source `explain()` reads. Structurally satisfied by\n * the builder's internal source; declared here so this module does not\n * depend on the builder's non-exported types.\n */\nexport interface ExplainSource {\n snapshot(): readonly unknown[]\n /**\n * #1414/#1421 — the cold-collection gate. `explain()` is the one terminal\n * that stays answerable while unhydrated (a diagnostic that refuses to\n * diagnose is useless), so it carries the distinction instead: a snapshot\n * of zero rows because nothing has been loaded is NOT the same fact as a\n * snapshot of zero rows because the collection is empty, and only the\n * second one is safe to act on.\n */\n hydration?: { isHydrated(): boolean }\n getIndexes?(): ExplainIndexProbe | null\n lookupById?(id: string): unknown\n via?: ViaPipeline\n}\n\n/**\n * The index-store surface `explain()` probes. Declared structurally rather\n * than importing `CollectionIndexes`: the kernel spine may not statically\n * reach a `with-*` service (`check:architecture`'s port-layering gate), and\n * every method here is a pure read. `CollectionIndexes` satisfies it.\n */\nexport interface ExplainIndexProbe {\n has(field: string): boolean\n fields(): string[]\n lookupEqual(field: string, value: unknown): ReadonlySet<string> | null\n lookupIn(field: string, values: readonly unknown[]): ReadonlySet<string> | null\n // ── #1375: the dispatch surface #1344 and #1345 added ──────────────────\n // OPTIONAL, every one of them. A probe that predates a kind simply cannot\n // serve it, which is the honest answer and the one this file already gives\n // for a source with no index store at all — never a crash on a build whose\n // index store is older than this module.\n /** #1344 — does a SORTED index cover this field? */\n hasSorted?(field: string): boolean\n /** #1344 — entry count of the sorted index; compare against the snapshot. */\n sortedSize?(field: string): number\n /** #1344 — ids satisfying a range operator, or `null` when unserved. */\n lookupRange?(field: string, op: string, value: unknown): ReadonlySet<string> | null\n /** #1344 — every indexed id in field order, or `null` when unserved. */\n orderedIds?(field: string, direction: 'asc' | 'desc'): readonly string[] | null\n /** #1345 — declared field tuples, in declaration order. */\n compoundTuples?(): ReadonlyArray<readonly string[]>\n /** #1345 — records the tuple's index holds; compare against the snapshot. */\n compoundSize?(fields: readonly string[]): number\n /** #1345 — ids for an equality prefix, optionally narrowed by a range. */\n lookupCompound?(\n fields: readonly string[],\n prefixValues: readonly unknown[],\n range?: { readonly op: string; readonly value: unknown },\n ): ReadonlySet<string> | null\n /** #1345 — an equality prefix ordered by the remaining component. */\n compoundOrderedIds?(\n fields: readonly string[],\n prefixValues: readonly unknown[],\n direction: 'asc' | 'desc',\n ): readonly string[] | null\n}\n\n/** Mirrors join.ts's `JOIN_WARN_FRACTION`. */\nconst WARN_FRACTION = 0.8\n\n/** Which clauses an index consumed, and the label each of their nodes carries. */\ninterface ClauseDispatchPick {\n readonly consumed: ReadonlyMap<number, ExplainDispatch>\n /** Cardinality of the candidate set the index produced. */\n readonly rows: number\n}\n\n/** A `CompoundTupleSource` view of a probe whose compound half may be absent. */\nfunction tupleSourceOf(indexes: ExplainIndexProbe): { compoundTuples(): ReadonlyArray<readonly string[]> } {\n return { compoundTuples: () => indexes.compoundTuples?.() ?? [] }\n}\n\n/**\n * Which clauses (if any) the index serves, and under which dispatch labels.\n *\n * Mirrors `candidateRecords()` in `builder.ts` — its compound-first ordering\n * (#1345), its range arm (#1344), its Via caveat (a covered clause with no\n * `indexValue` probe is not index-eligible, and a Via-covered RANGE is never\n * index-served because `indexProbe` yields an equality operand only), and its\n * \"first eligible clause wins\" rule. See this file's header for why it is a\n * mirror and how the mirror is policed.\n */\nfunction indexDispatchFor(source: ExplainSource, clauses: readonly Clause[]): ClauseDispatchPick | null {\n const indexes = source.getIndexes?.()\n if (!indexes || !source.lookupById || clauses.length === 0) return null\n\n // #1345 — `candidateRecords()` tries the compound arm FIRST, because an\n // equality prefix removes more clauses from the plan than any single-clause\n // choice below. Reporting the single-clause answer here would name a path\n // the executor did not take even though both are index paths.\n const compound = compoundDispatchFor(source, indexes, clauses)\n if (compound) return compound\n\n // #1355 — mirrors `prefixCandidates()`, ordering included.\n const prefixed = prefixDispatchFor(indexes, clauses)\n if (prefixed) return prefixed\n\n for (let i = 0; i < clauses.length; i++) {\n const clause = clauses[i]!\n if (clause.type !== 'field') continue\n if (!indexes.has(clause.field) && indexes.hasSorted?.(clause.field) !== true) continue\n if (clause.via && clause.via.indexValue === undefined) continue\n const probeValue = clause.via ? clause.via.indexValue : clause.value\n\n let ids: ReadonlySet<string> | null = null\n let dispatch: ExplainDispatch = 'index:hash'\n if (clause.op === '==') {\n ids = indexes.lookupEqual(clause.field, probeValue)\n } else if (clause.op === 'in' && Array.isArray(probeValue)) {\n ids = indexes.lookupIn(clause.field, probeValue)\n } else if (clause.via === undefined && isRangeOperator(clause.op)) {\n // #1344 — `null` both when no sorted index covers the field and when\n // this build's probe predates the method.\n ids = indexes.lookupRange?.(clause.field, clause.op, clause.value) ?? null\n dispatch = 'index:range'\n }\n if (ids !== null) return { consumed: new Map([[i, dispatch]]), rows: ids.size }\n }\n return null\n}\n\n/**\n * #1355 — mirrors `prefixCandidates()`. The clause is labelled even though\n * the executor does not consume it: the index really did produce the\n * candidate set, and reporting `scan` for a path that never walks the\n * snapshot is exactly the disagreement the witness table exists to catch.\n */\nfunction prefixDispatchFor(indexes: ExplainIndexProbe, clauses: readonly Clause[]): ClauseDispatchPick | null {\n for (let i = 0; i < clauses.length; i++) {\n const clause = clauses[i]!\n if (clause.type !== 'field' || clause.via === undefined) continue\n const probe = clause.via.indexValue\n if (!isViaPrefixProbe(probe)) continue\n if (indexes.hasSorted?.(clause.field) !== true) continue\n const ids = new Set<string>()\n for (const prefix of probe.prefixes) {\n const hit = indexes.lookupRange?.(clause.field, 'startsWith', prefix) ?? null\n if (hit === null) return null\n for (const id of hit) ids.add(id)\n }\n return { consumed: new Map([[i, 'index:prefix' as ExplainDispatch]]), rows: ids.size }\n }\n return null\n}\n\n/** #1345 — mirrors `compoundCandidates()`, coverage guard included. */\nfunction compoundDispatchFor(\n source: ExplainSource,\n indexes: ExplainIndexProbe,\n clauses: readonly Clause[],\n): ClauseDispatchPick | null {\n const pick = pickCompound(tupleSourceOf(indexes), clauses)\n if (!pick) return null\n // An under-covering tuple index would silently drop matching records, so the\n // executor declines it — and so must this.\n if (indexes.compoundSize?.(pick.fields) !== source.snapshot().length) return null\n const ids = indexes.lookupCompound?.(pick.fields, pick.values, pick.range) ?? null\n if (!ids) return null\n const consumed = new Map<number, ExplainDispatch>()\n for (const at of pick.consumed) consumed.set(at, 'index:compound')\n return { consumed, rows: ids.size }\n}\n\n/** An ordered-index walk that answers `orderBy(f).limit(n)` outright. */\ninterface OrderedPick {\n readonly rows: number\n /** Label for the clause nodes the compound walk also consumed; `null` when there are none. */\n readonly clauseDispatch: ExplainDispatch | null\n /** Which of the two walks ran, for the node's note. */\n readonly detail: string\n}\n\n/**\n * #1344 / #1345 — mirrors `orderedIndexRows() ?? compoundOrderedRows()`, the\n * pair `executePlanWithSource` tries BEFORE `candidateRecords()`. Both return\n * the page directly: no sort runs, and `offset`/`limit` are consumed by the\n * index walk rather than by a slice.\n *\n * Every guard the executor carries is repeated here, because each one is a\n * case where the two answers would otherwise disagree — the coverage checks in\n * particular (`sortedSize` / `compoundSize` against the snapshot size), which\n * is the whole reason a partial index does not take these paths.\n */\nfunction orderedIndexPick(source: ExplainSource, plan: QueryPlan): OrderedPick | null {\n const limit = plan.limit\n if (limit === undefined || plan.orderBy.length !== 1) return null\n const [order] = plan.orderBy\n if (!order || order.by === 'label') return null\n const indexes = source.getIndexes?.()\n if (!indexes || !source.lookupById) return null\n if (viaOrdersField(source.via, order.field)) return null\n const snapshotRows = source.snapshot().length\n\n if (plan.clauses.length === 0) {\n if (indexes.hasSorted?.(order.field) !== true) return null\n if (indexes.sortedSize?.(order.field) !== snapshotRows) return null\n const ids = indexes.orderedIds?.(order.field, order.direction) ?? null\n if (!ids) return null\n return { rows: pageOf(ids.length, plan.offset, limit), clauseDispatch: null, detail: `sorted index on \"${order.field}\"` }\n }\n\n const { eq } = indexableClauses(plan.clauses)\n if (eq.size !== plan.clauses.length) return null\n const match = pickCompoundOrder(tupleSourceOf(indexes), eq, order.field)\n if (!match) return null\n if (indexes.compoundSize?.(match.fields) !== snapshotRows) return null\n const ids = indexes.compoundOrderedIds?.(match.fields, match.values, order.direction) ?? null\n if (!ids) return null\n return {\n rows: pageOf(ids.length, plan.offset, limit),\n clauseDispatch: 'index:compound',\n detail: `compound index on (${match.fields.join(', ')})`,\n }\n}\n\nfunction pageOf(total: number, offset: number, limit: number): number {\n return Math.min(Math.max(0, total - offset), limit)\n}\n\n/**\n * Does this dispatch hand back a CANDIDATE set that the clause still filters,\n * rather than the answer?\n *\n * `index:range` is the one index label that is exact — `lookupRange` is served\n * by the sorted index, whose comparisons are the scan's own (#1344, measured\n * on #1415: `!=`, `startsWith` and the range operators never disagreed).\n */\nfunction isSupersetDispatch(dispatch: ExplainDispatch, clause: Clause): boolean {\n if (dispatch === 'index:prefix' || dispatch === 'index:compound') return true\n if (dispatch !== 'index:hash') return false\n return clause.type === 'field' && (clause.op === '==' || clause.op === 'in')\n}\n\n/** `op`-free one-line description of a clause. */\nfunction describeClause(clause: Clause): { op: string; detail: string } {\n switch (clause.type) {\n case 'field': {\n // #1351: an `in`/`!in` operand that came from a SUBQUERY is already a\n // resolved id array by the time explain() sees it, and printing 400 ids\n // is not a readable plan. Name the inner source and the set size — the\n // sentence a reader is after is \"the inner query ran once, it produced\n // N ids, and the outer clause is index-served off them\".\n const detail =\n clause.subquery !== undefined\n ? `${clause.field} ${clause.op} subquery(${clause.subquery.from}) → ${clause.subquery.ids} ids`\n : `${clause.field} ${clause.op} ${formatValue(clause.value)}`\n return { op: 'where', detail }\n }\n case 'group':\n return { op: 'group', detail: `${clause.op} (${clause.clauses.length} clause${clause.clauses.length === 1 ? '' : 's'})` }\n case 'filter':\n return { op: 'filter', detail: 'fn' }\n case 'wherePredicate':\n return { op: 'wherePredicate', detail: clause.name }\n case 'crossJoin':\n // #1289 — a `crossJoinWith` clause names BOTH sides, because the row it\n // emits has no top level to fall back on. `leftAs x rightAs` is the\n // shape the caller reads back; `as x target` is the asymmetric one.\n return {\n op: clause.leftAs === undefined ? 'crossJoin' : 'crossJoinWith',\n detail:\n (clause.leftAs === undefined\n ? `${clause.as} x ${clause.target}`\n : `${clause.leftAs} x ${clause.as} (self ${clause.target})`) +\n `${clause.on ? ' on fn' : ''}${clause.outer === true ? ' outer' : ''}`,\n }\n }\n}\n\n/** Compact, deterministic operand rendering. Never throws. */\nfunction formatValue(value: unknown): string {\n if (typeof value === 'bigint') return `${value.toString()}n`\n try {\n const json = JSON.stringify(value)\n return json === undefined ? String(value) : json\n } catch {\n return '[unserializable]'\n }\n}\n\n/** Field paths this query mentions — clause fields plus orderBy fields. */\nfunction referencedFields(plan: QueryPlan): string[] {\n const out: string[] = []\n const walk = (clauses: readonly Clause[]): void => {\n for (const c of clauses) {\n if (c.type === 'field') out.push(c.field)\n else if (c.type === 'group') walk(c.clauses)\n }\n }\n walk(plan.clauses)\n for (const o of plan.orderBy) out.push(o.field)\n return [...new Set(out)]\n}\n\nfunction capStatus(observed: number, limit: number): ExplainCap['status'] {\n if (observed > limit) return 'exceeded'\n if (observed > limit * WARN_FRACTION) return 'warn'\n return 'ok'\n}\n\n/** Build the explanation for a plan. Reads sizes and index buckets; runs nothing. */\nexport function explainPlan(\n source: ExplainSource,\n plan: QueryPlan,\n joinContext?: JoinContext,\n): QueryExplanation {\n const nodes: ExplainNode[] = []\n const caps: ExplainCap[] = []\n\n const indexes = source.getIndexes?.() ?? null\n const indexedFields = indexes ? indexes.fields() : []\n const sourceRows = source.snapshot().length\n let rows: number | undefined = sourceRows\n\n const reducerRewrite = collectReducerRewrites(source.via, referencedFields(plan))\n const sourceNotes: string[] = []\n // #1414 — say WHY the snapshot is empty. `rows: 0` on an unhydrated\n // collection is an absence of data in memory, not an absence of records.\n const notHydrated = source.hydration?.isHydrated() === false\n if (notHydrated) {\n sourceNotes.push(\n 'collection not hydrated — this plan\\'s row estimates are not authoritative; ' +\n 'call `await collection.list()` / `await collection.get(id)` first',\n )\n }\n for (const r of reducerRewrite) {\n sourceNotes.push(`reducer rewrite: ${r.brand}(\"${r.field}\")`)\n }\n\n nodes.push({\n op: 'source',\n dispatch: 'source',\n detail: notHydrated\n ? `snapshot (NOT HYDRATED — nothing has been read yet${indexedFields.length > 0 ? `; indexes: ${indexedFields.join(', ')}` : ''})`\n : indexedFields.length > 0 ? `snapshot (indexes: ${indexedFields.join(', ')})` : 'snapshot (no indexes)',\n estimatedRows: sourceRows,\n notes: sourceNotes,\n children: [],\n })\n\n const hasCrossJoin = plan.clauses.some(c => c.type === 'crossJoin')\n const { preJoin, postJoin } = splitAroundJoins(plan.clauses, plan.joins)\n\n // #1337 — an ordering that addresses an alias moves the sort/page after the\n // legs, exactly as a post-join predicate does. #1361 — an inner leg moves\n // only the page. Both decisions are read from the same helpers\n // `Query.toArray()` routes on, so `explain()` cannot report a placement the\n // executor does not use. They are computed HERE, ahead of the clause nodes,\n // because they also decide whether the ordered-index walk is reachable at\n // all: on either reordered path `toArray()` hands the executor a plan with\n // `orderBy: []` / `limit: undefined`, and #1344's fast path declines it.\n const orderPostJoin = orderReferencesJoinAlias(plan.orderBy, plan.joins)\n const runsPostJoin = postJoin.length > 0 || orderPostJoin\n const innerSplit = !runsPostJoin && plan.joins.length > 0 && joinsDropLeftRows(plan.joins)\n let ordered: OrderedPick | null = null\n\n if (hasCrossJoin) {\n // A crossJoin plan runs through `executeClausePipeline`, which starts from\n // the full snapshot — the index fast path is not on that road at all.\n for (const clause of plan.clauses) {\n if (clause.type === 'crossJoin') {\n const rightRows = joinContext?.resolveSource(clause.target)?.snapshot().length\n const limit = clause.maxRows ?? DEFAULT_CROSS_JOIN_MAX_ROWS\n const product: number | undefined =\n rows !== undefined && rightRows !== undefined ? rows * rightRows : undefined\n const { op, detail } = describeClause(clause)\n const notes: string[] = [\n rightRows === undefined ? 'right side unresolved' : `right side ${rightRows} rows`,\n `cap ${limit}`,\n ]\n nodes.push({ op, dispatch: 'crossJoin', detail, estimatedRows: product, notes, children: [] })\n if (product !== undefined) {\n caps.push({ name: `crossJoin:${clause.as}`, limit, observed: product, status: capStatus(product, limit) })\n }\n rows = product\n } else {\n nodes.push(scanNode(clause, rows, ['index fast path unavailable: the plan carries a crossJoin']))\n }\n }\n } else {\n ordered = runsPostJoin || innerSplit ? null : orderedIndexPick(source, plan)\n const pick = ordered ? null : indexDispatchFor(source, preJoin)\n if (ordered) rows = ordered.rows\n preJoin.forEach((clause, i) => {\n const dispatch = ordered ? ordered.clauseDispatch : (pick?.consumed.get(i) ?? null)\n if (dispatch !== null) {\n const { op, detail } = describeClause(clause)\n if (pick) rows = pick.rows\n // Index labels whose clause is NOT consumed. Say so, or\n // `estimatedRows` reads as the answer's size when it is the candidate\n // set's.\n //\n // #1355 started this list with `index:prefix`. #1415 and #1425 then\n // added the equality arms for the same reason from the other end: a\n // hash bucket and a tuple match are both supersets (bucket keys\n // collapse `1`/`'1'`, tuple keys collapse two Dates at one instant),\n // so those clauses stay in the plan and re-filter the candidates.\n // ⚠️ Keeping this list in step is not cosmetic — an explain that says\n // \"consumed\" for a clause the executor still evaluates is precisely\n // #1375's mirror defect, and it is how a superset arm looks correct.\n const notes = isSupersetDispatch(dispatch, clause)\n ? [`${dispatch === 'index:prefix' ? 'prefix cover' : 'index match'} is a superset: the clause still filters the candidates exactly`]\n : []\n nodes.push({ op, dispatch, detail, estimatedRows: rows, notes, children: [] })\n return\n }\n nodes.push(scanNode(clause, rows, scanReason(clause, indexes, pick !== null)))\n })\n }\n\n // Join legs, then — only when a predicate addresses an alias — the post-join\n // filter. Mirrors `Query.toArray()`: with no post-join clause the legs are\n // applied AFTER ordering and pagination, so they are emitted last below.\n const emitJoins = (): void => {\n for (const leg of plan.joins) {\n nodes.push(joinNode(leg, joinContext, rows, caps))\n }\n }\n\n if (runsPostJoin) {\n emitJoins()\n for (const clause of postJoin) {\n nodes.push(scanNode(clause, rows, ['post-join: addresses a join alias, so no index can serve it']))\n }\n }\n\n const placement = plan.joins.length === 0 ? undefined : runsPostJoin ? 'post-join' : 'pre-join'\n\n if (plan.orderBy.length > 0) {\n // #1375 — when an ordered index answers the plan there is no sort at all:\n // the walk emits the page in index order. Labelling it `sort` is the\n // sentence a consumer would act on by adding the index they already have.\n const orderNotes = placement ? [placement] : []\n if (ordered) orderNotes.push(`ordered index page off the ${ordered.detail}: no sort runs`)\n nodes.push({\n op: 'orderBy',\n dispatch: ordered ? 'index:ordered' : 'sort',\n detail: plan.orderBy.map(o => `${o.field} ${o.direction}${o.by === 'label' ? ' by label' : ''}`).join(', '),\n estimatedRows: rows,\n notes: orderNotes,\n children: [],\n })\n }\n\n if (innerSplit) emitJoins()\n\n if (plan.offset > 0 || plan.limit !== undefined) {\n const afterOffset = rows === undefined ? undefined : Math.max(0, rows - plan.offset)\n const paged =\n afterOffset === undefined ? undefined : plan.limit === undefined ? afterOffset : Math.min(afterOffset, plan.limit)\n nodes.push({\n op: 'page',\n dispatch: 'page',\n detail: `offset=${plan.offset} limit=${plan.limit ?? 'none'}`,\n estimatedRows: paged,\n notes: [\n ...(innerSplit ? ['post-join'] : placement ? [placement] : []),\n ...(ordered ? ['consumed by the ordered index walk; no rows are materialized past the page'] : []),\n ],\n children: [],\n })\n rows = paged\n }\n\n if (!runsPostJoin && !innerSplit) emitJoins()\n\n return { nodes, caps, reducerRewrite, text: renderExplainText(nodes) }\n}\n\n/** Why this clause fell to a scan — the sentence a consumer is actually after. */\nfunction scanReason(clause: Clause, indexes: ExplainIndexProbe | null, indexAlreadyUsed: boolean): string[] {\n if (indexAlreadyUsed) {\n const residual = 'residual: an earlier clause is already index-served'\n // Still name a missing index — that is the sentence a consumer acts on,\n // and it stays true regardless of which clause won the fast path.\n return clause.type === 'field' && indexes !== null && !indexes.has(clause.field)\n ? [residual, `no index on \"${clause.field}\"`]\n : [residual]\n }\n if (clause.type !== 'field') return [`${clause.type} clauses are never index-served`]\n if (!indexes) return ['linear scan: no index store on this source']\n const sorted = indexes.hasSorted?.(clause.field) === true\n if (!indexes.has(clause.field) && !sorted) return [`linear scan: no index on \"${clause.field}\"`]\n if (clause.op !== '==' && clause.op !== 'in') {\n // #1375 — a range operator IS index-servable now, but only off a SORTED\n // index. Naming which kind is missing is the sentence a consumer acts on;\n // the pre-#1344 wording said \"== and in only\" even where the fix is to\n // declare `kind: 'sorted'`.\n if (!isRangeOperator(clause.op)) {\n return [`linear scan: no index serves ${clause.op} on \"${clause.field}\"`]\n }\n if (!sorted) {\n return [\n `linear scan: the hash index on \"${clause.field}\" serves == and in only — ` +\n `declare a sorted index on it to serve ${clause.op}`,\n ]\n }\n if (clause.via !== undefined) {\n return [`linear scan: \"${clause.field}\" is Via-covered, and a Via range operand is evaluated per record`]\n }\n return [`linear scan: the sorted index on \"${clause.field}\" could not order this operand`]\n }\n return [`linear scan: the index on \"${clause.field}\" could not serve this operand`]\n}\n\nfunction scanNode(clause: Clause, rows: number | undefined, notes: readonly string[]): ExplainNode {\n const { op, detail } = describeClause(clause)\n return {\n op,\n dispatch: 'scan',\n detail,\n estimatedRows: rows,\n notes: [...notes, ...(rows === undefined ? [] : ['estimate is an upper bound'])],\n children:\n clause.type === 'group'\n ? clause.clauses.map(c => scanNode(c, rows, ['inside a group: evaluated per record']))\n : [],\n }\n}\n\nfunction joinNode(\n leg: JoinLeg,\n joinContext: JoinContext | undefined,\n leftRows: number | undefined,\n caps: ExplainCap[],\n): ExplainNode {\n const right = leg.isDictJoin === true ? joinContext?.resolveDictSource?.(leg.field) : joinContext?.resolveSource(leg.target)\n const rightRows = right?.snapshot().length\n const strategy = leg.strategy ?? (right?.lookupById ? 'nested' : 'hash')\n const limit = leg.maxRows ?? DEFAULT_JOIN_MAX_ROWS\n\n // #1289 — a right/full leg does not run the forward strategy at all: it\n // builds a reverse index over the left rows and drives off the right\n // snapshot. Reporting `join:nested` for it would name a path that never\n // executes, so the dispatch and the detail both say which join this is.\n const direction = leg.direction ?? 'left'\n const notes: string[] = [\n rightRows === undefined ? 'right side unresolved' : `right side ${rightRows} rows`,\n `cap ${limit}`,\n `ref mode ${leg.mode}`,\n ]\n if (direction !== 'left') {\n notes.push('reverse index over the left rows; right snapshot drives')\n }\n if (leg.inner === true) {\n notes.push('inner: unmatched left rows are dropped, so the estimate is an upper bound')\n }\n if (leg.strategy !== undefined) notes.push('strategy overridden by the caller')\n\n if (leftRows !== undefined) {\n caps.push({ name: `join:${leg.as}:left`, limit, observed: leftRows, status: capStatus(leftRows, limit) })\n }\n if (rightRows !== undefined) {\n caps.push({ name: `join:${leg.as}:right`, limit, observed: rightRows, status: capStatus(rightRows, limit) })\n }\n\n // #1339 — a declared `on` runs neither forward strategy nor the reverse\n // index, and it is the only join here that can EXPAND the relation, so both\n // the dispatch and the estimate have to say so rather than passing the left\n // count through as `.join()` legitimately does.\n if (leg.on !== undefined) {\n // `ref mode` is meaningless here and actively misleading: a declared join\n // has no ref(), so the leg's `'cascade'` is a placeholder that satisfies\n // the shared `JoinLeg` type, not a policy anything applies.\n notes.splice(notes.findIndex(n => n.startsWith('ref mode')), 1)\n notes.push(\n leg.on.kind === 'composite'\n ? 'declared composite `on`: one hash pass over the right snapshot, keyed on the field tuple'\n : 'declared range `on`: the right snapshot is sorted once, then binary-searched per left row',\n )\n notes.push('many-to-many: one row per match, so the estimate is a lower bound and the output ceiling applies')\n return {\n op: 'join',\n dispatch: joinOnDispatch(leg.on),\n detail: `${leg.as} <- ${describeJoinOn(leg.on)} (${leg.target})`,\n estimatedRows: leftRows,\n notes,\n children: [],\n }\n }\n\n // The direction is appended ONLY for a right/full leg. A left leg's detail\n // stays byte-identical to what it rendered before #1289: `.join()` is the\n // left outer join and always was, so labelling it now would churn every\n // consumer's `explain().text` to say nothing new.\n const label = direction === 'left' ? '' : direction === 'right' ? ' right outer' : ' full outer'\n // Row estimate: a LEFT leg is projection-only — it attaches an alias and\n // never filters, so the count passes through. A right/full leg reshapes the\n // relation (a row per unreferenced right record; for 'right', the unmatched\n // left rows drop), so the left count is no longer the answer and the only\n // honest bound without executing is left + right.\n const estimatedRows =\n direction === 'left'\n ? leftRows\n : leftRows === undefined || rightRows === undefined\n ? undefined\n : leftRows + rightRows\n\n return {\n op: 'join',\n dispatch: direction === 'left' ? `join:${strategy}` : 'join:reverse-index',\n detail: `${leg.as} <- ${leg.field} (${leg.target})${label}`,\n estimatedRows,\n notes,\n children: [],\n }\n}\n\n/** Money today: any binding that rewrites reducers and covers a referenced field. */\nfunction collectReducerRewrites(\n via: ViaPipeline | undefined,\n fields: readonly string[],\n): { readonly brand: string; readonly field: string }[] {\n if (!via) return []\n const out: { brand: string; field: string }[] = []\n for (const field of fields) {\n for (const binding of via.bindings) {\n if (binding.wrapReducers && binding.covers?.(field) === true) out.push({ brand: binding.brand, field })\n }\n }\n return out\n}\n\n/**\n * One line per node, two spaces per level of depth.\n *\n * Exported (#1342) so the partitioned union's `explain()` renders its\n * partition line and the member's nodes with THIS renderer rather than a\n * second one — a consumer diffing two `explain().text` outputs must not be\n * reading two formatters.\n */\nexport function renderExplainText(nodes: readonly ExplainNode[]): string {\n const lines: string[] = []\n const walk = (ns: readonly ExplainNode[], depth: number): void => {\n for (const n of ns) {\n const rows = n.estimatedRows === undefined ? '' : ` rows=${n.estimatedRows}`\n const notes = n.notes.length > 0 ? ` -- ${n.notes.join('; ')}` : ''\n lines.push(`${' '.repeat(depth)}${n.op} ${n.detail} [${n.dispatch}]${rows}${notes}`)\n walk(n.children, depth + 1)\n }\n }\n walk(nodes, 0)\n return lines.join('\\n')\n}\n","/**\n * Query DSL `.traverse()` — bounded breadth-first walk over ONE declared,\n * self-referencing `ref()` field (#1352).\n *\n * Org charts, bills of materials, account hierarchies, parent/child clients:\n * every one of them is a collection whose records point at other records in\n * the SAME collection, and every one of them otherwise needs the consumer to\n * hand-roll recursion in userland.\n *\n * Scope — and the scope is the design, not a limitation to be lifted later:\n *\n * - **Declared refs only.** The field must carry a `ref()` whose target is\n * the collection being queried. This is not a general graph engine; an\n * undeclared field, or a ref pointing at a different collection, is\n * refused at plan time with an actionable error.\n * - **`direction: 'up'`** follows the FK — one `lookupById` per hop, O(1).\n * **`direction: 'down'`** answers \"who points at me\", which no forward\n * index can serve, so it builds the reverse-FK index #1289 introduced\n * (`bucketByRefKey` in `join.ts`) ONCE per call and probes it per node.\n * - **`maxDepth` is required.** Not defaulted. An unbounded walk over a\n * large collection is a denial of service against the consumer's own UI,\n * and a silent default would truncate a result set without saying so —\n * the caller must state the bound they can afford.\n * - **A node is emitted once**, at the shallowest depth it is reached at.\n * That settles the diamond (two seeds converging on one ancestor → one\n * row) and it is the same set that makes cycles terminate.\n *\n * **Cost.** Nothing here decrypts. `collection.query()` is eager-mode only\n * and reads the vault's already-decrypted in-memory cache, so the AES-GCM\n * cost was paid once at `openVault()` prefetch: a depth-5 traversal is\n * `depth × frontier` Map lookups and zero `crypto.subtle` calls. The one\n * non-constant cost is `down`'s single O(n) pass to build the reverse index.\n * The architectural invariant is untouched — no filter, sort or hop is\n * pushed to the store, which holds ciphertext and never runs a query.\n */\n\nimport { readPath } from '../predicate.js'\nimport { bucketByRefKey, coerceRefKey } from './join.js'\nimport { TraversalCycleError } from '../../errors.js'\n\n/** Which way a traversal walks the declared self-ref. */\nexport type TraverseDirection = 'up' | 'down'\n\n/**\n * What a traversal does when it reaches a node already on the current path.\n *\n * `'stop'` (the default) prunes that branch and finishes the walk — a\n * circular parent chain produces a finite result instead of hanging.\n * `'throw'` raises {@link TraversalCycleError}, for hierarchies that are\n * supposed to be acyclic and where a cycle is a finding, not a shape.\n */\nexport type CyclePolicy = 'stop' | 'throw'\n\n/** Options for {@link runTraversal}. `maxDepth` is deliberately required. */\nexport interface TraverseOptions {\n readonly direction: TraverseDirection\n /**\n * Maximum number of hops from a seed. `0` returns the seeds alone. Must be\n * a non-negative integer — there is no default, on purpose.\n */\n readonly maxDepth: number\n /** Cycle behaviour. Defaults to `'stop'`. */\n readonly onCycle?: CyclePolicy\n}\n\n/**\n * One row of a traversal result.\n *\n * Deliberately NOT flattened into the record. Stamping `depth` / `path` onto\n * the record would collide with a real field on exactly the collections this\n * feature exists for — an org chart with its own `depth` column is not a\n * hypothetical — and the loser of that collision would be silent.\n *\n * `path` is the ids from the seed to this node, BOTH INCLUSIVE, so\n * `path.length === depth + 1` and `path.at(-1) === id` always. A seed has\n * `depth: 0` and `path: [id]`.\n */\nexport interface TraversalRow<T> {\n /** This node's record id. */\n readonly id: string\n /** The record itself, decoded exactly as `toArray()` would decode it. */\n readonly record: T\n /** Hops from the seed. `0` for a seed. */\n readonly depth: number\n /** Seed-to-node ids, inclusive at both ends. */\n readonly path: readonly string[]\n}\n\n/** The slice of a query source a traversal needs. */\nexport interface TraverseSource {\n snapshot(): readonly unknown[]\n lookupById?(id: string): unknown\n snapshotEntries?(): readonly { readonly id: string; readonly record: unknown }[]\n}\n\ninterface Node {\n readonly id: string\n readonly record: unknown\n readonly depth: number\n readonly path: readonly string[]\n}\n\n/**\n * Id-paired view of the source.\n *\n * Same reasoning as `JoinableSource.snapshotEntries` (#1289): a Collection\n * snapshot record does not carry its own id, so anything that has to ask\n * \"which record is this?\" must go through the id-paired view. The `id`-field\n * fallback serves the plain-object sources unit tests wire up.\n */\nfunction entriesOf(source: TraverseSource): readonly { id: string; record: unknown }[] {\n const paired = source.snapshotEntries?.()\n if (paired !== undefined) return paired as readonly { id: string; record: unknown }[]\n const out: { id: string; record: unknown }[] = []\n for (const record of source.snapshot()) {\n const id = coerceRefKey(readPath(record, 'id'))\n if (id !== null) out.push({ id, record })\n }\n return out\n}\n\n/**\n * Bounded BFS from `seeds`.\n *\n * `seeds` are ids, not records — a seed that names no existing record is\n * skipped, not thrown on, for the same reason a dangling ref terminates a\n * branch quietly: a traversal reports the graph it found, and a missing node\n * is an absence, not a failure of the walk.\n *\n * The two guards are separate on purpose:\n *\n * - `path.includes(next)` is a CYCLE — the walk would re-enter a node it is\n * standing on. Checked first, so `onCycle: 'throw'` reports a genuine\n * ring rather than the next case.\n * - `emitted.has(next)` is a DIAMOND — the node was already reached by\n * another branch, at a depth no greater than this one (BFS), so re-\n * emitting it would duplicate the row and re-walk its whole subtree.\n *\n * Collapsing them into one visited-set would make a diamond indistinguishable\n * from a cycle, which is precisely the distinction `onCycle` sells.\n */\nexport function runTraversal(\n source: TraverseSource,\n field: string,\n seeds: readonly string[],\n opts: TraverseOptions,\n): TraversalRow<unknown>[] {\n const { direction, maxDepth } = opts\n if (!Number.isInteger(maxDepth) || maxDepth < 0) {\n throw new Error(\n `.traverse(\"${field}\"): maxDepth must be a non-negative integer, got ` +\n `${String(maxDepth)}. It is required and has no default — an unbounded ` +\n `walk over a large collection is a denial of service against your own UI.`,\n )\n }\n const onCycle: CyclePolicy = opts.onCycle ?? 'stop'\n\n const entries = entriesOf(source)\n const lookup: (id: string) => unknown =\n source.lookupById !== undefined\n ? (id): unknown => source.lookupById?.(id)\n : ((): ((id: string) => unknown) => {\n const byId = new Map(entries.map(e => [e.id, e.record]))\n return (id): unknown => byId.get(id)\n })()\n\n // Built only for `down`: `up` follows the FK it already holds, so paying an\n // O(n) pass to answer a question it never asks would be pure waste.\n const children =\n direction === 'down'\n ? bucketByRefKey(entries, e => readPath(e.record, field))\n : undefined\n\n const emitted = new Set<string>()\n const out: TraversalRow<unknown>[] = []\n let frontier: Node[] = []\n\n for (const seedId of seeds) {\n if (emitted.has(seedId)) continue\n const record = lookup(seedId)\n if (record === undefined) continue\n emitted.add(seedId)\n const node: Node = { id: seedId, record, depth: 0, path: [seedId] }\n out.push(node)\n frontier.push(node)\n }\n\n for (let depth = 1; depth <= maxDepth && frontier.length > 0; depth++) {\n const next: Node[] = []\n for (const current of frontier) {\n for (const { id, record } of neighboursOf(current, field, direction, lookup, children)) {\n if (current.path.includes(id)) {\n if (onCycle === 'throw') {\n throw new TraversalCycleError({ field, cycle: [...current.path, id] })\n }\n continue\n }\n if (emitted.has(id)) continue\n emitted.add(id)\n const node: Node = { id, record, depth, path: [...current.path, id] }\n out.push(node)\n next.push(node)\n }\n }\n frontier = next\n }\n\n return out\n}\n\nfunction neighboursOf(\n current: Node,\n field: string,\n direction: TraverseDirection,\n lookup: (id: string) => unknown,\n children: Map<string, { id: string; record: unknown }[]> | undefined,\n): readonly { id: string; record: unknown }[] {\n if (direction === 'down') return children?.get(current.id) ?? []\n const parentId = coerceRefKey(readPath(current.record, field))\n if (parentId === null) return []\n const parent = lookup(parentId)\n // Dangling ref: the branch ends here. Deliberately NOT the join's strict\n // ref-mode throw — a traversal's answer to \"what is above this node\" is\n // \"nothing we can see\", and a missing ancestor should not take out the\n // rows the walk already found.\n if (parent === undefined) return []\n return [{ id: parentId, record: parent }]\n}\n","/**\n * #1458 — **Relate**: every multi-source and plan-level operation.\n *\n * `join` · `joinOn` · `rightJoin` · `fullOuterJoin` · `crossJoin` ·\n * `crossJoinWith` · `traverse` · `ancestorsOf` · `descendantsOf` · `explain`\n *\n * The bodies below moved out of `kernel/query/builder.ts` UNCHANGED. They read\n * `this.source` / `this.plan` / `this.joinContext` exactly as they did while\n * they were class members, because at runtime that is precisely what they\n * still are: `install()` copies them onto `Query.prototype`, and TypeScript's\n * `private` never existed at runtime. The `declare` fields at the top of the\n * mixin are how the compiler is told the same thing.\n *\n * ⚠️ **Do not import this module for its side effects — import\n * `./index.js`.** This file defines the methods; the barrel installs them, and\n * the barrel is what `package.json`'s `sideEffects` list names.\n */\nimport type { QueryField } from '../../types.js'\nimport { Query } from '../builder.js'\nimport type { DeclaredPredicate, InternalSource, QueryPlan, QuerySource } from '../builder.js'\nimport type { CrossJoinClause } from '../predicate.js'\nimport { gateTerminal } from '../hydration.js'\nimport type { ReduceStrategy } from '../../../with-lookup/reduce/strategy.js'\nimport type { JoinableSource, JoinContext, JoinDirection, JoinLeg, JoinStrategy } from './join.js'\nimport { DEFAULT_CROSS_JOIN_MAX_ROWS } from './join.js'\nimport { normalizeJoinOn, type JoinOnSpec } from './join-on.js'\nimport type { QueryExplanation } from './explain.js'\nimport { explainPlan } from './explain.js'\nimport type { CyclePolicy, TraversalRow, TraverseDirection, TraverseOptions } from './traverse.js'\nimport { runTraversal } from './traverse.js'\nimport { CrossJoinTooLargeError, RefNotDeclaredError } from '../../errors.js'\n\n/**\n * The Relate half of `Query`, as a mixin whose prototype is copied onto the\n * real class. Never instantiated.\n */\nexport class RelateMethods<\n T,\n S extends keyof T = never,\n Q extends keyof T & string = never,\n M extends keyof T & string = never,\n> {\n // ─── The instance state these bodies read (see the header) ──────────────\n declare protected readonly source: InternalSource\n declare protected readonly plan: QueryPlan\n declare protected readonly joinContext: JoinContext | undefined\n declare protected readonly reduceStrategy: ReduceStrategy\n declare protected readonly predicates: ReadonlyMap<string, DeclaredPredicate> | undefined\n // ─── The Find-side helpers they call ────────────────────────────────────\n declare protected decodeVia: (records: readonly unknown[], locale?: string) => unknown[]\n declare protected requireJoinContext: (terminal: string) => JoinContext\n declare ids: () => string[]\n\n /**\n * INNER join (#1361): `{ mode: 'inner' }` drops every left row whose alias\n * resolves to nothing, and types the alias NON-nullable.\n *\n * ```ts\n * invoices.query()\n * .join<'client', Client>('clientId', { as: 'client', mode: 'inner' })\n * .orderBy('total', 'desc')\n * .limit(10)\n * // → the ten largest invoices THAT HAVE a client; `row.client.name` needs\n * // no null check.\n * ```\n *\n * The long-hand `.join(f, { as }).where(as, '!=', null)` returns the same\n * rows and keeps working unchanged — what it cannot do is keep the sort on\n * the pre-join side. That predicate addresses the alias, so #1030 moves the\n * WHOLE sort and page behind the legs; `mode: 'inner'` moves only the page,\n * because the drop cannot reorder a left-side sort key. `.explain()` says\n * which: `pre-join` on the `orderBy` node, `post-join` on the `page` node.\n *\n * The drop runs after `attachJoin`, so ref-mode semantics are unchanged — a\n * `strict` dangling ref still throws rather than vanishing because the\n * caller asked for an inner join.\n */\n join<As extends string, R = unknown>(\n field: QueryField<T, S>,\n opts: { as: As; mode: 'inner'; strategy?: JoinStrategy; maxRows?: number },\n ): Query<T & Record<As, R>, S, Q, M>\n join<As extends string, R = unknown>(\n field: QueryField<T, S>,\n opts: { as: As; mode?: undefined; strategy?: JoinStrategy; maxRows?: number },\n ): Query<T & Record<As, R | null>, S, Q, M>\n // The implementation signature spans both overloads: the alias is\n // non-nullable only under `mode: 'inner'`, and TS needs a return type both\n // published shapes are assignable to.\n join<As extends string, R = unknown>(\n field: QueryField<T, S>,\n // `| undefined` is load-bearing under `exactOptionalPropertyTypes`: the\n // non-inner overload publishes `mode?: undefined`, and an implementation\n // that omitted it would reject an explicitly-passed `mode: undefined`.\n opts: { as: As; mode?: 'inner' | undefined; strategy?: JoinStrategy; maxRows?: number },\n ): Query<T & Record<As, R>, S, Q, M> | Query<T & Record<As, R | null>, S, Q, M> {\n return this.withJoinLeg(field, opts, 'left') as unknown as Query<T & Record<As, R | null>, S, Q, M>\n }\n\n /**\n * DECLARED non-equi / non-id join (#1339) — a join whose `on` is data, not\n * a callback.\n *\n * ```ts\n * // composite equality — a hash join over a tuple key\n * entries.query().joinOn<'rate', Rate>('rates', {\n * as: 'rate',\n * on: [['clientId', 'clientId'], ['year', 'year']],\n * })\n *\n * // a range — nested loop over a right side sorted once\n * entries.query().joinOn<'rate', Rate>('rates', {\n * as: 'rate',\n * on: { left: 'date', op: 'between', right: ['from', 'to'] },\n * })\n * ```\n *\n * ⭐ **Why this exists when `.crossJoin({ on })` already pairs anything.**\n * `crossJoin`'s `on` is a closure. It cannot be serialized, so a\n * materialized view built over one has its drift detection disabled — the\n * plan summary records the sentinel `'[inline]'` and two different\n * predicates hash identically. A `joinOn` predicate is plain JSON: it folds\n * into `toPlan()` and into the MV `queryHash`, so an MV can genuinely\n * DEPEND on it. That, not the pairing, is the feature.\n *\n * **No `ref()` needed** — the predicate names both sides itself, so `target`\n * is the collection name rather than a declared FK field. Dangling is not a\n * concept here: a left row matching nothing gets `null` under the alias (a\n * LEFT outer join, like `.join()`), and `{ mode: 'inner' }` drops it.\n *\n * **⚠️ This join EXPANDS rows.** A ref join is one-to-one, so the left row\n * count is constant; a declared `on` emits one row per MATCH, so a left row\n * matching three right records becomes three rows. The per-side `maxRows`\n * ceilings therefore cannot bound the result, and a third ceiling on the\n * OUTPUT throws `JoinTooLargeError` with `side: 'output'`. Do not remove\n * it: without it an unbounded theta join is a hang, not an error.\n *\n * **Cost.** Composite equality is O(n + m + output). A range is\n * O(m log m) to sort the right side once, then O(log m) per left row for\n * `< <= > >=`; `between` is O(log m + p) per left row, where p is the\n * number of right intervals starting at or before the probe — which\n * degrades to O(n·m) when every interval starts early. `explain()` names\n * which of the two ran. Neither reaches the right collection's declared\n * indexes: a `JoinableSource` does not expose them.\n */\n joinOn<As extends string, R = unknown>(\n target: string,\n opts: { as: As; on: JoinOnSpec; mode: 'inner'; maxRows?: number },\n ): Query<T & Record<As, R>, S, Q, M>\n joinOn<As extends string, R = unknown>(\n target: string,\n opts: { as: As; on: JoinOnSpec; mode?: undefined; maxRows?: number },\n ): Query<T & Record<As, R | null>, S, Q, M>\n joinOn<As extends string, R = unknown>(\n target: string,\n // `| undefined` is load-bearing under `exactOptionalPropertyTypes`, same\n // as `.join()`'s implementation signature.\n opts: { as: As; on: JoinOnSpec; mode?: 'inner' | undefined; maxRows?: number },\n ): Query<T & Record<As, R>, S, Q, M> | Query<T & Record<As, R | null>, S, Q, M> {\n if (!this.joinContext) {\n throw new Error(\n `Query.joinOn() requires a join context. Use collection.query() to construct a ` +\n `join-capable Query instead of the Query constructor directly (the direct ` +\n `constructor is only used for tests with plain-object sources).`,\n )\n }\n // Validated and normalised at PLAN time, never at execution: an `on` that\n // cannot be serialised deterministically must not reach a queryHash.\n const on = normalizeJoinOn(opts.on, target)\n const leg: JoinLeg = {\n // The driving left field. Not a ref — it exists so error messages and\n // `explain()` have something to name, and it is derivable from `on`.\n field: on.kind === 'composite' ? on.pairs[0]![0] : on.left,\n as: opts.as,\n target,\n // There is no ref(), so there is no dangling-ref policy to apply.\n // 'cascade' is the mode that attaches null silently, which is exactly\n // the left-outer behaviour a declared join wants.\n mode: 'cascade',\n strategy: undefined,\n maxRows: opts.maxRows,\n ...(opts.mode === 'inner' ? { inner: true as const } : {}),\n on,\n partitionScope: 'all',\n }\n return new Query<T, S, Q, M>(\n this.source as QuerySource<T>,\n { ...this.plan, joins: [...this.plan.joins, leg] },\n this.joinContext,\n this.reduceStrategy,\n this.predicates,\n ) as unknown as Query<T & Record<As, R | null>, S, Q, M>\n }\n\n /**\n * RIGHT outer join (#1289): every record of the TARGET collection appears,\n * including one no left row points at. The mirror of `.join()`, which is\n * and always was the left outer join.\n *\n * ```ts\n * invoices.query().rightJoin<'client', Client>('clientId', { as: 'client' })\n * // → one row per invoice/client match, PLUS { client } for every client\n * // no invoice references. An invoice whose clientId matches nothing is\n * // dropped — that is what makes it a right join.\n * ```\n *\n * **The row shape is not `T`.** A right-only row carries the alias and\n * nothing else, so the left fields are typed `Partial<T>` — SQL's \"the left\n * columns are NULL\" in an object language. Read them defensively; a row\n * where `amount` is `undefined` is a real, correct result, not a bug.\n *\n * **Cost.** A forward leg follows the left row's FK and is O(1) per row. A\n * right leg cannot: the rows it must produce are exactly the ones no FK\n * names. It builds a reverse index — the left rows bucketed by FK value —\n * and walks the right snapshot against it. That is one extra pass over the\n * left set and one `Map` the size of the distinct FK values; both sides are\n * fully materialized either way, and both row ceilings still apply.\n *\n * **Ordering.** Like `.join()`, legs run AFTER `orderBy`/`limit`/`offset`\n * unless the ordering addresses the alias (#1337),\n * so those narrow the LEFT side. Rows are emitted in right-snapshot order.\n *\n * A left row whose non-null FK resolves to nothing is dropped, but the\n * ref-mode check still runs on it: `strict` still throws\n * `DanglingReferenceError`. Corruption should not become invisible because\n * the caller changed join direction.\n */\n rightJoin<As extends string, R = unknown>(\n field: QueryField<T, S>,\n opts: { as: As; strategy?: JoinStrategy; maxRows?: number },\n ): Query<Partial<T> & Record<As, R>, S, Q, M> {\n return this.withJoinLeg(field, opts, 'right') as unknown as Query<Partial<T> & Record<As, R>, S, Q, M>\n }\n\n /**\n * FULL outer join (#1289): the union of `.join()` and `.rightJoin()` —\n * every left row, every right record, matched where they meet.\n *\n * ```ts\n * invoices.query().fullOuterJoin<'client', Client>('clientId', { as: 'client' })\n * // → matched rows, plus { client: null, ...invoice } for an unreferenced\n * // invoice, plus { client } for a client no invoice points at.\n * ```\n *\n * The alias is `R | null` and the left fields are `Partial<T>`, because a\n * row can be missing either side — never both. Same reverse index, same\n * ordering and same ref-mode semantics as {@link rightJoin}; the only\n * difference is that the unmatched LEFT rows are emitted (after the\n * right-driven ones) instead of dropped.\n */\n fullOuterJoin<As extends string, R = unknown>(\n field: QueryField<T, S>,\n opts: { as: As; strategy?: JoinStrategy; maxRows?: number },\n ): Query<Partial<T> & Record<As, R | null>, S, Q, M> {\n return this.withJoinLeg(field, opts, 'full') as unknown as Query<Partial<T> & Record<As, R | null>, S, Q, M>\n }\n\n /**\n * The one place a `JoinLeg` is built. `.join()`, `.rightJoin()` and\n * `.fullOuterJoin()` differ ONLY in `direction` and in the type they\n * publish — keeping the plan-time validation (ref declared? dict join?\n * join context?) in a single body is what stops the three from drifting on\n * which errors they raise.\n */\n private withJoinLeg(\n field: string,\n opts: { as: string; mode?: 'inner' | undefined; strategy?: JoinStrategy; maxRows?: number },\n direction: JoinDirection,\n ): Query<T, S, Q, M> {\n if (!this.joinContext) {\n throw new Error(\n `Query.join() requires a join context (same for .rightJoin() and .fullOuterJoin()). Use collection.query() ` +\n `to construct a join-capable Query instead of the Query constructor ` +\n `directly (the direct constructor is only used for tests with ` +\n `plain-object sources).`,\n )\n }\n const descriptor = this.joinContext.resolveRef(field)\n // Check for dictKey join when no ref() is declared\n const isDictJoinField = !descriptor && this.joinContext.resolveDictSource?.(field) != null\n if (!descriptor && !isDictJoinField) {\n // Typed (#1139) so the MV registry can tell \"this ref is not declared YET,\n // during openVault\" from any other planning failure without matching text.\n throw new RefNotDeclaredError({\n collection: this.joinContext.leftCollection,\n field,\n message:\n `Query.join(): no ref() declared for field \"${field}\" on collection ` +\n `\"${this.joinContext.leftCollection}\". Add ` +\n `refs: { ${field}: ref('<target-collection>') } to the collection ` +\n `options, then retry. See the ref() docs for the full list of modes.`,\n })\n }\n // `direction: 'left'` is left OFF the leg rather than written as the\n // default: a plan built by `.join()` must serialize byte-identically to\n // the one it built before #1289, or every stored queryHash moves.\n const directionField = direction === 'left' ? {} : { direction }\n // Same discipline as `directionField` (#1361): a non-inner leg carries no\n // `inner` key at all, so its serialized plan — and its queryHash — is\n // byte-identical to the pre-#1361 one.\n const innerField = opts.mode === 'inner' ? { inner: true as const } : {}\n const leg: JoinLeg = descriptor\n ? {\n field,\n as: opts.as,\n target: descriptor.target,\n mode: descriptor.mode,\n strategy: opts.strategy,\n maxRows: opts.maxRows,\n ...directionField,\n ...innerField,\n // The partition seam — always 'all'. Do not remove, and do not\n // populate without reading JoinLeg.partitionScope's two\n // constraints (#1342): this value is inside every stored MV\n // queryHash. Pinned by __tests__/query-partition-scope.test.ts.\n partitionScope: 'all',\n }\n : {\n // Dict join leg\n field,\n as: opts.as,\n target: field, // dict name = field name for dictKey\n mode: 'strict',\n strategy: opts.strategy,\n maxRows: opts.maxRows,\n partitionScope: 'all',\n ...directionField,\n ...innerField,\n isDictJoin: true,\n }\n return new Query<T, S, Q, M>(\n this.source as QuerySource<T>,\n { ...this.plan, joins: [...this.plan.joins, leg] },\n this.joinContext,\n this.reduceStrategy,\n this.predicates,\n )\n }\n\n /**\n * Cartesian-product cross-join against `target` collection. Each result row\n * carries the original `T` fields plus `result[as]` populated from every\n * right-side row (or the filtered subset when `on:` is supplied).\n *\n * **⚠️ INNER-join semantics — an empty right subset DROPS the left row.**\n * Each left row is emitted once per matching right row, so when `on:`\n * yields nothing the row vanishes with no error, no warning and no count\n * mismatch. This bites hardest on a reverse FK, where `.join()` (which is\n * forward-only, and already a genuine LEFT outer join) does not apply and\n * `.crossJoin()` is the only tool. To keep the row, return a one-element\n * array holding `null`:\n *\n * ```ts\n * .crossJoin('clients', { as: 'client', on: (b) => byEntity.get(b.entityId) ?? [null] })\n * // ^^^^^^^^\n * // the ONLY thing preserving the row\n * ```\n *\n * **Prefer `outer: true`**, which does exactly this and types the alias as\n * `TTarget | null`:\n *\n * ```ts\n * .crossJoin('clients', { as: 'client', outer: true, on: (b) => byEntity.get(b.entityId) ?? [] })\n * ```\n *\n * The `?? [null]` form remains valid and is what `outer` does internally, but\n * it is invisible intent: it types the alias as non-null while the row can\n * hold null, and a later \"simplification\" that drops it silently\n * reintroduces the row loss.\n *\n * **Order matters:** `.where().crossJoin()` filters BEFORE expanding (cheaper);\n * `.crossJoin().where('alias.field', ...)` filters AFTER (required when the\n * where clause references the aliased fields).\n *\n * **Cost ceiling:** `CrossJoinTooLargeError` fires before allocation when\n * `leftRows × rightRows` (or the cumulative lateral count) exceeds the limit.\n * Default: 50,000 rows. Override per-clause with `{ maxRows: N }`.\n *\n * **`on:` shapes:**\n * - `on: (left) => TTarget[]` — subset form (most efficient)\n * - `on: (left) => (right) => boolean` — predicate form\n * - `on: { predicate: 'name' }` — MV-safe, hash-tracked form\n * (requires the Query to have been augmented via `_withPredicates`)\n *\n * Requires a JoinContext (constructed via `collection.query()`).\n */\n crossJoin<TTarget = unknown, As extends string = string, TOuter extends boolean = false>(\n target: string,\n opts: {\n as: As\n on?:\n | ((left: T) => unknown[] | ((right: TTarget) => boolean))\n | { readonly predicate: string }\n maxRows?: number\n /**\n * Keep the left row when its right side is empty, with `null` under\n * `as`, instead of dropping it (#1130). Widens the alias to\n * `TTarget | null` — which is why it is a type parameter rather than a\n * plain boolean: `outer: false` must not pay for a null the row can\n * never hold.\n */\n outer?: TOuter\n },\n ): Query<T & { [K in As]: TOuter extends true ? TTarget | null : TTarget }, S, Q, M> {\n if (!this.joinContext) {\n throw new Error(\n `Query.crossJoin(\"${target}\"): requires a join context. ` +\n `Use collection.query() to construct a cross-join-capable Query instead of ` +\n `the Query constructor directly.`,\n )\n }\n\n let onFn: CrossJoinClause['on']\n let onPredicateName: string | undefined\n\n if (opts.on !== undefined) {\n if (typeof opts.on === 'function') {\n onFn = opts.on as CrossJoinClause['on']\n if (this.predicates) {\n console.warn(\n `Query.crossJoin(\"${target}\", { on: callback }): inline on: callback inside a ` +\n `withMaterializedView query() disables queryHash drift detection for this cross-join. ` +\n `Use on: { predicate: '<name>' } to enable it.`,\n )\n }\n } else {\n const predName = (opts.on as { predicate: string }).predicate\n if (!this.predicates) {\n throw new Error(\n `Query.crossJoin(\"${target}\", { on: { predicate: \"${predName}\" } }): ` +\n `the { predicate } form requires a predicates map. ` +\n `Use this form inside a withMaterializedView query() callback that declares ` +\n `predicates: { ${predName}: { hash, fn } }.`,\n )\n }\n const decl = this.predicates.get(predName)\n if (!decl) {\n throw new Error(\n `Query.crossJoin(\"${target}\"): predicate \"${predName}\" not registered. ` +\n `Available: ${[...this.predicates.keys()].join(', ') || '(none)'}.`,\n )\n }\n const as = opts.as\n const predicateFn = decl.fn\n onFn = (_left: unknown): ((right: unknown) => boolean) =>\n (right: unknown) =>\n predicateFn({ ...(_left as Record<string, unknown>), [as]: right })\n onPredicateName = predName\n }\n }\n\n const clause: CrossJoinClause = {\n type: 'crossJoin',\n target,\n as: opts.as,\n ...(onFn !== undefined && { on: onFn }),\n ...(onPredicateName !== undefined && { onPredicateName }),\n ...(opts.maxRows !== undefined && { maxRows: opts.maxRows }),\n ...(opts.outer === true && { outer: true as const }),\n }\n\n type Row = T & { [K in As]: TOuter extends true ? TTarget | null : TTarget }\n return new Query<Row, S, Q, M>(\n this.source as unknown as QuerySource<Row>,\n { ...this.plan, clauses: [...this.plan.clauses, clause] },\n this.joinContext,\n this.reduceStrategy,\n this.predicates,\n )\n }\n\n /**\n * Self cross-join with BOTH sides aliased (#1289).\n *\n * ```ts\n * const pairs = trades.query()\n * .crossJoinWith({ leftAs: 'a', rightAs: 'b', on: (t) => laterThan(t) })\n * .toArray()\n * // → [{ a: Trade, b: Trade }, ...] — no field at the top level\n * ```\n *\n * `.crossJoin('trades', { as: 'other' })` can already pair a collection\n * with itself, but only ASYMMETRICALLY: the left row's fields stay at the\n * top level and only the right side gets a name. Every comparison then\n * reads `r.amount` against `r.other.amount`, which is exactly the shape\n * that makes an accidentally-transposed pair invisible.\n *\n * ⚠️ **The cost is not the join, it is the Via dressing.** Aliasing the\n * left row moves every field off the top level, and the money / i18n /\n * lookup pipeline keys by BARE FIELD NAME — so the plain top-level decode\n * `toArray()` applies cannot see either side. Both aliases are therefore\n * dressed explicitly, through the source's own Via result decode, before\n * the rows are returned. Silently serving raw money under an alias is the\n * failure this method exists to not have; `dressAliases` is where it is\n * prevented and `__tests__/query-outer-join.test.ts` is what proves it.\n *\n * `on:` takes the same subset / predicate shapes as `.crossJoin()`, and the\n * same `maxRows` ceiling applies to the product. The target is always this\n * query's own collection — a cross-join against a DIFFERENT collection is\n * `.crossJoin()`, which needs no left alias to stay unambiguous.\n *\n * The returned `Query` drops this query's schema / queryable / money field\n * parameters. That is not laziness: those parameters name TOP-LEVEL fields,\n * and after `crossJoinWith` there are no top-level fields — only the two\n * aliases. Carrying them would let `where('amount', ...)` type-check on a\n * row where `amount` does not exist.\n */\n crossJoinWith<LeftAs extends string, RightAs extends string>(\n opts: {\n leftAs: LeftAs\n rightAs: RightAs\n on?: ((left: T) => unknown[] | ((right: T) => boolean)) | { readonly predicate: string }\n maxRows?: number\n },\n ): Query<{ [K in LeftAs]: T } & { [K in RightAs]: T }> {\n if (!this.joinContext) {\n throw new Error(\n `Query.crossJoinWith(): requires a join context. ` +\n `Use collection.query() to construct a cross-join-capable Query instead of ` +\n `the Query constructor directly.`,\n )\n }\n if ((opts.leftAs as string) === (opts.rightAs as string)) {\n throw new Error(\n `Query.crossJoinWith({ leftAs: \"${opts.leftAs}\", rightAs: \"${opts.rightAs}\" }): ` +\n `the two aliases must differ — a self cross-join whose sides share a name ` +\n `would emit the right row under both and silently lose the left one.`,\n )\n }\n // Built through `.crossJoin()` so the `on:`-shape validation, the\n // predicate-map lookup and the queryHash-drift warning have exactly one\n // implementation; `leftAs` is then folded into the clause it produced.\n const built = this.crossJoin<T, RightAs, false>(this.joinContext.leftCollection, {\n as: opts.rightAs,\n ...(opts.on !== undefined && { on: opts.on }),\n ...(opts.maxRows !== undefined && { maxRows: opts.maxRows }),\n })\n const plan = built._plan()\n const last = plan.clauses[plan.clauses.length - 1] as CrossJoinClause\n const clauses = [...plan.clauses.slice(0, -1), { ...last, leftAs: opts.leftAs }]\n type Row = { [K in LeftAs]: T } & { [K in RightAs]: T }\n return new Query<T, S, Q, M>(\n this.source as QuerySource<T>,\n { ...plan, clauses },\n this.joinContext,\n this.reduceStrategy,\n this.predicates,\n ) as unknown as Query<Row>\n }\n\n /**\n * Describe how this plan WOULD run (#1348): the dispatch per clause\n * (`index:hash` vs `scan`, and why), row estimates taken from real index\n * cardinalities, join strategy and side sizes against the row ceiling,\n * whether ordering/pagination lands pre- or post-join, and which\n * cardinality caps are close to tripping. `.text` renders one line per\n * node.\n *\n * ⛔ Purely observational — it probes index buckets and reads snapshot\n * sizes, never executes the plan. A terminal returns the same thing\n * whether or not `explain()` was called. See `query/explain.ts`.\n */\n explain(): QueryExplanation {\n return explainPlan(this.source, this.plan, this.joinContext)\n }\n\n /**\n * Recursive traversal over ONE declared, self-referencing `ref()` field\n * (#1352) — the org-chart / bill-of-materials / parent-client shape that\n * otherwise forces the consumer to hand-roll recursion.\n *\n * ```ts\n * people.query().where('name', '==', 'Dana')\n * .traverse('parentId', { direction: 'up', maxDepth: 10 })\n * // → [{ id: 'dana', record, depth: 0, path: ['dana'] },\n * // { id: 'bea', record, depth: 1, path: ['dana', 'bea'] }, …]\n * ```\n *\n * **A TERMINAL.** It returns rows, not a `Query`, so it composes with\n * `where()` / `orderBy()` / `limit()` on the way IN, not on the way out.\n *\n * **Seeds are this query's matched records** — the clauses choose the roots\n * of the walk, not which nodes the walk may pass through. A traversal from\n * one seed is `ancestorsOf` / `descendantsOf` below.\n *\n * **`maxDepth` is required**, with no default: an unbounded walk over a\n * large collection is a denial of service against your own UI, and a\n * silent default would truncate a result without saying so.\n *\n * **Cycles terminate.** A parent chain can be circular through user error,\n * and an unguarded BFS hangs the tab. The default `{ onCycle: 'stop' }`\n * prunes a node the walk is already standing on; `'throw'` raises\n * `TraversalCycleError` for hierarchies that are supposed to be acyclic.\n *\n * **A node is emitted once**, at its shallowest depth — so a diamond (two\n * seeds converging on one ancestor) yields ONE row for that ancestor,\n * carrying the path of whichever branch reached it first.\n *\n * **Declared refs only.** This is not a general graph engine: the field\n * must carry a `ref()` whose target is this same collection.\n *\n * **Cost.** Every hop reads the vault's already-decrypted in-memory cache\n * (`query()` is eager-mode only), so a depth-5 traversal costs\n * `depth × frontier` Map lookups and ZERO additional decrypts — the\n * AES-GCM work was paid once at `openVault()`. `direction: 'down'` adds one\n * O(n) pass to build the reverse-FK index; `'up'` adds nothing.\n *\n * ⛔ **Not an `explain()` node.** `explain()` describes the plan, and a\n * traversal is a terminal over the plan's result rather than a clause in\n * it — the same reason `.window()` and #1336's post-group ops are absent.\n * `explain()` on the seed query still describes how the SEEDS are found.\n */\n traverse(field: QueryField<T, S>, opts: TraverseOptions): TraversalRow<T>[] {\n // Validation FIRST: a misdeclared ref is a programming error whose own\n // message must survive #1414's gate, not be masked by it.\n this.assertSelfRef(field, 'traverse')\n const _h = this.source.hydration\n if (_h !== undefined && !_h.isHydrated()) return gateTerminal(_h, 'traverse', () => this.traverse(field, opts))\n return this.runTraverse(field, this.ids(), opts)\n }\n\n /**\n * `.traverse()` sugar: every ancestor of one record, that record included\n * at `depth: 0`. See {@link traverse} for the full contract.\n *\n * Refused on a query that already carries clauses — the seed is named\n * explicitly here, so a `where()` would silently do nothing. Use\n * `.traverse()` when the seeds come from a query.\n */\n ancestorsOf(\n id: string,\n field: QueryField<T, S>,\n opts: { maxDepth: number; onCycle?: CyclePolicy },\n ): TraversalRow<T>[] {\n return this.traverseFromId(id, field, 'up', opts)\n }\n\n /**\n * `.traverse()` sugar: every descendant of one record, that record included\n * at `depth: 0`. See {@link traverse} for the full contract.\n */\n descendantsOf(\n id: string,\n field: QueryField<T, S>,\n opts: { maxDepth: number; onCycle?: CyclePolicy },\n ): TraversalRow<T>[] {\n return this.traverseFromId(id, field, 'down', opts)\n }\n\n private traverseFromId(\n id: string,\n field: QueryField<T, S>,\n direction: TraverseDirection,\n opts: { maxDepth: number; onCycle?: CyclePolicy },\n ): TraversalRow<T>[] {\n const _h = this.source.hydration\n if (_h !== undefined && !_h.isHydrated()) return gateTerminal(_h, direction === 'up' ? 'ancestorsOf' : 'descendantsOf', () => this.traverseFromId(id, field, direction, opts))\n const sugar = direction === 'up' ? 'ancestorsOf' : 'descendantsOf'\n const plan = this.plan\n if (\n plan.clauses.length > 0 ||\n plan.orderBy.length > 0 ||\n plan.joins.length > 0 ||\n plan.limit !== undefined ||\n plan.offset !== 0\n ) {\n throw new Error(\n `Query.${sugar}(\"${id}\"): this query already carries clauses, but ${sugar}() ` +\n `seeds from the id you passed — the clauses would silently do nothing. ` +\n `Use .traverse(\"${field}\", { direction: '${direction}', … }), whose seeds ` +\n `ARE the query's matched records, or call ${sugar}() on a bare ` +\n `collection.query().`,\n )\n }\n this.assertSelfRef(field, sugar)\n return this.runTraverse(field, [id], { ...opts, direction })\n }\n\n /**\n * The one place a traversal runs. Both entry points share it so they cannot\n * drift on Via decoding or on which source view the walk reads.\n */\n private runTraverse(\n field: string,\n seeds: readonly string[],\n opts: TraverseOptions,\n ): TraversalRow<T>[] {\n const rows = runTraversal(this.source, field, seeds, opts)\n // Same result decode `toArray()` applies — a traversal reads the raw\n // cache records, so without this a money field would serve its stored\n // scaled integer here and its canonical decimal everywhere else.\n return rows.map(row => ({ ...row, record: this.decodeVia([row.record])[0] }) as TraversalRow<T>)\n }\n\n /**\n * Plan-time validation shared by `.traverse()` and its sugar: the field must\n * carry a `ref()`, and that ref must point back at this same collection.\n *\n * The second half is what keeps this from becoming a general graph engine.\n * A ref to ANOTHER collection has no second hop — the target's records do\n * not carry this field — so a two-collection \"traversal\" is a `.join()`\n * wearing the wrong name, and would walk exactly one level before stopping\n * for reasons the caller could not see.\n */\n private assertSelfRef(field: string, caller: string): void {\n if (!this.joinContext) {\n throw new Error(\n `Query.${caller}(): requires a collection-backed query. Use collection.query() ` +\n `instead of the Query constructor directly (the direct constructor is only ` +\n `used for tests with plain-object sources).`,\n )\n }\n const descriptor = this.joinContext.resolveRef(field)\n if (!descriptor) {\n throw new RefNotDeclaredError({\n collection: this.joinContext.leftCollection,\n field,\n message:\n `Query.${caller}(): no ref() declared for field \"${field}\" on collection ` +\n `\"${this.joinContext.leftCollection}\". Traversal walks DECLARED refs only — ` +\n `add refs: { ${field}: ref('${this.joinContext.leftCollection}') } to the ` +\n `collection options, then retry.`,\n })\n }\n if (descriptor.target !== this.joinContext.leftCollection) {\n throw new Error(\n `Query.${caller}(): field \"${field}\" refs \"${descriptor.target}\", but traversal ` +\n `requires a self-referencing ref — one whose target is the collection being ` +\n `queried (\"${this.joinContext.leftCollection}\"). A ref across collections has ` +\n `no second hop; use .join(\"${field}\", { as: … }) for that.`,\n )\n }\n }\n}\n\n/**\n * The public Relate surface, named once. The `declare module` block in\n * `./index.ts` merges exactly this into `Query`, so the signatures live in one\n * place and cannot drift from the implementations above.\n *\n * `Pick` rather than the class itself: an interface that extended\n * `RelateMethods` would inherit the `protected` state declarations too, and\n * they collide with `Query`'s own `private` fields.\n */\nexport type RelateSurface<\n T,\n S extends keyof T = never,\n Q extends keyof T & string = never,\n M extends keyof T & string = never,\n> = Pick<\n RelateMethods<T, S, Q, M>,\n | 'join'\n | 'joinOn'\n | 'rightJoin'\n | 'fullOuterJoin'\n | 'crossJoin'\n | 'crossJoinWith'\n | 'traverse'\n | 'ancestorsOf'\n | 'descendantsOf'\n | 'explain'\n>\n\n/**\n * Expand `leftRel` by cross-joining with `rightSource`. Enforces the cost ceiling\n * BEFORE allocating the expanded relation (full cartesian) or cumulatively\n * (lateral form). Throws `CrossJoinTooLargeError` on breach.\n */\nexport function applyCrossJoin(\n leftRel: unknown[],\n clause: CrossJoinClause,\n rightSource: JoinableSource,\n): unknown[] {\n const rightRows = rightSource.snapshot()\n const maxRows = clause.maxRows ?? DEFAULT_CROSS_JOIN_MAX_ROWS\n const { as } = clause\n\n // `outer` substitutes a single null right-hand row wherever the right side is\n // empty, which is exactly what the documented `?? [null]` idiom did by hand\n // (#1130). Emitting `{ ...left, [as]: null }` IS the outer-join row — the flag\n // makes it typed and explicit rather than a trick a later \"simplification\"\n // silently removes. Cost accounting is unchanged: a substituted row is one\n // row, and it counts toward the ceiling like any other.\n const outer = clause.outer === true\n\n // #1289 — `leftAs` set means BOTH sides are aliased (`.crossJoinWith()`),\n // so the row is a pair rather than a left row wearing one extra field.\n const { leftAs } = clause\n const emit =\n leftAs === undefined\n ? (left: Record<string, unknown>, right: unknown): unknown => ({ ...left, [as]: right })\n : (left: Record<string, unknown>, right: unknown): unknown => ({ [leftAs]: left, [as]: right })\n\n if (!clause.on) {\n const rightSide = outer && rightRows.length === 0 ? [null] : rightRows\n const product = leftRel.length * rightSide.length\n if (product > maxRows) {\n throw new CrossJoinTooLargeError({ target: clause.target, expected: product, limit: maxRows })\n }\n const expanded: unknown[] = []\n for (const left of leftRel) {\n const leftObj = left as Record<string, unknown>\n for (const right of rightSide) {\n expanded.push(emit(leftObj, right))\n }\n }\n return expanded\n }\n\n // Lateral — ceiling is cumulative (post-filter count)\n const expanded: unknown[] = []\n let cumulative = 0\n for (const left of leftRel) {\n const callbackResult = clause.on(left)\n let filteredRight: readonly unknown[]\n if (Array.isArray(callbackResult)) {\n filteredRight = callbackResult\n } else {\n filteredRight = (rightRows as unknown[]).filter(\n callbackResult as (r: unknown) => boolean,\n )\n }\n if (outer && filteredRight.length === 0) filteredRight = [null]\n cumulative += filteredRight.length\n if (cumulative > maxRows) {\n throw new CrossJoinTooLargeError({\n target: clause.target,\n expected: cumulative,\n limit: maxRows,\n })\n }\n const leftObj = left as Record<string, unknown>\n for (const right of filteredRight) {\n expanded.push(emit(leftObj, right))\n }\n }\n return expanded\n}\n","/**\n * #1458 — the **Relate** half of `ScanBuilder`.\n *\n * `join` · plus the two streaming-join privates the iterator calls.\n *\n * ⭐ **`ScanBuilder` gets the same treatment as `Query` because it has the same\n * problem** (ruled 2026-09-06): it is one class carrying Find (`where`,\n * `filter`, the async iterator), Reduce (`aggregate`, `groupBy`) and Relate\n * (`join`) methods, and `sideEffects: false` cannot drop a method. Left\n * unsplit it would have kept `relate/join.ts` and the whole reducer engine in\n * every `/query` bundle no matter what `Query` did — the architecture rule\n * would have been true of `builder.ts` and false of the package.\n *\n * ⚠️ `buildJoinResolvers` and `applyOneJoinStreaming` are called from the\n * ITERATOR, which stays in Find. Both calls sit behind `joins.length === 0`,\n * so a Find-only scan never reaches them — the same guarantee, and the same\n * shape of guarantee, as `internal/hooks.ts` gives the eager executor.\n */\nimport { ScanBuilder } from '../scan-builder.js'\nimport type { ScanPageProvider } from '../scan-builder.js'\nimport type { QueryField } from '../../types.js'\nimport type { Clause } from '../predicate.js'\nimport type { ViaPipeline } from '../../via/pipeline.js'\nimport type { JoinContext, JoinLeg, JoinableSource } from './join.js'\nimport { DanglingReferenceError, RefNotDeclaredError } from '../../errors.js'\nimport { readPath } from '../predicate.js'\n// ⭐ `scan-builder.ts` carried a byte-identical private copy of this. The two\n// were always the same policy — \"a nullish FK is not dangling, in either\n// builder\" — so the split folded the duplicate into the one `join.ts` already\n// published rather than moving a second definition into this file.\nimport { coerceRefKey } from './join.js'\n\n/** One resolved leg, prepared once per iteration. @internal */\nexport interface ScanJoinResolver {\n leg: JoinLeg\n source: JoinableSource\n lookupById: ((id: string) => unknown) | null\n hashByPrimaryKey: ReadonlyMap<string, unknown> | null\n warnedKeys: Set<string>\n}\n\n/** @internal — the mixin whose prototype `./index.ts` copies onto `ScanBuilder`. */\nexport class ScanRelateMethods<T, S extends keyof T = never, M extends keyof T & string = never> {\n declare protected readonly pageProvider: ScanPageProvider<T>\n declare protected readonly pageSize: number\n declare protected readonly clauses: readonly Clause[]\n declare protected readonly joins: readonly JoinLeg[]\n declare protected readonly joinContext: JoinContext | undefined\n declare protected readonly via: ViaPipeline | undefined\n\n /**\n * Resolve a `ref()`-declared foreign key per record as the scan\n * stream flows, attaching the right-side record (or null) under\n * `opts.as`. — streaming joins over `scan()`.\n *\n * ```ts\n * for await (const inv of invoices.scan().join('clientId', { as: 'client' })) {\n * await processInvoice(inv) // inv.client is attached\n * }\n *\n * // Or terminate with .aggregate() for streaming joined aggregation\n * const { total } = await invoices.scan()\n * .where('status', '==', 'open')\n * .join('clientId', { as: 'client' })\n * .aggregate({ total: sum('amount') })\n * ```\n *\n * **The key difference from eager `.join()`:** the LEFT\n * side streams page-by-page from the adapter and is never\n * materialized. Memory ceiling on the left is O(pageSize), not\n * O(rowCount). This is what makes streaming joins suitable for\n * collections that exceed the eager join's 50_000-row ceiling.\n *\n * **Right-side strategy** is auto-selected per leg:\n * - **Indexed** — right source exposes `lookupById`, so each\n * left row costs O(1). This is the common path for\n * Collection right sides, which back `lookupById` with a Map\n * lookup over the in-memory cache. The right collection must\n * be in eager mode (the same constraint as eager join's\n * `querySourceForJoin` from ).\n * - **Hash** — right source has only `snapshot()`. Build a\n * `Map<id, record>` once at iteration start, probe per left\n * row. Same correctness, same per-row cost as the indexed\n * path; the difference is the upfront cost of materializing\n * the right side once.\n *\n * Both strategies hold the right side in memory for the duration\n * of the iteration. The \"streaming\" property applies to the LEFT\n * side only — true left-and-right streaming joins (where neither\n * side fits in memory) require a sort-merge join planner that's\n * out of scope for.\n *\n * **Ref-mode semantics** match eager `.join()` exactly:\n * - `strict` → throws `DanglingReferenceError` mid-stream\n * when a left record points at a non-existent right id.\n * The throw aborts the async iterator — consumers should\n * wrap the `for await` in try/catch if they want to recover.\n * - `warn` → attaches `null` and emits a one-shot warning\n * per unique dangling pair (deduped via the same warn\n * channel as eager join).\n * - `cascade` → attaches `null` silently. A delete-time mode;\n * dangling refs at read time are mid-flight or pre-existing\n * orphans, not a DSL error.\n *\n * Left records with null/undefined FK values attach `null`\n * regardless of mode — same \"no reference at all\" policy as\n * eager join and write-time `enforceRefsOnPut`.\n *\n * **Multi-FK chaining** is supported via repeated `.join()`\n * calls: each leg resolves an independent ref. Each leg\n * independently picks its right-side strategy and applies its\n * own ref mode.\n *\n * **Joins are NOT applied** to a `.aggregate()` terminal that\n * doesn't reference joined fields — wait, that's not quite\n * right. The streaming path actually DOES apply joins before\n * `.aggregate()` because the join attaches a field that the\n * spec might reference. Unlike `Query.aggregate()` (which skips\n * joins entirely as a projection-only short-circuit), the\n * streaming aggregation can't know whether the spec touches a\n * joined field, so it always applies joins. Consumers who want\n * unjoined streaming aggregation should leave `.join()` off the\n * chain — the chain is composable for a reason.\n *\n * Every JoinLeg carries `partitionScope: 'all'`, plumbed through but never\n * read. Same seam as the eager join — see {@link JoinLeg.partitionScope}.\n */\n join<As extends string, R = unknown>(\n field: QueryField<T, S>,\n opts: { as: As },\n ): ScanBuilder<T & Record<As, R | null>, S, M> {\n if (!this.joinContext) {\n throw new Error(\n `ScanBuilder.join() requires a join context. Use ` +\n `collection.scan() to construct a join-capable scan instead ` +\n `of the ScanBuilder constructor directly (the direct ` +\n `constructor is only used for tests with synthetic page ` +\n `providers).`,\n )\n }\n const descriptor = this.joinContext.resolveRef(field)\n if (!descriptor) {\n // Typed for the same reason `Query.join()` is (#1139) — see RefNotDeclaredError.\n throw new RefNotDeclaredError({\n collection: this.joinContext.leftCollection,\n field,\n message:\n `ScanBuilder.join(): no ref() declared for field \"${field}\" on ` +\n `collection \"${this.joinContext.leftCollection}\". Add ` +\n `refs: { ${field}: ref('<target-collection>') } to the ` +\n `collection options, then retry.`,\n })\n }\n const leg: JoinLeg = {\n field,\n as: opts.as,\n target: descriptor.target,\n mode: descriptor.mode,\n strategy: undefined,\n maxRows: undefined,\n // Always 'all', never read by the streaming executor. This is the\n // path where partition pruning would actually pay (every listPage()\n // page is decrypted) — and the path blocked on a store-contract\n // change. See JoinLeg.partitionScope constraint 2 (#1342).\n partitionScope: 'all',\n }\n return new ScanBuilder<T & Record<As, R | null>, S, M>(\n this.pageProvider as unknown as ScanPageProvider<T & Record<As, R | null>>,\n this.pageSize,\n this.clauses,\n [...this.joins, leg],\n this.joinContext,\n this.via,\n )\n }\n\n /**\n * Iterate the scan as an async iterable. Walks the page\n * provider's cursors forward until exhaustion, applying every\n * clause per record — only matching records are yielded.\n *\n * Backward-compatible with the previous async-generator `scan()`\n * return type for `for await … of` consumers.\n */\n\n /**\n * Per-leg right-side resolution state. Built once at iteration\n * start and reused for every left record. Two strategies:\n *\n * - `lookupById`: present when the right source exposes the\n * hook directly (typical Collection right side). Per-row\n * cost is O(1).\n * - `hashByPrimaryKey`: built from `snapshot()` when no\n * lookupById. Per-row cost is O(1) after the upfront O(N)\n * materialization. Same as eager join's hash strategy.\n *\n * `warnedKeys` is the per-leg dedup set for ref-mode 'warn'. We\n * key on `field→target:refId` so the same dangling pair only\n * warns once per iteration. The dedup is per-iteration, not\n * per-process — a long-running scan that re-iterates would warn\n * again, which is the desired behavior (the data may have\n * changed between iterations).\n */\n private buildJoinResolvers(): Array<{\n leg: JoinLeg\n source: JoinableSource\n lookupById: ((id: string) => unknown) | null\n hashByPrimaryKey: ReadonlyMap<string, unknown> | null\n warnedKeys: Set<string>\n }> {\n if (!this.joinContext) {\n // Unreachable — .join() throws if joinContext is missing.\n // Belt-and-braces because the iterator is invoked via\n // Symbol.asyncIterator on a builder that may have been\n // constructed via the direct constructor with pre-populated\n // joins.\n throw new Error(\n `ScanBuilder iterator: ${this.joins.length} join leg(s) ` +\n `present but no JoinContext attached. Use collection.scan() ` +\n `to construct a join-capable scan.`,\n )\n }\n const resolvers: Array<{\n leg: JoinLeg\n source: JoinableSource\n lookupById: ((id: string) => unknown) | null\n hashByPrimaryKey: ReadonlyMap<string, unknown> | null\n warnedKeys: Set<string>\n }> = []\n for (const leg of this.joins) {\n // #1339 — unreachable today (`ScanBuilder` builds its own ref legs and\n // has no `.joinOn()`), and loud rather than silent if that ever\n // changes: a declared `on` is many-to-many, so it emits one row per\n // match, which the one-record-in/one-record-out streaming contract\n // below cannot express.\n if (leg.on !== undefined) {\n throw new Error(\n `ScanBuilder: the declared \\`on\\` join leg \"${leg.as}\" cannot stream — it emits one row ` +\n `per match, while scan() yields one row per stored record. Use collection.query().joinOn().`,\n )\n }\n const source = this.joinContext.resolveSource(leg.target)\n if (!source) {\n throw new Error(\n `ScanBuilder.join() cannot resolve target collection ` +\n `\"${leg.target}\" (referenced from field \"${leg.field}\" on ` +\n `\"${this.joinContext.leftCollection}\"). Make sure the target ` +\n `collection has been opened via vault.collection() ` +\n `at least once before iterating the scan.`,\n )\n }\n // Strategy selection: prefer lookupById when available\n // (O(1) per row, no upfront cost), fall back to hashing\n // snapshot() once otherwise.\n let lookupById: ((id: string) => unknown) | null = null\n let hashByPrimaryKey: ReadonlyMap<string, unknown> | null = null\n if (source.lookupById) {\n // Bind through an arrow so the lookupById's `this`\n // doesn't drift — same pattern as the eager join's\n // strategy resolver.\n const fn = source.lookupById.bind(source)\n lookupById = (id: string): unknown => fn(id)\n } else {\n const map = new Map<string, unknown>()\n for (const record of source.snapshot()) {\n const rawId = readPath(record, 'id')\n const key = coerceRefKey(rawId)\n if (key !== null) map.set(key, record)\n }\n hashByPrimaryKey = map\n }\n resolvers.push({\n leg,\n source,\n lookupById,\n hashByPrimaryKey,\n warnedKeys: new Set<string>(),\n })\n }\n return resolvers\n }\n\n /**\n * Resolve a single join leg for one left record and return the\n * left record with the joined field attached under\n * `leg.as`. Pure function over `(left, resolver)`; never\n * mutates the input.\n *\n * Ref-mode dispatch matches eager `applyJoins` from :\n * - null/undefined FK → attach null silently (always allowed)\n * - dangling FK + strict → throw `DanglingReferenceError`\n * - dangling FK + warn → attach null, warn-once per pair\n * - dangling FK + cascade → attach null silently\n */\n private applyOneJoinStreaming(\n left: unknown,\n resolver: {\n leg: JoinLeg\n source: JoinableSource\n lookupById: ((id: string) => unknown) | null\n hashByPrimaryKey: ReadonlyMap<string, unknown> | null\n warnedKeys: Set<string>\n },\n ): unknown {\n if (left === null || typeof left !== 'object') {\n // Pathological input; matches eager join's defensive return.\n return left\n }\n const { leg } = resolver\n const rawId = readPath(left, leg.field)\n const refKey = coerceRefKey(rawId)\n let right: unknown = undefined\n if (refKey !== null) {\n if (resolver.lookupById !== null) {\n right = resolver.lookupById(refKey)\n } else if (resolver.hashByPrimaryKey !== null) {\n right = resolver.hashByPrimaryKey.get(refKey)\n }\n }\n\n const merged: Record<string, unknown> = {\n ...(left as Record<string, unknown>),\n }\n if (right === undefined) {\n // No matching record. Distinguish \"no ref at all\" (null FK)\n // from \"dangling ref\" (FK pointed at nothing).\n if (refKey !== null && leg.mode === 'strict') {\n throw new DanglingReferenceError({\n field: leg.field,\n target: leg.target,\n refId: refKey,\n message:\n `ScanBuilder.join() strict dangling: record references ` +\n `\"${leg.target}:${refKey}\" via field \"${leg.field}\", but no ` +\n `such record exists. Use ref() mode 'warn' or 'cascade' if ` +\n `dangling refs are acceptable, or run ` +\n `vault.checkIntegrity() to find and fix the orphans.`,\n })\n }\n if (refKey !== null && leg.mode === 'warn') {\n const dedupKey = `${leg.field}→${leg.target}:${refKey}`\n if (!resolver.warnedKeys.has(dedupKey)) {\n resolver.warnedKeys.add(dedupKey)\n console.warn(\n `[noy-db] ScanBuilder.join() encountered dangling ref in ` +\n `'warn' mode: field \"${leg.field}\" → \"${leg.target}:` +\n `${refKey}\" not found. Attaching null.`,\n )\n }\n }\n // strict already threw above; warn falls through here; cascade\n // hits this path silently.\n merged[leg.as] = null\n } else {\n merged[leg.as] = right\n }\n return merged\n }\n\n /**\n * Reduce the scan stream through a named set of reducers and\n * return the final aggregated shape.\n *\n * Memory is O(reducers): one mutable state slot per spec key.\n * Records flow through the pipeline one at a time via\n * `for await` and are discarded after their `step()` is applied\n * — never collected into an array. This is the distinguishing\n * property from `Query.aggregate()`, which materializes the full\n * match set first.\n *\n * Reuses the same reducer protocol as `Query.aggregate()`,\n * so `count()`, `sum(field)`, `avg(field)`, `min(field)`,\n * `max(field)` all work unchanged. The `{ seed }` parameter\n * plumbing from constraint #2 is honored transparently — the\n * factories ignore it in and the scan executor never\n * touches the per-reducer state construction.\n *\n * **Returns a Promise**, unlike `Query.aggregate().run()` which\n * is synchronous. The scan is inherently async because it walks\n * adapter pages, so the terminal has to be too. Consumers\n * destructure with await:\n *\n * ```ts\n * const { total, n } = await invoices.scan()\n * .where('year', '==', 2025)\n * .aggregate({ total: sum('amount'), n: count() })\n * ```\n *\n * **No `.live()` in.** `scan().aggregate().live()` would\n * require reconciling an unbounded streaming iteration with a\n * change-stream subscription — a design problem, not just a code\n * one. Consumers with huge collections and live needs should\n * narrow with `.where()` enough to fit in the 50k `query()`\n * limit and use `query().aggregate().live()` instead.\n *\n * Consults the Via pipeline's posture before reducing (#629 Task 8 review\n * fix wave 1): a reducer over a field whose posture is `queryable: 'none'`\n * throws `FieldNotQueryableError` here, metadata-only — via\n * `ViaPipeline.refuseUnqueryableReducers`, NOT the full `wrapReducers`\n * (which would also activate money's exact-reducer rewrite, a path this\n * method has never run and must not start running as a side effect of\n * this gate).\n */\n // `const` so an inline `[specA, specB]` infers as a TUPLE, not a `Spec[]` —\n // that is what makes `const [a, b] = await …` land on the right shapes.\n}\n\n/** The public Relate surface of `ScanBuilder` — merged by `./index.ts`. */\nexport type ScanRelateSurface<\n T,\n S extends keyof T = never,\n M extends keyof T & string = never,\n> = Pick<ScanRelateMethods<T, S, M>, 'join'>\n","/**\n * #1458 — the Relate install, as a FUNCTION rather than a module side effect.\n *\n * ⛔ **This shape is load-bearing and was arrived at by measurement.** The\n * install used to be a top-level statement in `./index.ts`. `./index.ts` was\n * then reachable from two build entries — its own subpath AND the root barrel —\n * so esbuild's code-splitting moved its module body into a SHARED CHUNK, and\n * the built `dist/query/relate/index.js` became nothing but a list of chunk\n * imports. `package.json`'s `sideEffects` names the entry file; it cannot name\n * a hash-named chunk. So a consumer's bundler saw a side-effect-free bare\n * import and dropped it — `import '@noy-db/hub/query/relate'` compiled, shipped,\n * and installed nothing.\n *\n * ⭐ Measured, not theorised: the three control scenarios in\n * `scripts/check-bundle.mjs` reported all three groups byte-identical to\n * Find-only, and `MISSING:function reducerBuilder — the side-effect import did\n * not bring it`. That is the whole reason those controls exist.\n *\n * Keeping the CALL in `./index.ts` and the WORK here means the entry file has a\n * statement of its own, so it stays an entry rather than dissolving into\n * chunks. The root barrel calls this function directly, from its own module\n * body, for the same reason.\n */\nimport { Query } from '../builder.js'\nimport { ScanBuilder } from '../scan-builder.js'\nimport { installMethods } from '../internal/core.js'\nimport { installRelateHooks } from '../internal/hooks.js'\nimport { RelateMethods, applyCrossJoin } from './methods.js'\nimport { ScanRelateMethods } from './scan-methods.js'\nimport { applyJoins, joinsDropLeftRows, orderReferencesJoinAlias, splitAroundJoins } from './join.js'\n\nlet done = false\n\n/** Idempotent: the root barrel and the subpath entry both call it. */\nexport function installRelate(): void {\n if (done) return\n done = true\n installMethods(Query.prototype, RelateMethods)\n installMethods(ScanBuilder.prototype, ScanRelateMethods)\n installRelateHooks({\n applyJoins,\n splitAroundJoins,\n orderReferencesJoinAlias,\n joinsDropLeftRows,\n applyCrossJoin,\n })\n}\n"],"mappings":"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","names":["ids","expanded"]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  ValidationError
3
- } from "./chunk-7O3Y4PPD.js";
3
+ } from "./chunk-37EPTBBR.js";
4
4
 
5
5
  // src/with-formula/overlay-views/with-overlayed-view.ts
6
6
  function withOverlayedView(spec) {
@@ -33,4 +33,4 @@ function withOverlayedView(spec) {
33
33
  export {
34
34
  withOverlayedView
35
35
  };
36
- //# sourceMappingURL=chunk-SFAWCTEM.js.map
36
+ //# sourceMappingURL=chunk-TZZBXPZK.js.map
@@ -6,15 +6,15 @@ import {
6
6
  ViaGraph,
7
7
  matchTargetFieldNames,
8
8
  schemaFieldKeys
9
- } from "./chunk-CUQPWYRX.js";
9
+ } from "./chunk-IUT3GWP3.js";
10
10
  import {
11
11
  sha256Hex
12
- } from "./chunk-HPVZCW43.js";
12
+ } from "./chunk-EZGV6F47.js";
13
13
  import {
14
14
  DerivationCycleError,
15
15
  DuplicateBehaviorNameError,
16
16
  ValidationError
17
- } from "./chunk-7O3Y4PPD.js";
17
+ } from "./chunk-37EPTBBR.js";
18
18
 
19
19
  // src/with-formula/derivations/strategy-hash.ts
20
20
  async function computeStrategyHash(source, outputKeys, derive, sources) {
@@ -244,4 +244,4 @@ var DerivationRegistry = class {
244
244
  export {
245
245
  DerivationRegistry
246
246
  };
247
- //# sourceMappingURL=chunk-F3W6YMDC.js.map
247
+ //# sourceMappingURL=chunk-U2FZNEWJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/with-formula/derivations/strategy-hash.ts","../src/with-formula/derivations/registry.ts"],"sourcesContent":["/**\n * Deterministic hash of a derivation strategy's \"shape\": source\n * collection, declared sibling sources, output keys, derive function\n * source. Used to detect\n * strategy drift: a record whose `_derivedFrom.strategyHash` doesn't\n * match the current strategy is considered stale.\n *\n * Web Crypto SHA-256 — no extra deps.\n */\nimport { sha256Hex } from '../../capsule/index.js'\n\nexport async function computeStrategyHash(\n source: string,\n outputKeys: readonly string[],\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n derive: (...args: any[]) => any,\n sources?: ReadonlyArray<string>,\n): Promise<string> {\n const canonical = JSON.stringify({\n source,\n outputs: [...outputKeys].sort(),\n derive: derive.toString(),\n // Declared sibling sources — adding/removing a trigger\n // collection invalidates cached derived records. Omitted when empty\n // so strategies without siblings keep their existing hash.\n ...(sources?.length ? { sources: [...sources].sort() } : {}),\n })\n const bytes = new TextEncoder().encode(canonical)\n return sha256Hex(bytes)\n}\n","import { matchTargetFieldNames } from '../../kernel/collection-config.js'\nimport { DerivationCycleError, DuplicateBehaviorNameError, ValidationError } from '../../kernel/errors.js'\nimport { ViaGraph, type FieldRef, type EdgeKind, type Grain } from '../../kernel/via/graph.js'\nimport { schemaFieldKeys } from '../../with-shape/introspection/describe.js'\nimport { computeStrategyHash } from './strategy-hash.js'\nimport { hopCollections, normalizeTriggerBy, type NormalizedTrigger } from './trigger-match.js'\nimport type { DerivationSpec } from './types.js'\n\n/**\n * Whole-record artifact-grain field marker (#638 Task 2). A derivation's\n * `derive()`/a rollup's `compute()` reads the WHOLE source record — there is\n * no single declared field to point at — so a trigger/output collection is\n * modelled as one artifact node per collection (`kernel/via/graph.ts`'s\n * \"Artifact-grain targets... modelled as a field node whose field is the\n * artifact key\" convention). MUST match `materialized-views/registry.ts`'s\n * and `vault.ts`'s overlay-edge marker so cross-registry edges (a derivation\n * feeding into / out of an MV or overlay collection) resolve to the SAME\n * graph node.\n */\nconst WHOLE_RECORD = '*'\n\n/** Strip this registry's `.${WHOLE_RECORD}` artifact suffix off a graph cycle\n * path entry, recovering the bare collection name — preserves the exact\n * pre-#638 `DerivationCycleError` message shape (behavior lock) for a pure\n * record-shape derivation cycle. A rollup's real-field target (not suffixed\n * `.${WHOLE_RECORD}`) is left untouched. */\nfunction stripArtifactSuffix(displayId: string): string {\n const suffix = `.${WHOLE_RECORD}`\n return displayId.endsWith(suffix) ? displayId.slice(0, -suffix.length) : displayId\n}\n\ninterface RegisteredStrategy {\n // Type-erased to allow the registry to hold heterogeneous strategies.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n spec: DerivationSpec<any, any>\n strategyHash: string\n readonly triggers: ReadonlyArray<NormalizedTrigger>\n}\n\n/**\n * Vault-internal registry of derivation strategies. Owned by `Vault`;\n * not exported.\n *\n * @internal\n */\nexport class DerivationRegistry {\n private readonly _bySource = new Map<string, RegisteredStrategy[]>()\n private readonly _byOutput = new Map<string, RegisteredStrategy[]>()\n private readonly _byName = new Map<string, RegisteredStrategy>()\n\n /**\n * Register a derivation strategy. If `spec.name` is given and already\n * registered by another derivation in this vault, throws\n * {@link DuplicateBehaviorNameError} before indexing.\n */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n async register(spec: DerivationSpec<any, any>): Promise<void> {\n if (spec.name !== undefined && this._byName.has(spec.name)) {\n throw new DuplicateBehaviorNameError(spec.name, 'derivation')\n }\n\n const outputKeys = Object.keys(spec.outputs)\n const strategyHash = await computeStrategyHash(spec.source, outputKeys, spec.derive, spec.sources)\n const triggers = normalizeTriggerBy(spec.triggerBy)\n const reg: RegisteredStrategy = { spec, strategyHash, triggers }\n\n if (spec.name !== undefined) this._byName.set(spec.name, reg)\n\n const fromSource = this._bySource.get(spec.source)\n if (fromSource) fromSource.push(reg)\n else this._bySource.set(spec.source, [reg])\n\n // Declared sibling sources index the SAME `reg` under each\n // extra collection so `strategiesForSource(extra)` returns it and a\n // sibling write re-fires the derivation. Sibling keys also enter\n // `_bySource`, so `validate()`'s cycle DFS walks them automatically.\n for (const extra of spec.sources ?? []) {\n const fromExtra = this._bySource.get(extra)\n if (fromExtra) fromExtra.push(reg)\n else this._bySource.set(extra, [reg])\n }\n\n // FK triggers index the SAME `reg` under each parent collection so\n // a parent write re-fires the derivation (fanned out to matching source\n // records in `dispatchDerivations`). Like sources[], these keys enter\n // `_bySource` so the cycle DFS walks the trigger→output edge.\n // #1277 — the INTERMEDIATE of a declared hop is indexed too, so a write\n // that re-points it re-fires the derivation. Without this the hop's whole\n // correctness argument fails: nothing is written to the trigger or source\n // collection when an intermediate moves, so no other path can notice, and\n // every source it used to address is stranded silently. Entering `_bySource`\n // also puts the hop edge into `validate()`'s cycle DFS, which would\n // otherwise be blind to it.\n for (const t of triggers) {\n for (const hop of hopCollections(t.match)) {\n const fromHop = this._bySource.get(hop)\n if (fromHop) { if (!fromHop.includes(reg)) fromHop.push(reg) }\n else this._bySource.set(hop, [reg])\n }\n }\n for (const t of triggers) {\n const fromTrigger = this._bySource.get(t.collection)\n if (fromTrigger) fromTrigger.push(reg)\n else this._bySource.set(t.collection, [reg])\n }\n\n // Rollup: a write to the child `from` collection recomputes\n // the parent (= spec.source = into) at id child[key]. Index under `from`\n // so a child write fires it; spec.source (into) is already indexed above,\n // so a parent write also recomputes its own aggregate (covers the\n // parent-created-after-children case). The from→into edge enters the cycle\n // DFS automatically.\n if (spec.rollup) {\n const fromRollup = this._bySource.get(spec.rollup.from)\n if (fromRollup) fromRollup.push(reg)\n else this._bySource.set(spec.rollup.from, [reg])\n }\n\n for (const key of outputKeys) {\n const output = spec.outputs[key]\n if (!output) continue\n const outputCollection = output.collection\n const arr = this._byOutput.get(outputCollection)\n if (arr) arr.push(reg)\n else this._byOutput.set(outputCollection, [reg])\n }\n }\n\n strategiesForSource(source: string): ReadonlyArray<RegisteredStrategy> {\n return this._bySource.get(source) ?? []\n }\n\n strategiesProducingOutput(collection: string): ReadonlyArray<RegisteredStrategy> {\n return this._byOutput.get(collection) ?? []\n }\n\n /**\n * The #1253-pattern typo guard for match fields (#1249): a misspelt\n * `to`/`from` silently matches nothing forever, so validate against the\n * collection's enumerable field set at the earliest point it exists.\n * `schemaFieldKeys(schema) === undefined` (TS-generic collection,\n * unreadable validator) is DELIBERATELY silent — those fields are real\n * and unenumerable. `configKeys` folds in the collection's other\n * non-schema field declarations (fieldMeta/moneyFields/dictKeyFields/\n * refs/computed); `denormExempt` is derived here from this registry's\n * own strategies rather than taken as a parameter — a field this\n * collection's own derivations write via `denorm` is never a typo.\n */\n validateFieldsFor(\n collectionName: string,\n schema: unknown,\n configKeys: ReadonlyArray<string>,\n viaSources: {\n readonly computed?: Readonly<Record<string, unknown>> | undefined\n readonly viaFields?: Readonly<Record<string, unknown>> | undefined\n } | undefined = undefined,\n ): void {\n const targets = matchTargetFieldNames(viaSources ?? {})\n const virtual = new Set(targets.virtual)\n const shapeKeys = schemaFieldKeys(schema)\n // The two checks have DIFFERENT preconditions, which is why one loop runs\n // both rather than an early return covering both. The typo check needs a\n // readable field list and must stay silent without one — a false \"unknown\n // field\" on a TS-generic collection would be worse than no check. The\n // virtual check needs nothing but the declaration in hand: \"declared, and\n // never stored\" is provable from the declaration alone (#1266).\n if (shapeKeys === undefined && virtual.size === 0) return\n const keys = shapeKeys === undefined ? undefined\n : new Set([...shapeKeys, ...configKeys, ...targets.declared])\n const denormExempt = new Set<string>()\n const regs = new Set([...this._bySource.values()].flat())\n for (const reg of regs) {\n if (reg.spec.source !== collectionName) continue\n for (const out of Object.values(reg.spec.outputs) as Array<{ collection?: string; denorm?: readonly string[] }>) {\n if (out.collection === collectionName) for (const d of out.denorm ?? []) denormExempt.add(d)\n }\n }\n const unknown = (f: string): boolean =>\n keys !== undefined && !keys.has(f) && !denormExempt.has(f)\n for (const reg of regs) {\n const name = reg.spec.name ?? reg.spec.source\n for (const t of reg.triggers) {\n for (const p of t.match) {\n // `to` reads the SOURCE record; `from` reads the WRITTEN record.\n // Both are the stored shape, so both refuse a virtual target.\n if (reg.spec.source === collectionName) {\n if (virtual.has(p.to)) throw new ValidationError(this._virtualMatchMessage(name, collectionName, p.to, 'to'))\n if (unknown(p.to)) {\n throw new ValidationError(\n `derivation \"${name}\": triggerBy match names source field \"${p.to}\", which \"${collectionName}\" does not declare — a typo here silently matches nothing forever`)\n }\n }\n if (t.collection === collectionName && p.from !== 'id') {\n if (virtual.has(p.from)) throw new ValidationError(this._virtualMatchMessage(name, collectionName, p.from, 'from'))\n if (unknown(p.from)) {\n throw new ValidationError(\n `derivation \"${name}\": triggerBy match reads \"${p.from}\" from written \"${collectionName}\" records, which that collection does not declare — a typo here silently matches nothing forever`)\n }\n }\n }\n }\n }\n }\n\n /** #1266 — one message shape for both match sides; see {@link matchTargetFieldNames}. */\n private _virtualMatchMessage(name: string, collectionName: string, field: string, side: 'to' | 'from'): string {\n const where = side === 'to'\n ? `names source field \"${field}\", which \"${collectionName}\"`\n : `reads \"${field}\" from written \"${collectionName}\" records, which that collection`\n return `derivation \"${name}\": triggerBy match ${where} declares as a VIRTUAL computed field — virtual fields are evaluated on read and never stored, so the matcher would read every candidate record and match nothing, forever. Declare it as \\`mode: 'materialized'\\` (stored, indexable) or match on a stored field.`\n }\n\n /**\n * All registered strategies as a flat, deduplicated array.\n * Each strategy is indexed once per source (not once per output key),\n * so iterating `_bySource.values()` naturally yields each strategy\n * exactly once per source — deduplication is handled by flattening\n * the per-source arrays and collecting into a Set by identity.\n *\n * Used by `dumpSchema()` / `describeDerivations()` in the introspection\n * walker to populate the derivations map.\n */\n all(): ReadonlyArray<RegisteredStrategy> {\n const seen = new Set<RegisteredStrategy>()\n for (const strategies of this._bySource.values()) {\n for (const s of strategies) seen.add(s)\n }\n return [...seen]\n }\n\n /**\n * Graph edges for #638 Task 2: one `'derivation'`/`'record'` edge per\n * (non-self-write) output key — target = the output collection (a\n * `WHOLE_RECORD` artifact node), sources = every collection that can\n * trigger this strategy (`source`, `sources[]`, `triggerBy[].collection`,\n * and — for a rollup — `rollup.from`), mirroring EXACTLY the trigger keys\n * `register()` indexes under `_bySource`. The self-write reverse-denorm\n * output (`output.collection === source` with `denorm` declared) is\n * skipped — the SAME condition the old local DFS used; it is not a cycle\n * (see the comment `validate()` used to carry, now on this skip).\n * Rollups ADDITIONALLY get a dedicated `'rollup'`/`'aggregate'` edge\n * targeting the real `rollup.field` on the parent (`source`) — the\n * self-write output above only covers the cycle-DFS skip, not\n * dispatch/taint (Tasks 3/4/6), which need the real field.\n */\n edges(): ReadonlyArray<{ readonly target: FieldRef; readonly sources: readonly FieldRef[]; readonly kind: EdgeKind; readonly grain: Grain }> {\n const out: Array<{ target: FieldRef; sources: FieldRef[]; kind: EdgeKind; grain: Grain }> = []\n for (const reg of this.all()) {\n const spec = reg.spec\n const triggerCollections = [\n spec.source,\n ...(spec.sources ?? []),\n ...(spec.triggerBy ?? []).map((t) => t.collection),\n ...(spec.rollup ? [spec.rollup.from] : []),\n ]\n const sources: FieldRef[] = triggerCollections.map((c) => ({ collection: c, field: WHOLE_RECORD }))\n for (const key of Object.keys(spec.outputs)) {\n const output = spec.outputs[key]\n if (!output) continue\n if (output.shape === 'record' && output.collection === spec.source && output.denorm !== undefined) continue\n out.push({ target: { collection: output.collection, field: WHOLE_RECORD }, sources, kind: 'derivation', grain: 'record' })\n }\n if (spec.rollup) {\n out.push({\n target: { collection: spec.source, field: spec.rollup.field },\n sources: [{ collection: spec.rollup.from, field: WHOLE_RECORD }],\n kind: 'rollup',\n grain: 'aggregate',\n })\n }\n }\n return out\n }\n\n /**\n * Cycle detection, delegated to `ViaGraph.assertAcyclic()` (#638 Task 2 —\n * retires the local DFS). Call after all `register()` calls complete (i.e.\n * at vault open). Throws `DerivationCycleError` on the first cycle found —\n * SAME class/timing as before; the message/path is byte-identical to the\n * pre-#638 shape for a pure record-shape derivation cycle (the\n * `WHOLE_RECORD` artifact suffix is stripped back to a bare collection\n * name before re-throwing).\n *\n * `graph` is the caller's shared per-vault graph, ALREADY carrying this\n * registry's `edges()` (the caller registers them — see `Vault._initDerivations`)\n * — omit it (e.g. this registry's own unit tests) to validate this\n * registry's edges in isolation against a throwaway graph.\n */\n validate(graph?: ViaGraph): void {\n const g = graph ?? new ViaGraph()\n if (!graph) {\n for (const edge of this.edges()) g.registerDerived(edge.target, edge.sources, edge.kind, edge.grain)\n }\n try {\n g.assertAcyclic()\n } catch (e) {\n if (e instanceof DerivationCycleError) throw new DerivationCycleError(e.path.map(stripArtifactSuffix))\n throw e\n }\n }\n}\n"],"mappings":"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","names":[]}
@@ -6,7 +6,7 @@ import {
6
6
  ConflictError,
7
7
  InvariantError,
8
8
  ValidationError
9
- } from "./chunk-7O3Y4PPD.js";
9
+ } from "./chunk-37EPTBBR.js";
10
10
 
11
11
  // src/with-commit/tx/atomic-eligibility.ts
12
12
  function canCommitAtomically(db, ctx) {
@@ -58,6 +58,45 @@ async function bestEffortRevert(executed, adapter, compensate) {
58
58
  }
59
59
  }
60
60
 
61
+ // src/kernel/tx-write-gate.ts
62
+ var inFlight = /* @__PURE__ */ new WeakMap();
63
+ function writeGateKey(vault, collection, id) {
64
+ return `${vault}\0${collection}\0${id}`;
65
+ }
66
+ async function trackKeyedWrite(store, vault, collection, id, fn) {
67
+ let byKey = inFlight.get(store);
68
+ if (byKey === void 0) {
69
+ byKey = /* @__PURE__ */ new Map();
70
+ inFlight.set(store, byKey);
71
+ }
72
+ const key = writeGateKey(vault, collection, id);
73
+ let waiters = byKey.get(key);
74
+ if (waiters === void 0) {
75
+ waiters = /* @__PURE__ */ new Set();
76
+ byKey.set(key, waiters);
77
+ }
78
+ const running = fn();
79
+ const settled = running.then(() => void 0, () => void 0);
80
+ waiters.add(settled);
81
+ try {
82
+ return await running;
83
+ } finally {
84
+ waiters.delete(settled);
85
+ if (waiters.size === 0) byKey.delete(key);
86
+ }
87
+ }
88
+ async function drainKeyedWrites(store, keys) {
89
+ const byKey = inFlight.get(store);
90
+ if (byKey === void 0 || byKey.size === 0) return;
91
+ let waits;
92
+ for (const key of keys) {
93
+ const waiters = byKey.get(key);
94
+ if (waiters === void 0) continue;
95
+ for (const w of waiters) (waits ??= []).push(w);
96
+ }
97
+ if (waits !== void 0) await Promise.all(waits);
98
+ }
99
+
61
100
  // src/with-commit/tx/transaction.ts
62
101
  var TxContext = class {
63
102
  /** Stable id for this transaction; shared by all writes it performs. */
@@ -211,6 +250,7 @@ async function runTransaction(db, fn, options, txInvariants) {
211
250
  }
212
251
  const priorEnvelopes = /* @__PURE__ */ new Map();
213
252
  const store = db._store;
253
+ await drainKeyedWrites(store, ctx._ops.map(keyOf));
214
254
  const invariants = txInvariants ?? [];
215
255
  const watchedScopes = new Set(invariants.map((i) => i.scope));
216
256
  const plainBefore = /* @__PURE__ */ new Map();
@@ -240,17 +280,29 @@ async function runTransaction(db, fn, options, txInvariants) {
240
280
  if (canCommitAtomically(db, ctx)) {
241
281
  await db._writeQueueTracker.track(() => commitAtomicBatch(db, ctx, priorEnvelopes));
242
282
  } else {
283
+ const writtenKeys = /* @__PURE__ */ new Set();
243
284
  try {
244
285
  for (const op of ctx._ops) {
245
286
  const coll = db.vault(op.vaultName).collection(op.collectionName);
246
287
  const key = keyOf(op);
247
288
  const prior = priorEnvelopes.get(key) ?? null;
289
+ if (op.expectedVersion !== void 0 && !writtenKeys.has(key)) {
290
+ const current = await store.get(op.vaultName, op.collectionName, op.id);
291
+ const actual = current?._v ?? 0;
292
+ if (actual !== op.expectedVersion) {
293
+ throw new ConflictError(
294
+ actual,
295
+ `Transaction execute: ${op.vaultName}/${op.collectionName}/${op.id} expected v${op.expectedVersion}, found v${actual}`
296
+ );
297
+ }
298
+ }
248
299
  ctx._executed.push({ op, priorEnvelope: prior });
249
300
  if (op.type === "put") {
250
301
  await coll.put(op.id, op.record, op.reason !== void 0 ? { reason: op.reason } : void 0);
251
302
  } else {
252
303
  await coll.delete(op.id);
253
304
  }
305
+ writtenKeys.add(key);
254
306
  }
255
307
  } catch (err) {
256
308
  await revertExecuted(ctx._executed, store, db);
@@ -270,7 +322,7 @@ async function runTransaction(db, fn, options, txInvariants) {
270
322
  db._clearActiveTxContext(ctx);
271
323
  }
272
324
  if (ctx._amendment) {
273
- const { GuardExecutor } = await import("./executor-AQVXV5GZ.js");
325
+ const { GuardExecutor } = await import("./executor-LBBBRTN5.js");
274
326
  try {
275
327
  for (const [vaultName, v] of ctx._amendmentVaults) {
276
328
  const registry = v._getGuardRegistry();
@@ -441,10 +493,11 @@ function keyOf(op) {
441
493
  }
442
494
 
443
495
  export {
496
+ trackKeyedWrite,
444
497
  bestEffortRevert,
445
498
  TxContext,
446
499
  TxVault,
447
500
  TxCollection,
448
501
  runTransaction
449
502
  };
450
- //# sourceMappingURL=chunk-BLN54W3L.js.map
503
+ //# sourceMappingURL=chunk-UA372JHH.js.map