@noy-db/hub 0.7.1-pre.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 (610) hide show
  1. package/CHANGELOG.md +97 -14
  2. package/LICENSE +202 -21
  3. package/NOTICE +1 -0
  4. package/README.md +5 -5
  5. package/codemods/0.8.0-pre.json +61 -0
  6. package/dist/api-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-XKCXVKV3.js → backup-7TFRVFLH.js} +12 -12
  11. package/dist/blobs/index.js +13 -13
  12. package/dist/broker/index.js +12 -12
  13. package/dist/by/index.js +2 -2
  14. package/dist/cargo/index.js +39 -36
  15. package/dist/{chunk-7O3Y4PPD.js → chunk-244VXYPG.js} +140 -16
  16. package/dist/chunk-244VXYPG.js.map +1 -0
  17. package/dist/{chunk-BUE2D7PX.js → chunk-32YV3TJT.js} +2 -2
  18. package/dist/{chunk-3PGS7TYR.js → chunk-3ELRMVJK.js} +12 -12
  19. package/dist/{chunk-OTQZ7ZWU.js → chunk-3F7GLNAE.js} +6 -6
  20. package/dist/{chunk-SGZAIJCV.js → chunk-3H5KLDZN.js} +4 -4
  21. package/dist/{chunk-VTFVLCUH.js → chunk-3JWHAR6E.js} +2 -2
  22. package/dist/{chunk-YMUFFJCO.js → chunk-3TDUWVWB.js} +5 -2
  23. package/dist/chunk-3TDUWVWB.js.map +1 -0
  24. package/dist/{chunk-JBDFMYKQ.js → chunk-4AF3TUMP.js} +2 -2
  25. package/dist/{chunk-ZORTV6NH.js → chunk-4I522ERM.js} +88 -4
  26. package/dist/chunk-4I522ERM.js.map +1 -0
  27. package/dist/{chunk-A66I4JOA.js → chunk-4MXI3ODD.js} +4 -4
  28. package/dist/chunk-4MXI3ODD.js.map +1 -0
  29. package/dist/{chunk-BLN54W3L.js → chunk-5FDLC6G7.js} +56 -3
  30. package/dist/chunk-5FDLC6G7.js.map +1 -0
  31. package/dist/chunk-5O7D6ZTW.js +53 -0
  32. package/dist/chunk-5O7D6ZTW.js.map +1 -0
  33. package/dist/{chunk-DFMWUOU5.js → chunk-6B3VNR4P.js} +12 -12
  34. package/dist/{chunk-TUFM4UZP.js → chunk-6K7DPM7D.js} +2 -2
  35. package/dist/{chunk-3VF3WQ4F.js → chunk-6LMQ5R26.js} +7 -7
  36. package/dist/{chunk-UP4BECPY.js → chunk-6LNL42F5.js} +94 -32
  37. package/dist/chunk-6LNL42F5.js.map +1 -0
  38. package/dist/{chunk-XLMEZIAJ.js → chunk-6OWXYZK2.js} +2 -2
  39. package/dist/{chunk-BRLKZUBT.js → chunk-6QSQQLSE.js} +3 -3
  40. package/dist/chunk-7JE7BDYJ.js +1558 -0
  41. package/dist/chunk-7JE7BDYJ.js.map +1 -0
  42. package/dist/{chunk-XKWGNJ26.js → chunk-7VCXZDA4.js} +5 -5
  43. package/dist/chunk-7VCXZDA4.js.map +1 -0
  44. package/dist/{chunk-NQKIUNW5.js → chunk-A6IJU4TK.js} +2 -2
  45. package/dist/{chunk-HIWCKBEY.js → chunk-ANWPSTZU.js} +38 -9
  46. package/dist/chunk-ANWPSTZU.js.map +1 -0
  47. package/dist/{chunk-QIZPZMUI.js → chunk-AOWGXU6D.js} +2 -2
  48. package/dist/{chunk-CUZLNGD5.js → chunk-B2YY6WDD.js} +1 -1
  49. package/dist/chunk-B2YY6WDD.js.map +1 -0
  50. package/dist/{chunk-SFAWCTEM.js → chunk-B57AFBY2.js} +2 -2
  51. package/dist/{chunk-UHHPLO3I.js → chunk-B6SJIBQK.js} +4 -4
  52. package/dist/chunk-BJ2IXQ5Q.js +100 -0
  53. package/dist/chunk-BJ2IXQ5Q.js.map +1 -0
  54. package/dist/{chunk-Q2PU57HC.js → chunk-BK2HHQGN.js} +2 -2
  55. package/dist/chunk-BKT776R5.js +1 -0
  56. package/dist/{chunk-FET5XCAT.js → chunk-BP6DARYA.js} +33 -5
  57. package/dist/chunk-BP6DARYA.js.map +1 -0
  58. package/dist/{chunk-YJX7EOJD.js → chunk-BUDAGWL5.js} +6 -6
  59. package/dist/chunk-CF5UU4S7.js +757 -0
  60. package/dist/chunk-CF5UU4S7.js.map +1 -0
  61. package/dist/{chunk-QPQUVOZ2.js → chunk-CKNGS5MH.js} +3 -3
  62. package/dist/chunk-CY2CYVWZ.js +41 -0
  63. package/dist/chunk-CY2CYVWZ.js.map +1 -0
  64. package/dist/{chunk-2577DKXB.js → chunk-DC5QVPV7.js} +2 -2
  65. package/dist/chunk-DC5QVPV7.js.map +1 -0
  66. package/dist/{chunk-BTDR2PXY.js → chunk-DE4DH2RZ.js} +2 -2
  67. package/dist/{chunk-Q2MPFCQ7.js → chunk-DF73H4UN.js} +4 -4
  68. package/dist/{chunk-4GVM6QZA.js → chunk-ENAG3IY7.js} +2 -2
  69. package/dist/chunk-ENAG3IY7.js.map +1 -0
  70. package/dist/{chunk-6LKOJBV6.js → chunk-EOVMT6TB.js} +2 -2
  71. package/dist/chunk-F24ZZTHQ.js +193 -0
  72. package/dist/chunk-F24ZZTHQ.js.map +1 -0
  73. package/dist/chunk-F2TDU7MQ.js +456 -0
  74. package/dist/chunk-F2TDU7MQ.js.map +1 -0
  75. package/dist/chunk-F6NCB7KT.js +13 -0
  76. package/dist/chunk-F6NCB7KT.js.map +1 -0
  77. package/dist/{chunk-SPYWXKJN.js → chunk-F7XGHL5O.js} +3 -3
  78. package/dist/chunk-F7XGHL5O.js.map +1 -0
  79. package/dist/{chunk-R42NSZI6.js → chunk-FCKWQE2H.js} +5 -5
  80. package/dist/{chunk-R7BX2NB3.js → chunk-FH2L2E34.js} +4 -4
  81. package/dist/chunk-FH2L2E34.js.map +1 -0
  82. package/dist/{chunk-4OZNXTO4.js → chunk-FN5EBVTQ.js} +2 -2
  83. package/dist/chunk-FQ54DWUQ.js +270 -0
  84. package/dist/chunk-FQ54DWUQ.js.map +1 -0
  85. package/dist/{chunk-P3MG6QCN.js → chunk-FQ5VRHIB.js} +4 -4
  86. package/dist/{chunk-FAHMLERK.js → chunk-FW22ZCXT.js} +2 -2
  87. package/dist/chunk-FXQBGFOX.js +524 -0
  88. package/dist/chunk-FXQBGFOX.js.map +1 -0
  89. package/dist/{chunk-7APJ6CO6.js → chunk-GF5BZ7D4.js} +45 -9
  90. package/dist/chunk-GF5BZ7D4.js.map +1 -0
  91. package/dist/{chunk-TRGTKX5E.js → chunk-GHLTDZRS.js} +5 -3
  92. package/dist/{chunk-TRGTKX5E.js.map → chunk-GHLTDZRS.js.map} +1 -1
  93. package/dist/{chunk-BVN6KXL2.js → chunk-HBPPGWUM.js} +5 -5
  94. package/dist/chunk-HBPPGWUM.js.map +1 -0
  95. package/dist/{chunk-KTFRCC5C.js → chunk-HBRLNOHL.js} +82 -8
  96. package/dist/chunk-HBRLNOHL.js.map +1 -0
  97. package/dist/chunk-HLEK5VAN.js +275 -0
  98. package/dist/chunk-HLEK5VAN.js.map +1 -0
  99. package/dist/{chunk-RMS3NEA3.js → chunk-HT2AHGQI.js} +2 -2
  100. package/dist/{chunk-2N5ML6HT.js → chunk-HVSCEIYL.js} +7 -7
  101. package/dist/{chunk-LH5A3ZPG.js → chunk-I3JDRCMW.js} +150 -22
  102. package/dist/chunk-I3JDRCMW.js.map +1 -0
  103. package/dist/{chunk-GY4WYNNG.js → chunk-ID6Z6E66.js} +2 -2
  104. package/dist/{chunk-YJRT5UQM.js → chunk-IEX7NK2K.js} +3 -3
  105. package/dist/{chunk-334WSVOW.js → chunk-ISZQJBML.js} +5 -5
  106. package/dist/{chunk-LWBCUYZW.js → chunk-IT22PWKV.js} +2 -2
  107. package/dist/{chunk-EQEYOJBM.js → chunk-IUWCVHQ7.js} +3 -3
  108. package/dist/chunk-IUWCVHQ7.js.map +1 -0
  109. package/dist/{chunk-RF6D3Y5E.js → chunk-J6UOHJY5.js} +4 -4
  110. package/dist/{chunk-JMGDHKQF.js → chunk-JCN44NCY.js} +2 -2
  111. package/dist/{chunk-3BZZJJMQ.js → chunk-K6W7BVZ6.js} +3 -3
  112. package/dist/{chunk-4ZS56W5S.js → chunk-KJFW62P4.js} +29 -11
  113. package/dist/chunk-KJFW62P4.js.map +1 -0
  114. package/dist/{chunk-453F654R.js → chunk-L7DOS3TE.js} +2 -2
  115. package/dist/chunk-LGNDFRYC.js +23 -0
  116. package/dist/chunk-LGNDFRYC.js.map +1 -0
  117. package/dist/{chunk-QTQUH4DS.js → chunk-LGRLME4M.js} +7 -7
  118. package/dist/{chunk-CHQCZZWC.js → chunk-LQ4ZHOKP.js} +2 -2
  119. package/dist/{chunk-GPNTB4Y7.js → chunk-M522UYZ2.js} +5 -5
  120. package/dist/{chunk-3V4KWFX7.js → chunk-M7NI3IWE.js} +45 -12
  121. package/dist/chunk-M7NI3IWE.js.map +1 -0
  122. package/dist/chunk-MDWKM2XC.js +293 -0
  123. package/dist/chunk-MDWKM2XC.js.map +1 -0
  124. package/dist/chunk-MKXXMNJH.js +204 -0
  125. package/dist/chunk-MKXXMNJH.js.map +1 -0
  126. package/dist/{chunk-SKGMN35F.js → chunk-MLPHLJIQ.js} +3 -3
  127. package/dist/chunk-MLPHLJIQ.js.map +1 -0
  128. package/dist/{chunk-UDHWDSRL.js → chunk-MTL7MXGR.js} +6 -6
  129. package/dist/{chunk-TFR7DSOV.js → chunk-MVZ2TPVP.js} +2 -2
  130. package/dist/{chunk-K23VKTN4.js → chunk-N5DNADLQ.js} +7 -7
  131. package/dist/{chunk-RSGLUIO6.js → chunk-NNARWO72.js} +6 -6
  132. package/dist/{chunk-2ENE6445.js → chunk-NRT6QZQB.js} +102 -16
  133. package/dist/chunk-NRT6QZQB.js.map +1 -0
  134. package/dist/{chunk-PPTHY5QO.js → chunk-NWHBJQAL.js} +99 -8
  135. package/dist/chunk-NWHBJQAL.js.map +1 -0
  136. package/dist/chunk-NYMLINRP.js +28 -0
  137. package/dist/chunk-NYMLINRP.js.map +1 -0
  138. package/dist/{chunk-7MG7SJT7.js → chunk-ODVPTDPK.js} +1 -1
  139. package/dist/chunk-ODVPTDPK.js.map +1 -0
  140. package/dist/chunk-ORDURZBU.js +461 -0
  141. package/dist/chunk-ORDURZBU.js.map +1 -0
  142. package/dist/{chunk-6YXCPL4T.js → chunk-PDCG6PR5.js} +2 -2
  143. package/dist/{chunk-ACAQ2DSG.js → chunk-PSIV7CJV.js} +2 -2
  144. package/dist/{chunk-KKEESNPE.js → chunk-QBBUZ3I3.js} +126 -19
  145. package/dist/chunk-QBBUZ3I3.js.map +1 -0
  146. package/dist/{chunk-5VCRVKOZ.js → chunk-QOOUUR4A.js} +6 -4
  147. package/dist/{chunk-5VCRVKOZ.js.map → chunk-QOOUUR4A.js.map} +1 -1
  148. package/dist/{chunk-G73UVHCA.js → chunk-QWFHIOD2.js} +5 -5
  149. package/dist/{chunk-AYX7AINO.js → chunk-QWGU66MP.js} +3 -3
  150. package/dist/chunk-RHVMZSUU.js +7 -0
  151. package/dist/chunk-RHVMZSUU.js.map +1 -0
  152. package/dist/{chunk-3BVH633C.js → chunk-S57HTZ6X.js} +5 -5
  153. package/dist/{chunk-SZJ3DLZA.js → chunk-SEE332EV.js} +2 -2
  154. package/dist/{chunk-YYP7WSEB.js → chunk-SI3V7D4G.js} +2 -2
  155. package/dist/{chunk-UGTBXF5U.js → chunk-SOIQ4MM4.js} +3 -3
  156. package/dist/chunk-SUZKW6UR.js +25 -0
  157. package/dist/chunk-SUZKW6UR.js.map +1 -0
  158. package/dist/{chunk-4GFX6MPA.js → chunk-SYVZW77S.js} +6 -6
  159. package/dist/{chunk-ZYIYHJ5R.js → chunk-T2LBQ5DV.js} +815 -222
  160. package/dist/chunk-T2LBQ5DV.js.map +1 -0
  161. package/dist/chunk-T52GX4SA.js +215 -0
  162. package/dist/chunk-T52GX4SA.js.map +1 -0
  163. package/dist/{chunk-MVMXZYXT.js → chunk-TKUOEU2F.js} +2 -2
  164. package/dist/chunk-TOPYQ6GA.js +31 -0
  165. package/dist/chunk-TOPYQ6GA.js.map +1 -0
  166. package/dist/{chunk-SMH6SRX7.js → chunk-TROR3ALR.js} +2 -2
  167. package/dist/{chunk-CUQPWYRX.js → chunk-UD5EVGZ7.js} +42 -389
  168. package/dist/chunk-UD5EVGZ7.js.map +1 -0
  169. package/dist/{chunk-M4YPHYEH.js → chunk-UPD5NWI5.js} +65 -17
  170. package/dist/chunk-UPD5NWI5.js.map +1 -0
  171. package/dist/{chunk-HPVZCW43.js → chunk-UYB234ZR.js} +2 -2
  172. package/dist/chunk-VHM7HCKB.js +220 -0
  173. package/dist/chunk-VHM7HCKB.js.map +1 -0
  174. package/dist/{chunk-DGOZ4UZD.js → chunk-VNNRUGMM.js} +2 -2
  175. package/dist/{chunk-F3W6YMDC.js → chunk-VNPEWFPD.js} +4 -4
  176. package/dist/{chunk-JVIBCBC7.js → chunk-WNJ4AVGE.js} +2 -2
  177. package/dist/{chunk-ZHKOPKE3.js → chunk-WX5ADGTZ.js} +3 -3
  178. package/dist/{chunk-VXANTWBJ.js → chunk-WY2XXTET.js} +92 -6
  179. package/dist/{chunk-VXANTWBJ.js.map → chunk-WY2XXTET.js.map} +1 -1
  180. package/dist/{chunk-HJUWN7JN.js → chunk-X25NWUZB.js} +33 -8
  181. package/dist/chunk-X25NWUZB.js.map +1 -0
  182. package/dist/{chunk-Q7HZX3IF.js → chunk-X4773RBR.js} +2 -2
  183. package/dist/chunk-XBKH4FOC.js +195 -0
  184. package/dist/chunk-XBKH4FOC.js.map +1 -0
  185. package/dist/{chunk-A2HKRLPV.js → chunk-YNIUIERI.js} +3 -3
  186. package/dist/chunk-YSK2CU2Q.js +936 -0
  187. package/dist/chunk-YSK2CU2Q.js.map +1 -0
  188. package/dist/{chunk-UXVWEX5L.js → chunk-Z5HTYMMQ.js} +6 -2
  189. package/dist/chunk-Z5HTYMMQ.js.map +1 -0
  190. package/dist/{chunk-WQBG4SZS.js → chunk-ZE4CHIED.js} +56 -34
  191. package/dist/chunk-ZE4CHIED.js.map +1 -0
  192. package/dist/chunk-ZSX4S5XB.js +1289 -0
  193. package/dist/chunk-ZSX4S5XB.js.map +1 -0
  194. package/dist/{chunk-BZ3534YM.js → chunk-ZUVBC32X.js} +2 -2
  195. package/dist/{chunk-V7ZRRCRJ.js → chunk-ZXABPVM6.js} +6 -6
  196. package/dist/classified/index.js +5 -5
  197. package/dist/{classified-marker-BWOFVYAC.js → classified-marker-W3USLL5M.js} +3 -3
  198. package/dist/collection-facade-QU6IJBN3.js +48 -0
  199. package/dist/{computed-VPOKQK4N.js → computed-TPFBX7U4.js} +3 -3
  200. package/dist/consent/index.js +9 -9
  201. package/dist/cover/index.js +10 -10
  202. package/dist/coverage/index.js +306 -0
  203. package/dist/coverage/index.js.map +1 -0
  204. package/dist/custody/index.js +12 -12
  205. package/dist/{dead-filter-PKQDLOT4.js → dead-filter-U2UYKSZL.js} +2 -2
  206. package/dist/debug/index.js +1 -1
  207. package/dist/{delegation-DS5NRILW.js → delegation-S3AEPW2T.js} +11 -11
  208. package/dist/derivations/index.js +25 -22
  209. package/dist/derive-OX7F6TGG.js +21 -0
  210. package/dist/directory/index.js +10 -10
  211. package/dist/{dispatch-IEPAVQUM.js → dispatch-3CQDJV5Q.js} +5 -5
  212. package/dist/{dispatch-Q6MWLOJY.js → dispatch-RH4LHKBH.js} +21 -21
  213. package/dist/{enclave-55PAM4YO.js → enclave-27SMF6GF.js} +9 -9
  214. package/dist/executor-B6SRO2QS.js +36 -0
  215. package/dist/executor-BI5CHWRY.js +8 -0
  216. package/dist/executor-RBKM5W5K.js +8 -0
  217. package/dist/export-accessible-VMA3YM5V.js +22 -0
  218. package/dist/extract-partition-NF7PXGPP.js +37 -0
  219. package/dist/{fanout-sidecar-S3QL53YX.js → fanout-sidecar-OT6RYLOL.js} +9 -9
  220. package/dist/find-LZMP26KF.js +10 -0
  221. package/dist/forget/index.js +9 -9
  222. package/dist/guards/index.js +4 -4
  223. package/dist/history/index.js +13 -13
  224. package/dist/i18n/index.js +14 -14
  225. package/dist/index.d.ts +28 -6
  226. package/dist/index.js +999 -191
  227. package/dist/index.js.map +1 -1
  228. package/dist/indexing/index.js +13 -5
  229. package/dist/indexing/index.js.map +1 -1
  230. package/dist/introspection/index.js +11 -11
  231. package/dist/issue-IHARXWW5.js +18 -0
  232. package/dist/ivf-flat-UZ6DQDLS.js +314 -0
  233. package/dist/ivf-flat-UZ6DQDLS.js.map +1 -0
  234. package/dist/{json-schema-V3M5MUCM.js → json-schema-3SHX72CC.js} +2 -1
  235. package/dist/json-schema-3SHX72CC.js.map +1 -0
  236. package/dist/kernel/collection-config.d.ts +4 -20
  237. package/dist/kernel/collection.d.ts +29 -8
  238. package/dist/kernel/enclave/record-keys/record-codec.d.ts +25 -0
  239. package/dist/kernel/errors.d.ts +227 -36
  240. package/dist/kernel/generation-map.d.ts +48 -0
  241. package/dist/kernel/noydb.d.ts +6 -1
  242. package/dist/kernel/present-cache.d.ts +58 -0
  243. package/dist/kernel/query/all.d.ts +7 -0
  244. package/dist/kernel/query/builder.d.ts +601 -270
  245. package/dist/kernel/query/civil-date.d.ts +64 -0
  246. package/dist/kernel/query/cursor.d.ts +40 -0
  247. package/dist/kernel/query/distinct-key.d.ts +98 -0
  248. package/dist/kernel/query/hydration.d.ts +76 -0
  249. package/dist/kernel/query/index.d.ts +31 -15
  250. package/dist/kernel/query/internal/core.d.ts +30 -0
  251. package/dist/kernel/query/internal/hooks.d.ts +22 -0
  252. package/dist/kernel/query/internal/maintenance.d.ts +43 -0
  253. package/dist/kernel/query/live/incremental.d.ts +314 -0
  254. package/dist/kernel/query/live/index.d.ts +22 -0
  255. package/dist/kernel/query/live/install.d.ts +2 -0
  256. package/dist/kernel/query/{live.d.ts → live/live.d.ts} +39 -9
  257. package/dist/kernel/query/live/methods.d.ts +107 -0
  258. package/dist/kernel/query/predicate.d.ts +119 -1
  259. package/dist/kernel/query/reduce/date-trunc.d.ts +75 -0
  260. package/dist/kernel/query/reduce/index.d.ts +36 -0
  261. package/dist/kernel/query/reduce/install.d.ts +2 -0
  262. package/dist/kernel/query/reduce/methods.d.ts +259 -0
  263. package/dist/kernel/query/reduce/scan-methods.d.ts +121 -0
  264. package/dist/kernel/query/relate/explain.d.ts +199 -0
  265. package/dist/kernel/query/relate/index.d.ts +48 -0
  266. package/dist/kernel/query/relate/install.d.ts +2 -0
  267. package/dist/kernel/query/relate/join-on.d.ts +126 -0
  268. package/dist/kernel/query/relate/join-reduce.d.ts +16 -0
  269. package/dist/kernel/query/relate/join.d.ts +452 -0
  270. package/dist/kernel/query/relate/methods.d.ts +426 -0
  271. package/dist/kernel/query/relate/partition.d.ts +87 -0
  272. package/dist/kernel/query/relate/scan-methods.d.ts +163 -0
  273. package/dist/kernel/query/relate/traverse.d.ts +109 -0
  274. package/dist/kernel/query/scan-builder.d.ts +79 -176
  275. package/dist/kernel/query/sort-key.d.ts +52 -0
  276. package/dist/kernel/tx-write-gate.d.ts +77 -0
  277. package/dist/kernel/types.d.ts +71 -3
  278. package/dist/kernel/validation.d.ts +27 -10
  279. package/dist/kernel/vault.d.ts +9 -4
  280. package/dist/kernel/via/compose.d.ts +3 -0
  281. package/dist/kernel/via/index.d.ts +56 -0
  282. package/dist/kernel/via/pipeline.d.ts +48 -0
  283. package/dist/{ledger-EDXFFZQL.js → ledger-KZPCMVZY.js} +11 -11
  284. package/dist/liberate-GRLCZMW4.js +24 -0
  285. package/dist/link-set-JCMJ7ULP.js +30 -0
  286. package/dist/{managed-secret-NCWEMPUQ.js → managed-secret-S3MQ6SH6.js} +10 -10
  287. package/dist/materialized-views/index.js +30 -23
  288. package/dist/{migrate-cek-5ENH64AA.js → migrate-cek-V7GKJZ7O.js} +2 -2
  289. package/dist/money/index.js +5 -5
  290. package/dist/noydb-SWQJ3MZS.js +97 -0
  291. package/dist/overlay-views/index.js +4 -4
  292. package/dist/periods/index.js +12 -12
  293. package/dist/pod/index.js +75 -68
  294. package/dist/{pod-handle-ECVCDIXW.js → pod-handle-WGDFB4C2.js} +9 -9
  295. package/dist/policy/index.js +10 -10
  296. package/dist/port/with/blob-strategy.d.ts +9 -0
  297. package/dist/port/with/collection-options.d.ts +5 -0
  298. package/dist/port/with/coverage-strategy.d.ts +83 -0
  299. package/dist/port/with/service-bus.d.ts +46 -0
  300. package/dist/port/with/strategies.d.ts +2 -0
  301. package/dist/portability/index.js +8 -8
  302. package/dist/{post-register-3IPCSG6Q.js → post-register-SLSXIPBV.js} +6 -6
  303. package/dist/query/all/index.js +31 -0
  304. package/dist/query/index.js +20 -32
  305. package/dist/query/live/index.js +21 -0
  306. package/dist/query/live/index.js.map +1 -0
  307. package/dist/query/reduce/index.js +33 -0
  308. package/dist/query/reduce/index.js.map +1 -0
  309. package/dist/query/relate/index.js +56 -0
  310. package/dist/query/relate/index.js.map +1 -0
  311. package/dist/reduce/index.js +72 -18
  312. package/dist/reduce/index.js.map +1 -1
  313. package/dist/register-F3OYE7MJ.js +31 -0
  314. package/dist/registry-CILQFXFK.js +8 -0
  315. package/dist/registry-XNNYQVKV.js +8 -0
  316. package/dist/registry-YCDZV3VW.js +35 -0
  317. package/dist/registry-ZGYS33TE.js +24 -0
  318. package/dist/request-withdrawal-Z5NC6TXT.js +30 -0
  319. package/dist/{reveal-QZDHSGD4.js → reveal-4BCKPEC2.js} +6 -6
  320. package/dist/revoke-ZL62WC2D.js +23 -0
  321. package/dist/satellites/index.js +1 -1
  322. package/dist/schema-update/index.js +2 -2
  323. package/dist/sealed-record/index.js +12 -12
  324. package/dist/search/index.js +11 -5
  325. package/dist/{seed-X5CC22CQ.js → seed-4JS2RJ4A.js} +12 -12
  326. package/dist/sequence/index.js +9 -9
  327. package/dist/session/index.js +9 -9
  328. package/dist/shadow/index.js +2 -2
  329. package/dist/signer-MBZZMXTC.js +24 -0
  330. package/dist/snapshots/index.js +10 -10
  331. package/dist/{stale-BZS6H2RY.js → stale-TJ3DYZMQ.js} +10 -10
  332. package/dist/storage-SVMKRGCW.js +22 -0
  333. package/dist/{store-coordination-provider-4WZAIRHC.js → store-coordination-provider-2O2VUHKW.js} +10 -10
  334. package/dist/sync/index.js +10 -10
  335. package/dist/team/index.js +17 -15
  336. package/dist/tiers/index.js +13 -11
  337. package/dist/to/index.js +2 -2
  338. package/dist/transactions/index.js +3 -3
  339. package/dist/util/index.js +1 -1
  340. package/dist/vault-head/index.js +8 -8
  341. package/dist/{verify-6MDTIUEV.js → verify-RVT67IMH.js} +5 -5
  342. package/dist/via/blob/index.d.ts +1 -0
  343. package/dist/via/geo/binding.d.ts +31 -0
  344. package/dist/via/geo/descriptor.d.ts +54 -0
  345. package/dist/via/geo/geohash.d.ts +95 -0
  346. package/dist/via/geo/index.d.ts +13 -0
  347. package/dist/via/geo/where.d.ts +50 -0
  348. package/dist/via/i18n/core.d.ts +1 -1
  349. package/dist/via/lookup/registry.d.ts +1 -1
  350. package/dist/via/lookup/snapshot.d.ts +3 -3
  351. package/dist/walk-HJ42EISE.js +21 -0
  352. package/dist/walk-HJ42EISE.js.map +1 -0
  353. package/dist/with-audit/coverage/accounting.d.ts +112 -0
  354. package/dist/with-audit/coverage/active.d.ts +29 -0
  355. package/dist/with-audit/coverage/index.d.ts +61 -0
  356. package/dist/with-audit/coverage/sketch.d.ts +75 -0
  357. package/dist/with-audit/periods/periods.d.ts +55 -7
  358. package/dist/with-audit/periods/reserved-collections.d.ts +3 -0
  359. package/dist/with-audit/periods/vault-facade.d.ts +17 -0
  360. package/dist/with-audit/tiers/index.d.ts +51 -0
  361. package/dist/with-audit/tiers/strategy.d.ts +8 -0
  362. package/dist/with-cargo/floor.d.ts +2 -2
  363. package/dist/with-commit/tx/invariants.d.ts +1 -1
  364. package/dist/with-commit/tx/transaction.d.ts +13 -3
  365. package/dist/with-formula/materialized-views/dependency-analyzer.d.ts +4 -3
  366. package/dist/with-formula/materialized-views/emit-memo.d.ts +40 -0
  367. package/dist/with-formula/materialized-views/executor.d.ts +8 -0
  368. package/dist/with-formula/materialized-views/index.d.ts +1 -1
  369. package/dist/with-formula/materialized-views/registry.d.ts +15 -0
  370. package/dist/with-formula/materialized-views/types.d.ts +106 -14
  371. package/dist/with-formula/materialized-views/window-stage.d.ts +11 -0
  372. package/dist/with-formula/overlay-views/types.d.ts +1 -1
  373. package/dist/with-formula/overlay-views/virtual-collection.d.ts +13 -4
  374. package/dist/with-lookup/embeddings/chunks.d.ts +79 -0
  375. package/dist/with-lookup/embeddings/descriptor.d.ts +21 -0
  376. package/dist/with-lookup/embeddings/index.d.ts +3 -0
  377. package/dist/with-lookup/embeddings/ivf-flat.d.ts +93 -0
  378. package/dist/with-lookup/embeddings/vector-index.d.ts +73 -0
  379. package/dist/with-lookup/embeddings/vector-set.d.ts +94 -1
  380. package/dist/with-lookup/embeddings/with-vector-index.d.ts +67 -0
  381. package/dist/with-lookup/indexing/collection-facade.d.ts +85 -2
  382. package/dist/with-lookup/indexing/compound-indexes.d.ts +129 -0
  383. package/dist/with-lookup/indexing/eager-indexes.d.ts +170 -1
  384. package/dist/with-lookup/indexing/index-snapshot.d.ts +62 -0
  385. package/dist/with-lookup/indexing/lazy-builder.d.ts +33 -0
  386. package/dist/with-lookup/indexing/persisted-field-indexes.d.ts +104 -0
  387. package/dist/with-lookup/indexing/persisted-indexes.d.ts +12 -0
  388. package/dist/with-lookup/indexing/sorted-indexes.d.ts +117 -0
  389. package/dist/with-lookup/indexing/unique-constraints.d.ts +106 -23
  390. package/dist/with-lookup/reduce/active.d.ts +2 -24
  391. package/dist/with-lookup/reduce/group-core.d.ts +43 -0
  392. package/dist/with-lookup/reduce/groupby.d.ts +195 -36
  393. package/dist/with-lookup/reduce/incremental-group.d.ts +153 -0
  394. package/dist/with-lookup/reduce/index.d.ts +26 -5
  395. package/dist/with-lookup/reduce/reducers.d.ts +255 -1
  396. package/dist/with-lookup/reduce/reduction.d.ts +44 -13
  397. package/dist/with-lookup/reduce/strategy.d.ts +43 -3
  398. package/dist/with-lookup/reduce/window.d.ts +262 -0
  399. package/dist/with-lookup/search/collection-facade.d.ts +44 -8
  400. package/dist/with-lookup/search/index-store.d.ts +5 -3
  401. package/dist/with-lookup/search/index.d.ts +4 -2
  402. package/dist/with-lookup/search/inverted-index.d.ts +38 -2
  403. package/dist/with-lookup/search/persisted-index-store.d.ts +5 -2
  404. package/dist/with-lookup/search/phrase.d.ts +28 -0
  405. package/dist/with-lookup/search/retrieve-types.d.ts +57 -1
  406. package/dist/with-lookup/search/serialize.d.ts +29 -3
  407. package/dist/with-lookup/search/strategy.d.ts +2 -6
  408. package/dist/with-party/directory/cover/index.d.ts +1 -1
  409. package/dist/with-party/directory/cover/storage.d.ts +1 -1
  410. package/dist/with-party/directory/cover/types.d.ts +1 -1
  411. package/dist/with-party/directory/index.d.ts +1 -1
  412. package/dist/with-party/directory/types.d.ts +1 -1
  413. package/dist/with-party/directory/user-envelope/api.d.ts +1 -1
  414. package/dist/with-party/policy/engine.d.ts +1 -1
  415. package/dist/with-party/policy/index.d.ts +1 -1
  416. package/dist/with-party/policy/presets.d.ts +1 -1
  417. package/dist/with-party/team/authenticators.d.ts +91 -1
  418. package/dist/with-party/team/index.d.ts +3 -2
  419. package/dist/with-party/team/keyring.d.ts +1 -1
  420. package/dist/with-party/team/managed-secret.d.ts +1 -1
  421. package/dist/with-party/team/noydb-facade.d.ts +12 -3
  422. package/dist/with-pod/format.d.ts +1 -1
  423. package/dist/with-pod/pod.d.ts +1 -1
  424. package/dist/with-shape/blobs/blob-compaction.d.ts +16 -0
  425. package/dist/with-shape/blobs/blob-set.d.ts +21 -2
  426. package/dist/with-shape/blobs/legacy-sweep.d.ts +35 -0
  427. package/dist/with-shape/introspection/describe.d.ts +6 -0
  428. package/dist/with-shape/introspection/field-meta.d.ts +18 -0
  429. package/dist/with-shape/introspection/types.d.ts +57 -1
  430. package/dist/with-shape/links/vault-facade.d.ts +1 -1
  431. package/dist/with-store/partitioned/index.d.ts +337 -0
  432. package/dist/with-sync/change-broadcast.d.ts +153 -0
  433. package/dist/withdraw-accessible-5NZUPAVA.js +27 -0
  434. package/dist/withdraw-accessible-5NZUPAVA.js.map +1 -0
  435. package/package.json +37 -10
  436. package/dist/api-WYW4YEQG.js +0 -19
  437. package/dist/chunk-2577DKXB.js.map +0 -1
  438. package/dist/chunk-2ENE6445.js.map +0 -1
  439. package/dist/chunk-3V4KWFX7.js.map +0 -1
  440. package/dist/chunk-4GVM6QZA.js.map +0 -1
  441. package/dist/chunk-4ZS56W5S.js.map +0 -1
  442. package/dist/chunk-7APJ6CO6.js.map +0 -1
  443. package/dist/chunk-7MG2LHO5.js +0 -1616
  444. package/dist/chunk-7MG2LHO5.js.map +0 -1
  445. package/dist/chunk-7MG7SJT7.js.map +0 -1
  446. package/dist/chunk-7O3Y4PPD.js.map +0 -1
  447. package/dist/chunk-A66I4JOA.js.map +0 -1
  448. package/dist/chunk-ATL3ZVXT.js +0 -151
  449. package/dist/chunk-ATL3ZVXT.js.map +0 -1
  450. package/dist/chunk-BLN54W3L.js.map +0 -1
  451. package/dist/chunk-BVN6KXL2.js.map +0 -1
  452. package/dist/chunk-CUQPWYRX.js.map +0 -1
  453. package/dist/chunk-CUZLNGD5.js.map +0 -1
  454. package/dist/chunk-EQEYOJBM.js.map +0 -1
  455. package/dist/chunk-FET5XCAT.js.map +0 -1
  456. package/dist/chunk-HIWCKBEY.js.map +0 -1
  457. package/dist/chunk-HJUWN7JN.js.map +0 -1
  458. package/dist/chunk-I3ISCYT7.js +0 -159
  459. package/dist/chunk-I3ISCYT7.js.map +0 -1
  460. package/dist/chunk-KKEESNPE.js.map +0 -1
  461. package/dist/chunk-KTFRCC5C.js.map +0 -1
  462. package/dist/chunk-LH5A3ZPG.js.map +0 -1
  463. package/dist/chunk-M4YPHYEH.js.map +0 -1
  464. package/dist/chunk-NSITFOCJ.js +0 -99
  465. package/dist/chunk-NSITFOCJ.js.map +0 -1
  466. package/dist/chunk-PPTHY5QO.js.map +0 -1
  467. package/dist/chunk-R7BX2NB3.js.map +0 -1
  468. package/dist/chunk-RTBJ5IOO.js +0 -87
  469. package/dist/chunk-RTBJ5IOO.js.map +0 -1
  470. package/dist/chunk-SKGMN35F.js.map +0 -1
  471. package/dist/chunk-SPYWXKJN.js.map +0 -1
  472. package/dist/chunk-UP4BECPY.js.map +0 -1
  473. package/dist/chunk-UXVWEX5L.js.map +0 -1
  474. package/dist/chunk-WQBG4SZS.js.map +0 -1
  475. package/dist/chunk-XKWGNJ26.js.map +0 -1
  476. package/dist/chunk-YMUFFJCO.js.map +0 -1
  477. package/dist/chunk-ZN4FD4PE.js +0 -364
  478. package/dist/chunk-ZN4FD4PE.js.map +0 -1
  479. package/dist/chunk-ZORTV6NH.js.map +0 -1
  480. package/dist/chunk-ZYIYHJ5R.js.map +0 -1
  481. package/dist/collection-facade-JSJYIKS4.js +0 -45
  482. package/dist/derive-E642AOUB.js +0 -21
  483. package/dist/executor-5NIMLSKZ.js +0 -8
  484. package/dist/executor-7UQ3BZ4F.js +0 -29
  485. package/dist/executor-AQVXV5GZ.js +0 -8
  486. package/dist/export-accessible-ORMKLA3E.js +0 -22
  487. package/dist/extract-partition-NKYO3WNG.js +0 -37
  488. package/dist/find-NOGJ25VX.js +0 -10
  489. package/dist/issue-3DTQ7VJJ.js +0 -18
  490. package/dist/json-schema-V3M5MUCM.js.map +0 -1
  491. package/dist/kernel/query/join.d.ts +0 -232
  492. package/dist/liberate-V35QUHJP.js +0 -24
  493. package/dist/link-set-2TTM3IZC.js +0 -30
  494. package/dist/noydb-62MX4QUG.js +0 -90
  495. package/dist/register-HHLXEQDN.js +0 -31
  496. package/dist/registry-23WF3TGH.js +0 -8
  497. package/dist/registry-4AYVUNXK.js +0 -8
  498. package/dist/registry-JS3YFQQM.js +0 -18
  499. package/dist/registry-XX2Z7B46.js +0 -32
  500. package/dist/request-withdrawal-CHPATE4G.js +0 -30
  501. package/dist/revoke-7M2VW4ON.js +0 -23
  502. package/dist/signer-SJQJVSM6.js +0 -24
  503. package/dist/storage-RW4QBS23.js +0 -22
  504. package/dist/walk-ZURCH6RZ.js +0 -21
  505. package/dist/withdraw-accessible-PXR4IXDX.js +0 -27
  506. /package/dist/{api-WYW4YEQG.js.map → api-GVYEKSJE.js.map} +0 -0
  507. /package/dist/{backup-XKCXVKV3.js.map → backup-7TFRVFLH.js.map} +0 -0
  508. /package/dist/{chunk-BUE2D7PX.js.map → chunk-32YV3TJT.js.map} +0 -0
  509. /package/dist/{chunk-3PGS7TYR.js.map → chunk-3ELRMVJK.js.map} +0 -0
  510. /package/dist/{chunk-OTQZ7ZWU.js.map → chunk-3F7GLNAE.js.map} +0 -0
  511. /package/dist/{chunk-SGZAIJCV.js.map → chunk-3H5KLDZN.js.map} +0 -0
  512. /package/dist/{chunk-VTFVLCUH.js.map → chunk-3JWHAR6E.js.map} +0 -0
  513. /package/dist/{chunk-JBDFMYKQ.js.map → chunk-4AF3TUMP.js.map} +0 -0
  514. /package/dist/{chunk-DFMWUOU5.js.map → chunk-6B3VNR4P.js.map} +0 -0
  515. /package/dist/{chunk-TUFM4UZP.js.map → chunk-6K7DPM7D.js.map} +0 -0
  516. /package/dist/{chunk-3VF3WQ4F.js.map → chunk-6LMQ5R26.js.map} +0 -0
  517. /package/dist/{chunk-XLMEZIAJ.js.map → chunk-6OWXYZK2.js.map} +0 -0
  518. /package/dist/{chunk-BRLKZUBT.js.map → chunk-6QSQQLSE.js.map} +0 -0
  519. /package/dist/{chunk-NQKIUNW5.js.map → chunk-A6IJU4TK.js.map} +0 -0
  520. /package/dist/{chunk-QIZPZMUI.js.map → chunk-AOWGXU6D.js.map} +0 -0
  521. /package/dist/{chunk-SFAWCTEM.js.map → chunk-B57AFBY2.js.map} +0 -0
  522. /package/dist/{chunk-UHHPLO3I.js.map → chunk-B6SJIBQK.js.map} +0 -0
  523. /package/dist/{chunk-Q2PU57HC.js.map → chunk-BK2HHQGN.js.map} +0 -0
  524. /package/dist/{collection-facade-JSJYIKS4.js.map → chunk-BKT776R5.js.map} +0 -0
  525. /package/dist/{chunk-YJX7EOJD.js.map → chunk-BUDAGWL5.js.map} +0 -0
  526. /package/dist/{chunk-QPQUVOZ2.js.map → chunk-CKNGS5MH.js.map} +0 -0
  527. /package/dist/{chunk-BTDR2PXY.js.map → chunk-DE4DH2RZ.js.map} +0 -0
  528. /package/dist/{chunk-Q2MPFCQ7.js.map → chunk-DF73H4UN.js.map} +0 -0
  529. /package/dist/{chunk-6LKOJBV6.js.map → chunk-EOVMT6TB.js.map} +0 -0
  530. /package/dist/{chunk-R42NSZI6.js.map → chunk-FCKWQE2H.js.map} +0 -0
  531. /package/dist/{chunk-4OZNXTO4.js.map → chunk-FN5EBVTQ.js.map} +0 -0
  532. /package/dist/{chunk-P3MG6QCN.js.map → chunk-FQ5VRHIB.js.map} +0 -0
  533. /package/dist/{chunk-FAHMLERK.js.map → chunk-FW22ZCXT.js.map} +0 -0
  534. /package/dist/{chunk-RMS3NEA3.js.map → chunk-HT2AHGQI.js.map} +0 -0
  535. /package/dist/{chunk-2N5ML6HT.js.map → chunk-HVSCEIYL.js.map} +0 -0
  536. /package/dist/{chunk-GY4WYNNG.js.map → chunk-ID6Z6E66.js.map} +0 -0
  537. /package/dist/{chunk-YJRT5UQM.js.map → chunk-IEX7NK2K.js.map} +0 -0
  538. /package/dist/{chunk-334WSVOW.js.map → chunk-ISZQJBML.js.map} +0 -0
  539. /package/dist/{chunk-LWBCUYZW.js.map → chunk-IT22PWKV.js.map} +0 -0
  540. /package/dist/{chunk-RF6D3Y5E.js.map → chunk-J6UOHJY5.js.map} +0 -0
  541. /package/dist/{chunk-JMGDHKQF.js.map → chunk-JCN44NCY.js.map} +0 -0
  542. /package/dist/{chunk-3BZZJJMQ.js.map → chunk-K6W7BVZ6.js.map} +0 -0
  543. /package/dist/{chunk-453F654R.js.map → chunk-L7DOS3TE.js.map} +0 -0
  544. /package/dist/{chunk-QTQUH4DS.js.map → chunk-LGRLME4M.js.map} +0 -0
  545. /package/dist/{chunk-CHQCZZWC.js.map → chunk-LQ4ZHOKP.js.map} +0 -0
  546. /package/dist/{chunk-GPNTB4Y7.js.map → chunk-M522UYZ2.js.map} +0 -0
  547. /package/dist/{chunk-UDHWDSRL.js.map → chunk-MTL7MXGR.js.map} +0 -0
  548. /package/dist/{chunk-TFR7DSOV.js.map → chunk-MVZ2TPVP.js.map} +0 -0
  549. /package/dist/{chunk-K23VKTN4.js.map → chunk-N5DNADLQ.js.map} +0 -0
  550. /package/dist/{chunk-RSGLUIO6.js.map → chunk-NNARWO72.js.map} +0 -0
  551. /package/dist/{chunk-6YXCPL4T.js.map → chunk-PDCG6PR5.js.map} +0 -0
  552. /package/dist/{chunk-ACAQ2DSG.js.map → chunk-PSIV7CJV.js.map} +0 -0
  553. /package/dist/{chunk-G73UVHCA.js.map → chunk-QWFHIOD2.js.map} +0 -0
  554. /package/dist/{chunk-AYX7AINO.js.map → chunk-QWGU66MP.js.map} +0 -0
  555. /package/dist/{chunk-3BVH633C.js.map → chunk-S57HTZ6X.js.map} +0 -0
  556. /package/dist/{chunk-SZJ3DLZA.js.map → chunk-SEE332EV.js.map} +0 -0
  557. /package/dist/{chunk-YYP7WSEB.js.map → chunk-SI3V7D4G.js.map} +0 -0
  558. /package/dist/{chunk-UGTBXF5U.js.map → chunk-SOIQ4MM4.js.map} +0 -0
  559. /package/dist/{chunk-4GFX6MPA.js.map → chunk-SYVZW77S.js.map} +0 -0
  560. /package/dist/{chunk-MVMXZYXT.js.map → chunk-TKUOEU2F.js.map} +0 -0
  561. /package/dist/{chunk-SMH6SRX7.js.map → chunk-TROR3ALR.js.map} +0 -0
  562. /package/dist/{chunk-HPVZCW43.js.map → chunk-UYB234ZR.js.map} +0 -0
  563. /package/dist/{chunk-DGOZ4UZD.js.map → chunk-VNNRUGMM.js.map} +0 -0
  564. /package/dist/{chunk-F3W6YMDC.js.map → chunk-VNPEWFPD.js.map} +0 -0
  565. /package/dist/{chunk-JVIBCBC7.js.map → chunk-WNJ4AVGE.js.map} +0 -0
  566. /package/dist/{chunk-ZHKOPKE3.js.map → chunk-WX5ADGTZ.js.map} +0 -0
  567. /package/dist/{chunk-Q7HZX3IF.js.map → chunk-X4773RBR.js.map} +0 -0
  568. /package/dist/{chunk-A2HKRLPV.js.map → chunk-YNIUIERI.js.map} +0 -0
  569. /package/dist/{chunk-BZ3534YM.js.map → chunk-ZUVBC32X.js.map} +0 -0
  570. /package/dist/{chunk-V7ZRRCRJ.js.map → chunk-ZXABPVM6.js.map} +0 -0
  571. /package/dist/{classified-marker-BWOFVYAC.js.map → classified-marker-W3USLL5M.js.map} +0 -0
  572. /package/dist/{computed-VPOKQK4N.js.map → collection-facade-QU6IJBN3.js.map} +0 -0
  573. /package/dist/{derive-E642AOUB.js.map → computed-TPFBX7U4.js.map} +0 -0
  574. /package/dist/{dead-filter-PKQDLOT4.js.map → dead-filter-U2UYKSZL.js.map} +0 -0
  575. /package/dist/{delegation-DS5NRILW.js.map → delegation-S3AEPW2T.js.map} +0 -0
  576. /package/dist/{enclave-55PAM4YO.js.map → derive-OX7F6TGG.js.map} +0 -0
  577. /package/dist/{dispatch-IEPAVQUM.js.map → dispatch-3CQDJV5Q.js.map} +0 -0
  578. /package/dist/{dispatch-Q6MWLOJY.js.map → dispatch-RH4LHKBH.js.map} +0 -0
  579. /package/dist/{executor-5NIMLSKZ.js.map → enclave-27SMF6GF.js.map} +0 -0
  580. /package/dist/{executor-7UQ3BZ4F.js.map → executor-B6SRO2QS.js.map} +0 -0
  581. /package/dist/{executor-AQVXV5GZ.js.map → executor-BI5CHWRY.js.map} +0 -0
  582. /package/dist/{export-accessible-ORMKLA3E.js.map → executor-RBKM5W5K.js.map} +0 -0
  583. /package/dist/{extract-partition-NKYO3WNG.js.map → export-accessible-VMA3YM5V.js.map} +0 -0
  584. /package/dist/{find-NOGJ25VX.js.map → extract-partition-NF7PXGPP.js.map} +0 -0
  585. /package/dist/{fanout-sidecar-S3QL53YX.js.map → fanout-sidecar-OT6RYLOL.js.map} +0 -0
  586. /package/dist/{issue-3DTQ7VJJ.js.map → find-LZMP26KF.js.map} +0 -0
  587. /package/dist/{ledger-EDXFFZQL.js.map → issue-IHARXWW5.js.map} +0 -0
  588. /package/dist/{liberate-V35QUHJP.js.map → ledger-KZPCMVZY.js.map} +0 -0
  589. /package/dist/{link-set-2TTM3IZC.js.map → liberate-GRLCZMW4.js.map} +0 -0
  590. /package/dist/{managed-secret-NCWEMPUQ.js.map → link-set-JCMJ7ULP.js.map} +0 -0
  591. /package/dist/{noydb-62MX4QUG.js.map → managed-secret-S3MQ6SH6.js.map} +0 -0
  592. /package/dist/{migrate-cek-5ENH64AA.js.map → migrate-cek-V7GKJZ7O.js.map} +0 -0
  593. /package/dist/{register-HHLXEQDN.js.map → noydb-SWQJ3MZS.js.map} +0 -0
  594. /package/dist/{pod-handle-ECVCDIXW.js.map → pod-handle-WGDFB4C2.js.map} +0 -0
  595. /package/dist/{post-register-3IPCSG6Q.js.map → post-register-SLSXIPBV.js.map} +0 -0
  596. /package/dist/{registry-23WF3TGH.js.map → query/all/index.js.map} +0 -0
  597. /package/dist/{registry-4AYVUNXK.js.map → register-F3OYE7MJ.js.map} +0 -0
  598. /package/dist/{registry-JS3YFQQM.js.map → registry-CILQFXFK.js.map} +0 -0
  599. /package/dist/{registry-XX2Z7B46.js.map → registry-XNNYQVKV.js.map} +0 -0
  600. /package/dist/{request-withdrawal-CHPATE4G.js.map → registry-YCDZV3VW.js.map} +0 -0
  601. /package/dist/{revoke-7M2VW4ON.js.map → registry-ZGYS33TE.js.map} +0 -0
  602. /package/dist/{signer-SJQJVSM6.js.map → request-withdrawal-Z5NC6TXT.js.map} +0 -0
  603. /package/dist/{reveal-QZDHSGD4.js.map → reveal-4BCKPEC2.js.map} +0 -0
  604. /package/dist/{stale-BZS6H2RY.js.map → revoke-ZL62WC2D.js.map} +0 -0
  605. /package/dist/{seed-X5CC22CQ.js.map → seed-4JS2RJ4A.js.map} +0 -0
  606. /package/dist/{storage-RW4QBS23.js.map → signer-MBZZMXTC.js.map} +0 -0
  607. /package/dist/{walk-ZURCH6RZ.js.map → stale-TJ3DYZMQ.js.map} +0 -0
  608. /package/dist/{withdraw-accessible-PXR4IXDX.js.map → storage-SVMKRGCW.js.map} +0 -0
  609. /package/dist/{store-coordination-provider-4WZAIRHC.js.map → store-coordination-provider-2O2VUHKW.js.map} +0 -0
  610. /package/dist/{verify-6MDTIUEV.js.map → verify-RVT67IMH.js.map} +0 -0
