@noy-db/hub 0.8.0 → 0.9.0-pre.1

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 (567) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/README.md +8 -8
  3. package/codemods/0.4.0-pre.json +1 -1
  4. package/codemods/0.8.0-pre.json +1 -1
  5. package/dist/api-6EFD43KN.js +18 -0
  6. package/dist/as/index.js +33 -23
  7. package/dist/as/index.js.map +1 -1
  8. package/dist/at/index.js +8 -8
  9. package/dist/attestation/index.js +18 -18
  10. package/dist/{backup-YE2VQ26S.js → backup-RJBFQSHE.js} +92 -31
  11. package/dist/backup-RJBFQSHE.js.map +1 -0
  12. package/dist/blobs/index.js +12 -12
  13. package/dist/broker/index.js +19 -11
  14. package/dist/broker/index.js.map +1 -1
  15. package/dist/by/index.js +2 -2
  16. package/dist/capsule/contract.d.ts +1 -1
  17. package/dist/capsule/contract.js +6 -6
  18. package/dist/capsule/enclave-aes/broker/proof.d.ts +12 -3
  19. package/dist/capsule/enclave-aes/crypto.d.ts +18 -0
  20. package/dist/capsule/enclave-aes/index.d.ts +3 -3
  21. package/dist/capsule/enclave-aes/index.js +46 -14
  22. package/dist/capsule/enclave-aes/index.js.map +1 -1
  23. package/dist/capsule/index.d.ts +2 -2
  24. package/dist/capsule/plumbing/record-codec.d.ts +7 -0
  25. package/dist/{capsule-VOLX3QRQ.js → capsule-6LJAVQNM.js} +14 -8
  26. package/dist/cargo/index.js +35 -35
  27. package/dist/{chunk-GZT3NQRA.js → chunk-25FXU6WS.js} +8 -2
  28. package/dist/chunk-25FXU6WS.js.map +1 -0
  29. package/dist/{chunk-OYW3I5M4.js → chunk-2DOCDOPL.js} +6 -6
  30. package/dist/chunk-2DX4JCRI.js +1 -0
  31. package/dist/{chunk-FLPCETP6.js → chunk-2LBS62AC.js} +2 -2
  32. package/dist/{chunk-WXE4W2U6.js → chunk-2ST3WA3C.js} +4 -4
  33. package/dist/{chunk-DQESF6RP.js → chunk-3G3GOGZZ.js} +50 -40
  34. package/dist/chunk-3G3GOGZZ.js.map +1 -0
  35. package/dist/{chunk-O2IMQSNA.js → chunk-3YBIVLTC.js} +2 -2
  36. package/dist/{chunk-LGNDFRYC.js → chunk-4CFHL5RY.js} +1 -1
  37. package/dist/chunk-4CFHL5RY.js.map +1 -0
  38. package/dist/{chunk-DIZLQVAA.js → chunk-4CHM2TRS.js} +2 -2
  39. package/dist/{chunk-V7ADQF5O.js → chunk-4CUJLEOA.js} +4 -4
  40. package/dist/{chunk-3EWS67C7.js → chunk-4TG2ITRW.js} +2 -2
  41. package/dist/{chunk-HS554XAF.js → chunk-5HQFROZS.js} +2 -2
  42. package/dist/{chunk-IUBMZPHM.js → chunk-5ZVE3N5C.js} +5 -6
  43. package/dist/chunk-5ZVE3N5C.js.map +1 -0
  44. package/dist/{chunk-PP3K67AJ.js → chunk-654RE5YC.js} +3 -3
  45. package/dist/{chunk-FOEDQATO.js → chunk-66GD7XXU.js} +2 -2
  46. package/dist/{chunk-BNWA3WG5.js → chunk-72FQ46VW.js} +3 -3
  47. package/dist/{chunk-EYG2CY2X.js → chunk-7JPA3LIH.js} +11 -11
  48. package/dist/chunk-7JPA3LIH.js.map +1 -0
  49. package/dist/{chunk-JQYKPKG6.js → chunk-7K42TSCY.js} +4 -4
  50. package/dist/{chunk-BPWYQ25R.js → chunk-7Q6IU3R7.js} +4 -4
  51. package/dist/{chunk-BPWYQ25R.js.map → chunk-7Q6IU3R7.js.map} +1 -1
  52. package/dist/{chunk-T7IR4N2S.js → chunk-7UHLO4ZN.js} +37 -2
  53. package/dist/chunk-7UHLO4ZN.js.map +1 -0
  54. package/dist/{chunk-UEFOQH74.js → chunk-ADCXTW7L.js} +2 -2
  55. package/dist/{chunk-MBMTND6D.js → chunk-AGGPT4UE.js} +2 -2
  56. package/dist/{chunk-RB4DOPGZ.js → chunk-AKIEBFIJ.js} +10 -10
  57. package/dist/{chunk-VHBKYN2J.js → chunk-B3B6HV5S.js} +2 -2
  58. package/dist/{chunk-JWWYRR4Q.js → chunk-B6EWMGFX.js} +2 -2
  59. package/dist/{chunk-H7JBY4P7.js → chunk-B7Y2BRQA.js} +14 -14
  60. package/dist/chunk-B7Y2BRQA.js.map +1 -0
  61. package/dist/{chunk-4CIQDWRB.js → chunk-BFJE2GPP.js} +14 -8
  62. package/dist/{chunk-4CIQDWRB.js.map → chunk-BFJE2GPP.js.map} +1 -1
  63. package/dist/{chunk-WPOYWFSE.js → chunk-BJRKXNFP.js} +7 -7
  64. package/dist/{chunk-H427H63K.js → chunk-BPQ5CRJF.js} +2 -2
  65. package/dist/{chunk-VFHCKG5M.js → chunk-BVRJYMFZ.js} +3 -3
  66. package/dist/{chunk-244QBK7Z.js → chunk-C4XV3PSJ.js} +4 -4
  67. package/dist/{chunk-244QBK7Z.js.map → chunk-C4XV3PSJ.js.map} +1 -1
  68. package/dist/{chunk-SMV2HRDU.js → chunk-DFC4WTJW.js} +2 -2
  69. package/dist/{chunk-5A4345TG.js → chunk-DMIEKD24.js} +3 -3
  70. package/dist/{chunk-TKVUE4JF.js → chunk-DQAXA2GK.js} +9 -9
  71. package/dist/{chunk-AL6ML4LA.js → chunk-DWCFGF2K.js} +5 -5
  72. package/dist/{chunk-Y3LPTBG7.js → chunk-E2C6FFSI.js} +6 -9
  73. package/dist/chunk-E2C6FFSI.js.map +1 -0
  74. package/dist/{chunk-LNSVGRHO.js → chunk-EQ6C2ZPT.js} +17 -51
  75. package/dist/chunk-EQ6C2ZPT.js.map +1 -0
  76. package/dist/chunk-EZOFTI4K.js +60 -0
  77. package/dist/chunk-EZOFTI4K.js.map +1 -0
  78. package/dist/{chunk-PD64727P.js → chunk-FMINS2B6.js} +2 -2
  79. package/dist/chunk-FMINS2B6.js.map +1 -0
  80. package/dist/{chunk-QBLT6POL.js → chunk-FPF5HRBE.js} +2 -2
  81. package/dist/{chunk-UA372JHH.js → chunk-FZVCZEVI.js} +3 -3
  82. package/dist/chunk-FZVCZEVI.js.map +1 -0
  83. package/dist/{chunk-FFWI7UH7.js → chunk-GAGT3YZN.js} +1 -1
  84. package/dist/chunk-GAGT3YZN.js.map +1 -0
  85. package/dist/{chunk-5WWDGFOS.js → chunk-GIQJGXV7.js} +2 -2
  86. package/dist/{chunk-V3RWOOSO.js → chunk-GYZICGRU.js} +4 -4
  87. package/dist/chunk-GYZICGRU.js.map +1 -0
  88. package/dist/{chunk-BVCUTXE3.js → chunk-H334G6KU.js} +2 -2
  89. package/dist/{chunk-AEQGFRU4.js → chunk-HE7EAHGS.js} +3 -3
  90. package/dist/chunk-HKB4HZDU.js +74 -0
  91. package/dist/chunk-HKB4HZDU.js.map +1 -0
  92. package/dist/{chunk-4V3Q35WG.js → chunk-ICF3TIGY.js} +3 -3
  93. package/dist/{chunk-3L2NBKDR.js → chunk-IF2M43G4.js} +2 -2
  94. package/dist/{chunk-37EPTBBR.js → chunk-IKPQ2GGB.js} +46 -4
  95. package/dist/chunk-IKPQ2GGB.js.map +1 -0
  96. package/dist/{chunk-DHHGL42E.js → chunk-IKS2CPAG.js} +27 -11
  97. package/dist/chunk-IKS2CPAG.js.map +1 -0
  98. package/dist/{chunk-3A5DUZ56.js → chunk-IMIQAGR7.js} +6 -6
  99. package/dist/{chunk-3A5DUZ56.js.map → chunk-IMIQAGR7.js.map} +1 -1
  100. package/dist/{chunk-A4XMIZT3.js → chunk-IQAJ4OR6.js} +41 -6
  101. package/dist/chunk-IQAJ4OR6.js.map +1 -0
  102. package/dist/{chunk-IUT3GWP3.js → chunk-IUD7WU67.js} +17 -93
  103. package/dist/chunk-IUD7WU67.js.map +1 -0
  104. package/dist/{chunk-AUKKUPVB.js → chunk-IVLRPRXM.js} +2 -2
  105. package/dist/{chunk-GUZET4SG.js → chunk-JAQHWHUN.js} +4 -4
  106. package/dist/chunk-JAQHWHUN.js.map +1 -0
  107. package/dist/{chunk-Y2RKVFKR.js → chunk-K4JSTGXT.js} +2 -2
  108. package/dist/{chunk-EJLV62NI.js → chunk-KN4LUMH6.js} +2 -2
  109. package/dist/{chunk-23D6M6VM.js → chunk-KZA3DITX.js} +4 -4
  110. package/dist/{chunk-E2N2T5ZO.js → chunk-L2VM64HK.js} +2 -2
  111. package/dist/chunk-L4UL4IAR.js +55 -0
  112. package/dist/chunk-L4UL4IAR.js.map +1 -0
  113. package/dist/{chunk-UIYESRD6.js → chunk-LUCQY3OM.js} +10 -10
  114. package/dist/{chunk-UIYESRD6.js.map → chunk-LUCQY3OM.js.map} +1 -1
  115. package/dist/{chunk-O46CHQT7.js → chunk-MAQBYBUX.js} +4 -4
  116. package/dist/{chunk-EZOAKKTB.js → chunk-MBPZMZVB.js} +2 -2
  117. package/dist/{chunk-XQRFSKYM.js → chunk-MCNNZBG7.js} +2 -2
  118. package/dist/{chunk-YRXFFWG4.js → chunk-MLVPMDOZ.js} +2 -2
  119. package/dist/{chunk-5FE75J4S.js → chunk-MMCN7TLK.js} +5 -5
  120. package/dist/{chunk-MXOQ5JCG.js → chunk-MRCR7ZMC.js} +686 -202
  121. package/dist/chunk-MRCR7ZMC.js.map +1 -0
  122. package/dist/{chunk-SYNY3VB5.js → chunk-NCTN2FW4.js} +2 -2
  123. package/dist/{chunk-4T3SE27M.js → chunk-ND6S2DKC.js} +2 -2
  124. package/dist/{chunk-3XJQBBZD.js → chunk-NTVKHQ3L.js} +2 -2
  125. package/dist/{chunk-RHVMZSUU.js → chunk-NV4OESHC.js} +1 -1
  126. package/dist/chunk-NV4OESHC.js.map +1 -0
  127. package/dist/chunk-NXQEOC3X.js +40 -0
  128. package/dist/chunk-NXQEOC3X.js.map +1 -0
  129. package/dist/{chunk-Q4UHJ5SN.js → chunk-O2VQ3K36.js} +2 -2
  130. package/dist/{chunk-HW7CMKUG.js → chunk-OFD2HD6F.js} +1 -1
  131. package/dist/{chunk-HW7CMKUG.js.map → chunk-OFD2HD6F.js.map} +1 -1
  132. package/dist/{chunk-2GHDLTPE.js → chunk-OGKMRIIJ.js} +2 -2
  133. package/dist/{chunk-N7EVQD5S.js → chunk-ONZ3B5EW.js} +4 -4
  134. package/dist/{chunk-VKI2EB3N.js → chunk-OOPSMQX5.js} +3 -3
  135. package/dist/{chunk-VMV5SBE4.js → chunk-OYEBSWLE.js} +5 -5
  136. package/dist/{chunk-JDEYF3PJ.js → chunk-P6FATPXQ.js} +2 -2
  137. package/dist/chunk-P6FATPXQ.js.map +1 -0
  138. package/dist/{chunk-VVOLDVIR.js → chunk-PLTIJDQN.js} +2 -2
  139. package/dist/{chunk-OKSTSITU.js → chunk-PR7ILCIH.js} +3 -3
  140. package/dist/{chunk-7R2Q7CPL.js → chunk-QE3TLZ6Z.js} +7 -7
  141. package/dist/{chunk-G2MVBDFP.js → chunk-QFW4MYGN.js} +39 -9
  142. package/dist/chunk-QFW4MYGN.js.map +1 -0
  143. package/dist/{chunk-6QVKPHBF.js → chunk-QHG7GQKM.js} +2 -2
  144. package/dist/chunk-QJNAHPVT.js +91 -0
  145. package/dist/chunk-QJNAHPVT.js.map +1 -0
  146. package/dist/{chunk-LIOVX5TJ.js → chunk-QT5ITL25.js} +3 -3
  147. package/dist/{chunk-IMQKWR46.js → chunk-R2ZULFXU.js} +4 -5
  148. package/dist/chunk-R2ZULFXU.js.map +1 -0
  149. package/dist/{chunk-Q2XRFWOI.js → chunk-RRTQAQ3N.js} +2 -2
  150. package/dist/{chunk-H23XHRTT.js → chunk-RUE6TCES.js} +809 -101
  151. package/dist/chunk-RUE6TCES.js.map +1 -0
  152. package/dist/chunk-RWFQVNXR.js +24 -0
  153. package/dist/chunk-RWFQVNXR.js.map +1 -0
  154. package/dist/{chunk-2PVXF5CS.js → chunk-SALY3LIJ.js} +3 -3
  155. package/dist/{chunk-JOSPH3E5.js → chunk-SBAR5JQ6.js} +2 -2
  156. package/dist/{chunk-N7UDP5VU.js → chunk-SCH2F7R2.js} +7 -7
  157. package/dist/{chunk-MXKI4ABF.js → chunk-SOOAW6HK.js} +3 -3
  158. package/dist/{chunk-VQDZYB2B.js → chunk-T4VTRKCY.js} +3 -3
  159. package/dist/{chunk-VQDZYB2B.js.map → chunk-T4VTRKCY.js.map} +1 -1
  160. package/dist/{chunk-TEHHROZL.js → chunk-T5EXREMW.js} +5 -5
  161. package/dist/{chunk-M5B2W6YY.js → chunk-TDJVQTXD.js} +3 -3
  162. package/dist/{chunk-QMWY2FDS.js → chunk-THQ3BHLM.js} +2 -2
  163. package/dist/{chunk-VAORSCSU.js → chunk-TLIFNRU5.js} +2 -2
  164. package/dist/chunk-TLIFNRU5.js.map +1 -0
  165. package/dist/{chunk-FVH5QYY2.js → chunk-TRHUNPXP.js} +2 -2
  166. package/dist/{chunk-EGVJ7TM4.js → chunk-UL6MTRMJ.js} +8 -9
  167. package/dist/chunk-UL6MTRMJ.js.map +1 -0
  168. package/dist/chunk-UNL6YGL5.js +169 -0
  169. package/dist/chunk-UNL6YGL5.js.map +1 -0
  170. package/dist/{chunk-747G6CT3.js → chunk-UORWAG7K.js} +2 -2
  171. package/dist/{chunk-XSPFDUDG.js → chunk-V7AKGAXY.js} +314 -77
  172. package/dist/chunk-V7AKGAXY.js.map +1 -0
  173. package/dist/{chunk-TZZBXPZK.js → chunk-VLQ6KT7F.js} +2 -2
  174. package/dist/{chunk-NCO25JZO.js → chunk-VP37VUKQ.js} +4 -4
  175. package/dist/{chunk-52MGURXO.js → chunk-WBUHHMLN.js} +2 -2
  176. package/dist/{chunk-EZGV6F47.js → chunk-WRLWEYHY.js} +7 -1
  177. package/dist/chunk-WRLWEYHY.js.map +1 -0
  178. package/dist/{chunk-2MG3SW7Q.js → chunk-X6Z2SIRF.js} +2 -2
  179. package/dist/{chunk-U2FZNEWJ.js → chunk-XLKWF3L4.js} +8 -6
  180. package/dist/{chunk-U2FZNEWJ.js.map → chunk-XLKWF3L4.js.map} +1 -1
  181. package/dist/{chunk-5UMK7GRI.js → chunk-XPNJH7GN.js} +5 -5
  182. package/dist/{chunk-KZXDLBY6.js → chunk-XPW7T2GN.js} +5 -5
  183. package/dist/{chunk-SV2PM2OY.js → chunk-XX4R7TUB.js} +1 -1
  184. package/dist/chunk-XX4R7TUB.js.map +1 -0
  185. package/dist/{chunk-NBQ3KK6X.js → chunk-Y55XHMQB.js} +4 -4
  186. package/dist/chunk-Y55XHMQB.js.map +1 -0
  187. package/dist/{chunk-5KC7QYEC.js → chunk-YH4OUOSI.js} +33 -7
  188. package/dist/chunk-YH4OUOSI.js.map +1 -0
  189. package/dist/{chunk-FFJFE4T7.js → chunk-YJGKOSQD.js} +2 -2
  190. package/dist/{chunk-2AFX33YA.js → chunk-Z3STG43F.js} +3 -3
  191. package/dist/chunk-Z3STG43F.js.map +1 -0
  192. package/dist/{chunk-OIEO4WDL.js → chunk-ZD7WFMV2.js} +2 -2
  193. package/dist/chunk-ZD7WFMV2.js.map +1 -0
  194. package/dist/{chunk-42ALPZ2B.js → chunk-ZF6JECDT.js} +4 -4
  195. package/dist/{chunk-42ALPZ2B.js.map → chunk-ZF6JECDT.js.map} +1 -1
  196. package/dist/{chunk-4JPMZTJY.js → chunk-ZF7KNSLU.js} +2 -2
  197. package/dist/{chunk-2ODVB6LZ.js → chunk-ZGKODRGB.js} +2 -2
  198. package/dist/{chunk-JIBUPZHA.js → chunk-ZNEKQFGF.js} +4 -4
  199. package/dist/{chunk-DLD5LGDS.js → chunk-ZUTUNVFD.js} +3 -3
  200. package/dist/{chunk-JSMTXZR3.js → chunk-ZWMOHANW.js} +8 -6
  201. package/dist/chunk-ZWMOHANW.js.map +1 -0
  202. package/dist/{chunk-MILI22XQ.js → chunk-ZZZ4VCY2.js} +10 -10
  203. package/dist/chunk-ZZZ4VCY2.js.map +1 -0
  204. package/dist/classified/index.js +5 -5
  205. package/dist/{classified-marker-SIYKUU5L.js → classified-marker-WKP33U2R.js} +3 -3
  206. package/dist/collection-facade-COSGZKLC.js +41 -0
  207. package/dist/{computed-FAD7SED4.js → computed-WN6V53ZV.js} +3 -3
  208. package/dist/consent/index.js +8 -8
  209. package/dist/cover/index.js +8 -8
  210. package/dist/coverage/index.js +1 -1
  211. package/dist/custody/index.js +12 -11
  212. package/dist/{dead-filter-4F3LWYKH.js → dead-filter-43WL3Y5H.js} +10 -10
  213. package/dist/debug/index.js +7 -7
  214. package/dist/delegation-5UWT4JGT.js +26 -0
  215. package/dist/derivations/index.js +24 -23
  216. package/dist/derive-IL5JNLEE.js +20 -0
  217. package/dist/directory/index.js +9 -9
  218. package/dist/{dispatch-JDZNGEB3.js → dispatch-LOQQD5JK.js} +20 -20
  219. package/dist/{dispatch-H4HV32AM.js → dispatch-SHKTG57L.js} +5 -5
  220. package/dist/executor-6PQ7WAGV.js +35 -0
  221. package/dist/executor-6ZPQA6HS.js +8 -0
  222. package/dist/executor-OXRA64TY.js +8 -0
  223. package/dist/export-accessible-XG3FKJWW.js +22 -0
  224. package/dist/extract-partition-33747NY5.js +35 -0
  225. package/dist/{fanout-sidecar-L7NHPIOC.js → fanout-sidecar-NEB6IYV7.js} +8 -8
  226. package/dist/find-VW543G3J.js +10 -0
  227. package/dist/forget/index.js +25 -8
  228. package/dist/forget/index.js.map +1 -1
  229. package/dist/guards/index.js +4 -4
  230. package/dist/history/index.js +15 -13
  231. package/dist/history/index.js.map +1 -1
  232. package/dist/i18n/index.js +13 -13
  233. package/dist/index.d.ts +9 -6
  234. package/dist/index.js +126 -110
  235. package/dist/index.js.map +1 -1
  236. package/dist/indexing/index.js +6 -6
  237. package/dist/introspection/index.js +15 -11
  238. package/dist/issue-4ZPSY44M.js +19 -0
  239. package/dist/kernel/cache/index.d.ts +1 -1
  240. package/dist/kernel/collection.d.ts +86 -6
  241. package/dist/kernel/constants.d.ts +7 -0
  242. package/dist/kernel/errors.d.ts +42 -4
  243. package/dist/kernel/export-scope.d.ts +40 -0
  244. package/dist/kernel/merge-authority.d.ts +5 -1
  245. package/dist/kernel/noydb.d.ts +118 -21
  246. package/dist/kernel/put-many-atomic.d.ts +1 -1
  247. package/dist/kernel/query/live/live.d.ts +2 -1
  248. package/dist/kernel/query/sort-key.d.ts +0 -2
  249. package/dist/kernel/rejection-seal.d.ts +13 -0
  250. package/dist/kernel/sync-wiring.d.ts +55 -0
  251. package/dist/kernel/tx-write-gate.d.ts +2 -4
  252. package/dist/kernel/types.d.ts +463 -14
  253. package/dist/kernel/validation.d.ts +0 -10
  254. package/dist/kernel/vault.d.ts +42 -4
  255. package/dist/kernel/via/reconcile.d.ts +1 -42
  256. package/dist/{ledger-5ZMGE44K.js → ledger-MZ25UFT2.js} +10 -10
  257. package/dist/liberate-OJIP2ZFX.js +25 -0
  258. package/dist/{link-set-MFXC24VK.js → link-set-4FRRAVTH.js} +10 -10
  259. package/dist/{managed-secret-MFTFT22X.js → managed-secret-SQWO2EUR.js} +9 -9
  260. package/dist/materialized-views/index.js +26 -26
  261. package/dist/{migrate-cek-DZRFFOHW.js → migrate-cek-JWEM4RP6.js} +2 -2
  262. package/dist/money/index.js +5 -5
  263. package/dist/noydb-U62OVKXB.js +100 -0
  264. package/dist/on/index.js +25 -0
  265. package/dist/overlay-views/index.js +4 -4
  266. package/dist/periods/index.js +11 -11
  267. package/dist/pod/index.js +71 -67
  268. package/dist/{pod-handle-A3LET7NO.js → pod-handle-R6Y4MILX.js} +8 -8
  269. package/dist/policy/index.js +9 -9
  270. package/dist/port/as/active.d.ts +4 -0
  271. package/dist/port/as/index.d.ts +1 -0
  272. package/dist/port/by/index.d.ts +14 -5
  273. package/dist/port/on/index.d.ts +26 -0
  274. package/dist/port/to/index.d.ts +1 -1
  275. package/dist/port/with/admission-authority.d.ts +34 -0
  276. package/dist/port/with/broker-strategy.d.ts +24 -0
  277. package/dist/port/with/coverage-strategy.d.ts +17 -1
  278. package/dist/port/with/formats-strategy.d.ts +34 -1
  279. package/dist/port/with/lookup-strategy.d.ts +85 -4
  280. package/dist/port/with/rejection-courier.d.ts +37 -0
  281. package/dist/port/with/restore-host.d.ts +33 -0
  282. package/dist/port/with/service-bus.d.ts +20 -1
  283. package/dist/port/with/team-strategy.d.ts +2 -2
  284. package/dist/port/with/write-hooks.d.ts +2 -0
  285. package/dist/portability/index.js +8 -8
  286. package/dist/{post-register-7ND27CF2.js → post-register-GRVQHBOH.js} +6 -6
  287. package/dist/query/all/index.js +16 -16
  288. package/dist/query/index.js +8 -8
  289. package/dist/query/live/index.js +7 -7
  290. package/dist/query/reduce/index.js +10 -10
  291. package/dist/query/relate/index.js +10 -10
  292. package/dist/reduce/index.js +8 -8
  293. package/dist/register-YJ5YLQ36.js +30 -0
  294. package/dist/registry-ICOHBQFD.js +8 -0
  295. package/dist/registry-MJ7MWCSW.js +35 -0
  296. package/dist/registry-MVEKKGWL.js +23 -0
  297. package/dist/registry-XP744FAP.js +8 -0
  298. package/dist/request-withdrawal-LSU4G6W3.js +28 -0
  299. package/dist/restore-to-DVBHAQAA.js +66 -0
  300. package/dist/restore-to-DVBHAQAA.js.map +1 -0
  301. package/dist/{reveal-B2TLP4JQ.js → reveal-AIHOIK2N.js} +7 -7
  302. package/dist/revoke-QUT7WWG3.js +24 -0
  303. package/dist/satellites/index.js +1 -1
  304. package/dist/schema-update/index.js +2 -2
  305. package/dist/sealed-record/index.js +11 -11
  306. package/dist/search/index.js +4 -4
  307. package/dist/{seed-XNSE4U3S.js → seed-GFLA4FCK.js} +136 -27
  308. package/dist/seed-GFLA4FCK.js.map +1 -0
  309. package/dist/sequence/index.js +8 -8
  310. package/dist/session/index.js +8 -8
  311. package/dist/shadow/index.js +2 -2
  312. package/dist/signer-NYR4I3FO.js +23 -0
  313. package/dist/snapshots/index.js +9 -9
  314. package/dist/{stale-6GCFMOOR.js → stale-PIJPAL5T.js} +9 -9
  315. package/dist/storage-VH6SPXHC.js +21 -0
  316. package/dist/{store-coordination-provider-C4BPT5XF.js → store-coordination-provider-2KSHCOPU.js} +9 -9
  317. package/dist/sync/index.js +19 -13
  318. package/dist/sync/index.js.map +1 -1
  319. package/dist/team/index.js +17 -15
  320. package/dist/tiers/index.js +10 -10
  321. package/dist/to/index.js +2 -2
  322. package/dist/transactions/index.js +3 -3
  323. package/dist/util/index.js +1 -1
  324. package/dist/vault-head/index.js +8 -8
  325. package/dist/{verify-UKALW7C2.js → verify-PCFS4PNS.js} +7 -7
  326. package/dist/via/classified/presets.d.ts +29 -0
  327. package/dist/via/classified/resolve.d.ts +7 -0
  328. package/dist/via/geo/binding.d.ts +0 -4
  329. package/dist/via/lookup/index.d.ts +32 -0
  330. package/dist/via/money/binding.d.ts +0 -9
  331. package/dist/walk-OZCN6LJS.js +20 -0
  332. package/dist/with-audit/attestation/strategy.d.ts +2 -1
  333. package/dist/with-audit/attestation/vault-facade.d.ts +7 -0
  334. package/dist/with-audit/forget/completeness.d.ts +66 -0
  335. package/dist/with-audit/forget/index.d.ts +2 -0
  336. package/dist/with-audit/forget/strategy.d.ts +65 -0
  337. package/dist/with-audit/guards/types.d.ts +2 -0
  338. package/dist/with-audit/periods/periods.d.ts +0 -9
  339. package/dist/with-audit/periods/reserved-collections.d.ts +7 -0
  340. package/dist/with-audit/portability/request-withdrawal.d.ts +0 -1
  341. package/dist/with-audit/portability/withdraw-accessible.d.ts +0 -1
  342. package/dist/with-audit/tiers/index.d.ts +6 -6
  343. package/dist/with-audit/tiers/strategy.d.ts +19 -0
  344. package/dist/with-cargo/extract-partition.d.ts +0 -46
  345. package/dist/with-commit/history/history.d.ts +16 -0
  346. package/dist/with-commit/history/restore-to.d.ts +40 -0
  347. package/dist/with-commit/numbering/index.d.ts +0 -2
  348. package/dist/with-commit/tx/transaction.d.ts +2 -24
  349. package/dist/with-commit/vault-head/strategy.d.ts +7 -0
  350. package/dist/with-fork/snapshots/noydb-facade.d.ts +7 -0
  351. package/dist/with-formula/derivations/trigger-match.d.ts +8 -5
  352. package/dist/with-formula/materialized-views/emit-memo.d.ts +0 -2
  353. package/dist/with-lookup/embeddings/index.d.ts +1 -2
  354. package/dist/with-lookup/indexing/collection-facade.d.ts +1 -15
  355. package/dist/with-lookup/indexing/eager-indexes.d.ts +2 -1
  356. package/dist/with-lookup/search/collection-facade.d.ts +0 -12
  357. package/dist/with-party/broker/index.d.ts +2 -2
  358. package/dist/with-party/broker/seed.d.ts +29 -10
  359. package/dist/with-party/custody/strategy.d.ts +2 -2
  360. package/dist/with-party/policy/noydb-facade.d.ts +1 -31
  361. package/dist/with-party/team/delegation.d.ts +93 -7
  362. package/dist/with-party/team/echo-secret.d.ts +0 -2
  363. package/dist/with-party/team/index.d.ts +2 -0
  364. package/dist/with-party/team/keyring.d.ts +133 -24
  365. package/dist/with-party/team/magic-link-grant.d.ts +11 -1
  366. package/dist/with-party/team/noydb-facade.d.ts +19 -2
  367. package/dist/with-party/team/reserved-secret-collections.d.ts +10 -8
  368. package/dist/with-party/team/roster-tag.d.ts +42 -1
  369. package/dist/with-party/team/tiers.d.ts +36 -5
  370. package/dist/with-pod/backup.d.ts +9 -17
  371. package/dist/with-shape/blobs/blob-set.d.ts +23 -0
  372. package/dist/with-shape/blobs/legacy-sweep.d.ts +16 -0
  373. package/dist/with-shape/introspection/describe.d.ts +1 -2
  374. package/dist/with-shape/introspection/index.d.ts +1 -0
  375. package/dist/with-shape/introspection/types.d.ts +2 -1
  376. package/dist/with-shape/schema-update/fence.d.ts +7 -0
  377. package/dist/with-sync/active.d.ts +28 -1
  378. package/dist/with-sync/engine.d.ts +88 -2
  379. package/dist/with-sync/index.d.ts +1 -0
  380. package/dist/with-sync/reserved-mirror.d.ts +112 -0
  381. package/dist/with-sync/strategy.d.ts +9 -0
  382. package/dist/with-sync/tab-write-relay.d.ts +0 -10
  383. package/dist/withdraw-accessible-MTFP7OIB.js +25 -0
  384. package/dist/withdraw-accessible-MTFP7OIB.js.map +1 -0
  385. package/package.json +3 -3
  386. package/dist/api-OS747DS4.js +0 -18
  387. package/dist/backup-YE2VQ26S.js.map +0 -1
  388. package/dist/chunk-2AFX33YA.js.map +0 -1
  389. package/dist/chunk-2RH777HH.js +0 -126
  390. package/dist/chunk-2RH777HH.js.map +0 -1
  391. package/dist/chunk-37EPTBBR.js.map +0 -1
  392. package/dist/chunk-5KC7QYEC.js.map +0 -1
  393. package/dist/chunk-7XMHMVTS.js +0 -20
  394. package/dist/chunk-7XMHMVTS.js.map +0 -1
  395. package/dist/chunk-A4XMIZT3.js.map +0 -1
  396. package/dist/chunk-DHHGL42E.js.map +0 -1
  397. package/dist/chunk-DQESF6RP.js.map +0 -1
  398. package/dist/chunk-EGVJ7TM4.js.map +0 -1
  399. package/dist/chunk-EYG2CY2X.js.map +0 -1
  400. package/dist/chunk-EZGV6F47.js.map +0 -1
  401. package/dist/chunk-FFWI7UH7.js.map +0 -1
  402. package/dist/chunk-G2MVBDFP.js.map +0 -1
  403. package/dist/chunk-GUZET4SG.js.map +0 -1
  404. package/dist/chunk-GZT3NQRA.js.map +0 -1
  405. package/dist/chunk-H23XHRTT.js.map +0 -1
  406. package/dist/chunk-H7JBY4P7.js.map +0 -1
  407. package/dist/chunk-IMQKWR46.js.map +0 -1
  408. package/dist/chunk-IUBMZPHM.js.map +0 -1
  409. package/dist/chunk-IUT3GWP3.js.map +0 -1
  410. package/dist/chunk-JDEYF3PJ.js.map +0 -1
  411. package/dist/chunk-JSMTXZR3.js.map +0 -1
  412. package/dist/chunk-LGNDFRYC.js.map +0 -1
  413. package/dist/chunk-LNSVGRHO.js.map +0 -1
  414. package/dist/chunk-MILI22XQ.js.map +0 -1
  415. package/dist/chunk-MXOQ5JCG.js.map +0 -1
  416. package/dist/chunk-NBQ3KK6X.js.map +0 -1
  417. package/dist/chunk-OIEO4WDL.js.map +0 -1
  418. package/dist/chunk-PD64727P.js.map +0 -1
  419. package/dist/chunk-RHVMZSUU.js.map +0 -1
  420. package/dist/chunk-SV2PM2OY.js.map +0 -1
  421. package/dist/chunk-T7IR4N2S.js.map +0 -1
  422. package/dist/chunk-UA372JHH.js.map +0 -1
  423. package/dist/chunk-UBSFPGVJ.js +0 -1
  424. package/dist/chunk-V3RWOOSO.js.map +0 -1
  425. package/dist/chunk-VAORSCSU.js.map +0 -1
  426. package/dist/chunk-XSPFDUDG.js.map +0 -1
  427. package/dist/chunk-Y3LPTBG7.js.map +0 -1
  428. package/dist/collection-facade-CS7CA2XO.js +0 -47
  429. package/dist/delegation-NANZDG4N.js +0 -102
  430. package/dist/delegation-NANZDG4N.js.map +0 -1
  431. package/dist/derive-XLOJVXPU.js +0 -20
  432. package/dist/executor-FMPVN6DT.js +0 -35
  433. package/dist/executor-LBBBRTN5.js +0 -8
  434. package/dist/executor-OSRZST2U.js +0 -8
  435. package/dist/export-accessible-RAOJAAU5.js +0 -22
  436. package/dist/extract-partition-JD5CUSTG.js +0 -37
  437. package/dist/find-JRN4RNQ5.js +0 -10
  438. package/dist/issue-YIVBZUTH.js +0 -19
  439. package/dist/liberate-WZSZM2W6.js +0 -24
  440. package/dist/noydb-ITIGNKUF.js +0 -96
  441. package/dist/register-DT5HZ2LZ.js +0 -30
  442. package/dist/registry-BHRZGZHF.js +0 -8
  443. package/dist/registry-ET6ZFFWA.js +0 -34
  444. package/dist/registry-HXFGLGTG.js +0 -8
  445. package/dist/registry-THCPDEOD.js +0 -23
  446. package/dist/request-withdrawal-AV2MJJKY.js +0 -30
  447. package/dist/revoke-6DWIEOCV.js +0 -24
  448. package/dist/seed-XNSE4U3S.js.map +0 -1
  449. package/dist/signer-MHGW3OIL.js +0 -23
  450. package/dist/storage-BYN5LO6Z.js +0 -21
  451. package/dist/walk-4VPK7AS4.js +0 -20
  452. package/dist/withdraw-accessible-HL7GACUE.js +0 -27
  453. /package/dist/{api-OS747DS4.js.map → api-6EFD43KN.js.map} +0 -0
  454. /package/dist/{capsule-VOLX3QRQ.js.map → capsule-6LJAVQNM.js.map} +0 -0
  455. /package/dist/{chunk-OYW3I5M4.js.map → chunk-2DOCDOPL.js.map} +0 -0
  456. /package/dist/{chunk-UBSFPGVJ.js.map → chunk-2DX4JCRI.js.map} +0 -0
  457. /package/dist/{chunk-FLPCETP6.js.map → chunk-2LBS62AC.js.map} +0 -0
  458. /package/dist/{chunk-WXE4W2U6.js.map → chunk-2ST3WA3C.js.map} +0 -0
  459. /package/dist/{chunk-O2IMQSNA.js.map → chunk-3YBIVLTC.js.map} +0 -0
  460. /package/dist/{chunk-DIZLQVAA.js.map → chunk-4CHM2TRS.js.map} +0 -0
  461. /package/dist/{chunk-V7ADQF5O.js.map → chunk-4CUJLEOA.js.map} +0 -0
  462. /package/dist/{chunk-3EWS67C7.js.map → chunk-4TG2ITRW.js.map} +0 -0
  463. /package/dist/{chunk-HS554XAF.js.map → chunk-5HQFROZS.js.map} +0 -0
  464. /package/dist/{chunk-PP3K67AJ.js.map → chunk-654RE5YC.js.map} +0 -0
  465. /package/dist/{chunk-FOEDQATO.js.map → chunk-66GD7XXU.js.map} +0 -0
  466. /package/dist/{chunk-BNWA3WG5.js.map → chunk-72FQ46VW.js.map} +0 -0
  467. /package/dist/{chunk-JQYKPKG6.js.map → chunk-7K42TSCY.js.map} +0 -0
  468. /package/dist/{chunk-UEFOQH74.js.map → chunk-ADCXTW7L.js.map} +0 -0
  469. /package/dist/{chunk-MBMTND6D.js.map → chunk-AGGPT4UE.js.map} +0 -0
  470. /package/dist/{chunk-RB4DOPGZ.js.map → chunk-AKIEBFIJ.js.map} +0 -0
  471. /package/dist/{chunk-VHBKYN2J.js.map → chunk-B3B6HV5S.js.map} +0 -0
  472. /package/dist/{chunk-JWWYRR4Q.js.map → chunk-B6EWMGFX.js.map} +0 -0
  473. /package/dist/{chunk-WPOYWFSE.js.map → chunk-BJRKXNFP.js.map} +0 -0
  474. /package/dist/{chunk-H427H63K.js.map → chunk-BPQ5CRJF.js.map} +0 -0
  475. /package/dist/{chunk-VFHCKG5M.js.map → chunk-BVRJYMFZ.js.map} +0 -0
  476. /package/dist/{chunk-SMV2HRDU.js.map → chunk-DFC4WTJW.js.map} +0 -0
  477. /package/dist/{chunk-5A4345TG.js.map → chunk-DMIEKD24.js.map} +0 -0
  478. /package/dist/{chunk-TKVUE4JF.js.map → chunk-DQAXA2GK.js.map} +0 -0
  479. /package/dist/{chunk-AL6ML4LA.js.map → chunk-DWCFGF2K.js.map} +0 -0
  480. /package/dist/{chunk-QBLT6POL.js.map → chunk-FPF5HRBE.js.map} +0 -0
  481. /package/dist/{chunk-5WWDGFOS.js.map → chunk-GIQJGXV7.js.map} +0 -0
  482. /package/dist/{chunk-BVCUTXE3.js.map → chunk-H334G6KU.js.map} +0 -0
  483. /package/dist/{chunk-AEQGFRU4.js.map → chunk-HE7EAHGS.js.map} +0 -0
  484. /package/dist/{chunk-4V3Q35WG.js.map → chunk-ICF3TIGY.js.map} +0 -0
  485. /package/dist/{chunk-3L2NBKDR.js.map → chunk-IF2M43G4.js.map} +0 -0
  486. /package/dist/{chunk-AUKKUPVB.js.map → chunk-IVLRPRXM.js.map} +0 -0
  487. /package/dist/{chunk-Y2RKVFKR.js.map → chunk-K4JSTGXT.js.map} +0 -0
  488. /package/dist/{chunk-EJLV62NI.js.map → chunk-KN4LUMH6.js.map} +0 -0
  489. /package/dist/{chunk-23D6M6VM.js.map → chunk-KZA3DITX.js.map} +0 -0
  490. /package/dist/{chunk-E2N2T5ZO.js.map → chunk-L2VM64HK.js.map} +0 -0
  491. /package/dist/{chunk-O46CHQT7.js.map → chunk-MAQBYBUX.js.map} +0 -0
  492. /package/dist/{chunk-EZOAKKTB.js.map → chunk-MBPZMZVB.js.map} +0 -0
  493. /package/dist/{chunk-XQRFSKYM.js.map → chunk-MCNNZBG7.js.map} +0 -0
  494. /package/dist/{chunk-YRXFFWG4.js.map → chunk-MLVPMDOZ.js.map} +0 -0
  495. /package/dist/{chunk-5FE75J4S.js.map → chunk-MMCN7TLK.js.map} +0 -0
  496. /package/dist/{chunk-SYNY3VB5.js.map → chunk-NCTN2FW4.js.map} +0 -0
  497. /package/dist/{chunk-4T3SE27M.js.map → chunk-ND6S2DKC.js.map} +0 -0
  498. /package/dist/{chunk-3XJQBBZD.js.map → chunk-NTVKHQ3L.js.map} +0 -0
  499. /package/dist/{chunk-Q4UHJ5SN.js.map → chunk-O2VQ3K36.js.map} +0 -0
  500. /package/dist/{chunk-2GHDLTPE.js.map → chunk-OGKMRIIJ.js.map} +0 -0
  501. /package/dist/{chunk-N7EVQD5S.js.map → chunk-ONZ3B5EW.js.map} +0 -0
  502. /package/dist/{chunk-VKI2EB3N.js.map → chunk-OOPSMQX5.js.map} +0 -0
  503. /package/dist/{chunk-VMV5SBE4.js.map → chunk-OYEBSWLE.js.map} +0 -0
  504. /package/dist/{chunk-VVOLDVIR.js.map → chunk-PLTIJDQN.js.map} +0 -0
  505. /package/dist/{chunk-OKSTSITU.js.map → chunk-PR7ILCIH.js.map} +0 -0
  506. /package/dist/{chunk-7R2Q7CPL.js.map → chunk-QE3TLZ6Z.js.map} +0 -0
  507. /package/dist/{chunk-6QVKPHBF.js.map → chunk-QHG7GQKM.js.map} +0 -0
  508. /package/dist/{chunk-LIOVX5TJ.js.map → chunk-QT5ITL25.js.map} +0 -0
  509. /package/dist/{chunk-Q2XRFWOI.js.map → chunk-RRTQAQ3N.js.map} +0 -0
  510. /package/dist/{chunk-2PVXF5CS.js.map → chunk-SALY3LIJ.js.map} +0 -0
  511. /package/dist/{chunk-JOSPH3E5.js.map → chunk-SBAR5JQ6.js.map} +0 -0
  512. /package/dist/{chunk-N7UDP5VU.js.map → chunk-SCH2F7R2.js.map} +0 -0
  513. /package/dist/{chunk-MXKI4ABF.js.map → chunk-SOOAW6HK.js.map} +0 -0
  514. /package/dist/{chunk-TEHHROZL.js.map → chunk-T5EXREMW.js.map} +0 -0
  515. /package/dist/{chunk-M5B2W6YY.js.map → chunk-TDJVQTXD.js.map} +0 -0
  516. /package/dist/{chunk-QMWY2FDS.js.map → chunk-THQ3BHLM.js.map} +0 -0
  517. /package/dist/{chunk-FVH5QYY2.js.map → chunk-TRHUNPXP.js.map} +0 -0
  518. /package/dist/{chunk-747G6CT3.js.map → chunk-UORWAG7K.js.map} +0 -0
  519. /package/dist/{chunk-TZZBXPZK.js.map → chunk-VLQ6KT7F.js.map} +0 -0
  520. /package/dist/{chunk-NCO25JZO.js.map → chunk-VP37VUKQ.js.map} +0 -0
  521. /package/dist/{chunk-52MGURXO.js.map → chunk-WBUHHMLN.js.map} +0 -0
  522. /package/dist/{chunk-2MG3SW7Q.js.map → chunk-X6Z2SIRF.js.map} +0 -0
  523. /package/dist/{chunk-5UMK7GRI.js.map → chunk-XPNJH7GN.js.map} +0 -0
  524. /package/dist/{chunk-KZXDLBY6.js.map → chunk-XPW7T2GN.js.map} +0 -0
  525. /package/dist/{chunk-FFJFE4T7.js.map → chunk-YJGKOSQD.js.map} +0 -0
  526. /package/dist/{chunk-4JPMZTJY.js.map → chunk-ZF7KNSLU.js.map} +0 -0
  527. /package/dist/{chunk-2ODVB6LZ.js.map → chunk-ZGKODRGB.js.map} +0 -0
  528. /package/dist/{chunk-JIBUPZHA.js.map → chunk-ZNEKQFGF.js.map} +0 -0
  529. /package/dist/{chunk-DLD5LGDS.js.map → chunk-ZUTUNVFD.js.map} +0 -0
  530. /package/dist/{classified-marker-SIYKUU5L.js.map → classified-marker-WKP33U2R.js.map} +0 -0
  531. /package/dist/{collection-facade-CS7CA2XO.js.map → collection-facade-COSGZKLC.js.map} +0 -0
  532. /package/dist/{computed-FAD7SED4.js.map → computed-WN6V53ZV.js.map} +0 -0
  533. /package/dist/{dead-filter-4F3LWYKH.js.map → dead-filter-43WL3Y5H.js.map} +0 -0
  534. /package/dist/{derive-XLOJVXPU.js.map → delegation-5UWT4JGT.js.map} +0 -0
  535. /package/dist/{executor-FMPVN6DT.js.map → derive-IL5JNLEE.js.map} +0 -0
  536. /package/dist/{dispatch-JDZNGEB3.js.map → dispatch-LOQQD5JK.js.map} +0 -0
  537. /package/dist/{dispatch-H4HV32AM.js.map → dispatch-SHKTG57L.js.map} +0 -0
  538. /package/dist/{executor-LBBBRTN5.js.map → executor-6PQ7WAGV.js.map} +0 -0
  539. /package/dist/{executor-OSRZST2U.js.map → executor-6ZPQA6HS.js.map} +0 -0
  540. /package/dist/{export-accessible-RAOJAAU5.js.map → executor-OXRA64TY.js.map} +0 -0
  541. /package/dist/{extract-partition-JD5CUSTG.js.map → export-accessible-XG3FKJWW.js.map} +0 -0
  542. /package/dist/{find-JRN4RNQ5.js.map → extract-partition-33747NY5.js.map} +0 -0
  543. /package/dist/{fanout-sidecar-L7NHPIOC.js.map → fanout-sidecar-NEB6IYV7.js.map} +0 -0
  544. /package/dist/{issue-YIVBZUTH.js.map → find-VW543G3J.js.map} +0 -0
  545. /package/dist/{ledger-5ZMGE44K.js.map → issue-4ZPSY44M.js.map} +0 -0
  546. /package/dist/{liberate-WZSZM2W6.js.map → ledger-MZ25UFT2.js.map} +0 -0
  547. /package/dist/{link-set-MFXC24VK.js.map → liberate-OJIP2ZFX.js.map} +0 -0
  548. /package/dist/{managed-secret-MFTFT22X.js.map → link-set-4FRRAVTH.js.map} +0 -0
  549. /package/dist/{noydb-ITIGNKUF.js.map → managed-secret-SQWO2EUR.js.map} +0 -0
  550. /package/dist/{migrate-cek-DZRFFOHW.js.map → migrate-cek-JWEM4RP6.js.map} +0 -0
  551. /package/dist/{register-DT5HZ2LZ.js.map → noydb-U62OVKXB.js.map} +0 -0
  552. /package/dist/{pod-handle-A3LET7NO.js.map → pod-handle-R6Y4MILX.js.map} +0 -0
  553. /package/dist/{post-register-7ND27CF2.js.map → post-register-GRVQHBOH.js.map} +0 -0
  554. /package/dist/{registry-BHRZGZHF.js.map → register-YJ5YLQ36.js.map} +0 -0
  555. /package/dist/{registry-ET6ZFFWA.js.map → registry-ICOHBQFD.js.map} +0 -0
  556. /package/dist/{registry-HXFGLGTG.js.map → registry-MJ7MWCSW.js.map} +0 -0
  557. /package/dist/{registry-THCPDEOD.js.map → registry-MVEKKGWL.js.map} +0 -0
  558. /package/dist/{request-withdrawal-AV2MJJKY.js.map → registry-XP744FAP.js.map} +0 -0
  559. /package/dist/{revoke-6DWIEOCV.js.map → request-withdrawal-LSU4G6W3.js.map} +0 -0
  560. /package/dist/{reveal-B2TLP4JQ.js.map → reveal-AIHOIK2N.js.map} +0 -0
  561. /package/dist/{signer-MHGW3OIL.js.map → revoke-QUT7WWG3.js.map} +0 -0
  562. /package/dist/{stale-6GCFMOOR.js.map → signer-NYR4I3FO.js.map} +0 -0
  563. /package/dist/{storage-BYN5LO6Z.js.map → stale-PIJPAL5T.js.map} +0 -0
  564. /package/dist/{walk-4VPK7AS4.js.map → storage-VH6SPXHC.js.map} +0 -0
  565. /package/dist/{store-coordination-provider-C4BPT5XF.js.map → store-coordination-provider-2KSHCOPU.js.map} +0 -0
  566. /package/dist/{verify-UKALW7C2.js.map → verify-PCFS4PNS.js.map} +0 -0
  567. /package/dist/{withdraw-accessible-HL7GACUE.js.map → walk-OZCN6LJS.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/kernel/query/live/live.ts","../src/kernel/query/live/methods.ts","../src/kernel/query/live/install.ts"],"sourcesContent":["/**\n * Reactive query primitive — `query.live()`.\n *\n * produces a `LiveQuery<T>` that re-runs the query and\n * updates its `value` whenever any source feeding it (the left\n * collection AND every right-side collection a join leg points at)\n * mutates.\n *\n * Framework-agnostic by design — core never depends on a UI\n * framework. The framework bindings live in the `noy-db/in` repo\n * (extracted 2026-09-21). The one that wraps a `LiveQuery` is\n * `@noy-db/in-vue`'s `useLiveQuery(live)`: it subscribes once,\n * mirrors `value` into a `ShallowRef`, re-reads `error` on every\n * notification, and disposes via `onScopeDispose`.\n * `@noy-db/in-pinia`'s `store.liveQuery(build)` delegates to it, so\n * there is one implementation rather than two that drift (#1131).\n *\n * There is NO wrapper for `in-react`, `in-solid` or `in-svelte` — a\n * consumer on those subscribes directly (see **Error semantics**\n * below, which is the part a hand-rolled wrapper usually gets\n * wrong). Do not describe those adapters as existing until one does.\n *\n * **Error semantics.** A `.live()` query may throw at re-run time —\n * a strict-mode `DanglingReferenceError` is the most common case\n * (a right-side record was deleted out-of-band, leaving a left\n * row's FK pointing at nothing). When the re-run throws, the\n * `LiveQuery` catches the error and stores it in the `error`\n * field; it does NOT propagate the throw out of the source's\n * change handler, because doing so would tear down whatever\n * upstream emitter is dispatching. Listeners check `error` after\n * each notification and render an error state in the UI.\n *\n * **Dedup of right-side subscriptions.** A multi-FK chain that\n * joins the same target twice (e.g.\n * `.join('billingClientId').join('shippingClientId')`, both\n * pointing at `clients`) only subscribes to that target once. We\n * dedup by target collection name, on the assumption that\n * `resolveSource(name)` returns a single subscribable source per\n * vault + name. Vault's `resolveSource` reads from\n * `collectionCache` so this assumption holds.\n *\n * **Delta maintenance (#1341).** A live query over a plan\n * `canMaintainIncrementally()` admits no longer re-runs: the change event\n * carries which record moved, and `LiveMaintainer` patches the result set —\n * one predicate evaluation, a binary search, a splice. The emitted value is\n * identical to a re-run's, because the maintainer is handed the query's OWN\n * membership test and sort comparator. Every other plan, and every\n * notification that arrives without a delta, re-runs exactly as before.\n *\n * **What .live() still does NOT do:**\n * - No batching unless asked — `live({ batch: true })` coalesces a burst\n * into one recompute + one notification on a microtask; the default stays\n * one event in, one notification out, because batching makes `value`\n * stale until the microtask runs.\n * - No async notifications — every unbatched notification is synchronous\n * within the source's change handler.\n * - No re-planning under live mutations — the planner picks once\n * at subscription time and reuses the same plan for every\n * re-run.\n */\n\nimport type { LiveMaintainer, SourceChange } from './incremental.js'\n\n/**\n * The reactive primitive returned by `Query.live()`.\n *\n * Listeners can read the current `value` snapshot at any time and\n * subscribe to changes via `.subscribe(cb)`. The `error` field\n * carries the most recent re-run error, if any — read it after\n * each notification to render error state.\n *\n * Always call `stop()` when the live query is no longer needed.\n * Without it, the upstream change-stream subscriptions stay live\n * forever and the query keeps re-running on every mutation.\n */\nexport interface LiveQuery<T> {\n /**\n * Current snapshot of the query result.\n *\n * **A FRESH ARRAY on every successful re-run** — `refresh()` assigns\n * `this._value = this.recompute()`, and `recompute` is the query's own\n * `toArray()`. So the reference CHANGES on each change, and reference\n * identity is a valid change signal: a Vue `shallowRef`, a React\n * `useState`, or any `Object.is` comparison detects an update without\n * copying.\n *\n * The corollary is the part that bites: a consumer who reads `value`\n * ONCE and holds the array gets a snapshot that never updates. Read it\n * again after each notification — do not cache it.\n *\n * (An earlier version of this comment said the opposite — \"updated in\n * place… the reference returned is the same array\" — and told callers to\n * copy for change detection. Both halves were wrong, and the advice was\n * backwards. Verified against `buildLiveQuery`: two reads across a\n * notification are not `===`, and the first array still holds the old\n * contents.)\n */\n readonly value: readonly T[]\n /**\n * Most recent re-run error, or `null` on success. Set when the\n * executor throws (e.g. `DanglingReferenceError` in strict mode\n * after a right-side delete). Cleared on the next successful\n * re-run.\n */\n readonly error: Error | null\n /**\n * Register a notification callback. Fires AFTER `value` and\n * `error` have been updated for a given upstream change.\n * Returns an unsubscribe function.\n *\n * The first call to `subscribe` does NOT fire the callback\n * immediately — call sites that want the initial value should\n * read `live.value` directly before subscribing.\n */\n subscribe(cb: () => void): () => void\n /**\n * Tear down every upstream subscription and clear the listener\n * set. Idempotent — calling twice is safe. After `stop()`, the\n * query no longer re-runs and `subscribe()` becomes a no-op\n * (the returned unsubscribe is still callable and is also a\n * no-op).\n */\n stop(): void\n}\n\n/**\n * Internal subscription handle for an upstream source — left or\n * right side. The contract is just `subscribe(cb): unsubscribe`,\n * matching the existing `QuerySource.subscribe` and the new\n * `JoinableSource.subscribe` (added in ).\n */\nexport interface LiveUpstream {\n /**\n * `cb` may be handed the delta that caused the notification (#1341) so the\n * live query can patch its result set instead of re-running. Calling it with\n * NO argument is always valid and always correct — it means \"something\n * changed, I can't say what\", and the live query answers with a full re-run.\n */\n subscribe(cb: (change?: SourceChange) => void): () => void\n}\n\n/** Options for {@link buildLiveQuery}. */\nexport interface LiveBuildOptions {\n /**\n * Coalesce a burst of upstream changes into ONE recompute and ONE\n * notification, flushed on a microtask (#1341). Off by default: with it on,\n * `live.value` is stale until the microtask runs, so a consumer that reads\n * synchronously after an `await put()` would see the old value.\n */\n readonly batch?: boolean\n /**\n * Incremental maintainer for this query's result set. When present it\n * REPLACES `recompute` as the value source — it patches per delta and\n * rebuilds itself whenever a delta is not provably patchable.\n */\n readonly maintainer?: LiveMaintainer\n}\n\n/**\n * Build a LiveQuery from a `recompute` callback (typically the\n * Query's bound `toArray`) and a list of upstream sources to\n * subscribe to.\n *\n * The recompute fires once synchronously to populate the initial\n * value, then re-fires every time any upstream notifies. Errors\n * thrown by recompute are caught and stored in `error` instead of\n * propagating — see the file docstring for the rationale.\n */\nexport function buildLiveQuery<T>(\n recompute: () => T[],\n upstreams: readonly LiveUpstream[],\n options?: LiveBuildOptions,\n): LiveQuery<T> {\n return new LiveQueryImpl<T>(recompute, upstreams, options)\n}\n\nclass LiveQueryImpl<T> implements LiveQuery<T> {\n private _value: readonly T[] = []\n private _error: Error | null = null\n private readonly listeners = new Set<() => void>()\n private readonly unsubs: Array<() => void> = []\n private stopped = false\n\n private readonly maintainer: LiveMaintainer | undefined\n private readonly batch: boolean\n private queued: Array<SourceChange | undefined> = []\n private flushScheduled = false\n\n constructor(\n private readonly recompute: () => T[],\n upstreams: readonly LiveUpstream[],\n options?: LiveBuildOptions,\n ) {\n this.maintainer = options?.maintainer\n this.batch = options?.batch === true\n // From here on the maintainer is delta-driven: it patches on every event\n // and only rebuilds when it has to.\n this.maintainer?.attach()\n // Initial compute. If this throws, the constructor still\n // succeeds — we want consumers to be able to render an error\n // state from `live.error` rather than wrapping every\n // `query.live()` call in a try/catch.\n this.refresh()\n for (const upstream of upstreams) {\n try {\n this.unsubs.push(upstream.subscribe(this.onUpstreamChange))\n } catch (err) {\n // Upstream subscription failed — record it as the live\n // error and continue with the upstreams that did work.\n // The LiveQuery is now degraded (won't re-fire on this\n // upstream's changes) but isn't broken; consumers can\n // detect this via `live.error`.\n this._error = err instanceof Error ? err : new Error(String(err))\n }\n }\n }\n\n get value(): readonly T[] {\n return this._value\n }\n\n get error(): Error | null {\n return this._error\n }\n\n /**\n * Bound change handler — used as the callback passed to every\n * upstream's subscribe. Bound via class field so the `this`\n * context survives the indirect call from arbitrary upstreams.\n */\n private readonly onUpstreamChange = (change?: SourceChange): void => {\n if (this.batch) {\n this.queued.push(change)\n if (!this.flushScheduled) {\n this.flushScheduled = true\n queueMicrotask(this.flush)\n }\n return\n }\n this.absorb([change])\n this.notify()\n }\n\n /**\n * Drain a coalesced burst: every queued delta is folded in, then the value\n * is read ONCE and listeners are notified ONCE.\n */\n private readonly flush = (): void => {\n this.flushScheduled = false\n const batch = this.queued\n this.queued = []\n if (this.stopped) return\n this.absorb(batch)\n this.notify()\n }\n\n private absorb(changes: ReadonlyArray<SourceChange | undefined>): void {\n if (this.stopped) return\n if (this.maintainer) {\n try {\n for (const change of changes) this.maintainer.apply(change)\n } catch {\n // A predicate threw mid-patch. Drop the maintained state and let the\n // read below rebuild: it runs the same predicate, so the consumer sees\n // exactly the error (and the preserved last-good value) a full re-run\n // would have produced.\n this.maintainer.invalidate()\n }\n }\n this.refresh()\n }\n\n private notify(): void {\n for (const cb of this.listeners) {\n try {\n cb()\n } catch {\n // Listener errors are isolated — one buggy consumer\n // doesn't break the others or tear down the live query.\n }\n }\n }\n\n private refresh(): void {\n if (this.stopped) return\n try {\n this._value = (this.maintainer ? this.maintainer.rows() : this.recompute()) as T[]\n this._error = null\n } catch (err) {\n this._error = err instanceof Error ? err : new Error(String(err))\n // Whatever the maintainer holds is no longer trustworthy — the next\n // read pays for a rebuild rather than serving a half-patched set.\n this.maintainer?.invalidate()\n // Don't clobber the previous value on error — consumers\n // typically want to keep showing the last known good state\n // alongside the error message rather than flashing to an\n // empty list.\n }\n }\n\n subscribe(cb: () => void): () => void {\n if (this.stopped) return () => {}\n this.listeners.add(cb)\n return () => this.listeners.delete(cb)\n }\n\n stop(): void {\n if (this.stopped) return\n this.stopped = true\n for (const unsub of this.unsubs) {\n try {\n unsub()\n } catch {\n // Unsub errors are swallowed — at this point we're tearing\n // down anyway and the failure is noise.\n }\n }\n this.unsubs.length = 0\n this.listeners.clear()\n }\n}\n","/**\n * #1458 — **Live**: the same plan, re-run on change.\n *\n * `subscribe` · `live`\n *\n * Bodies moved out of `kernel/query/builder.ts` unchanged; see\n * `../relate/methods.ts` for why `this.plan` still resolves.\n */\nimport type { DeclaredPredicate, InternalSource, QueryPlan } from '../builder.js'\nimport type { JoinContext } from '../relate/join.js'\nimport type { ReduceStrategy } from '../../../with-lookup/reduce/strategy.js'\nimport type { LiveQuery, LiveUpstream } from './live.js'\nimport { buildLiveQuery } from './live.js'\nimport type { LiveMaintainer } from './incremental.js'\nimport type { DateTruncKey } from '../reduce/date-trunc.js'\nimport type { GroupMaintenanceSource } from './incremental.js'\nimport { gateTerminal } from '../hydration.js'\n\n/** @internal — the mixin whose prototype `./index.ts` copies onto `Query`. */\n /* eslint-disable @typescript-eslint/no-unused-vars -- #1458: the parameter\n list must match `Query`'s exactly (T, S, Q, M) because `declare module`\n merges this mixin's `Pick` into it, and TypeScript requires every\n declaration of an interface to carry identical type parameters. A group\n whose methods happen to use only `T` still declares all four. */\nexport class LiveMethods<\n T,\n S extends keyof T = never,\n Q extends keyof T & string = never,\n M extends keyof T & string = never,\n /* eslint-enable @typescript-eslint/no-unused-vars */\n> {\n declare protected readonly source: InternalSource\n declare protected readonly plan: QueryPlan\n declare protected readonly joinContext: JoinContext | undefined\n declare protected readonly reduceStrategy: ReduceStrategy\n declare protected readonly predicates: ReadonlyMap<string, DeclaredPredicate> | undefined\n declare protected decodeVia: (records: readonly unknown[], locale?: string) => unknown[]\n declare protected incrementalMaintainer: (mode: 'rows' | 'records') => LiveMaintainer | undefined\n declare protected groupMaintenance: (derived: readonly DateTruncKey[]) => GroupMaintenanceSource | undefined\n declare toArray: (opts?: { locale?: string }) => T[]\n\n /**\n * Re-run the query whenever the source notifies of changes.\n * Returns an unsubscribe function. The callback receives the latest result.\n * Throws if the source does not support subscriptions.\n *\n * **For joined queries, prefer `.live()`** — `subscribe()`\n * only re-fires on LEFT-side changes, so joined data can be\n * stale if the right side mutates between emissions. `.live()`\n * merges change streams from every join target.\n */\n subscribe(cb: (result: T[]) => void): () => void {\n const _h = this.source.hydration\n if (_h !== undefined && !_h.isHydrated()) return gateTerminal(_h, 'subscribe', () => this.subscribe(cb))\n if (!this.source.subscribe) {\n throw new Error('Query source does not support subscriptions. Pass a source with a subscribe() method.')\n }\n cb(this.toArray())\n return this.source.subscribe(() => cb(this.toArray()))\n }\n\n /**\n * Reactive terminal — returns a `LiveQuery<T>` that re-runs the\n * query and updates its `value` whenever any source feeding it\n * mutates..\n *\n * For non-joined queries, `.live()` is a convenience over the\n * existing `.subscribe()` callback shape: a hand-rolled reactive\n * primitive with `value` / `error` fields and a `subscribe(cb)`\n * notification channel. Frame-agnostic — Vue / React / Solid\n * adapters wrap it in their own primitive.\n *\n * For joined queries, `.live()` additionally subscribes to every\n * join target's change stream. Mutations on a right-side\n * collection (insert / update / delete of a client referenced by\n * an invoice) re-fire the live query and re-evaluate every\n * dependent left row. Right-side targets are deduped by\n * collection name, so a chain that joins the same target twice\n * (e.g. billing client + shipping client → both 'clients') only\n * subscribes once.\n *\n * **Ref-mode behavior on right-side disappearance** — matches the\n * eager `.toArray()` contract from :\n * - `strict` → re-run throws `DanglingReferenceError`. The\n * LiveQuery catches the throw, stores it in `live.error`, and\n * notifies listeners (the throw does NOT propagate out of\n * the source's change handler — that would tear down the\n * emitter). Consumers check `live.error` after each\n * notification and render an error state in the UI.\n * - `warn` → joined value flips to `null`; the existing\n * warn-channel deduplication keeps repeated re-runs from\n * spamming the console.\n * - `cascade` → no special handling needed; the cascade-\n * delete mechanism propagates the right-side delete into the\n * left collection on the next tick, and the live query\n * naturally re-fires with the orphaned left rows gone.\n *\n * Always call `live.stop()` when finished — it tears down every\n * upstream subscription. The Vue layer's `onUnmounted` hook\n * should call `stop()` automatically; raw consumers must do it\n * themselves.\n *\n * **Incremental maintenance (#1341).** For a plan\n * `incrementalMaintainer()` accepts — no joins, no `.filter(fn)`, no\n * label-sort, and nothing an index would serve in index order (an `==`/`in`\n * probe, #1344's sorted-index range, or #1344's `orderBy(f).limit(n)`\n * index page) — the result set is PATCHED per change\n * event instead of re-run: one predicate evaluation for the changed record,\n * a binary search, a splice. Everything else, and any change event that\n * arrives without a delta, still re-runs the whole plan. Either way the\n * emitted value is identical to `toArray()` — the maintainer reuses this\n * query's own membership test and sort comparator.\n *\n * `options.batch` coalesces a burst of changes into one recompute and one\n * notification on a microtask. It is OFF by default because it makes\n * `live.value` stale until the microtask runs: a consumer that reads\n * synchronously after `await put()` would see the previous value.\n *\n * **Limitations:**\n * - No re-planning under live mutations — the planner picks\n * once at subscription time and reuses the same plan.\n * - Streaming live joins are deferred.\n */\n live(options?: { batch?: boolean }): LiveQuery<T> {\n const _h = this.source.hydration\n if (_h !== undefined && !_h.isHydrated()) return gateTerminal(_h, 'live', () => this.live(options))\n const upstreams: LiveUpstream[] = []\n\n // Left-side change stream — every live query subscribes to\n // its source if the source supports subscriptions.\n if (this.source.subscribe) {\n const leftSubscribe = this.source.subscribe.bind(this.source)\n upstreams.push({\n subscribe: (cb: () => void) => leftSubscribe(cb),\n })\n }\n\n // Right-side change streams — only for joined queries. Dedup\n // by target name so a chain joining the same target twice\n // doesn't double-subscribe and double-fire on every right-side\n // mutation.\n if (this.plan.joins.length > 0 && this.joinContext) {\n const subscribed = new Set<string>()\n for (const leg of this.plan.joins) {\n if (subscribed.has(leg.target)) continue\n subscribed.add(leg.target)\n const rightSource = this.joinContext.resolveSource(leg.target)\n if (rightSource?.subscribe) {\n const rightSubscribe = rightSource.subscribe.bind(rightSource)\n upstreams.push({\n subscribe: (cb: () => void) => rightSubscribe(cb),\n })\n }\n }\n }\n\n // Cross-join right-side change streams — symmetric with FK joins above.\n if (this.joinContext) {\n const subscribedCross = new Set<string>()\n for (const clause of this.plan.clauses) {\n if (clause.type !== 'crossJoin') continue\n if (subscribedCross.has(clause.target)) continue\n subscribedCross.add(clause.target)\n const rightSource = this.joinContext.resolveSource(clause.target)\n if (rightSource?.subscribe) {\n const rightSubscribe = rightSource.subscribe.bind(rightSource)\n upstreams.push({\n subscribe: (cb: () => void) => rightSubscribe(cb),\n })\n }\n }\n }\n\n // The recompute is just toArray bound to this query — same\n // pipeline as eager execution, including join application. It stays the\n // fallback even when a maintainer is attached.\n const maintainer = this.incrementalMaintainer('rows')\n return buildLiveQuery<T>(() => this.toArray(), upstreams, {\n ...(options?.batch === true ? { batch: true } : {}),\n ...(maintainer ? { maintainer } : {}),\n })\n }\n}\n\n/** The public Live surface — merged into `Query` by `./index.ts`. */\nexport type LiveSurface<\n T,\n S extends keyof T = never,\n Q extends keyof T & string = never,\n M extends keyof T & string = never,\n> = Pick<LiveMethods<T, S, Q, M>, 'subscribe' | 'live'>\n","/**\n * #1458 — the Live install. See `../relate/install.ts` for why this is a\n * function called from the entry rather than a module-level side effect.\n */\nimport { Query } from '../builder.js'\nimport { installMethods } from '../internal/core.js'\nimport { MaintenanceMethods } from '../internal/maintenance.js'\nimport { LiveMethods } from './methods.js'\n\nlet done = false\n\n/** Idempotent: the root barrel and the subpath entry both call it. */\nexport function installLive(): void {\n if (done) return\n done = true\n installMethods(Query.prototype, MaintenanceMethods)\n installMethods(Query.prototype, LiveMethods)\n}\n"],"mappings":"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","names":[]}
@@ -2,11 +2,11 @@ import {
2
2
  VDIG_ITERATIONS,
3
3
  mintBidxTag,
4
4
  pbkdf2VerifyDigest
5
- } from "./chunk-EZOAKKTB.js";
5
+ } from "./chunk-MBPZMZVB.js";
6
6
  import {
7
7
  ctEqualTags,
8
8
  makeCapsule
9
- } from "./chunk-42ALPZ2B.js";
9
+ } from "./chunk-ZF6JECDT.js";
10
10
  import {
11
11
  IV_BYTES,
12
12
  KEY_BITS,
@@ -16,14 +16,14 @@ import {
16
16
  generateIV,
17
17
  generateSalt,
18
18
  normalizeForVerify
19
- } from "./chunk-QMWY2FDS.js";
19
+ } from "./chunk-THQ3BHLM.js";
20
20
  import {
21
21
  ClassifiedRotationError,
22
22
  DecryptionError,
23
23
  InvalidKeyError,
24
24
  TamperedError,
25
25
  ValidationError
26
- } from "./chunk-37EPTBBR.js";
26
+ } from "./chunk-IKPQ2GGB.js";
27
27
 
