@noy-db/hub 0.7.0 → 0.8.0-pre.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 (616) hide show
  1. package/CHANGELOG.md +105 -14
  2. package/LICENSE +202 -21
  3. package/NOTICE +1 -0
  4. package/README.md +27 -10
  5. package/codemods/0.8.0-pre.json +61 -0
  6. package/dist/api-GVYEKSJE.js +19 -0
  7. package/dist/as/index.js +11 -11
  8. package/dist/at/index.js +9 -9
  9. package/dist/attestation/index.js +20 -20
  10. package/dist/{backup-IJTB4S4M.js → backup-7TFRVFLH.js} +21 -15
  11. package/dist/backup-7TFRVFLH.js.map +1 -0
  12. package/dist/blobs/index.js +13 -13
  13. package/dist/broker/index.js +12 -12
  14. package/dist/by/index.js +2 -2
  15. package/dist/cargo/index.js +39 -36
  16. package/dist/{chunk-7O3Y4PPD.js → chunk-244VXYPG.js} +140 -16
  17. package/dist/chunk-244VXYPG.js.map +1 -0
  18. package/dist/{chunk-BUE2D7PX.js → chunk-32YV3TJT.js} +2 -2
  19. package/dist/{chunk-3RCJJBNR.js → chunk-3ELRMVJK.js} +12 -12
  20. package/dist/{chunk-6GMZ7HEE.js → chunk-3F7GLNAE.js} +6 -6
  21. package/dist/{chunk-2Y4IMKA6.js → chunk-3H5KLDZN.js} +4 -4
  22. package/dist/{chunk-VTFVLCUH.js → chunk-3JWHAR6E.js} +2 -2
  23. package/dist/{chunk-YMUFFJCO.js → chunk-3TDUWVWB.js} +5 -2
  24. package/dist/chunk-3TDUWVWB.js.map +1 -0
  25. package/dist/{chunk-JBDFMYKQ.js → chunk-4AF3TUMP.js} +2 -2
  26. package/dist/{chunk-ZORTV6NH.js → chunk-4I522ERM.js} +88 -4
  27. package/dist/chunk-4I522ERM.js.map +1 -0
  28. package/dist/{chunk-MUM7IANK.js → chunk-4MXI3ODD.js} +4 -4
  29. package/dist/chunk-4MXI3ODD.js.map +1 -0
  30. package/dist/{chunk-BLN54W3L.js → chunk-5FDLC6G7.js} +56 -3
  31. package/dist/chunk-5FDLC6G7.js.map +1 -0
  32. package/dist/chunk-5O7D6ZTW.js +53 -0
  33. package/dist/chunk-5O7D6ZTW.js.map +1 -0
  34. package/dist/{chunk-J6FXAEUG.js → chunk-6B3VNR4P.js} +12 -12
  35. package/dist/{chunk-TUFM4UZP.js → chunk-6K7DPM7D.js} +2 -2
  36. package/dist/{chunk-K6LHRFBL.js → chunk-6LMQ5R26.js} +7 -7
  37. package/dist/{chunk-SPXXX5E4.js → chunk-6LNL42F5.js} +94 -32
  38. package/dist/chunk-6LNL42F5.js.map +1 -0
  39. package/dist/{chunk-XLMEZIAJ.js → chunk-6OWXYZK2.js} +2 -2
  40. package/dist/{chunk-BOWNCWZT.js → chunk-6QSQQLSE.js} +3 -3
  41. package/dist/chunk-7JE7BDYJ.js +1558 -0
  42. package/dist/chunk-7JE7BDYJ.js.map +1 -0
  43. package/dist/{chunk-KG7TZKZG.js → chunk-7VCXZDA4.js} +5 -5
  44. package/dist/chunk-7VCXZDA4.js.map +1 -0
  45. package/dist/{chunk-NQKIUNW5.js → chunk-A6IJU4TK.js} +2 -2
  46. package/dist/{chunk-BM5TWITZ.js → chunk-ANWPSTZU.js} +38 -9
  47. package/dist/chunk-ANWPSTZU.js.map +1 -0
  48. package/dist/{chunk-QIZPZMUI.js → chunk-AOWGXU6D.js} +2 -2
  49. package/dist/{chunk-CUZLNGD5.js → chunk-B2YY6WDD.js} +1 -1
  50. package/dist/chunk-B2YY6WDD.js.map +1 -0
  51. package/dist/{chunk-SFAWCTEM.js → chunk-B57AFBY2.js} +2 -2
  52. package/dist/{chunk-GPEQUXHL.js → chunk-B6SJIBQK.js} +4 -4
  53. package/dist/chunk-BJ2IXQ5Q.js +100 -0
  54. package/dist/chunk-BJ2IXQ5Q.js.map +1 -0
  55. package/dist/{chunk-Q2PU57HC.js → chunk-BK2HHQGN.js} +2 -2
  56. package/dist/chunk-BKT776R5.js +1 -0
  57. package/dist/{chunk-KUX3OB6D.js → chunk-BP6DARYA.js} +33 -5
  58. package/dist/chunk-BP6DARYA.js.map +1 -0
  59. package/dist/{chunk-FXBIP2WD.js → chunk-BUDAGWL5.js} +6 -6
  60. package/dist/chunk-CF5UU4S7.js +757 -0
  61. package/dist/chunk-CF5UU4S7.js.map +1 -0
  62. package/dist/{chunk-BOET4NA4.js → chunk-CKNGS5MH.js} +3 -3
  63. package/dist/chunk-CY2CYVWZ.js +41 -0
  64. package/dist/chunk-CY2CYVWZ.js.map +1 -0
  65. package/dist/{chunk-2577DKXB.js → chunk-DC5QVPV7.js} +2 -2
  66. package/dist/chunk-DC5QVPV7.js.map +1 -0
  67. package/dist/{chunk-YSRUYAVU.js → chunk-DE4DH2RZ.js} +2 -2
  68. package/dist/{chunk-6I2RQCET.js → chunk-DF73H4UN.js} +4 -4
  69. package/dist/{chunk-4GVM6QZA.js → chunk-ENAG3IY7.js} +2 -2
  70. package/dist/chunk-ENAG3IY7.js.map +1 -0
  71. package/dist/{chunk-K7NTTA6P.js → chunk-EOVMT6TB.js} +2 -2
  72. package/dist/chunk-F24ZZTHQ.js +193 -0
  73. package/dist/chunk-F24ZZTHQ.js.map +1 -0
  74. package/dist/chunk-F2TDU7MQ.js +456 -0
  75. package/dist/chunk-F2TDU7MQ.js.map +1 -0
  76. package/dist/chunk-F6NCB7KT.js +13 -0
  77. package/dist/chunk-F6NCB7KT.js.map +1 -0
  78. package/dist/{chunk-SPYWXKJN.js → chunk-F7XGHL5O.js} +3 -3
  79. package/dist/chunk-F7XGHL5O.js.map +1 -0
  80. package/dist/{chunk-XTXOCYOJ.js → chunk-FCKWQE2H.js} +5 -5
  81. package/dist/{chunk-U4FOQDY4.js → chunk-FH2L2E34.js} +4 -4
  82. package/dist/chunk-FH2L2E34.js.map +1 -0
  83. package/dist/{chunk-4OZNXTO4.js → chunk-FN5EBVTQ.js} +2 -2
  84. package/dist/chunk-FQ54DWUQ.js +270 -0
  85. package/dist/chunk-FQ54DWUQ.js.map +1 -0
  86. package/dist/{chunk-NKHRDYOR.js → chunk-FQ5VRHIB.js} +4 -4
  87. package/dist/{chunk-FAHMLERK.js → chunk-FW22ZCXT.js} +2 -2
  88. package/dist/chunk-FXQBGFOX.js +524 -0
  89. package/dist/chunk-FXQBGFOX.js.map +1 -0
  90. package/dist/{chunk-AO42KJO6.js → chunk-GF5BZ7D4.js} +45 -9
  91. package/dist/chunk-GF5BZ7D4.js.map +1 -0
  92. package/dist/{chunk-TRGTKX5E.js → chunk-GHLTDZRS.js} +5 -3
  93. package/dist/{chunk-TRGTKX5E.js.map → chunk-GHLTDZRS.js.map} +1 -1
  94. package/dist/{chunk-5WDXHNSW.js → chunk-HBPPGWUM.js} +5 -5
  95. package/dist/chunk-HBPPGWUM.js.map +1 -0
  96. package/dist/{chunk-KTFRCC5C.js → chunk-HBRLNOHL.js} +82 -8
  97. package/dist/chunk-HBRLNOHL.js.map +1 -0
  98. package/dist/chunk-HLEK5VAN.js +275 -0
  99. package/dist/chunk-HLEK5VAN.js.map +1 -0
  100. package/dist/{chunk-RMS3NEA3.js → chunk-HT2AHGQI.js} +2 -2
  101. package/dist/{chunk-CHJBLCOG.js → chunk-HVSCEIYL.js} +7 -7
  102. package/dist/{chunk-UXWB3FPF.js → chunk-I3JDRCMW.js} +150 -22
  103. package/dist/chunk-I3JDRCMW.js.map +1 -0
  104. package/dist/{chunk-GY4WYNNG.js → chunk-ID6Z6E66.js} +2 -2
  105. package/dist/{chunk-EYBQEIUY.js → chunk-IEX7NK2K.js} +3 -3
  106. package/dist/{chunk-KUJDV5QH.js → chunk-ISZQJBML.js} +5 -5
  107. package/dist/{chunk-LWBCUYZW.js → chunk-IT22PWKV.js} +2 -2
  108. package/dist/{chunk-EQEYOJBM.js → chunk-IUWCVHQ7.js} +3 -3
  109. package/dist/chunk-IUWCVHQ7.js.map +1 -0
  110. package/dist/{chunk-7V4TP3AF.js → chunk-J6UOHJY5.js} +4 -4
  111. package/dist/{chunk-JMGDHKQF.js → chunk-JCN44NCY.js} +2 -2
  112. package/dist/{chunk-CARABLSQ.js → chunk-K6W7BVZ6.js} +3 -3
  113. package/dist/{chunk-77K4PG6P.js → chunk-KJFW62P4.js} +29 -11
  114. package/dist/chunk-KJFW62P4.js.map +1 -0
  115. package/dist/{chunk-453F654R.js → chunk-L7DOS3TE.js} +2 -2
  116. package/dist/chunk-LGNDFRYC.js +23 -0
  117. package/dist/chunk-LGNDFRYC.js.map +1 -0
  118. package/dist/{chunk-WEQEYLCS.js → chunk-LGRLME4M.js} +7 -7
  119. package/dist/{chunk-RMF67KCG.js → chunk-LQ4ZHOKP.js} +2 -2
  120. package/dist/{chunk-ZVO4QVPD.js → chunk-M522UYZ2.js} +5 -5
  121. package/dist/{chunk-G56KBWFY.js → chunk-M7NI3IWE.js} +45 -12
  122. package/dist/chunk-M7NI3IWE.js.map +1 -0
  123. package/dist/chunk-MDWKM2XC.js +293 -0
  124. package/dist/chunk-MDWKM2XC.js.map +1 -0
  125. package/dist/chunk-MKXXMNJH.js +204 -0
  126. package/dist/chunk-MKXXMNJH.js.map +1 -0
  127. package/dist/{chunk-SKGMN35F.js → chunk-MLPHLJIQ.js} +3 -3
  128. package/dist/chunk-MLPHLJIQ.js.map +1 -0
  129. package/dist/{chunk-2N4GY74U.js → chunk-MTL7MXGR.js} +6 -6
  130. package/dist/{chunk-TFR7DSOV.js → chunk-MVZ2TPVP.js} +2 -2
  131. package/dist/{chunk-CPWQB3N5.js → chunk-N5DNADLQ.js} +7 -7
  132. package/dist/{chunk-ELNXJMGB.js → chunk-NNARWO72.js} +6 -6
  133. package/dist/{chunk-PT43Y56J.js → chunk-NRT6QZQB.js} +102 -16
  134. package/dist/chunk-NRT6QZQB.js.map +1 -0
  135. package/dist/{chunk-QIBVIOXO.js → chunk-NWHBJQAL.js} +99 -8
  136. package/dist/chunk-NWHBJQAL.js.map +1 -0
  137. package/dist/chunk-NYMLINRP.js +28 -0
  138. package/dist/chunk-NYMLINRP.js.map +1 -0
  139. package/dist/{chunk-7MG7SJT7.js → chunk-ODVPTDPK.js} +1 -1
  140. package/dist/chunk-ODVPTDPK.js.map +1 -0
  141. package/dist/chunk-ORDURZBU.js +461 -0
  142. package/dist/chunk-ORDURZBU.js.map +1 -0
  143. package/dist/{chunk-6YXCPL4T.js → chunk-PDCG6PR5.js} +2 -2
  144. package/dist/{chunk-REDOOY2Q.js → chunk-PSIV7CJV.js} +2 -2
  145. package/dist/{chunk-NA2NIJZI.js → chunk-QBBUZ3I3.js} +126 -19
  146. package/dist/chunk-QBBUZ3I3.js.map +1 -0
  147. package/dist/{chunk-5VCRVKOZ.js → chunk-QOOUUR4A.js} +6 -4
  148. package/dist/{chunk-5VCRVKOZ.js.map → chunk-QOOUUR4A.js.map} +1 -1
  149. package/dist/{chunk-ANATMFIO.js → chunk-QWFHIOD2.js} +5 -5
  150. package/dist/{chunk-X2DLENDQ.js → chunk-QWGU66MP.js} +3 -3
  151. package/dist/chunk-RHVMZSUU.js +7 -0
  152. package/dist/chunk-RHVMZSUU.js.map +1 -0
  153. package/dist/{chunk-BSFNRLK2.js → chunk-S57HTZ6X.js} +5 -5
  154. package/dist/{chunk-SZJ3DLZA.js → chunk-SEE332EV.js} +2 -2
  155. package/dist/{chunk-YYP7WSEB.js → chunk-SI3V7D4G.js} +2 -2
  156. package/dist/{chunk-UGTBXF5U.js → chunk-SOIQ4MM4.js} +3 -3
  157. package/dist/chunk-SUZKW6UR.js +25 -0
  158. package/dist/chunk-SUZKW6UR.js.map +1 -0
  159. package/dist/{chunk-VXGSWL6L.js → chunk-SYVZW77S.js} +6 -6
  160. package/dist/{chunk-6GOE5PGN.js → chunk-T2LBQ5DV.js} +883 -227
  161. package/dist/chunk-T2LBQ5DV.js.map +1 -0
  162. package/dist/chunk-T52GX4SA.js +215 -0
  163. package/dist/chunk-T52GX4SA.js.map +1 -0
  164. package/dist/{chunk-MVMXZYXT.js → chunk-TKUOEU2F.js} +2 -2
  165. package/dist/chunk-TOPYQ6GA.js +31 -0
  166. package/dist/chunk-TOPYQ6GA.js.map +1 -0
  167. package/dist/{chunk-SMH6SRX7.js → chunk-TROR3ALR.js} +2 -2
  168. package/dist/{chunk-2C3AQB46.js → chunk-UD5EVGZ7.js} +42 -389
  169. package/dist/chunk-UD5EVGZ7.js.map +1 -0
  170. package/dist/{chunk-KJIMGIWO.js → chunk-UPD5NWI5.js} +65 -17
  171. package/dist/chunk-UPD5NWI5.js.map +1 -0
  172. package/dist/{chunk-SL3JAAKN.js → chunk-UYB234ZR.js} +30 -2
  173. package/dist/chunk-UYB234ZR.js.map +1 -0
  174. package/dist/chunk-VHM7HCKB.js +220 -0
  175. package/dist/chunk-VHM7HCKB.js.map +1 -0
  176. package/dist/{chunk-DGOZ4UZD.js → chunk-VNNRUGMM.js} +2 -2
  177. package/dist/{chunk-HDOU6I2Y.js → chunk-VNPEWFPD.js} +4 -4
  178. package/dist/{chunk-L7CIOOBW.js → chunk-WNJ4AVGE.js} +2 -2
  179. package/dist/{chunk-FMZY5Q6L.js → chunk-WX5ADGTZ.js} +3 -3
  180. package/dist/{chunk-VXANTWBJ.js → chunk-WY2XXTET.js} +92 -6
  181. package/dist/{chunk-VXANTWBJ.js.map → chunk-WY2XXTET.js.map} +1 -1
  182. package/dist/{chunk-6X6SEMEE.js → chunk-X25NWUZB.js} +33 -8
  183. package/dist/chunk-X25NWUZB.js.map +1 -0
  184. package/dist/{chunk-Q7HZX3IF.js → chunk-X4773RBR.js} +2 -2
  185. package/dist/chunk-XBKH4FOC.js +195 -0
  186. package/dist/chunk-XBKH4FOC.js.map +1 -0
  187. package/dist/{chunk-ANSIZYEG.js → chunk-YNIUIERI.js} +3 -3
  188. package/dist/chunk-YSK2CU2Q.js +936 -0
  189. package/dist/chunk-YSK2CU2Q.js.map +1 -0
  190. package/dist/{chunk-UXVWEX5L.js → chunk-Z5HTYMMQ.js} +6 -2
  191. package/dist/chunk-Z5HTYMMQ.js.map +1 -0
  192. package/dist/{chunk-RRNRNANG.js → chunk-ZE4CHIED.js} +66 -75
  193. package/dist/chunk-ZE4CHIED.js.map +1 -0
  194. package/dist/chunk-ZSX4S5XB.js +1289 -0
  195. package/dist/chunk-ZSX4S5XB.js.map +1 -0
  196. package/dist/{chunk-BZ3534YM.js → chunk-ZUVBC32X.js} +2 -2
  197. package/dist/{chunk-L742JPKZ.js → chunk-ZXABPVM6.js} +6 -6
  198. package/dist/classified/index.js +5 -5
  199. package/dist/{classified-marker-LI2SF2E4.js → classified-marker-W3USLL5M.js} +3 -3
  200. package/dist/collection-facade-QU6IJBN3.js +48 -0
  201. package/dist/{computed-VPOKQK4N.js → computed-TPFBX7U4.js} +3 -3
  202. package/dist/consent/index.js +9 -9
  203. package/dist/cover/index.js +10 -10
  204. package/dist/coverage/index.js +306 -0
  205. package/dist/coverage/index.js.map +1 -0
  206. package/dist/custody/index.js +12 -12
  207. package/dist/{dead-filter-TSWZQRR5.js → dead-filter-U2UYKSZL.js} +2 -2
  208. package/dist/debug/index.js +1 -1
  209. package/dist/{delegation-OVIFFPG4.js → delegation-S3AEPW2T.js} +11 -11
  210. package/dist/derivations/index.js +25 -22
  211. package/dist/derive-OX7F6TGG.js +21 -0
  212. package/dist/directory/index.js +10 -10
  213. package/dist/{dispatch-WC6X2M6C.js → dispatch-3CQDJV5Q.js} +5 -5
  214. package/dist/{dispatch-S73TK3IY.js → dispatch-RH4LHKBH.js} +21 -21
  215. package/dist/{enclave-KJOTOH7X.js → enclave-27SMF6GF.js} +15 -9
  216. package/dist/executor-B6SRO2QS.js +36 -0
  217. package/dist/executor-BI5CHWRY.js +8 -0
  218. package/dist/executor-RBKM5W5K.js +8 -0
  219. package/dist/export-accessible-VMA3YM5V.js +22 -0
  220. package/dist/extract-partition-NF7PXGPP.js +37 -0
  221. package/dist/{fanout-sidecar-WUFXNYP4.js → fanout-sidecar-OT6RYLOL.js} +9 -9
  222. package/dist/find-LZMP26KF.js +10 -0
  223. package/dist/forget/index.js +9 -9
  224. package/dist/guards/index.js +4 -4
  225. package/dist/history/index.js +13 -13
  226. package/dist/i18n/index.js +14 -14
  227. package/dist/index.d.ts +29 -6
  228. package/dist/index.js +999 -191
  229. package/dist/index.js.map +1 -1
  230. package/dist/indexing/index.js +13 -5
  231. package/dist/indexing/index.js.map +1 -1
  232. package/dist/introspection/index.js +11 -11
  233. package/dist/issue-IHARXWW5.js +18 -0
  234. package/dist/ivf-flat-UZ6DQDLS.js +314 -0
  235. package/dist/ivf-flat-UZ6DQDLS.js.map +1 -0
  236. package/dist/{json-schema-V3M5MUCM.js → json-schema-3SHX72CC.js} +2 -1
  237. package/dist/json-schema-3SHX72CC.js.map +1 -0
  238. package/dist/kernel/collection-config.d.ts +4 -20
  239. package/dist/kernel/collection.d.ts +29 -8
  240. package/dist/kernel/enclave/crypto.d.ts +16 -0
  241. package/dist/kernel/enclave/index.d.ts +1 -1
  242. package/dist/kernel/enclave/record-keys/record-codec.d.ts +25 -0
  243. package/dist/kernel/errors.d.ts +227 -36
  244. package/dist/kernel/generation-map.d.ts +48 -0
  245. package/dist/kernel/memory-store.d.ts +35 -7
  246. package/dist/kernel/noydb.d.ts +6 -1
  247. package/dist/kernel/present-cache.d.ts +58 -0
  248. package/dist/kernel/query/all.d.ts +7 -0
  249. package/dist/kernel/query/builder.d.ts +601 -270
  250. package/dist/kernel/query/civil-date.d.ts +64 -0
  251. package/dist/kernel/query/cursor.d.ts +40 -0
  252. package/dist/kernel/query/distinct-key.d.ts +98 -0
  253. package/dist/kernel/query/hydration.d.ts +76 -0
  254. package/dist/kernel/query/index.d.ts +31 -15
  255. package/dist/kernel/query/internal/core.d.ts +30 -0
  256. package/dist/kernel/query/internal/hooks.d.ts +22 -0
  257. package/dist/kernel/query/internal/maintenance.d.ts +43 -0
  258. package/dist/kernel/query/live/incremental.d.ts +314 -0
  259. package/dist/kernel/query/live/index.d.ts +22 -0
  260. package/dist/kernel/query/live/install.d.ts +2 -0
  261. package/dist/kernel/query/{live.d.ts → live/live.d.ts} +39 -9
  262. package/dist/kernel/query/live/methods.d.ts +107 -0
  263. package/dist/kernel/query/predicate.d.ts +119 -1
  264. package/dist/kernel/query/reduce/date-trunc.d.ts +75 -0
  265. package/dist/kernel/query/reduce/index.d.ts +36 -0
  266. package/dist/kernel/query/reduce/install.d.ts +2 -0
  267. package/dist/kernel/query/reduce/methods.d.ts +259 -0
  268. package/dist/kernel/query/reduce/scan-methods.d.ts +121 -0
  269. package/dist/kernel/query/relate/explain.d.ts +199 -0
  270. package/dist/kernel/query/relate/index.d.ts +48 -0
  271. package/dist/kernel/query/relate/install.d.ts +2 -0
  272. package/dist/kernel/query/relate/join-on.d.ts +126 -0
  273. package/dist/kernel/query/relate/join-reduce.d.ts +16 -0
  274. package/dist/kernel/query/relate/join.d.ts +452 -0
  275. package/dist/kernel/query/relate/methods.d.ts +426 -0
  276. package/dist/kernel/query/relate/partition.d.ts +87 -0
  277. package/dist/kernel/query/relate/scan-methods.d.ts +163 -0
  278. package/dist/kernel/query/relate/traverse.d.ts +109 -0
  279. package/dist/kernel/query/scan-builder.d.ts +79 -176
  280. package/dist/kernel/query/sort-key.d.ts +52 -0
  281. package/dist/kernel/tx-write-gate.d.ts +77 -0
  282. package/dist/kernel/types.d.ts +71 -3
  283. package/dist/kernel/validation.d.ts +27 -10
  284. package/dist/kernel/vault.d.ts +9 -4
  285. package/dist/kernel/via/compose.d.ts +3 -0
  286. package/dist/kernel/via/index.d.ts +56 -0
  287. package/dist/kernel/via/pipeline.d.ts +48 -0
  288. package/dist/{ledger-F33ZVMTK.js → ledger-KZPCMVZY.js} +11 -11
  289. package/dist/liberate-GRLCZMW4.js +24 -0
  290. package/dist/link-set-JCMJ7ULP.js +30 -0
  291. package/dist/{managed-secret-PQYKSR6T.js → managed-secret-S3MQ6SH6.js} +10 -10
  292. package/dist/materialized-views/index.js +30 -23
  293. package/dist/{migrate-cek-5ENH64AA.js → migrate-cek-V7GKJZ7O.js} +2 -2
  294. package/dist/money/index.js +5 -5
  295. package/dist/noydb-SWQJ3MZS.js +97 -0
  296. package/dist/overlay-views/index.js +4 -4
  297. package/dist/periods/index.js +12 -12
  298. package/dist/pod/index.js +75 -68
  299. package/dist/{pod-handle-Q736KYON.js → pod-handle-WGDFB4C2.js} +9 -9
  300. package/dist/policy/index.js +10 -10
  301. package/dist/port/with/blob-strategy.d.ts +9 -0
  302. package/dist/port/with/collection-options.d.ts +5 -0
  303. package/dist/port/with/coverage-strategy.d.ts +83 -0
  304. package/dist/port/with/service-bus.d.ts +46 -0
  305. package/dist/port/with/strategies.d.ts +2 -0
  306. package/dist/portability/index.js +8 -8
  307. package/dist/{post-register-LNE2FE2A.js → post-register-SLSXIPBV.js} +6 -6
  308. package/dist/query/all/index.js +31 -0
  309. package/dist/query/index.js +20 -32
  310. package/dist/query/live/index.js +21 -0
  311. package/dist/query/live/index.js.map +1 -0
  312. package/dist/query/reduce/index.js +33 -0
  313. package/dist/query/reduce/index.js.map +1 -0
  314. package/dist/query/relate/index.js +56 -0
  315. package/dist/query/relate/index.js.map +1 -0
  316. package/dist/reduce/index.js +72 -18
  317. package/dist/reduce/index.js.map +1 -1
  318. package/dist/register-F3OYE7MJ.js +31 -0
  319. package/dist/registry-CILQFXFK.js +8 -0
  320. package/dist/registry-XNNYQVKV.js +8 -0
  321. package/dist/registry-YCDZV3VW.js +35 -0
  322. package/dist/registry-ZGYS33TE.js +24 -0
  323. package/dist/request-withdrawal-Z5NC6TXT.js +30 -0
  324. package/dist/{reveal-67RDQRIN.js → reveal-4BCKPEC2.js} +6 -6
  325. package/dist/revoke-ZL62WC2D.js +23 -0
  326. package/dist/satellites/index.js +1 -1
  327. package/dist/schema-update/index.js +2 -2
  328. package/dist/sealed-record/index.js +12 -12
  329. package/dist/search/index.js +11 -5
  330. package/dist/{seed-G42JYN56.js → seed-4JS2RJ4A.js} +12 -12
  331. package/dist/sequence/index.js +9 -9
  332. package/dist/session/index.js +9 -9
  333. package/dist/shadow/index.js +2 -2
  334. package/dist/signer-MBZZMXTC.js +24 -0
  335. package/dist/snapshots/index.js +10 -10
  336. package/dist/{stale-DDL7WQEZ.js → stale-TJ3DYZMQ.js} +10 -10
  337. package/dist/storage-SVMKRGCW.js +22 -0
  338. package/dist/{store-coordination-provider-MEQ2MJQG.js → store-coordination-provider-2O2VUHKW.js} +10 -10
  339. package/dist/sync/index.js +10 -10
  340. package/dist/team/index.js +17 -15
  341. package/dist/tiers/index.js +13 -11
  342. package/dist/to/index.js +2 -2
  343. package/dist/transactions/index.js +3 -3
  344. package/dist/util/index.js +1 -1
  345. package/dist/vault-head/index.js +8 -8
  346. package/dist/{verify-KOV2G5D6.js → verify-RVT67IMH.js} +5 -5
  347. package/dist/via/blob/index.d.ts +1 -0
  348. package/dist/via/geo/binding.d.ts +31 -0
  349. package/dist/via/geo/descriptor.d.ts +54 -0
  350. package/dist/via/geo/geohash.d.ts +95 -0
  351. package/dist/via/geo/index.d.ts +13 -0
  352. package/dist/via/geo/where.d.ts +50 -0
  353. package/dist/via/i18n/core.d.ts +1 -1
  354. package/dist/via/lookup/registry.d.ts +1 -1
  355. package/dist/via/lookup/snapshot.d.ts +3 -3
  356. package/dist/walk-HJ42EISE.js +21 -0
  357. package/dist/walk-HJ42EISE.js.map +1 -0
  358. package/dist/with-audit/coverage/accounting.d.ts +112 -0
  359. package/dist/with-audit/coverage/active.d.ts +29 -0
  360. package/dist/with-audit/coverage/index.d.ts +61 -0
  361. package/dist/with-audit/coverage/sketch.d.ts +75 -0
  362. package/dist/with-audit/periods/periods.d.ts +55 -7
  363. package/dist/with-audit/periods/reserved-collections.d.ts +3 -0
  364. package/dist/with-audit/periods/vault-facade.d.ts +17 -0
  365. package/dist/with-audit/tiers/index.d.ts +51 -0
  366. package/dist/with-audit/tiers/strategy.d.ts +8 -0
  367. package/dist/with-cargo/floor.d.ts +2 -2
  368. package/dist/with-commit/tx/invariants.d.ts +1 -1
  369. package/dist/with-commit/tx/transaction.d.ts +13 -3
  370. package/dist/with-formula/materialized-views/dependency-analyzer.d.ts +4 -3
  371. package/dist/with-formula/materialized-views/emit-memo.d.ts +40 -0
  372. package/dist/with-formula/materialized-views/executor.d.ts +8 -0
  373. package/dist/with-formula/materialized-views/index.d.ts +1 -1
  374. package/dist/with-formula/materialized-views/registry.d.ts +15 -0
  375. package/dist/with-formula/materialized-views/types.d.ts +106 -14
  376. package/dist/with-formula/materialized-views/window-stage.d.ts +11 -0
  377. package/dist/with-formula/overlay-views/types.d.ts +1 -1
  378. package/dist/with-formula/overlay-views/virtual-collection.d.ts +13 -4
  379. package/dist/with-lookup/embeddings/chunks.d.ts +79 -0
  380. package/dist/with-lookup/embeddings/descriptor.d.ts +21 -0
  381. package/dist/with-lookup/embeddings/index.d.ts +3 -0
  382. package/dist/with-lookup/embeddings/ivf-flat.d.ts +93 -0
  383. package/dist/with-lookup/embeddings/vector-index.d.ts +73 -0
  384. package/dist/with-lookup/embeddings/vector-set.d.ts +94 -1
  385. package/dist/with-lookup/embeddings/with-vector-index.d.ts +67 -0
  386. package/dist/with-lookup/indexing/collection-facade.d.ts +85 -2
  387. package/dist/with-lookup/indexing/compound-indexes.d.ts +129 -0
  388. package/dist/with-lookup/indexing/eager-indexes.d.ts +170 -1
  389. package/dist/with-lookup/indexing/index-snapshot.d.ts +62 -0
  390. package/dist/with-lookup/indexing/lazy-builder.d.ts +33 -0
  391. package/dist/with-lookup/indexing/persisted-field-indexes.d.ts +104 -0
  392. package/dist/with-lookup/indexing/persisted-indexes.d.ts +12 -0
  393. package/dist/with-lookup/indexing/sorted-indexes.d.ts +117 -0
  394. package/dist/with-lookup/indexing/unique-constraints.d.ts +106 -23
  395. package/dist/with-lookup/reduce/active.d.ts +2 -24
  396. package/dist/with-lookup/reduce/group-core.d.ts +43 -0
  397. package/dist/with-lookup/reduce/groupby.d.ts +195 -36
  398. package/dist/with-lookup/reduce/incremental-group.d.ts +153 -0
  399. package/dist/with-lookup/reduce/index.d.ts +26 -5
  400. package/dist/with-lookup/reduce/reducers.d.ts +255 -1
  401. package/dist/with-lookup/reduce/reduction.d.ts +44 -13
  402. package/dist/with-lookup/reduce/strategy.d.ts +43 -3
  403. package/dist/with-lookup/reduce/window.d.ts +262 -0
  404. package/dist/with-lookup/search/collection-facade.d.ts +44 -8
  405. package/dist/with-lookup/search/index-store.d.ts +5 -3
  406. package/dist/with-lookup/search/index.d.ts +4 -2
  407. package/dist/with-lookup/search/inverted-index.d.ts +38 -2
  408. package/dist/with-lookup/search/persisted-index-store.d.ts +5 -2
  409. package/dist/with-lookup/search/phrase.d.ts +28 -0
  410. package/dist/with-lookup/search/retrieve-types.d.ts +57 -1
  411. package/dist/with-lookup/search/serialize.d.ts +29 -3
  412. package/dist/with-lookup/search/strategy.d.ts +2 -6
  413. package/dist/with-party/directory/cover/index.d.ts +1 -1
  414. package/dist/with-party/directory/cover/storage.d.ts +1 -1
  415. package/dist/with-party/directory/cover/types.d.ts +1 -1
  416. package/dist/with-party/directory/index.d.ts +1 -1
  417. package/dist/with-party/directory/types.d.ts +1 -1
  418. package/dist/with-party/directory/user-envelope/api.d.ts +1 -1
  419. package/dist/with-party/policy/engine.d.ts +1 -1
  420. package/dist/with-party/policy/index.d.ts +1 -1
  421. package/dist/with-party/policy/presets.d.ts +1 -1
  422. package/dist/with-party/team/authenticators.d.ts +91 -1
  423. package/dist/with-party/team/index.d.ts +3 -2
  424. package/dist/with-party/team/keyring.d.ts +13 -6
  425. package/dist/with-party/team/managed-secret.d.ts +1 -1
  426. package/dist/with-party/team/noydb-facade.d.ts +12 -3
  427. package/dist/with-party/team/wrapped-deks.d.ts +4 -4
  428. package/dist/with-pod/format.d.ts +1 -1
  429. package/dist/with-pod/pod.d.ts +5 -5
  430. package/dist/with-shape/blobs/blob-compaction.d.ts +16 -0
  431. package/dist/with-shape/blobs/blob-set.d.ts +21 -2
  432. package/dist/with-shape/blobs/legacy-sweep.d.ts +35 -0
  433. package/dist/with-shape/introspection/describe.d.ts +6 -0
  434. package/dist/with-shape/introspection/field-meta.d.ts +18 -0
  435. package/dist/with-shape/introspection/types.d.ts +57 -1
  436. package/dist/with-shape/links/vault-facade.d.ts +1 -1
  437. package/dist/with-store/partitioned/index.d.ts +337 -0
  438. package/dist/with-sync/change-broadcast.d.ts +153 -0
  439. package/dist/withdraw-accessible-5NZUPAVA.js +27 -0
  440. package/dist/withdraw-accessible-5NZUPAVA.js.map +1 -0
  441. package/package.json +37 -10
  442. package/dist/api-TXFOVOXX.js +0 -19
  443. package/dist/backup-IJTB4S4M.js.map +0 -1
  444. package/dist/chunk-2577DKXB.js.map +0 -1
  445. package/dist/chunk-2C3AQB46.js.map +0 -1
  446. package/dist/chunk-4GVM6QZA.js.map +0 -1
  447. package/dist/chunk-5WDXHNSW.js.map +0 -1
  448. package/dist/chunk-6GOE5PGN.js.map +0 -1
  449. package/dist/chunk-6X6SEMEE.js.map +0 -1
  450. package/dist/chunk-77K4PG6P.js.map +0 -1
  451. package/dist/chunk-7MG2LHO5.js +0 -1616
  452. package/dist/chunk-7MG2LHO5.js.map +0 -1
  453. package/dist/chunk-7MG7SJT7.js.map +0 -1
  454. package/dist/chunk-7O3Y4PPD.js.map +0 -1
  455. package/dist/chunk-AO42KJO6.js.map +0 -1
  456. package/dist/chunk-ATL3ZVXT.js +0 -151
  457. package/dist/chunk-ATL3ZVXT.js.map +0 -1
  458. package/dist/chunk-BLN54W3L.js.map +0 -1
  459. package/dist/chunk-BM5TWITZ.js.map +0 -1
  460. package/dist/chunk-CUZLNGD5.js.map +0 -1
  461. package/dist/chunk-EQEYOJBM.js.map +0 -1
  462. package/dist/chunk-G56KBWFY.js.map +0 -1
  463. package/dist/chunk-I3ISCYT7.js +0 -159
  464. package/dist/chunk-I3ISCYT7.js.map +0 -1
  465. package/dist/chunk-KG7TZKZG.js.map +0 -1
  466. package/dist/chunk-KJIMGIWO.js.map +0 -1
  467. package/dist/chunk-KTFRCC5C.js.map +0 -1
  468. package/dist/chunk-KUX3OB6D.js.map +0 -1
  469. package/dist/chunk-MUM7IANK.js.map +0 -1
  470. package/dist/chunk-NA2NIJZI.js.map +0 -1
  471. package/dist/chunk-NSITFOCJ.js +0 -99
  472. package/dist/chunk-NSITFOCJ.js.map +0 -1
  473. package/dist/chunk-PT43Y56J.js.map +0 -1
  474. package/dist/chunk-QIBVIOXO.js.map +0 -1
  475. package/dist/chunk-RRNRNANG.js.map +0 -1
  476. package/dist/chunk-RTBJ5IOO.js +0 -87
  477. package/dist/chunk-RTBJ5IOO.js.map +0 -1
  478. package/dist/chunk-SKGMN35F.js.map +0 -1
  479. package/dist/chunk-SL3JAAKN.js.map +0 -1
  480. package/dist/chunk-SPXXX5E4.js.map +0 -1
  481. package/dist/chunk-SPYWXKJN.js.map +0 -1
  482. package/dist/chunk-U4FOQDY4.js.map +0 -1
  483. package/dist/chunk-UXVWEX5L.js.map +0 -1
  484. package/dist/chunk-UXWB3FPF.js.map +0 -1
  485. package/dist/chunk-YMUFFJCO.js.map +0 -1
  486. package/dist/chunk-ZN4FD4PE.js +0 -364
  487. package/dist/chunk-ZN4FD4PE.js.map +0 -1
  488. package/dist/chunk-ZORTV6NH.js.map +0 -1
  489. package/dist/collection-facade-4GRREZ6C.js +0 -45
  490. package/dist/derive-6O5SWQKN.js +0 -21
  491. package/dist/executor-5NIMLSKZ.js +0 -8
  492. package/dist/executor-AQVXV5GZ.js +0 -8
  493. package/dist/executor-PUAO6AKJ.js +0 -29
  494. package/dist/export-accessible-72EQNBMR.js +0 -22
  495. package/dist/extract-partition-PUYNU3UF.js +0 -37
  496. package/dist/find-2ABFCZX4.js +0 -10
  497. package/dist/issue-SIDORTSZ.js +0 -18
  498. package/dist/json-schema-V3M5MUCM.js.map +0 -1
  499. package/dist/kernel/query/join.d.ts +0 -232
  500. package/dist/liberate-LCDPNAG2.js +0 -24
  501. package/dist/link-set-FKNWAYKS.js +0 -30
  502. package/dist/noydb-DUXZPKSN.js +0 -90
  503. package/dist/register-I2DZXGAR.js +0 -31
  504. package/dist/registry-23WF3TGH.js +0 -8
  505. package/dist/registry-4AYVUNXK.js +0 -8
  506. package/dist/registry-VSSQPIGF.js +0 -18
  507. package/dist/registry-YLEWMGAC.js +0 -32
  508. package/dist/request-withdrawal-KFQHEZ25.js +0 -30
  509. package/dist/revoke-DQDZAZZM.js +0 -23
  510. package/dist/signer-WAMDZHEN.js +0 -24
  511. package/dist/storage-FLR73HHF.js +0 -22
  512. package/dist/walk-3UQBRMDV.js +0 -21
  513. package/dist/withdraw-accessible-EL5GXZBS.js +0 -27
  514. /package/dist/{api-TXFOVOXX.js.map → api-GVYEKSJE.js.map} +0 -0
  515. /package/dist/{chunk-BUE2D7PX.js.map → chunk-32YV3TJT.js.map} +0 -0
  516. /package/dist/{chunk-3RCJJBNR.js.map → chunk-3ELRMVJK.js.map} +0 -0
  517. /package/dist/{chunk-6GMZ7HEE.js.map → chunk-3F7GLNAE.js.map} +0 -0
  518. /package/dist/{chunk-2Y4IMKA6.js.map → chunk-3H5KLDZN.js.map} +0 -0
  519. /package/dist/{chunk-VTFVLCUH.js.map → chunk-3JWHAR6E.js.map} +0 -0
  520. /package/dist/{chunk-JBDFMYKQ.js.map → chunk-4AF3TUMP.js.map} +0 -0
  521. /package/dist/{chunk-J6FXAEUG.js.map → chunk-6B3VNR4P.js.map} +0 -0
  522. /package/dist/{chunk-TUFM4UZP.js.map → chunk-6K7DPM7D.js.map} +0 -0
  523. /package/dist/{chunk-K6LHRFBL.js.map → chunk-6LMQ5R26.js.map} +0 -0
  524. /package/dist/{chunk-XLMEZIAJ.js.map → chunk-6OWXYZK2.js.map} +0 -0
  525. /package/dist/{chunk-BOWNCWZT.js.map → chunk-6QSQQLSE.js.map} +0 -0
  526. /package/dist/{chunk-NQKIUNW5.js.map → chunk-A6IJU4TK.js.map} +0 -0
  527. /package/dist/{chunk-QIZPZMUI.js.map → chunk-AOWGXU6D.js.map} +0 -0
  528. /package/dist/{chunk-SFAWCTEM.js.map → chunk-B57AFBY2.js.map} +0 -0
  529. /package/dist/{chunk-GPEQUXHL.js.map → chunk-B6SJIBQK.js.map} +0 -0
  530. /package/dist/{chunk-Q2PU57HC.js.map → chunk-BK2HHQGN.js.map} +0 -0
  531. /package/dist/{collection-facade-4GRREZ6C.js.map → chunk-BKT776R5.js.map} +0 -0
  532. /package/dist/{chunk-FXBIP2WD.js.map → chunk-BUDAGWL5.js.map} +0 -0
  533. /package/dist/{chunk-BOET4NA4.js.map → chunk-CKNGS5MH.js.map} +0 -0
  534. /package/dist/{chunk-YSRUYAVU.js.map → chunk-DE4DH2RZ.js.map} +0 -0
  535. /package/dist/{chunk-6I2RQCET.js.map → chunk-DF73H4UN.js.map} +0 -0
  536. /package/dist/{chunk-K7NTTA6P.js.map → chunk-EOVMT6TB.js.map} +0 -0
  537. /package/dist/{chunk-XTXOCYOJ.js.map → chunk-FCKWQE2H.js.map} +0 -0
  538. /package/dist/{chunk-4OZNXTO4.js.map → chunk-FN5EBVTQ.js.map} +0 -0
  539. /package/dist/{chunk-NKHRDYOR.js.map → chunk-FQ5VRHIB.js.map} +0 -0
  540. /package/dist/{chunk-FAHMLERK.js.map → chunk-FW22ZCXT.js.map} +0 -0
  541. /package/dist/{chunk-RMS3NEA3.js.map → chunk-HT2AHGQI.js.map} +0 -0
  542. /package/dist/{chunk-CHJBLCOG.js.map → chunk-HVSCEIYL.js.map} +0 -0
  543. /package/dist/{chunk-GY4WYNNG.js.map → chunk-ID6Z6E66.js.map} +0 -0
  544. /package/dist/{chunk-EYBQEIUY.js.map → chunk-IEX7NK2K.js.map} +0 -0
  545. /package/dist/{chunk-KUJDV5QH.js.map → chunk-ISZQJBML.js.map} +0 -0
  546. /package/dist/{chunk-LWBCUYZW.js.map → chunk-IT22PWKV.js.map} +0 -0
  547. /package/dist/{chunk-7V4TP3AF.js.map → chunk-J6UOHJY5.js.map} +0 -0
  548. /package/dist/{chunk-JMGDHKQF.js.map → chunk-JCN44NCY.js.map} +0 -0
  549. /package/dist/{chunk-CARABLSQ.js.map → chunk-K6W7BVZ6.js.map} +0 -0
  550. /package/dist/{chunk-453F654R.js.map → chunk-L7DOS3TE.js.map} +0 -0
  551. /package/dist/{chunk-WEQEYLCS.js.map → chunk-LGRLME4M.js.map} +0 -0
  552. /package/dist/{chunk-RMF67KCG.js.map → chunk-LQ4ZHOKP.js.map} +0 -0
  553. /package/dist/{chunk-ZVO4QVPD.js.map → chunk-M522UYZ2.js.map} +0 -0
  554. /package/dist/{chunk-2N4GY74U.js.map → chunk-MTL7MXGR.js.map} +0 -0
  555. /package/dist/{chunk-TFR7DSOV.js.map → chunk-MVZ2TPVP.js.map} +0 -0
  556. /package/dist/{chunk-CPWQB3N5.js.map → chunk-N5DNADLQ.js.map} +0 -0
  557. /package/dist/{chunk-ELNXJMGB.js.map → chunk-NNARWO72.js.map} +0 -0
  558. /package/dist/{chunk-6YXCPL4T.js.map → chunk-PDCG6PR5.js.map} +0 -0
  559. /package/dist/{chunk-REDOOY2Q.js.map → chunk-PSIV7CJV.js.map} +0 -0
  560. /package/dist/{chunk-ANATMFIO.js.map → chunk-QWFHIOD2.js.map} +0 -0
  561. /package/dist/{chunk-X2DLENDQ.js.map → chunk-QWGU66MP.js.map} +0 -0
  562. /package/dist/{chunk-BSFNRLK2.js.map → chunk-S57HTZ6X.js.map} +0 -0
  563. /package/dist/{chunk-SZJ3DLZA.js.map → chunk-SEE332EV.js.map} +0 -0
  564. /package/dist/{chunk-YYP7WSEB.js.map → chunk-SI3V7D4G.js.map} +0 -0
  565. /package/dist/{chunk-UGTBXF5U.js.map → chunk-SOIQ4MM4.js.map} +0 -0
  566. /package/dist/{chunk-VXGSWL6L.js.map → chunk-SYVZW77S.js.map} +0 -0
  567. /package/dist/{chunk-MVMXZYXT.js.map → chunk-TKUOEU2F.js.map} +0 -0
  568. /package/dist/{chunk-SMH6SRX7.js.map → chunk-TROR3ALR.js.map} +0 -0
  569. /package/dist/{chunk-DGOZ4UZD.js.map → chunk-VNNRUGMM.js.map} +0 -0
  570. /package/dist/{chunk-HDOU6I2Y.js.map → chunk-VNPEWFPD.js.map} +0 -0
  571. /package/dist/{chunk-L7CIOOBW.js.map → chunk-WNJ4AVGE.js.map} +0 -0
  572. /package/dist/{chunk-FMZY5Q6L.js.map → chunk-WX5ADGTZ.js.map} +0 -0
  573. /package/dist/{chunk-Q7HZX3IF.js.map → chunk-X4773RBR.js.map} +0 -0
  574. /package/dist/{chunk-ANSIZYEG.js.map → chunk-YNIUIERI.js.map} +0 -0
  575. /package/dist/{chunk-BZ3534YM.js.map → chunk-ZUVBC32X.js.map} +0 -0
  576. /package/dist/{chunk-L742JPKZ.js.map → chunk-ZXABPVM6.js.map} +0 -0
  577. /package/dist/{classified-marker-LI2SF2E4.js.map → classified-marker-W3USLL5M.js.map} +0 -0
  578. /package/dist/{computed-VPOKQK4N.js.map → collection-facade-QU6IJBN3.js.map} +0 -0
  579. /package/dist/{derive-6O5SWQKN.js.map → computed-TPFBX7U4.js.map} +0 -0
  580. /package/dist/{dead-filter-TSWZQRR5.js.map → dead-filter-U2UYKSZL.js.map} +0 -0
  581. /package/dist/{delegation-OVIFFPG4.js.map → delegation-S3AEPW2T.js.map} +0 -0
  582. /package/dist/{enclave-KJOTOH7X.js.map → derive-OX7F6TGG.js.map} +0 -0
  583. /package/dist/{dispatch-WC6X2M6C.js.map → dispatch-3CQDJV5Q.js.map} +0 -0
  584. /package/dist/{dispatch-S73TK3IY.js.map → dispatch-RH4LHKBH.js.map} +0 -0
  585. /package/dist/{executor-5NIMLSKZ.js.map → enclave-27SMF6GF.js.map} +0 -0
  586. /package/dist/{executor-AQVXV5GZ.js.map → executor-B6SRO2QS.js.map} +0 -0
  587. /package/dist/{executor-PUAO6AKJ.js.map → executor-BI5CHWRY.js.map} +0 -0
  588. /package/dist/{export-accessible-72EQNBMR.js.map → executor-RBKM5W5K.js.map} +0 -0
  589. /package/dist/{extract-partition-PUYNU3UF.js.map → export-accessible-VMA3YM5V.js.map} +0 -0
  590. /package/dist/{find-2ABFCZX4.js.map → extract-partition-NF7PXGPP.js.map} +0 -0
  591. /package/dist/{fanout-sidecar-WUFXNYP4.js.map → fanout-sidecar-OT6RYLOL.js.map} +0 -0
  592. /package/dist/{issue-SIDORTSZ.js.map → find-LZMP26KF.js.map} +0 -0
  593. /package/dist/{ledger-F33ZVMTK.js.map → issue-IHARXWW5.js.map} +0 -0
  594. /package/dist/{liberate-LCDPNAG2.js.map → ledger-KZPCMVZY.js.map} +0 -0
  595. /package/dist/{link-set-FKNWAYKS.js.map → liberate-GRLCZMW4.js.map} +0 -0
  596. /package/dist/{managed-secret-PQYKSR6T.js.map → link-set-JCMJ7ULP.js.map} +0 -0
  597. /package/dist/{noydb-DUXZPKSN.js.map → managed-secret-S3MQ6SH6.js.map} +0 -0
  598. /package/dist/{migrate-cek-5ENH64AA.js.map → migrate-cek-V7GKJZ7O.js.map} +0 -0
  599. /package/dist/{register-I2DZXGAR.js.map → noydb-SWQJ3MZS.js.map} +0 -0
  600. /package/dist/{pod-handle-Q736KYON.js.map → pod-handle-WGDFB4C2.js.map} +0 -0
  601. /package/dist/{post-register-LNE2FE2A.js.map → post-register-SLSXIPBV.js.map} +0 -0
  602. /package/dist/{registry-23WF3TGH.js.map → query/all/index.js.map} +0 -0
  603. /package/dist/{registry-4AYVUNXK.js.map → register-F3OYE7MJ.js.map} +0 -0
  604. /package/dist/{registry-VSSQPIGF.js.map → registry-CILQFXFK.js.map} +0 -0
  605. /package/dist/{registry-YLEWMGAC.js.map → registry-XNNYQVKV.js.map} +0 -0
  606. /package/dist/{request-withdrawal-KFQHEZ25.js.map → registry-YCDZV3VW.js.map} +0 -0
  607. /package/dist/{revoke-DQDZAZZM.js.map → registry-ZGYS33TE.js.map} +0 -0
  608. /package/dist/{signer-WAMDZHEN.js.map → request-withdrawal-Z5NC6TXT.js.map} +0 -0
  609. /package/dist/{reveal-67RDQRIN.js.map → reveal-4BCKPEC2.js.map} +0 -0
  610. /package/dist/{stale-DDL7WQEZ.js.map → revoke-ZL62WC2D.js.map} +0 -0
  611. /package/dist/{seed-G42JYN56.js.map → seed-4JS2RJ4A.js.map} +0 -0
  612. /package/dist/{storage-FLR73HHF.js.map → signer-MBZZMXTC.js.map} +0 -0
  613. /package/dist/{walk-3UQBRMDV.js.map → stale-TJ3DYZMQ.js.map} +0 -0
  614. /package/dist/{withdraw-accessible-EL5GXZBS.js.map → storage-SVMKRGCW.js.map} +0 -0
  615. /package/dist/{store-coordination-provider-MEQ2MJQG.js.map → store-coordination-provider-2O2VUHKW.js.map} +0 -0
  616. /package/dist/{verify-KOV2G5D6.js.map → verify-RVT67IMH.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/with-lookup/search/collection-facade.ts"],"sourcesContent":["/**\n * Collection-level search / retrieval (`search` / `retrieve` / `similarTo` +\n * the lexical-index build/flush/warm machinery).\n *\n * This is the retrieval surface: a pure client-side lexical scan\n * (`search`), the persisted-or-in-memory inverted-index lifecycle\n * (`flushIndex` / `warmIndex` / `buildRetrievalDocs` + the dict-label / blob-\n * filename resolvers that feed it), and the lexical / semantic / hybrid\n * `retrieve` fan-out plus raw-vector kNN (`similarTo`). None of it touches the\n * write path — it reads the live eager cache and the encrypted `_vec` / `_ftindex`\n * side-cars.\n *\n * Every function takes a small {@link SearchContext} instead of `this`,\n * mirroring the `record-keys/` siblings.\n *\n * The `cache` is the SAME `Map` reference `Collection` owns (passed by\n * reference, never copied) so the index always builds over the live working\n * set. {@link buildPersistedIndexCallbacks} is special: it is invoked from the\n * `Collection` constructor *before* `this.codec` exists, so it takes a context\n * THUNK and resolves the context lazily at each callback invocation.\n *\n * Internal service — not exported as a `@noy-db/hub/*` subpath.\n */\nimport type { NoydbStore } from '../../kernel/types.js'\nimport type { RecordCodec } from '../../kernel/enclave/index.js'\nimport { stripI18nFilled, type I18nTextDescriptor } from '../../via/i18n/core.js'\nimport { isStaticDictDescriptor, type DictKeyDescriptor, type StaticDictDescriptor, type DictionaryHandle } from '../../via/i18n/dictionary.js'\nimport type { BlobSet } from '../../with-shape/blobs/blob-set.js'\nimport type { BlobFieldsConfig } from '../../with-shape/blobs/blob-compaction.js'\nimport type { Query } from '../../kernel/query/index.js'\nimport { embeddingSourceText, type VectorSet, type EmbeddingDescriptor, type StoredVector } from '../embeddings/index.js'\nimport { encodeVecId, decodeVecId, isVecIdFor } from '../embeddings/vec-id.js'\nimport { EmbeddingDimMismatchError } from '../../kernel/errors.js'\nimport { liveRecordIsElevated } from '../../kernel/tier-visibility.js'\nimport { searchScan, fuseRetrieval, type SearchOptions, type SearchResult } from './index.js'\nimport type { IndexStore } from './index-store.js'\nimport type { PersistedIndexCallbacks } from './persisted-index-store.js'\nimport { extractSnippet } from './snippet.js'\nimport { buildStringFieldEntries, buildI18nFieldEntries, buildDictKeyFieldEntries, buildBlobFieldEntries } from './build-docs.js'\nimport type { IndexDoc, IndexHit } from './inverted-index.js'\nimport type { RetrieveOptions, RetrieveHit } from './retrieve-types.js'\n\n/** Everything the moving search/retrieval methods touched on `this.*`. */\nexport interface SearchContext<T> {\n /** Collection name — error context + `_ftindex` row key. */\n readonly name: string\n /** Vault namespace the side-cars (`_vec`, `_ftindex`) live under. */\n readonly vault: string\n /** The ciphertext store. */\n readonly adapter: NoydbStore\n /** The record codec — decrypts the `_vec` / `_ftindex` side-car bodies. */\n readonly codec: RecordCodec<T>\n /** The eager working-set cache (SHARED `Map` reference, never copied). */\n readonly cache: Map<string, { record: T; version: number }>\n /** True in lazy mode — search/retrieve/warm require eager mode. */\n readonly lazy: boolean\n /** Declared text-index fields, or undefined. */\n readonly textIndexes: readonly string[] | undefined\n /** Declared i18n fields, or undefined. */\n readonly i18nFields: Record<string, I18nTextDescriptor> | undefined\n /** Declared dictionary-key fields, or undefined. */\n readonly dictKeyFields: Record<string, DictKeyDescriptor | StaticDictDescriptor> | undefined\n /** Declared blob fields, or undefined. */\n readonly blobFields: BlobFieldsConfig | undefined\n /** Dictionary handle resolver (dynamic dict-key labels), or undefined. */\n readonly getDictionary: ((name: string) => Promise<DictionaryHandle>) | undefined\n /** The lexical inverted-index store (in-memory or persisted), or undefined. */\n readonly searchIndexStore: IndexStore | undefined\n /** The vector set for semantic retrieval, or undefined. */\n readonly vectorSet: VectorSet | undefined\n /** The embeddings descriptor, or undefined. */\n readonly embeddings: EmbeddingDescriptor | undefined\n /** Hydrate the eager cache before reading it. */\n ensureHydrated(): Promise<void>\n /** Open the blob facade for a record (used to list indexed blob filenames). */\n blob(id: string): BlobSet\n}\n\n/**\n * Client-side lexical scan over the live eager cache. Eager mode only;\n * nothing searchable is written to the store.\n */\nexport async function search<T>(ctx: SearchContext<T>, field: string, query: string, opts: SearchOptions = {}): Promise<SearchResult<T>[]> {\n if (ctx.lazy) {\n throw new Error(\n `Collection \"${ctx.name}\": search() (scan mode) requires eager mode (prefetch: true). ` +\n `A store-usable blind index for lazy / at-scale search is a separate gated opt-in (#308).`,\n )\n }\n await ctx.ensureHydrated()\n const entries: { id: string; record: T }[] = []\n // Strip the internal densify marker from the user-facing records.\n // Non-mutating: never touches the cached record object. The search index\n // is built over the same (marker-free) record, which is fine — the marker\n // is never a searchable field.\n for (const [id, e] of ctx.cache) entries.push({ id, record: stripI18nFilled(e.record as Record<string, unknown>) as T })\n return searchScan(entries, field, query, opts)\n}\n\n/** L1 — build IndexDoc[] for the configured text fields over the live cache. */\nexport function buildRetrievalDocs<T>(\n ctx: SearchContext<T>,\n labelMaps: Map<string, Map<string, Record<string, string>>>,\n blobFilenames: Map<string, Map<string, string[]>>,\n only?: readonly string[],\n): IndexDoc[] {\n const docs: IndexDoc[] = []\n for (const [id, e] of ctx.cache) {\n const rec = stripI18nFilled(e.record as Record<string, unknown>)\n const fields = buildStringFieldEntries(rec, ctx.textIndexes ?? [], only)\n if (ctx.i18nFields) fields.push(...buildI18nFieldEntries(rec, ctx.i18nFields, ctx.textIndexes ?? [], only))\n if (ctx.dictKeyFields) fields.push(...buildDictKeyFieldEntries(rec, ctx.dictKeyFields, labelMaps, ctx.textIndexes ?? [], only))\n const blobNames = blobFilenames.get(id)\n if (blobNames) fields.push(...buildBlobFieldEntries(blobNames))\n if (fields.length > 0) docs.push({ id, fields })\n }\n return docs\n}\n\n/** L1 — true iff any configured text index is also a blob field (gates ALL slot I/O). */\nexport function hasIndexedBlobFields<T>(ctx: SearchContext<T>, only?: readonly string[]): boolean {\n if (!ctx.blobFields || !ctx.textIndexes) return false\n const fields = only ? ctx.textIndexes.filter((f) => only.includes(f)) : ctx.textIndexes\n return fields.some((f) => f in ctx.blobFields!)\n}\n\n/**\n * L1 — resolve `recordId -> (blobField -> filenames[])` by listing slots\n * for the configured blob fields of each cached record. Blob slot metadata is\n * NOT inline on the record: it lives in a separate `_blob_slots_*` collection,\n * so this costs ONE `blob(id).list()` (a `listSlots`) per record at build time\n * — the heaviest indexing source. Fully gated by {@link hasIndexedBlobFields};\n * non-blob (and blob-but-not-indexed) collections do ZERO slot I/O.\n */\nasync function resolveBlobFilenames<T>(ctx: SearchContext<T>, only?: readonly string[]): Promise<Map<string, Map<string, string[]>>> {\n const out = new Map<string, Map<string, string[]>>()\n if (!hasIndexedBlobFields(ctx, only)) return out\n const indexed = (only ? ctx.textIndexes!.filter((f) => only.includes(f)) : ctx.textIndexes!)\n .filter((f) => f in ctx.blobFields!)\n const indexedSet = new Set(indexed)\n for (const id of ctx.cache.keys()) {\n let slots\n try {\n slots = await ctx.blob(id).list()\n } catch {\n continue\n }\n let byField: Map<string, string[]> | undefined\n for (const slot of slots) {\n if (!indexedSet.has(slot.name) || !slot.filename) continue\n if (!byField) { byField = new Map(); out.set(id, byField) }\n const names = byField.get(slot.name)\n if (names) names.push(slot.filename)\n else byField.set(slot.name, [slot.filename])\n }\n }\n return out\n}\n\n/** L1 — field -> (key -> {locale->label}) for dictKey fields; static from table, dynamic via getDictionary().list(). */\nasync function resolveDictLabelMaps<T>(ctx: SearchContext<T>): Promise<Map<string, Map<string, Record<string, string>>>> {\n const maps = new Map<string, Map<string, Record<string, string>>>()\n if (!ctx.dictKeyFields || !ctx.textIndexes) return maps\n for (const field of ctx.textIndexes) {\n const desc = ctx.dictKeyFields[field]\n if (!desc) continue\n const m = new Map<string, Record<string, string>>()\n if (isStaticDictDescriptor(desc)) {\n for (const [key, labels] of Object.entries(desc.table)) m.set(key, labels as Record<string, string>)\n } else {\n if (ctx.getDictionary) {\n const handle = await ctx.getDictionary(desc.name)\n for (const e of await handle.list()) m.set(e.key, e.labels)\n }\n }\n maps.set(field, m)\n }\n return maps\n}\n\n/** L1.5 — force-persist the lexical index now (e.g. on save/idle). Persists only when textIndexPersist is enabled; a no-op otherwise. */\nexport async function flushIndex<T>(ctx: SearchContext<T>): Promise<void> {\n if (!ctx.searchIndexStore) return\n await ctx.ensureHydrated()\n const labelMaps = await resolveDictLabelMaps(ctx)\n const blobFilenames = await resolveBlobFilenames(ctx)\n await ctx.searchIndexStore.ensureBuilt(() => buildRetrievalDocs(ctx, labelMaps, blobFilenames))\n await ctx.searchIndexStore.flush?.()\n}\n\n/** L2 — load + decrypt all _vec sidecars into StoredVector[] for the VectorSet. */\nfunction buildVectorLoad<T>(ctx: SearchContext<T>): () => Promise<StoredVector[]> {\n return async () => {\n const ids = await ctx.adapter.list(ctx.vault, '_vec')\n const out: StoredVector[] = []\n for (const vecId of ids) {\n // #726: _vec is a vault-wide bucket namespaced by collection prefix —\n // skip rows belonging to other collections before touching this one's.\n if (!isVecIdFor(ctx.name, vecId)) continue\n const id = decodeVecId(ctx.name, vecId)!\n // #721 defense-in-depth: a _vec row carries no _tier of its own; the purge\n // on elevate is best-effort and cannot reach a legacy sidecar, so gate on\n // the owning record's live tier. Envelope peek, no decryption.\n if (await liveRecordIsElevated(ctx.adapter, ctx.vault, ctx.name, id)) continue\n const env = await ctx.adapter.get(ctx.vault, '_vec', vecId)\n if (!env) continue\n // #726 fails-safe: a row can pass isVecIdFor's prefix filter yet still\n // be undecryptable under THIS collection's DEK — a surviving legacy\n // bare-id row whose record id happens to start with `<thisCollection>/`,\n // or plain corruption. _vec sidecars are derived, re-derivable\n // artifacts (embedOnWrite regenerates them on the record's next put()),\n // so best-effort skip is correct: never let one poison row crash\n // similarTo()/retrieve() for the whole collection.\n let body: string | null\n try {\n body = await ctx.codec.decryptJsonString({ collection: '_vec', id: vecId }, env)\n } catch {\n continue\n }\n if (body === null) continue\n const parsed = JSON.parse(body) as { vec: number[]; model: string }\n out.push({ id, vec: new Float32Array(parsed.vec), model: parsed.model })\n }\n return out\n }\n}\n\n/**\n * L1.5 — build the PersistedIndexCallbacks bridge: crypto lives here\n * (collection has getDEK / encryptJsonString / decryptJsonString / adapter),\n * the index store itself is crypto-free.\n *\n * Fingerprint encoding: body-wrap approach — save(json, fp) stores\n * JSON.stringify({ fp, idx: json }) as the encrypted body so the standard\n * EncryptedEnvelope shape is never extended. load() decrypts and JSON.parses\n * the wrapper back out.\n *\n * Cache shape: ctx.cache stores { record, version } — currentFingerprint()\n * iterates over e.version.\n *\n * NOTE: this factory is invoked from the `Collection` constructor *before*\n * `this.codec` is assigned, so it takes a context THUNK and resolves the\n * context lazily inside each callback — by the time a callback actually runs,\n * the codec and cache are fully wired.\n */\nexport function buildPersistedIndexCallbacks<T>(provideCtx: () => SearchContext<T>): PersistedIndexCallbacks {\n const FT = '_ftindex'\n return {\n load: async () => {\n const ctx = provideCtx()\n const env = await ctx.adapter.get(ctx.vault, FT, ctx.name)\n if (!env) return null\n const body = await ctx.codec.decryptJsonString({ collection: FT, id: ctx.name }, env)\n if (body === null) return null\n try {\n const wrapped = JSON.parse(body) as { fp: { count: number; maxVersion: number }; idx: string }\n return { json: wrapped.idx, fingerprint: wrapped.fp }\n } catch {\n return null\n }\n },\n save: async (json, fp, isStale) => {\n const ctx = provideCtx()\n const body = JSON.stringify({ fp, idx: json })\n const env = await ctx.codec.encryptJsonString({ collection: FT, id: ctx.name }, body, fp.count)\n // #725 review: a purge (removePersisted) can land while the encrypt above was\n // in flight — check right before the write and skip it rather than resurrect a\n // purged/forgotten record's blob. PersistedIndexStore's own post-save epoch\n // check is the backstop for every other ordering (incl. a purge landing during\n // this very put).\n if (isStale()) return\n await ctx.adapter.put(ctx.vault, FT, ctx.name, env)\n },\n remove: async () => { const ctx = provideCtx(); await ctx.adapter.delete(ctx.vault, FT, ctx.name) },\n currentFingerprint: () => {\n const ctx = provideCtx()\n let maxVersion = 0\n for (const e of ctx.cache.values()) if (e.version > maxVersion) maxVersion = e.version\n return { count: ctx.cache.size, maxVersion }\n },\n }\n}\n\n/** L1 — pre-build the lexical index (e.g. on open) so the first retrieve() pays no build scan. */\nexport async function warmIndex<T>(ctx: SearchContext<T>): Promise<void> {\n if (!ctx.searchIndexStore) return\n if (ctx.lazy) {\n throw new Error(\n `Collection \"${ctx.name}\": warmIndex() requires eager mode (prefetch: true).`,\n )\n }\n await ctx.ensureHydrated()\n const built = ctx.searchIndexStore.built\n const labelMaps = built ? new Map() : await resolveDictLabelMaps(ctx)\n const blobFilenames = built ? new Map() : await resolveBlobFilenames(ctx)\n await ctx.searchIndexStore.ensureBuilt(() => buildRetrievalDocs(ctx, labelMaps, blobFilenames))\n}\n\n/** Retrieval. mode: 'lexical' (default) | 'semantic' (L2) | 'hybrid' (L3). */\nexport async function retrieve<T>(ctx: SearchContext<T>, query: string, opts: RetrieveOptions<T> = {}): Promise<RetrieveHit<T>[]> {\n const hits =\n opts.mode === 'semantic' ? await retrieveSemantic(ctx, query, opts)\n : opts.mode === 'hybrid' ? await retrieveHybrid(ctx, query, opts)\n : await retrieveLexical(ctx, query, opts)\n return opts.within ? applyWithin(hits, opts.within) : hits\n}\n\n/** L3 — keep only hits whose id matches the structured query, re-rank 1-based. */\nfunction applyWithin<T>(hits: RetrieveHit<T>[], within: Query<T>): RetrieveHit<T>[] {\n const ids = new Set(within._idArray())\n return hits.filter(h => ids.has(h.id)).map((h, i) => ({ ...h, rank: i + 1 }))\n}\n\n/** L1 — client-side lexical retrieval; ranked { id, score, field, snippet, locale? }. */\nasync function retrieveLexical<T>(ctx: SearchContext<T>, query: string, opts: RetrieveOptions<T>): Promise<RetrieveHit<T>[]> {\n if (!ctx.searchIndexStore) {\n throw new Error(`Collection \"${ctx.name}\": retrieve() requires a textIndexes config.`)\n }\n if (ctx.lazy) {\n throw new Error(\n `Collection \"${ctx.name}\": retrieve() requires eager mode (prefetch: true).`,\n )\n }\n await ctx.ensureHydrated()\n const built = ctx.searchIndexStore.built\n const labelMaps = built ? new Map() : await resolveDictLabelMaps(ctx)\n const blobFilenames = built ? new Map() : await resolveBlobFilenames(ctx)\n const index = await ctx.searchIndexStore.ensureBuilt(() => buildRetrievalDocs(ctx, labelMaps, blobFilenames))\n const hits = index.query(query, {\n ...(opts.limit !== undefined ? { limit: opts.limit } : {}),\n ...(opts.match ? { match: opts.match } : {}),\n ...(opts.prefix ? { prefix: opts.prefix } : {}),\n ...(opts.fields ? { fields: opts.fields } : {}),\n })\n const window = opts.snippetWindow ?? 80\n return hits.map((h: IndexHit, i: number) => {\n const base: RetrieveHit<T> = {\n id: h.id,\n score: h.score,\n rank: i + 1,\n field: h.field,\n snippet: extractSnippet(h.text, h.offset, window),\n ...(h.locale !== undefined ? { locale: h.locale } : {}),\n ...(opts.includeRecord\n ? (() => {\n const e = ctx.cache.get(h.id)\n return e ? { record: stripI18nFilled(e.record as Record<string, unknown>) as T } : {}\n })()\n : {}),\n }\n return base\n })\n}\n\n/** L3 — hybrid: fuse lexical (L1) + semantic (L2) by RRF. Requires embeddings. */\nasync function retrieveHybrid<T>(ctx: SearchContext<T>, query: string, opts: RetrieveOptions<T>): Promise<RetrieveHit<T>[]> {\n if (!ctx.embeddings) {\n throw new Error(`Collection \"${ctx.name}\": retrieve({mode:'hybrid'}) requires an embeddings config.`)\n }\n const [lex, sem] = await Promise.all([\n retrieveLexical(ctx, query, opts),\n retrieveSemantic(ctx, query, opts),\n ])\n return fuseRetrieval([lex, sem], opts.limit !== undefined ? { limit: opts.limit } : {})\n}\n\n/** L2 — semantic branch of retrieve(): encode query → similarTo(). */\nasync function retrieveSemantic<T>(ctx: SearchContext<T>, query: string, opts: RetrieveOptions<T>): Promise<RetrieveHit<T>[]> {\n if (!ctx.embeddings) throw new Error(`Collection \"${ctx.name}\": retrieve({mode:'semantic'}) requires an embeddings config.`)\n if (ctx.lazy) throw new Error(`Collection \"${ctx.name}\": retrieve() requires eager mode (prefetch: true).`)\n const qVec = await ctx.embeddings.encode(query)\n return similarTo(ctx, qVec, {\n ...(opts.limit !== undefined ? { k: opts.limit } : {}),\n ...(opts.minScore !== undefined ? { minScore: opts.minScore } : {}),\n ...(opts.includeRecord ? { includeRecord: true } : {}),\n })\n}\n\n/** L2 — raw-vector kNN over the encrypted vector set (decrypted in the trusted tier).\n * Snippet is '' for vector hits in v1 (semantic match isn't span-located). */\nexport async function similarTo<T>(ctx: SearchContext<T>, vector: Float32Array, opts: { k?: number; minScore?: number; includeRecord?: boolean } = {}): Promise<RetrieveHit<T>[]> {\n if (!ctx.embeddings || !ctx.vectorSet) throw new Error(`Collection \"${ctx.name}\": similarTo() requires an embeddings config.`)\n if (ctx.lazy) throw new Error(`Collection \"${ctx.name}\": similarTo() requires eager mode (prefetch: true).`)\n await ctx.ensureHydrated()\n await ctx.vectorSet.ensureLoaded(buildVectorLoad(ctx))\n const hits = ctx.vectorSet.cosineTopK(vector, opts.k ?? 10, {\n ...(opts.minScore !== undefined ? { minScore: opts.minScore } : {}),\n expectModel: ctx.embeddings.model,\n })\n return hits.map((h, i) => {\n const base: RetrieveHit<T> = { id: h.id, score: h.score, rank: i + 1, field: '(vector)', snippet: '' }\n if (opts.includeRecord) { const e = ctx.cache.get(h.id); if (e) (base as { record?: T }).record = stripI18nFilled(e.record as Record<string, unknown>) as T }\n return base\n })\n}\n\n/**\n * L2 — the embedding write-hook: derive a record's embedding vector at\n * write and persist it as the encrypted `_vec` side-car. Routed through the\n * search strategy so it runs only when `withSearch()` is opted in — computing\n * vectors that no gated `similarTo` / semantic `retrieve` could query would be\n * dead weight, so the compute is paired with the search capability. The caller\n * (`Collection.put`) only invokes this when `embeddings` is declared.\n */\nexport async function embedOnWrite<T>(ctx: SearchContext<T>, id: string, record: T, version: number): Promise<void> {\n if (!ctx.embeddings) return\n const text = embeddingSourceText(record as Record<string, unknown>, ctx.embeddings.source)\n const vec = await ctx.embeddings.encode(text)\n if (vec.length !== ctx.embeddings.dim) throw new EmbeddingDimMismatchError('embeddings', ctx.embeddings.dim, vec.length)\n const body = JSON.stringify({ vec: Array.from(vec), model: ctx.embeddings.model, dim: ctx.embeddings.dim })\n const vecEnv = await ctx.codec.encryptJsonString({ collection: '_vec', id: encodeVecId(ctx.name, id) }, body, version)\n await ctx.adapter.put(ctx.vault, '_vec', encodeVecId(ctx.name, id), vecEnv)\n ctx.vectorSet?.markDirty()\n}\n\n/**\n * Force-re-derive every eligible tier-0 record's `_vec` sidecar once (#788).\n * Opt-in bulk repair for the #726 re-namespace: legacy bare-id rows are\n * unreachable to `buildVectorLoad` (it only recognises `<collection>/<id>`\n * keys) and otherwise self-heal only when a record is next `put()` — this\n * lets an adopter recover recall immediately instead of waiting on writes.\n *\n * **Skips elevated records** (`liveRecordIsElevated`) rather than refusing\n * the whole walk — the OPPOSITE of `_applyCutoverTransform`'s\n * `assertCutoverTierSafe` refuse-whole-batch precedent. An elevated record is\n * SUPPOSED to have no `_vec` (`syncTierSearch` purges it on elevate);\n * re-embedding one here would write searchable plaintext-derived data above\n * tier 0. Load-bearing: never write a `_vec` row for an elevated record.\n *\n * Tombstones, delete markers, and a raw `get` racing a delete between `list`\n * and `get` all decrypt to `null` (`decryptRecord` already folds\n * tombstone/delete-marker into that null) and are skipped the same way.\n * Unconditional re-derive, no already-migrated check — safe to re-run after\n * a partial failure (each id is independently idempotent).\n */\nexport async function rebuildEmbeddings<T>(ctx: SearchContext<T>): Promise<{ rebuilt: number; skipped: number }> {\n if (!ctx.embeddings) return { rebuilt: 0, skipped: 0 }\n const ids = await ctx.adapter.list(ctx.vault, ctx.name)\n let rebuilt = 0\n let skipped = 0\n for (const id of ids) {\n if (await liveRecordIsElevated(ctx.adapter, ctx.vault, ctx.name, id)) { skipped++; continue }\n const env = await ctx.adapter.get(ctx.vault, ctx.name, id)\n if (!env) { skipped++; continue }\n const decoded = await ctx.codec.decryptRecord({ collection: ctx.name, id }, env)\n if (decoded === null) { skipped++; continue }\n await embedOnWrite(ctx, id, decoded, env._v ?? 1)\n rebuilt++\n }\n return { rebuilt, skipped }\n}\n\n/**\n * Sync the collection's SEARCH artifacts after a tier move (#721). Both the\n * lexical `_ftindex` blob and the `_vec/<id>` embedding are encrypted under\n * the tier-0 DEK and hold the record's derived plaintext (full field text /\n * a text-invertible vector), so leaving them means elevation never hid what\n * the record was searchable by — the `forget()` precedent, unapplied to\n * elevate. `null` → the record left tier 0: purge its `_vec` sidecar (mirrors\n * `Collection._purgeVector`), and invalidate the `_ftindex` blob (mirrors\n * `Collection._purgeSearchIndex`: deletes the persisted blob when persisted,\n * else drops the in-memory index) so the next `retrieve()` rebuilds from the\n * elevated-free `ctx.cache`. A record → it is tier-0 again: re-embed it via\n * {@link embedOnWrite}, then invalidate `_ftindex` so the rebuild includes it\n * again. No-op fast when the collection has neither a lexical index nor a\n * vector set.\n */\nexport async function syncTierSearch<T>(\n ctx: SearchContext<T>,\n id: string,\n record: T | null,\n version?: number,\n): Promise<void> {\n if (!ctx.searchIndexStore && !ctx.vectorSet) return\n if (record === null) {\n await ctx.adapter.delete(ctx.vault, '_vec', encodeVecId(ctx.name, id))\n ctx.vectorSet?.markDirty()\n } else {\n await embedOnWrite(ctx, id, record, version ?? 1)\n }\n const store = ctx.searchIndexStore\n if (store && 'removePersisted' in store) await (store as { removePersisted(): Promise<void> }).removePersisted()\n else store?.markDirty()\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/with-party/policy/presets.ts","../src/with-party/policy/engine.ts","../src/with-party/policy/noydb-facade.ts"],"sourcesContent":["import type { VaultPolicy } from '../../kernel/types.js'\n\n/**\n * Default policy for personal vaults and SMB deployments — the gates\n * that need an off-device factor get one (TOTP / email-OTP / paper\n * recovery), the rest take a tier-1 unlock alone. Tier-3 (PIN) is the\n * floor only for `rotate-unlock` because that's the\n * \"change my PIN\" flow.\n *\n * The unspecified gates (e.g. `view-user-auth`) inherit the engine\n * default of `{ enabled: false, minTier: 1 }` — they fail closed.\n *\n * @see https://github.com/vLannaAi/noy-db-docs/blob/main/content/docs/services/session-tiers.md → Built-in gates\n */\nexport const PERSONAL_POLICY: VaultPolicy = Object.freeze({\n secret: {\n minWords: 6,\n minWordLength: 3,\n rejectRepeatedAdjacent: true,\n },\n gates: {\n 'rotate-secret': {\n minTier: 1,\n // Any second factor satisfies the gate — off-device kinds (TOTP,\n // email-OTP, paper recovery, roaming WebAuthn) are the strongest;\n // platform-bound kinds (platform WebAuthn, password, PIN) are\n // accepted because requiring \"something off-device\" is overkill\n // for personal/SMB threat models. Consumers needing the off-device\n // guarantee should use STRICT_POLICY or override this gate.\n factors: [{\n anyOf: [\n 'totp', 'email-otp', 'recovery',\n 'webauthn-roaming', 'webauthn-platform',\n 'password', 'pin',\n ],\n }],\n },\n 'recover-secret': {\n minTier: 1,\n enabled: true,\n },\n // rotate-recovery: deliberate paper-sheet regeneration\n // when the user remembers their secret. PERSONAL allows tier-1 —\n // knowing the secret is enough.\n 'rotate-recovery': { minTier: 1 },\n 'enroll-authenticator': { minTier: 1 },\n 'remove-authenticator': { minTier: 1 },\n // update-authenticator: meta-only mutation (slot rename, label\n // changes). Symmetric with enroll/remove under PERSONAL — tier-1\n // unlock alone. The structural anti-slot-swap guard inside the\n // implementation enforces wrap-material/id/method immutability\n // regardless of this gate's settings.\n 'update-authenticator': { minTier: 1 },\n 'rotate-unlock': { minTier: 2 },\n 'enroll-user': { minTier: 1 },\n 'revoke-user': { minTier: 1 },\n // Peer-recovery is a high-trust intentional op — co-owners\n // recovering each other should not need an off-device factor in\n // the personal/SMB threat model (the partner is already vetted by\n // virtue of being a co-owner). Tier-1 unlock is the floor; the\n // STRICT preset adds a recovery/email-OTP requirement.\n 'peer-recover-user': { minTier: 1 },\n // update-user: post-grant identity mutation (role/displayName/\n // permissions). PERSONAL_POLICY treats this on par with enroll-user\n // / revoke-user — tier-1 unlock alone. The role-elevation guard\n // inside the implementation is the structural backstop that this\n // gate's settings cannot weaken.\n 'update-user': { minTier: 1 },\n 'export-bundle': { minTier: 1 },\n 'export-plaintext': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp'] }],\n },\n 'view-user-auth': {\n minTier: 1,\n enabled: false,\n },\n // ─── User envelope gates ──────────────────────────────────────────\n // edit-own-profile: tier 3 floor — any active session can edit their\n // own profile/preferences. Tightening to require a TOTP for\n // profile changes is a one-line override.\n // view-team-profiles: tier 2 floor — an authenticated session can\n // read teammates' profiles (display names, avatars, locales).\n // Setting `enabled: false` makes vault.user.list() return only\n // self (privacy-strict opt-out).\n 'edit-own-profile': { minTier: 3 },\n 'view-team-profiles': { minTier: 2 },\n // client-unilateral-withdraw: a non-owner's self-service DESTRUCTIVE\n // withdrawal (export-and-delete/freeze). Fail-closed by default —\n // the firm opts in per jurisdiction/contract (e.g. GDPR Art. 17).\n // Listed explicitly (not just relying on the built-in default) so it is\n // discoverable in describeGate / policy dumps.\n 'client-unilateral-withdraw': { minTier: 1, enabled: false },\n // Two-party withdrawal: filing a request is non-destructive\n // (tier-1, enabled so a read-only client can ask); deciding it is the\n // destructive step (tier-2 floor + owner/admin role, enforced in code).\n 'user-request-withdrawal': { minTier: 1 },\n 'approve-user-withdrawal': { minTier: 2 },\n },\n}) as VaultPolicy\n\n/**\n * Strict policy for regulated deployments and shared workstations —\n * raises the phrase floor to 8 words, demands two distinct factors for\n * exports, and blocks export-on-shared-device. Use as a base for\n * `policy: { ...STRICT_POLICY, gates: { ...STRICT_POLICY.gates, ... } }`\n * tweaks.\n */\nexport const STRICT_POLICY: VaultPolicy = Object.freeze({\n secret: {\n minWords: 8,\n minWordLength: 3,\n rejectRepeatedAdjacent: true,\n },\n gates: {\n 'rotate-secret': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp', 'recovery'], count: 2 }],\n },\n 'recover-secret': {\n minTier: 1,\n enabled: true,\n },\n // rotate-recovery: STRICT requires an off-device factor —\n // rotating recovery is an off-site-trust event; a stolen unlocked\n // laptop must not be able to silently mint a new sheet for the\n // attacker. Matches the `peer-recover-user` STRICT default.\n 'rotate-recovery': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp', 'webauthn-roaming'] }],\n },\n 'enroll-authenticator': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp'] }],\n },\n 'remove-authenticator': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp'] }],\n },\n // STRICT update-authenticator: same factor floor as enroll/remove.\n // Even though meta changes don't touch wrap material, a malicious\n // rename could mislead the user about which device a slot\n // corresponds to (\"MacBook Touch ID\" → \"iPhone Touch ID\" on a\n // shared workstation). STRICT requires a fresh factor proof.\n 'update-authenticator': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp'] }],\n },\n 'rotate-unlock': { minTier: 1 },\n 'enroll-user': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp'] }],\n },\n 'revoke-user': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp'] }],\n },\n // STRICT peer-recovery: the issuer must present a recovery code\n // OR a fresh off-device second factor at the moment of recovery.\n // This binds the high-trust operation to a verifiable proof\n // (recovery sheet photographed by an attacker won't suffice —\n // they'd also need tier-1 unlock first; this gate is the freshness\n // binding on top). Roaming WebAuthn (YubiKey-class hardware key)\n // accepted; platform-bound kinds (Touch ID, password, PIN)\n // intentionally excluded under STRICT because they don't survive\n // device theft — the off-device requirement is the whole point.\n 'peer-recover-user': {\n minTier: 1,\n factors: [{ anyOf: ['recovery', 'totp', 'email-otp', 'webauthn-roaming'] }],\n },\n // STRICT update-user: matches the enroll-user / revoke-user shape\n // (off-device factor required). Update-user is admin-shaped — it\n // mutates someone else's role/permissions; STRICT requires a fresh\n // off-device factor proof so the operator affirmatively re-asserts\n // identity at the moment of mutation. Platform-bound factors\n // (Touch ID / password / PIN) intentionally excluded: same logic as\n // peer-recover-user — the off-device requirement is the whole\n // point under STRICT.\n 'update-user': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp'] }],\n },\n 'export-bundle': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp'] }],\n warn: { sharedDevice: 'block' },\n },\n 'export-plaintext': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp'], count: 2 }],\n warn: { sharedDevice: 'block' },\n },\n 'view-user-auth': {\n minTier: 1,\n enabled: false,\n },\n // ─── User envelope gates ──────────────────────────────────────────\n // STRICT: profile edits require a TOTP/email-OTP factor (typical\n // shared-workstation hardening — your name/avatar shouldn't change\n // without a fresh second-factor proof).\n 'edit-own-profile': {\n minTier: 2,\n factors: [{ anyOf: ['totp', 'email-otp'] }],\n },\n 'view-team-profiles': { minTier: 2 },\n // STRICT: still fail-closed, but if a regulated firm flips enabled:true\n // they inherit a two-factor proof + shared-device block for the\n // destructive withdrawal (mirrors export-plaintext's hardening).\n 'client-unilateral-withdraw': {\n minTier: 1,\n enabled: false,\n factors: [{ anyOf: ['totp', 'email-otp'], count: 2 }],\n warn: { sharedDevice: 'block' },\n },\n // STRICT: filing stays tier-1; the destructive APPROVE demands an\n // off-device factor + shared-device block (mirrors export-bundle).\n 'user-request-withdrawal': { minTier: 1 },\n 'approve-user-withdrawal': {\n minTier: 2,\n factors: [{ anyOf: ['totp', 'email-otp'] }],\n warn: { sharedDevice: 'block' },\n },\n },\n}) as VaultPolicy\n\n/**\n * Merge a developer override onto a preset. Unspecified gates inherit;\n * specified gates fully replace the preset's entry for that gate.\n *\n * Example:\n *\n * ```ts\n * mergePolicy(PERSONAL_POLICY, {\n * gates: {\n * 'app:approve-large-payment': { minTier: 2, factors: [{ anyOf: ['totp'] }] },\n * },\n * })\n * // → PERSONAL_POLICY plus the new app gate; existing gates intact.\n * ```\n */\nexport function mergePolicy(\n base: VaultPolicy,\n override?: Partial<VaultPolicy>,\n): VaultPolicy {\n if (!override) return base\n const secret = override.secret ?? base.secret\n return {\n ...(secret !== undefined ? { secret } : {}),\n gates: {\n ...base.gates,\n ...(override.gates ?? {}),\n },\n }\n}\n","/**\n * Policy gate engine — the {@link checkGate} entry point.\n *\n * Given a configured {@link VaultPolicy}, an active session tier, and\n * the factor proofs an actor is presenting, decide whether the gate\n * permits the action. On denial, throws {@link PolicyDeniedError} with\n * a stable {@link PolicyDenyReason} so consumers can branch in error\n * UIs.\n *\n * @see https://github.com/vLannaAi/noy-db-docs/blob/main/content/docs/services/session-tiers.md → checkGate() API\n *\n * @module\n */\nimport { PolicyDeniedError, type PolicyDenyReason } from '../../kernel/errors.js'\nimport type {\n ActiveTier,\n FactorProof,\n GateName,\n GatePolicy,\n VaultPolicy,\n FactorRequirement,\n} from '../../kernel/types.js'\n\n/** Default freshness window — 5 minutes. */\nexport const DEFAULT_FRESHNESS_MS = 5 * 60 * 1000\n\n/** Caller-supplied context for one `checkGate` invocation. */\nexport interface CheckGateContext {\n /** Tier the active session currently holds. */\n readonly activeTier: ActiveTier\n /** Proofs the actor is presenting for this gate. */\n readonly factors?: ReadonlyArray<FactorProof>\n /**\n * If the host knows the actor is on a shared device, set this to\n * `true` so the engine can apply `warn.sharedDevice` rules. Defaults\n * to `false`.\n */\n readonly sharedDevice?: boolean\n /**\n * Override `now()` for tests. Defaults to `Date.now()`.\n * @internal\n */\n readonly now?: number\n}\n\n/**\n * Decide whether `gate` permits the action under `context`. Throws\n * {@link PolicyDeniedError} on denial; resolves with `void` on success.\n *\n * Lookup rules:\n * - **Built-in gates** without a configured policy fail closed\n * (`enabled: false`).\n * - **App-defined gates** (`app:*`) without a configured policy are\n * treated as no-op (allow). The developer registered the policy if\n * they wanted enforcement; absence means the gate is informational.\n */\nexport async function checkGate(\n policy: VaultPolicy,\n gate: GateName,\n context: CheckGateContext,\n): Promise<void> {\n const configured = policy.gates[gate]\n if (!configured) {\n if (gate.startsWith('app:')) {\n // Custom app gate without a policy — the developer hasn't\n // registered one; engine treats it as an unenforced label.\n return\n }\n // Built-in gate without a policy — fail closed.\n throw deny(gate, 'disabled', { minTier: 1, enabled: false })\n }\n\n if (configured.enabled === false) {\n throw deny(gate, 'disabled', configured)\n }\n\n // Tier check first — cheap and a hard prerequisite.\n if (context.activeTier > configured.minTier) {\n // Higher number is a LOWER tier in this model (1 is most privileged).\n throw deny(gate, 'insufficient-tier', configured)\n }\n\n // Factor checks — every requirement entry must be satisfied.\n if (configured.factors && configured.factors.length > 0) {\n const presented = context.factors ?? []\n const now = context.now ?? Date.now()\n for (const requirement of configured.factors) {\n const matches = countMatchingFactors(presented, requirement, now)\n const need = requirement.count ?? 1\n if (matches.fresh < need) {\n if (matches.totalKindMatches < need) {\n throw deny(gate, 'missing-factor', configured)\n }\n // Some matched the kind list but not the freshness window.\n throw deny(gate, 'stale-proof', configured)\n }\n }\n }\n\n // Soft signals — only `'block'` raises here.\n if (configured.warn?.sharedDevice === 'block' && context.sharedDevice === true) {\n throw deny(gate, 'shared-device-blocked', configured)\n }\n}\n\n/**\n * Same as {@link checkGate} but returns a structured verdict instead\n * of throwing. Useful when an error UI wants to show the user\n * \"you'll need TOTP plus a recovery code to do that\" without first\n * triggering the action.\n */\nexport async function describeGate(\n policy: VaultPolicy,\n gate: GateName,\n context: CheckGateContext,\n): Promise<{ ok: true } | { ok: false; reason: PolicyDenyReason; required: GatePolicy }> {\n try {\n await checkGate(policy, gate, context)\n return { ok: true }\n } catch (err) {\n if (err instanceof PolicyDeniedError) {\n return { ok: false, reason: err.reason, required: err.required }\n }\n throw err\n }\n}\n\nfunction countMatchingFactors(\n presented: ReadonlyArray<FactorProof>,\n requirement: FactorRequirement,\n now: number,\n): { totalKindMatches: number; fresh: number } {\n const freshnessMs = requirement.freshnessMs ?? DEFAULT_FRESHNESS_MS\n let totalKindMatches = 0\n let fresh = 0\n for (const proof of presented) {\n if (!requirement.anyOf.includes(proof.kind)) continue\n totalKindMatches += 1\n const minted = proof.mintedAt ? Date.parse(proof.mintedAt) : now\n if (Number.isFinite(minted) && now - minted <= freshnessMs) {\n fresh += 1\n }\n }\n return { totalKindMatches, fresh }\n}\n\nfunction deny(gate: GateName, reason: PolicyDenyReason, required: GatePolicy): PolicyDeniedError {\n return new PolicyDeniedError(gate, reason, required)\n}\n","/**\n * Noydb-side policy / session-policy facade.\n *\n * Holds the vault-policy read/update/bootstrap logic (`getPolicy`,\n * `updatePolicy`, `bootstrapPolicy`) and the per-vault session-policy\n * enforcer wiring (`touchPolicy`, `checkPolicyOperation`). The session\n * *timer* and the managed-recovery enrolment check stay kernel-resident on\n * `Noydb` (interleaved with the instance lifecycle) and arrive here as the\n * `resetSessionTimer` / `assertRecoveryEnrolled` callbacks. The policy cache\n * and the enforcer map stay `Noydb`-resident too (touched by\n * `openVault`/`close`) and arrive by reference; behaviour is byte-identical\n * to the inline `Noydb` methods it replaced — every other dependency the\n * moving code touched on `this.*` arrives via {@link NoydbPolicyDeps}.\n *\n * Internal service — reached through `noydb.getPolicy(...)` etc. Public\n * contract ({@link NoydbPolicyApi} / {@link NoydbPolicyDeps} /\n * {@link NoydbPolicyFactory}) lives in the kernel spine; `createNoydb()`\n * wires this file's {@link createNoydbPolicy} in via a pre-resolved dynamic\n * import (the S4 gate recipe).\n */\nimport { ValidationError } from '../../kernel/errors.js'\nimport { PERSONAL_POLICY, mergePolicy } from './presets.js'\nimport { loadVaultPolicy, saveVaultPolicy } from './storage.js'\nimport type { VaultPolicy, ReAuthOperation, NoydbPolicyApi, NoydbPolicyDeps, NoydbPolicyFactory } from '../../kernel/types.js'\n\nexport class NoydbPolicy implements NoydbPolicyApi {\n constructor(private readonly deps: NoydbPolicyDeps) {}\n\n /**\n * Touch the policy enforcer for a vault (records activity, resets\n * idle timer). Also touches the legacy session timer. No-op if no enforcer.\n */\n touchPolicy(vault?: string): void {\n this.deps.resetSessionTimer()\n if (vault) {\n this.deps.policyEnforcers.get(vault)?.touch()\n }\n }\n\n /**\n * Check that a policy-guarded operation is permitted.\n * Throws `SessionPolicyError` if re-auth is required.\n */\n checkPolicyOperation(vault: string, op: ReAuthOperation): void {\n this.deps.policyEnforcers.get(vault)?.checkOperation(op)\n }\n\n /**\n * Read the active policy for a vault. Loads from `_meta/policy` on\n * first call; subsequent calls hit the in-memory cache. Throws\n * `ValidationError` if the vault has not been opened.\n */\n async getPolicy(vault: string): Promise<VaultPolicy> {\n if (this.deps.isClosed()) throw new ValidationError('Instance is closed')\n const cached = this.deps.policyCache.get(vault)\n if (cached) return cached\n await this.bootstrapPolicy(vault)\n return this.deps.policyCache.get(vault) ?? PERSONAL_POLICY\n }\n\n /**\n * Replace the policy document at `_meta/policy` and update the\n * in-memory cache. Gated by the `enroll-user` policy (a policy\n * change is fundamentally a privilege-management action).\n */\n async updatePolicy(vault: string, override: Partial<VaultPolicy>): Promise<VaultPolicy> {\n if (this.deps.isClosed()) throw new ValidationError('Instance is closed')\n const current = await this.getPolicy(vault)\n const merged = mergePolicy(current, override)\n if (this.deps.encrypted) {\n await saveVaultPolicy(this.deps.store, vault, merged)\n }\n this.deps.policyCache.set(vault, merged)\n return merged\n }\n\n /** Read or persist the vault policy at `_meta/policy` on first open. */\n async bootstrapPolicy(\n vault: string,\n opts?: { skipManagedCheck?: boolean },\n ): Promise<void> {\n const onDisk = await loadVaultPolicy(this.deps.store, vault)\n if (onDisk) {\n // Honour the on-disk document; developer overrides cannot\n // weaken what the vault committed to at creation time.\n this.deps.policyCache.set(vault, onDisk)\n await this.deps.assertRecoveryEnrolled(vault, onDisk, opts)\n return\n }\n // First time — persist the developer's policy (or default preset).\n const initial = this.deps.policyOption\n ? mergePolicy(PERSONAL_POLICY, this.deps.policyOption)\n : PERSONAL_POLICY\n await saveVaultPolicy(this.deps.store, vault, initial)\n this.deps.policyCache.set(vault, initial)\n await this.deps.assertRecoveryEnrolled(vault, initial, opts)\n }\n}\n\n/**\n * Factory that builds the `NoydbPolicy` service. `createNoydb()`\n * pre-resolves this via a dynamic import (mirrors\n * `with-party/directory/user-envelope/api.js#createUserApi`) and threads\n * it through `NoydbOptions.policyFactory` so `Noydb`'s constructor can\n * build `this.policyManager` synchronously.\n */\nexport const createNoydbPolicy: NoydbPolicyFactory = (deps) => new NoydbPolicy(deps)\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/via/lookup/registry.ts","../src/via/lookup/snapshot.ts","../src/port/with/lookup-strategy.ts"],"sourcesContent":["/**\n * Pure dict-registry helpers — extracted from `kernel/vault.ts`'s dict\n * bodies (#650 Task 1 — via-lookup extraction, phase D).\n *\n * These take the vault-resident registry Maps (and a couple of vault-bound\n * callbacks) as ARGUMENTS instead of closing over `this` — no `Vault`\n * import here, so this module stays a plain, testable function library.\n * `kernel/vault.ts` keeps the registry Maps themselves (they're populated\n * by `vault.collection()` and read by the backup path) and calls these\n * helpers through the `port/with/lookup-strategy.ts` seam.\n */\n\nimport { getAtPath } from '../../kernel/paths.js'\nimport { UnknownDictCodeError, ValidationError } from '../../kernel/errors.js'\nimport type { JoinableSource } from '../../kernel/query/index.js'\nimport type { FieldRef, ViaGraph } from '../../kernel/via/graph.js'\nimport type { StaticDictDescriptor } from '../../port/with/i18n-strategy.js'\nimport { dictCollectionName, type LookupHandle } from './handle.js'\nimport type { LookupDescriptor, OnDelete } from './descriptor.js'\n\n/**\n * Validate staticDict codes on a `put()`. For each `staticDict()` field,\n * every stored code must be a declared key of the descriptor's table, else\n * `UnknownDictCodeError`. Opt out per descriptor with `{ validateCodes:\n * false }`. Supports scalar, dotted, and `[].`-wildcard field paths via\n * `getAtPath` (same path support as i18n validation).\n *\n * `staticFields` is the collection's `field → StaticDictDescriptor` map\n * (`Vault#staticDescriptorByField.get(collectionName)`) — `undefined`/empty\n * is a no-op.\n */\nexport function enforceStaticDictOnPut(\n staticFields: Record<string, StaticDictDescriptor> | undefined,\n record: unknown,\n): void {\n if (!staticFields || Object.keys(staticFields).length === 0) return\n if (!record || typeof record !== 'object') return\n\n const obj = record as Record<string, unknown>\n for (const [field, desc] of Object.entries(staticFields)) {\n if (desc.validateCodes === false) continue\n const known = new Set<string>(desc.keys)\n const values = getAtPath(obj, field)\n for (const value of values) {\n if (value === undefined || value === null) continue\n const codes = Array.isArray(value) ? value : [value]\n for (const code of codes) {\n if (typeof code !== 'string') continue\n if (!known.has(code)) {\n throw new UnknownDictCodeError(desc.name, field, code)\n }\n }\n }\n }\n}\n\n/**\n * Build a `JoinableSource` for a dictKey field, for use in dict joins.\n * Returns a source whose snapshot contains `{ key, labels, ...labels }`\n * records — one per dictionary entry — keyed by the stable key.\n *\n * staticDict: a code-table-backed source — snapshot() materialises the\n * in-memory table into rows, mirroring `LookupHandle.snapshotEntries()`.\n * Carries `displayLocale` so a locale-less `{ by: 'label' }` query has a\n * default locale to resolve at.\n *\n * Plain dictKey: the snapshot is built synchronously from the\n * `LookupHandle`'s write-through cache, which is populated on every\n * `put()`, `rename()`, `delete()`, and `list()` call. For pre-existing\n * data not yet touched this session, call `await vault.dictionary(name).list()`\n * first to warm the cache.\n *\n * Returns `null` when `field` is not a dictKey in `leftCollection`.\n */\nexport function resolveDictSource(\n leftCollection: string,\n field: string,\n staticDescriptorByField: ReadonlyMap<string, Record<string, StaticDictDescriptor>>,\n dictKeyFieldRegistry: ReadonlyMap<string, Record<string, string>>,\n getDictionaryHandle: (name: string) => LookupHandle,\n): JoinableSource | null {\n const staticFields = staticDescriptorByField.get(leftCollection)\n if (staticFields && field in staticFields) {\n const desc = staticFields[field]!\n const rows: readonly Record<string, unknown>[] = Object.entries(desc.table).map(\n ([key, labels]) => ({ key, labels, ...(labels as Record<string, string>) }),\n )\n const source: JoinableSource = {\n snapshot(): readonly unknown[] {\n return rows\n },\n lookupById(id: string): unknown {\n return rows.find((e) => e['key'] === id)\n },\n }\n if (desc.displayLocale !== undefined) {\n ;(source as { displayLocale?: string }).displayLocale = desc.displayLocale\n }\n return source\n }\n\n const dictFields = dictKeyFieldRegistry.get(leftCollection)\n if (!dictFields || !(field in dictFields)) return null\n const dictName = dictFields[field]\n if (!dictName) return null\n const handle = getDictionaryHandle(dictName)\n return {\n snapshot(): readonly unknown[] {\n return handle.snapshotEntries()\n },\n lookupById(id: string): unknown {\n const entries = handle.snapshotEntries()\n return entries.find((e) => e['key'] === id)\n },\n }\n}\n\n/** The minimal collection surface `updateReferencingRecords` needs. */\nexport interface DictReferencingCollection {\n list(): Promise<Record<string, unknown>[]>\n put(id: string, record: Record<string, unknown>): Promise<unknown>\n}\n\n/**\n * Find and rewrite records in every registered collection whose\n * dictKeyField points at `name`, replacing `oldKey` with `newKey`. Used by\n * `LookupHandle.rename()` (the only sanctioned mass-mutation path for\n * dictKey fields) via the vault's `findAndUpdateReferences` callback.\n *\n * `registry` is `Vault#dictKeyFieldRegistry` (collection name → field name\n * → dictionary name); `getCollection` is the vault's collection accessor —\n * rewrites go through the public `coll.put()` choke point, same as before.\n */\nexport async function updateReferencingRecords(\n registry: ReadonlyMap<string, Record<string, string>>,\n getCollection: (collectionName: string) => DictReferencingCollection,\n name: string,\n oldKey: string,\n newKey: string,\n): Promise<void> {\n for (const [collectionName, dictFields] of registry) {\n // Find fields that point at this dictionary\n const fields = Object.entries(dictFields)\n .filter(([, dn]) => dn === name)\n .map(([field]) => field)\n if (fields.length === 0) continue\n\n const coll = getCollection(collectionName)\n const records = await coll.list()\n for (const record of records) {\n let changed = false\n const updated = { ...record }\n for (const field of fields) {\n if (updated[field] === oldKey) {\n updated[field] = newKey\n changed = true\n }\n }\n if (changed) {\n const id = record['id'] as string | undefined\n if (id !== undefined) {\n await coll.put(id, updated)\n }\n }\n }\n }\n}\n\n/**\n * Resolve a label from an in-memory `{ locale -> label }` map, walking the\n * same fallback chain semantics as `LookupHandle.resolveLabel` (#650 Task 2\n * — moved here from `kernel/vault.ts` so the SAME chain serves both the\n * i18n binding's `dictLabelResolver` and the lookup binding's\n * `lookupLabelResolver`, which #650 Task 2 wires to the identical closure).\n */\nexport function resolveLabelFromMap(\n labels: Readonly<Record<string, string>>,\n locale: string,\n fallback?: string | readonly string[],\n): string | undefined {\n if (labels[locale] !== undefined) return labels[locale]\n const chain = Array.isArray(fallback)\n ? (fallback as readonly string[])\n : fallback\n ? [fallback as string]\n : []\n for (const fb of chain) {\n if (fb === 'any') {\n const any = Object.values(labels)[0]\n if (any !== undefined) return any\n } else if (labels[fb] !== undefined) {\n return labels[fb]\n }\n }\n return undefined\n}\n\n/**\n * Project a native `lookup(dimension, { backing:'static', table, … })`\n * descriptor into the legacy `StaticDictDescriptor` shape — the\n * alias-equivalence compat seam (#650 Task 2) that lets a native\n * static-tier lookup field reuse the SAME vault registries\n * (`staticByName`/`staticDescriptorByField`) — and therefore the same\n * `dictLabelResolver`/`resolveDictSource` machinery — as its `staticDict()`\n * alias. `vocabulary:'closed'` maps to `validateCodes:true` (closed = only\n * declared codes are legal); `'open'` maps to `validateCodes:false`.\n * Returns `undefined` for non-static or table-less (bare `enumOf`)\n * descriptors — those have nothing to register.\n */\nexport function lookupToStaticDictCompat(desc: LookupDescriptor): StaticDictDescriptor | undefined {\n if (desc.backing !== 'static' || desc.table === undefined) return undefined\n return {\n _noydbStaticDict: true,\n _viaBrand: 'i18n',\n name: desc.dimension,\n table: desc.table,\n keys: desc.keys ?? Object.keys(desc.table),\n ...(desc.displayLocale !== undefined ? { displayLocale: desc.displayLocale } : {}),\n ...(desc.onMissing !== undefined ? { onMissing: desc.onMissing } : {}),\n ...(desc.substitute !== undefined ? { substitute: desc.substitute } : {}),\n validateCodes: desc.vocabulary === 'closed',\n }\n}\n\n/** The vault-registry entries a collection's `lookupFields` contribute — the alias-equivalence bridge (#650 Task 2). */\nexport interface LookupDictCompat {\n /** Reserved-tier fields: field name -> dimension (dictionary) name — merges into `dictKeyFieldRegistry`. */\n readonly dictFieldMap: Record<string, string>\n /** Static-tier (table-bearing) fields, projected — merges into `staticDescriptorByField`/`staticByName`. */\n readonly staticEntries: ReadonlyArray<readonly [string, StaticDictDescriptor]>\n}\n\n/**\n * Bridge a collection's `lookupFields` into the SAME shape the legacy dict\n * registries expect, so `resolveDictSource`/`dictLabelResolver` (and\n * therefore `.join()`/`orderBy({by:'label'})`) serve a native `dict()`/\n * `lookup(static)` field identically to its `dictKey()`/`staticDict()`\n * alias — the reserved-vs-first-class-backing \"matrix\" tier is NOT bridged\n * here (no vault registry backs it; Task 5/6 build its own graph edge /\n * snapshot seam).\n */\nexport function collectLookupDictCompat(\n lookupFields: Record<string, LookupDescriptor> | undefined,\n): LookupDictCompat {\n const dictFieldMap: Record<string, string> = {}\n const staticEntries: Array<readonly [string, StaticDictDescriptor]> = []\n for (const [field, desc] of Object.entries(lookupFields ?? {})) {\n if (desc.backing === 'reserved') {\n dictFieldMap[field] = desc.dimension\n } else {\n const compat = lookupToStaticDictCompat(desc)\n if (compat) staticEntries.push([field, compat])\n }\n }\n return { dictFieldMap, staticEntries }\n}\n\n/**\n * Reserved-dict deps of a set of named collections (#653) — the `_dict_*`\n * collections partial sync must auto-include alongside a `collections`\n * filter, mirroring `SyncEngine`'s existing satellite-pair expansion.\n * One hop is provably complete: `vault.collection()` refuses `_dict_*`\n * names, so a dict can never itself declare lookup fields — no\n * dict-of-dict chain to recurse through.\n */\nexport function reservedDictDepsOf(\n names: readonly string[],\n dictKeyFieldRegistry: ReadonlyMap<string, Record<string, string>>,\n): readonly string[] {\n const out = new Set<string>()\n for (const name of names) {\n const fieldMap = dictKeyFieldRegistry.get(name)\n if (!fieldMap) continue\n for (const dictName of Object.values(fieldMap)) out.add(dictCollectionName(dictName))\n }\n return [...out]\n}\n\n/**\n * A lookup dimension's sync membership/altKey table, materialized from its\n * backing rows (#650 Task 3). `keys` is every canonical key present;\n * `altIndex` maps an altKey candidate VALUE to its owning canonical key.\n */\nexport interface MaterializedBacking {\n /** Canonical key values present in the materialized rows. */\n readonly keys: ReadonlySet<string>\n /** altKey candidate value -> canonical key. */\n readonly altIndex: ReadonlyMap<string, string>\n}\n\n/**\n * Build a lookup dimension's altKey index from its backing rows, enforcing\n * declare/warm-time uniqueness across `key ∪ altKeys` values (#650 Task 3 —\n * the CHE/SWZ drift class: two different rows must never claim the same\n * candidate key). `rows` is keyed by canonical key (`row[descriptor.key]`\n * for the matrix tier; the dimension's own key for static/reserved).\n * An altKey candidate VALUE may be a string or number — both normalize via\n * `coerceLookupKey` (#651 Task 3); non-scalar/absent values are skipped.\n * Pure — no I/O. Throws `ValidationError` on collision.\n */\nexport function materializeBackingTable(\n descriptor: LookupDescriptor,\n rows: ReadonlyMap<string, Record<string, unknown>>,\n): MaterializedBacking {\n const keys = new Set<string>(rows.keys())\n // Every value that has claimed ownership so far (canonical keys seed it) —\n // the union `key ∪ altKeys` uniqueness set the spec requires.\n const owner = new Map<string, string>()\n for (const key of keys) owner.set(key, key)\n\n const altIndex = new Map<string, string>()\n const altFields = descriptor.altKeys ?? []\n for (const [canonicalKey, row] of rows) {\n for (const altField of altFields) {\n const value = coerceLookupKey(row[altField])\n if (value === undefined || value === '') continue\n const existingOwner = owner.get(value)\n if (existingOwner !== undefined && existingOwner !== canonicalKey) {\n throw new ValidationError(\n `lookup \"${descriptor.dimension}\": altKey field \"${altField}\" value \"${value}\" is claimed by ` +\n `both \"${existingOwner}\" and \"${canonicalKey}\" — key/altKey values must be unique across the dimension.`,\n )\n }\n owner.set(value, canonicalKey)\n altIndex.set(value, canonicalKey)\n }\n }\n return { keys, altIndex }\n}\n\n/**\n * Closed-vocabulary membership test for one candidate key (#650 Task 3).\n * Static tier: sync, against the in-config key set (declared `keys`, or the\n * table's own keys when table-bearing). Reserved tier: sync — the declared\n * `keys` union the reserved handle's live write-through snapshot (closes\n * #649 for the native `dict()` spelling: the declared-keys promise the old\n * `dictKey()` doc comment made falsely). Matrix (collection) tier: sync —\n * delegates to `buildLookupAltIndex` so membership is checked against the\n * SAME `row[descriptor.key]` keying the altKey index uses (review fix,\n * Important 1: an earlier PUT-id `.get(key)` scan disagreed with the\n * altIndex whenever `descriptor.key !== 'id'`, wrongly rejecting valid\n * non-id candidates and wrongly accepting an unrelated row's PUT-id).\n */\nexport function checkLookupMembership(\n descriptor: LookupDescriptor,\n key: string,\n getDictionary: (dimension: string) => LookupHandle,\n getCollection: (dimension: string) => { querySourceForJoin(): JoinableSource },\n): boolean {\n if (descriptor.backing === 'static') {\n const known = descriptor.keys ?? (descriptor.table ? Object.keys(descriptor.table) : [])\n return known.includes(key)\n }\n if (descriptor.backing === 'reserved') {\n if ((descriptor.keys ?? []).includes(key)) return true\n return getDictionary(descriptor.dimension).snapshotEntries().some((e) => e['key'] === key)\n }\n return buildLookupAltIndex(descriptor, getDictionary, getCollection).keys.has(key)\n}\n\n/**\n * The ONE guarded key coercion (#651 Task 3, dm12) — string/number values\n * coerce to their canonical `String()` form; everything else (`null`,\n * `undefined`, objects, …) coerces to `undefined`. Every consumer that turns\n * a raw record field into a lookup key routes through this, closing the\n * bare-`String()` `\"undefined\"`/`\"null\"`-key poisoning class (seam map\n * finding 6): a row whose key field is genuinely absent must never mint the\n * literal candidate string `\"undefined\"`.\n */\nexport function coerceLookupKey(raw: unknown): string | undefined {\n return typeof raw === 'string' || typeof raw === 'number' ? String(raw) : undefined\n}\n\n/**\n * Resolve a backing row's canonical key VALUE — `coerceLookupKey(row[descriptor.key])`\n * (#651 Task 3). The matrix tier's `row[descriptor.key]`, never the row's own PUT-id\n * when the two differ (`descriptor.key !== 'id'`).\n */\nexport function resolveBackingRowKey(\n descriptor: LookupDescriptor,\n row: Record<string, unknown>,\n): string | undefined {\n return coerceLookupKey(row[descriptor.key])\n}\n\n/**\n * The referencing-side match predicate — does `rec[field]` (coerced) equal an\n * already-coerced `compareKey` (#651 Task 3)? Shared by every site that scans a\n * referencing collection for rows pointing at a given backing key\n * (`with-shape/links/vault-facade.ts`'s ref-delete propagation, `kernel/via/dispatch.ts`'s\n * forget-fanout twin).\n */\nexport function matchesReferencingValue(\n rec: Record<string, unknown>,\n field: string,\n compareKey: string,\n): boolean {\n return coerceLookupKey(rec[field]) === compareKey\n}\n\n/**\n * Materialize a lookup dimension's altKey index from whatever backing data\n * is synchronously available (#650 Task 3 — the `ingest` source). Static:\n * the in-config table. Reserved: the reserved handle's live write-through\n * cache (the same warm-via-put()/list() cache `resolveDictSource` already\n * relies on). Matrix (collection): the backing collection's own in-memory\n * eager cache via `querySourceForJoin()` — already public, already the\n * mechanism `.join()` uses (`with-shape/links/vault-facade.ts`'s\n * `resolveSource`); no new I/O, no fire-and-forget warm step. Like that\n * existing join precedent, a dimension collection this vault session has\n * not yet opened/populated sees an empty snapshot (no altKey normalization\n * until it has rows) — open/populate it first for normalization to apply.\n * A matrix row whose `descriptor.key` field coerces to `undefined` (missing/\n * non-scalar) is SKIPPED — never enters the index under a poisoned\n * `\"undefined\"` key (#651 Task 3, dm12).\n */\nexport function buildLookupAltIndex(\n descriptor: LookupDescriptor,\n getDictionary: (dimension: string) => LookupHandle,\n getCollection: (dimension: string) => { querySourceForJoin(): JoinableSource },\n): MaterializedBacking {\n if (descriptor.backing === 'static') {\n return materializeBackingTable(descriptor, new Map(Object.entries(descriptor.table ?? {})))\n }\n if (descriptor.backing === 'reserved') {\n const entries = getDictionary(descriptor.dimension).snapshotEntries()\n return materializeBackingTable(descriptor, new Map(entries.map((e) => [String(e['key']), e])))\n }\n const rows = getCollection(descriptor.dimension).querySourceForJoin().snapshot()\n const keyed = new Map<string, Record<string, unknown>>()\n for (const r of rows) {\n const row = r as Record<string, unknown>\n const key = resolveBackingRowKey(descriptor, row)\n if (key !== undefined) keyed.set(key, row)\n }\n return materializeBackingTable(descriptor, keyed)\n}\n\n/** One cross-collection `'ref'` graph edge a lookup field declares (#650 Task 5). Module-private —\n * only `registerLookupRefEdges` below (the exported entry point) consumes it. */\ninterface LookupRefEdge {\n readonly referencing: FieldRef\n readonly sources: readonly FieldRef[]\n readonly onDelete: OnDelete\n /** The backing dimension's canonical-key FIELD NAME on its own row (`desc.key` — matrix tier\n * only varies this; reserved/static tiers are always `'id'`). A referencing field always\n * stores THIS field's value, never the backing row's PUT-id when the two differ. */\n readonly keyField: string\n}\n\n/**\n * Compute the cross-collection `'ref'` edges a collection's `lookupFields` declare (#650 Task 5,\n * spec §4) — one edge per non-static-backing field: target = the referencing field; sources =\n * the backing dimension's whole-collection node (`field:'*'`, the wildcard key\n * `ViaGraph.referencingEdgesOf` does its O(1) reverse lookup against) PLUS, when the descriptor\n * names a presentation field (`present.label`), that SPECIFIC field too. `foldPosture`'s\n * `DEFAULT_POSTURE` is the fold's identity element, so adding the wildcard alongside a real field\n * source changes nothing when that field is plain — but folds in a classified/money posture when\n * it isn't (taint composition, spec §4: \"a lookup edge whose source names a classified field\n * contributes that field's posture\"). Static tier (`backing:'static'`) has no backing collection/\n * dimension rows to reference-check — excluded. Pure; consumed only by `registerLookupRefEdges` below.\n */\nfunction collectLookupRefEdges(\n collectionName: string,\n lookupFields: Record<string, LookupDescriptor> | undefined,\n): readonly LookupRefEdge[] {\n const edges: LookupRefEdge[] = []\n for (const [field, desc] of Object.entries(lookupFields ?? {})) {\n if (desc.backing === 'static') continue\n const backing = desc.backing === 'reserved' ? dictCollectionName(desc.dimension) : desc.dimension\n edges.push({\n referencing: { collection: collectionName, field },\n sources: [\n { collection: backing, field: '*' },\n ...(desc.present?.label !== undefined ? [{ collection: backing, field: desc.present.label }] : []),\n ],\n onDelete: desc.onDelete,\n keyField: desc.key,\n })\n }\n return edges\n}\n\n/** Thin wrapper — `collectLookupRefEdges` + one `graph.registerDerived` call per edge. Lets\n * `vault.collection()` (kernel-surface-budgeted, #650 Task 5) register a collection's lookup-ref\n * edges with a single line, keeping the ceiling-guarded call site a thin call (route logic here). */\nexport function registerLookupRefEdges(\n graph: ViaGraph,\n collectionName: string,\n lookupFields: Record<string, LookupDescriptor> | undefined,\n): void {\n for (const e of collectLookupRefEdges(collectionName, lookupFields)) {\n graph.registerDerived(e.referencing, e.sources, 'ref', 'record', e.onDelete, e.keyField)\n }\n}\n\n/**\n * `LookupViaConfig.snapshotFor`'s vault-built row source (#650 Task 6, spec\n * §5; matrix-tier coverage added #650 Task 7, spec §6 — Task 6 deferred it,\n * see `task-6-report.md`'s Concerns #1; the reviewer's Task-7 dispatch\n * refuted the \"needs a new vault-resident registry\" premise: the descriptor\n * is already in hand at both call sites, so `snapshotFor` just needs to\n * ACCEPT it). Takes the full `descriptor` (not a bare dimension name) so it\n * can route the matrix tier's `key` field, which — unlike reserved tier's\n * hardcoded `'id'` — varies per collection. Routes on `descriptor.backing`:\n *\n * - **reserved**: rows come straight from the SAME `LookupHandle.\n * snapshotEntries()` write-through cache `dictLabelResolver`/\n * `resolveDictSource` already read (no second copy), keyed by each\n * entry's own canonical `key` (always `'id'` by construction for this\n * tier — `dict()`'s factory hardcodes it).\n * - **collection** (matrix): rows come from `getCollection(dimension).\n * querySourceForJoin().snapshot()` — the SAME sync, already-live cache\n * `buildLookupAltIndex`'s matrix branch (above, this file) and `.join()`\n * itself already read — re-keyed via `resolveBackingRowKey(descriptor, row)`,\n * NOT the row's own PUT-id (which may differ when `key !== 'id'`; the exact\n * distinction the #650 Task 3 review fix already applies to\n * `checkLookupMembership`'s matrix branch). A row whose `descriptor.key`\n * field coerces to `undefined` is skipped (#651 Task 3, dm12).\n * - **static**: never routed here — `descriptor.table` is read directly by\n * the caller (`binding.ts`'s `compareLookupOrder`/`resolveLookupOrderLabel`,\n * `snapshot.ts`'s `presentLookupForJoin`); no vault call needed.\n *\n * `isReservedDimension` is the vault's `reservedLookupCollections`\n * membership test.\n */\nexport function buildLookupSnapshotRows(\n descriptor: LookupDescriptor,\n isReservedDimension: (dimension: string) => boolean,\n getDictionary: (dimension: string) => LookupHandle,\n getCollection: (dimension: string) => { querySourceForJoin(): JoinableSource },\n): ReadonlyMap<string, Record<string, unknown>> | undefined {\n const dimension = descriptor.dimension\n if (isReservedDimension(dimension)) {\n const rows = new Map<string, Record<string, unknown>>()\n for (const entry of getDictionary(dimension).snapshotEntries()) {\n const key = entry['key']\n if (typeof key === 'string') rows.set(key, entry)\n }\n return rows\n }\n if (descriptor.backing === 'collection') {\n const rawRows = getCollection(dimension).querySourceForJoin().snapshot()\n const rows = new Map<string, Record<string, unknown>>()\n for (const r of rawRows) {\n const row = r as Record<string, unknown>\n const key = resolveBackingRowKey(descriptor, row)\n if (key !== undefined) rows.set(key, row)\n }\n return rows\n }\n return undefined\n}\n","/**\n * The sync lookup snapshot + join/locale seam (#650 Task 6, spec §5 — \"the\n * snapshot+locale seam\"). Retires the #626 kernel→via grandfather:\n * `kernel/query/join.ts` no longer imports `via/i18n/core.js` directly\n * — it calls the `presentForJoin` hook this file's `buildPresentForJoin`\n * builds instead (seam map Part 2 item 4, the #626 reviewer-spec'd shape:\n * a sync `presentI18nForJoin`-class hook on `JoinableSource`).\n *\n * `LookupSnapshot` is the sync materialized `key -> row` view over ONE\n * lookup dimension's ALREADY-LIVE backing data (the `active.ts`\n * `_syncCache`/`snapshotEntries` write-through-cache pattern — never a\n * second copy of the data: `LookupViaConfig.snapshotFor`'s vault-built\n * closure reads the SAME `LookupHandle._syncCache` /\n * first-class-collection cache every other lookup consumer\n * (`dictLabelResolver`, `resolveDictSource`, `getAltIndex`) already reads).\n * Serves (reserved AND matrix tier since #650 Task 7 — `registry.ts`'s\n * `buildLookupSnapshotRows` routes both; static tier is read straight off\n * `descriptor.table` by every consumer below, never through this cache):\n * - join dressing (`presentForJoin`, consumed by `kernel/query/join.ts`\n * via `JoinableSource.presentForJoin`)\n * - dimension sort (`compareForOrder`, consumed by\n * `via/lookup/binding.ts`'s `NoydbVia.compareForOrder` closure)\n * - per-call-locale order-label resolution (`resolveOrderLabel`, #650\n * Task 7 — the `orderBy(..., {by:'label'})` channel `compareForOrder`\n * structurally can't serve, no locale param; consumed by\n * `kernel/query/builder.ts`'s `buildOrderLabelMaps`)\n * - membership: reserved/static-tier membership (#650 Task 3,\n * `checkLookupMembership`) already reads the identical sync caches\n * directly — not re-plumbed through this file; see\n * `.superpowers/sdd/task-6-report.md`'s \"bridge disposition\" section.\n *\n * Sync end-to-end (#553) — every function here is a pure, synchronous\n * transform over already-materialized rows; no store read, no Promise.\n */\nimport type { LookupDescriptor } from './descriptor.js'\nimport { presentI18nForJoin, type I18nTextDescriptor } from '../i18n/core.js'\n\n/** A lookup dimension's sync materialized view — see file header. */\nexport interface LookupSnapshot {\n /** The full backing row for `key`, or `undefined` when `key` isn't (yet) present in the snapshot. */\n row(key: string): Record<string, unknown> | undefined\n /** The dimension's declared presentation label for `key` at `locale` — mirrors `binding.ts`'s `fetchLookupLabel` (matrix-row branch), generalized to any tier's already-materialized rows. */\n label(key: string, locale: string, fallback?: unknown): string | undefined\n /**\n * Exact ordering for two canonical keys against `descriptor.sortBy`\n * (falls back to `present.label`, then to the raw keys) at `locale`.\n * Never throws — degrades to comparing the raw keys when no sortable\n * value resolves for either side.\n */\n compareKeys(a: string, b: string, locale: string): number\n}\n\n/** Read one row field, resolving a `by`-keyed (locale-map) value when `by` is declared. */\nfunction readRowField(\n row: Record<string, unknown> | undefined,\n field: string | undefined,\n by: string | undefined,\n locale: string,\n fallback?: unknown,\n): string | undefined {\n if (!row || field === undefined) return undefined\n const raw = row[field]\n if (by === undefined) return typeof raw === 'string' ? raw : undefined\n if (!raw || typeof raw !== 'object') return undefined\n const map = raw as Record<string, unknown>\n const val = map[locale]\n if (typeof val === 'string') return val\n if (typeof fallback === 'string' && typeof map[fallback] === 'string') return map[fallback]\n return undefined\n}\n\n/**\n * Build a sync `LookupSnapshot` over one dimension's already-materialized\n * rows (canonical-key -> row, the SAME keying `materializeBackingTable`\n * (`registry.ts`, #650 Task 3) uses). Pure — never reads a store.\n */\nexport function buildLookupSnapshot(\n dimension: string,\n rows: ReadonlyMap<string, Record<string, unknown>>,\n descriptor: LookupDescriptor,\n): LookupSnapshot {\n void dimension // identity only — kept for parity with materializeBackingTable/buildLookupAltIndex's signature and future diagnostics\n return {\n row: (key) => rows.get(key),\n label: (key, locale, fallback) =>\n readRowField(rows.get(key), descriptor.present?.label, descriptor.present?.by, locale, fallback),\n compareKeys: (a, b, locale) => {\n const sortField = descriptor.sortBy ?? descriptor.present?.label\n const av = readRowField(rows.get(a), sortField, descriptor.present?.by, locale) ?? a\n const bv = readRowField(rows.get(b), sortField, descriptor.present?.by, locale) ?? b\n return av < bv ? -1 : av > bv ? 1 : 0\n },\n }\n}\n\n/**\n * The lookup-label HALF of `presentForJoin` (#626 retirement, spec §5;\n * matrix-tier coverage added #650 Task 7) — resolves `<field>Label` for\n * every declared lookup field with a `present` dressing dimension, sync,\n * from `getSnapshotRows` (the vault-built `LookupViaConfig.snapshotFor`\n * closure — now descriptor-routed, see `registry.ts`'s\n * `buildLookupSnapshotRows`; static tier reads its own in-config `table`\n * directly, no vault call — never `undefined` for a declared static table).\n * Mirrors `binding.ts`'s `runLookupPresent` (the async `present()` hook)\n * minus the array/`[].`-wildcard handling that hook needs for full-record\n * reads — join dressing only ever sees the joined RIGHT-side record's\n * scalar fields, so that complexity doesn't apply here.\n */\nfunction presentLookupForJoin(\n record: Record<string, unknown>,\n locale: string,\n lookupFields: Record<string, LookupDescriptor>,\n getSnapshotRows: (descriptor: LookupDescriptor) => ReadonlyMap<string, Record<string, unknown>> | undefined,\n): Record<string, unknown> {\n let result = record\n for (const [field, desc] of Object.entries(lookupFields)) {\n if (desc.present === undefined) continue\n const raw = record[field]\n if (typeof raw !== 'string') continue\n const rows = desc.backing === 'static'\n ? (desc.table ? new Map(Object.entries(desc.table)) : undefined)\n : getSnapshotRows(desc)\n if (!rows) continue\n const label = buildLookupSnapshot(desc.dimension, rows, desc).label(raw, locale)\n if (label === undefined) continue\n if (result === record) result = { ...record }\n result[`${field}Label`] = label\n }\n return result\n}\n\n/**\n * Build the combined sync `presentForJoin(record, locale)` hook a\n * `Collection` attaches to the `JoinableSource` it exposes\n * (`querySourceForJoin()`) — the i18n-text half (`presentI18nForJoin`, the\n * exact `applyI18nLocale(..., 'join')` partial application\n * `kernel/query/join.ts` used to call directly, #626) composed with the\n * lookup-label half above. `undefined` when the collection declares\n * neither — `JoinableSource.presentForJoin` then stays unset, matching\n * today's `i18nFields`-absent behavior exactly (#626 parity lock).\n */\nexport function buildPresentForJoin(\n i18nFields: Record<string, I18nTextDescriptor> | undefined,\n lookupFields: Record<string, LookupDescriptor> | undefined,\n getSnapshotRows: ((descriptor: LookupDescriptor) => ReadonlyMap<string, Record<string, unknown>> | undefined) | undefined,\n): ((record: unknown, locale: string) => unknown) | undefined {\n const hasI18n = i18nFields !== undefined && Object.keys(i18nFields).length > 0\n const hasLookup = lookupFields !== undefined && Object.keys(lookupFields).length > 0\n if (!hasI18n && !hasLookup) return undefined\n const resolveRows = getSnapshotRows ?? (() => undefined)\n return (record, locale) => {\n if (record === null || typeof record !== 'object') return record\n let result = record as Record<string, unknown>\n if (hasI18n) result = presentI18nForJoin(result, i18nFields, locale)\n if (hasLookup) result = presentLookupForJoin(result, locale, lookupFields, resolveRows)\n return result\n }\n}\n","/**\n * Lookup strategy seam (#650 Task 1 — via-lookup extraction, phase D of the\n * Via port; precedent: `port/with/i18n-strategy.ts`). Lives on the `/with`\n * port (the one seam the kernel spine may import statically) so `Vault` can\n * reach the dict-registry pure helpers and the `LookupHandle`/`NO_LOOKUP`\n * types without a spine→`via/` static import (Check 14 via-layering bans\n * that; `port/with/` is always allowed, Check 9's sanctioned exception).\n *\n * `kernel/vault.ts` imports ONLY this module for lookup — never\n * `via/lookup/*` directly.\n *\n * This task (#650 Task 1) is a pure move: `Vault.dictionary()` still\n * constructs its handle through `i18nStrategy.buildDictionaryHandle`\n * (`port/with/i18n-strategy.ts`), which now internally delegates to\n * `withLookup().buildLookupHandle` (same handle, new home). `LookupStrategy`\n * / `NO_LOOKUP` / `isLookupCollectionName` here are the seam later phase-D\n * tasks bind `vault.collection()`'s lookup fields onto — unused by Task 1's\n * wiring, but their exact shapes are frozen now so later tasks don't\n * re-litigate them.\n */\n\nimport type { NoydbStore, EncryptedEnvelope } from '../../kernel/types.js'\nimport type { LedgerStore } from '../../with-commit/history/ledger/store.js'\nimport type { UnlockedKeyring } from '../../with-party/team/keyring.js'\nimport type { NoydbEventEmitter } from '../../kernel/events.js'\nimport type { ViaCryptoCtx } from '../../kernel/via/index.js'\nimport type { LookupHandle, DictionaryOptions } from '../../via/lookup/handle.js'\nimport {\n enforceStaticDictOnPut,\n resolveDictSource,\n updateReferencingRecords,\n resolveLabelFromMap,\n collectLookupDictCompat,\n lookupToStaticDictCompat,\n reservedDictDepsOf,\n materializeBackingTable,\n checkLookupMembership,\n buildLookupAltIndex,\n registerLookupRefEdges,\n buildLookupSnapshotRows,\n coerceLookupKey,\n resolveBackingRowKey,\n matchesReferencingValue,\n type DictReferencingCollection,\n type LookupDictCompat,\n type MaterializedBacking,\n} from '../../via/lookup/registry.js'\nimport { buildPresentForJoin } from '../../via/lookup/snapshot.js'\nimport type { LookupDescriptor } from '../../via/lookup/descriptor.js'\n\n/**\n * Backing options for `LookupStrategy.buildLookupHandle` — same shape as\n * `DictionaryOptions` (kept as a distinct alias since the \"lookup\" name is\n * the forward-looking one; `DictionaryOptions` stays the dict-tier name).\n */\nexport type LookupBackingOptions = DictionaryOptions\n\n/**\n * Options accepted by `LookupStrategy.buildLookupHandle`. Mirrors the\n * `LookupHandle` constructor verbatim, plus the two choke-point\n * participation hooks (`onDirty`/`onRecordMutated`) #647 (Task 4) wires —\n * both `undefined` in this task (pure move, no new call sites).\n */\nexport interface BuildLookupHandleOptions<Keys extends string = string> {\n readonly adapter: NoydbStore\n readonly compartmentName: string\n readonly dimensionName: string\n readonly keyring: UnlockedKeyring\n /**\n * The `reservedEnvelopes('_dict_')` capability (#629 Task 4) — the\n * handle's sanctioned crypto door onto its `_dict_<name>` collection.\n * Bound by the Vault to its own `getDEK`, the same per-collection-name\n * DEK resolver every other collection uses.\n */\n readonly reservedEnvelopes: ReturnType<ViaCryptoCtx['reservedEnvelopes']>\n readonly encrypted: boolean\n readonly ledger: LedgerStore | undefined\n readonly options: LookupBackingOptions\n readonly findAndUpdateReferences:\n | ((dimension: string, oldKey: string, newKey: string) => Promise<void>)\n | undefined\n readonly emitter: NoydbEventEmitter\n /**\n * #647 fix wave 1 — mints a version-ordered delete-marker envelope. Bound by the Vault to the\n * real `kernel/enclave` `buildDeleteMarker` function — `LookupHandle` (`via/lookup/**`)\n * may not import `kernel/enclave/` itself (Check 11/15), so this capability is injected the\n * same way `reservedEnvelopes` above is.\n */\n readonly buildDeleteMarker: (identity: { collection: string; id: string }, version: number, actor: string) => EncryptedEnvelope\n /** #650 Task 4 (#647) — choke-point participation hooks. */\n readonly onDirty?: ((collection: string, id: string, action: 'put' | 'delete', version: number) => Promise<void>) | undefined\n readonly onRecordMutated?: ((collection: string, id: string, action: 'put' | 'delete', version: number) => Promise<void>) | undefined\n /**\n * #650 Task 5 (#648) — the real reference check `LookupHandle.delete()`'s strict branch calls:\n * restrict throws `DictKeyInUseError` naming the referencing collection, cascade/nullify apply\n * their propagation. Bound by the Vault (never a `Collection`/keyring/DEK reach-around); a\n * no-op when the dimension has no declared lookup-referencing edges (today's dangling behavior\n * for undeclared refs is unaffected). Return value is discarded by the handle — callers who\n * need cascade/nullify counts (forget) go through `VaultLinks` directly.\n */\n readonly checkReferencesOnDelete?: ((key: string) => Promise<unknown>) | undefined\n /**\n * Used by the active strategy to satisfy the generic-key parameter on the\n * returned handle. The NO_LOOKUP stub never reads it. Mirrors\n * `BuildDictionaryHandleOptions._keyMarker` (`port/with/i18n-strategy.ts`).\n */\n // marker generic — runtime sees no value\n _keyMarker?: Keys\n}\n\nexport interface LookupStrategy {\n /**\n * Construct a typed `LookupHandle` for the named dimension. Throws under\n * `NO_LOOKUP`.\n */\n buildLookupHandle<Keys extends string = string>(\n opts: BuildLookupHandleOptions<Keys>,\n ): LookupHandle<Keys>\n}\n\nfunction notEnabled(op: string): Error {\n return new Error(\n `${op}: the NO_LOOKUP stub was reached, which should be unreachable today — there is no ` +\n '`lookupStrategy` `createNoydb({ ... })` option yet to select this stub over the real one; ' +\n '`vault.dictionary()` always resolves through `withLookup()` (see `via/i18n/active.ts`\\'s ' +\n 'delegation). This is forward scaffolding for a later task (mirrors `NO_I18N`\\'s shape) — if you ' +\n 'hit this, it indicates a bug, not a missing opt-in.',\n )\n}\n\n/**\n * No-lookup stub. Mirrors `NO_I18N.buildDictionaryHandle`'s shape, but unlike `NO_I18N` (wired as\n * `vault.ts`'s `opts.i18nStrategy ?? NO_I18N` default), nothing selects this stub today — there is\n * no `lookupStrategy` option on `createNoydb()`; `vault.dictionary()`'s only construction path\n * (`Vault.i18nStrategy.buildDictionaryHandle` → `withLookup().buildLookupHandle`) never reaches\n * here. Kept as forward scaffolding for a later task that wires an independent lookup opt-in.\n */\nexport const NO_LOOKUP: LookupStrategy = {\n buildLookupHandle() {\n throw notEnabled('vault.dictionary()')\n },\n}\n\n/** `_dict_*` (legacy dict tier) and `_lookup_*` (the phase-D reserved backing). */\nexport const LOOKUP_COLLECTION_PREFIXES = ['_dict_', '_lookup_'] as const\n\n/** Return true when a collection name is a reserved lookup-backing collection. */\nexport function isLookupCollectionName(name: string): boolean {\n return LOOKUP_COLLECTION_PREFIXES.some((prefix) => name.startsWith(prefix))\n}\n\n// Re-exported pure registry helpers (#650 Task 1) — `kernel/vault.ts`'s\n// thin delegators call these directly; small always-on functions, not\n// behind the tree-shake seam (same bundling class as `isLookupCollectionName`\n// above, just too large to duplicate inline like that one is).\nexport { enforceStaticDictOnPut, resolveDictSource, updateReferencingRecords }\nexport type { DictReferencingCollection }\n\n// #650 Task 4 (#647) — the reserved-collection naming helper `vault.ts`'s sync-registry\n// bookkeeping needs (mapping a declared dimension name to its `_dict_<name>` collection name).\nexport { dictCollectionName } from '../../via/lookup/handle.js'\n\n// #650 Task 2 — the alias-equivalence bridge (`resolveLabelFromMap` +\n// `collectLookupDictCompat`/`lookupToStaticDictCompat`) + the runtime\n// brand/shape predicates `via/compose.ts` needs to route `'lookup'`-branded\n// descriptors, mirroring `isI18nTextDescriptor`/`isDictKeyDescriptor` below.\nexport { resolveLabelFromMap, collectLookupDictCompat, lookupToStaticDictCompat }\nexport type { LookupDictCompat }\n\n// #653 — partial-sync reserved-dict expansion: maps a set of named collections to the\n// one-hop `_dict_*` deps their lookup fields reference, off `dictKeyFieldRegistry`.\nexport { reservedDictDepsOf }\n\n// #650 Task 3 — altKeys ingest normalization + open/closed vocabulary\n// governance: the declare/warm-time altIndex builder + the membership test\n// vault.ts's `membership`/`getAltIndex` closures delegate to.\nexport { materializeBackingTable, checkLookupMembership, buildLookupAltIndex }\nexport type { MaterializedBacking }\n\n// #650 Task 5 — registers a collection's lookup-fields' cross-collection 'ref' graph edges.\nexport { registerLookupRefEdges }\n\n// #650 Task 6 — the sync snapshot+locale seam (#626 retirement, spec §5):\n// `snapshotFor`'s vault-built row source + the combined presentForJoin\n// builder `kernel/collection-config.ts` calls to build the\n// `JoinableSource.presentForJoin` hook `kernel/query/join.ts` consumes.\nexport { buildLookupSnapshotRows, buildPresentForJoin }\nexport type { LookupSnapshot } from '../../via/lookup/snapshot.js'\n\n// #651 Task 3 — the ONE descriptor-keyed key-resolution core (guarded coercion +\n// backing-row-key resolve + referencing-value match) — every consumer (vault.ts,\n// with-shape/links/vault-facade.ts, kernel/via/dispatch.ts) routes through here,\n// never a bare `String()`, ending the dm12 dialect drift.\nexport { coerceLookupKey, resolveBackingRowKey, matchesReferencingValue }\n\n/** Runtime predicate for detecting a `LookupDescriptor` (any of the three tiers). */\nexport function isLookupDescriptor(x: unknown): x is LookupDescriptor {\n return (\n typeof x === 'object' &&\n x !== null &&\n (x as { _viaBrand?: unknown })._viaBrand === 'lookup'\n )\n}\n\n/** Runtime predicate for the bare enum tier (`backing:'static'`, no in-code `table` — no label source). */\nexport function isEnumDescriptor(x: unknown): x is LookupDescriptor {\n return isLookupDescriptor(x) && x.backing === 'static' && x.table === undefined\n}\n\n/**\n * Type-only re-exports — the kernel spine imports these descriptor/handle\n * types through the port instead of reaching into `via/lookup/*` or\n * `via/i18n/*` directly. `isolatedModules: true` erases these at\n * build time — no runtime coupling.\n */\nexport type { LookupHandle, DictEntry, DictionaryOptions } from '../../via/lookup/handle.js'\nexport type { LookupDescriptor, Vocabulary, LookupBacking, OnDelete } from '../../via/lookup/descriptor.js'\nexport type { LookupViaConfig } from '../../via/lookup/binding.js'\nexport type { DictKeyDescriptor, StaticDictDescriptor } from '../../via/i18n/dictionary.js'\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/kernel/via/index.ts"],"sourcesContent":["// kernel/via/index.ts — the ONLY kernel-resident via surface.\nimport { NoydbError } from '../errors.js'\nimport type { EncryptedEnvelope } from '../types.js'\n\n/** Awaitable type for potentially async results. */\ntype Awaitable<T> = T | Promise<T>\n\n/** Declared security posture — a property the kernel enforces (enforcement activates in phases B/C). */\nexport interface ViaPosture {\n readonly encryptedAtRest: 'envelope' | 'sealed'\n readonly queryable: 'none' | 'det-exact' | 'ordered' | 'full'\n readonly exportable: boolean\n readonly forgettable: boolean\n}\n\n/** Opaque marker every feature descriptor extends; the kernel never sees concrete descriptor types. */\nexport interface ViaDescriptor { readonly _viaBrand: string }\n\n/** Per-call write context (A: minimal; B/C extend). */\nexport interface ViaWriteCtx {\n readonly id: string\n /** Owning vault name (event payload identity — e.g. i18n:script-violation). */\n readonly vault: string\n /** Prior stored record (decoded), lazily resolved. Null when creating. */\n readonly prior: () => Promise<Record<string, unknown> | null>\n /** Typed event emission (e.g. i18n:script-violation). */\n readonly emit: (event: string, payload: unknown) => void\n}\n\n/** Per-call read context — mirrors LocaleReadOptions loosely; features narrow. */\nexport interface ViaReadCtx {\n readonly locale?: unknown\n readonly fallback?: unknown\n readonly layer: string\n}\n\n/** One sealed slot's ciphertext — matches the existing `iv:data` sealed map entries (seam map §2 step 2). */\nexport interface SealedSlotRef { readonly iv: string; readonly data: string }\n\n/**\n * A scoped crypto capability handed to a `via` feature's `encodeAtRest`/\n * `decodeAtRest`/`erase` hooks — never the keyring, never the enclave.\n * `sealedSlots` is pre-bound to one `(collection, recordId)`; `reservedEnvelopes`\n * is a whole-envelope encrypt/decrypt door scoped to collection names under a\n * declared prefix (e.g. `_dict_`).\n */\nexport interface ViaCryptoCtx {\n readonly sealedSlots: {\n seal(field: string, plaintext: unknown): Promise<SealedSlotRef>\n unseal(field: string, ref: SealedSlotRef): Promise<unknown>\n delete(field: string): Promise<void>\n }\n reservedEnvelopes(prefix: string): {\n /**\n * `id` is the record id the envelope will be stored under. Required\n * (#1051) because this function holds the DEK, so it is where record-identity\n * AAD is applied — a caller that cannot name the id cannot be bound.\n */\n encrypt(\n identity: { readonly collection: string; readonly id: string; readonly by?: string },\n json: string,\n v: number,\n ): Promise<EncryptedEnvelope>\n decrypt(collection: string, id: string, env: EncryptedEnvelope): Promise<string>\n }\n}\n\n/** Per-call erase context — `forget()`'s per-ref participation door (phase C). */\nexport interface ViaEraseCtx { readonly id: string; readonly vault: string; readonly live: unknown /* EncryptedEnvelope */; readonly crypto: ViaCryptoCtx }\n/**\n * What an `erase` hook reports back to `forget()`'s summary ledger entry.\n * `retainedShared` is additive (#629 Task 10) — content NOT erased because\n * still referenced by another live record (blob's shared-chunk dual\n * accounting, `shredAllForRecord()`'s `retainedShared` count). Absent/0 for\n * bindings with no such concept (a sealed field is never \"shared\").\n */\nexport interface ViaEraseReport { readonly shredded: number; readonly residue: readonly unknown[]; readonly retainedShared?: number }\n\n/**\n * A feature bound to one collection's declared config. Record-grain hooks —\n * every hook receives the whole record (matches the real engine signatures,\n * e.g. quantizeMoneyFields(record, moneyFields)). All hooks optional;\n * absent = passthrough. Query-participation hooks are SYNC (#553).\n */\nexport interface NoydbVia {\n readonly brand: string\n readonly posture: ViaPosture\n /** Declared dependencies (field paths / cross-record specs). MANDATORY for any future\n * derive-bearing binding — phase C validates well-formedness (strings, non-empty,\n * reference declared fields) and graph-registers a derived edge for each covered\n * field at declare time, right after `compileVias` builds the bindings\n * (unknown source field throws `ValidationError`). See\n * `kernel/collection-config.ts`'s `resolveViaDepsEdges`. */\n readonly deps?: readonly string[]\n /** Collection-name prefixes this binding's `reservedEnvelopes` capability may address (e.g. `_dict_`). */\n readonly reservedPrefixes?: readonly string[]\n /**\n * Does this binding own `field`? Backs `ViaPipeline.postureFor` (#629 Task\n * 8's posture consumer) — a passive coverage check, independent of\n * `buildClause`/`compareForOrder` (which some bindings, e.g. classified and\n * blob, never define). SYNC, no side effects.\n *\n * Contract (documentation only — not enforced at runtime, future work):\n * any binding declaring a non-default posture value — `queryable: 'none'`\n * (#629 Task 8) or `exportable: false` (#629 Task 9's `redactForExport`)\n * — MUST implement `covers()`. `postureFor`'s consumers only engage for\n * fields a binding actively claims via `covers()`; a binding that omits\n * it would silently fall through to the generic (unrefused/unredacted)\n * path instead.\n */\n covers?(field: string): boolean\n // NOTE: phase C adds a `derive` hook ADDITIVELY — do not stub it now.\n // ── write pipeline ──\n /** Refuse a write before crypto runs (classified step-3 slot: storage:'never' rejection + validators). Throws to refuse. */\n enforceWrite?(record: Record<string, unknown>, ctx: ViaWriteCtx): void | Promise<void>\n /** First pipeline stage (money canonicalizeIncomingMoney). SYNC. */\n ingest?(record: Record<string, unknown>): Record<string, unknown>\n /** Decode STORED form to canonical for internal boundaries (gates, derivations, patch bases). SYNC. */\n canonicalizeStored?(record: Record<string, unknown>): Record<string, unknown>\n /** Post-validation write encoding (money quantize; i18n translate→script→validate→densify). May be async. */\n encodeWrite?(record: Record<string, unknown>, ctx: ViaWriteCtx): Awaitable<Record<string, unknown>>\n /** Final write-pipeline stage: seal/encrypt declared fields via `crypto` before the envelope body is built (classified step-2 slot). */\n encodeAtRest?(record: Record<string, unknown>, crypto: ViaCryptoCtx): Promise<{ record: Record<string, unknown>; sealed?: Record<string, SealedSlotRef> }>\n // ── read pipeline ──\n /** First read-pipeline stage: unseal/decrypt declared fields via `crypto` before `present` runs (classified sealed-handle slot). */\n decodeAtRest?(record: Record<string, unknown>, sealed: Record<string, SealedSlotRef>, crypto: ViaCryptoCtx, opts: { asHandles: boolean }): Promise<Record<string, unknown>>\n /** Read-time presentation (money decode+virtuals; i18n locale/labels/strip). May be async. */\n present?(record: Record<string, unknown>, ctx: ViaReadCtx): Awaitable<Record<string, unknown>>\n /**\n * Late read-time presentation (#669) — runs AFTER every binding's `present()` in the\n * money+computed present-order segment (`ViaPipeline`'s `_presentOrder`, `kernel/via/\n * pipeline.ts`), BEFORE the \"everything else\" segment (i18n/lookup dressing, taint\n * redaction) runs. Exists for a binding that needs to react to a virtual computed\n * field's fresh OWN-field output before anything dresses it (money's MAJOR-UNITS\n * quantize-and-present for a field that is BOTH money AND `mode:'virtual'` computed) —\n * `present()` alone can't express \"run after computed for THESE fields only, before\n * computed for all others\", since it's a per-BINDING fold, not per-field. Folded over\n * `bindings` in declaration order (mirrors every other per-binding fold), so lookup/\n * i18n dressing and taint/redaction (both in the \"everything else\" segment) still see\n * the already-dressed value.\n */\n presentLate?(record: Record<string, unknown>, ctx: ViaReadCtx): Awaitable<Record<string, unknown>>\n // ── query participation (ALL SYNC — #553) ──\n /** Returns an opaque clause payload when this binding covers `field`, else undefined. */\n // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents\n buildClause?(field: string, op: string, value: unknown): unknown | undefined\n /** Evaluate a payload produced by buildClause against a raw stored value. */\n evaluateClause?(actual: unknown, op: string, payload: unknown): boolean\n /**\n * Optional: the STORED-form operand for a direct secondary-index probe\n * against a payload produced by `buildClause` (#625) — lets\n * `candidateRecords()` (`query/builder.ts`) hit `CollectionIndexes.\n * lookupEqual`/`lookupIn` for `==`/`in` clauses instead of falling back\n * to a linear scan + per-record `evaluateClause`. Returning `undefined`\n * means \"no sound probe for this op/payload\" (e.g. a comparison whose\n * stored form isn't a single index-bucketable value, or an op the index\n * can't serve) — the caller falls back to the scan. A binding that\n * never implements this hook always falls back, unchanged from before\n * this hook existed.\n */\n // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents\n indexProbe?(op: string, payload: unknown): unknown | undefined\n /**\n * Optional: canonicalize a raw STORED field value into the bucket key an\n * eager index should use (#672) — lets `CollectionIndexes` group a\n * pre-declaration / non-canonical stored value (e.g. a money field's\n * leftover `'0100'` written before its `money()` declaration) under the\n * SAME key a canonical write produces (`'100'`), so the index-probe fast\n * path (`indexProbe` above) and the fallback scan (`evaluateClause`)\n * agree on which records match. `undefined` means \"not mine / can't\n * canonicalize this value\" — the caller buckets the raw stringified\n * value, unchanged from before this hook existed. MUST agree with what\n * this binding's own `evaluateClause`/`indexProbe` treat as equal, or\n * the fast path and the scan will disagree.\n */\n canonicalizeIndexKey?(field: string, rawValue: unknown): string | undefined\n /** Decode a raw stored record for query/scan results and callback views ('raw' — no virtuals). */\n decodeResults?(record: unknown): unknown\n /** Exact ordering for a covered field; undefined when the field is not covered. */\n compareForOrder?(field: string, a: unknown, b: unknown): number | undefined\n /**\n * Per-key, PER-CALL-locale label resolution for `orderBy(field, dir,\n * { by: 'label' })` (#650 Task 7) — the sibling `compareForOrder` above\n * structurally cannot serve, since it carries no locale parameter.\n * `locale` is the query's per-call locale (`undefined` for a locale-less\n * query — a binding may fall back to its own descriptor-level default,\n * mirroring `present`'s displayLocale hinge). `undefined` return = this\n * binding doesn't resolve a label for `key` at `field` — caller falls\n * back to the raw stored value, same graceful-degrade discipline every\n * other via query hook uses. SYNC (#553 — query participation).\n */\n resolveOrderLabel?(field: string, key: string, locale: string | undefined): string | undefined\n /** Rewrite an aggregate spec (money exact reducers). */\n wrapReducers?(spec: unknown): unknown\n // ── forget participation ──\n /** `forget()`'s per-ref erasure door — shred/report this binding's residue for one record (classified/blob forget participation). */\n erase?(ctx: ViaEraseCtx): Promise<ViaEraseReport>\n // ── introspection ──\n describeFragment?(): Record<string, unknown>\n}\n\n/** Binder: constructs a binding from a collection's declared config. Installed by the feature's declaration factory. */\nexport type ViaBinder = (config: unknown) => NoydbVia\n\nconst binders = new Map<string, ViaBinder>()\n\n/** @internal — called (idempotently, first-wins) by a feature's declaration factory, e.g. money(). */\nexport function installViaBinder(brand: string, binder: ViaBinder): void {\n if (!binders.has(brand)) binders.set(brand, binder)\n}\n\n/** @internal — registry presence check. Used by tests (mirrors isMoneyEngineInstalled) and by vault's i18n validator delegators as a no-i18n-ever-declared fast path. */\nexport function isViaInstalled(brand: string): boolean {\n return binders.has(brand)\n}\n\n/** @internal — resolve a binder; throws when the declaration factory never ran (hand-rolled descriptors). */\nexport function viaBinder(brand: string): ViaBinder {\n const b = binders.get(brand)\n if (!b) {\n throw new NoydbError(\n 'VIA_NOT_LINKED',\n `via feature \"${brand}\" requires descriptors created via its declaration factory from @noy-db/hub`,\n )\n }\n return b\n}\n"],"mappings":";;;;;AA4MA,IAAM,UAAU,oBAAI,IAAuB;AAGpC,SAAS,iBAAiB,OAAe,QAAyB;AACvE,MAAI,CAAC,QAAQ,IAAI,KAAK,EAAG,SAAQ,IAAI,OAAO,MAAM;AACpD;AAGO,SAAS,eAAe,OAAwB;AACrD,SAAO,QAAQ,IAAI,KAAK;AAC1B;AAGO,SAAS,UAAU,OAA0B;AAClD,QAAM,IAAI,QAAQ,IAAI,KAAK;AAC3B,MAAI,CAAC,GAAG;AACN,UAAM,IAAI;AAAA,MACR;AAAA,MACA,gBAAgB,KAAK;AAAA,IACvB;AAAA,EACF;AACA,SAAO;AACT;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/with-lookup/search/tokenize.ts","../src/with-lookup/search/scan.ts","../src/with-lookup/search/segment.ts","../src/with-lookup/search/inverted-index.ts","../src/with-lookup/search/snippet.ts","../src/with-lookup/search/index-store.ts","../src/with-lookup/search/build-docs.ts","../src/with-lookup/search/active.ts","../src/with-lookup/search/strategy.ts"],"sourcesContent":["/**\n * Default text tokenizer for scan-mode search.\n *\n * NFKC-normalize → lowercase → split on Unicode letter/number runs. This is a\n * word-boundary tokenizer: it does **not** segment scripts written without\n * inter-word spaces (Thai, Lao, Khmer, CJK) — those collapse to one token per\n * run. For such data, a dictionary/ICU segmenter is the right `tokenizer`\n * (the engine takes one as a parameter); substring/`contains` matching is the\n * pragmatic fallback until then.\n */\nexport type Tokenizer = (text: string) => string[]\n\nconst WORD = /[\\p{L}\\p{N}]+/gu\n\nexport const tokenize: Tokenizer = (text: string): string[] => {\n if (!text) return []\n return text.normalize('NFKC').toLowerCase().match(WORD) ?? []\n}\n","/**\n * Scan-mode full-text search — ranks **already-decrypted** records by\n * BM25 against a tokenized query. Pure client-side: nothing is written to the\n * store, so this adds **zero** leakage (unlike a store-usable blind index,\n * which is a separate, gated opt-in).\n *\n * O(n) over the collection; intended for small/medium collections (the pilot's\n * scale) where moving the existing userland scan into the DB is the win.\n */\nimport { tokenize, type Tokenizer } from './tokenize.js'\n\nexport interface SearchOptions {\n /** Top-N by score (default: all matches). */\n readonly limit?: number\n /** `'any'` (default) = OR of query terms; `'all'` = every term must match. */\n readonly match?: 'any' | 'all'\n /** Treat the LAST query term as a prefix (typeahead). */\n readonly prefix?: boolean\n}\n\nexport interface SearchResult<T> {\n readonly id: string\n readonly score: number\n readonly record: T\n}\n\nexport interface SearchEntry<T> {\n readonly id: string\n readonly record: T\n}\n\nconst K1 = 1.2\nconst B = 0.75\n\n/** Coerce a field value to searchable text (numbers/booleans stringified). */\nfunction fieldText(record: unknown, field: string): string {\n const v = (record as Record<string, unknown>)[field]\n if (typeof v === 'string') return v\n if (v === null || v === undefined) return ''\n if (typeof v === 'number' || typeof v === 'boolean') return String(v)\n return ''\n}\n\nexport function searchScan<T>(\n entries: ReadonlyArray<SearchEntry<T>>,\n field: string,\n query: string,\n opts: SearchOptions = {},\n tokenizer: Tokenizer = tokenize,\n): SearchResult<T>[] {\n const queryTerms = tokenizer(query)\n if (queryTerms.length === 0) return []\n\n const match = opts.match ?? 'any'\n const usePrefix = opts.prefix ?? false\n const exactTerms = usePrefix ? queryTerms.slice(0, -1) : queryTerms\n const prefixTerm = usePrefix ? queryTerms[queryTerms.length - 1] : undefined\n\n // One tokenize pass per doc; collect corpus stats (df, avg length).\n const docs = entries.map((e) => ({ id: e.id, record: e.record, terms: tokenizer(fieldText(e.record, field)) }))\n const N = docs.length || 1\n const df = new Map<string, number>()\n let totalLen = 0\n for (const d of docs) {\n totalLen += d.terms.length\n for (const t of new Set(d.terms)) df.set(t, (df.get(t) ?? 0) + 1)\n }\n const avgdl = totalLen / N || 1\n\n // Document frequency for the prefix term: docs containing ANY term with it.\n let prefixDf = 0\n if (prefixTerm !== undefined) {\n for (const d of docs) {\n if (d.terms.some((t) => t.startsWith(prefixTerm))) prefixDf++\n }\n }\n\n const requiredCount = exactTerms.length + (prefixTerm !== undefined ? 1 : 0)\n const results: SearchResult<T>[] = []\n\n for (const d of docs) {\n const tf = new Map<string, number>()\n for (const t of d.terms) tf.set(t, (tf.get(t) ?? 0) + 1)\n\n const matched: { tf: number; df: number }[] = []\n for (const qt of exactTerms) {\n const c = tf.get(qt) ?? 0\n if (c > 0) matched.push({ tf: c, df: df.get(qt) ?? 0 })\n }\n if (prefixTerm !== undefined) {\n let ptf = 0\n for (const [t, c] of tf) if (t.startsWith(prefixTerm)) ptf += c\n if (ptf > 0) matched.push({ tf: ptf, df: prefixDf })\n }\n\n if (matched.length === 0) continue\n if (match === 'all' && matched.length < requiredCount) continue\n\n let score = 0\n for (const m of matched) {\n const idf = Math.log(1 + (N - m.df + 0.5) / (m.df + 0.5))\n const denom = m.tf + K1 * (1 - B + B * (d.terms.length / avgdl))\n score += idf * ((m.tf * (K1 + 1)) / (denom || 1))\n }\n results.push({ id: d.id, score, record: d.record })\n }\n\n results.sort((a, b) => b.score - a.score)\n return opts.limit !== undefined ? results.slice(0, opts.limit) : results\n}\n","/**\n * i18n word tokenizer for the L1 lexical index. Uses Intl.Segmenter\n * (standard ECMAScript — hub-portable) to dictionary-segment Thai/Lao/Khmer/CJK,\n * which the word-run `tokenize` cannot. Terms are matched in NFKC-lowercased form;\n * offsets index the ORIGINAL text so snippets slice the user's text.\n */\nimport type { Tokenizer } from './tokenize.js'\n\nconst SEGMENTER = new Intl.Segmenter(undefined, { granularity: 'word' })\n\nexport interface Token {\n readonly term: string\n readonly offset: number\n}\n\n/** Word-like tokens with NFKC-lowercased terms + original-text char offsets. */\nexport const segmentTokens = (text: string): Token[] => {\n const out: Token[] = []\n if (!text) return out\n for (const s of SEGMENTER.segment(text)) {\n if (s.isWordLike) out.push({ term: s.segment.normalize('NFKC').toLowerCase(), offset: s.index })\n }\n return out\n}\n\n/** Term-only tokenizer (the public `Tokenizer` shape) — for queries. */\nexport const segmentTokenizer: Tokenizer = (text: string): string[] =>\n segmentTokens(text).map((t) => t.term)\n","/**\n * In-memory inverted index for the L1 lexical retrieval layer. Built\n * client-side from already-decrypted records; nothing touches the store. BM25\n * mirrors src/search/scan.ts; multi-field with max-field combination so a record\n * ranks by its strongest field, which also supplies the snippet location.\n */\nimport { segmentTokens, segmentTokenizer } from './segment.js'\n\nconst K1 = 1.2\nconst B = 0.75\n\nexport interface IndexDoc {\n readonly id: string\n readonly fields: ReadonlyArray<{ readonly field: string; readonly locale?: string; readonly text: string }>\n}\n\nexport interface IndexHit {\n readonly id: string\n readonly score: number\n readonly field: string\n readonly locale?: string\n readonly text: string\n readonly offset: number\n}\n\nexport interface QueryOptions {\n readonly limit?: number\n readonly match?: 'any' | 'all'\n readonly prefix?: boolean\n readonly fields?: readonly string[]\n}\n\nexport interface IndexSnapshot {\n readonly v: 1\n readonly fieldStats: ReadonlyArray<[string, { df: [string, number][]; n: number; totalLen: number }]>\n readonly docs: ReadonlyArray<{\n id: string; field: string; locale?: string; text: string; len: number\n tf: [string, number][]; firstOffset: [string, number][]\n }>\n}\n\ninterface Doc {\n id: string\n field: string\n locale?: string\n text: string\n len: number\n tf: Map<string, number>\n firstOffset: Map<string, number>\n}\n\nexport class InvertedIndex {\n // per field: df (term -> #docs), N (#docs), totalLen\n private readonly fieldStats = new Map<string, { df: Map<string, number>; n: number; totalLen: number }>()\n private readonly docs: Doc[] = []\n\n static build(docs: ReadonlyArray<IndexDoc>): InvertedIndex {\n const idx = new InvertedIndex()\n for (const d of docs) {\n for (const f of d.fields) {\n const tokens = segmentTokens(f.text)\n const tf = new Map<string, number>()\n const firstOffset = new Map<string, number>()\n for (const t of tokens) {\n tf.set(t.term, (tf.get(t.term) ?? 0) + 1)\n if (!firstOffset.has(t.term)) firstOffset.set(t.term, t.offset)\n }\n const doc: Doc = { id: d.id, field: f.field, ...(f.locale !== undefined ? { locale: f.locale } : {}), text: f.text, len: tokens.length, tf, firstOffset }\n idx.docs.push(doc)\n let s = idx.fieldStats.get(f.field)\n if (!s) { s = { df: new Map(), n: 0, totalLen: 0 }; idx.fieldStats.set(f.field, s) }\n s.n += 1\n s.totalLen += doc.len\n for (const term of tf.keys()) s.df.set(term, (s.df.get(term) ?? 0) + 1)\n }\n }\n return idx\n }\n\n query(query: string, opts: QueryOptions = {}): IndexHit[] {\n const terms = segmentTokenizer(query)\n if (terms.length === 0) return []\n const usePrefix = opts.prefix ?? false\n const exact = usePrefix ? terms.slice(0, -1) : terms\n const prefix = usePrefix ? terms[terms.length - 1] : undefined\n const match = opts.match ?? 'any'\n const required = exact.length + (prefix !== undefined ? 1 : 0)\n\n // best (max-score) doc per record\n const best = new Map<string, IndexHit>()\n for (const doc of this.docs) {\n if (opts.fields !== undefined && !opts.fields.includes(doc.field)) continue\n const stats = this.fieldStats.get(doc.field)!\n const avgdl = stats.totalLen / stats.n || 1\n let score = 0\n let matchedCount = 0\n let snippetOffset = -1\n\n const scoreTerm = (tf: number, df: number, offset: number): void => {\n if (tf <= 0) return\n matchedCount += 1\n if (snippetOffset < 0 && offset >= 0) snippetOffset = offset\n const idf = Math.log(1 + (stats.n - df + 0.5) / (df + 0.5))\n const denom = tf + K1 * (1 - B + B * (doc.len / avgdl))\n score += idf * ((tf * (K1 + 1)) / (denom || 1))\n }\n\n for (const qt of exact) scoreTerm(doc.tf.get(qt) ?? 0, stats.df.get(qt) ?? 0, doc.firstOffset.get(qt) ?? -1)\n\n if (prefix !== undefined) {\n // Build a set of exact query terms so we don't double-count a term that\n // is both an exact match and starts with the prefix (defect 2 fix).\n const exactSet = new Set(exact)\n let ptf = 0\n let poff = -1\n for (const [term, c] of doc.tf) {\n if (term.startsWith(prefix) && !exactSet.has(term)) {\n ptf += c\n if (poff < 0) poff = doc.firstOffset.get(term) ?? -1\n }\n }\n if (ptf > 0) {\n // df for the prefix: count DISTINCT docs in this field that have any\n // prefix-matching term — mirrors scan.ts semantics (defect 1 fix).\n let pdf = 0\n for (const d of this.docs) {\n if (d.field === doc.field && [...d.tf.keys()].some((t) => t.startsWith(prefix))) pdf++\n }\n scoreTerm(ptf, pdf || 1, poff)\n }\n }\n\n if (matchedCount === 0) continue\n if (match === 'all' && matchedCount < required) continue\n\n const hit: IndexHit = {\n id: doc.id, score, field: doc.field, text: doc.text,\n offset: snippetOffset < 0 ? 0 : snippetOffset,\n ...(doc.locale !== undefined ? { locale: doc.locale } : {}),\n }\n const prev = best.get(doc.id)\n if (!prev || hit.score > prev.score) best.set(doc.id, hit)\n }\n\n const results = [...best.values()].sort((a, b) => b.score - a.score)\n return opts.limit !== undefined ? results.slice(0, opts.limit) : results\n }\n\n toSnapshot(): IndexSnapshot {\n return {\n v: 1,\n fieldStats: [...this.fieldStats].map(([f, s]) => [f, { df: [...s.df], n: s.n, totalLen: s.totalLen }]),\n docs: this.docs.map((d) => ({\n id: d.id, field: d.field, text: d.text, len: d.len,\n tf: [...d.tf], firstOffset: [...d.firstOffset],\n ...(d.locale !== undefined ? { locale: d.locale } : {}),\n })),\n }\n }\n\n static fromSnapshot(s: IndexSnapshot): InvertedIndex {\n const idx = new InvertedIndex()\n for (const [f, st] of s.fieldStats) idx.fieldStats.set(f, { df: new Map(st.df), n: st.n, totalLen: st.totalLen })\n for (const d of s.docs) {\n idx.docs.push({\n id: d.id, field: d.field, text: d.text, len: d.len,\n tf: new Map(d.tf), firstOffset: new Map(d.firstOffset),\n ...(d.locale !== undefined ? { locale: d.locale } : {}),\n })\n }\n return idx\n }\n}\n","/**\n * Minimal-disclosure snippet: a char-window around a match offset (L1).\n * Unicode-safe (operates on code points). `…` marks each truncated end.\n */\nexport function extractSnippet(text: string, offset: number, window = 80): string {\n const chars = Array.from(text)\n if (chars.length <= window) return text\n // offset is a UTF-16 index into `text`; map to a code-point index.\n const cpOffset = Array.from(text.slice(0, Math.max(0, offset))).length\n const half = Math.floor(window / 2)\n let start = Math.max(0, cpOffset - half)\n const end = Math.min(chars.length, start + window)\n start = Math.max(0, end - window)\n const body = chars.slice(start, end).join('')\n return `${start > 0 ? '…' : ''}${body}${end < chars.length ? '…' : ''}`\n}\n","/**\n * The index persistence seam (L1.5). MemoryIndexStore is session-scoped and\n * lazy; an opaque-blob backend implements the same interface so the\n * collection call-site is unchanged.\n */\nimport { InvertedIndex, type IndexDoc } from './inverted-index.js'\n\nexport interface IndexStore {\n ensureBuilt(build: () => ReadonlyArray<IndexDoc>): Promise<InvertedIndex>\n markDirty(): void\n flush(): Promise<void>\n readonly built: boolean\n}\n\nexport class MemoryIndexStore implements IndexStore {\n private index: InvertedIndex | undefined\n\n get built(): boolean { return this.index !== undefined }\n\n async ensureBuilt(build: () => ReadonlyArray<IndexDoc>): Promise<InvertedIndex> {\n if (this.index === undefined) this.index = InvertedIndex.build(build())\n return this.index\n }\n\n markDirty(): void { this.index = undefined }\n\n async flush(): Promise<void> { /* in-memory: nothing to persist */ }\n}\n","/**\n * Map a decrypted record's configured text fields → IndexDoc field entries\n * (L1). String, i18nText, dictKey, and blob-filename expansion. Uses\n * getAtPath for nested/[]-wildcard paths. Blob filenames are NOT inline on the\n * record — the collection pre-resolves them (one listSlots() per record, the\n * heaviest source) and feeds them to {@link buildBlobFieldEntries}.\n */\nimport { getAtPath } from '../../via/i18n/core.js'\nimport type { I18nTextDescriptor } from '../../via/i18n/core.js'\nimport type { DictKeyDescriptor, StaticDictDescriptor } from '../../via/i18n/dictionary.js'\nimport type { IndexDoc } from './inverted-index.js'\n\n/**\n * One entry in an {@link IndexDoc}'s `fields` array — the return shape of the\n * `build*FieldEntries` helpers. Exported so `@noy-db/hub/search` can name the\n * return type of its own public functions (#843 C1: the subpath's first\n * type-reachability gap).\n */\nexport type FieldEntry = IndexDoc['fields'][number]\n\nexport function buildStringFieldEntries(\n record: Record<string, unknown>,\n textIndexes: readonly string[],\n only?: readonly string[],\n): FieldEntry[] {\n const fields = only ? textIndexes.filter((f) => only.includes(f)) : textIndexes\n const out: FieldEntry[] = []\n for (const field of fields) {\n for (const leaf of getAtPath(record, field)) {\n if (typeof leaf === 'string' && leaf !== '') out.push({ field, text: leaf })\n }\n }\n return out\n}\n\nexport function buildI18nFieldEntries(\n record: Record<string, unknown>,\n i18nFields: Record<string, I18nTextDescriptor>,\n textIndexes: readonly string[],\n only?: readonly string[],\n): FieldEntry[] {\n const fields = (only ? textIndexes.filter((f) => only.includes(f)) : textIndexes).filter((f) => f in i18nFields)\n const out: FieldEntry[] = []\n for (const field of fields) {\n for (const leaf of getAtPath(record, field)) {\n if (!leaf || typeof leaf !== 'object' || Array.isArray(leaf)) continue\n for (const [locale, val] of Object.entries(leaf as Record<string, unknown>)) {\n if (typeof val === 'string' && val !== '') out.push({ field, locale, text: val })\n }\n }\n }\n return out\n}\n\n/** label map: field -> (key -> { locale -> label }). Precomputed in the collection (async for dynamic dicts). */\nexport function buildDictKeyFieldEntries(\n record: Record<string, unknown>,\n dictKeyFields: Record<string, DictKeyDescriptor | StaticDictDescriptor>,\n labelMaps: Map<string, Map<string, Record<string, string>>>,\n textIndexes: readonly string[],\n only?: readonly string[],\n): FieldEntry[] {\n const fields = (only ? textIndexes.filter((f) => only.includes(f)) : textIndexes).filter((f) => f in dictKeyFields)\n const out: FieldEntry[] = []\n for (const field of fields) {\n const map = labelMaps.get(field)\n if (!map) continue\n for (const leaf of getAtPath(record, field)) {\n const keys = typeof leaf === 'string' ? [leaf] : Array.isArray(leaf) ? leaf.filter((k): k is string => typeof k === 'string') : []\n for (const key of keys) {\n const labels = map.get(key)\n if (!labels) continue\n for (const [locale, label] of Object.entries(labels)) {\n if (label !== '') out.push({ field, locale, text: label })\n }\n }\n }\n }\n return out\n}\n\n/**\n * Blob filenames precomputed in the collection (`field -> filenames[]`, from one\n * async `listSlots()` per record — the heaviest source, see {@link buildBlobFieldEntries}'s\n * caller). Bytes are never tokenized; only the slot `filename` is indexed.\n */\nexport function buildBlobFieldEntries(filenamesByField: Map<string, string[]>): FieldEntry[] {\n const out: FieldEntry[] = []\n for (const [field, names] of filenamesByField) {\n for (const name of names) if (name !== '') out.push({ field, text: name })\n }\n return out\n}\n","/**\n * Enable the search / retrieval capability.\n * Pass to `createNoydb({ searchStrategy: withSearch() })` to make a collection's\n * `search` / `retrieve` / `similarTo` / `warmIndex` / `flushIndex` methods live,\n * and to enable the put()-time embedding-vector compute for collections that\n * declare an `embeddings` config. The search/retrieval engine is dynamically\n * imported here, so it stays out of the floor bundle until opted in.\n */\nimport type { SearchStrategy } from './strategy.js'\n\nexport function withSearch(): SearchStrategy {\n return {\n async search(ctx, field, query, opts) {\n const { search } = await import('./collection-facade.js')\n return search(ctx, field, query, opts)\n },\n async retrieve(ctx, query, opts) {\n const { retrieve } = await import('./collection-facade.js')\n return retrieve(ctx, query, opts)\n },\n async similarTo(ctx, vector, opts) {\n const { similarTo } = await import('./collection-facade.js')\n return similarTo(ctx, vector, opts)\n },\n async warmIndex(ctx) {\n const { warmIndex } = await import('./collection-facade.js')\n return warmIndex(ctx)\n },\n async flushIndex(ctx) {\n const { flushIndex } = await import('./collection-facade.js')\n return flushIndex(ctx)\n },\n async embedOnWrite(ctx, id, record, version) {\n const { embedOnWrite } = await import('./collection-facade.js')\n return embedOnWrite(ctx, id, record, version)\n },\n async rebuildEmbeddings(ctx) {\n const { rebuildEmbeddings } = await import('./collection-facade.js')\n return rebuildEmbeddings(ctx)\n },\n }\n}\n","/**\n * Search capability strategy — the on-demand collection-level retrieval\n * operations the `Collection` routes through: scan-mode full-text `search`,\n * unified `retrieve` (lexical | semantic | hybrid), raw-vector `similarTo`, and\n * the lexical-index lifecycle (`warmIndex` / `flushIndex`). The active engine\n * ({@link withSearch}) dynamically imports the search/retrieval facade (keeping\n * it out of the floor bundle); {@link NO_SEARCH} throws.\n *\n * The embedding write-hook (`embedOnWrite`) is paired here too: opting into\n * `withSearch()` enables both the query surface AND the put()-time vector\n * compute — a vector that no gated `similarTo` / semantic `retrieve` could read\n * is dead weight, so embedding compute is not separately gatable. `Collection`\n * always assembles the per-call {@link SearchContext} and delegates here, so an\n * un-opted-in caller hits `NO_SEARCH`'s throw.\n * @internal\n */\nimport type { SearchContext } from './collection-facade.js'\nimport type { SearchOptions, SearchResult } from './index.js'\nimport type { RetrieveOptions, RetrieveHit } from './retrieve-types.js'\nimport { SearchNotEnabledError } from '../../kernel/errors.js'\n\nexport interface SearchStrategy {\n search<T>(ctx: SearchContext<T>, field: string, query: string, opts?: SearchOptions): Promise<SearchResult<T>[]>\n retrieve<T>(ctx: SearchContext<T>, query: string, opts?: RetrieveOptions<T>): Promise<RetrieveHit<T>[]>\n similarTo<T>(ctx: SearchContext<T>, vector: Float32Array, opts?: { k?: number; minScore?: number; includeRecord?: boolean }): Promise<RetrieveHit<T>[]>\n warmIndex<T>(ctx: SearchContext<T>): Promise<void>\n flushIndex<T>(ctx: SearchContext<T>): Promise<void>\n embedOnWrite<T>(ctx: SearchContext<T>, id: string, record: T, version: number): Promise<void>\n rebuildEmbeddings<T>(ctx: SearchContext<T>): Promise<{ rebuilt: number; skipped: number }>\n}\n\n/**\n * No-op stub — the floor default. Every capability method (and the embedding\n * write-hook) throws {@link SearchNotEnabledError}; opt in with\n * `searchStrategy: withSearch()` in createNoydb. @internal\n */\nexport const NO_SEARCH: SearchStrategy = {\n async search() { throw new SearchNotEnabledError() },\n async retrieve() { throw new SearchNotEnabledError() },\n async similarTo() { throw new SearchNotEnabledError() },\n async warmIndex() { throw new SearchNotEnabledError() },\n async flushIndex() { throw new SearchNotEnabledError() },\n async embedOnWrite() { throw new SearchNotEnabledError() },\n async rebuildEmbeddings() { throw new SearchNotEnabledError() },\n}\n"],"mappings":"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","names":["K1","B"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/with-lookup/reduce/strategy.ts"],"sourcesContent":["/**\n * Strategy seam between the core Query / ScanBuilder chain and the\n * optional aggregate / groupBy service. Core imports\n * `ReduceStrategy` as a TYPE-ONLY symbol and `NO_REDUCE` as a\n * tiny runtime stub.\n *\n * The heavy machinery — `Reduction`, `GroupedQuery`, the\n * reducer-step logic — is only reachable from `withReduce()` in\n * `./active.ts`, which is only exported through the\n * `@noy-db/hub/reduce` subpath. Consumers that don't import the\n * subpath ship none of the ~886 LOC.\n *\n * @internal\n */\n\nimport type {\n Reduction,\n ReduceSpec,\n ReduceResult,\n ReductionUpstream,\n} from './reduction.js'\nimport type { GroupedQuery, GroupedQueryN } from './groupby.js'\nimport type { ViaPipeline } from '../../kernel/via/pipeline.js'\n\n/**\n * Seam interface. `@internal` — will promote to public only when the\n * aggregate service is extracted into its own package.\n *\n * @internal\n */\nexport interface ReduceStrategy {\n /**\n * Build an `Reduction<R>` for `Query.aggregate(spec)`. `executeRecords`\n * is a closure that produces the matching record set when the\n * reduction runs. NO_REDUCE throws; the active strategy\n * constructs a real `Reduction`.\n */\n aggregate<Spec extends ReduceSpec>(\n executeRecords: () => readonly unknown[],\n spec: Spec,\n upstreams: readonly ReductionUpstream[],\n ): Reduction<ReduceResult<Spec>>\n\n /**\n * Build a `GroupedQuery<T, F, S>` for `Query.groupBy(field)`. Same\n * closure / upstream inputs as `aggregate` plus the group key field.\n */\n groupBy<T, F extends string, S extends keyof T = never, M extends keyof T & string = never>(\n executeRecords: () => readonly unknown[],\n field: F,\n upstreams: readonly ReductionUpstream[],\n dictLabelResolver?: (\n key: string,\n locale: string,\n fallback?: string | readonly string[],\n ) => Promise<string | undefined>,\n via?: ViaPipeline,\n ): GroupedQuery<T, F, S, M>\n\n /**\n * Variadic-keyed sibling — builds a `GroupedQueryN<T, F, S>` for\n * `Query.groupBy(...fields)`. No dictLabelResolver — `<field>Label`\n * projection only applies to single-field groupings, which dispatch\n * through `groupBy` above.\n */\n groupByN<T, F extends readonly string[], S extends keyof T = never, M extends keyof T & string = never>(\n executeRecords: () => readonly unknown[],\n fields: F,\n upstreams: readonly ReductionUpstream[],\n via?: ViaPipeline,\n ): GroupedQueryN<T, F, S, M>\n\n /**\n * Terminal streaming aggregator for `ScanBuilder.aggregate(spec)`.\n * Takes an async iterable of decrypted records + the spec and\n * returns the reduced result.\n */\n scanAggregate<Spec extends ReduceSpec>(\n iter: AsyncIterable<unknown>,\n spec: Spec,\n ): Promise<ReduceResult<Spec>>\n}\n\nconst NOT_ENABLED = new Error(\n 'Aggregate / groupBy is not enabled on this Noydb instance. ' +\n 'Import `{ withReduce }` from \"@noy-db/hub/reduce\" and pass it to ' +\n '`createNoydb({ reduceStrategy: withReduce() })`.',\n)\n\n/**\n * No-aggregate stub. Every `.aggregate()` / `.groupBy()` / streaming\n * `scan().aggregate()` call throws with a pointer at the subpath. The\n * real `Reduction` / `GroupedQuery` classes are never referenced at\n * runtime, so the bundler drops the ~886 LOC.\n *\n * @internal\n */\nexport const NO_REDUCE: ReduceStrategy = {\n aggregate() { throw NOT_ENABLED },\n groupBy() { throw NOT_ENABLED },\n groupByN() { throw NOT_ENABLED },\n scanAggregate() { throw NOT_ENABLED },\n}\n"],"mappings":";AAmFA,IAAM,cAAc,IAAI;AAAA,EACtB;AAGF;AAUO,IAAM,YAA4B;AAAA,EACvC,YAAY;AAAE,UAAM;AAAA,EAAY;AAAA,EAChC,UAAU;AAAE,UAAM;AAAA,EAAY;AAAA,EAC9B,WAAW;AAAE,UAAM;AAAA,EAAY;AAAA,EAC/B,gBAAgB;AAAE,UAAM;AAAA,EAAY;AACtC;","names":[]}