@@ -1,34 +1,35 @@
1
1
  import {
2
2
  assertTierAccess
3
- } from "./chunk-UGTBXF5U.js";
3
+ } from "./chunk-SOIQ4MM4.js";
4
4
  import {
5
5
  dekKey
6
- } from "./chunk-JMGDHKQF.js";
6
+ } from "./chunk-JCN44NCY.js";
7
7
  import {
8
8
  applyRewrappedBody,
9
9
  buildRecordAad,
10
10
  recordAadFor,
11
11
  rewrapBodyToDek
12
- } from "./chunk-4ZS56W5S.js";
12
+ } from "./chunk-KJFW62P4.js";
13
13
  import {
14
14
  buildRecordEnvelope,
15
15
  isDeleteMarker,
16
16
  isTombstoneShape
17
- } from "./chunk-SZJ3DLZA.js";
17
+ } from "./chunk-SEE332EV.js";
18
18
  import {
19
19
  decrypt,
20
20
  encrypt,
21
21
  unwrapCek
22
- } from "./chunk-HPVZCW43.js";
22
+ } from "./chunk-UYB234ZR.js";
23
23
  import {
24
24
  NOYDB_FORMAT_VERSION
25
- } from "./chunk-7MG7SJT7.js";
25
+ } from "./chunk-ODVPTDPK.js";
26
26
  import {
27
27
  PersistedIndexCompensationError,
28
28
  TierDemoteDeniedError,
29
29
  TiersNotEnabledError,
30
+ UniqueConstraintError,
30
31
  UnsupportedTierCompositionError
31
- } from "./chunk-7O3Y4PPD.js";
32
+ } from "./chunk-244VXYPG.js";
32
33
 