28
28
  // src/capsule/enclave-aes/classify/compare.ts
29
29
  var subtle = globalThis.crypto.subtle;
@@ -196,6 +196,12 @@ async function importTransferKey(raw) {
196
196
  }
197
197
  return subtle2.importKey("raw", raw, { name: "AES-GCM", length: KEY_BITS }, false, ["encrypt", "decrypt"]);
198
198
  }
199
+ async function importWrappingKey(raw) {
200
+ if (raw.byteLength !== 32) {
201
+ throw new ValidationError(`wrapping key must be 32 bytes, got ${raw.byteLength}.`);
202
+ }
203
+ return subtle2.importKey("raw", raw, { name: "AES-KW", length: KEY_BITS }, false, ["wrapKey", "unwrapKey"]);
204
+ }
199
205
  async function encrypt(plaintext, dek, aad) {
200
206
  const iv = generateIV();
201
207
  const encoded = new TextEncoder().encode(plaintext);
@@ -214,8 +220,14 @@ async function encrypt(plaintext, dek, aad) {
214
220
  };
215
221
  }
216
222
  async function decrypt(ivBase64, dataBase64, dek, aad) {
217
- const iv = base64ToBuffer(ivBase64);
218
- const ciphertext = base64ToBuffer(dataBase64);
223
+ let iv;
224
+ let ciphertext;
225
+ try {
226
+ iv = base64ToBuffer(ivBase64);
227
+ ciphertext = base64ToBuffer(dataBase64);
228
+ } catch (err) {
229
+ throw new DecryptionError(`envelope body is not valid base64: ${err instanceof Error ? err.message : String(err)}`);
230
+ }
219
231
  try {
220
232
  const plaintext = await subtle2.decrypt(
221
233
  {
@@ -419,6 +431,17 @@ async function recipientWrap(pub, bytes) {
419
431
  async function recipientUnwrap(pair, wrapped) {
420
432
  return new Uint8Array(await subtle2.decrypt({ name: "RSA-OAEP" }, pair.privateKey, wrapped));
421
433
  }
434
+ async function exportRecipientPrivateKeyPkcs8(pair) {
435
+ return new Uint8Array(await subtle2.exportKey("pkcs8", pair.privateKey));
436
+ }
437
+ async function importRecipientKeyPair(pkcs8, spki) {
438
+ const alg = { name: "RSA-OAEP", hash: "SHA-256" };
439
+ const [privateKey, publicKey] = await Promise.all([
440
+ subtle2.importKey("pkcs8", pkcs8, alg, false, ["decrypt"]),
441
+ subtle2.importKey("spki", spki, alg, false, ["encrypt"])
442
+ ]);
443
+ return { privateKey, publicKey };
444
+ }
422
445
 
423
446
  // src/capsule/enclave-aes/classify/vdig.ts
424
447
  var subtle3 = globalThis.crypto.subtle;
@@ -541,6 +564,7 @@ export {
541
564
  unwrapCek,
542
565
  importCek,
543
566
  importTransferKey,
567
+ importWrappingKey,
544
568
  encrypt,
545
569
  decrypt,
546
570
  encryptBytes,
@@ -557,9 +581,11 @@ export {
557
581
  importRecipientPublicKeySpki,
558
582
  recipientWrap,
559
583
  recipientUnwrap,
584
+ exportRecipientPrivateKeyPkcs8,
585
+ importRecipientKeyPair,
560
586
  deriveVdigSlotKey,
561
587
  openVdigPayload,
562
588
  aesCapsule,
563
589
  dualReadSealedSlot
564
590
  };
565
- //# sourceMappingURL=chunk-5KC7QYEC.js.map
591
+ //# sourceMappingURL=chunk-YH4OUOSI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/capsule/enclave-aes/classify/compare.ts","../src/capsule/enclave-aes/crypto.ts","../src/capsule/enclave-aes/classify/vdig.ts","../src/capsule/enclave-aes/classify/write.ts","../src/capsule/enclave-aes/primitives.ts","../src/capsule/enclave-aes/bound.ts"],"sourcesContent":["/**\n * C2 — fixed-length-tag constant-time comparison (hub-portable; no\n * Node timingSafeEqual). Two mandatory rules (spec §3):\n * 1. Only fixed 32-byte tags are ever compared — ctEqualTags throws on\n * anything else (tag length is structural, never secret-dependent).\n * 2. Every comparand is reduced to a 32-byte tag under a FRESH ephemeral\n * HMAC-SHA256 key before comparison — keyed blinding makes compare\n * timing uncorrelated with underlying values; rule 1 (not blinding)\n * is what removes input-length timing. Length inequality folds into\n * unequal tags — never an early return.\n * @module\n */\n\nimport { ctEqualTags } from '../../plumbing/ct-equal.js'\nconst subtle = globalThis.crypto.subtle\n\n\n/**\n * Blinded equality of arbitrary-length byte strings: fresh K_e per\n * comparison (never stored, never reused), HMAC both sides to 32-byte\n * tags, then ctEqualTags. On the digest path the inputs are already\n * 32-byte PBKDF2 outputs but still route through this reduction so\n * there is exactly ONE comparison construction (spec §3 rule 2).\n */\nexport async function blindedEqual(a: Uint8Array, b: Uint8Array): Promise<boolean> {\n const ke = await subtle.generateKey({ name: 'HMAC', hash: 'SHA-256' }, false, ['sign'])\n const tagA = new Uint8Array(await subtle.sign('HMAC', ke, a as BufferSource))\n const tagB = new Uint8Array(await subtle.sign('HMAC', ke, b as BufferSource))\n return ctEqualTags(tagA, tagB)\n}\n","/**\n * Cryptographic primitives — thin wrappers around the Web Crypto API.\n *\n * ## Design principle\n *\n * **Zero npm crypto dependencies.** Every operation uses `globalThis.crypto.subtle`,\n * which is available natively in Node.js ≥ 18, all modern browsers, and\n * Deno/Bun. This avoids supply-chain risk from third-party crypto packages and\n * ensures the library stays auditable.\n *\n * ## Algorithms\n *\n * | Use case | Algorithm | Parameters |\n * |----------|-----------|------------|\n * | Key derivation | PBKDF2-SHA256 | 600,000 iterations, 32-byte salt |\n * | Record encryption | AES-256-GCM | 12-byte random IV per operation |\n * | DEK wrapping | AES-KW (RFC 3394) | 256-bit KEK |\n * | Binary encrypt | AES-256-GCM | same as record encryption |\n * | Integrity | HMAC-SHA256 | for presence channels |\n * | Content hash | SHA-256 | for ledger and bundle integrity |\n *\n * ## Key lifecycle\n *\n * ```\n * secret + salt\n * └─► deriveKey() → KEK (CryptoKey, extractable: false)\n * └─► wrapKey() → wrapped DEK bytes [stored in keyring]\n * └─► unwrapKey() → DEK (CryptoKey) [memory only during session]\n * └─► encrypt() / decrypt() → ciphertext / plaintext\n * ```\n *\n * IVs are generated fresh by {@link generateIV} on every encrypt call.\n * Reusing an IV with the same key would break GCM's authentication guarantee —\n * this function should be the only place IVs are produced.\n *\n * @module\n */\n\nimport { DecryptionError, InvalidKeyError, TamperedError, ValidationError } from '../../kernel/errors.js'\nimport {\n KEY_BITS,\n IV_BYTES,\n bufferToBase64,\n base64ToBuffer,\n generateIV,\n encodeEchoParts,\n type EchoSecretParts,\n} from '../plumbing/digest.js'\n\n/**\n * **EnclaveKey** — the opaque key type at the enclave seam.\n *\n * In noy-db's reference enclave this is `CryptoKey` (the Web Crypto API's\n * key handle). A fork's enclave redefines this alias to its own key\n * representation (e.g. `type EnclaveKey = null` for a keyless HSM-backed\n * fork) — outside `capsule/enclave-aes/**`, every consumer must treat it as\n * opaque: never construct, inspect, or serialize it directly, only pass it\n * between barrel functions (`encrypt`/`decrypt`/`wrapKey`/`unwrapKey`/…).\n */\nexport type EnclaveKey = CryptoKey\n\n/** Opaque asymmetric pair at the enclave seam — `CryptoKeyPair` in the reference enclave. */\nexport type EnclaveKeyPair = CryptoKeyPair\n\nconst PBKDF2_ITERATIONS = 600_000\n\nconst subtle = globalThis.crypto.subtle\n\n// ─── Key Derivation ────────────────────────────────────────────────────\n\n/** Derive a KEK from a secret and salt using PBKDF2-SHA256. */\nexport async function deriveKey(\n secret: string,\n salt: Uint8Array,\n): Promise<CryptoKey> {\n return deriveKekFromMaterial(new TextEncoder().encode(secret), salt)\n}\n\n/**\n * Shared PBKDF2 → AES-KW derivation core. `material` is the raw\n * pre-KDF input bytes (a UTF-8 phrase for standard mode, an\n * AG-1-encoded 3-part structure for echo mode).\n */\nasync function deriveKekFromMaterial(\n material: Uint8Array,\n salt: Uint8Array,\n): Promise<CryptoKey> {\n const keyMaterial = await subtle.importKey('raw', material as BufferSource, 'PBKDF2', false, ['deriveKey'])\n return subtle.deriveKey(\n { name: 'PBKDF2', salt: salt as BufferSource, iterations: PBKDF2_ITERATIONS, hash: 'SHA-256' },\n keyMaterial,\n { name: 'AES-KW', length: KEY_BITS },\n false,\n ['wrapKey', 'unwrapKey'],\n )\n}\n\n/** One three-part echo secret: prompt (typed) → echo (revealed) → key (typed). */\n\n/**\n * Domain context for the AG-1 encoding. The leading `0xFF` is the load-bearing\n * byte: it is not a legal UTF-8 lead byte, so `TextEncoder` can never emit it —\n * no string's UTF-8 encoding can equal an AG-1 encoding, whatever the string.\n */\n\nexport async function deriveEchoKey(\n parts: EchoSecretParts,\n salt: Uint8Array,\n): Promise<CryptoKey> {\n return deriveKekFromMaterial(encodeEchoParts(parts), salt)\n}\n\n/**\n * Which AES algorithm/usage a {@link deriveSecretKey} result is for:\n * `'aes-kw'` mints a key-wrapping key (`wrapKey`/`unwrapKey`, e.g. for\n * KEK derivation); `'aes-gcm'` mints a direct encrypt/decrypt key (e.g.\n * for the wrap-DEKs primitive in `with-party/team/wrapped-deks.ts`).\n */\nexport type SecretKeyUsage = 'aes-kw' | 'aes-gcm'\n\n/**\n * Derive a non-extractable AES key from a secret/credential and salt\n * via PBKDF2-SHA256, generalizing {@link deriveKey}'s AES-KW derivation to\n * also cover AES-GCM-usage keys. Callers pin their own `iterations` and\n * `keyUsage` so an existing call site's exact parameters (and thus its\n * derived-key bytes) are preserved verbatim when migrated onto this\n * shared primitive — this is call-site consolidation, not a KDF change.\n */\nexport async function deriveSecretKey(\n secret: string,\n salt: Uint8Array,\n params: { iterations: number; keyUsage: SecretKeyUsage },\n): Promise<CryptoKey> {\n const keyMaterial = await subtle.importKey(\n 'raw',\n new TextEncoder().encode(secret),\n 'PBKDF2',\n false,\n ['deriveKey'],\n )\n\n return params.keyUsage === 'aes-gcm'\n ? subtle.deriveKey(\n {\n name: 'PBKDF2',\n salt: salt as BufferSource,\n iterations: params.iterations,\n hash: 'SHA-256',\n },\n keyMaterial,\n { name: 'AES-GCM', length: KEY_BITS },\n false,\n ['encrypt', 'decrypt'],\n )\n : subtle.deriveKey(\n {\n name: 'PBKDF2',\n salt: salt as BufferSource,\n iterations: params.iterations,\n hash: 'SHA-256',\n },\n keyMaterial,\n { name: 'AES-KW', length: KEY_BITS },\n false,\n ['wrapKey', 'unwrapKey'],\n )\n}\n\n// ─── DEK Generation ────────────────────────────────────────────────────\n\n/** Generate a random AES-256-GCM data encryption key. */\nexport async function generateDEK(): Promise<CryptoKey> {\n return subtle.generateKey(\n { name: 'AES-GCM', length: KEY_BITS },\n true, // extractable — needed for AES-KW wrapping\n ['encrypt', 'decrypt'],\n )\n}\n\n/**\n * Generate a NON-extractable AES-256-GCM key for in-memory-only use — a\n * session key, a device seal. Unlike {@link generateDEK} it can never be\n * wrapped or exported: WebCrypto enforces that, and it is the tab-scope\n * invariant `with-party/session` and `device-seal` rely on.\n */\nexport async function generateEphemeralKey(): Promise<CryptoKey> {\n return subtle.generateKey({ name: 'AES-GCM', length: KEY_BITS }, false, ['encrypt', 'decrypt'])\n}\n\n// ─── DEK-Set Codec ─────────────────────────────────────────────────────\n//\n// The portable form of a DEK set — `{ collection: base64(rawKey) }` — is the\n// plaintext body of every persisted WrappedDeksBlob (recovery-paper,\n// recovery-shamir, tier-2 password slots). It is an enclave door because it\n// is the one place a key's REPRESENTATION crosses into bytes: a fork with its\n// own EnclaveKey (hardware-backed, post-quantum, no encryption) decides here\n// what \"the bytes of a key\" means, and nothing outside capsule/enclave-aes has to\n// know. Byte-for-byte what wrapped-deks.ts did inline before #1317.\n\n/** Serialize a DEK set to `{ collection: base64(rawKey) }`. */\nexport async function exportDekSet(deks: Map<string, CryptoKey>): Promise<Record<string, string>> {\n const out: Record<string, string> = {}\n for (const [coll, dek] of deks) {\n out[coll] = bufferToBase64(await subtle.exportKey('raw', dek))\n }\n return out\n}\n\n/**\n * Reverse of {@link exportDekSet}. Keys come back extractable AES-GCM\n * (`encrypt`/`decrypt`), matching what `generateDEK` mints.\n */\nexport async function importDekSet(exported: Record<string, string>): Promise<Map<string, CryptoKey>> {\n const deks = new Map<string, CryptoKey>()\n for (const [coll, b64] of Object.entries(exported)) {\n const key = await subtle.importKey(\n 'raw',\n base64ToBuffer(b64) as BufferSource,\n { name: 'AES-GCM', length: KEY_BITS },\n true,\n ['encrypt', 'decrypt'],\n )\n deks.set(coll, key)\n }\n return deks\n}\n\n// ─── Key Wrapping ──────────────────────────────────────────────────────\n\n/** Wrap (encrypt) a DEK with a KEK using AES-KW. Returns base64 string. */\nexport async function wrapKey(dek: CryptoKey, kek: CryptoKey): Promise<string> {\n const wrapped = await subtle.wrapKey('raw', dek, kek, 'AES-KW')\n return bufferToBase64(wrapped)\n}\n\n/** Unwrap (decrypt) a DEK from base64 string using a KEK. */\nexport async function unwrapKey(\n wrappedBase64: string,\n kek: CryptoKey,\n): Promise<CryptoKey> {\n try {\n return await subtle.unwrapKey(\n 'raw',\n base64ToBuffer(wrappedBase64) as BufferSource,\n kek,\n 'AES-KW',\n { name: 'AES-GCM', length: KEY_BITS },\n true,\n ['encrypt', 'decrypt'],\n )\n } catch {\n throw new InvalidKeyError()\n }\n}\n\n// ─── Canary ────────────────────────────────────────────────────────────\n//\n// \"Is this KEK the right one?\" is answered by wrapping a CONSTANT key under\n// it and seeing whether the wrap opens later. AES-KW is deterministic\n// (RFC 3394 fixed IV), so the same constant under the same KEK always yields\n// the same bytes — every write site can re-mint on persist. The keyring\n// canary (32 zero bytes) and the echo prompt/echo verifiers (32 × 0x5a) are\n// both this primitive with a different constant.\n\n/** Wrap the constant AES-GCM key built from `plaintext` under `kek`. */\nexport async function mintCanary(kek: CryptoKey, plaintext: Uint8Array): Promise<string> {\n const constant = await subtle.importKey(\n 'raw', plaintext as BufferSource, { name: 'AES-GCM', length: KEY_BITS }, true, ['encrypt', 'decrypt'],\n )\n return wrapKey(constant, kek)\n}\n\n/** True iff `wrapped` unwraps under `kek` — the KEK is right AND the bytes are intact. */\nexport async function checkCanary(wrapped: string, kek: CryptoKey): Promise<boolean> {\n try {\n await unwrapKey(wrapped, kek)\n return true\n } catch {\n return false\n }\n}\n\n// ─── Per-record CEK wrapping ───────────────────────────────────────────\n\n/**\n * Derive a **dedicated** AES-KW wrapping key from a collection/tier DEK via\n * HKDF-SHA256, used to wrap/unwrap a per-record CEK.\n *\n * The collection/tier DEKs are AES-256-**GCM** keys (usages\n * `encrypt`/`decrypt`) and cannot themselves act as an AES-KW KEK. We do NOT\n * re-import the raw DEK bytes directly as an AES-KW key — that would reuse one\n * key across two primitives (AES-GCM for `_det`/presence, AES-KW for CEK\n * wrapping), violating key separation. Instead we HKDF-derive a domain-\n * separated KW key (salt `noydb-cek-wrap`), exactly as `derivePresenceKey`\n * derives a separate presence key. The derivation is deterministic, so\n * wrapping the same CEK under the same DEK always yields identical ciphertext\n * — which is what lets an update reuse a record's stable CEK and produce a\n * byte-identical `_cek`. The KW key is independent of the DEK's GCM key.\n *\n * The DEK must be extractable (it is — `generateDEK`/`unwrapKey` mint\n * extractable keys).\n */\nasync function asKwKey(dek: CryptoKey): Promise<CryptoKey> {\n const rawDek = await subtle.exportKey('raw', dek)\n const hkdfKey = await subtle.importKey('raw', rawDek, 'HKDF', false, ['deriveBits'])\n const salt = new TextEncoder().encode('noydb-cek-wrap')\n const info = new TextEncoder().encode('v1')\n const bits = await subtle.deriveBits(\n { name: 'HKDF', hash: 'SHA-256', salt, info },\n hkdfKey,\n KEY_BITS,\n )\n return subtle.importKey('raw', bits, 'AES-KW', false, ['wrapKey', 'unwrapKey'])\n}\n\n/**\n * AES-KW-wrap a per-record CEK under a collection/tier DEK. Returns base64.\n * Deterministic over `(cek, dek)`.\n */\nexport async function wrapCek(cek: CryptoKey, dek: CryptoKey): Promise<string> {\n const kw = await asKwKey(dek)\n const wrapped = await subtle.wrapKey('raw', cek, kw, 'AES-KW')\n return bufferToBase64(wrapped)\n}\n\n/**\n * Unwrap a per-record CEK from base64 under a collection/tier DEK. Throws\n * `InvalidKeyError` if the wrapped bytes do not authenticate under the DEK.\n */\nexport async function unwrapCek(wrappedBase64: string, dek: CryptoKey): Promise<CryptoKey> {\n const kw = await asKwKey(dek)\n try {\n return await subtle.unwrapKey(\n 'raw',\n base64ToBuffer(wrappedBase64) as BufferSource,\n kw,\n 'AES-KW',\n { name: 'AES-GCM', length: KEY_BITS },\n true,\n ['encrypt', 'decrypt'],\n )\n } catch {\n throw new InvalidKeyError()\n }\n}\n\n/**\n * Import a raw 32-byte AES-256-GCM record CEK (e.g. from a sealed-CEK\n * delivery binding). Non-extractable, decrypt-only — the imported key is\n * used solely to open the record's `_iv`/`_data` body under `decrypt()`.\n */\nexport async function importCek(rawKey: Uint8Array): Promise<CryptoKey> {\n return subtle.importKey('raw', rawKey as BufferSource, { name: 'AES-GCM', length: KEY_BITS }, false, ['decrypt'])\n}\n\n/**\n * Import a raw 32-byte pre-shared key as a NON-extractable AES-256-GCM key\n * (encrypt + decrypt). The transfer seal (`with-cargo`) and the RSA-OAEP\n * TLV's per-blob CEK (`managed-secret`) both hand raw bytes to the enclave\n * here; the bytes never become a key anywhere else.\n */\nexport async function importTransferKey(raw: Uint8Array): Promise<CryptoKey> {\n if (raw.byteLength !== 32) {\n throw new ValidationError(`transfer key must be 32 bytes, got ${raw.byteLength}.`)\n }\n return subtle.importKey('raw', raw as BufferSource, { name: 'AES-GCM', length: KEY_BITS }, false, ['encrypt', 'decrypt'])\n}\n\n/**\n * core#65 — import raw 32 bytes as a NON-extractable AES-KW key (wrap +\n * unwrap). The per-delegation CONTENT KEY: a delegation's tier DEKs are\n * AES-KW-wrapped under it exactly as they are under a KEK, and the key itself\n * travels RSA-OAEP-sealed to the target's inbox public half — so the token's\n * slot NAMES stay readable to any vault member for audit while its keys open\n * for the target alone. Distinct from {@link importTransferKey}, which imports\n * an AES-GCM key for body encryption and cannot wrap.\n */\nexport async function importWrappingKey(raw: Uint8Array): Promise<CryptoKey> {\n if (raw.byteLength !== 32) {\n throw new ValidationError(`wrapping key must be 32 bytes, got ${raw.byteLength}.`)\n }\n return subtle.importKey('raw', raw as BufferSource, { name: 'AES-KW', length: KEY_BITS }, false, ['wrapKey', 'unwrapKey'])\n}\n\n// ─── Encrypt / Decrypt ─────────────────────────────────────────────────\n\nexport interface EncryptResult {\n iv: string // base64\n data: string // base64\n}\n\n/**\n * Encrypt plaintext JSON string with AES-256-GCM. Fresh IV per call.\n *\n * `aad` binds the record's identity into the auth tag (#1041) — see\n * `record-aad.ts` for what is bound and why `_v` is not. A body sealed with\n * AAD can only be opened by a reader supplying the identical bytes, which is\n * what stops an untrusted store from relocating or re-tiering an envelope.\n *\n * Optional **only while the call-site sweep is in progress**. It becomes\n * mandatory once every `encrypt`/`decrypt` pair supplies it, at which point\n * the format version bumps and the reader rejects anything unbound. Until\n * then an omitted `aad` reproduces the previous, unauthenticated behaviour.\n */\nexport async function encrypt(\n plaintext: string,\n dek: CryptoKey,\n aad?: Uint8Array,\n): Promise<EncryptResult> {\n const iv = generateIV()\n const encoded = new TextEncoder().encode(plaintext)\n\n const ciphertext = await subtle.encrypt(\n {\n name: 'AES-GCM',\n iv: iv as BufferSource,\n ...(aad !== undefined && { additionalData: aad as BufferSource }),\n },\n dek,\n encoded,\n )\n\n return {\n iv: bufferToBase64(iv),\n data: bufferToBase64(ciphertext),\n }\n}\n\n/**\n * Decrypt AES-256-GCM ciphertext. Throws on wrong key or tampered data.\n *\n * `aad` must be byte-identical to what {@link encrypt} was given, or the auth\n * tag fails and this throws `TamperedError` (#1041). Note the asymmetry that\n * makes this useful: a mismatched identity is indistinguishable from a\n * corrupted body, so relocation fails **closed** rather than returning a\n * plausible record in the wrong place.\n */\nexport async function decrypt(\n ivBase64: string,\n dataBase64: string,\n dek: CryptoKey,\n aad?: Uint8Array,\n): Promise<string> {\n // A body that is not even base64 (`atob` throws a DOMException) is a corrupted\n // envelope, and must read as one: the same named error a wrong key produces,\n // never the raw WebCrypto/`atob` exception (measured by a consumer, core#67).\n let iv: Uint8Array\n let ciphertext: Uint8Array\n try {\n iv = base64ToBuffer(ivBase64)\n ciphertext = base64ToBuffer(dataBase64)\n } catch (err) {\n throw new DecryptionError(`envelope body is not valid base64: ${err instanceof Error ? err.message : String(err)}`)\n }\n\n try {\n const plaintext = await subtle.decrypt(\n {\n name: 'AES-GCM',\n iv: iv as BufferSource,\n ...(aad !== undefined && { additionalData: aad as BufferSource }),\n },\n dek,\n ciphertext as BufferSource,\n )\n return new TextDecoder().decode(plaintext)\n } catch (err) {\n if (err instanceof Error && err.name === 'OperationError') {\n throw new TamperedError(...(await classifyTagFailure(iv, ciphertext, dek, aad)))\n }\n throw new DecryptionError(\n err instanceof Error ? err.message : 'Decryption failed',\n )\n }\n}\n\n\n/**\n * Distinguish a FORMAT TRANSITION from an attack, when the enclave can (#1103).\n *\n * ## The problem\n *\n * Since #1041 switched identity AAD on, one `TamperedError` covers at least\n * four situations: legitimate pre-binding data, a store that reconstructs an\n * envelope and drops a bound field, a CEK/rotation mismatch, and actual\n * tampering. `SECURITY.md` and the subsystem docs teach the LAST reading — so a\n * user who upgrades, hits this on their own honest data, and consults the docs\n * is told their store has been compromised.\n *\n * That is a false positive on the product's central security claim, and the\n * cost is not merely a confusing message: **a tamper alarm that cries wolf is\n * one users learn to ignore.**\n *\n * ## Why the probe is sound, and why it is NOT a downgrade\n *\n * A body sealed before #1041 carries no AAD, so it opens under an empty one.\n * Retrying that way is **positive evidence** of the legacy format rather than a\n * guess: forging a body that decrypts under this DEK requires the DEK, and an\n * untrusted store does not hold one.\n *\n * ⚠️ **Classification ONLY — the plaintext is discarded and the caller still\n * throws.** That is the entire safety argument: the outcome is identical either\n * way, so this cannot become the lenient path #1041 exists to remove. A variant\n * that RETURNED the retry's plaintext would be exactly the accept-without-AAD\n * downgrade the binding was built to prevent. Do not \"optimise\" it into one.\n *\n * Note what the honest message concedes: pre-#1041 data had no authenticated\n * metadata, so a legacy record that was ALSO tampered with reads as legacy.\n * That is not a weakening — it is an accurate statement about data that\n * genuinely never carried a binding.\n */\nasync function classifyTagFailure(\n iv: Uint8Array,\n ciphertext: Uint8Array,\n dek: CryptoKey,\n aad: Uint8Array | undefined,\n): Promise<[] | [string, 'unbound-legacy-format']> {\n // Only meaningful when AAD was supplied: with none there is no second\n // interpretation to test, and the failure is a plain tag mismatch.\n if (aad === undefined) return []\n try {\n await subtle.decrypt({ name: 'AES-GCM', iv: iv as BufferSource }, dek, ciphertext as BufferSource)\n } catch {\n return [] // no benign explanation — the security alert stands\n }\n return [\n 'This record was sealed BEFORE record-identity binding (#1041) and cannot be read by this ' +\n 'version. Its body decrypts correctly under the record key, so this is a data-format ' +\n 'transition, not tampering — but it also means the record predates authenticated metadata. ' +\n 'There is no migration path; see noy-db #1100.',\n 'unbound-legacy-format',\n ]\n}\n\n// ─── Binary Encrypt / Decrypt ────────\n\n/**\n * Encrypt raw bytes with AES-256-GCM using a fresh random IV.\n * Used by the attachment store so binary blobs avoid double base64 encoding\n * (the existing `encrypt()` function calls `TextEncoder` on a string — here\n * we pass the `Uint8Array` directly to `subtle.encrypt`).\n */\nexport async function encryptBytes(\n data: Uint8Array,\n dek: CryptoKey,\n): Promise<EncryptResult> {\n const iv = generateIV()\n const ciphertext = await subtle.encrypt(\n { name: 'AES-GCM', iv: iv as BufferSource },\n dek,\n data as unknown as BufferSource,\n )\n return {\n iv: bufferToBase64(iv),\n data: bufferToBase64(ciphertext),\n }\n}\n\n/**\n * Decrypt AES-256-GCM ciphertext back to raw bytes.\n * Counterpart to `encryptBytes`. Throws `TamperedError` on auth-tag failure.\n */\nexport async function decryptBytes(\n ivBase64: string,\n dataBase64: string,\n dek: CryptoKey,\n): Promise<Uint8Array> {\n const iv = base64ToBuffer(ivBase64)\n const ciphertext = base64ToBuffer(dataBase64)\n try {\n const plaintext = await subtle.decrypt(\n { name: 'AES-GCM', iv: iv as BufferSource },\n dek,\n ciphertext as BufferSource,\n )\n return new Uint8Array(plaintext)\n } catch (err) {\n if (err instanceof Error && err.name === 'OperationError') {\n throw new TamperedError()\n }\n throw new DecryptionError(\n err instanceof Error ? err.message : 'Decryption failed',\n )\n }\n}\n\n\nexport async function encryptBytesWithAAD(\n data: Uint8Array,\n dek: CryptoKey,\n aad: Uint8Array,\n): Promise<EncryptResult> {\n const iv = generateIV()\n const ciphertext = await subtle.encrypt(\n {\n name: 'AES-GCM',\n iv: iv as BufferSource,\n additionalData: aad as BufferSource,\n },\n dek,\n data as unknown as BufferSource,\n )\n return {\n iv: bufferToBase64(iv),\n data: bufferToBase64(ciphertext),\n }\n}\n\n/**\n * Decrypt AES-256-GCM ciphertext with AAD verification.\n *\n * If the AAD does not match the one used at encryption time (e.g. because\n * a chunk was reordered or substituted from another blob), the GCM auth\n * tag fails and this throws `TamperedError`.\n */\nexport async function decryptBytesWithAAD(\n ivBase64: string,\n dataBase64: string,\n dek: CryptoKey,\n aad: Uint8Array,\n): Promise<Uint8Array> {\n const iv = base64ToBuffer(ivBase64)\n const ciphertext = base64ToBuffer(dataBase64)\n try {\n const plaintext = await subtle.decrypt(\n {\n name: 'AES-GCM',\n iv: iv as BufferSource,\n additionalData: aad as BufferSource,\n },\n dek,\n ciphertext as BufferSource,\n )\n return new Uint8Array(plaintext)\n } catch (err) {\n if (err instanceof Error && err.name === 'OperationError') {\n throw new TamperedError()\n }\n throw new DecryptionError(\n err instanceof Error ? err.message : 'Decryption failed',\n )\n }\n}\n\n// ─── Presence Key Derivation ──────────────────────────────\n\n\nexport async function deriveSealedFieldKey(\n dek: CryptoKey,\n collectionName: string,\n field: string,\n): Promise<CryptoKey> {\n const rawDek = await subtle.exportKey('raw', dek)\n const hkdfKey = await subtle.importKey('raw', rawDek, 'HKDF', false, ['deriveBits'])\n const salt = new TextEncoder().encode('noydb-sealed')\n // JSON-array encoding is injective: each element is separately quoted/\n // escaped, so collection `a/sealed/b` + field `c` cannot collide with\n // collection `a` + field `b/sealed/c`.\n const info = new TextEncoder().encode(JSON.stringify(['noydb-sealed', collectionName, field]))\n const bits = await subtle.deriveBits(\n { name: 'HKDF', hash: 'SHA-256', salt, info },\n hkdfKey,\n KEY_BITS,\n )\n return subtle.importKey(\n 'raw',\n bits,\n { name: 'AES-GCM', length: KEY_BITS },\n false,\n ['encrypt', 'decrypt'],\n )\n}\n\n/**\n * Derive a per-record sealed-field key from the record's **per-record CEK**\n * rather than the collection DEK. Same HKDF construction as\n * {@link deriveSealedFieldKey} but with salt `'noydb-sealed-cek'` (distinct\n * from `'noydb-sealed'`), so a CEK-derived key can never collide with a\n * DEK-derived one for the same `{collection, field}`.\n *\n * The point: the sealed ciphertext's only key now flows from the record's CEK.\n * Dropping the record's wrapped `_cek` (crypto-shred / `forget`) makes the key\n * — and thus `_sealed[field]` — unrecoverable, giving sealed fields the same\n * erasure guarantee `_data` already has. The CEK must be extractable (it is —\n * `unwrapCek`/`generateDEK` mint extractable keys).\n *\n * @param cek The record's AES-256-GCM CEK (extractable).\n * @param collectionName Part of the HKDF `info` for domain separation.\n * @param field Sensitive field name — the rest of the `info`.\n * @returns A non-extractable AES-256-GCM key for that field's sealed slot.\n */\nexport async function deriveSealedFieldKeyFromCek(\n cek: CryptoKey,\n collectionName: string,\n field: string,\n): Promise<CryptoKey> {\n const rawCek = await subtle.exportKey('raw', cek)\n const hkdfKey = await subtle.importKey('raw', rawCek, 'HKDF', false, ['deriveBits'])\n const salt = new TextEncoder().encode('noydb-sealed-cek')\n const info = new TextEncoder().encode(JSON.stringify(['noydb-sealed-cek', collectionName, field]))\n const bits = await subtle.deriveBits(\n { name: 'HKDF', hash: 'SHA-256', salt, info },\n hkdfKey,\n KEY_BITS,\n )\n return subtle.importKey(\n 'raw',\n bits,\n { name: 'AES-GCM', length: KEY_BITS },\n false,\n ['encrypt', 'decrypt'],\n )\n}\n\n// ─── Deterministic Encryption ────────────────────────────\n\n/**\n * Derive the collection's **dedicated deterministic-index key** from its DEK\n * via HKDF-SHA256 (L-1, #554).\n *\n * `_det` slots previously encrypted under the raw collection DEK — the same\n * key `_data` uses with a *randomized*-IV regime while `_det` uses a\n * *deterministic*-IV regime. Two IV regimes on one key is avoidable hygiene\n * debt (~2^-96 theoretical collision), so the deterministic index now gets its\n * own HKDF-separated key: salt `'noydb-det'`, info\n * `JSON.stringify(['noydb-det'])` (the injective JSON-array domain tag, same\n * convention as {@link deriveSealedFieldKey}). Per-field separation still\n * comes from the `'<collection>/<field>'` context inside\n * {@link encryptDeterministic}, exactly as before.\n *\n * The derived key stays **DEK-derived (collection-level)** on purpose: `_det`\n * is carried verbatim through per-record CEK rotation (see\n * `record-keys/sealing.ts`), so its key must not depend on the CEK. It rotates\n * with the collection DEK, like the presence key.\n *\n * The key is minted **extractable** — {@link encryptDeterministic} derives its\n * per-value IV via HKDF over the raw key bytes (an `exportKey` under the\n * hood), which a non-extractable key would forbid. Same in-memory posture as\n * the DEK itself (`generateDEK` mints extractable keys).\n *\n * @param dek The collection's AES-256-GCM DEK (extractable).\n * @returns A dedicated AES-256-GCM key for the `_det` deterministic index.\n */\nexport async function deriveDeterministicKey(dek: CryptoKey): Promise<CryptoKey> {\n const rawDek = await subtle.exportKey('raw', dek)\n const hkdfKey = await subtle.importKey('raw', rawDek, 'HKDF', false, ['deriveBits'])\n const salt = new TextEncoder().encode('noydb-det')\n const info = new TextEncoder().encode(JSON.stringify(['noydb-det']))\n const bits = await subtle.deriveBits(\n { name: 'HKDF', hash: 'SHA-256', salt, info },\n hkdfKey,\n KEY_BITS,\n )\n return subtle.importKey(\n 'raw',\n bits,\n { name: 'AES-GCM', length: KEY_BITS },\n true,\n ['encrypt', 'decrypt'],\n )\n}\n\n/**\n * Derive a deterministic 12-byte IV from `{ DEK, context, plaintext }`\n * via HKDF-SHA256. Given the same three inputs, the IV is identical, so\n * `encryptDeterministic` produces the same ciphertext on every call —\n * which is precisely what enables blind equality search on encrypted\n * fields.\n *\n * **The side channel this opens.** Two records whose field value is the\n * same produce the same ciphertext. An observer with store access can\n * therefore tell which records share a value — not *what* the value is,\n * but the equivalence class. This is the well-known trade-off of\n * deterministic encryption and is why the feature is strictly opt-in\n * per field, guarded by `acknowledgeDeterministicRisk: true` at\n * collection creation.\n *\n * The context string MUST include the collection name and field name,\n * so:\n * - The same plaintext in two different fields encrypts differently\n * (no cross-field equality leak).\n * - The same plaintext in two different collections (different DEKs)\n * encrypts differently by virtue of the key, even before HKDF\n * domain separation kicks in.\n */\nasync function deriveDeterministicIV(\n dek: CryptoKey,\n context: string,\n plaintext: string,\n): Promise<Uint8Array> {\n const rawDek = await subtle.exportKey('raw', dek)\n const hkdfKey = await subtle.importKey('raw', rawDek, 'HKDF', false, ['deriveBits'])\n const salt = new TextEncoder().encode('noydb-deterministic-v1')\n const info = new TextEncoder().encode(`${context}\\x00${plaintext}`)\n const bits = await subtle.deriveBits(\n { name: 'HKDF', hash: 'SHA-256', salt, info },\n hkdfKey,\n IV_BYTES * 8,\n )\n return new Uint8Array(bits)\n}\n\n/**\n * Encrypt a plaintext string with AES-256-GCM and a deterministic,\n * HKDF-derived IV.\n *\n * The same `{ dek, context, plaintext }` triple always produces the\n * same `{ iv, data }` — call this twice and you can string-compare the\n * ciphertexts to check equality of the inputs without decrypting them.\n *\n * @param context Domain-separation string — by convention\n * `'<collection>/<field>'`. Different contexts encrypt\n * the same plaintext to different ciphertexts, so\n * `email` in collection `users` does not collide with\n * `email` in collection `customers`.\n */\nexport async function encryptDeterministic(\n plaintext: string,\n dek: CryptoKey,\n context: string,\n): Promise<EncryptResult> {\n const iv = await deriveDeterministicIV(dek, context, plaintext)\n const encoded = new TextEncoder().encode(plaintext)\n const ciphertext = await subtle.encrypt(\n { name: 'AES-GCM', iv: iv as BufferSource },\n dek,\n encoded,\n )\n return {\n iv: bufferToBase64(iv),\n data: bufferToBase64(ciphertext),\n }\n}\n\n/**\n * Counterpart to {@link encryptDeterministic}. The IV is stored\n * alongside the ciphertext (exactly like the randomized path), so\n * decrypt uses the stored IV and verifies the GCM auth tag — a tampered\n * ciphertext throws `TamperedError` just like randomized AES-GCM.\n */\nexport async function decryptDeterministic(\n ivBase64: string,\n dataBase64: string,\n dek: CryptoKey,\n): Promise<string> {\n return decrypt(ivBase64, dataBase64, dek)\n}\n\n// ─── Random Generation ─────────────────────────────────────────────────\n\n\nexport async function generateRecipientKeyPair(): Promise<CryptoKeyPair> {\n return subtle.generateKey(\n { name: 'RSA-OAEP', modulusLength: 2048, publicExponent: new Uint8Array([1, 0, 1]), hash: 'SHA-256' },\n true,\n ['encrypt', 'decrypt'],\n )\n}\n\nexport async function exportRecipientPublicKeySpki(pair: CryptoKeyPair): Promise<Uint8Array> {\n return new Uint8Array(await subtle.exportKey('spki', pair.publicKey))\n}\n\nexport async function importRecipientPublicKeySpki(spki: Uint8Array): Promise<CryptoKey> {\n return subtle.importKey('spki', spki as BufferSource, { name: 'RSA-OAEP', hash: 'SHA-256' }, false, ['encrypt'])\n}\n\n/** RSA-OAEP-encrypt `bytes` (a 32-byte CEK) to the recipient's public key. */\nexport async function recipientWrap(pub: CryptoKey, bytes: Uint8Array): Promise<Uint8Array> {\n return new Uint8Array(await subtle.encrypt({ name: 'RSA-OAEP' }, pub, bytes as BufferSource))\n}\n\n/**\n * RSA-OAEP-decrypt with the pair's private key. Propagates WebCrypto's own\n * error on failure — callers that need a typed error map it themselves.\n */\nexport async function recipientUnwrap(pair: CryptoKeyPair, wrapped: Uint8Array): Promise<Uint8Array> {\n return new Uint8Array(await subtle.decrypt({ name: 'RSA-OAEP' }, pair.privateKey, wrapped as BufferSource))\n}\n\n/**\n * core#96 — the private half of a recipient pair as PKCS#8 bytes, so a caller\n * can seal it under a key it holds and persist it (a member's keyring inbox\n * key pair lives in the keyring file). The caller zeroes the bytes after use.\n */\nexport async function exportRecipientPrivateKeyPkcs8(pair: CryptoKeyPair): Promise<Uint8Array> {\n return new Uint8Array(await subtle.exportKey('pkcs8', pair.privateKey))\n}\n\n/** core#96 — rebuild a recipient pair from persisted PKCS#8 private + SPKI public bytes. */\nexport async function importRecipientKeyPair(pkcs8: Uint8Array, spki: Uint8Array): Promise<CryptoKeyPair> {\n const alg = { name: 'RSA-OAEP', hash: 'SHA-256' } as const\n const [privateKey, publicKey] = await Promise.all([\n subtle.importKey('pkcs8', pkcs8 as BufferSource, alg, false, ['decrypt']),\n subtle.importKey('spki', spki as BufferSource, alg, false, ['encrypt']),\n ])\n return { privateKey, publicKey }\n}\n\n// ─── Base64 Helpers ────────────────────────────────────────────────────\n\n\n","/**\n * The `_vdig` slot payload + crypto (stage 2, spec §2).\n *\n * A `_vdig[field]` blob is AES-256-GCM `\"iv:data\"` sealed under an\n * HKDF(CEK) slot key with AAD = ['noydb-classify-vdig', collection,\n * recordId, field] (C1 rollback-splice hardening). The AAD is NOT stored —\n * readers reconstruct it. It is deliberately `_v`-independent: C6's\n * carry-forward copies blob bytes verbatim across version bumps; the\n * same-record same-field TEMPORAL rollback residual is detected by the\n * ledger's conditional `_vdig` binding (envelope-body.ts).\n *\n * CEK-ONLY (I3): there is no DEK derivation and no\n * 'noydb-classify-vdig-dek' salt domain — every vdig slot dies with the\n * record's `_cek` (forget() shreds it totally; no vdig-dekResidue class).\n * @module\n */\nimport { encryptBytesWithAAD, decryptBytesWithAAD, type EnclaveKey } from '../crypto.js'\nimport { base64ToBuffer } from '../../plumbing/digest.js'\nimport { TamperedError } from '../../../kernel/errors.js'\n\nconst subtle = globalThis.crypto.subtle\n\nexport const VDIG_SALT_DOMAIN = 'noydb-classify-vdig'\n\nexport interface VdigDigestEntry {\n readonly salt: string // base64 32-byte per-write random salt\n readonly hash: string // base64 32-byte pbkdf2VerifyDigest output\n}\n\nexport interface VdigPayload {\n readonly v: 1\n readonly alg: 'PBKDF2-SHA256'\n readonly iter: number\n readonly cur: VdigDigestEntry & { readonly at: string } // ISO write-time\n /** Previous digests, oldest-first, length ≤ notLastN (cap 8). */\n readonly ring?: readonly VdigDigestEntry[]\n}\n\n/** Injective JSON-array AAD — same collision argument as deriveSealedFieldKey. */\nexport function buildVdigAad(collection: string, recordId: string, field: string): Uint8Array {\n return new TextEncoder().encode(JSON.stringify([VDIG_SALT_DOMAIN, collection, recordId, field]))\n}\n\n/** HKDF(CEK) → non-extractable AES-256-GCM vdig slot key. CEK-only (I3). */\nexport async function deriveVdigSlotKey(\n cek: EnclaveKey,\n collection: string,\n field: string,\n): Promise<EnclaveKey> {\n const raw = await subtle.exportKey('raw', cek)\n const hkdf = await subtle.importKey('raw', raw, 'HKDF', false, ['deriveBits'])\n const salt = new TextEncoder().encode(VDIG_SALT_DOMAIN)\n const info = new TextEncoder().encode(JSON.stringify([VDIG_SALT_DOMAIN, collection, field]))\n const bits = await subtle.deriveBits({ name: 'HKDF', hash: 'SHA-256', salt, info }, hkdf, 256)\n return subtle.importKey('raw', bits, { name: 'AES-GCM', length: 256 }, false, ['encrypt', 'decrypt'])\n}\n\nexport async function sealVdigPayload(\n payload: VdigPayload,\n cek: EnclaveKey,\n collection: string,\n recordId: string,\n field: string,\n): Promise<string> {\n const key = await deriveVdigSlotKey(cek, collection, field)\n const { iv, data } = await encryptBytesWithAAD(\n new TextEncoder().encode(JSON.stringify(payload)),\n key,\n buildVdigAad(collection, recordId, field),\n )\n return `${iv}:${data}`\n}\n\n/** Throws TamperedError on any AAD / auth-tag mismatch (C1). */\nexport async function openVdigPayload(\n blob: string,\n cek: EnclaveKey,\n collection: string,\n recordId: string,\n field: string,\n): Promise<VdigPayload> {\n const sep = blob.indexOf(':')\n if (sep === -1) throw new TamperedError()\n const ivPart = blob.slice(0, sep)\n const dataPart = blob.slice(sep + 1)\n try {\n base64ToBuffer(ivPart)\n base64ToBuffer(dataPart)\n } catch {\n throw new TamperedError()\n }\n const key = await deriveVdigSlotKey(cek, collection, field)\n const bytes = await decryptBytesWithAAD(\n ivPart,\n dataPart,\n key,\n buildVdigAad(collection, recordId, field),\n )\n return JSON.parse(new TextDecoder().decode(bytes)) as VdigPayload\n}\n","/**\n * Digest-only write engine (C6 rotate branch + notLastN ring, spec §2/§4).\n * Called ONLY by RecordCodec.encryptRecord — both live inside the enclave.\n * @module\n */\nimport { type EnclaveKey } from '../crypto.js'\nimport { generateSalt, bufferToBase64, base64ToBuffer } from '../../plumbing/digest.js'\nimport { pbkdf2VerifyDigest, VDIG_ITERATIONS } from './digest.js'\nimport { normalizeForVerify } from '../../plumbing/normalize.js'\nimport { blindedEqual } from './compare.js'\nimport { sealVdigPayload, openVdigPayload, type VdigPayload, type VdigDigestEntry } from './vdig.js'\nimport { ClassifiedRotationError, TamperedError } from '../../../kernel/errors.js'\nimport type { VdigFieldPolicy } from '../../../kernel/types.js'\n\nexport async function mintVdigSlot(\n rawValue: string,\n policy: VdigFieldPolicy,\n prevBlob: string | undefined,\n cek: EnclaveKey,\n collection: string,\n recordId: string,\n field: string,\n): Promise<string> {\n const normalized = normalizeForVerify(policy.normalize, rawValue)\n\n let prev: VdigPayload | null = null\n if (prevBlob !== undefined) {\n try {\n prev = await openVdigPayload(prevBlob, cek, collection, recordId, field)\n } catch {\n // Any failure opening a prior _vdig slot (auth-tag mismatch, malformed\n // JSON, wrong AAD) is a tamper/false condition — normalize to\n // TamperedError so the write path never sees a distinct error shape.\n throw new TamperedError()\n }\n if (!Number.isInteger(prev.iter) || prev.iter < 1) {\n // A corrupted/tampered iter count would silently weaken (or break)\n // the reuse-check PBKDF2 pass — floor/validate before trusting it.\n throw new TamperedError()\n }\n }\n\n // notLastN reuse refusal: candidate vs cur + every ring entry, each a full\n // PBKDF2 at the payload's own iteration count (n × 600K is the documented\n // write-time cost ceiling, cap 8 — spec Q4).\n if (prev !== null && policy.notLastN > 0) {\n const history: readonly VdigDigestEntry[] = [prev.cur, ...(prev.ring ?? [])]\n for (const entry of history) {\n const digest = await pbkdf2VerifyDigest(normalized, base64ToBuffer(entry.salt), prev.iter)\n if (await blindedEqual(digest, base64ToBuffer(entry.hash))) {\n throw new ClassifiedRotationError(collection, field, 'password was used recently')\n }\n }\n }\n\n const salt = generateSalt()\n const hash = await pbkdf2VerifyDigest(normalized, salt, VDIG_ITERATIONS)\n const ring = prev !== null && policy.notLastN > 0\n ? [...(prev.ring ?? []), { salt: prev.cur.salt, hash: prev.cur.hash }].slice(-policy.notLastN)\n : undefined\n\n const payload: VdigPayload = {\n v: 1,\n alg: 'PBKDF2-SHA256',\n iter: VDIG_ITERATIONS,\n cur: { salt: bufferToBase64(salt), hash: bufferToBase64(hash), at: new Date().toISOString() },\n ...(ring !== undefined && ring.length > 0 ? { ring } : {}),\n }\n return sealVdigPayload(payload, cek, collection, recordId, field)\n}\n","/**\n * `enclave-aes` as a {@link CapsulePrimitives} — the 13 functions the shared\n * plumbing binds to.\n *\n * ⭐ THE ASSIGNMENT BELOW IS A TEST, and it is the reason this file exists as\n * a file rather than an inline object at the `makeCapsule()` call. Declaring\n * the seam type and implementing it are two different acts; nothing checks a\n * hand-written interface against the module it claims to describe unless\n * something binds one to the other. This binding caught two errors in the\n * declaration within minutes of it being written:\n *\n * - `deriveDeterministicKey` was declared `(dek, context)`. It takes ONE\n * argument — the AES capsule derives the context into the IV, not the key.\n * - `bufferToBase64` was declared `(bytes: Uint8Array)`. It also accepts an\n * `ArrayBuffer`, which is what its callers actually pass.\n *\n * Both would have compiled here and failed at the far end of the refactor,\n * where the cause is no longer visible. (The same lesson as `#16`: a\n * structural declaration drifts silently from its implementation until an\n * assignment pins the two together.)\n *\n * ⚠️ Method shorthand in `CapsulePrimitives` is checked BIVARIANTLY, so this\n * assignment does NOT catch parameter-arity drift — that is exactly how the\n * `deriveDeterministicKey` mistake survived the type and was caught by a call\n * site instead. Keep the conformance kit's call-site coverage; this assignment\n * is necessary, not sufficient.\n */\nimport type { CapsulePrimitives } from '../contract.js'\nimport { encrypt, decrypt, encryptBytesWithAAD, decryptBytesWithAAD, encryptDeterministic, deriveDeterministicKey, deriveSealedFieldKey, deriveSealedFieldKeyFromCek, generateDEK, wrapCek, unwrapCek } from './crypto.js'\nimport { bufferToBase64 } from '../plumbing/digest.js'\nimport { mintVdigSlot } from './classify/write.js'\nimport { mintBidxTag } from './classify/bidx.js'\nimport { openVdigPayload, sealVdigPayload } from './classify/vdig.js'\n\nexport const aesPrimitives: CapsulePrimitives = {\n encrypt,\n decrypt,\n encryptBytesWithAAD,\n decryptBytesWithAAD,\n encryptDeterministic,\n deriveDeterministicKey,\n deriveSealedFieldKey,\n deriveSealedFieldKeyFromCek,\n generateDEK,\n wrapCek,\n unwrapCek,\n bufferToBase64,\n mintVdigSlot,\n mintBidxTag,\n openVdigPayload,\n sealVdigPayload,\n}\n","/**\n * The AES capsule, assembled: hub's shared plumbing bound to `aesPrimitives`.\n *\n * `classify/**` stays capsule-private (it is an optional group an exclave\n * refuses) but still needs `dualReadSealedSlot`, which is plumbing. Binding it\n * once here keeps `reveal.ts`/`verify.ts` from each building their own copy —\n * two bindings of the same primitives would work, but they would be two\n * objects, and `instanceof` across them is the class of bug the Stage B door\n * test caught by asserting identity rather than names.\n */\nimport { makeCapsule } from '../plumbing/index.js'\nimport { aesPrimitives } from './primitives.js'\n\nexport const aesCapsule = makeCapsule(aesPrimitives)\nexport const { dualReadSealedSlot } = aesCapsule\n"],"mappings":"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","names":["subtle","subtle"]}
@@ -11,7 +11,7 @@ import {
11
11
  filterRecords,
12
12
  fnViewDecoder,
13
13
  orderKeyOf
14
- } from "./chunk-AL6ML4LA.js";
14
+ } from "./chunk-DWCFGF2K.js";
15
15
 
16
16
  // src/kernel/query/internal/maintenance.ts
17
17
  var MaintenanceMethods = class {
@@ -97,4 +97,4 @@ var MaintenanceMethods = class {
97
97
  export {
98
98
  MaintenanceMethods
99
99
  };
100
- //# sourceMappingURL=chunk-FFJFE4T7.js.map
100
+ //# sourceMappingURL=chunk-YJGKOSQD.js.map
@@ -6,10 +6,10 @@ import {
6
6
  KIND_STRING,
7
7
  compareKeys,
8
8
  toSortKey
9
- } from "./chunk-LGNDFRYC.js";
9
+ } from "./chunk-4CFHL5RY.js";
10
10
  import {
11
11
  readPath
12
- } from "./chunk-5WWDGFOS.js";
12
+ } from "./chunk-GIQJGXV7.js";
13
13
 
14
14
  // src/with-lookup/indexing/index-snapshot.ts
15
15
  var FIELD_INDEX_SNAPSHOT_VERSION = 1;
@@ -933,4 +933,4 @@ export {
933
933
  normalizeIndexDefs,
934
934
  CollectionIndexes
935
935
  };
936
- //# sourceMappingURL=chunk-2AFX33YA.js.map
936
+ //# sourceMappingURL=chunk-Z3STG43F.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/with-lookup/indexing/index-snapshot.ts","../src/with-lookup/indexing/sorted-indexes.ts","../src/with-lookup/indexing/compound-indexes.ts","../src/with-lookup/indexing/eager-indexes.ts"],"sourcesContent":["/**\n * The on-disk shape of a persisted field index (#1359) — the format both\n * `SortedIndex` (#1344) and `CompoundIndex` (#1345) round-trip through, plus\n * the structural validator every load must pass.\n *\n * ⭐ **Nothing is flattened into a delimited string.** A compound entry keeps\n * its tuple as an ARRAY of per-component keys, each carrying its runtime KIND\n * alongside its value — which is the whole point of #1345's in-memory shape\n * and would be destroyed by a `join()`. Two properties depend on it:\n *\n * - **Kind survives.** Entries rank by runtime kind FIRST (mirroring\n * `predicate.ts`'s `isComparable`), so a `string` probe must not reach\n * `number` entries. An encoding that wrote only the value would collapse\n * `1` and `'1'` into one key space on the way back in.\n * - **Per-component ordering survives.** A string component may contain any\n * byte, including whatever a separator would have been.\n *\n * The validator is deliberately paranoid and its failure mode is a REBUILD,\n * never a partial load: a blob that is truncated, from a future format, or\n * internally out of order is rejected whole. See\n * {@link parseFieldIndexSnapshot}.\n */\n\n/** Bump on ANY incompatible change to the shapes below. An older stamp is rejected, not migrated. */\nexport const FIELD_INDEX_SNAPSHOT_VERSION = 1\n\n/** One `SortKey`, wire form: `[kind, key]`. `kind` IS the sort rank. */\nexport type WireKey = readonly [kind: number, key: number | string]\n\n/** One `SortedIndex` entry: `[kind, key, seq, id]`. */\nexport type WireSortedEntry = readonly [kind: number, key: number | string, seq: number, id: string]\n\n/** One `CompoundIndex` entry: `[tupleKeys, seq, id]` — the tuple stays an ARRAY. */\nexport type WireCompoundEntry = readonly [keys: readonly WireKey[], seq: number, id: string]\n\nexport interface SortedIndexSnapshot {\n readonly v: number\n readonly t: 'sorted'\n readonly field: string\n readonly nextSeq: number\n readonly entries: readonly WireSortedEntry[]\n}\n\nexport interface CompoundIndexSnapshot {\n readonly v: number\n readonly t: 'compound'\n readonly fields: readonly string[]\n readonly nextSeq: number\n readonly entries: readonly WireCompoundEntry[]\n}\n\nexport type FieldIndexSnapshot = SortedIndexSnapshot | CompoundIndexSnapshot\n\n/**\n * Sidecar key for a single-field sorted index. Field paths are\n * percent-encoded so no field name can collide with the `,` the compound\n * form joins on, nor with the `s:` / `c:` discriminator.\n */\nexport function sortedIndexKey(field: string): string {\n return `s:${encodeURIComponent(field)}`\n}\n\n/** Sidecar key for a compound index over an ordered field tuple. */\nexport function compoundIndexKey(fields: readonly string[]): string {\n return `c:${fields.map(encodeURIComponent).join(',')}`\n}\n\n/** A key is well-formed only if its declared kind matches its value's runtime type. */\nfunction isWireKey(x: unknown): x is WireKey {\n if (!Array.isArray(x) || x.length !== 2) return false\n const [kind, key] = x as [unknown, unknown]\n // 0 = number, 1 = string, 2 = Date-as-epoch-millis. See `sorted-indexes.ts`.\n if (kind === 0 || kind === 2) return typeof key === 'number' && Number.isFinite(key)\n if (kind === 1) return typeof key === 'string'\n return false\n}\n\nfunction isSeq(x: unknown): x is number {\n return typeof x === 'number' && Number.isInteger(x) && x >= 0\n}\n\n/**\n * Decode + validate a persisted snapshot. Returns `null` — meaning \"rebuild\"\n * — for anything that is not exactly the current format: bad JSON (a torn\n * write), a version stamp from another release, a shape mismatch, a\n * malformed key, or entries out of the order the index's binary searches\n * require. A caller must never repair a snapshot; the source of truth is the\n * cache, and rebuilding from it is always available.\n */\nexport function parseFieldIndexSnapshot(json: string): FieldIndexSnapshot | null {\n let raw: unknown\n try {\n raw = JSON.parse(json)\n } catch {\n return null\n }\n if (typeof raw !== 'object' || raw === null) return null\n const o = raw as Record<string, unknown>\n if (o['v'] !== FIELD_INDEX_SNAPSHOT_VERSION) return null\n if (!isSeq(o['nextSeq']) || !Array.isArray(o['entries'])) return null\n const nextSeq = o['nextSeq']\n const entries = o['entries'] as unknown[]\n\n if (o['t'] === 'sorted') {\n if (typeof o['field'] !== 'string') return null\n const out: WireSortedEntry[] = []\n for (const e of entries) {\n if (!Array.isArray(e) || e.length !== 4) return null\n const [kind, key, seq, id] = e as [unknown, unknown, unknown, unknown]\n if (!isWireKey([kind, key])) return null\n if (!isSeq(seq) || seq >= nextSeq || typeof id !== 'string') return null\n out.push([kind as number, key as number | string, seq, id])\n }\n if (!isAscending(out.map(e => [[e[0], e[1]] as WireKey]), out.map(e => e[2]))) return null\n return { v: FIELD_INDEX_SNAPSHOT_VERSION, t: 'sorted', field: o['field'], nextSeq, entries: out }\n }\n\n if (o['t'] === 'compound') {\n const fields = o['fields']\n if (!Array.isArray(fields) || fields.length === 0 || !fields.every(f => typeof f === 'string')) return null\n const out: WireCompoundEntry[] = []\n for (const e of entries) {\n if (!Array.isArray(e) || e.length !== 3) return null\n const [keys, seq, id] = e as [unknown, unknown, unknown]\n if (!Array.isArray(keys) || keys.length !== fields.length || !keys.every(isWireKey)) return null\n if (!isSeq(seq) || seq >= nextSeq || typeof id !== 'string') return null\n out.push([keys as readonly WireKey[], seq, id])\n }\n if (!isAscending(out.map(e => e[0]), out.map(e => e[1]))) return null\n return { v: FIELD_INDEX_SNAPSHOT_VERSION, t: 'compound', fields, nextSeq, entries: out }\n }\n\n return null\n}\n\n/**\n * Every binary search in both index classes assumes `(keys…, seq)` ascending.\n * A blob that is not sorted would not merely be slow — it would answer\n * WRONGLY, so it is rejected rather than re-sorted (re-sorting would launder\n * a corrupt blob into a plausible-looking answer).\n */\nfunction isAscending(keys: ReadonlyArray<readonly WireKey[]>, seqs: readonly number[]): boolean {\n for (let i = 1; i < keys.length; i++) {\n const c = compareWireTuples(keys[i - 1]!, keys[i]!)\n if (c > 0) return false\n if (c === 0 && seqs[i - 1]! >= seqs[i]!) return false\n }\n return true\n}\n\nfunction compareWireTuples(a: readonly WireKey[], b: readonly WireKey[]): number {\n for (let i = 0; i < a.length; i++) {\n const x = a[i]!\n const y = b[i]!\n if (x[0] !== y[0]) return x[0] - y[0]\n if (typeof x[1] === 'number' && typeof y[1] === 'number') {\n if (x[1] !== y[1]) return x[1] - y[1]\n } else if (x[1] !== y[1]) {\n return x[1] < y[1] ? -1 : 1\n }\n }\n return 0\n}\n","/**\n * Sorted (range) secondary indexes — the ordered sibling of the hash\n * index in `eager-indexes.ts` (#1344).\n *\n * A sorted index is an array of `{ kind, key, seq, id }` entries kept in\n * ascending `(kindRank, key, seq)` order. Binary search then answers\n * `<`, `<=`, `>`, `>=`, `between` and `startsWith` as a contiguous slice,\n * and `orderedIds()` walks the array for `orderBy(field).limit(n)`.\n *\n * Three properties are load-bearing, each mirroring the linear scan this\n * replaces (`kernel/query/predicate.ts`):\n *\n * - **Kind-partitioned.** `evaluateFieldClause`'s `isComparable` refuses\n * to order two values of different runtime types, so entries are ranked\n * by kind FIRST. A `string` probe therefore cannot reach `number`\n * entries, exactly as the scan cannot. Values with no order-defined\n * type (booleans, objects, arrays) are not indexed at all.\n * - **Nullish is not indexed**, same as the hash index.\n * - **Ties keep insertion order** (`seq`), which after a `build()` is\n * snapshot order — so an index-served `orderBy(...).limit(n)` returns\n * the same rows the stable scan-and-sort would. An in-place UPDATE\n * reinstates the rank it held rather than appending (#1369): the record\n * cache does not move a re-`put` record, so neither may the index.\n *\n * Keys canonicalise through the SAME per-field closure the hash index\n * uses (`ViaPipeline.canonicalizeIndexKey`), so a Via-covered field's\n * entries live in one key space here too. Range DISPATCH for a\n * Via-covered clause is nevertheless declined by the query builder (a\n * money operand has no ordered stored-form probe) — see\n * `kernel/query/builder.ts`'s `candidateRecords`.\n *\n * PERSISTENCE (#1359) is OPT-IN, via `{ persist: true }` on the declaration.\n * {@link SortedIndex.toSnapshot} / {@link SortedIndex.loadSnapshot} are the\n * whole of this class's part in it — the encrypted sidecar, the freshness\n * stamp and the debounce live in `persisted-field-indexes.ts`. Without the\n * opt-in the index is in memory only and rebuilt on hydrate, as before.\n */\n\nimport { readPath } from '../../kernel/query/predicate.js'\nimport { KIND_STRING, compareKeys, toSortKey, type KeyKind, type SortKey } from '../../kernel/query/sort-key.js'\nimport {\n FIELD_INDEX_SNAPSHOT_VERSION,\n type FieldIndexSnapshot,\n type SortedIndexSnapshot,\n type WireSortedEntry,\n} from './index-snapshot.js'\n\n/** Range operators a sorted index can answer. */\nexport type RangeOperator = '<' | '<=' | '>' | '>=' | 'between' | 'startsWith'\n\n// The ordered-key encoding itself moved to `kernel/query/sort-key.ts` (#1339):\n// #1339's declared joins key on it too, and the kernel spine may not\n// statically import a `with-*` service (`check-architecture.mjs`'s\n// port-layering ratchet). Re-exported here so every existing importer of this\n// module is unchanged, and so there is still exactly ONE definition of what\n// makes two stored values comparable.\nexport { KIND_STRING, compareKeys, toSortKey, type KeyKind, type SortKey } from '../../kernel/query/sort-key.js'\n\ninterface Entry extends SortKey {\n readonly seq: number\n readonly id: string\n}\n\n/** A single field's sorted index. */\nexport class SortedIndex {\n private readonly entries: Entry[] = []\n private nextSeq = 0\n\n constructor(readonly field: string) {}\n\n get size(): number {\n return this.entries.length\n }\n\n clear(): void {\n this.entries.length = 0\n this.nextSeq = 0\n }\n\n /**\n * Insert one record. No-op when the value has no order-defined kind.\n *\n * `seq` REINSTATES a rank a previous entry for this id held — see\n * {@link remove}'s return value and `CollectionIndexes.upsert`. Omit it\n * for a fresh insert, which appends after every existing tie.\n */\n add(id: string, value: unknown, canonicalKey: string | undefined, seq?: number): void {\n const sk = toSortKey(value, canonicalKey)\n if (!sk) return\n const entry: Entry = { ...sk, seq: seq ?? this.nextSeq++, id }\n this.entries.splice(this.insertionPoint(entry), 0, entry)\n }\n\n /**\n * Remove one record, addressed by the value it was indexed under.\n * Returns the rank it held, so an UPDATE can reinstate it (#1369):\n * `sortRecords()` sorts a snapshot whose order does not change when a\n * record is written in place, so a tie-breaking rank that drifted to the\n * back on every `put` would make an index-served page disagree with the\n * scan it must match. Same contract as `CompoundIndex.remove`.\n */\n remove(id: string, value: unknown, canonicalKey: string | undefined): number | undefined {\n const sk = toSortKey(value, canonicalKey)\n if (!sk) return undefined\n // Every entry sharing this key is contiguous; walk that run for the id.\n for (let i = this.lowerBound(sk); i < this.entries.length; i++) {\n const e = this.entries[i]!\n if (compareKeys(e, sk) !== 0) break\n if (e.id === id) {\n this.entries.splice(i, 1)\n return e.seq\n }\n }\n return undefined\n }\n\n /**\n * Ids in ascending (or descending) key order. Ties keep INSERTION order\n * in both directions — `sortRecords()` negates its comparator over a\n * stable sort, which reverses the key order but not the order of equal\n * keys. A plain `.reverse()` here would disagree on ties.\n */\n orderedIds(direction: 'asc' | 'desc'): string[] {\n if (direction === 'asc') return this.entries.map(e => e.id)\n const out: string[] = []\n let end = this.entries.length\n while (end > 0) {\n let start = end - 1\n while (start > 0 && compareKeys(this.entries[start - 1]!, this.entries[end - 1]!) === 0) start--\n for (let i = start; i < end; i++) out.push(this.entries[i]!.id)\n end = start\n }\n return out\n }\n\n /**\n * Ids matching a range clause. Returns an empty set when the probe has\n * no comparable kind — which is what the linear scan would produce too.\n */\n lookup(op: RangeOperator, value: unknown): Set<string> {\n if (op === 'startsWith') return this.prefix(value)\n if (op === 'between') {\n if (!Array.isArray(value) || value.length !== 2) return new Set()\n const lo = toSortKey(value[0], undefined)\n const hi = toSortKey(value[1], undefined)\n if (!lo || !hi || lo.kind !== hi.kind) return new Set()\n return this.slice(this.lowerBound(lo), this.upperBound(hi))\n }\n const probe = toSortKey(value, undefined)\n if (!probe) return new Set()\n const lo = this.lowerBound(probe)\n const hi = this.upperBound(probe)\n // Kind-partitioned: `<`/`>` must stay inside the probe's own kind run.\n const [kindStart, kindEnd] = this.kindBounds(probe.kind)\n switch (op) {\n case '<':\n return this.slice(kindStart, lo)\n case '<=':\n return this.slice(kindStart, hi)\n case '>':\n return this.slice(hi, kindEnd)\n case '>=':\n return this.slice(lo, kindEnd)\n default: {\n const _exhaustive: never = op\n void _exhaustive\n return new Set()\n }\n }\n }\n\n private prefix(value: unknown): Set<string> {\n if (typeof value !== 'string') return new Set()\n const out = new Set<string>()\n const from = this.lowerBound({ kind: KIND_STRING, key: value })\n for (let i = from; i < this.entries.length; i++) {\n const e = this.entries[i]!\n if (e.kind !== KIND_STRING) break\n if (!(e.key as string).startsWith(value)) break\n out.add(e.id)\n }\n return out\n }\n\n private slice(from: number, to: number): Set<string> {\n const out = new Set<string>()\n for (let i = from; i < to; i++) out.add(this.entries[i]!.id)\n return out\n }\n\n /** [start, end) of the run of entries with the given kind — binary, not linear. */\n private kindBounds(kind: KeyKind): [number, number] {\n return [this.kindBoundary(k => k < kind), this.kindBoundary(k => k <= kind)]\n }\n\n private kindBoundary(before: (k: KeyKind) => boolean): number {\n let lo = 0\n let hi = this.entries.length\n while (lo < hi) {\n const mid = (lo + hi) >>> 1\n if (before(this.entries[mid]!.kind)) lo = mid + 1\n else hi = mid\n }\n return lo\n }\n\n /** First index whose key is >= `probe`. */\n private lowerBound(probe: SortKey): number {\n let lo = 0\n let hi = this.entries.length\n while (lo < hi) {\n const mid = (lo + hi) >>> 1\n if (compareKeys(this.entries[mid]!, probe) < 0) lo = mid + 1\n else hi = mid\n }\n return lo\n }\n\n /** First index whose key is > `probe`. */\n private upperBound(probe: SortKey): number {\n let lo = 0\n let hi = this.entries.length\n while (lo < hi) {\n const mid = (lo + hi) >>> 1\n if (compareKeys(this.entries[mid]!, probe) <= 0) lo = mid + 1\n else hi = mid\n }\n return lo\n }\n\n /**\n * The persistable form of this index (#1359). `kind` travels with every\n * key: entries rank by runtime kind first, so an encoding that dropped it\n * would let a `string` probe reach `number` entries on the way back in.\n */\n toSnapshot(): SortedIndexSnapshot {\n return {\n v: FIELD_INDEX_SNAPSHOT_VERSION,\n t: 'sorted',\n field: this.field,\n nextSeq: this.nextSeq,\n entries: this.entries.map(e => [e.kind, e.key, e.seq, e.id] as WireSortedEntry),\n }\n }\n\n /**\n * Adopt a validated snapshot, or refuse it. Refusal (`false`) means the\n * caller rebuilds — it NEVER means a partial index: the entries are staged\n * and only swapped in once every one of them is accepted.\n *\n * `isLive` is the caller's liveness predicate over the record cache. An\n * entry naming a record the cache does not hold means the blob and the\n * collection have diverged (a crash between the two writes, say), so the\n * whole blob is discarded. Crash residue must be a rebuild, never a wrong\n * answer.\n */\n loadSnapshot(snap: FieldIndexSnapshot, isLive: (id: string) => boolean): boolean {\n if (snap.t !== 'sorted' || snap.field !== this.field) return false\n const staged: Entry[] = []\n for (const [kind, key, seq, id] of snap.entries) {\n if (!isLive(id)) return false\n staged.push({ kind: kind as KeyKind, key, seq, id })\n }\n this.entries.length = 0\n for (const e of staged) this.entries.push(e)\n this.nextSeq = snap.nextSeq\n return true\n }\n\n /**\n * Insertion point that keeps ties in `seq` order. A fresh entry lands at\n * the end of its tie run; a REINSTATED one (see {@link add}) lands back at\n * its own rank inside it.\n */\n private insertionPoint(entry: Entry): number {\n let i = this.upperBound(entry)\n while (i > 0 && compareKeys(this.entries[i - 1]!, entry) === 0 && this.entries[i - 1]!.seq > entry.seq) {\n i--\n }\n return i\n }\n}\n\n/** Build the whole index from a snapshot. Entry seqs follow snapshot order. */\nexport function buildSortedIndex<T>(\n idx: SortedIndex,\n records: ReadonlyArray<{ id: string; record: T }>,\n canonicalize?: (field: string, value: unknown) => string | undefined,\n): void {\n idx.clear()\n for (const { id, record } of records) {\n const value = readPath(record, idx.field)\n if (value === null || value === undefined) continue\n idx.add(id, value, canonicalize?.(idx.field, value))\n }\n}\n\n","/**\n * Compound (multi-field) sorted indexes — the tuple-keyed sibling of\n * `sorted-indexes.ts` (#1345).\n *\n * A compound index is an array of `{ keys, seq, id }` entries kept in\n * ascending `(keys[0], keys[1], …, seq)` order, where each `keys[i]` is\n * the SAME `SortKey` the single-field sorted index builds — so the tuple\n * encoding is order-preserving per component BY CONSTRUCTION rather than\n * by a second, hand-rolled serialization. Nothing is flattened into a\n * delimited string: a string component can therefore contain any byte\n * without colliding with a separator, and a money field canonicalized to\n * a scaled-integer string (`ViaPipeline.canonicalizeIndexKey`) or a date\n * stored as ISO text sorts inside its own component exactly as it does in\n * the single-field index.\n *\n * The two load-bearing properties of #1344 hold PER COMPONENT:\n *\n * - **Kind-partitioned.** `compareKeys` ranks by runtime kind first, so\n * within any equality-prefix run a `string` probe on the next\n * component cannot reach `number` entries — mirroring `predicate.ts`'s\n * `isComparable`, exactly as the linear scan behaves.\n * - **Ties keep insertion order** in both directions. `orderedIds()`\n * walks equal-key runs forward even when emitting descending, because\n * `sortRecords()` negates its comparator over a STABLE sort.\n *\n * **A record is indexed only when EVERY component has an order-defined\n * value.** One nullish or non-orderable component and the record is\n * absent — which is why the query builder compares {@link\n * CompoundIndex.size} against the snapshot size before dispatching, and\n * falls back to the scan when the index does not cover the collection.\n *\n * PERSISTENCE (#1359) is OPT-IN, same as its single-field sibling. The wire\n * form keeps the tuple as an ARRAY of per-component keys — see\n * `index-snapshot.ts`: flattening it to a delimited string would destroy\n * exactly the per-component ordering and kind partition this class is built\n * to preserve.\n */\n\nimport { readPath } from '../../kernel/query/predicate.js'\nimport { KIND_STRING, compareKeys, toSortKey, type RangeOperator, type SortKey } from './sorted-indexes.js'\nimport {\n FIELD_INDEX_SNAPSHOT_VERSION,\n type CompoundIndexSnapshot,\n type FieldIndexSnapshot,\n type WireCompoundEntry,\n type WireKey,\n} from './index-snapshot.js'\n\n/** A range constraint on the component just past the equality prefix. */\nexport interface CompoundRangeProbe {\n readonly op: RangeOperator\n readonly value: unknown\n}\n\ninterface CompoundEntry {\n readonly keys: readonly SortKey[]\n readonly seq: number\n readonly id: string\n}\n\n/** One collection's index over an ordered field tuple. */\nexport class CompoundIndex {\n private readonly entries: CompoundEntry[] = []\n private nextSeq = 0\n\n constructor(readonly fields: readonly string[]) {}\n\n get size(): number {\n return this.entries.length\n }\n\n clear(): void {\n this.entries.length = 0\n this.nextSeq = 0\n }\n\n /**\n * Insert one record. No-op unless every component has an ordered key.\n *\n * `seq` REINSTATES a rank a previous entry for this id held — see\n * {@link remove}'s return value and `CollectionIndexes.upsert`. Omit it\n * for a fresh insert, which appends after every existing tie.\n */\n add(id: string, keys: readonly SortKey[] | undefined, seq?: number): void {\n if (!keys) return\n const entry: CompoundEntry = { keys, seq: seq ?? this.nextSeq++, id }\n this.entries.splice(this.insertionPoint(entry), 0, entry)\n }\n\n /**\n * Remove one record, addressed by the tuple it was indexed under.\n * Returns the rank it held, so an UPDATE can reinstate it: `sortRecords()`\n * sorts a snapshot whose order does not change when a record is written in\n * place, so a tie-breaking rank that drifted to the back on every `put`\n * would make an index-served page disagree with the scan it must match.\n */\n remove(id: string, keys: readonly SortKey[] | undefined): number | undefined {\n if (!keys) return undefined\n const [from, to] = this.run(keys, keys.length)\n for (let i = from; i < to; i++) {\n if (this.entries[i]!.id === id) {\n const [gone] = this.entries.splice(i, 1)\n return gone!.seq\n }\n }\n return undefined\n }\n\n /**\n * Ids matching an equality prefix, optionally narrowed by a range on\n * the next component. An empty set is authoritative: the index covers\n * these fields and nothing matches.\n */\n lookup(prefix: readonly SortKey[], range?: CompoundRangeProbe): Set<string> {\n const [from, to] = this.run(prefix, prefix.length)\n if (!range) return this.slice(from, to)\n const k = prefix.length\n if (k >= this.fields.length) return new Set()\n\n if (range.op === 'startsWith') {\n if (typeof range.value !== 'string') return new Set()\n const out = new Set<string>()\n const start = this.lowerBound([...prefix, { kind: KIND_STRING, key: range.value }], k + 1, from, to)\n for (let i = start; i < to; i++) {\n const key = this.entries[i]!.keys[k]!\n if (key.kind !== KIND_STRING) break\n if (!(key.key as string).startsWith(range.value)) break\n out.add(this.entries[i]!.id)\n }\n return out\n }\n\n if (range.op === 'between') {\n if (!Array.isArray(range.value) || range.value.length !== 2) return new Set()\n const lo = toSortKey(range.value[0], undefined)\n const hi = toSortKey(range.value[1], undefined)\n if (!lo || !hi || lo.kind !== hi.kind) return new Set()\n return this.slice(\n this.lowerBound([...prefix, lo], k + 1, from, to),\n this.upperBound([...prefix, hi], k + 1, from, to),\n )\n }\n\n const probe = toSortKey(range.value, undefined)\n if (!probe) return new Set()\n // Kind-partitioned per component: an open-ended bound stays inside the\n // probe's own kind run, so `< '5'` never sweeps up numeric entries.\n const [kindStart, kindEnd] = this.kindRun(from, to, k, probe.kind)\n const lo = this.lowerBound([...prefix, probe], k + 1, from, to)\n const hi = this.upperBound([...prefix, probe], k + 1, from, to)\n switch (range.op) {\n case '<':\n return this.slice(kindStart, lo)\n case '<=':\n return this.slice(kindStart, hi)\n case '>':\n return this.slice(hi, kindEnd)\n case '>=':\n return this.slice(lo, kindEnd)\n default: {\n const _exhaustive: never = range.op\n void _exhaustive\n return new Set()\n }\n }\n }\n\n /**\n * Ids matching an equality prefix, in the order of the remaining\n * components. Ties keep INSERTION order in both directions — a plain\n * `.reverse()` would disagree with `sortRecords()` on equal keys.\n */\n orderedIds(prefix: readonly SortKey[], direction: 'asc' | 'desc'): string[] {\n const [from, to] = this.run(prefix, prefix.length)\n const out: string[] = []\n if (direction === 'asc') {\n for (let i = from; i < to; i++) out.push(this.entries[i]!.id)\n return out\n }\n let end = to\n while (end > from) {\n let start = end - 1\n while (start > from && this.compare(this.entries[start - 1]!, this.entries[end - 1]!.keys, this.fields.length) === 0) {\n start--\n }\n for (let i = start; i < end; i++) out.push(this.entries[i]!.id)\n end = start\n }\n return out\n }\n\n private slice(from: number, to: number): Set<string> {\n const out = new Set<string>()\n for (let i = from; i < to; i++) out.add(this.entries[i]!.id)\n return out\n }\n\n /** [start, end) of the entries whose first `upto` components equal `probe`. */\n private run(probe: readonly SortKey[], upto: number): [number, number] {\n return [\n this.lowerBound(probe, upto, 0, this.entries.length),\n this.upperBound(probe, upto, 0, this.entries.length),\n ]\n }\n\n /** [start, end) of the entries in [from,to) whose component `k` has this kind. */\n private kindRun(from: number, to: number, k: number, kind: number): [number, number] {\n return [\n this.kindBoundary(from, to, k, x => x < kind),\n this.kindBoundary(from, to, k, x => x <= kind),\n ]\n }\n\n private kindBoundary(from: number, to: number, k: number, before: (kind: number) => boolean): number {\n let lo = from\n let hi = to\n while (lo < hi) {\n const mid = (lo + hi) >>> 1\n if (before(this.entries[mid]!.keys[k]!.kind)) lo = mid + 1\n else hi = mid\n }\n return lo\n }\n\n /** First index in [from,to) whose first `upto` components are >= `probe`. */\n private lowerBound(probe: readonly SortKey[], upto: number, from: number, to: number): number {\n let lo = from\n let hi = to\n while (lo < hi) {\n const mid = (lo + hi) >>> 1\n if (this.compare(this.entries[mid]!, probe, upto) < 0) lo = mid + 1\n else hi = mid\n }\n return lo\n }\n\n /** First index in [from,to) whose first `upto` components are > `probe`. */\n private upperBound(probe: readonly SortKey[], upto: number, from: number, to: number): number {\n let lo = from\n let hi = to\n while (lo < hi) {\n const mid = (lo + hi) >>> 1\n if (this.compare(this.entries[mid]!, probe, upto) <= 0) lo = mid + 1\n else hi = mid\n }\n return lo\n }\n\n /**\n * The persistable form of this index (#1359). Each entry's tuple stays an\n * ARRAY of `[kind, key]` pairs: nothing is joined into a string, so a\n * string component may hold any byte and the per-component kind partition\n * survives the round trip intact.\n */\n toSnapshot(): CompoundIndexSnapshot {\n return {\n v: FIELD_INDEX_SNAPSHOT_VERSION,\n t: 'compound',\n fields: [...this.fields],\n nextSeq: this.nextSeq,\n entries: this.entries.map(\n e => [e.keys.map(k => [k.kind, k.key] as WireKey), e.seq, e.id] as WireCompoundEntry,\n ),\n }\n }\n\n /**\n * Adopt a validated snapshot, or refuse it. Same contract as\n * `SortedIndex.loadSnapshot`: all-or-nothing, and an entry naming a record\n * the cache does not hold rejects the whole blob so crash residue becomes a\n * rebuild rather than a wrong answer. A snapshot whose field tuple is not\n * exactly this index's is refused — the declaration changed under it.\n */\n loadSnapshot(snap: FieldIndexSnapshot, isLive: (id: string) => boolean): boolean {\n if (snap.t !== 'compound') return false\n if (snap.fields.length !== this.fields.length) return false\n for (let i = 0; i < snap.fields.length; i++) if (snap.fields[i] !== this.fields[i]) return false\n const staged: CompoundEntry[] = []\n for (const [keys, seq, id] of snap.entries) {\n if (!isLive(id)) return false\n staged.push({ keys: keys.map(k => ({ kind: k[0] as SortKey['kind'], key: k[1] })), seq, id })\n }\n this.entries.length = 0\n for (const e of staged) this.entries.push(e)\n this.nextSeq = snap.nextSeq\n return true\n }\n\n /**\n * Insertion point that keeps ties in `seq` order. A fresh entry lands at\n * the end of its tie run; a REINSTATED one (see {@link add}) lands back at\n * its own rank inside it.\n */\n private insertionPoint(entry: CompoundEntry): number {\n const to = this.upperBound(entry.keys, this.fields.length, 0, this.entries.length)\n let i = to\n while (i > 0 && this.compare(this.entries[i - 1]!, entry.keys, this.fields.length) === 0\n && this.entries[i - 1]!.seq > entry.seq) {\n i--\n }\n return i\n }\n\n private compare(entry: CompoundEntry, probe: readonly SortKey[], upto: number): number {\n for (let i = 0; i < upto; i++) {\n const c = compareKeys(entry.keys[i]!, probe[i]!)\n if (c !== 0) return c\n }\n return 0\n }\n}\n\n/**\n * The tuple key for one record, or `undefined` when any component is\n * nullish or has no order-defined runtime type. Canonicalizes through the\n * same per-field closure the hash and sorted indexes use, so a Via-covered\n * component lives in one key space across all three.\n */\nexport function tupleKeyOf<T>(\n fields: readonly string[],\n record: T,\n canonicalize?: (field: string, value: unknown) => string | undefined,\n): SortKey[] | undefined {\n const keys: SortKey[] = []\n for (const field of fields) {\n const value = readPath(record, field)\n if (value === null || value === undefined) return undefined\n const key = toSortKey(value, canonicalize?.(field, value))\n if (!key) return undefined\n keys.push(key)\n }\n return keys\n}\n\n/** Probe keys for an equality prefix, or `undefined` if any operand is unorderable. */\nexport function probeKeysOf(values: readonly unknown[]): SortKey[] | undefined {\n const keys: SortKey[] = []\n for (const value of values) {\n const key = toSortKey(value, undefined)\n if (!key) return undefined\n keys.push(key)\n }\n return keys\n}\n\n/** Build the whole index from a snapshot. Entry seqs follow snapshot order. */\nexport function buildCompoundIndex<T>(\n idx: CompoundIndex,\n records: ReadonlyArray<{ id: string; record: T }>,\n canonicalize?: (field: string, value: unknown) => string | undefined,\n): void {\n idx.clear()\n for (const { id, record } of records) {\n idx.add(id, tupleKeyOf(idx.fields, record, canonicalize))\n }\n}\n\n/** Stable map key for a field tuple. `\\0` cannot appear in a field path. */\nexport function compoundKey(fields: readonly string[]): string {\n return fields.join('\\u0000')\n}\n","/**\n * Secondary indexes for the query DSL.\n *\n * ships **in-memory hash indexes**:\n * - Built during `Collection.ensureHydrated()` from the decrypted cache\n * - Maintained incrementally on `put` and `delete`\n * - Consulted by the query executor for `==` and `in` operators on\n * indexed fields, falling back to a linear scan otherwise\n * - Live entirely in memory — no adapter writes for the index itself\n *\n * Persistent encrypted index blobs (the spec's \"store as a separate\n * AES-256-GCM blob\" note) are deferred to a follow-up issue. The reasons\n * are documented in the PR body — short version: at the target\n * scale of 1K–50K records, building the index during hydrate is free,\n * so persistence buys nothing measurable.\n */\n\nimport { readPath } from '../../kernel/query/predicate.js'\nimport { stringifyBucketKey, isProbeableBucketKey } from '../../kernel/query/distinct-key.js'\nimport { SortedIndex, buildSortedIndex, type RangeOperator } from './sorted-indexes.js'\nimport {\n CompoundIndex,\n buildCompoundIndex,\n compoundKey,\n probeKeysOf,\n tupleKeyOf,\n type CompoundRangeProbe,\n} from './compound-indexes.js'\nimport {\n compoundIndexKey,\n sortedIndexKey,\n type FieldIndexSnapshot,\n} from './index-snapshot.js'\n\n/**\n * Index declaration accepted by `Collection`'s constructor.\n *\n * Accepts:\n * - `string` — a single-field hash index (`'clientId'`)\n * - `{ fields: [...] }` or `readonly string[]` — a composite index\n * over an ordered field tuple. Only lazy-mode\n * collections consume composite declarations today; eager mode\n * silently treats a composite as equivalent to declaring each\n * component field as its own single-field index.\n *\n * Additive variants (unique constraints, partial indexes) will land as\n * further union members without breaking existing declarations.\n */\nexport type IndexDef =\n | string\n | {\n readonly fields: readonly string[]\n /**\n * Enforce that no two records share this field tuple. A MULTI-field\n * tuple is a COMPOUND unique — uniqueness over the tuple, never over\n * each component on its own (`['workerId','employerId']` allows one\n * worker at many employers). Null-distinct: a record with `null` or\n * `undefined` in any constrained field is exempt.\n *\n * ⚠️ **What \"unique\" means depends on the collection's mode (#1358),\n * and one of the four cannot promise prevention at all:**\n *\n * - eager (default) — prevented, from the in-memory map.\n * - lazy (`prefetch: false`) — prevented, by a point lookup through the\n * persisted `_idx/` mirror. Requires `withIndexing()`.\n * - tiered (`tiers: [...]`) — prevented across every tier whose DEK the\n * writer holds. **A tier the writer cannot read is outside the\n * guarantee** — those records are unreadable, so no local check can\n * see them, and a duplicate against one is accepted.\n * - CRDT (`crdt: '...'`) — **NOT prevented.** Uniqueness cannot be\n * enforced across concurrent replicas: two replicas that are offline\n * from each other can both accept the same value, and no local check\n * can prevent that. The write always succeeds and both records are\n * kept; the collision is reported on the `unique:violation` event as\n * a `UniqueConstraintError`, both when it happens and when a later\n * session first sees the two records together. What you get is\n * uniqueness within what this writer could see at write time, plus\n * detection when the replicas meet.\n */\n readonly unique?: boolean\n readonly kind?: IndexKind\n /**\n * Persist this index as an encrypted sidecar so a restart reuses it\n * instead of rebuilding (#1359). Only meaningful with `kind: 'sorted'`\n * — the hash index is not persisted. OPT-IN until measured: at the\n * 1K–50K target scale rebuild-on-open is free, and a sidecar is a\n * write on every debounce window plus a blob at rest.\n */\n readonly persist?: boolean\n }\n | readonly string[]\n\n/**\n * The access structure an index declaration asks for (#1344).\n *\n * `'hash'` (the default, and what every pre-#1344 declaration means) is\n * the equality/`in` bucket map. `'sorted'` additionally maintains an\n * ordered array over the same canonicalized keys, which lights up\n * index-driven `<`, `<=`, `>`, `>=`, `between`, `startsWith` and\n * `orderBy(field).limit(n)`. A `'sorted'` declaration keeps the hash\n * index too — `==`/`in` stay O(1).\n */\ntype IndexKind = 'hash' | 'sorted'\n\n/**\n * Normalize a declared `IndexDef[]` into a uniform `{ fields, unique? }`\n * shape: `string` → `{fields:[s]}`, `string[]` → `{fields}`, object →\n * passthrough. Pure — used by `Collection`'s sensitive-field leak check\n * and by `getDeclaredIndexes()` (introspection).\n */\nexport function normalizeIndexDefs(\n defs: readonly IndexDef[],\n): ReadonlyArray<{ readonly fields: readonly string[]; readonly unique?: boolean }> {\n return defs.map((def) => {\n if (typeof def === 'string') return { fields: [def] }\n if (Array.isArray(def)) return { fields: def }\n return def as { readonly fields: readonly string[]; readonly unique?: boolean }\n })\n}\n\n/**\n * Internal representation of a built hash index.\n *\n * Maps stringified field values to the set of record ids whose value\n * for that field matches. Stringification keeps the index simple and\n * works uniformly for primitives (`'open'`, `'42'`, `'true'`).\n *\n * Records whose indexed field is `undefined` or `null` are NOT inserted\n * — `query().where('field', '==', undefined)` falls back to a linear\n * scan, which is the conservative behavior.\n */\nexport interface HashIndex {\n readonly field: string\n readonly buckets: Map<string, Set<string>>\n}\n\n/**\n * Container for all indexes on a single collection.\n *\n * Methods are pure with respect to the in-memory `buckets` Map — they\n * never touch the adapter or the keyring. The Collection class owns\n * lifecycle (build on hydrate, maintain on put/delete).\n */\nexport class CollectionIndexes {\n private readonly indexes = new Map<string, HashIndex>()\n\n /**\n * Sorted (range) indexes, keyed by field — the #1344 half. Parallel to\n * `indexes` above and maintained at the SAME mutation sites, through the\n * SAME `canonicalize` closure, so the two can never disagree about which\n * key space a field lives in.\n */\n private readonly sorted = new Map<string, SortedIndex>()\n\n /**\n * Compound (tuple-keyed) sorted indexes, keyed by the joined field\n * tuple — the #1345 half. Third parallel map, maintained at the SAME\n * mutation sites through the SAME `canonicalize` closure as the other\n * two, so no field can end up in disagreeing key spaces.\n */\n private readonly compound = new Map<string, CompoundIndex>()\n\n /**\n * The indexes declared `persist: true` (#1359), keyed by their SIDECAR key\n * (`s:<field>` / `c:<f1>,<f2>`). A separate map rather than a flag on the\n * index classes: persistence is a property of the DECLARATION, and the\n * index classes stay unaware of storage.\n */\n private readonly persistable = new Map<string, SortedIndex | CompoundIndex>()\n\n /**\n * Per-field bucket-key canonicalizer (#672 review C1), registered ONCE\n * via {@link setCanonicalizer} when the collection wires indexing up\n * (money-aware via `ViaPipeline.canonicalizeIndexKey`). Consulted by\n * EVERY bucket-mutation site — `build`/`upsert`/`remove` — so bucket\n * membership is symmetric by construction: a value can never be added\n * under a canonical key and later removed under the raw one (or vice\n * versa), which is what stranded ids on `put`/`delete` before this fix.\n */\n private canonicalize?: (field: string, value: unknown) => string | undefined\n\n /**\n * Register the bucket-key canonicalizer. Called once, where the\n * collection constructs its indexing state — safe to call again (the\n * closure is simply replaced) but there is normally only one caller.\n */\n setCanonicalizer(fn: (field: string, value: unknown) => string | undefined): void {\n this.canonicalize = fn\n }\n\n /**\n * Declare an index. Subsequent record additions are tracked under it.\n * Calling this twice for the same field is a no-op (idempotent).\n */\n declare(field: string): void {\n if (this.indexes.has(field)) return\n this.indexes.set(field, { field, buckets: new Map() })\n }\n\n /**\n * Declare a sorted (range) index on a field. Independent of\n * {@link declare} — callers that want both `==` speed and range speed\n * declare both (which is what `withIndexing()` does for a\n * `kind: 'sorted'` declaration). Idempotent.\n */\n declareSorted(field: string, opts?: { readonly persist?: boolean }): void {\n let idx = this.sorted.get(field)\n if (!idx) {\n idx = new SortedIndex(field)\n this.sorted.set(field, idx)\n }\n if (opts?.persist) this.persistable.set(sortedIndexKey(field), idx)\n }\n\n /** True if the given field has a declared SORTED index. */\n hasSorted(field: string): boolean {\n return this.sorted.has(field)\n }\n\n /** All sorted-index field names, in declaration order. */\n sortedFields(): string[] {\n return [...this.sorted.keys()]\n }\n\n /** Number of entries in a field's sorted index (0 when undeclared). */\n sortedSize(field: string): number {\n return this.sorted.get(field)?.size ?? 0\n }\n\n /**\n * Range lookup: ids whose `field` satisfies the operator. Returns\n * `null` when no SORTED index covers the field — the caller falls back\n * to a linear scan. An empty set means \"the index covers this field and\n * nothing matches\", which is authoritative.\n */\n lookupRange(field: string, op: RangeOperator, value: unknown): ReadonlySet<string> | null {\n return this.sorted.get(field)?.lookup(op, value) ?? null\n }\n\n /**\n * Ids of every indexed record in `field` order. `null` when no sorted\n * index covers the field. Records whose value is nullish or has no\n * order-defined type are absent — compare against {@link sortedSize}\n * before treating the result as the full collection.\n */\n orderedIds(field: string, direction: 'asc' | 'desc'): readonly string[] | null {\n return this.sorted.get(field)?.orderedIds(direction) ?? null\n }\n\n /**\n * Declare a compound (multi-field) sorted index over an ordered field\n * tuple. A tuple shorter than two fields is a single-field sorted index\n * and is ignored here. Idempotent.\n */\n declareCompound(fields: readonly string[], opts?: { readonly persist?: boolean }): void {\n if (fields.length < 2) return\n const key = compoundKey(fields)\n let idx = this.compound.get(key)\n if (!idx) {\n idx = new CompoundIndex([...fields])\n this.compound.set(key, idx)\n }\n if (opts?.persist) this.persistable.set(compoundIndexKey(fields), idx)\n }\n\n /** Every declared field tuple, in declaration order. */\n compoundTuples(): ReadonlyArray<readonly string[]> {\n return [...this.compound.values()].map(idx => idx.fields)\n }\n\n /**\n * Number of records the tuple's index holds (0 when undeclared). A\n * record with a nullish or non-orderable component is absent, so a\n * caller that removes clauses from the plan MUST compare this against\n * the snapshot size before trusting the result.\n */\n compoundSize(fields: readonly string[]): number {\n return this.compound.get(compoundKey(fields))?.size ?? 0\n }\n\n /**\n * Compound lookup: ids whose leading components equal `prefixValues`,\n * optionally narrowed by a range on the component just past them.\n * `null` when no compound index covers the tuple, or when an operand\n * has no order-defined type — the caller falls back to a linear scan.\n */\n lookupCompound(\n fields: readonly string[],\n prefixValues: readonly unknown[],\n range?: CompoundRangeProbe,\n ): ReadonlySet<string> | null {\n const idx = this.compound.get(compoundKey(fields))\n if (!idx) return null\n const prefix = probeKeysOf(prefixValues)\n if (!prefix) return null\n return idx.lookup(prefix, range)\n }\n\n /**\n * Ids matching an equality prefix, ordered by the remaining components.\n * `null` when no compound index covers the tuple or an operand has no\n * order-defined type. See {@link compoundSize} for the coverage caveat.\n */\n compoundOrderedIds(\n fields: readonly string[],\n prefixValues: readonly unknown[],\n direction: 'asc' | 'desc',\n ): readonly string[] | null {\n const idx = this.compound.get(compoundKey(fields))\n if (!idx) return null\n const prefix = probeKeysOf(prefixValues)\n if (!prefix) return null\n return idx.orderedIds(prefix, direction)\n }\n\n /** True if the given field has a declared index. */\n has(field: string): boolean {\n return this.indexes.has(field)\n }\n\n /** All declared field names, in declaration order. */\n fields(): string[] {\n return [...this.indexes.keys()]\n }\n\n /**\n * Build all declared indexes from a snapshot of records.\n * Called once per hydration. O(N × indexes.size). Buckets through the\n * registered {@link setCanonicalizer} closure, same as `upsert`/`remove`.\n */\n build<T>(records: ReadonlyArray<{ id: string; record: T }>, skip: ReadonlySet<string> = EMPTY_KEYS): void {\n for (const idx of this.indexes.values()) {\n idx.buckets.clear()\n for (const { id, record } of records) {\n addToIndex(idx, id, record, this.canonicalize)\n }\n }\n // `skip` names the sidecar keys a persisted snapshot already restored\n // (#1359) — rebuilding them would throw that work away AND renumber every\n // `seq`, which is what the whole ordered fast path rests on.\n for (const [field, idx] of this.sorted) {\n if (skip.has(sortedIndexKey(field))) continue\n buildSortedIndex(idx, records, this.canonicalize)\n }\n for (const idx of this.compound.values()) {\n if (skip.has(compoundIndexKey(idx.fields))) continue\n buildCompoundIndex(idx, records, this.canonicalize)\n }\n }\n\n /** Sidecar keys of every index declared `persist: true`, in declaration order. */\n persistableKeys(): readonly string[] {\n return [...this.persistable.keys()]\n }\n\n /** The persistable snapshot behind one sidecar key, or `undefined` if it is not declared. */\n snapshotIndex(key: string): FieldIndexSnapshot | undefined {\n return this.persistable.get(key)?.toSnapshot()\n }\n\n /**\n * Adopt a validated snapshot into the index behind `key`. `false` means the\n * caller must rebuild that index from the cache — the index is left\n * untouched, never half-loaded.\n */\n restoreIndex(key: string, snap: FieldIndexSnapshot, isLive: (id: string) => boolean): boolean {\n return this.persistable.get(key)?.loadSnapshot(snap, isLive) ?? false\n }\n\n /**\n * Insert or update a single record across all indexes.\n * Called by `Collection.put()` after the encrypted write succeeds.\n *\n * If `previousRecord` is provided, the record is removed from any old\n * buckets first — this is the update path. Pass `null` for fresh adds.\n */\n upsert<T>(id: string, newRecord: T, previousRecord: T | null): void {\n if (this.indexes.size === 0 && this.sorted.size === 0 && this.compound.size === 0) return\n // Detach the compound and sorted entries FIRST, holding the rank each one had. An\n // in-place `put` does not move a record within `snapshot()`, so it must\n // not move it within a tie run either — otherwise an index-served\n // `orderBy(...).limit(n)` page disagrees with the stable scan-and-sort\n // it is required to reproduce exactly (#1345, #1369). The `this.remove()`\n // below re-runs both removals, which are then no-ops.\n const ranks = new Map<string, number | undefined>()\n const sortedRanks = new Map<string, number | undefined>()\n if (previousRecord !== null) {\n for (const [key, idx] of this.compound) {\n ranks.set(key, idx.remove(id, tupleKeyOf(idx.fields, previousRecord, this.canonicalize)))\n }\n // Same for the single-field sorted indexes (#1369) — the defect and the\n // remedy are identical, and the two implementations must agree.\n for (const [key, idx] of this.sorted) {\n const value = readPath(previousRecord, idx.field)\n if (value === null || value === undefined) continue\n sortedRanks.set(key, idx.remove(id, value, this.canonicalize?.(idx.field, value)))\n }\n this.remove(id, previousRecord)\n }\n for (const idx of this.indexes.values()) {\n addToIndex(idx, id, newRecord, this.canonicalize)\n }\n for (const [key, idx] of this.sorted) {\n const value = readPath(newRecord, idx.field)\n if (value === null || value === undefined) continue\n idx.add(id, value, this.canonicalize?.(idx.field, value), sortedRanks.get(key))\n }\n for (const [key, idx] of this.compound) {\n idx.add(id, tupleKeyOf(idx.fields, newRecord, this.canonicalize), ranks.get(key))\n }\n }\n\n /**\n * Remove a record from all indexes. Called by `Collection.delete()`\n * (and as the first half of `upsert` for the update path).\n */\n remove<T>(id: string, record: T): void {\n if (this.indexes.size === 0 && this.sorted.size === 0 && this.compound.size === 0) return\n for (const idx of this.indexes.values()) {\n removeFromIndex(idx, id, record, this.canonicalize)\n }\n for (const idx of this.sorted.values()) {\n const value = readPath(record, idx.field)\n if (value === null || value === undefined) continue\n idx.remove(id, value, this.canonicalize?.(idx.field, value))\n }\n for (const idx of this.compound.values()) {\n idx.remove(id, tupleKeyOf(idx.fields, record, this.canonicalize))\n }\n }\n\n /** Drop all index data. Called when the collection is invalidated. */\n clear(): void {\n for (const idx of this.indexes.values()) {\n idx.buckets.clear()\n }\n for (const idx of this.sorted.values()) {\n idx.clear()\n }\n for (const idx of this.compound.values()) {\n idx.clear()\n }\n }\n\n /**\n * Equality lookup: return the set of record ids whose `field` matches\n * the given value. Returns `null` if no index covers the field — the\n * caller should fall back to a linear scan.\n *\n * ⛔ ALSO `null` when the OPERAND has no bucket ADDRESS (#1402) — a\n * nullish operand, or an object one, which every object-valued record in\n * the collection shares. Answering those from the buckets returns rows\n * the scan does not, silently, and only on the collections that happen to\n * have an index. See `isProbeableBucketKey` for the two measurements.\n *\n * The returned Set is a reference to the index's internal storage —\n * callers must NOT mutate it.\n */\n lookupEqual(field: string, value: unknown): ReadonlySet<string> | null {\n const idx = this.indexes.get(field)\n if (!idx) return null\n if (!isProbeableBucketKey(value)) return null\n const key = stringifyKey(value)\n return idx.buckets.get(key) ?? EMPTY_SET\n }\n\n /**\n * Set lookup: return the union of record ids whose `field` matches any\n * of the given values. Returns `null` if no index covers the field.\n *\n * ⛔ ALSO `null` when ANY member of `values` has no bucket address\n * (#1402) — one unaddressable member poisons the whole union, since the\n * result is a union and there is no partial answer to hand back. Same\n * measurement as {@link lookupEqual}.\n */\n lookupIn(field: string, values: readonly unknown[]): ReadonlySet<string> | null {\n const idx = this.indexes.get(field)\n if (!idx) return null\n if (!values.every(isProbeableBucketKey)) return null\n const out = new Set<string>()\n for (const value of values) {\n const key = stringifyKey(value)\n const bucket = idx.buckets.get(key)\n if (bucket) {\n for (const id of bucket) out.add(id)\n }\n }\n return out\n }\n\n /**\n * One record id per NON-EMPTY bucket of `field`'s hash index, in bucket\n * order — the index-backed spine of `Query.distinct()` (#1347). `null` when\n * no hash index covers the field, so the caller scans instead.\n *\n * The bucket set IS the distinct key set, so this costs O(buckets) rather\n * than O(records). It returns REPRESENTATIVE IDS rather than the keys\n * themselves on purpose: a bucket key is a canonical string (money's\n * BigInt-normalized scaled int, say), and `distinct()` owes its caller the\n * field's real value, which only the record carries.\n *\n * Bucket insertion order is first-seen record order — `build()` walks the\n * snapshot in order and `upsert()` appends — which is why an index-backed\n * `distinct()` and a scanned one agree on ORDER too, not merely on the set.\n * Empty buckets are skipped defensively; `removeFromIndex` already deletes\n * them, so this is belt-and-braces against a future partial removal path.\n */\n bucketRepresentatives(field: string): readonly string[] | null {\n const idx = this.indexes.get(field)\n if (!idx) return null\n const out: string[] = []\n for (const bucket of idx.buckets.values()) {\n for (const id of bucket) {\n out.push(id)\n break\n }\n }\n return out\n }\n}\n\nconst EMPTY_SET: ReadonlySet<string> = new Set()\nconst EMPTY_KEYS: ReadonlySet<string> = new Set()\n\n/**\n * Stringify a value into a stable bucket key.\n *\n * ⚠️ The DEFINITION moved to `kernel/query/distinct-key.ts` (#1347) and is\n * only aliased here. `distinct()` / `countDistinct()` recompute this key on\n * the scan path, and an index-backed `distinct()` reads the buckets it made —\n * one definition is what stops those two answers from drifting apart. Change\n * the shared function, not a copy.\n */\nconst stringifyKey = stringifyBucketKey\n\nfunction addToIndex<T>(\n idx: HashIndex,\n id: string,\n record: T,\n canonicalize?: (field: string, value: unknown) => string | undefined,\n): void {\n const value = readPath(record, idx.field)\n if (value === null || value === undefined) return\n const key = canonicalize?.(idx.field, value) ?? stringifyKey(value)\n let bucket = idx.buckets.get(key)\n if (!bucket) {\n bucket = new Set()\n idx.buckets.set(key, bucket)\n }\n bucket.add(id)\n}\n\nfunction removeFromIndex<T>(\n idx: HashIndex,\n id: string,\n record: T,\n canonicalize?: (field: string, value: unknown) => string | undefined,\n): void {\n const value = readPath(record, idx.field)\n if (value === null || value === undefined) return\n const key = canonicalize?.(idx.field, value) ?? stringifyKey(value)\n const bucket = idx.buckets.get(key)\n if (!bucket) return\n bucket.delete(id)\n // Clean up empty buckets so the Map doesn't accumulate dead keys.\n if (bucket.size === 0) idx.buckets.delete(key)\n}\n"],"mappings":";;;;;;;;;;;;;;AAwBO,IAAM,+BAA+B;AAkCrC,SAAS,eAAe,OAAuB;AACpD,SAAO,KAAK,mBAAmB,KAAK,CAAC;AACvC;AAGO,SAAS,iBAAiB,QAAmC;AAClE,SAAO,KAAK,OAAO,IAAI,kBAAkB,EAAE,KAAK,GAAG,CAAC;AACtD;AAGA,SAAS,UAAU,GAA0B;AAC3C,MAAI,CAAC,MAAM,QAAQ,CAAC,KAAK,EAAE,WAAW,EAAG,QAAO;AAChD,QAAM,CAAC,MAAM,GAAG,IAAI;AAEpB,MAAI,SAAS,KAAK,SAAS,EAAG,QAAO,OAAO,QAAQ,YAAY,OAAO,SAAS,GAAG;AACnF,MAAI,SAAS,EAAG,QAAO,OAAO,QAAQ;AACtC,SAAO;AACT;AAEA,SAAS,MAAM,GAAyB;AACtC,SAAO,OAAO,MAAM,YAAY,OAAO,UAAU,CAAC,KAAK,KAAK;AAC9D;AAUO,SAAS,wBAAwB,MAAyC;AAC/E,MAAI;AACJ,MAAI;AACF,UAAM,KAAK,MAAM,IAAI;AAAA,EACvB,QAAQ;AACN,WAAO;AAAA,EACT;AACA,MAAI,OAAO,QAAQ,YAAY,QAAQ,KAAM,QAAO;AACpD,QAAM,IAAI;AACV,MAAI,EAAE,GAAG,MAAM,6BAA8B,QAAO;AACpD,MAAI,CAAC,MAAM,EAAE,SAAS,CAAC,KAAK,CAAC,MAAM,QAAQ,EAAE,SAAS,CAAC,EAAG,QAAO;AACjE,QAAM,UAAU,EAAE,SAAS;AAC3B,QAAM,UAAU,EAAE,SAAS;AAE3B,MAAI,EAAE,GAAG,MAAM,UAAU;AACvB,QAAI,OAAO,EAAE,OAAO,MAAM,SAAU,QAAO;AAC3C,UAAM,MAAyB,CAAC;AAChC,eAAW,KAAK,SAAS;AACvB,UAAI,CAAC,MAAM,QAAQ,CAAC,KAAK,EAAE,WAAW,EAAG,QAAO;AAChD,YAAM,CAAC,MAAM,KAAK,KAAK,EAAE,IAAI;AAC7B,UAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAG,QAAO;AACpC,UAAI,CAAC,MAAM,GAAG,KAAK,OAAO,WAAW,OAAO,OAAO,SAAU,QAAO;AACpE,UAAI,KAAK,CAAC,MAAgB,KAAwB,KAAK,EAAE,CAAC;AAAA,IAC5D;AACA,QAAI,CAAC,YAAY,IAAI,IAAI,OAAK,CAAC,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC,CAAY,CAAC,GAAG,IAAI,IAAI,OAAK,EAAE,CAAC,CAAC,CAAC,EAAG,QAAO;AACtF,WAAO,EAAE,GAAG,8BAA8B,GAAG,UAAU,OAAO,EAAE,OAAO,GAAG,SAAS,SAAS,IAAI;AAAA,EAClG;AAEA,MAAI,EAAE,GAAG,MAAM,YAAY;AACzB,UAAM,SAAS,EAAE,QAAQ;AACzB,QAAI,CAAC,MAAM,QAAQ,MAAM,KAAK,OAAO,WAAW,KAAK,CAAC,OAAO,MAAM,OAAK,OAAO,MAAM,QAAQ,EAAG,QAAO;AACvG,UAAM,MAA2B,CAAC;AAClC,eAAW,KAAK,SAAS;AACvB,UAAI,CAAC,MAAM,QAAQ,CAAC,KAAK,EAAE,WAAW,EAAG,QAAO;AAChD,YAAM,CAAC,MAAM,KAAK,EAAE,IAAI;AACxB,UAAI,CAAC,MAAM,QAAQ,IAAI,KAAK,KAAK,WAAW,OAAO,UAAU,CAAC,KAAK,MAAM,SAAS,EAAG,QAAO;AAC5F,UAAI,CAAC,MAAM,GAAG,KAAK,OAAO,WAAW,OAAO,OAAO,SAAU,QAAO;AACpE,UAAI,KAAK,CAAC,MAA4B,KAAK,EAAE,CAAC;AAAA,IAChD;AACA,QAAI,CAAC,YAAY,IAAI,IAAI,OAAK,EAAE,CAAC,CAAC,GAAG,IAAI,IAAI,OAAK,EAAE,CAAC,CAAC,CAAC,EAAG,QAAO;AACjE,WAAO,EAAE,GAAG,8BAA8B,GAAG,YAAY,QAAQ,SAAS,SAAS,IAAI;AAAA,EACzF;AAEA,SAAO;AACT;AAQA,SAAS,YAAY,MAAyC,MAAkC;AAC9F,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAM,IAAI,kBAAkB,KAAK,IAAI,CAAC,GAAI,KAAK,CAAC,CAAE;AAClD,QAAI,IAAI,EAAG,QAAO;AAClB,QAAI,MAAM,KAAK,KAAK,IAAI,CAAC,KAAM,KAAK,CAAC,EAAI,QAAO;AAAA,EAClD;AACA,SAAO;AACT;AAEA,SAAS,kBAAkB,GAAuB,GAA+B;AAC/E,WAAS,IAAI,GAAG,IAAI,EAAE,QAAQ,KAAK;AACjC,UAAM,IAAI,EAAE,CAAC;AACb,UAAM,IAAI,EAAE,CAAC;AACb,QAAI,EAAE,CAAC,MAAM,EAAE,CAAC,EAAG,QAAO,EAAE,CAAC,IAAI,EAAE,CAAC;AACpC,QAAI,OAAO,EAAE,CAAC,MAAM,YAAY,OAAO,EAAE,CAAC,MAAM,UAAU;AACxD,UAAI,EAAE,CAAC,MAAM,EAAE,CAAC,EAAG,QAAO,EAAE,CAAC,IAAI,EAAE,CAAC;AAAA,IACtC,WAAW,EAAE,CAAC,MAAM,EAAE,CAAC,GAAG;AACxB,aAAO,EAAE,CAAC,IAAI,EAAE,CAAC,IAAI,KAAK;AAAA,IAC5B;AAAA,EACF;AACA,SAAO;AACT;;;AClGO,IAAM,cAAN,MAAkB;AAAA,EAIvB,YAAqB,OAAe;AAAf;AAAA,EAAgB;AAAA,EAAhB;AAAA,EAHJ,UAAmB,CAAC;AAAA,EAC7B,UAAU;AAAA,EAIlB,IAAI,OAAe;AACjB,WAAO,KAAK,QAAQ;AAAA,EACtB;AAAA,EAEA,QAAc;AACZ,SAAK,QAAQ,SAAS;AACtB,SAAK,UAAU;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,IAAI,IAAY,OAAgB,cAAkC,KAAoB;AACpF,UAAM,KAAK,UAAU,OAAO,YAAY;AACxC,QAAI,CAAC,GAAI;AACT,UAAM,QAAe,EAAE,GAAG,IAAI,KAAK,OAAO,KAAK,WAAW,GAAG;AAC7D,SAAK,QAAQ,OAAO,KAAK,eAAe,KAAK,GAAG,GAAG,KAAK;AAAA,EAC1D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,OAAO,IAAY,OAAgB,cAAsD;AACvF,UAAM,KAAK,UAAU,OAAO,YAAY;AACxC,QAAI,CAAC,GAAI,QAAO;AAEhB,aAAS,IAAI,KAAK,WAAW,EAAE,GAAG,IAAI,KAAK,QAAQ,QAAQ,KAAK;AAC9D,YAAM,IAAI,KAAK,QAAQ,CAAC;AACxB,UAAI,YAAY,GAAG,EAAE,MAAM,EAAG;AAC9B,UAAI,EAAE,OAAO,IAAI;AACf,aAAK,QAAQ,OAAO,GAAG,CAAC;AACxB,eAAO,EAAE;AAAA,MACX;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,WAAW,WAAqC;AAC9C,QAAI,cAAc,MAAO,QAAO,KAAK,QAAQ,IAAI,OAAK,EAAE,EAAE;AAC1D,UAAM,MAAgB,CAAC;AACvB,QAAI,MAAM,KAAK,QAAQ;AACvB,WAAO,MAAM,GAAG;AACd,UAAI,QAAQ,MAAM;AAClB,aAAO,QAAQ,KAAK,YAAY,KAAK,QAAQ,QAAQ,CAAC,GAAI,KAAK,QAAQ,MAAM,CAAC,CAAE,MAAM,EAAG;AACzF,eAAS,IAAI,OAAO,IAAI,KAAK,IAAK,KAAI,KAAK,KAAK,QAAQ,CAAC,EAAG,EAAE;AAC9D,YAAM;AAAA,IACR;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO,IAAmB,OAA6B;AACrD,QAAI,OAAO,aAAc,QAAO,KAAK,OAAO,KAAK;AACjD,QAAI,OAAO,WAAW;AACpB,UAAI,CAAC,MAAM,QAAQ,KAAK,KAAK,MAAM,WAAW,EAAG,QAAO,oBAAI,IAAI;AAChE,YAAMA,MAAK,UAAU,MAAM,CAAC,GAAG,MAAS;AACxC,YAAMC,MAAK,UAAU,MAAM,CAAC,GAAG,MAAS;AACxC,UAAI,CAACD,OAAM,CAACC,OAAMD,IAAG,SAASC,IAAG,KAAM,QAAO,oBAAI,IAAI;AACtD,aAAO,KAAK,MAAM,KAAK,WAAWD,GAAE,GAAG,KAAK,WAAWC,GAAE,CAAC;AAAA,IAC5D;AACA,UAAM,QAAQ,UAAU,OAAO,MAAS;AACxC,QAAI,CAAC,MAAO,QAAO,oBAAI,IAAI;AAC3B,UAAM,KAAK,KAAK,WAAW,KAAK;AAChC,UAAM,KAAK,KAAK,WAAW,KAAK;AAEhC,UAAM,CAAC,WAAW,OAAO,IAAI,KAAK,WAAW,MAAM,IAAI;AACvD,YAAQ,IAAI;AAAA,MACV,KAAK;AACH,eAAO,KAAK,MAAM,WAAW,EAAE;AAAA,MACjC,KAAK;AACH,eAAO,KAAK,MAAM,WAAW,EAAE;AAAA,MACjC,KAAK;AACH,eAAO,KAAK,MAAM,IAAI,OAAO;AAAA,MAC/B,KAAK;AACH,eAAO,KAAK,MAAM,IAAI,OAAO;AAAA,MAC/B,SAAS;AACP,cAAM,cAAqB;AAC3B,aAAK;AACL,eAAO,oBAAI,IAAI;AAAA,MACjB;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,OAAO,OAA6B;AAC1C,QAAI,OAAO,UAAU,SAAU,QAAO,oBAAI,IAAI;AAC9C,UAAM,MAAM,oBAAI,IAAY;AAC5B,UAAM,OAAO,KAAK,WAAW,EAAE,MAAM,aAAa,KAAK,MAAM,CAAC;AAC9D,aAAS,IAAI,MAAM,IAAI,KAAK,QAAQ,QAAQ,KAAK;AAC/C,YAAM,IAAI,KAAK,QAAQ,CAAC;AACxB,UAAI,EAAE,SAAS,YAAa;AAC5B,UAAI,CAAE,EAAE,IAAe,WAAW,KAAK,EAAG;AAC1C,UAAI,IAAI,EAAE,EAAE;AAAA,IACd;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,MAAM,MAAc,IAAyB;AACnD,UAAM,MAAM,oBAAI,IAAY;AAC5B,aAAS,IAAI,MAAM,IAAI,IAAI,IAAK,KAAI,IAAI,KAAK,QAAQ,CAAC,EAAG,EAAE;AAC3D,WAAO;AAAA,EACT;AAAA;AAAA,EAGQ,WAAW,MAAiC;AAClD,WAAO,CAAC,KAAK,aAAa,OAAK,IAAI,IAAI,GAAG,KAAK,aAAa,OAAK,KAAK,IAAI,CAAC;AAAA,EAC7E;AAAA,EAEQ,aAAa,QAAyC;AAC5D,QAAI,KAAK;AACT,QAAI,KAAK,KAAK,QAAQ;AACtB,WAAO,KAAK,IAAI;AACd,YAAM,MAAO,KAAK,OAAQ;AAC1B,UAAI,OAAO,KAAK,QAAQ,GAAG,EAAG,IAAI,EAAG,MAAK,MAAM;AAAA,UAC3C,MAAK;AAAA,IACZ;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAGQ,WAAW,OAAwB;AACzC,QAAI,KAAK;AACT,QAAI,KAAK,KAAK,QAAQ;AACtB,WAAO,KAAK,IAAI;AACd,YAAM,MAAO,KAAK,OAAQ;AAC1B,UAAI,YAAY,KAAK,QAAQ,GAAG,GAAI,KAAK,IAAI,EAAG,MAAK,MAAM;AAAA,UACtD,MAAK;AAAA,IACZ;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAGQ,WAAW,OAAwB;AACzC,QAAI,KAAK;AACT,QAAI,KAAK,KAAK,QAAQ;AACtB,WAAO,KAAK,IAAI;AACd,YAAM,MAAO,KAAK,OAAQ;AAC1B,UAAI,YAAY,KAAK,QAAQ,GAAG,GAAI,KAAK,KAAK,EAAG,MAAK,MAAM;AAAA,UACvD,MAAK;AAAA,IACZ;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,aAAkC;AAChC,WAAO;AAAA,MACL,GAAG;AAAA,MACH,GAAG;AAAA,MACH,OAAO,KAAK;AAAA,MACZ,SAAS,KAAK;AAAA,MACd,SAAS,KAAK,QAAQ,IAAI,OAAK,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,CAAoB;AAAA,IAChF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,aAAa,MAA0B,QAA0C;AAC/E,QAAI,KAAK,MAAM,YAAY,KAAK,UAAU,KAAK,MAAO,QAAO;AAC7D,UAAM,SAAkB,CAAC;AACzB,eAAW,CAAC,MAAM,KAAK,KAAK,EAAE,KAAK,KAAK,SAAS;AAC/C,UAAI,CAAC,OAAO,EAAE,EAAG,QAAO;AACxB,aAAO,KAAK,EAAE,MAAuB,KAAK,KAAK,GAAG,CAAC;AAAA,IACrD;AACA,SAAK,QAAQ,SAAS;AACtB,eAAW,KAAK,OAAQ,MAAK,QAAQ,KAAK,CAAC;AAC3C,SAAK,UAAU,KAAK;AACpB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,eAAe,OAAsB;AAC3C,QAAI,IAAI,KAAK,WAAW,KAAK;AAC7B,WAAO,IAAI,KAAK,YAAY,KAAK,QAAQ,IAAI,CAAC,GAAI,KAAK,MAAM,KAAK,KAAK,QAAQ,IAAI,CAAC,EAAG,MAAM,MAAM,KAAK;AACtG;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACF;AAGO,SAAS,iBACd,KACA,SACA,cACM;AACN,MAAI,MAAM;AACV,aAAW,EAAE,IAAI,OAAO,KAAK,SAAS;AACpC,UAAM,QAAQ,SAAS,QAAQ,IAAI,KAAK;AACxC,QAAI,UAAU,QAAQ,UAAU,OAAW;AAC3C,QAAI,IAAI,IAAI,OAAO,eAAe,IAAI,OAAO,KAAK,CAAC;AAAA,EACrD;AACF;;;AC1OO,IAAM,gBAAN,MAAoB;AAAA,EAIzB,YAAqB,QAA2B;AAA3B;AAAA,EAA4B;AAAA,EAA5B;AAAA,EAHJ,UAA2B,CAAC;AAAA,EACrC,UAAU;AAAA,EAIlB,IAAI,OAAe;AACjB,WAAO,KAAK,QAAQ;AAAA,EACtB;AAAA,EAEA,QAAc;AACZ,SAAK,QAAQ,SAAS;AACtB,SAAK,UAAU;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,IAAI,IAAY,MAAsC,KAAoB;AACxE,QAAI,CAAC,KAAM;AACX,UAAM,QAAuB,EAAE,MAAM,KAAK,OAAO,KAAK,WAAW,GAAG;AACpE,SAAK,QAAQ,OAAO,KAAK,eAAe,KAAK,GAAG,GAAG,KAAK;AAAA,EAC1D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAO,IAAY,MAA0D;AAC3E,QAAI,CAAC,KAAM,QAAO;AAClB,UAAM,CAAC,MAAM,EAAE,IAAI,KAAK,IAAI,MAAM,KAAK,MAAM;AAC7C,aAAS,IAAI,MAAM,IAAI,IAAI,KAAK;AAC9B,UAAI,KAAK,QAAQ,CAAC,EAAG,OAAO,IAAI;AAC9B,cAAM,CAAC,IAAI,IAAI,KAAK,QAAQ,OAAO,GAAG,CAAC;AACvC,eAAO,KAAM;AAAA,MACf;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,OAAO,QAA4B,OAAyC;AAC1E,UAAM,CAAC,MAAM,EAAE,IAAI,KAAK,IAAI,QAAQ,OAAO,MAAM;AACjD,QAAI,CAAC,MAAO,QAAO,KAAK,MAAM,MAAM,EAAE;AACtC,UAAM,IAAI,OAAO;AACjB,QAAI,KAAK,KAAK,OAAO,OAAQ,QAAO,oBAAI,IAAI;AAE5C,QAAI,MAAM,OAAO,cAAc;AAC7B,UAAI,OAAO,MAAM,UAAU,SAAU,QAAO,oBAAI,IAAI;AACpD,YAAM,MAAM,oBAAI,IAAY;AAC5B,YAAM,QAAQ,KAAK,WAAW,CAAC,GAAG,QAAQ,EAAE,MAAM,aAAa,KAAK,MAAM,MAAM,CAAC,GAAG,IAAI,GAAG,MAAM,EAAE;AACnG,eAAS,IAAI,OAAO,IAAI,IAAI,KAAK;AAC/B,cAAM,MAAM,KAAK,QAAQ,CAAC,EAAG,KAAK,CAAC;AACnC,YAAI,IAAI,SAAS,YAAa;AAC9B,YAAI,CAAE,IAAI,IAAe,WAAW,MAAM,KAAK,EAAG;AAClD,YAAI,IAAI,KAAK,QAAQ,CAAC,EAAG,EAAE;AAAA,MAC7B;AACA,aAAO;AAAA,IACT;AAEA,QAAI,MAAM,OAAO,WAAW;AAC1B,UAAI,CAAC,MAAM,QAAQ,MAAM,KAAK,KAAK,MAAM,MAAM,WAAW,EAAG,QAAO,oBAAI,IAAI;AAC5E,YAAMC,MAAK,UAAU,MAAM,MAAM,CAAC,GAAG,MAAS;AAC9C,YAAMC,MAAK,UAAU,MAAM,MAAM,CAAC,GAAG,MAAS;AAC9C,UAAI,CAACD,OAAM,CAACC,OAAMD,IAAG,SAASC,IAAG,KAAM,QAAO,oBAAI,IAAI;AACtD,aAAO,KAAK;AAAA,QACV,KAAK,WAAW,CAAC,GAAG,QAAQD,GAAE,GAAG,IAAI,GAAG,MAAM,EAAE;AAAA,QAChD,KAAK,WAAW,CAAC,GAAG,QAAQC,GAAE,GAAG,IAAI,GAAG,MAAM,EAAE;AAAA,MAClD;AAAA,IACF;AAEA,UAAM,QAAQ,UAAU,MAAM,OAAO,MAAS;AAC9C,QAAI,CAAC,MAAO,QAAO,oBAAI,IAAI;AAG3B,UAAM,CAAC,WAAW,OAAO,IAAI,KAAK,QAAQ,MAAM,IAAI,GAAG,MAAM,IAAI;AACjE,UAAM,KAAK,KAAK,WAAW,CAAC,GAAG,QAAQ,KAAK,GAAG,IAAI,GAAG,MAAM,EAAE;AAC9D,UAAM,KAAK,KAAK,WAAW,CAAC,GAAG,QAAQ,KAAK,GAAG,IAAI,GAAG,MAAM,EAAE;AAC9D,YAAQ,MAAM,IAAI;AAAA,MAChB,KAAK;AACH,eAAO,KAAK,MAAM,WAAW,EAAE;AAAA,MACjC,KAAK;AACH,eAAO,KAAK,MAAM,WAAW,EAAE;AAAA,MACjC,KAAK;AACH,eAAO,KAAK,MAAM,IAAI,OAAO;AAAA,MAC/B,KAAK;AACH,eAAO,KAAK,MAAM,IAAI,OAAO;AAAA,MAC/B,SAAS;AACP,cAAM,cAAqB,MAAM;AACjC,aAAK;AACL,eAAO,oBAAI,IAAI;AAAA,MACjB;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,WAAW,QAA4B,WAAqC;AAC1E,UAAM,CAAC,MAAM,EAAE,IAAI,KAAK,IAAI,QAAQ,OAAO,MAAM;AACjD,UAAM,MAAgB,CAAC;AACvB,QAAI,cAAc,OAAO;AACvB,eAAS,IAAI,MAAM,IAAI,IAAI,IAAK,KAAI,KAAK,KAAK,QAAQ,CAAC,EAAG,EAAE;AAC5D,aAAO;AAAA,IACT;AACA,QAAI,MAAM;AACV,WAAO,MAAM,MAAM;AACjB,UAAI,QAAQ,MAAM;AAClB,aAAO,QAAQ,QAAQ,KAAK,QAAQ,KAAK,QAAQ,QAAQ,CAAC,GAAI,KAAK,QAAQ,MAAM,CAAC,EAAG,MAAM,KAAK,OAAO,MAAM,MAAM,GAAG;AACpH;AAAA,MACF;AACA,eAAS,IAAI,OAAO,IAAI,KAAK,IAAK,KAAI,KAAK,KAAK,QAAQ,CAAC,EAAG,EAAE;AAC9D,YAAM;AAAA,IACR;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,MAAM,MAAc,IAAyB;AACnD,UAAM,MAAM,oBAAI,IAAY;AAC5B,aAAS,IAAI,MAAM,IAAI,IAAI,IAAK,KAAI,IAAI,KAAK,QAAQ,CAAC,EAAG,EAAE;AAC3D,WAAO;AAAA,EACT;AAAA;AAAA,EAGQ,IAAI,OAA2B,MAAgC;AACrE,WAAO;AAAA,MACL,KAAK,WAAW,OAAO,MAAM,GAAG,KAAK,QAAQ,MAAM;AAAA,MACnD,KAAK,WAAW,OAAO,MAAM,GAAG,KAAK,QAAQ,MAAM;AAAA,IACrD;AAAA,EACF;AAAA;AAAA,EAGQ,QAAQ,MAAc,IAAY,GAAW,MAAgC;AACnF,WAAO;AAAA,MACL,KAAK,aAAa,MAAM,IAAI,GAAG,OAAK,IAAI,IAAI;AAAA,MAC5C,KAAK,aAAa,MAAM,IAAI,GAAG,OAAK,KAAK,IAAI;AAAA,IAC/C;AAAA,EACF;AAAA,EAEQ,aAAa,MAAc,IAAY,GAAW,QAA2C;AACnG,QAAI,KAAK;AACT,QAAI,KAAK;AACT,WAAO,KAAK,IAAI;AACd,YAAM,MAAO,KAAK,OAAQ;AAC1B,UAAI,OAAO,KAAK,QAAQ,GAAG,EAAG,KAAK,CAAC,EAAG,IAAI,EAAG,MAAK,MAAM;AAAA,UACpD,MAAK;AAAA,IACZ;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAGQ,WAAW,OAA2B,MAAc,MAAc,IAAoB;AAC5F,QAAI,KAAK;AACT,QAAI,KAAK;AACT,WAAO,KAAK,IAAI;AACd,YAAM,MAAO,KAAK,OAAQ;AAC1B,UAAI,KAAK,QAAQ,KAAK,QAAQ,GAAG,GAAI,OAAO,IAAI,IAAI,EAAG,MAAK,MAAM;AAAA,UAC7D,MAAK;AAAA,IACZ;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAGQ,WAAW,OAA2B,MAAc,MAAc,IAAoB;AAC5F,QAAI,KAAK;AACT,QAAI,KAAK;AACT,WAAO,KAAK,IAAI;AACd,YAAM,MAAO,KAAK,OAAQ;AAC1B,UAAI,KAAK,QAAQ,KAAK,QAAQ,GAAG,GAAI,OAAO,IAAI,KAAK,EAAG,MAAK,MAAM;AAAA,UAC9D,MAAK;AAAA,IACZ;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,aAAoC;AAClC,WAAO;AAAA,MACL,GAAG;AAAA,MACH,GAAG;AAAA,MACH,QAAQ,CAAC,GAAG,KAAK,MAAM;AAAA,MACvB,SAAS,KAAK;AAAA,MACd,SAAS,KAAK,QAAQ;AAAA,QACpB,OAAK,CAAC,EAAE,KAAK,IAAI,OAAK,CAAC,EAAE,MAAM,EAAE,GAAG,CAAY,GAAG,EAAE,KAAK,EAAE,EAAE;AAAA,MAChE;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,aAAa,MAA0B,QAA0C;AAC/E,QAAI,KAAK,MAAM,WAAY,QAAO;AAClC,QAAI,KAAK,OAAO,WAAW,KAAK,OAAO,OAAQ,QAAO;AACtD,aAAS,IAAI,GAAG,IAAI,KAAK,OAAO,QAAQ,IAAK,KAAI,KAAK,OAAO,CAAC,MAAM,KAAK,OAAO,CAAC,EAAG,QAAO;AAC3F,UAAM,SAA0B,CAAC;AACjC,eAAW,CAAC,MAAM,KAAK,EAAE,KAAK,KAAK,SAAS;AAC1C,UAAI,CAAC,OAAO,EAAE,EAAG,QAAO;AACxB,aAAO,KAAK,EAAE,MAAM,KAAK,IAAI,QAAM,EAAE,MAAM,EAAE,CAAC,GAAsB,KAAK,EAAE,CAAC,EAAE,EAAE,GAAG,KAAK,GAAG,CAAC;AAAA,IAC9F;AACA,SAAK,QAAQ,SAAS;AACtB,eAAW,KAAK,OAAQ,MAAK,QAAQ,KAAK,CAAC;AAC3C,SAAK,UAAU,KAAK;AACpB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,eAAe,OAA8B;AACnD,UAAM,KAAK,KAAK,WAAW,MAAM,MAAM,KAAK,OAAO,QAAQ,GAAG,KAAK,QAAQ,MAAM;AACjF,QAAI,IAAI;AACR,WAAO,IAAI,KAAK,KAAK,QAAQ,KAAK,QAAQ,IAAI,CAAC,GAAI,MAAM,MAAM,KAAK,OAAO,MAAM,MAAM,KAClF,KAAK,QAAQ,IAAI,CAAC,EAAG,MAAM,MAAM,KAAK;AACzC;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,QAAQ,OAAsB,OAA2B,MAAsB;AACrF,aAAS,IAAI,GAAG,IAAI,MAAM,KAAK;AAC7B,YAAM,IAAI,YAAY,MAAM,KAAK,CAAC,GAAI,MAAM,CAAC,CAAE;AAC/C,UAAI,MAAM,EAAG,QAAO;AAAA,IACtB;AACA,WAAO;AAAA,EACT;AACF;AAQO,SAAS,WACd,QACA,QACA,cACuB;AACvB,QAAM,OAAkB,CAAC;AACzB,aAAW,SAAS,QAAQ;AAC1B,UAAM,QAAQ,SAAS,QAAQ,KAAK;AACpC,QAAI,UAAU,QAAQ,UAAU,OAAW,QAAO;AAClD,UAAM,MAAM,UAAU,OAAO,eAAe,OAAO,KAAK,CAAC;AACzD,QAAI,CAAC,IAAK,QAAO;AACjB,SAAK,KAAK,GAAG;AAAA,EACf;AACA,SAAO;AACT;AAGO,SAAS,YAAY,QAAmD;AAC7E,QAAM,OAAkB,CAAC;AACzB,aAAW,SAAS,QAAQ;AAC1B,UAAM,MAAM,UAAU,OAAO,MAAS;AACtC,QAAI,CAAC,IAAK,QAAO;AACjB,SAAK,KAAK,GAAG;AAAA,EACf;AACA,SAAO;AACT;AAGO,SAAS,mBACd,KACA,SACA,cACM;AACN,MAAI,MAAM;AACV,aAAW,EAAE,IAAI,OAAO,KAAK,SAAS;AACpC,QAAI,IAAI,IAAI,WAAW,IAAI,QAAQ,QAAQ,YAAY,CAAC;AAAA,EAC1D;AACF;AAGO,SAAS,YAAY,QAAmC;AAC7D,SAAO,OAAO,KAAK,IAAQ;AAC7B;;;AC1PO,SAAS,mBACd,MACkF;AAClF,SAAO,KAAK,IAAI,CAAC,QAAQ;AACvB,QAAI,OAAO,QAAQ,SAAU,QAAO,EAAE,QAAQ,CAAC,GAAG,EAAE;AACpD,QAAI,MAAM,QAAQ,GAAG,EAAG,QAAO,EAAE,QAAQ,IAAI;AAC7C,WAAO;AAAA,EACT,CAAC;AACH;AAyBO,IAAM,oBAAN,MAAwB;AAAA,EACZ,UAAU,oBAAI,IAAuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQrC,SAAS,oBAAI,IAAyB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQtC,WAAW,oBAAI,IAA2B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQ1C,cAAc,oBAAI,IAAyC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWpE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOR,iBAAiB,IAAiE;AAChF,SAAK,eAAe;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,QAAQ,OAAqB;AAC3B,QAAI,KAAK,QAAQ,IAAI,KAAK,EAAG;AAC7B,SAAK,QAAQ,IAAI,OAAO,EAAE,OAAO,SAAS,oBAAI,IAAI,EAAE,CAAC;AAAA,EACvD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,cAAc,OAAe,MAA6C;AACxE,QAAI,MAAM,KAAK,OAAO,IAAI,KAAK;AAC/B,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,YAAY,KAAK;AAC3B,WAAK,OAAO,IAAI,OAAO,GAAG;AAAA,IAC5B;AACA,QAAI,MAAM,QAAS,MAAK,YAAY,IAAI,eAAe,KAAK,GAAG,GAAG;AAAA,EACpE;AAAA;AAAA,EAGA,UAAU,OAAwB;AAChC,WAAO,KAAK,OAAO,IAAI,KAAK;AAAA,EAC9B;AAAA;AAAA,EAGA,eAAyB;AACvB,WAAO,CAAC,GAAG,KAAK,OAAO,KAAK,CAAC;AAAA,EAC/B;AAAA;AAAA,EAGA,WAAW,OAAuB;AAChC,WAAO,KAAK,OAAO,IAAI,KAAK,GAAG,QAAQ;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,YAAY,OAAe,IAAmB,OAA4C;AACxF,WAAO,KAAK,OAAO,IAAI,KAAK,GAAG,OAAO,IAAI,KAAK,KAAK;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,WAAW,OAAe,WAAqD;AAC7E,WAAO,KAAK,OAAO,IAAI,KAAK,GAAG,WAAW,SAAS,KAAK;AAAA,EAC1D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,gBAAgB,QAA2B,MAA6C;AACtF,QAAI,OAAO,SAAS,EAAG;AACvB,UAAM,MAAM,YAAY,MAAM;AAC9B,QAAI,MAAM,KAAK,SAAS,IAAI,GAAG;AAC/B,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,cAAc,CAAC,GAAG,MAAM,CAAC;AACnC,WAAK,SAAS,IAAI,KAAK,GAAG;AAAA,IAC5B;AACA,QAAI,MAAM,QAAS,MAAK,YAAY,IAAI,iBAAiB,MAAM,GAAG,GAAG;AAAA,EACvE;AAAA;AAAA,EAGA,iBAAmD;AACjD,WAAO,CAAC,GAAG,KAAK,SAAS,OAAO,CAAC,EAAE,IAAI,SAAO,IAAI,MAAM;AAAA,EAC1D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,aAAa,QAAmC;AAC9C,WAAO,KAAK,SAAS,IAAI,YAAY,MAAM,CAAC,GAAG,QAAQ;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,eACE,QACA,cACA,OAC4B;AAC5B,UAAM,MAAM,KAAK,SAAS,IAAI,YAAY,MAAM,CAAC;AACjD,QAAI,CAAC,IAAK,QAAO;AACjB,UAAM,SAAS,YAAY,YAAY;AACvC,QAAI,CAAC,OAAQ,QAAO;AACpB,WAAO,IAAI,OAAO,QAAQ,KAAK;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,mBACE,QACA,cACA,WAC0B;AAC1B,UAAM,MAAM,KAAK,SAAS,IAAI,YAAY,MAAM,CAAC;AACjD,QAAI,CAAC,IAAK,QAAO;AACjB,UAAM,SAAS,YAAY,YAAY;AACvC,QAAI,CAAC,OAAQ,QAAO;AACpB,WAAO,IAAI,WAAW,QAAQ,SAAS;AAAA,EACzC;AAAA;AAAA,EAGA,IAAI,OAAwB;AAC1B,WAAO,KAAK,QAAQ,IAAI,KAAK;AAAA,EAC/B;AAAA;AAAA,EAGA,SAAmB;AACjB,WAAO,CAAC,GAAG,KAAK,QAAQ,KAAK,CAAC;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAS,SAAmD,OAA4B,YAAkB;AACxG,eAAW,OAAO,KAAK,QAAQ,OAAO,GAAG;AACvC,UAAI,QAAQ,MAAM;AAClB,iBAAW,EAAE,IAAI,OAAO,KAAK,SAAS;AACpC,mBAAW,KAAK,IAAI,QAAQ,KAAK,YAAY;AAAA,MAC/C;AAAA,IACF;AAIA,eAAW,CAAC,OAAO,GAAG,KAAK,KAAK,QAAQ;AACtC,UAAI,KAAK,IAAI,eAAe,KAAK,CAAC,EAAG;AACrC,uBAAiB,KAAK,SAAS,KAAK,YAAY;AAAA,IAClD;AACA,eAAW,OAAO,KAAK,SAAS,OAAO,GAAG;AACxC,UAAI,KAAK,IAAI,iBAAiB,IAAI,MAAM,CAAC,EAAG;AAC5C,yBAAmB,KAAK,SAAS,KAAK,YAAY;AAAA,IACpD;AAAA,EACF;AAAA;AAAA,EAGA,kBAAqC;AACnC,WAAO,CAAC,GAAG,KAAK,YAAY,KAAK,CAAC;AAAA,EACpC;AAAA;AAAA,EAGA,cAAc,KAA6C;AACzD,WAAO,KAAK,YAAY,IAAI,GAAG,GAAG,WAAW;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,aAAa,KAAa,MAA0B,QAA0C;AAC5F,WAAO,KAAK,YAAY,IAAI,GAAG,GAAG,aAAa,MAAM,MAAM,KAAK;AAAA,EAClE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAU,IAAY,WAAc,gBAAgC;AAClE,QAAI,KAAK,QAAQ,SAAS,KAAK,KAAK,OAAO,SAAS,KAAK,KAAK,SAAS,SAAS,EAAG;AAOnF,UAAM,QAAQ,oBAAI,IAAgC;AAClD,UAAM,cAAc,oBAAI,IAAgC;AACxD,QAAI,mBAAmB,MAAM;AAC3B,iBAAW,CAAC,KAAK,GAAG,KAAK,KAAK,UAAU;AACtC,cAAM,IAAI,KAAK,IAAI,OAAO,IAAI,WAAW,IAAI,QAAQ,gBAAgB,KAAK,YAAY,CAAC,CAAC;AAAA,MAC1F;AAGA,iBAAW,CAAC,KAAK,GAAG,KAAK,KAAK,QAAQ;AACpC,cAAM,QAAQ,SAAS,gBAAgB,IAAI,KAAK;AAChD,YAAI,UAAU,QAAQ,UAAU,OAAW;AAC3C,oBAAY,IAAI,KAAK,IAAI,OAAO,IAAI,OAAO,KAAK,eAAe,IAAI,OAAO,KAAK,CAAC,CAAC;AAAA,MACnF;AACA,WAAK,OAAO,IAAI,cAAc;AAAA,IAChC;AACA,eAAW,OAAO,KAAK,QAAQ,OAAO,GAAG;AACvC,iBAAW,KAAK,IAAI,WAAW,KAAK,YAAY;AAAA,IAClD;AACA,eAAW,CAAC,KAAK,GAAG,KAAK,KAAK,QAAQ;AACpC,YAAM,QAAQ,SAAS,WAAW,IAAI,KAAK;AAC3C,UAAI,UAAU,QAAQ,UAAU,OAAW;AAC3C,UAAI,IAAI,IAAI,OAAO,KAAK,eAAe,IAAI,OAAO,KAAK,GAAG,YAAY,IAAI,GAAG,CAAC;AAAA,IAChF;AACA,eAAW,CAAC,KAAK,GAAG,KAAK,KAAK,UAAU;AACtC,UAAI,IAAI,IAAI,WAAW,IAAI,QAAQ,WAAW,KAAK,YAAY,GAAG,MAAM,IAAI,GAAG,CAAC;AAAA,IAClF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAU,IAAY,QAAiB;AACrC,QAAI,KAAK,QAAQ,SAAS,KAAK,KAAK,OAAO,SAAS,KAAK,KAAK,SAAS,SAAS,EAAG;AACnF,eAAW,OAAO,KAAK,QAAQ,OAAO,GAAG;AACvC,sBAAgB,KAAK,IAAI,QAAQ,KAAK,YAAY;AAAA,IACpD;AACA,eAAW,OAAO,KAAK,OAAO,OAAO,GAAG;AACtC,YAAM,QAAQ,SAAS,QAAQ,IAAI,KAAK;AACxC,UAAI,UAAU,QAAQ,UAAU,OAAW;AAC3C,UAAI,OAAO,IAAI,OAAO,KAAK,eAAe,IAAI,OAAO,KAAK,CAAC;AAAA,IAC7D;AACA,eAAW,OAAO,KAAK,SAAS,OAAO,GAAG;AACxC,UAAI,OAAO,IAAI,WAAW,IAAI,QAAQ,QAAQ,KAAK,YAAY,CAAC;AAAA,IAClE;AAAA,EACF;AAAA;AAAA,EAGA,QAAc;AACZ,eAAW,OAAO,KAAK,QAAQ,OAAO,GAAG;AACvC,UAAI,QAAQ,MAAM;AAAA,IACpB;AACA,eAAW,OAAO,KAAK,OAAO,OAAO,GAAG;AACtC,UAAI,MAAM;AAAA,IACZ;AACA,eAAW,OAAO,KAAK,SAAS,OAAO,GAAG;AACxC,UAAI,MAAM;AAAA,IACZ;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,YAAY,OAAe,OAA4C;AACrE,UAAM,MAAM,KAAK,QAAQ,IAAI,KAAK;AAClC,QAAI,CAAC,IAAK,QAAO;AACjB,QAAI,CAAC,qBAAqB,KAAK,EAAG,QAAO;AACzC,UAAM,MAAM,aAAa,KAAK;AAC9B,WAAO,IAAI,QAAQ,IAAI,GAAG,KAAK;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,SAAS,OAAe,QAAwD;AAC9E,UAAM,MAAM,KAAK,QAAQ,IAAI,KAAK;AAClC,QAAI,CAAC,IAAK,QAAO;AACjB,QAAI,CAAC,OAAO,MAAM,oBAAoB,EAAG,QAAO;AAChD,UAAM,MAAM,oBAAI,IAAY;AAC5B,eAAW,SAAS,QAAQ;AAC1B,YAAM,MAAM,aAAa,KAAK;AAC9B,YAAM,SAAS,IAAI,QAAQ,IAAI,GAAG;AAClC,UAAI,QAAQ;AACV,mBAAW,MAAM,OAAQ,KAAI,IAAI,EAAE;AAAA,MACrC;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmBA,sBAAsB,OAAyC;AAC7D,UAAM,MAAM,KAAK,QAAQ,IAAI,KAAK;AAClC,QAAI,CAAC,IAAK,QAAO;AACjB,UAAM,MAAgB,CAAC;AACvB,eAAW,UAAU,IAAI,QAAQ,OAAO,GAAG;AACzC,iBAAW,MAAM,QAAQ;AACvB,YAAI,KAAK,EAAE;AACX;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACF;AAEA,IAAM,YAAiC,oBAAI,IAAI;AAC/C,IAAM,aAAkC,oBAAI,IAAI;AAWhD,IAAM,eAAe;AAErB,SAAS,WACP,KACA,IACA,QACA,cACM;AACN,QAAM,QAAQ,SAAS,QAAQ,IAAI,KAAK;AACxC,MAAI,UAAU,QAAQ,UAAU,OAAW;AAC3C,QAAM,MAAM,eAAe,IAAI,OAAO,KAAK,KAAK,aAAa,KAAK;AAClE,MAAI,SAAS,IAAI,QAAQ,IAAI,GAAG;AAChC,MAAI,CAAC,QAAQ;AACX,aAAS,oBAAI,IAAI;AACjB,QAAI,QAAQ,IAAI,KAAK,MAAM;AAAA,EAC7B;AACA,SAAO,IAAI,EAAE;AACf;AAEA,SAAS,gBACP,KACA,IACA,QACA,cACM;AACN,QAAM,QAAQ,SAAS,QAAQ,IAAI,KAAK;AACxC,MAAI,UAAU,QAAQ,UAAU,OAAW;AAC3C,QAAM,MAAM,eAAe,IAAI,OAAO,KAAK,KAAK,aAAa,KAAK;AAClE,QAAM,SAAS,IAAI,QAAQ,IAAI,GAAG;AAClC,MAAI,CAAC,OAAQ;AACb,SAAO,OAAO,EAAE;AAEhB,MAAI,OAAO,SAAS,EAAG,KAAI,QAAQ,OAAO,GAAG;AAC/C;","names":["lo","hi","lo","hi"]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  NoydbError
3
- } from "./chunk-37EPTBBR.js";
3
+ } from "./chunk-IKPQ2GGB.js";
4
4
 
5
5
  // src/capsule/contract.ts
6
6
  function assertCapsuleSupports(caps, group, requirer) {
@@ -24,4 +24,4 @@ export {
24
24
  assertCapsuleSupports,
25
25
  CapsuleNotSupportedError
26
26
  };
27
- //# sourceMappingURL=chunk-OIEO4WDL.js.map
27
+ //# sourceMappingURL=chunk-ZD7WFMV2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/capsule/contract.ts"],"sourcesContent":["/**\n * The capsule seam (capsule seam spec, Section 2).\n *\n * A capsule is hub's crypto interior behind one contract. `enclave-aes` is the\n * default and ships INSIDE hub, so `npm install @noy-db/hub` alone is a working\n * noy-db. An alternative binds at BUILD TIME through hub's `imports` map —\n * deliberately not at runtime: a `createNoydb({ capsule })` option would be a\n * hot-swap surface, and a build condition lives in build config where the\n * shipped bundle stays auditable (`npm ls` tells an auditor whether a build is\n * plaintext-at-rest).\n *\n * ⛔ `CapsuleKey` is OPAQUE outside `capsule/`. Never construct, inspect or\n * serialise one; only pass it between contract functions. A fork may define it\n * as something that is not a `CryptoKey` at all — hardware-backed,\n * post-quantum, or null for a capsule that does no encryption.\n */\nimport { NoydbError } from '../kernel/errors.js'\nimport type { VdigFieldPolicy } from '../kernel/types.js'\n\n/** Opaque key at the capsule seam. `CryptoKey` in the reference capsule. */\nexport type CapsuleKey = CryptoKey\n\n/** Opaque asymmetric pair at the capsule seam. */\nexport type CapsuleKeyPair = CryptoKeyPair\n\n/**\n * The groups a capsule may support. A capsule declares its set via\n * `capabilities()`; a service needing a group asserts at `createNoydb()`.\n *\n * `authenticate` and `seal` are what an `enclave-*` MUST support and an\n * `exclave-*` MUST refuse. That prefix rule is asserted by the conformance\n * suite from the package name, which is what makes the prefix a trust posture\n * rather than a naming convention.\n */\nexport type CapsuleGroup =\n | 'authenticate'\n | 'seal'\n | 'cipher'\n | 'digest'\n | 'sign'\n | 'codec'\n | 'sealing'\n | 'deterministic'\n | 'classify'\n // ⭐ ADDED 2026-09-16 (core#42). `wrapCek` / `unwrapCek` are real primitives\n // a capsule may refuse independently, and the conformance kit has carried a\n // live refusal test for them under this name since it shipped — but no\n // member of this union covered them, so the refusal could not be NAMED.\n // Found when `EnclaveNotSupportedError` turned out to accept it while this\n // union did not: three vocabularies disagreed, and this one was the one\n // missing a group rather than the error inventing one.\n | 'per-record-keys'\n\n/**\n * Thrown at `createNoydb()` when a service needs a group the bound capsule\n * does not support.\n *\n * ⚠️ Never thrown on first write, and never discovered by try/catch probing: a\n * consumer learns at startup or not at all. A capability discovered mid-write\n * is a half-built vault.\n */\n/**\n * Refuse at CONSTRUCTION when a service needs a capsule group the bound\n * capsule lacks.\n *\n * ⛔ At startup or not at all. A capability discovered on first write is a\n * half-built vault: some records sealed, a service silently inert, and a\n * consumer who cannot tell a missing capability from a bug. `capabilities()`\n * is a set, so this is a membership test — never a try/catch probe against the\n * primitive itself, which would make \"unsupported\" and \"broken\" the same\n * observation.\n *\n * Lives on the CONTRACT, not in the kernel: it depends on nothing but the\n * declared set, and every capsule's consumers need the same assertion.\n *\n * ⚠️ Per-service wiring is deliberately NOT done yet. `enclave-aes` supports\n * every group, so every call site would be unreachable code behind an\n * untestable branch. It lands in Stage C with `exclave-plain`, which is the\n * first capsule that refuses anything. Until then this is exercised against a\n * stub set — see `__tests__/capsule-capabilities.test.ts`.\n */\nexport function assertCapsuleSupports(\n caps: ReadonlySet<CapsuleGroup>,\n group: CapsuleGroup,\n requirer: string,\n): void {\n if (!caps.has(group)) throw new CapsuleNotSupportedError(group, requirer)\n}\n\nexport class CapsuleNotSupportedError extends NoydbError {\n constructor(readonly group: CapsuleGroup, readonly requirer: string) {\n super(\n 'CAPSULE_NOT_SUPPORTED',\n `Capsule does not support the \"${group}\" group, which \"${requirer}\" requires. ` +\n `An exclave capsule refuses \"authenticate\" and \"seal\" by design — services ` +\n `that need them cannot be used with it. Check capabilities().`,\n )\n this.name = 'CapsuleNotSupportedError'\n }\n}\n\n/**\n * The 13 cipher primitives the shared plumbing needs — the ENTIRE surface a\n * capsule must actually implement.\n *\n * ⭐ This is the measurement that shaped Stage C. `enclave-aes` is ~4,200\n * lines, but only ~1,200 of them touch `crypto.subtle`; the other ~3,000 are\n * envelope assembly, record-identity AAD, tombstones and the record codec —\n * plumbing that is IDENTICAL for every capsule because it encodes hub's\n * envelope format, not anyone's cipher. `makeCapsule()` binds that plumbing to\n * these primitives, so a second capsule writes ~400 lines instead of ~3,400\n * and the format lives in exactly one place.\n *\n * The alternative — copying the plumbing into each capsule — was rejected for\n * a specific reason: nothing would fail when the two copies drifted. A change\n * to the tombstone shape or the AAD would have to be made twice, and the\n * second miss surfaces as an envelope that one capsule writes and the other\n * cannot read.\n *\n * ⚠️ Declared with PROPERTY syntax (`encrypt: (…) => …`), never method\n * shorthand. Two reasons, both measured. TypeScript checks method shorthand\n * BIVARIANTLY, so a capsule whose `encrypt` took the wrong number of arguments\n * would satisfy a shorthand declaration and fail only at a call site — the\n * exact hole #16 fell through. And `@typescript-eslint/unbound-method` refuses\n * to let a shorthand method be destructured off the object, which is precisely\n * how the plumbing consumes these.\n *\n * ⚠️ Every primitive here is `async` except `bufferToBase64`, including ones a\n * plaintext capsule answers instantly. That is deliberate: a capsule that\n * needs real asynchrony (hardware-backed keys, a remote KMS) must be\n * expressible without changing this type, and a synchronous implementation\n * loses nothing by returning a resolved promise.\n */\nexport interface CapsulePrimitives<K = CapsuleKey> {\n encrypt: (plaintext: string, key: K, aad?: Uint8Array) => Promise<{ iv: string; data: string }>\n decrypt: (iv: string, data: string, key: K, aad?: Uint8Array) => Promise<string>\n encryptBytesWithAAD: (bytes: Uint8Array, key: K, aad: Uint8Array) => Promise<{ iv: string; data: string }>\n decryptBytesWithAAD: (iv: string, data: string, key: K, aad: Uint8Array) => Promise<Uint8Array>\n /** Same plaintext + key + context ⇒ same ciphertext. Refused by a capsule without the group. */\n encryptDeterministic: (plaintext: string, key: K, context: string) => Promise<{ iv: string; data: string }>\n /** ⚠️ ONE argument. The AES capsule derives the CONTEXT into the IV, not the key\n * (`encryptDeterministic` calls `deriveDeterministicIV(dek, context, plaintext)`),\n * so a `(dek, context)` signature here would have been a plausible-looking lie\n * that only the call sites caught. */\n deriveDeterministicKey: (dek: K) => Promise<K>\n deriveSealedFieldKey: (dek: K, collectionName: string, field: string) => Promise<K>\n deriveSealedFieldKeyFromCek: (cek: K, collectionName: string, field: string) => Promise<K>\n generateDEK: () => Promise<K>\n wrapCek: (cek: K, dek: K) => Promise<string>\n unwrapCek: (wrapped: string, dek: K) => Promise<K>\n /** Accepts `ArrayBuffer` too — the AES capsule's callers pass raw `subtle` output. */\n bufferToBase64: (buffer: ArrayBuffer | Uint8Array) => string\n\n // ─── optional group: classify ──────────────────────────────────────\n //\n // The record codec reaches into exactly two cipher-bound classify functions\n // (plus `normalizeForVerify`, which is pure and lives in the plumbing). They\n // sit here rather than in a separate object because the codec calls them the\n // same way it calls `encrypt` — and a capsule that refuses the `classify`\n // group implements them as a throw, which is the refusal the group means.\n mintVdigSlot: (\n value: string,\n policy: VdigFieldPolicy,\n prevBlob: string | undefined,\n cek: K,\n collection: string,\n id: string,\n field: string,\n ) => Promise<string>\n mintBidxTag: (normalized: string, dek: K, collection: string, field: string) => Promise<string>\n /** The vdig payload is sealed under a capsule-derived slot key, so open/seal\n * are the capsule's, not the plumbing's. `rotateRecordCek` needs both to\n * carry a classified slot across a key rotation. */\n openVdigPayload: (blob: string, cek: K, collection: string, id: string, field: string) => Promise<VdigPayload>\n sealVdigPayload: (payload: VdigPayload, cek: K, collection: string, id: string, field: string) => Promise<string>\n}\n\n/** The classified verify-digest payload, at the seam because both the capsule\n * and the plumbing name it. Structural, not the capsule's own type. */\nexport interface VdigDigestEntry {\n readonly salt: string\n readonly hash: string\n}\n\nexport interface VdigPayload {\n readonly v: 1\n readonly alg: 'PBKDF2-SHA256'\n readonly iter: number\n readonly cur: VdigDigestEntry & { readonly at: string }\n readonly ring?: readonly VdigDigestEntry[]\n}\n\n\n// ─── what an alternative capsule builds on ─────────────────────────\n//\n// `@noy-db/hub/capsule` is the subpath an out-of-tree capsule installs, so the\n// shared halves have to be reachable from it: `makeCapsule()` binds hub's\n// envelope plumbing to a cipher, and the `digest` group is identical for every\n// capsule by design. Without these, an alternative capsule would have to\n// re-implement ~3,400 lines it does not own — and drift from them silently.\nexport { makeCapsule } from './plumbing/index.js'\nexport type { Capsule, RecordCodec } from './plumbing/index.js'\nexport {\n sha256Hex,\n sha256Bytes,\n hmacSha256Hex,\n hmacSignHex,\n hkdfAesGcmKey,\n deriveBlobAddressKey,\n derivePresenceKey,\n derivePresenceTagKey,\n generateIV,\n generateSalt,\n generateRecoverySecret,\n bufferToBase64,\n base64ToBuffer,\n encodeEchoParts,\n KEY_BITS,\n} from './plumbing/digest.js'\nexport type { EchoSecretParts } from './plumbing/digest.js'\nexport {\n buildRecordAad,\n recordAadFor,\n buildRecordEnvelope,\n buildTombstone,\n isTombstone,\n isTombstoneShape,\n buildDeleteMarker,\n isDeleteMarker,\n requireSealedBody,\n sealedBodyArgs,\n envelopeBodySize,\n hasPerRecordKey,\n envelopeBodyForHash,\n hasSealedBody,\n normalizeForVerify,\n parseSealedSlot,\n} from './plumbing/index.js'\nexport type { RecordIdentity, RecordRef } from './plumbing/index.js'\nexport { buildSealedRecordEnvelope } from './plumbing/record-envelope.js'\nexport { generateSigningKeyPair, signBytes, verifyBytes } from './plumbing/sign.js'\nexport { ctEqualTags } from './plumbing/ct-equal.js'\nexport { evaluateKofN } from './plumbing/kofn.js'\n"],"mappings":";;;;;AAiFO,SAAS,sBACd,MACA,OACA,UACM;AACN,MAAI,CAAC,KAAK,IAAI,KAAK,EAAG,OAAM,IAAI,yBAAyB,OAAO,QAAQ;AAC1E;AAEO,IAAM,2BAAN,cAAuC,WAAW;AAAA,EACvD,YAAqB,OAA8B,UAAkB;AACnE;AAAA,MACE;AAAA,MACA,iCAAiC,KAAK,mBAAmB,QAAQ;AAAA,IAGnE;AANmB;AAA8B;AAOjD,SAAK,OAAO;AAAA,EACd;AAAA,EARqB;AAAA,EAA8B;AASrD;","names":[]}
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  normalizeForVerify
3
- } from "./chunk-QMWY2FDS.js";
3
+ } from "./chunk-THQ3BHLM.js";
4
4
  import {
5
5
  NOYDB_FORMAT_VERSION,
6
6
  SealedHandle
7
- } from "./chunk-SV2PM2OY.js";
7
+ } from "./chunk-XX4R7TUB.js";
8
8
  import {
9
9
  ClassifiedConfigError,
10
10
  DebugReservedFieldError,
@@ -12,7 +12,7 @@ import {
12
12
  RecordCekNotFoundError,
13
13
  SchemaValidationError,
14
14
  ValidationError
15
- } from "./chunk-37EPTBBR.js";
15
+ } from "./chunk-IKPQ2GGB.js";
16
16
 
17
17
  // src/capsule/plumbing/record-aad.ts
18
18
  var SCHEME = "noydb-aad/2";
@@ -1372,4 +1372,4 @@ export {
1372
1372
  makeCapsule,
1373
1373
  ctEqualTags
1374
1374
  };
1375
- //# sourceMappingURL=chunk-42ALPZ2B.js.map
1375
+ //# sourceMappingURL=chunk-ZF6JECDT.js.map