33
34
  // src/with-audit/tiers/active.ts
34
35
  function withTiers() {
@@ -52,6 +53,11 @@ function withTiers() {
52
53
  async demote(ctx, id, toTier) {
53
54
  const { demote: demote2 } = await import("./tiers/index.js");
54
55
  return demote2(ctx, id, toTier);
56
+ },
57
+ async checkUnique(ctx, id, record) {
58
+ if (!ctx.uniqueKeys) return;
59
+ const { checkUniqueAcrossTiers: checkUniqueAcrossTiers2 } = await import("./tiers/index.js");
60
+ return checkUniqueAcrossTiers2(ctx, id, record);
55
61
  }
56
62
  };
57
63
  }
@@ -72,6 +78,14 @@ var NO_TIERS = {
72
78
  },
73
79
  async demote() {
74
80
  throw new TiersNotEnabledError();
81
+ },
82
+ // NOT a throw, unlike its five siblings: this one is called from the
83
+ // ORDINARY put path of any collection that declared `tiers` — and a
84
+ // collection can declare `tiers` without wiring `withTiers()`. Without the
85
+ // engine no record can ever leave tier 0, so there is nothing above tier 0
86
+ // to scan and the tier-0 mirror is already the whole truth. Throwing here
87
+ // would break plain `put()` on such a collection for no gain.
88
+ async checkUnique() {
75
89
  }
76
90
  };
77
91
 
@@ -121,6 +135,8 @@ async function putAtTier(ctx, id, record, tier, opts) {
121
135
  assertTiersEnabled(ctx);
122
136
  assertDeclaredTier(ctx, tier);
123
137
  assertTierAccess(ctx.keyring, ctx.name, tier);
138
+ await ctx.checkUniqueLocal?.(id, record);
139
+ await checkUniqueAcrossTiers(ctx, id, record);
124
140
  const key = dekKey(ctx.name, tier);
125
141
  const dek = await ctx.getDEK(key);
126
142
  const existing = await ctx.adapter.get(ctx.vault, ctx.name, id);
@@ -210,6 +226,19 @@ async function getAtTier(ctx, id) {
210
226
  }
211
227
  return null;
212
228
  }
229
+ const record = await decryptElevated(ctx, id, envelope, key);
230
+ ctx.emitCrossTierEvent({
231
+ actor: ctx.keyring.userId,
232
+ collection: ctx.name,
233
+ id,
234
+ tier,
235
+ authorization: isElevatorOrOwner(ctx) ? "inherent" : "delegation",
236
+ op: "get",
237
+ ts: (/* @__PURE__ */ new Date()).toISOString()
238
+ });
239
+ return record;
240
+ }
241
+ async function decryptElevated(ctx, id, envelope, key) {
213
242
  const dek = await ctx.getDEK(key);
214
243
  const aad = recordAadFor({ collection: ctx.name, id }, envelope);
215
244
  let plaintext;
@@ -225,17 +254,35 @@ async function getAtTier(ctx, id) {
225
254
  if (envelope._sealed !== void 0) {
226
255
  record = await ctx.codec.applySealedSlots(record, envelope._sealed, cek, { id });
227
256
  }
228
- ctx.emitCrossTierEvent({
229
- actor: ctx.keyring.userId,
230
- collection: ctx.name,
231
- id,
232
- tier,
233
- authorization: isElevatorOrOwner(ctx) ? "inherent" : "delegation",
234
- op: "get",
235
- ts: (/* @__PURE__ */ new Date()).toISOString()
236
- });
237
257
  return record;
238
258
  }
259
+ async function checkUniqueAcrossTiers(ctx, id, record) {
260
+ const keysOf = ctx.uniqueKeys;
261
+ if (!keysOf || !ctx.tiers) return;
262
+ const mine = keysOf(record);
263
+ if (mine.length === 0) return;
264
+ for (const otherId of await ctx.adapter.list(ctx.vault, ctx.name)) {
265
+ if (otherId === id || otherId.startsWith("_")) continue;
266
+ const env = await ctx.adapter.get(ctx.vault, ctx.name, otherId);
267
+ if (!env) continue;
268
+ const tier = env._tier ?? 0;
269
+ if (tier === 0) continue;
270
+ const key = dekKey(ctx.name, tier);
271
+ if (!ctx.keyring.deks.has(key)) continue;
272
+ let other;
273
+ try {
274
+ other = await decryptElevated(ctx, otherId, env, key);
275
+ } catch {
276
+ continue;
277
+ }
278
+ const theirs = new Map(keysOf(other).map((k) => [`${k.fields.join("\0")}\0${k.key}`, k]));
279
+ for (const k of mine) {
280
+ if (theirs.has(`${k.fields.join("\0")}\0${k.key}`)) {
281
+ throw new UniqueConstraintError(ctx.name, id, k.fields, otherId);
282
+ }
283
+ }
284
+ }
285
+ }
239
286
  async function listAtTier(ctx) {
240
287
  assertTiersEnabled(ctx);
241
288
  const ids = await ctx.adapter.list(ctx.vault, ctx.name);
@@ -430,9 +477,10 @@ export {
430
477
  syncDerivedOutputs,
431
478
  putAtTier,
432
479
  getAtTier,
480
+ checkUniqueAcrossTiers,
433
481
  listAtTier,
434
482
  elevate,
435
483
  demote,
436
484
  classifySealedShred
437
485
  };
438
- //# sourceMappingURL=chunk-M4YPHYEH.js.map
486
+ //# sourceMappingURL=chunk-UPD5NWI5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/with-audit/tiers/active.ts","../src/with-audit/tiers/strategy.ts","../src/with-audit/tiers/index.ts"],"sourcesContent":["/**\n * Enable the hierarchical-tiers capability.\n * Pass to `createNoydb({ tiersStrategy: withTiers() })` to make a collection's\n * `putAtTier` / `getAtTier` / `listAtTier` / `elevate` / `demote` methods live.\n * The tier read/write/re-key engine is dynamically imported here, so it stays\n * out of the floor bundle until opted in.\n */\nimport type { TiersStrategy } from './strategy.js'\n\nexport function withTiers(): TiersStrategy {\n return {\n async putAtTier(ctx, id, record, tier, opts) {\n const { putAtTier } = await import('./index.js')\n return putAtTier(ctx, id, record, tier, opts)\n },\n async getAtTier(ctx, id) {\n const { getAtTier } = await import('./index.js')\n return getAtTier(ctx, id)\n },\n async listAtTier(ctx) {\n const { listAtTier } = await import('./index.js')\n return listAtTier(ctx)\n },\n async elevate(ctx, id, toTier) {\n const { elevate } = await import('./index.js')\n return elevate(ctx, id, toTier)\n },\n async demote(ctx, id, toTier) {\n const { demote } = await import('./index.js')\n return demote(ctx, id, toTier)\n },\n async checkUnique(ctx, id, record) {\n // Skip the dynamic import entirely on the overwhelmingly common case:\n // a tiered collection with no `unique` index declared.\n if (!ctx.uniqueKeys) return\n const { checkUniqueAcrossTiers } = await import('./index.js')\n return checkUniqueAcrossTiers(ctx, id, record)\n },\n }\n}\n","/**\n * Tiers capability strategy — the five on-demand collection-level tier\n * operations the `Collection` routes through. The active engine\n * ({@link withTiers}) dynamically imports the tier cores (keeping them out of\n * the floor bundle); {@link NO_TIERS} throws. Collection always builds its\n * per-call {@link TiersContext} and delegates here, so an un-opted-in caller\n * hits `NO_TIERS`'s throw.\n * @internal\n */\nimport type { GhostRecord } from '../../kernel/types.js'\nimport type { TiersContext, TierMoveResult } from './index.js'\nimport { TiersNotEnabledError } from '../../kernel/errors.js'\n\n// #779 — re-exported so kernel-spine callers (e.g. `Vault._elevatedPut`) can reference the\n// result shape via this grandfathered strategy.js seam instead of statically importing\n// tiers/index.js directly (the port-layering check only grandfathers this file).\nexport type { TierMoveResult }\n\nexport interface TiersStrategy {\n putAtTier<T>(\n ctx: TiersContext<T>,\n id: string,\n record: T,\n tier: number,\n opts?: { elevation?: { reason: string; fromTier: number }; source?: string; sourceTs?: string },\n ): Promise<TierMoveResult>\n getAtTier<T>(ctx: TiersContext<T>, id: string): Promise<T | GhostRecord | null>\n listAtTier<T>(ctx: TiersContext<T>): Promise<Array<{ id: string; tier: number; readable: boolean }>>\n elevate<T>(ctx: TiersContext<T>, id: string, toTier: number): Promise<TierMoveResult>\n demote<T>(ctx: TiersContext<T>, id: string, toTier: number): Promise<TierMoveResult>\n /**\n * #1358 — unique-constraint scan across every tier whose DEK the writer\n * holds. Called by the ORDINARY `Collection.put()` on a tiered collection\n * (`putAtTier` calls the core directly): the tier-0 mirror cannot see an\n * elevated record, because #709 purges its index entries on elevation.\n * A tier the writer cannot read is outside the guarantee.\n */\n checkUnique<T>(ctx: TiersContext<T>, id: string, record: T): Promise<void>\n}\n\n/**\n * No-op stub — the floor default. Every capability method throws\n * {@link TiersNotEnabledError}; opt in with `tiersStrategy: withTiers()` in\n * createNoydb. @internal\n */\nexport const NO_TIERS: TiersStrategy = {\n async putAtTier() { throw new TiersNotEnabledError() },\n async getAtTier() { throw new TiersNotEnabledError() },\n async listAtTier() { throw new TiersNotEnabledError() },\n async elevate() { throw new TiersNotEnabledError() },\n async demote() { throw new TiersNotEnabledError() },\n // NOT a throw, unlike its five siblings: this one is called from the\n // ORDINARY put path of any collection that declared `tiers` — and a\n // collection can declare `tiers` without wiring `withTiers()`. Without the\n // engine no record can ever leave tier 0, so there is nothing above tier 0\n // to scan and the tier-0 mirror is already the whole truth. Throwing here\n // would break plain `put()` on such a collection for no gain.\n async checkUnique() { /* no tier engine ⇒ every record is at tier 0 */ },\n}\n","/**\n * Hierarchical access — the collection-level tier operations\n * (`putAtTier` / `getAtTier` / `listAtTier` / `elevate` / `demote`).\n *\n * A collection opted into `{ tiers: [...] }` stamps `_tier: N` on each envelope\n * and encrypts its body under the tier-N DEK. These helpers are the read/write\n * surface for that scheme: write at a tier, read with tier-aware visibility\n * (invisibility vs. ghost), and move a record up (`elevate`) or down (`demote`)\n * the tier ladder by re-wrapping its body key.\n *\n * Each function takes a small {@link TiersContext} (the exact `this.*` the\n * moving methods touched) instead of `this`, mirroring the `record-keys/`\n * siblings. Behaviour is byte-identical to the inline code it replaced.\n *\n * The crux is `cekCache`: `elevate`/`demote`/`getAtTier` write the SAME `Lru`\n * reference `Collection` owns (never a copy) so a per-record CEK re-wrap stays\n * synchronous with the cache the kernel's write/read path also mutates. The\n * cross-tier event sink stays collection-resident and is reached via the\n * `emitCrossTierEvent` callback.\n *\n * Internal service — not exported as a `@noy-db/hub/*` subpath.\n */\nexport { withTiers } from './active.js'\nexport { NO_TIERS, type TiersStrategy } from './strategy.js'\nexport { TiersNotEnabledError } from '../../kernel/errors.js'\nimport { recordAadFor, type RecordIdentity, buildRecordAad, buildRecordEnvelope, encrypt, decrypt, unwrapCek, rewrapBodyToDek, applyRewrappedBody, isDeleteMarker, isTombstoneShape, type RecordCodec, type EnclaveKey, type SealedShredSlot } from '../../kernel/enclave/index.js'\nimport { TierDemoteDeniedError, UnsupportedTierCompositionError, PersistedIndexCompensationError, UniqueConstraintError } from '../../kernel/errors.js'\nimport { dekKey, assertTierAccess } from '../../with-party/team/tiers.js'\nimport type { UnlockedKeyring } from '../../with-party/team/keyring.js'\nimport type { Lru } from '../../kernel/cache/index.js'\nimport type { BlobFieldsConfig } from '../../with-shape/blobs/blob-compaction.js'\nimport {\n NOYDB_FORMAT_VERSION,\n type NoydbStore,\n type EncryptedEnvelope,\n type GhostRecord,\n type TierMode,\n type CrossTierAccessEvent,\n} from '../../kernel/types.js'\n\n/** Everything the moving tier methods touched on `this.*`, as a flat context. */\nexport interface TiersContext<T> {\n /** Collection name — the crypto AAD scope and tier-DEK key prefix. */\n readonly name: string\n /** Vault namespace the records live under. */\n readonly vault: string\n /** The ciphertext store. */\n readonly adapter: NoydbStore\n /**\n * #1358 — the unique-constraint keys a record occupies, or `[]` when the\n * record is exempt (null-distinct) . `undefined` when the collection\n * declares no `unique` index, which is what makes the tier scan free for\n * every other collection. Deliberately a plain callback rather than the\n * `UniqueConstraintSet` itself: the tier domain must not import the\n * indexing domain, and this is the whole of what it needs.\n */\n readonly uniqueKeys?: ((record: unknown) => ReadonlyArray<{ readonly fields: readonly string[]; readonly key: string }>) | undefined\n /**\n * #1358 — the collection's own tier-0 unique pre-flight (the eager map or\n * the lazy `_idx/` probe). `putAtTier` runs it before its write because it\n * bypasses `Collection.put()` entirely; the tier-0 `put()` path calls it\n * directly and does not need this. `undefined` ⇒ no unique index declared.\n */\n readonly checkUniqueLocal?: ((id: string, record: unknown) => Promise<void>) | undefined\n /** The caller's unlocked keyring (tier-DEK holdings + role + userId). */\n readonly keyring: UnlockedKeyring\n /** The record codec — decrypts a tier-0 envelope to T. */\n readonly codec: RecordCodec<T>\n /**\n * The collection's per-record CEK cache (SHARED reference, not a copy).\n * `elevate`/`demote`/`getAtTier` re-wrap a record's CEK and `set` it here so\n * the move stays synchronous with the cache the kernel's read/write path\n * owns. `null` → no caching.\n */\n readonly cekCache: Lru<string, EnclaveKey> | null\n /**\n * Sync the collection's decoded-record cache after a tier move rewraps the\n * envelope (#691). The lazy LRU is evicted on EVERY call — it is never\n * re-seeded, since a lazy `#getRaw` miss refetches and decodes the fresh\n * envelope via its adapter fallback (a stale LRU entry after a tier-0\n * `putAtTier` overwrite was the #702 lazy-mode gap). `null` → also evict\n * the eager cache entry; an `entry` → set the eager cache to the given\n * decoded record/version (used by `demote()` landing back at tier 0 and\n * `putAtTier`'s tier-0 write, #702 — the record is tier-0, so it must stay\n * plain-`get()`-readable in-session).\n */\n syncCache(id: string, entry: { record: T; version: number } | null): void\n /**\n * Sync the collection's indexes after a tier move rewraps the envelope\n * (#709). Persisted `_idx/<field>/<recordId>` side-cars hold the indexed\n * field's PLAINTEXT value and are always encrypted under the tier-0 DEK,\n * whatever the record's own tier — the same leak class `forget()` fixed\n * via `purgePersistedIndexes` (\"forget() crypto-shreds the body but keeps\n * the collection DEK, under which these side-cars are encrypted — so\n * without this they leave the indexed field VALUES readable\"). `null` →\n * the record just left tier 0: purge its persisted side-cars and drop its\n * in-memory index entries. A record → it is tier-0 again: (re)build its\n * entries from that record. Call this BEFORE {@link syncCache} — the\n * implementation reads the pre-write cached value as \"previous\" to clean\n * up stale index buckets, so it must run while that entry is still live.\n * `version` stamps a rebuilt side-car's own envelope version — every\n * caller has one in scope (the envelope it just wrote), including the\n * purge (`null`) branches, which pass it along even though it's ignored\n * there (#720: keeps the parameter honestly required, no dead default).\n * `priorEnvelope` (#720) — the RAW envelope read BEFORE this call's own\n * overwrite (already in scope as `existing`/`envelope` at every record-\n * branch call site), so a lazy same-tier value change (a `putAtTier(0)`\n * dropping an indexed field, a `demote(0)` off an elevated record) can\n * still be tier-gate-decoded as \"previous\" once the live envelope itself\n * has already moved past it. The `null`-record branches never pass one —\n * see the implementation's doc comment for why they don't need to.\n */\n syncIndexes(id: string, record: T | null, version: number, priorEnvelope?: EncryptedEnvelope): Promise<void>\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`, and\n * invalidate the `_ftindex` blob (the cache-driven rebuild then excludes\n * it). A record → it is tier-0 again: re-embed it, and invalidate\n * `_ftindex` (rebuild includes it). No-op fast when the collection has no\n * search. */\n syncSearch(id: string, record: T | null, version?: number): Promise<void>\n /**\n * Sync a record's `_history` snapshots after a tier move rewraps the live\n * envelope (#712, at-rest hardening). Each snapshot carries its own key\n * material (a direct DEK wrap, or a per-record `_cek` itself wrapped under\n * the tier DEK) — `elevate()`'s live-body rewrap moves only the live\n * envelope, leaving prior versions decryptable at rest under the tier the\n * record has moved away from (the same leak class `forget()`'s\n * `tombstoneHistory` closed for erasure). `fromDek`/`toDek` are the SAME\n * DEKs the caller already resolved for the live rewrap — reuse them, don't\n * recompute. No-op when the strategy is `NO_HISTORY`.\n */\n syncHistory(id: string, fromDek: EnclaveKey, toDek: EnclaveKey): Promise<void>\n /**\n * Save a raw pre-move envelope as a `_history` snapshot (#728). Tier moves\n * (`putAtTier`/`elevate`/`demote`) bump `_v` and overwrite the live\n * envelope without ever snapshotting the version that existed just before\n * the move — so `history()` silently lost it. The caller (`tiers/index.ts`)\n * builds `envelope` by reusing the SAME `rewrapBodyToDek(envelope, fromDek,\n * toDek)` result it already computed for the live write, so the snapshot\n * lands wrapped under the DESTINATION tier's DEK — never `ctx.codec.\n * encryptRecord`, which always resolves the tier-0 DEK and would leak the\n * pre-move body whenever `fromTier > 0`. No-op when history is disabled\n * (folds the `historyConfig.enabled` gate so `tiers/index.ts` stays simple).\n */\n /**\n * Persist a `_history` snapshot of `version`, sealed against the address it\n * will be STORED at (#1041).\n *\n * Takes a **sealer**, not a finished envelope, because the destination\n * identity is not knowable here: only the history strategy owns the\n * `_history` layout. It hands the address in; the caller seals to it.\n *\n * ⚠️ The identity passed to `rewrapBodyToDek` must be what a READER will\n * recompute — `recordAadFor(address, finalEnvelope)`. A tier-move snapshot\n * strips `_tier`/`_elevatedBy` but KEEPS `_by`, so the destination is\n * `{...address, by: envelope._by}` with no tier. Sealing against the bare\n * address would produce history nothing can open, and the failure would\n * surface only when someone reads it.\n */\n saveHistorySnapshot(\n id: string,\n version: number,\n seal: (address: RecordIdentity) => Promise<EncryptedEnvelope>,\n ): Promise<void>\n /**\n * `true` iff a real history strategy is wired (not `NO_HISTORY`) AND not\n * explicitly disabled via `historyConfig.enabled`. `putAtTier` checks this\n * BEFORE decrypting `existing` to build a snapshot (#728, #737 regression\n * fix) — unlike elevate/demote, which reuse a `body` rewrap their live\n * write needs unconditionally, putAtTier's live write never decrypts the\n * prior envelope, so building a snapshot is the ONLY reason it would\n * touch (and potentially throw decrypting) `existing`'s ciphertext. A\n * derivation-free, history-disabled collection must not pay that decode —\n * or risk it, on a corrupted/inaccessible prior body — same law\n * `hasDerivedOutputs` already enforces for the derived-outputs decode.\n */\n readonly historyEnabled: boolean\n /**\n * Rehome a record's blob attachments after a tier move (#724 Arc 10 Task\n * 2, at-rest hardening). A blob's home tier is its owning record's tier —\n * the `_blob` DEK is tier-scoped (`dekKey('_blob', tier)`), so a solo-\n * owned blob's content CEK must move with the record or it stays\n * tier-0-unwrappable at rest even once the live body has moved (the same\n * leak class `syncHistory` closes for `_history` snapshots). Delegates to\n * `BlobSet.rehomeForTier`; no-op fast when the collection has no blob\n * fields. Order-independent with the other sync hooks — touches only\n * blob side structures, not this collection's own cache/indexes.\n */\n syncBlobs(id: string, fromTier: number, toTier: number): Promise<void>\n /**\n * Purge a record's tier-0-era plaintext ledger deltas after a tier move\n * lands it above tier 0 (#729). The audit ledger is a flat, vault-wide,\n * hash-chained log — a record's reverse-JSON-Patch deltas in\n * `_ledger_deltas` are encrypted under one collection-wide `_ledger` DEK\n * (not the record's own tier DEK), so `elevate()`/`putAtTier()`'s live-body\n * rewrap never moves them: they stay readable at rest to any tier-0\n * caller, the same leak class `syncHistory` closed for `_history`\n * snapshots. Chain-safe: `verify()` reads only `_ledger` entry fields\n * (including `deltaHash`, which lives on the entry, not the deleted delta\n * row), never `_ledger_deltas`, so a purge cannot break it.\n * **Irreversible** — the deleted plaintext cannot be restored by\n * `demote()`. **Metadata-retained** — the `_ledger` entries (that the\n * record was mutated, at which version/timestamp/actor) are untouched;\n * only the delta *content* is purged. No-op when the collection has no\n * ledger (`withHistory()` not enabled).\n */\n syncLedger(id: string): Promise<void>\n /**\n * Sync a record's derived outputs (materialized-view rows, rollup\n * contributions, `withDerivation` outputs) after a tier move (#722).\n * Those outputs are computed from this record and written to OTHER\n * (output) collections via a plain `put` at tier 0 — `elevate()`'s live-\n * body rewrap moves only the source envelope, so the output rows keep\n * holding the source's tier-0-era plaintext, the same leak class\n * `syncSearch`/`syncIndexes` closed for THIS collection's own artifacts.\n * `elevated` (landing tier > 0) reuses the SAME onDelete fanout\n * `forgetDerivedFanout` drives for `forget()` (`kernel/via/dispatch.ts`)\n * — minus its `'ref'` cascade edge (elevate/demote never erase a\n * *different* record) — to recompute this record's derived outputs as\n * REMOVED. Recompute is tier-safe: the fanout's own source scan reads\n * the elevated-excluding cache (#701/#709/#712), so it naturally omits\n * the now-elevated record instead of re-embedding its plaintext. Landing\n * back at tier 0 (`elevated === false`) is the reverse (Task 2, #722):\n * `syncDerivedOutputs` instead runs the ordinary local-write add-\n * dispatchers (`dispatchDerivations`/`dispatchMaterializedViews`, the\n * same ones a plain `put()` fires) to restore the contribution —\n * reversible, since the source's plaintext survives the elevate/demote\n * rewrap round-trip. `record` is the decoded source record (PRE-move on\n * the remove side, POST-move on the add side); only the rollup edge\n * consumes it on remove, both add-dispatchers require it on add; `null`\n * (tombstone/delete-marker) skips both. `version` stamps the add-\n * dispatchers' `_derivedFrom.sourceVersion` metadata — reuses the version\n * the tier op already has, no re-read; unused on the remove side. No-op\n * fast when the collection has no MV/derivation source — each dispatcher\n * below checks its own source before doing any work.\n */\n syncDerived(id: string, record: T | null, elevated: boolean, version?: number): Promise<void>\n /**\n * `true` iff the collection has a materialized-view or derivation source\n * attached. Gates the {@link syncDerived} pre-move decode on the remove\n * direction (`elevate()`, `putAtTier(tier>0)`, `demote()`'s intermediate-\n * tier branch): those sites decode the record SOLELY to feed\n * `syncDerived(..., true)`, whose dispatchers no-op immediately when the\n * collection has no MV/derivation source — so a no-derivation collection\n * would otherwise pay a full record-body decrypt on every tier move for\n * nothing (#722 perf regression). `false` short-circuits the decode to\n * `null`, which `syncDerivedOutputs` already treats safely.\n */\n readonly hasDerivedOutputs: boolean\n /** Emit `_source`/`_sourceTs` provenance fields when a source is supplied. */\n readonly provenance: boolean\n /** Declared tiers, or null when the feature is off. */\n readonly tiers: ReadonlySet<number> | null\n /** Above-tier read visibility mode (`'invisibility'` | `'ghost'`). */\n readonly tierMode: TierMode\n /** Resolve a tier DEK by its `dekKey(name, tier)`. */\n getDEK(key: string): Promise<EnclaveKey>\n /** Fire a cross-tier access event (sink stays collection-resident). */\n emitCrossTierEvent(event: CrossTierAccessEvent): void\n /**\n * Register this record's ref in the encrypted `_subject_index` (#766).\n * `putAtTier`'s raw `ctx.adapter.put` bypasses `Collection.put()`'s write-\n * hook pipeline — the `onAfterWrite` hook that normally does this — so a\n * record whose FIRST persistence is `putAtTier` (sensitive from birth, a\n * documented legitimate use) would otherwise never enter the index and\n * stay unreachable by `vault.forget()`. Idempotent (safe on every call,\n * including a repeat write of an already-registered record) and a no-op\n * when the collection declares no forget-subject field.\n */\n addSubjectRef(id: string, record: T): Promise<void>\n}\n\nexport function assertTiersEnabled<T>(ctx: TiersContext<T>): void {\n if (!ctx.tiers) {\n throw new Error(\n `Collection \"${ctx.name}\": hierarchical tiers are not enabled. ` +\n `Pass { tiers: [0, 1, 2, …] } to vault.collection() to opt in.`,\n )\n }\n}\n\nexport function assertDeclaredTier<T>(ctx: TiersContext<T>, tier: number): void {\n if (tier < 0 || !Number.isInteger(tier)) {\n throw new Error(`Collection \"${ctx.name}\": tier must be a non-negative integer, got ${tier}`)\n }\n if (tier === 0) return\n if (!ctx.tiers || !ctx.tiers.has(tier)) {\n throw new Error(\n `Collection \"${ctx.name}\": tier ${tier} is not declared in { tiers: [...] }`,\n )\n }\n}\n\n/**\n * Tier-composition guard (#724 / Arc 7 of the tier-invisibility campaign).\n *\n * Refuses `tiers` declared together with a derived-artifact feature whose\n * crypto has not yet been made tier-aware — i.e. a feature `elevate()` /\n * `demote()` does not re-key when a record moves tiers, so an elevated\n * record's data for that feature would stay readable at tier 0.\n *\n * **Status:** the original call site (`Collection` constructor, beside\n * `buildUniqueConstraintSet`) was removed by Arc 10 Task 1 (#724) — the\n * `tiers + blobFields` refusal below was superseded by a runtime read gate\n * on `collection.blob(id)` (`with-shape/blobs/blob-set.ts`), so this\n * function currently has no caller. Relocated here from\n * `with-lookup/indexing/unique-constraints.ts` (#733) so the tier-domain\n * guard lives in the tier domain, rather than an indexing file it only\n * borrowed for a grandfathered import specifier.\n *\n * ## #724 verified: `tiers + blobFields` leaks\n *\n * `collection.blob(id)` (`Collection.blob()`) never checks the live\n * record's tier before returning a `BlobSet` handle, and `BlobSet`'s crypto\n * is entirely orthogonal to the tier ladder:\n * - the slot map (`_blob_slots_{collection}/{id}`) is encrypted under the\n * collection's TIER-0 DEK (`getDEK(name)` ≡ `dekKey(name, 0)` — see\n * `dekKey` in `with-party/team/tiers.ts`), never a tier-N DEK;\n * - chunk content (`_blob_index` / `_blob_chunks`) is encrypted under the\n * vault-shared `_blob` DEK (`BLOB_COLLECTION`), which has no tier\n * dimension at all.\n * `elevate()`/`demote()` (this file) rewrap only the live record body,\n * `_history` snapshots (#712), and index side-cars — blob slots and chunks\n * are untouched. A caller whose keyring never held the record's elevated\n * tier DEK can still open `collection.blob(id).get(slot)` and read full\n * plaintext, even though `collection.get(id)` correctly reports the same\n * record as invisible. See `__tests__/tier-composition-guard.test.ts` for\n * the reproduction.\n *\n * ## Safe today — no check needed here\n *\n * Field indexes, search (`textIndexes`/`embeddings`), `withHistory`\n * (snapshot keys are rewrapped by `elevate()`/`demote()`, #712), and the\n * decoded-record cache (evicted on tier moves) are already tier-safe. They\n * are not enumerated below; only known-unsafe features are refused, so any\n * combination not named here passes silently by default.\n *\n * ## Deliberately NOT handled here\n *\n * - `ledger` — `withHistory` threads a ledger writer onto every tiered\n * collection by default in shipped usage; refusing `tiers + ledger` would\n * break that default. A ledger-specific tier-rekey handler (rewrap ledger\n * entries, or scope ledger visibility to tier) is a separate arc.\n * - materialized-view (MV) output — an MV's fanout spec lives on the\n * SOURCE collection, not on the MV collection's own config, so it is not\n * visible at `vault.collection()` registration time and this guard cannot\n * detect it structurally.\n */\nexport function assertTierComposition(\n collectionName: string,\n cfg: { readonly tiers: boolean; readonly blobFields: BlobFieldsConfig | undefined },\n): void {\n if (!cfg.tiers) return\n if (cfg.blobFields !== undefined && Object.keys(cfg.blobFields).length > 0) {\n throw new UnsupportedTierCompositionError(\n 'blobs',\n `Collection \"${collectionName}\": blobFields are not supported together with tiers (#724) — ` +\n `blob chunk content is encrypted under a vault-shared DEK that elevate()/demote() do not ` +\n `re-key, so an elevated record's blob attachments would remain readable at tier 0. Use a ` +\n `non-tiered collection for blob-bearing records until a blob tier-rekey handler ships.`,\n )\n }\n}\n\nfunction isElevatorOrOwner<T>(ctx: TiersContext<T>): boolean {\n return ctx.keyring.role === 'owner' || ctx.keyring.role === 'admin'\n}\n\n/**\n * Structural surface {@link syncDerivedOutputs} needs from the owning\n * collection — the SAME onDelete dispatchers `forgetDerivedFanout` already\n * drives (`kernel/via/dispatch.ts`), reused as-is (#722). Narrower than\n * `Collection<T>` (avoids an import cycle: collection.ts constructs\n * `TiersContext` FROM `this`, which already satisfies this shape\n * structurally — no cast needed at the `tiersContext()` call site).\n */\nexport interface DerivedOutputsHost<T> {\n dispatchMaterializedViewsOnDelete(id: string): Promise<{ deleted: number; residueUndecodable: string[]; residueDeclined: string[] }>\n dispatchArrayDerivationsOnDelete(id: string, eraseRecordShapeToo?: boolean): Promise<number>\n dispatchRollupsOnDelete(id: string, deleted: T): Promise<unknown>\n /** Task 2 (#722) add-direction: the same local-write dispatchers an ordinary `put()` fires. */\n dispatchMaterializedViews(id: string, record: T): Promise<void>\n dispatchDerivations(id: string, record: T, version: number): Promise<void>\n}\n\n/**\n * The {@link TiersContext.syncDerived} implementation collection.ts's\n * `tiersContext()` binds `this` into (#722). See that field's doc comment\n * for the design; `host` is `this` — every dispatcher below is a public\n * Collection method, already self-guarding (no-op) when the collection has\n * no materialized-view/derivation source, so no separate fast-path check is\n * needed here.\n */\nexport async function syncDerivedOutputs<T>(\n host: DerivedOutputsHost<T>,\n id: string,\n record: T | null,\n elevated: boolean,\n version?: number,\n): Promise<void> {\n if (elevated) {\n await host.dispatchMaterializedViewsOnDelete(id)\n await host.dispatchArrayDerivationsOnDelete(id, true)\n if (record !== null) await host.dispatchRollupsOnDelete(id, record)\n return\n }\n // Task 2 (#722) recompute-as-add: the record rejoined tier 0 (demote(→0) /\n // putAtTier(0)) — restore its contribution via the SAME local-write\n // dispatchers an ordinary `put()` fires (`collection.ts`'s\n // `_onRecordMutated('local-write')`), same order. `record === null` only\n // when a caller demotes a tombstone/delete-marker to 0 — nothing to add.\n if (record === null) return\n await host.dispatchDerivations(id, record, version ?? 0)\n await host.dispatchMaterializedViews(id, record)\n}\n\n/**\n * tier-aware put. Encrypts the record with the collection's tier-N DEK and\n * stamps `_tier: N` on the envelope. The caller's keyring must hold the tier-N\n * DEK (directly, by delegation, or by virtue of being the grantor); otherwise\n * throws `TierNotGrantedError`.\n *\n * accepts an optional `elevation` context. When present, the emitted cross-tier\n * event is stamped with `authorization: 'elevation'`, the elevation's reason,\n * and the caller's pre-elevation tier. `vault.elevate(...).collection().put`\n * threads this through; direct `putAtTier` calls leave it undefined and fall\n * back to the inherent-write event shape.\n */\nexport async function putAtTier<T>(\n ctx: TiersContext<T>,\n id: string,\n record: T,\n tier: number,\n opts?: { elevation?: { reason: string; fromTier: number }; source?: string; sourceTs?: string },\n): Promise<TierMoveResult> {\n assertTiersEnabled(ctx)\n assertDeclaredTier(ctx, tier)\n assertTierAccess(ctx.keyring, ctx.name, tier)\n\n // #1358: `putAtTier` is the \"separate path that bypasses unique\n // enforcement\" the old registration-time refusal named. Both halves run\n // here, BEFORE any key resolution or write, so a violation leaves nothing\n // behind: the tier-0 mirror check the collection owns, then the scan of\n // every above-tier record this writer can decrypt.\n await ctx.checkUniqueLocal?.(id, record)\n await checkUniqueAcrossTiers(ctx, id, record)\n\n const key = dekKey(ctx.name, tier)\n const dek = await ctx.getDEK(key)\n\n const existing = await ctx.adapter.get(ctx.vault, ctx.name, id)\n // #712/whole-branch-fix-1: putAtTier moves the record OFF its existing\n // tier, same as elevate/demote — so the caller must also be cleared for\n // that existing tier, not just the target. Without this, a member holding\n // only the target tier's DEK could putAtTier over a record parked at a\n // tier they've never been granted; the from-tier `getDEK` below would then\n // silently MINT a fresh DEK for that tier into their keyring (a\n // non-cleared caller creating tier key material inside the trust\n // boundary — see `assertTierAccess`'s doc comment). Gate here, BEFORE any\n // from-tier getDEK/syncHistory call, so the mint never happens; owner/\n // admin/custodian still bypass (they may mint, same as elevate/demote).\n assertTierAccess(ctx.keyring, ctx.name, existing?._tier ?? 0)\n const version = existing ? existing._v + 1 : 1\n\n // #728 review-fix-2: resolve the from-tier DEK and snapshot the PRE-move\n // version BEFORE the live write below, mirroring elevate()/demote() —\n // originally this ran much later (after syncIndexes/syncLedger/syncDerived/\n // syncSearchResilient), so a throw in any of those left the live record\n // already moved with `existing` — its sole pre-move copy — gone, silently\n // losing the version #728 exists to preserve. `fromKey`/`fromDek` are\n // resolved ONCE here and reused below for the trailing syncHistory rewrap.\n const fromKey = dekKey(ctx.name, existing?._tier ?? 0)\n const fromDek = await ctx.getDEK(fromKey)\n if (existing && ctx.historyEnabled) {\n // Snapshot the version this write is about to overwrite — same law as\n // Collection.put()'s history save, extended to putAtTier (#728). Rewrap\n // under the DESTINATION `dek` via `applyRewrappedBody` (never\n // `ctx.codec.encryptRecord`, which always resolves the tier-0 DEK and\n // would leak this body at rest whenever the prior tier was > 0).\n // Untagged (`_tier`/`_elevatedBy` stripped), same as elevate()/\n // demote()'s snapshots. `_v` stays the PRE-move version (unbumped), as\n // `preCarried` already carries it.\n const preFrom: RecordIdentity = {\n // The PRE-move version — this identity opens what is already stored.\n collection: ctx.name, id, version: existing._v,\n ...(existing._tier !== undefined ? { tier: existing._tier } : {}),\n ...(existing._by !== undefined ? { by: existing._by } : {}),\n }\n await ctx.saveHistorySnapshot(id, existing._v, async (address) => {\n // The snapshot is UNTAGGED (`_tier` stripped) and keeps `_by`, so that is\n // the identity a reader will recompute from it (#1041).\n const to: RecordIdentity = { ...address, ...(existing._by !== undefined ? { by: existing._by } : {}) }\n const body = await rewrapBodyToDek(preFrom, to, existing, fromDek, dek)\n // eslint-disable-next-line @typescript-eslint/no-unused-vars -- excluded from ...preCarried\n const { _tier: _preTier, _elevatedBy: _preElevatedBy, ...preCarried } = existing\n return applyRewrappedBody(preCarried, body)\n })\n }\n\n const json = JSON.stringify(record)\n const identity = { collection: ctx.name, id, version, by: ctx.keyring.userId, ...(tier > 0 ? { tier } : {}) }\n const { iv, data } = await encrypt(json, dek, buildRecordAad(identity))\n const envelope = buildRecordEnvelope(\n identity,\n {\n iv,\n data,\n // `_tier` is stamped from `identity.tier` above — the single source.\n ...(ctx.provenance && opts?.source !== undefined\n ? { provenance: { source: opts.source, sourceTs: opts.sourceTs ?? new Date().toISOString() } }\n : {}),\n },\n )\n\n await ctx.adapter.put(ctx.vault, ctx.name, id, envelope)\n\n // #766: putAtTier bypasses Collection.put()'s onAfterWrite hook — register\n // the subject ref directly so a sensitive-from-birth first write stays\n // reachable by vault.forget(). No-op when no forget-subject field is declared.\n await ctx.addSubjectRef(id, record)\n\n // #702/#709: keep the record cache AND indexes coherent with the raw\n // write — same law as elevate/demote (#691): tier > 0 → invisible on\n // tier-0 surfaces (evict + purge); tier 0 → an ordinary write (re-seed +\n // reindex). syncIndexes runs first — it needs the pre-write cache entry\n // as \"previous\", which syncCache is about to overwrite/evict.\n if (tier > 0) {\n await ctx.syncIndexes(id, null, version)\n ctx.syncCache(id, null)\n // #729: the record lands above tier 0 — purge its tier-0-era plaintext\n // ledger deltas (irreversible; a tier-0 putAtTier(0) has nothing to purge).\n await ctx.syncLedger(id)\n // #722: recompute this record's derived outputs now that it left tier 0\n // — same law as elevate() below. `existing` is the PRE-write envelope;\n // decode it only here (the rollup edge is the only consumer). Gated by\n // `hasDerivedOutputs` — no-derivation collections skip this decrypt\n // entirely (perf regression review finding, Arc 9 #722). Whole-branch\n // review: `existing` may sit at ANY prior tier (including a\n // `putAtTier`-origin tier>0 record with no `_cek` ever minted) — decode\n // it under ITS OWN tier's DEK via `codec.decryptRecordAtDek`, not\n // `ctx.codec.decryptRecord`'s tier-unaware default, which threw\n // `TamperedError` here.\n await ctx.syncDerived(\n id,\n ctx.hasDerivedOutputs && existing\n ? await ctx.codec.decryptRecordAtDek({ collection: ctx.name, id }, existing, await ctx.getDEK(dekKey(ctx.name, existing._tier ?? 0)))\n : null,\n true,\n )\n } else {\n const rec = await ctx.codec.decryptRecord({ collection: ctx.name, id }, envelope, { sealedAsHandles: true })\n await ctx.syncIndexes(id, rec, envelope._v, existing ?? undefined)\n ctx.syncCache(id, rec !== null ? { record: rec, version: envelope._v } : null)\n // #722 Task 2: the record is written at tier 0 — restore its\n // contribution to every derived output (reuse the decode above, no\n // double-decrypt).\n await ctx.syncDerived(id, rec, false, envelope._v)\n }\n // #721: search artifacts follow the same tier > 0 → purge / tier 0 →\n // re-embed law as syncIndexes above. No ordering dependency on syncCache —\n // the _ftindex rebuild is deferred to the next retrieve() and _vec re-embed\n // reads `record` directly, not the cache. #774: a permanently stuck\n // compensation must not abort the write — the record put above already\n // landed — so it is caught and surfaced as residue instead, same as\n // elevate()/demote() (#764).\n const searchResidue = await syncSearchResilient(ctx, id, tier > 0 ? null : record, envelope._v)\n\n if (tier > 0) {\n ctx.emitCrossTierEvent({\n actor: ctx.keyring.userId,\n collection: ctx.name,\n id,\n tier,\n authorization: opts?.elevation ? 'elevation' : 'inherent',\n op: 'put',\n ts: envelope._ts,\n ...(opts?.elevation && {\n reason: opts.elevation.reason,\n elevatedFrom: opts.elevation.fromTier,\n }),\n })\n }\n\n // #712/whole-branch-fix-2: syncHistory runs LAST — after syncIndexes/\n // syncCache/syncSearch (and the cross-tier emit) have already landed. Its\n // own throw (adapter I/O, the Fix-1 assertion, the rewrap) then strands\n // only the `_history` artifact instead of leaving indexes/cache/search\n // unsynced behind an already-moved live record (would conditionally\n // reopen #709/#721/#723 on the error path). A direct putAtTier also moves\n // the record's tier — its history snapshots (if any exist from an earlier\n // tier-0 put()) must follow, same as elevate/demote. Skip when the record\n // was already at this tier (no move, nothing to rewrap). `fromKey`/\n // `fromDek` were already resolved above (review-fix-2), before the live\n // write, for the pre-move snapshot — reused here rather than recomputed.\n if (fromKey !== key) {\n await ctx.syncHistory(id, fromDek, dek)\n // #724: this putAtTier moved the record's tier — rehome its blobs too.\n await ctx.syncBlobs(id, existing?._tier ?? 0, tier)\n }\n return { searchResidue }\n}\n\n/**\n * tier-aware get. When the stored record is at a tier the caller cannot\n * decrypt:\n * - `'invisibility'` mode (default) → returns `null`.\n * - `'ghost'` mode → returns a `GhostRecord` placeholder with the tier and\n * the record id (the record exists but contents are withheld).\n *\n * Fully-cleared reads return the plaintext record and fire a cross-tier event\n * when `_tier > 0`.\n */\nexport async function getAtTier<T>(ctx: TiersContext<T>, id: string): Promise<T | GhostRecord | null> {\n assertTiersEnabled(ctx)\n const envelope = await ctx.adapter.get(ctx.vault, ctx.name, id)\n if (!envelope) return null\n const tier = envelope._tier ?? 0\n if (tier === 0) {\n return ctx.codec.decryptRecord({ collection: ctx.name, id }, envelope)\n }\n\n const key = dekKey(ctx.name, tier)\n if (!ctx.keyring.deks.has(key)) {\n if (ctx.tierMode === 'ghost') {\n return { _ghost: true, _tier: tier } as GhostRecord\n }\n return null\n }\n\n const record = await decryptElevated<T>(ctx, id, envelope, key)\n\n ctx.emitCrossTierEvent({\n actor: ctx.keyring.userId,\n collection: ctx.name,\n id,\n tier,\n authorization: isElevatorOrOwner(ctx) ? 'inherent' : 'delegation',\n op: 'get',\n ts: new Date().toISOString(),\n })\n\n return record\n}\n\n/**\n * Decrypt an ABOVE-TIER envelope under `dekKey` — the manual leg\n * {@link getAtTier} used to inline (#635/#1041). Extracted so the\n * unique-constraint tier scan (#1358) reuses exactly this key handling\n * instead of growing a second copy that could drift from it.\n *\n * A tiered record may carry a per-record CEK (e.g. a CEK record elevated via\n * `elevate()`): the CEK is wrapped under the TIER DEK, so unwrap under the\n * tier DEK then decrypt the body under the CEK. Legacy tiered records decrypt\n * directly under the tier DEK.\n *\n * This leg decrypts manually rather than through `decryptRecord`, so it must\n * build the AAD itself — from the address it fetched from plus the envelope's\n * own `_tier`/`_by`, exactly as `recordAadFor` does everywhere else (#1041).\n *\n * #635: it never went through `decryptRecord`, so it never processed\n * `_sealed` slots — an elevated classified record read back through here\n * would otherwise return the body WITHOUT its sealed fields (silent\n * omission). `applySealedSlots` takes OUR already-unwrapped `cek` (unwrapped\n * under the TIER dek) instead of resolving one under the collection DEK the\n * way `decryptRecord`/`resolveEnvelopeCek` would — which would be the wrong\n * key for a `_cek` wrapped under a tier DEK. `sealedAsHandles` is omitted\n * (default false) to match `getAtTier`'s tier-0 branch: both tiers return\n * sealed fields inline-decrypted, not as handles.\n *\n * The caller MUST have established readability first (`keyring.deks.has(key)`\n * or owner/elevator standing) — this function does not gate.\n */\nasync function decryptElevated<T>(ctx: TiersContext<T>, id: string, envelope: EncryptedEnvelope, key: string): Promise<T> {\n const dek = await ctx.getDEK(key)\n const aad = recordAadFor({ collection: ctx.name, id }, envelope)\n let plaintext: string\n let cek: EnclaveKey | undefined\n if (envelope._cek !== undefined) {\n cek = await unwrapCek(envelope._cek, dek)\n ctx.cekCache?.set(id, cek, 1)\n plaintext = await decrypt(envelope._iv, envelope._data, cek, aad)\n } else {\n plaintext = await decrypt(envelope._iv, envelope._data, dek, aad)\n }\n let record = JSON.parse(plaintext) as T\n if (envelope._sealed !== undefined) {\n record = await ctx.codec.applySealedSlots(record, envelope._sealed, cek, { id })\n }\n return record\n}\n\n/**\n * Unique-constraint enforcement across TIERS (#1358).\n *\n * The in-memory / persisted mirrors that back ordinary unique enforcement\n * hold TIER-0 records only — #709 purges an elevated record's index entries\n * precisely so elevation actually hides its field values. That is correct,\n * and it is also exactly why a tier-0 `put()` would otherwise be free to\n * re-take a value an elevated record still holds. This closes that by\n * scanning the above-tier records the writer can decrypt.\n *\n * ## The guarantee, stated exactly\n *\n * Uniqueness is enforced across **every tier whose DEK this writer holds**.\n * A tier the writer cannot read is **outside the guarantee**: those records\n * are not merely skipped-with-a-warning, they are unreadable, so no local\n * check of any design can see them. A duplicate against such a record is\n * accepted, and stays accepted. Do not describe this as \"enforced across all\n * tiers\" anywhere.\n *\n * ## Cost\n *\n * Zero for a collection with no unique index (`ctx.uniqueKeys` is undefined\n * and this returns immediately) and for one with no elevated records (the\n * scan reads envelope headers only until it meets a `_tier > 0` row it can\n * read). On a tiered collection that DOES hold both, it is a list + get per\n * write — the price of the guarantee, paid only where it was asked for.\n *\n * No cross-tier ACCESS event is emitted per scanned record: this is a\n * constraint pre-flight over material the writer is already cleared for, not\n * a read the caller asked for. The write it gates emits its own event.\n */\nexport async function checkUniqueAcrossTiers<T>(ctx: TiersContext<T>, id: string, record: T): Promise<void> {\n const keysOf = ctx.uniqueKeys\n if (!keysOf || !ctx.tiers) return\n const mine = keysOf(record)\n if (mine.length === 0) return // null-distinct exempt, or nothing declared\n\n for (const otherId of await ctx.adapter.list(ctx.vault, ctx.name)) {\n if (otherId === id || otherId.startsWith('_')) continue\n const env = await ctx.adapter.get(ctx.vault, ctx.name, otherId)\n if (!env) continue\n const tier = env._tier ?? 0\n if (tier === 0) continue // already covered by the tier-0 mirror\n const key = dekKey(ctx.name, tier)\n if (!ctx.keyring.deks.has(key)) continue // unreadable ⇒ outside the guarantee\n let other: T\n try {\n other = await decryptElevated<T>(ctx, otherId, env, key)\n } catch {\n continue // a row this writer cannot open is, for this purpose, unreadable\n }\n const theirs = new Map(keysOf(other).map(k => [`${k.fields.join('\\u0000')}\\u0000${k.key}`, k]))\n for (const k of mine) {\n if (theirs.has(`${k.fields.join('\\u0000')}\\u0000${k.key}`)) {\n throw new UniqueConstraintError(ctx.name, id, k.fields, otherId)\n }\n }\n }\n}\n\n/**\n * list ids grouped by the caller's readability. Returns only ids whose tier the\n * caller can read. Above-tier ids are omitted in `'invisibility'` mode and\n * included (with tier metadata) in `'ghost'` mode.\n */\nexport async function listAtTier<T>(ctx: TiersContext<T>): Promise<Array<{ id: string; tier: number; readable: boolean }>> {\n assertTiersEnabled(ctx)\n const ids = await ctx.adapter.list(ctx.vault, ctx.name)\n const out: Array<{ id: string; tier: number; readable: boolean }> = []\n for (const id of ids) {\n const env = await ctx.adapter.get(ctx.vault, ctx.name, id)\n if (!env) continue\n const tier = env._tier ?? 0\n const readable = tier === 0 || ctx.keyring.deks.has(dekKey(ctx.name, tier))\n if (!readable && ctx.tierMode === 'invisibility') continue\n out.push({ id, tier, readable })\n }\n return out\n}\n\n/**\n * Result of a completed `elevate()`/`demote()` (#764). The record move\n * (put + indexes/cache/ledger/derived/history/blobs sync) always completes —\n * `searchResidue: true` means only the search-index side (`_vec`/`_ftindex`)\n * was left in a needs-retry state (a stuck `PersistedIndexCompensationError`),\n * mirroring `forget()`'s `indexResidue` posture rather than aborting the move.\n */\nexport interface TierMoveResult {\n readonly searchResidue: boolean\n}\n\n/**\n * Run {@link TiersContext.syncSearch} with #764 resilience: a permanently\n * stuck compensation (`PersistedIndexCompensationError`, thrown by\n * `PersistedIndexStore` when its compensating `remove()` of a stale\n * `_ftindex` blob keeps failing) must not abort `elevate()`/`demote()` — the\n * record's tier-move `put` has already landed, and aborting here would leave\n * `syncLedger`/`syncDerived`/`syncHistory`/`syncBlobs` unsynced behind it (the\n * partial-completion hazard #764 names). Same posture `forget()` takes for\n * `_purgeSearchIndex` (`vault.ts`'s `indexResidue`) — everything else (a\n * genuinely unexpected search-hook error) still aborts, undisturbed.\n */\nasync function syncSearchResilient<T>(ctx: TiersContext<T>, id: string, record: T | null, version?: number): Promise<boolean> {\n try {\n await ctx.syncSearch(id, record, version)\n return false\n } catch (e) {\n if (e instanceof PersistedIndexCompensationError) return true\n throw e\n }\n}\n\n/**\n * elevate a record to a higher tier. Re-encrypts with the target tier's DEK.\n * The caller must hold DEKs for both the current tier (to decrypt) and the\n * target tier (to re-encrypt). Stamps `_elevatedBy` with the caller id so\n * `demote()` can check the reverse operation.\n */\nexport async function elevate<T>(ctx: TiersContext<T>, id: string, toTier: number): Promise<TierMoveResult> {\n assertTiersEnabled(ctx)\n assertDeclaredTier(ctx, toTier)\n assertTierAccess(ctx.keyring, ctx.name, toTier)\n\n const envelope = await ctx.adapter.get(ctx.vault, ctx.name, id)\n if (!envelope || isDeleteMarker(envelope) || isTombstoneShape(envelope)) {\n throw new Error(`Record \"${id}\" not found in collection \"${ctx.name}\"`)\n }\n const fromTier = envelope._tier ?? 0\n if (toTier === fromTier) return { searchResidue: false }\n if (toTier < fromTier) {\n throw new Error(`Use demote() to lower the tier of \"${id}\" from ${fromTier} to ${toTier}`)\n }\n // Caller must have access at the existing tier to decrypt.\n if (fromTier > 0) assertTierAccess(ctx.keyring, ctx.name, fromTier)\n\n const fromKey = dekKey(ctx.name, fromTier)\n const toKey = dekKey(ctx.name, toTier)\n const fromDek = await ctx.getDEK(fromKey)\n const toDek = await ctx.getDEK(toKey)\n\n // Per-record CEK composes with tiers: the body key is unchanged (history\n // chain identity preserved); only the wrapping key moves with the tier.\n // Legacy (no `_cek`) records take the direct-DEK path unchanged.\n const now = new Date().toISOString()\n const moveFrom: RecordIdentity = {\n // Opens at the version currently stored; the live write below re-seals at\n // `_v + 1`, so the two ends of a move are NOT the same identity (#1093).\n collection: ctx.name, id, version: envelope._v,\n ...(fromTier > 0 ? { tier: fromTier } : {}),\n ...(envelope._by !== undefined ? { by: envelope._by } : {}),\n }\n const moveTo: RecordIdentity = {\n collection: ctx.name, id, version: envelope._v + 1,\n ...(toTier > 0 ? { tier: toTier } : {}),\n by: ctx.keyring.userId,\n }\n const body = await rewrapBodyToDek(moveFrom, moveTo, envelope, fromDek, toDek)\n if (body.cek) ctx.cekCache?.set(id, body.cek, 1)\n // #728: snapshot the PRE-move version into `_history` before it's\n // overwritten below — reuses `body` (already fromDek→toDek) via\n // `applyRewrappedBody` (never `ctx.codec.encryptRecord`, which always\n // resolves the tier-0 DEK and would leak this body at rest whenever\n // `fromTier > 0`). Untagged (`_tier`/`_elevatedBy` stripped) so the\n // history read-gate doesn't hide it PERMANENTLY once the record demotes\n // back — at-rest protection comes from the ciphertext being under\n // `toDek`, not from the tag. `_v` stays the PRE-move version (unbumped),\n // exactly as `envelope` already carries it.\n //\n // A SECOND rewrap, not a reuse of `body` above. The live write and the\n // snapshot now land at different identities, so they need different AAD and\n // therefore different ciphertext — sharing one rewrap would produce bytes\n // that open at one address and not the other (#1041).\n await ctx.saveHistorySnapshot(id, envelope._v, async (address) => {\n const to: RecordIdentity = { ...address, ...(envelope._by !== undefined ? { by: envelope._by } : {}) }\n const histBody = await rewrapBodyToDek(moveFrom, to, envelope, fromDek, toDek)\n // eslint-disable-next-line @typescript-eslint/no-unused-vars -- excluded from ...snapshot\n const { _tier: _preTier, _elevatedBy: _preElevatedBy, ...snapshot } = applyRewrappedBody(envelope, histBody)\n return snapshot\n })\n // #662: spread every slot the source carries (_sealed/_det/_vdig/_bidx/\n // _source/_sourceTs/_debug) through UNCHANGED, then override only\n // the fields a tier move manages. rewrapBodyToDek preserves the CEK, so no\n // passenger slot is re-keyed by the move. The old field-literal dropped every\n // unlisted slot.\n // NOT a `buildRecordEnvelope` site, deliberately (#1051). This is an envelope\n // TRANSFORM, not a construction: the spread is load-bearing (#662) — it carries\n // every passenger slot (`_sealed`/`_det`/`_vdig`/`_bidx`/`_source`/`_debug`)\n // through unchanged, which a fresh literal would drop. That drop is exactly the\n // defect #1074 found in `rotateKeys`. Its body already goes through the enclave\n // (`rewrapBodyToDek`), which is where a tier move will supply AAD.\n const next: EncryptedEnvelope = {\n ...envelope,\n _noydb: NOYDB_FORMAT_VERSION,\n _v: envelope._v + 1,\n _ts: now,\n _iv: body._iv,\n _data: body._data,\n _by: ctx.keyring.userId,\n _tier: toTier,\n _elevatedBy: ctx.keyring.userId,\n ...(body._cek !== undefined ? { _cek: body._cek } : {}),\n }\n await ctx.adapter.put(ctx.vault, ctx.name, id, next)\n // Evict/purge only once the write landed — a throwing put must not blind\n // the eager cache or leave a readable index behind for a still-valid\n // tier-0 record (same ordering as demote). #709: syncIndexes runs first —\n // it needs the pre-elevation cache entry as \"previous\" to clean the\n // eager index bucket; the persisted side-car purge is content-free.\n await ctx.syncIndexes(id, null, next._v)\n ctx.syncCache(id, null)\n // #721: same purge law as syncIndexes above — the record left tier 0, so\n // its _vec sidecar is purged and _ftindex is invalidated. #764: a\n // permanently stuck compensation must not abort the move — the record put\n // above already landed — so it is caught and surfaced as residue instead.\n const searchResidue = await syncSearchResilient(ctx, id, null)\n // #729: elevate always lands the record at tier > 0 — purge its\n // tier-0-era plaintext ledger deltas (irreversible; entry metadata stays).\n await ctx.syncLedger(id)\n // #722: recompute this record's derived outputs now that it left tier 0 —\n // same law as putAtTier(tier>0) above. `envelope` is the PRE-move envelope\n // (captured before the rewrap), decoded only here (the rollup edge is the\n // only consumer of the record content). Gated by `hasDerivedOutputs` — no-\n // derivation collections skip this decrypt entirely (perf regression\n // review finding, Arc 9 #722). Whole-branch review: decode under `fromDek`\n // via `codec.decryptRecordAtDek` — `fromTier` may be > 0 here (a prior\n // elevate), and `ctx.codec.decryptRecord`'s tier-unaware CEK resolution\n // threw `TamperedError` whenever this op's own rewrap hadn't just primed\n // the cekCache (non-`perRecordKeys` collections; `_cek`-absent bodies).\n await ctx.syncDerived(id, ctx.hasDerivedOutputs ? await ctx.codec.decryptRecordAtDek({ collection: ctx.name, id }, envelope, fromDek) : null, true)\n\n ctx.emitCrossTierEvent({\n actor: ctx.keyring.userId,\n collection: ctx.name,\n id,\n tier: toTier,\n authorization: 'elevation',\n op: 'elevate',\n ts: now,\n })\n\n // #712/whole-branch-fix-2: syncHistory runs LAST — after syncIndexes/\n // syncCache/syncSearch/the cross-tier emit have already landed, so its own\n // throw (adapter I/O, the rewrap) strands only the `_history` artifact\n // instead of leaving indexes/cache/search unsynced behind an already-moved\n // live record (would conditionally reopen #709/#721/#723 on the error\n // path). Rewraps prior-version history snapshots to the SAME toTier DEK —\n // otherwise they stay decryptable at rest under fromDek forever.\n await ctx.syncHistory(id, fromDek, toDek)\n // #724: rehome any solo-owned blob attachments to the target tier's\n // `_blob` DEK — same at-rest law as syncHistory above.\n await ctx.syncBlobs(id, fromTier, toTier)\n return { searchResidue }\n}\n\n/**\n * demote a record to a lower tier. Allowed only for the user who performed the\n * last elevation or an owner.\n */\nexport async function demote<T>(ctx: TiersContext<T>, id: string, toTier: number): Promise<TierMoveResult> {\n assertTiersEnabled(ctx)\n if (toTier < 0) throw new Error(`Cannot demote to negative tier ${toTier}`)\n\n const envelope = await ctx.adapter.get(ctx.vault, ctx.name, id)\n if (!envelope || isDeleteMarker(envelope) || isTombstoneShape(envelope)) {\n throw new Error(`Record \"${id}\" not found in collection \"${ctx.name}\"`)\n }\n const fromTier = envelope._tier ?? 0\n if (toTier === fromTier) return { searchResidue: false }\n if (toTier > fromTier) {\n throw new Error(`Use elevate() to raise the tier of \"${id}\" from ${fromTier} to ${toTier}`)\n }\n const isOwner = ctx.keyring.role === 'owner'\n const isOriginalElevator = envelope._elevatedBy === ctx.keyring.userId\n if (!isOwner && !isOriginalElevator) {\n throw new TierDemoteDeniedError(id, fromTier)\n }\n // Caller must still hold the DEK of the current tier to decrypt.\n assertTierAccess(ctx.keyring, ctx.name, fromTier)\n if (toTier > 0) assertDeclaredTier(ctx, toTier)\n\n const fromDek = await ctx.getDEK(dekKey(ctx.name, fromTier))\n const toDek = await ctx.getDEK(dekKey(ctx.name, toTier))\n\n // CEK re-wrap on demote — same body key, moved from the source tier\n // DEK to the target tier DEK. Legacy records take the direct-DEK path.\n const now = new Date().toISOString()\n const moveFrom: RecordIdentity = {\n // Opens at the version currently stored; the live write below re-seals at\n // `_v + 1`, so the two ends of a move are NOT the same identity (#1093).\n collection: ctx.name, id, version: envelope._v,\n ...(fromTier > 0 ? { tier: fromTier } : {}),\n ...(envelope._by !== undefined ? { by: envelope._by } : {}),\n }\n const moveTo: RecordIdentity = {\n collection: ctx.name, id, version: envelope._v + 1,\n ...(toTier > 0 ? { tier: toTier } : {}),\n by: ctx.keyring.userId,\n }\n const body = await rewrapBodyToDek(moveFrom, moveTo, envelope, fromDek, toDek)\n if (body.cek) ctx.cekCache?.set(id, body.cek, 1)\n // #662: same passenger carry-through as elevate(). demote additionally CLEARS\n // `_elevatedBy` (the demote right is consumed) and OMITS `_tier` at tier 0, so\n // both are destructured out of the spread rather than carried.\n // eslint-disable-next-line @typescript-eslint/no-unused-vars -- excluded from ...carried\n const { _elevatedBy, _tier: _priorTier, ...carried } = envelope\n // #728: snapshot the PRE-move version into `_history` — reuses `body`\n // (already fromDek→toDek) and `carried` (envelope minus `_tier`/\n // `_elevatedBy`, computed above for the live write) via\n // `applyRewrappedBody`, so a tier-0-landing demote's snapshot is untagged\n // just like an ordinary put() entry, same law as elevate()'s snapshot\n // above. `_v` stays the PRE-move version (unbumped), as `carried` already\n // carries it.\n // A SECOND rewrap — see elevate()'s note. The snapshot's destination\n // identity differs from the live write's, so the bytes must differ too.\n await ctx.saveHistorySnapshot(id, envelope._v, async (address) => {\n const to: RecordIdentity = { ...address, ...(envelope._by !== undefined ? { by: envelope._by } : {}) }\n const histBody = await rewrapBodyToDek(moveFrom, to, envelope, fromDek, toDek)\n return applyRewrappedBody(carried, histBody)\n })\n // Transform, not construction — see the note on elevate()'s `next` above.\n const next: EncryptedEnvelope = {\n ...carried,\n _noydb: NOYDB_FORMAT_VERSION,\n _v: envelope._v + 1,\n _ts: now,\n _iv: body._iv,\n _data: body._data,\n _by: ctx.keyring.userId,\n ...(toTier > 0 ? { _tier: toTier } : {}),\n ...(body._cek !== undefined ? { _cek: body._cek } : {}),\n }\n await ctx.adapter.put(ctx.vault, ctx.name, id, next)\n\n // #691/#709: landing back at tier 0 makes this a plain tier-0 record\n // again — it must stay plain-get()-readable AND indexed in the same\n // session, so re-seed the eager cache and rebuild its index entries from\n // the just-written (now tier-0-keyed) envelope through the canonical\n // codec path, the same decode collection.ts's own eager hydration / lazy\n // cache-miss paths use — reused for both, no double-decrypt. A demote\n // that lands on an intermediate elevated tier (toTier > 0) still evicts\n // + purges: the record stays above tier 0 and must remain invisible on\n // tier-0 surfaces, unindexed. syncIndexes runs first in both branches —\n // it needs the pre-demote cache entry as \"previous\".\n // #764: a permanently stuck search-index compensation must not abort the\n // move — the record put above already landed — so it is caught in both\n // branches and surfaced as residue on the return value instead.\n let searchResidue: boolean\n if (toTier === 0) {\n const rec = await ctx.codec.decryptRecord({ collection: ctx.name, id }, next, { sealedAsHandles: true })\n await ctx.syncIndexes(id, rec, next._v, envelope)\n ctx.syncCache(id, rec !== null ? { record: rec, version: next._v } : null)\n // #721: reuse the decode above — no double-decrypt. The record is tier-0\n // again, so re-embed its _vec and invalidate _ftindex to include it.\n searchResidue = await syncSearchResilient(ctx, id, rec, next._v)\n // #722 Task 2: the record rejoined tier 0 — restore its contribution to\n // every derived output (reuse the decode above, no double-decrypt).\n await ctx.syncDerived(id, rec, false, next._v)\n } else {\n await ctx.syncIndexes(id, null, next._v)\n ctx.syncCache(id, null)\n // #721: still above tier 0 — purge _vec, invalidate _ftindex.\n searchResidue = await syncSearchResilient(ctx, id, null)\n // #722 Task 2: still elevated (an intermediate tier) — the source's\n // derived outputs stay recompute-as-removed, same law as elevate()\n // above. `envelope` is the PRE-move envelope captured at function\n // entry; decoded only here (the rollup edge is the only consumer).\n // Gated by `hasDerivedOutputs` — no-derivation collections skip this\n // decrypt entirely (perf regression review finding, Arc 9 #722).\n // Whole-branch review: decode under `fromDek` via\n // `codec.decryptRecordAtDek` — this branch's `fromTier` is always > 0 (a\n // demote FROM tier `fromTier` TO an intermediate `toTier` > 0), so\n // `ctx.codec.decryptRecord`'s tier-unaware CEK resolution threw\n // `TamperedError` here exactly as it did in elevate() above\n // (code-identical bug, same fix).\n await ctx.syncDerived(id, ctx.hasDerivedOutputs ? await ctx.codec.decryptRecordAtDek({ collection: ctx.name, id }, envelope, fromDek) : null, true)\n }\n\n ctx.emitCrossTierEvent({\n actor: ctx.keyring.userId,\n collection: ctx.name,\n id,\n tier: fromTier,\n authorization: 'elevation',\n op: 'demote',\n ts: now,\n })\n\n // #712/whole-branch-fix-2: syncHistory runs LAST — after syncIndexes/\n // syncCache/syncSearch/the cross-tier emit have already landed, so its own\n // throw (adapter I/O, the rewrap) strands only the `_history` artifact\n // instead of leaving indexes/cache/search unsynced behind an already-moved\n // live record (would conditionally reopen #709/#721/#723 on the error\n // path). Rewraps history snapshots the same direction as the live body —\n // demote restores tier-0 (or intermediate-tier) readability at rest.\n await ctx.syncHistory(id, fromDek, toDek)\n // #724: rehome any solo-owned blob attachments the same direction as the\n // live body — restores tier-0 (or intermediate-tier) readability at rest.\n await ctx.syncBlobs(id, fromTier, toTier)\n return { searchResidue }\n}\n\n/**\n * Classify a live envelope's `_sealed` slots for crypto-shred completeness\n * (#M-1). Thin delegate to {@link RecordCodec.classifySealedShred}; surfaced\n * here because `vault.ts` forget() reaches in via `collection._classifySealedShred`.\n */\nexport function classifySealedShred<T>(\n ctx: TiersContext<T>,\n live: EncryptedEnvelope,\n): Promise<{ readonly slots: readonly SealedShredSlot[] }> {\n return ctx.codec.classifySealedShred(live)\n}\n\n// #837 — classifySealedShred's slot type must be nameable from this entry.\nexport type { SealedShredSlot } from '../../kernel/enclave/index.js'\n"],"mappings":"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","names":["putAtTier","getAtTier","listAtTier","elevate","demote","checkUniqueAcrossTiers"]}
@@ -3,7 +3,7 @@ import {
3
3
  InvalidKeyError,
4
4
  TamperedError,
5
5
  ValidationError
6
- } from "./chunk-7O3Y4PPD.js";
6
+ } from "./chunk-244VXYPG.js";
7
7
 
8
8
  // src/kernel/enclave/crypto.ts
9
9
  var PBKDF2_ITERATIONS = 6e5;
@@ -476,4 +476,4 @@ export {
476
476
  bufferToBase64,
477
477
  base64ToBuffer
478
478
  };
479
- //# sourceMappingURL=chunk-HPVZCW43.js.map
479
+ //# sourceMappingURL=chunk-UYB234ZR.js.map
@@ -0,0 +1,220 @@
1
+ // src/kernel/query/live/incremental.ts
2
+ var EMPTY_KEY = [];
3
+ var REBUILT = { kind: "rebuilt" };
4
+ function canMaintainIncrementally(plan, indexes) {
5
+ if (plan.joins.length > 0) return false;
6
+ if (plan.orderBy.some((o) => o.by === "label")) return false;
7
+ if (!clausesMaintainable(plan.clauses)) return false;
8
+ if (isIndexDriven(plan.clauses, indexes)) return false;
9
+ if (servedByOrderedIndex(plan, indexes)) return false;
10
+ return true;
11
+ }
12
+ function servedByOrderedIndex(plan, indexes) {
13
+ if (!indexes) return false;
14
+ if (plan.limit === void 0) return false;
15
+ if (plan.clauses.length > 0 || plan.orderBy.length !== 1) return false;
16
+ const order = plan.orderBy[0];
17
+ return order.by !== "label" && indexes.sorted(order.field);
18
+ }
19
+ function clausesMaintainable(clauses) {
20
+ for (const clause of clauses) {
21
+ if (clause.type === "crossJoin" || clause.type === "filter") return false;
22
+ if (clause.type === "group" && !clausesMaintainable(clause.clauses)) return false;
23
+ }
24
+ return true;
25
+ }
26
+ function isIndexDriven(clauses, indexes) {
27
+ if (!indexes) return false;
28
+ for (const clause of clauses) {
29
+ if (clause.type !== "field") continue;
30
+ if (!indexes.covers(clause.field) && !indexes.sorted(clause.field)) continue;
31
+ if (clause.via === void 0 && RANGE_OPS.has(clause.op)) return indexes.sorted(clause.field);
32
+ if (clause.via && clause.via.indexValue === void 0) continue;
33
+ const probe = clause.via ? clause.via.indexValue : clause.value;
34
+ if (clause.op === "==") return true;
35
+ if (clause.op === "in" && Array.isArray(probe)) return true;
36
+ }
37
+ return false;
38
+ }
39
+ var RANGE_OPS = /* @__PURE__ */ new Set(["<", "<=", ">", ">=", "between", "startsWith"]);
40
+ var LiveMaintainer = class {
41
+ constructor(cfg) {
42
+ this.cfg = cfg;
43
+ }
44
+ cfg;
45
+ entries = [];
46
+ memberById = /* @__PURE__ */ new Map();
47
+ seqById = /* @__PURE__ */ new Map();
48
+ maxSeq = -1;
49
+ /** Maintained state is stale — the next `rows()` rebuilds from the snapshot. */
50
+ stale = true;
51
+ /** True once a subscription is driving `apply()`. */
52
+ attached = false;
53
+ /**
54
+ * Start accepting deltas. Every read before this rebuilds from the snapshot,
55
+ * so a detached maintainer is just an eager executor.
56
+ *
57
+ * ⚠️ Call this in the SAME synchronous turn as a read — either immediately
58
+ * before the first `rows()` (the `.live()` path) or immediately after the
59
+ * initial one (the `.aggregate().live()` path, where the reduction computes
60
+ * before it subscribes). Attaching in a turn of its own would let a mutation
61
+ * slip past unrecorded: it arrives with no subscription to `apply()` it, and
62
+ * the maintained state would then be trusted while already behind.
63
+ */
64
+ attach() {
65
+ this.attached = true;
66
+ }
67
+ /**
68
+ * Stop accepting deltas — the subscription feeding them has gone. Every
69
+ * later read rebuilds, because nothing is keeping the state current any
70
+ * more. Without this, a `Reduction` whose `.live()` was stopped would keep
71
+ * serving its last maintained value from `.run()`.
72
+ */
73
+ detach() {
74
+ this.attached = false;
75
+ }
76
+ /** Force the next read to rebuild — the caller saw something it can't patch. */
77
+ invalidate() {
78
+ this.stale = true;
79
+ }
80
+ /**
81
+ * Fold one upstream change into the maintained set. A change with no
82
+ * payload (the source could not say which record moved) invalidates
83
+ * instead — the next read pays for a full rebuild.
84
+ */
85
+ apply(change) {
86
+ if (!this.attached || this.stale) return REBUILT;
87
+ if (!change) {
88
+ this.stale = true;
89
+ return REBUILT;
90
+ }
91
+ try {
92
+ return this.patch(change);
93
+ } catch (err) {
94
+ this.stale = true;
95
+ throw err;
96
+ }
97
+ }
98
+ /** The current result window — a fresh array on every call. */
99
+ rows() {
100
+ if (!this.attached || this.stale) this.rebuild();
101
+ const { offset, limit } = this.cfg;
102
+ const end = limit === void 0 ? this.entries.length : offset + limit;
103
+ const window = [];
104
+ for (let i = offset; i < end && i < this.entries.length; i++) {
105
+ window.push(this.entries[i].record);
106
+ }
107
+ return this.cfg.decode ? this.cfg.decode(window) : window;
108
+ }
109
+ /**
110
+ * The whole maintained set — every matching record, in maintained order,
111
+ * paired with its id and snapshot sequence. Ignores `offset`/`limit`/
112
+ * `decode` on purpose: this is the input a DERIVED maintainer rebuilds from,
113
+ * and grouped aggregation reduces the full match set, never a window.
114
+ *
115
+ * Rebuilds first when detached or stale, exactly as `rows()` does, so a
116
+ * caller can read it at any time.
117
+ */
118
+ maintainedEntries() {
119
+ if (!this.attached || this.stale) this.rebuild();
120
+ return this.entries;
121
+ }
122
+ /**
123
+ * Full recompute from the source snapshot. Equivalent to the eager path by
124
+ * construction: filter in snapshot order, then sort with snapshot sequence
125
+ * as the tiebreak — which is what a stable sort of the same input does.
126
+ */
127
+ rebuild() {
128
+ const snapshot = this.cfg.snapshotEntries();
129
+ this.entries = [];
130
+ this.memberById.clear();
131
+ this.seqById = /* @__PURE__ */ new Map();
132
+ for (let i = 0; i < snapshot.length; i++) {
133
+ const { id, record } = snapshot[i];
134
+ this.seqById.set(id, i);
135
+ if (this.cfg.matches(record)) {
136
+ const entry = { id, seq: i, record, key: this.keyOf(record) };
137
+ this.entries.push(entry);
138
+ this.memberById.set(id, entry);
139
+ }
140
+ }
141
+ this.maxSeq = snapshot.length - 1;
142
+ this.entries.sort((a, b) => this.compareEntries(a, b));
143
+ this.stale = false;
144
+ }
145
+ patch(change) {
146
+ const { id } = change;
147
+ const previous = this.memberById.get(id);
148
+ const record = change.action === "delete" ? void 0 : this.cfg.lookupById(id);
149
+ if (record === void 0) {
150
+ this.seqById.delete(id);
151
+ if (previous) this.removeEntry(previous);
152
+ return previous ? { kind: "patched", id, removed: { seq: previous.seq, record: previous.record } } : { kind: "patched", id };
153
+ }
154
+ let seq = this.seqById.get(id);
155
+ if (seq === void 0) {
156
+ seq = ++this.maxSeq;
157
+ this.seqById.set(id, seq);
158
+ }
159
+ const matches = this.cfg.matches(record);
160
+ if (previous) this.removeEntry(previous);
161
+ const removed = previous ? { seq: previous.seq, record: previous.record } : void 0;
162
+ if (!matches) {
163
+ return removed ? { kind: "patched", id, removed } : { kind: "patched", id };
164
+ }
165
+ const entry = { id, seq, record, key: this.keyOf(record) };
166
+ this.entries.splice(this.lowerBound(entry), 0, entry);
167
+ this.memberById.set(id, entry);
168
+ const inserted = { seq, record };
169
+ return removed ? { kind: "patched", id, removed, inserted } : { kind: "patched", id, inserted };
170
+ }
171
+ removeEntry(entry) {
172
+ const at = this.lowerBound(entry);
173
+ const index = this.entries[at] === entry ? at : this.entries.indexOf(entry);
174
+ if (index >= 0) this.entries.splice(index, 1);
175
+ this.memberById.delete(entry.id);
176
+ }
177
+ /** First index whose entry does not sort before `probe`. */
178
+ lowerBound(probe) {
179
+ let lo = 0;
180
+ let hi = this.entries.length;
181
+ while (lo < hi) {
182
+ const mid = lo + hi >>> 1;
183
+ if (this.compareEntries(this.entries[mid], probe) < 0) lo = mid + 1;
184
+ else hi = mid;
185
+ }
186
+ return lo;
187
+ }
188
+ keyOf(record) {
189
+ return this.cfg.order ? this.cfg.order.keyOf(record) : EMPTY_KEY;
190
+ }
191
+ /**
192
+ * The eager path's ordering, made total.
193
+ *
194
+ * `order.compare` is the query's own `compareOrderKeys`, the identical
195
+ * function `sortRecords` sorts with, so sort keys cannot be read or ranked
196
+ * differently here. It returns 0 for equal keys — it can do nothing else,
197
+ * having been handed the keys rather than the records — and the eager sort
198
+ * then leaves those in the order they arrived, which is candidate order,
199
+ * which is snapshot order given `canMaintainIncrementally` has refused every
200
+ * plan whose candidates arrive in index order. The sequence number below is
201
+ * that same resolution, made explicit so a binary search has an exact
202
+ * position to find. ⚠️ If the eager path ever grows a tiebreak of its own
203
+ * (an id, say), this stops agreeing with it — which is what
204
+ * `__tests__/query-incremental.test.ts`'s "inherits an order key plan that
205
+ * leaves equal keys to the tiebreak" is there to catch.
206
+ */
207
+ compareEntries(a, b) {
208
+ if (this.cfg.order) {
209
+ const cmp = this.cfg.order.compare(a.key, b.key);
210
+ if (cmp !== 0) return cmp;
211
+ }
212
+ return a.seq - b.seq;
213
+ }
214
+ };
215
+
216
+ export {
217
+ canMaintainIncrementally,
218
+ LiveMaintainer
219
+ };
220
+ //# sourceMappingURL=chunk-VHM7HCKB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/kernel/query/live/incremental.ts"],"sourcesContent":["/**\n * Incremental (delta) maintenance for `.live()` — #1341.\n *\n * A live query used to re-run its whole plan on every change event: scan\n * every record in the collection, re-evaluate every clause, re-sort, re-slice.\n * That is O(N log N) per keystroke-sized mutation and is what makes a reactive\n * list unusable at 10k+ rows.\n *\n * This module maintains the match set instead. Given a change event\n * `{ id, action }` it re-evaluates the predicate for **that record only** and\n * splices it into (or out of) a sorted array, so the per-change cost is\n * O(log k) comparisons + one array splice, where k is the number of MATCHING\n * records rather than N.\n *\n * ## The correctness contract\n *\n * The maintained array must be **identical** — same records, same order — to\n * what a full re-run would produce, at every step. Two things buy that:\n *\n * 1. **Membership is delegated.** The caller passes the very `matches()`\n * closure the full pipeline uses (`filterRecords` over the plan's\n * clauses), so a maintained membership decision cannot drift from an\n * eagerly-computed one. This module never re-implements a predicate.\n *\n * 2. **The ordering is delegated too, and then made total.** The sort keys\n * are read and ranked by the query's own order key plan — the same\n * `buildOrderKeyPlan`/`orderKeyOf`/`compareOrderKeys` trio `sortRecords`\n * sorts with and the keyset cursor compares against (#1346), so there is\n * one definition of \"what order is this query in\" rather than two that\n * drift. What that trio does NOT decide is equal keys: `compareOrderKeys`\n * is handed two KEY TUPLES, not two records, so with equal keys its\n * inputs are indistinguishable and 0 is the only answer it can give —\n * structurally, not by convention. (#1346 breaks its own ties one level\n * up, at the `page()` call site, never inside the comparator.) The eager\n * path lets its stable sort resolve those, leaving them in candidate =\n * snapshot order; we append each record's snapshot position as a final\n * key, which is the same resolution stated explicitly — and being\n * explicit is what lets a binary search land on an exact index.\n *\n * ⚠️ That rests on one property of the backing cache: **snapshot order is\n * `Map` insertion order.** `Map.set` on an existing key keeps its slot\n * (so an update never moves a record), a new key appends (so a new record\n * sorts last among ties), and `delete` removes without reordering the\n * rest. `Collection`'s eager cache is a `Map`, so this holds. A source\n * whose snapshot order is not insertion-stable must not be maintained —\n * it would produce a correct SET in a wrong ORDER among ties.\n *\n * Anything not provably patchable falls back to a full rebuild: an unknown\n * (payload-less) change event, an error thrown mid-patch, or a plan shape\n * `canMaintainIncrementally()` refuses. **The fallback is the default** —\n * `canMaintainIncrementally` is a whitelist, not a blacklist.\n *\n * ## Stacking on top of it\n *\n * `apply()` reports what it did as a `PatchOutcome`, and `maintainedEntries()`\n * exposes the set with its snapshot sequence numbers. Together those let a\n * DERIVED maintainer mirror this one without forking its membership logic —\n * which is exactly what per-group maintenance for\n * `groupBy().aggregate().live()` does (`with-lookup/reduce/incremental-group.ts`).\n * A layer built that way inherits the whitelist and the fallback rather than\n * re-deciding them, so there is one answer to \"can this plan be maintained\"\n * rather than two that drift.\n */\n\nimport type { Clause } from '../predicate.js'\nimport type { OrderBy } from '../builder.js'\n\n/**\n * The delta a source hands to its `subscribe` callback: which record changed\n * and whether it was written or removed. Deliberately the same shape as the\n * hub-level `ChangeEvent` minus the vault/collection routing fields, which\n * the source has already filtered on.\n *\n * A source that cannot say WHICH record changed simply calls its callback with\n * no argument — every consumer treats that as \"rebuild from scratch\", which is\n * exactly the pre-#1341 behaviour.\n */\nexport interface SourceChange {\n readonly id: string\n readonly action: 'put' | 'delete'\n}\n\n/**\n * One side of a patch: a record that entered or left the maintained set, with\n * the snapshot sequence number it occupies. `seq` is what makes a patch\n * composable — a layer built ON TOP of the match set (grouped aggregation,\n * #1341's second half) can place the record in its own ordering without\n * re-deriving snapshot position, and sequence numbers are stable across an\n * update because `Map.set` on an existing key keeps its slot.\n */\nexport interface PatchDelta {\n readonly seq: number\n readonly record: unknown\n}\n\n/**\n * What `apply()` did, so a layer stacked on the maintained set can mirror it.\n *\n * `'rebuilt'` is the honest answer for everything that is NOT a clean patch —\n * a payload-less event, a detached maintainer, an already-stale one. A\n * consumer reading it must invalidate its own derived state; it must never\n * read `'rebuilt'` as \"nothing happened\".\n *\n * A `'patched'` outcome with neither `removed` nor `inserted` DID happen: a\n * non-member changed and stayed a non-member. That is a no-op for every\n * derived layer, which is exactly why it is reported as a patch rather than a\n * rebuild.\n */\nexport type PatchOutcome =\n | { readonly kind: 'rebuilt' }\n | {\n readonly kind: 'patched'\n readonly id: string\n readonly removed?: PatchDelta\n readonly inserted?: PatchDelta\n }\n\n/** An id-paired member of the maintained set, in maintained order. */\nexport interface MaintainedEntry {\n readonly id: string\n readonly seq: number\n readonly record: unknown\n}\n\n/**\n * The subset of a query source a DERIVED maintainer needs (#1341, grouped\n * half). Deliberately a kernel type even though its only consumer today is\n * the reduce service: everything in it is a kernel concept, and declaring it\n * here is what lets `kernel/query/builder.ts` hand one to the service without\n * a new spine to service import specifier.\n */\nexport interface GroupMaintenanceSource {\n /**\n * Id-paired snapshot, in snapshot (Map insertion) order.\n *\n * ⚠️ Declared as function-typed PROPERTIES, not methods: every member here\n * is a standalone closure the query builder binds before handing it over,\n * and property syntax says so — a method declaration would invite a `this`\n * these closures do not have.\n */\n readonly snapshotEntries: () => readonly { id: string; record: unknown }[]\n /** O(1) current-state lookup for the AFTER state of a change. */\n readonly lookupById: (id: string) => unknown\n /** The plan's membership test — the same one the eager path runs. */\n readonly matches: (record: unknown) => boolean\n /**\n * Per-record projection the eager grouping pipeline applies AFTER filtering\n * and before bucketing — today only `projectDateTruncKeys` (#1350). Applied\n * per record here because the eager path applies it per record too; a\n * projection that read across records could not be maintained and must not\n * be plumbed through this hook.\n */\n readonly project?: (record: unknown) => unknown\n}\n\n/** Everything the maintainer needs, supplied by the query builder. */\nexport interface MaintainerConfig {\n /** Id-paired snapshot, in snapshot (Map insertion) order. */\n snapshotEntries(): readonly { id: string; record: unknown }[]\n /** O(1) current-state lookup, used to read the AFTER state of a change. */\n lookupById(id: string): unknown\n /** The plan's membership test — the same one the eager path runs. */\n matches(record: unknown): boolean\n /**\n * The plan's ordering, in the same key-plan shape `sortRecords` and the\n * keyset cursor use (#1346): read a record's sort-key tuple, and compare two\n * of those tuples. `undefined` when the plan has no `orderBy` — result order\n * is then snapshot order alone.\n *\n * `compare` need not be a total order: it returns 0 for equal sort keys,\n * exactly as it does for the eager sort, and the maintainer resolves those\n * ties by snapshot sequence.\n */\n order?: {\n keyOf(record: unknown): unknown[]\n compare(a: readonly unknown[], b: readonly unknown[]): number\n }\n /** Plan offset (0 when unset). */\n offset: number\n /** Plan limit, or undefined for \"all matching rows\". */\n limit: number | undefined\n /**\n * Post-slice projection the eager path applies to the emitted window (Via\n * result decoding). Applied to the window, never to the maintained records,\n * mirroring `toArray()` which decodes AFTER filter/sort/slice.\n */\n decode?: (rows: readonly unknown[]) => unknown[]\n}\n\nconst EMPTY_KEY: readonly unknown[] = []\n\n/** Shared 'you cannot patch from this' answer — allocation-free on the hot path. */\nconst REBUILT: PatchOutcome = { kind: 'rebuilt' }\n\ninterface Entry {\n readonly id: string\n readonly seq: number\n readonly record: unknown\n /**\n * The record's sort-key tuple, computed once when the entry is built. Every\n * write to a record re-enters it, so a cached key is never stale — and the\n * binary search then compares tuples instead of re-reading fields at every\n * probe.\n */\n readonly key: readonly unknown[]\n}\n\n/**\n * Reject any plan whose result set cannot be provably patched from a single\n * record's delta. Everything this refuses still works — it just re-runs in\n * full, as it did before #1341.\n *\n * Refused, and why:\n * - **joins / crossJoin** — a row's membership depends on other collections'\n * records, so a left-side delta does not determine the new result.\n * - **`.filter(fn)`** — an arbitrary consumer closure with no determinism\n * guarantee. `r => r.due < Date.now()` changes its verdict for records that\n * never changed, which a full re-run observes and a patch cannot.\n * (`.wherePredicate()` is admitted: it is DECLARED deterministic and\n * carries a body hash saying so.)\n * - **`orderBy(..., { by: 'label' })`** — the label maps are built eagerly\n * from a dictionary collection's snapshot, so the comparator would be\n * captured at subscribe time and go stale when that dictionary changes.\n * - **an index-driven plan** — the rows then reach the pipeline in INDEX\n * order rather than snapshot order, so snapshot sequence is the wrong\n * tiebreak among equal sort keys. Three shapes qualify, and all three are\n * refused: an `==`/`in` clause on any indexed field, a range clause on a\n * SORTED-indexed field, and #1344's `orderedIndexRows()` page, which\n * serves `orderBy(f).limit(n)` straight off a sorted index with no\n * predicate at all. Little is lost: each of those re-runs is already\n * proportional to the page or the match set, not to the collection.\n */\nexport function canMaintainIncrementally(\n plan: {\n readonly clauses: readonly Clause[]\n readonly orderBy: readonly OrderBy[]\n readonly limit?: number | undefined\n readonly joins: readonly unknown[]\n },\n indexes: IndexProbe | null,\n): boolean {\n if (plan.joins.length > 0) return false\n if (plan.orderBy.some(o => o.by === 'label')) return false\n if (!clausesMaintainable(plan.clauses)) return false\n if (isIndexDriven(plan.clauses, indexes)) return false\n if (servedByOrderedIndex(plan, indexes)) return false\n return true\n}\n\n/**\n * What the maintainer needs to know about the source's indexes: which fields\n * carry ANY index, and which carry a SORTED one. Both matter — the sorted\n * index feeds two paths (#1344) the hash index does not.\n */\nexport interface IndexProbe {\n covers(field: string): boolean\n sorted(field: string): boolean\n}\n\n/**\n * Would #1344's `orderedIndexRows()` serve this plan off a sorted index?\n *\n * Mirrors the cheap half of its preconditions and deliberately stops there:\n * the remaining ones (full index coverage of the snapshot, no Via ordering)\n * cost a snapshot walk to check, and answering \"maybe\" here only ever costs a\n * fallback. The page it would serve is in stored-key order, and among records\n * with EQUAL keys that order is the index's, not the cache's — which is\n * precisely the tie resolution the maintainer would get wrong.\n */\nfunction servedByOrderedIndex(\n plan: {\n readonly clauses: readonly Clause[]\n readonly orderBy: readonly OrderBy[]\n readonly limit?: number | undefined\n },\n indexes: IndexProbe | null,\n): boolean {\n if (!indexes) return false\n if (plan.limit === undefined) return false\n if (plan.clauses.length > 0 || plan.orderBy.length !== 1) return false\n const order = plan.orderBy[0]!\n return order.by !== 'label' && indexes.sorted(order.field)\n}\n\nfunction clausesMaintainable(clauses: readonly Clause[]): boolean {\n for (const clause of clauses) {\n if (clause.type === 'crossJoin' || clause.type === 'filter') return false\n if (clause.type === 'group' && !clausesMaintainable(clause.clauses)) return false\n }\n return true\n}\n\n/**\n * Would `candidateRecords()` take the index fast path for this plan?\n *\n * Deliberately more eager to say \"yes\" than `candidateRecords` itself (which\n * additionally requires the index probe to return a hit set) — erring that way\n * costs a fallback, never a wrong answer.\n */\nfunction isIndexDriven(clauses: readonly Clause[], indexes: IndexProbe | null): boolean {\n if (!indexes) return false\n for (const clause of clauses) {\n if (clause.type !== 'field') continue\n if (!indexes.covers(clause.field) && !indexes.sorted(clause.field)) continue\n // #1344: a range probe reads the SORTED index, and only for a clause the\n // Via layer has not claimed — mirroring `candidateRecords`'s own branch.\n // On a hash-only field `lookupRange` returns null and the plan scans, so\n // that case is left maintainable.\n if (clause.via === undefined && RANGE_OPS.has(clause.op)) return indexes.sorted(clause.field)\n if (clause.via && clause.via.indexValue === undefined) continue\n const probe = clause.via ? clause.via.indexValue : clause.value\n if (clause.op === '==') return true\n if (clause.op === 'in' && Array.isArray(probe)) return true\n }\n return false\n}\n\n/** The operators #1344's `lookupRange` serves off a sorted index. */\nconst RANGE_OPS: ReadonlySet<string> = new Set(['<', '<=', '>', '>=', 'between', 'startsWith'])\n\n/**\n * The maintained result set behind one live query.\n *\n * Lifecycle: `attach()` when a subscription opens, `apply(change)` per upstream\n * event, `rows()` to read the current window. Before `attach()` (and after any\n * fallback) `rows()` recomputes from the snapshot, so a detached maintainer is\n * simply an eager executor and is safe to read at any time.\n */\nexport class LiveMaintainer {\n private entries: Entry[] = []\n private readonly memberById = new Map<string, Entry>()\n private seqById = new Map<string, number>()\n private maxSeq = -1\n /** Maintained state is stale — the next `rows()` rebuilds from the snapshot. */\n private stale = true\n /** True once a subscription is driving `apply()`. */\n private attached = false\n\n constructor(private readonly cfg: MaintainerConfig) {}\n\n /**\n * Start accepting deltas. Every read before this rebuilds from the snapshot,\n * so a detached maintainer is just an eager executor.\n *\n * ⚠️ Call this in the SAME synchronous turn as a read — either immediately\n * before the first `rows()` (the `.live()` path) or immediately after the\n * initial one (the `.aggregate().live()` path, where the reduction computes\n * before it subscribes). Attaching in a turn of its own would let a mutation\n * slip past unrecorded: it arrives with no subscription to `apply()` it, and\n * the maintained state would then be trusted while already behind.\n */\n attach(): void {\n this.attached = true\n }\n\n /**\n * Stop accepting deltas — the subscription feeding them has gone. Every\n * later read rebuilds, because nothing is keeping the state current any\n * more. Without this, a `Reduction` whose `.live()` was stopped would keep\n * serving its last maintained value from `.run()`.\n */\n detach(): void {\n this.attached = false\n }\n\n /** Force the next read to rebuild — the caller saw something it can't patch. */\n invalidate(): void {\n this.stale = true\n }\n\n /**\n * Fold one upstream change into the maintained set. A change with no\n * payload (the source could not say which record moved) invalidates\n * instead — the next read pays for a full rebuild.\n */\n apply(change: SourceChange | undefined): PatchOutcome {\n if (!this.attached || this.stale) return REBUILT\n if (!change) {\n this.stale = true\n return REBUILT\n }\n try {\n return this.patch(change)\n } catch (err) {\n // A predicate threw mid-patch: the maintained set may be half-updated,\n // so drop it rather than serve a set we can no longer vouch for. The\n // error still reaches the consumer — the rebuild on the next read runs\n // the same predicate and throws the same way.\n this.stale = true\n throw err\n }\n }\n\n /** The current result window — a fresh array on every call. */\n rows(): unknown[] {\n if (!this.attached || this.stale) this.rebuild()\n const { offset, limit } = this.cfg\n const end = limit === undefined ? this.entries.length : offset + limit\n const window: unknown[] = []\n for (let i = offset; i < end && i < this.entries.length; i++) {\n window.push(this.entries[i]!.record)\n }\n return this.cfg.decode ? this.cfg.decode(window) : window\n }\n\n /**\n * The whole maintained set — every matching record, in maintained order,\n * paired with its id and snapshot sequence. Ignores `offset`/`limit`/\n * `decode` on purpose: this is the input a DERIVED maintainer rebuilds from,\n * and grouped aggregation reduces the full match set, never a window.\n *\n * Rebuilds first when detached or stale, exactly as `rows()` does, so a\n * caller can read it at any time.\n */\n maintainedEntries(): readonly MaintainedEntry[] {\n if (!this.attached || this.stale) this.rebuild()\n return this.entries\n }\n\n /**\n * Full recompute from the source snapshot. Equivalent to the eager path by\n * construction: filter in snapshot order, then sort with snapshot sequence\n * as the tiebreak — which is what a stable sort of the same input does.\n */\n private rebuild(): void {\n const snapshot = this.cfg.snapshotEntries()\n this.entries = []\n this.memberById.clear()\n this.seqById = new Map()\n for (let i = 0; i < snapshot.length; i++) {\n const { id, record } = snapshot[i]!\n this.seqById.set(id, i)\n if (this.cfg.matches(record)) {\n const entry: Entry = { id, seq: i, record, key: this.keyOf(record) }\n this.entries.push(entry)\n this.memberById.set(id, entry)\n }\n }\n this.maxSeq = snapshot.length - 1\n this.entries.sort((a, b) => this.compareEntries(a, b))\n this.stale = false\n }\n\n private patch(change: SourceChange): PatchOutcome {\n const { id } = change\n const previous = this.memberById.get(id)\n const record = change.action === 'delete' ? undefined : this.cfg.lookupById(id)\n\n if (record === undefined) {\n // Gone. Its snapshot slot is released too: a later re-add of the same id\n // appends to the cache's Map, so it must earn a fresh sequence number.\n this.seqById.delete(id)\n if (previous) this.removeEntry(previous)\n return previous\n ? { kind: 'patched', id, removed: { seq: previous.seq, record: previous.record } }\n : { kind: 'patched', id }\n }\n\n let seq = this.seqById.get(id)\n if (seq === undefined) {\n // A key the snapshot did not carry — `Map.set` appended it, so it sorts\n // after every record we have seen.\n seq = ++this.maxSeq\n this.seqById.set(id, seq)\n }\n\n const matches = this.cfg.matches(record)\n if (previous) this.removeEntry(previous)\n const removed = previous ? { seq: previous.seq, record: previous.record } : undefined\n if (!matches) {\n return removed ? { kind: 'patched', id, removed } : { kind: 'patched', id }\n }\n\n const entry: Entry = { id, seq, record, key: this.keyOf(record) }\n this.entries.splice(this.lowerBound(entry), 0, entry)\n this.memberById.set(id, entry)\n const inserted = { seq, record }\n return removed ? { kind: 'patched', id, removed, inserted } : { kind: 'patched', id, inserted }\n }\n\n private removeEntry(entry: Entry): void {\n // The comparator is a total order (sequence numbers are unique), so the\n // binary search lands exactly on the entry. The linear scan is a belt-and-\n // braces fallback for a source that broke the ordering assumption.\n const at = this.lowerBound(entry)\n const index = this.entries[at] === entry ? at : this.entries.indexOf(entry)\n if (index >= 0) this.entries.splice(index, 1)\n this.memberById.delete(entry.id)\n }\n\n /** First index whose entry does not sort before `probe`. */\n private lowerBound(probe: Entry): number {\n let lo = 0\n let hi = this.entries.length\n while (lo < hi) {\n const mid = (lo + hi) >>> 1\n if (this.compareEntries(this.entries[mid]!, probe) < 0) lo = mid + 1\n else hi = mid\n }\n return lo\n }\n\n private keyOf(record: unknown): readonly unknown[] {\n return this.cfg.order ? this.cfg.order.keyOf(record) : EMPTY_KEY\n }\n\n /**\n * The eager path's ordering, made total.\n *\n * `order.compare` is the query's own `compareOrderKeys`, the identical\n * function `sortRecords` sorts with, so sort keys cannot be read or ranked\n * differently here. It returns 0 for equal keys — it can do nothing else,\n * having been handed the keys rather than the records — and the eager sort\n * then leaves those in the order they arrived, which is candidate order,\n * which is snapshot order given `canMaintainIncrementally` has refused every\n * plan whose candidates arrive in index order. The sequence number below is\n * that same resolution, made explicit so a binary search has an exact\n * position to find. ⚠️ If the eager path ever grows a tiebreak of its own\n * (an id, say), this stops agreeing with it — which is what\n * `__tests__/query-incremental.test.ts`'s \"inherits an order key plan that\n * leaves equal keys to the tiebreak\" is there to catch.\n */\n private compareEntries(a: Entry, b: Entry): number {\n if (this.cfg.order) {\n const cmp = this.cfg.order.compare(a.key, b.key)\n if (cmp !== 0) return cmp\n }\n return a.seq - b.seq\n }\n}\n"],"mappings":"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","names":[]}