@noy-db/hub 0.2.0-pre.4 → 0.2.0-pre.5

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 (280) hide show
  1. package/dist/aggregate/index.cjs.map +1 -1
  2. package/dist/aggregate/index.js +4 -4
  3. package/dist/attestation/index.cjs.map +1 -1
  4. package/dist/attestation/index.d.cts +4 -4
  5. package/dist/attestation/index.d.ts +4 -4
  6. package/dist/attestation/index.js +6 -6
  7. package/dist/blobs/index.cjs.map +1 -1
  8. package/dist/blobs/index.d.cts +5 -5
  9. package/dist/blobs/index.d.ts +5 -5
  10. package/dist/blobs/index.js +5 -5
  11. package/dist/bundle/index.cjs +443 -338
  12. package/dist/bundle/index.cjs.map +1 -1
  13. package/dist/bundle/index.d.cts +17 -17
  14. package/dist/bundle/index.d.ts +17 -17
  15. package/dist/bundle/index.js +10 -10
  16. package/dist/bundle/index.js.map +1 -1
  17. package/dist/{chunk-YL2DR3HY.js → chunk-25WFLKOH.js} +2 -2
  18. package/dist/chunk-25WFLKOH.js.map +1 -0
  19. package/dist/{chunk-EMEX37ZN.js → chunk-2GMRNNI3.js} +3 -3
  20. package/dist/chunk-2GMRNNI3.js.map +1 -0
  21. package/dist/{chunk-NGSPBLLE.js → chunk-34XGYMQT.js} +3 -3
  22. package/dist/chunk-34XGYMQT.js.map +1 -0
  23. package/dist/{chunk-FXQYZNOW.js → chunk-5OVIFUQE.js} +1 -1
  24. package/dist/chunk-5OVIFUQE.js.map +1 -0
  25. package/dist/{chunk-P6256WTJ.js → chunk-5QPF2MJ5.js} +3 -3
  26. package/dist/chunk-5QPF2MJ5.js.map +1 -0
  27. package/dist/{chunk-5ZGZ6HIZ.js → chunk-5VMTAX4Y.js} +2 -2
  28. package/dist/{chunk-74JEQFMT.js → chunk-6A4AMQ2H.js} +5 -5
  29. package/dist/chunk-6A4AMQ2H.js.map +1 -0
  30. package/dist/{chunk-YDLAFP36.js → chunk-6HJ2ZALB.js} +1 -1
  31. package/dist/chunk-6HJ2ZALB.js.map +1 -0
  32. package/dist/{chunk-GDTCGIPX.js → chunk-7TX7HN42.js} +2 -2
  33. package/dist/chunk-7TX7HN42.js.map +1 -0
  34. package/dist/{chunk-EPK6A3WJ.js → chunk-A3JMGXPG.js} +2 -2
  35. package/dist/chunk-A3JMGXPG.js.map +1 -0
  36. package/dist/{chunk-75QDHSE4.js → chunk-A4JNVBPF.js} +5 -5
  37. package/dist/{chunk-IS5HWQO7.js → chunk-ARZAHCCF.js} +3 -3
  38. package/dist/{chunk-T6HQMVML.js → chunk-BT7544RM.js} +399 -301
  39. package/dist/chunk-BT7544RM.js.map +1 -0
  40. package/dist/{chunk-4OQWR46B.js → chunk-CCC25PA7.js} +5 -5
  41. package/dist/{chunk-NSLTPGEN.js → chunk-CGJFCT3X.js} +2 -2
  42. package/dist/{chunk-YK72A4IT.js → chunk-CKH247ZR.js} +4 -4
  43. package/dist/{chunk-HGZ7DC5H.js → chunk-DFCINPB5.js} +2 -2
  44. package/dist/chunk-DFCINPB5.js.map +1 -0
  45. package/dist/{chunk-4X2S7PBF.js → chunk-E225X5CQ.js} +3 -3
  46. package/dist/chunk-E225X5CQ.js.map +1 -0
  47. package/dist/{chunk-5YHWBPOT.js → chunk-ED3E3OLO.js} +2 -2
  48. package/dist/{chunk-UOF74WQY.js → chunk-EKTOYEZ3.js} +2 -2
  49. package/dist/{chunk-SAVQ6E2O.js → chunk-G26QAQNI.js} +2 -2
  50. package/dist/{chunk-YMYK7US4.js → chunk-HIELMTUK.js} +2 -2
  51. package/dist/{chunk-MRIBLZL3.js → chunk-ICH4AIGL.js} +1 -1
  52. package/dist/chunk-ICH4AIGL.js.map +1 -0
  53. package/dist/{chunk-LOL725S4.js → chunk-JSYTGEX4.js} +3 -3
  54. package/dist/{chunk-FBMXWVGP.js → chunk-KGFV72WK.js} +5 -5
  55. package/dist/{chunk-GVXBHCZ2.js → chunk-LJO6Q3X6.js} +5 -5
  56. package/dist/chunk-LJO6Q3X6.js.map +1 -0
  57. package/dist/{chunk-ZC2AAE6J.js → chunk-LWFQYT4N.js} +2 -2
  58. package/dist/chunk-LWFQYT4N.js.map +1 -0
  59. package/dist/{chunk-K5PVGKE4.js → chunk-MDIC4FAU.js} +2 -2
  60. package/dist/{chunk-A6SWRXUQ.js → chunk-NONMIU6C.js} +2 -2
  61. package/dist/{chunk-ZUMGGHRB.js → chunk-OPD3PZOG.js} +4 -4
  62. package/dist/{chunk-LS3JLEIB.js → chunk-PS5G6A3Y.js} +4 -4
  63. package/dist/{chunk-KYKMKLJ6.js → chunk-PX3MJ6RB.js} +3 -3
  64. package/dist/{chunk-FCDO7UAO.js → chunk-R4LTCI6O.js} +2 -2
  65. package/dist/{chunk-BFI3RS42.js → chunk-R7JTYCRX.js} +2 -2
  66. package/dist/chunk-R7JTYCRX.js.map +1 -0
  67. package/dist/{chunk-WRLHNG6H.js → chunk-RIHZBSWJ.js} +4 -4
  68. package/dist/chunk-RIHZBSWJ.js.map +1 -0
  69. package/dist/{chunk-UVPGJXVO.js → chunk-SGSHQ4PH.js} +5 -5
  70. package/dist/{chunk-TLFUDXVV.js → chunk-T6MTNGBM.js} +5 -5
  71. package/dist/chunk-T6MTNGBM.js.map +1 -0
  72. package/dist/{chunk-6S3LLAQ5.js → chunk-TNBIWSQ7.js} +2 -2
  73. package/dist/{chunk-GD3BGKAR.js → chunk-UGVDIOY7.js} +2 -2
  74. package/dist/{chunk-FS7A4XNF.js → chunk-WEA4TDTJ.js} +3 -3
  75. package/dist/{chunk-4UBOTYP5.js → chunk-XDW37COG.js} +5 -5
  76. package/dist/chunk-XDW37COG.js.map +1 -0
  77. package/dist/{chunk-QAU5HM6Q.js → chunk-XVJFFGTG.js} +3 -3
  78. package/dist/{chunk-2EYC3WDT.js → chunk-Y3P5DEMZ.js} +6 -6
  79. package/dist/chunk-Y3P5DEMZ.js.map +1 -0
  80. package/dist/{chunk-G7PAZ3TD.js → chunk-YEHUEUNP.js} +4 -4
  81. package/dist/chunk-YEHUEUNP.js.map +1 -0
  82. package/dist/{chunk-2XLVPKXG.js → chunk-YJ46RFCD.js} +2 -2
  83. package/dist/{chunk-KMI2NBBF.js → chunk-YZ6JETII.js} +6 -6
  84. package/dist/{chunk-NCO2JGKK.js → chunk-Z6FNBOTC.js} +1 -1
  85. package/dist/chunk-Z6FNBOTC.js.map +1 -0
  86. package/dist/{chunk-GAUBWHAF.js → chunk-ZQMYB56Z.js} +4 -4
  87. package/dist/consent/index.cjs.map +1 -1
  88. package/dist/consent/index.d.cts +5 -5
  89. package/dist/consent/index.d.ts +5 -5
  90. package/dist/consent/index.js +3 -3
  91. package/dist/{crypto-H2Y3DDFW.js → crypto-5UDZZL26.js} +3 -3
  92. package/dist/{delegation-QSC7G5QC.js → delegation-42LO4WFO.js} +5 -5
  93. package/dist/derivations/index.cjs +1 -1
  94. package/dist/derivations/index.cjs.map +1 -1
  95. package/dist/derivations/index.d.cts +8 -8
  96. package/dist/derivations/index.d.ts +8 -8
  97. package/dist/derivations/index.js +4 -4
  98. package/dist/{dev-unlock-Cf2B7Kih.d.ts → dev-unlock--ahUTrhc.d.ts} +1 -1
  99. package/dist/{dev-unlock-De3mjQWv.d.cts → dev-unlock-BIwt2V3p.d.cts} +1 -1
  100. package/dist/executor-AWCHQ2KN.js +8 -0
  101. package/dist/executor-RWICJI7J.js +11 -0
  102. package/dist/executor-SOLEQVUB.js +8 -0
  103. package/dist/{fanout-sidecar-NRBWSLRK.js → fanout-sidecar-EVICRM46.js} +2 -2
  104. package/dist/fanout-sidecar-EVICRM46.js.map +1 -0
  105. package/dist/guards/index.cjs +1 -1
  106. package/dist/guards/index.cjs.map +1 -1
  107. package/dist/guards/index.d.cts +6 -6
  108. package/dist/guards/index.d.ts +6 -6
  109. package/dist/guards/index.js +4 -4
  110. package/dist/{hash-vBCB0-Ps.d.cts → hash-BQVrGV-t.d.cts} +1 -1
  111. package/dist/{hash-gVn_uKhp.d.ts → hash-CJEFQxSD.d.ts} +1 -1
  112. package/dist/history/index.cjs.map +1 -1
  113. package/dist/history/index.d.cts +6 -6
  114. package/dist/history/index.d.ts +6 -6
  115. package/dist/history/index.js +6 -6
  116. package/dist/i18n/index.cjs.map +1 -1
  117. package/dist/i18n/index.d.cts +5 -5
  118. package/dist/i18n/index.d.ts +5 -5
  119. package/dist/i18n/index.js +7 -7
  120. package/dist/{index-DVkvrgpm.d.cts → index-5I0MZ0jQ.d.cts} +12 -12
  121. package/dist/{index-BF1B2HB9.d.ts → index-fIPPh5dg.d.ts} +12 -12
  122. package/dist/index.cjs +362 -264
  123. package/dist/index.cjs.map +1 -1
  124. package/dist/index.d.cts +20 -22
  125. package/dist/index.d.ts +20 -22
  126. package/dist/index.js +45 -45
  127. package/dist/index.js.map +1 -1
  128. package/dist/indexing/index.cjs +1 -1
  129. package/dist/indexing/index.cjs.map +1 -1
  130. package/dist/indexing/index.d.cts +3 -3
  131. package/dist/indexing/index.d.ts +3 -3
  132. package/dist/indexing/index.js +4 -4
  133. package/dist/issue-IODMTPME.js +12 -0
  134. package/dist/{lazy-builder-Rpd-V3jP.d.ts → lazy-builder-D1MyR1qH.d.ts} +2 -2
  135. package/dist/{lazy-builder-C-rPfWG0.d.cts → lazy-builder-DXlSCNCJ.d.cts} +2 -2
  136. package/dist/{ledger-WOEJUYTP.js → ledger-UX4QIHWI.js} +6 -6
  137. package/dist/materialized-views/index.cjs.map +1 -1
  138. package/dist/materialized-views/index.d.cts +18 -18
  139. package/dist/materialized-views/index.d.ts +18 -18
  140. package/dist/materialized-views/index.js +7 -7
  141. package/dist/noydb-6TADQIYH.js +34 -0
  142. package/dist/overlay-views/index.cjs +1 -1
  143. package/dist/overlay-views/index.cjs.map +1 -1
  144. package/dist/overlay-views/index.d.cts +8 -8
  145. package/dist/overlay-views/index.d.ts +8 -8
  146. package/dist/overlay-views/index.js +4 -4
  147. package/dist/periods/index.cjs.map +1 -1
  148. package/dist/periods/index.d.cts +5 -5
  149. package/dist/periods/index.d.ts +5 -5
  150. package/dist/periods/index.js +6 -6
  151. package/dist/{predicate-Dnu81tsS.d.cts → predicate-B0IKeBXx.d.cts} +1 -1
  152. package/dist/{predicate-Dnu81tsS.d.ts → predicate-B0IKeBXx.d.ts} +1 -1
  153. package/dist/{public-envelope-OHQ5UZFM.js → public-envelope-YKHKP74C.js} +4 -4
  154. package/dist/query/index.cjs +2 -2
  155. package/dist/query/index.cjs.map +1 -1
  156. package/dist/query/index.d.cts +2 -2
  157. package/dist/query/index.d.ts +2 -2
  158. package/dist/query/index.js +6 -6
  159. package/dist/registry-446I2NMN.js +8 -0
  160. package/dist/{registry-CDHASH73.js → registry-4NEW7LQY.js} +3 -3
  161. package/dist/registry-524KJZG4.js +8 -0
  162. package/dist/registry-DKEXOJVO.js +7 -0
  163. package/dist/{revoke-7JOVLZFD.js → revoke-R5NIQ74J.js} +6 -6
  164. package/dist/session/index.cjs.map +1 -1
  165. package/dist/session/index.d.cts +6 -6
  166. package/dist/session/index.d.ts +6 -6
  167. package/dist/session/index.js +3 -3
  168. package/dist/shadow/index.cjs.map +1 -1
  169. package/dist/shadow/index.d.cts +5 -5
  170. package/dist/shadow/index.d.ts +5 -5
  171. package/dist/shadow/index.js +2 -2
  172. package/dist/{signer-M4K5HBLD.js → signer-WGDJNWSU.js} +5 -5
  173. package/dist/{stale-PAGCS4K5.js → stale-74WGLVZ2.js} +2 -2
  174. package/dist/store/index.cjs.map +1 -1
  175. package/dist/store/index.d.cts +5 -5
  176. package/dist/store/index.d.ts +5 -5
  177. package/dist/store/index.js +2 -2
  178. package/dist/sync/index.cjs.map +1 -1
  179. package/dist/sync/index.d.cts +4 -4
  180. package/dist/sync/index.d.ts +4 -4
  181. package/dist/sync/index.js +4 -4
  182. package/dist/team/index.cjs +1 -1
  183. package/dist/team/index.cjs.map +1 -1
  184. package/dist/team/index.d.cts +5 -5
  185. package/dist/team/index.d.ts +5 -5
  186. package/dist/team/index.js +8 -8
  187. package/dist/tx/index.cjs +2 -2
  188. package/dist/tx/index.cjs.map +1 -1
  189. package/dist/tx/index.d.cts +5 -5
  190. package/dist/tx/index.d.ts +5 -5
  191. package/dist/tx/index.js +3 -3
  192. package/dist/tx/index.js.map +1 -1
  193. package/dist/{types-D9eB0Rvh.d.ts → types-BV4AZKmx.d.ts} +340 -302
  194. package/dist/{types-CSLcfytP.d.cts → types-BeKi0hCx.d.cts} +340 -302
  195. package/dist/{ulid-CiM2OAeM.d.ts → ulid-CQc0eBxE.d.ts} +19 -19
  196. package/dist/{ulid-CG2YvAbg.d.cts → ulid-Cvljl7ZZ.d.cts} +19 -19
  197. package/dist/util/index.cjs.map +1 -1
  198. package/dist/util/index.js +1 -1
  199. package/dist/{with-derivation-Bzpj6UTv.d.ts → with-derivation-BWcwmevt.d.ts} +1 -1
  200. package/dist/{with-derivation-DWajFh4K.d.cts → with-derivation-BkOBDhsu.d.cts} +1 -1
  201. package/dist/{with-guard-DF_Ul3DT.d.cts → with-guard-BD4Hyu8s.d.cts} +1 -1
  202. package/dist/{with-guard-DR7U-l4v.d.ts → with-guard-Du54s3Ti.d.ts} +1 -1
  203. package/dist/{with-materialized-view-qtoJ3xKJ.d.ts → with-materialized-view-B5W4wFAC.d.ts} +2 -2
  204. package/dist/{with-materialized-view-_piodoIz.d.cts → with-materialized-view-BCPPZdjC.d.cts} +2 -2
  205. package/dist/{with-overlayed-view-DFaRfgMr.d.ts → with-overlayed-view-B8RrlLsG.d.cts} +2 -2
  206. package/dist/{with-overlayed-view-DwzCKxn2.d.cts → with-overlayed-view-Cw-h9p9N.d.ts} +2 -2
  207. package/package.json +3 -3
  208. package/dist/chunk-2EYC3WDT.js.map +0 -1
  209. package/dist/chunk-4UBOTYP5.js.map +0 -1
  210. package/dist/chunk-4X2S7PBF.js.map +0 -1
  211. package/dist/chunk-74JEQFMT.js.map +0 -1
  212. package/dist/chunk-BFI3RS42.js.map +0 -1
  213. package/dist/chunk-EMEX37ZN.js.map +0 -1
  214. package/dist/chunk-EPK6A3WJ.js.map +0 -1
  215. package/dist/chunk-FXQYZNOW.js.map +0 -1
  216. package/dist/chunk-G7PAZ3TD.js.map +0 -1
  217. package/dist/chunk-GDTCGIPX.js.map +0 -1
  218. package/dist/chunk-GVXBHCZ2.js.map +0 -1
  219. package/dist/chunk-HGZ7DC5H.js.map +0 -1
  220. package/dist/chunk-MRIBLZL3.js.map +0 -1
  221. package/dist/chunk-NCO2JGKK.js.map +0 -1
  222. package/dist/chunk-NGSPBLLE.js.map +0 -1
  223. package/dist/chunk-P6256WTJ.js.map +0 -1
  224. package/dist/chunk-T6HQMVML.js.map +0 -1
  225. package/dist/chunk-TLFUDXVV.js.map +0 -1
  226. package/dist/chunk-WRLHNG6H.js.map +0 -1
  227. package/dist/chunk-YDLAFP36.js.map +0 -1
  228. package/dist/chunk-YL2DR3HY.js.map +0 -1
  229. package/dist/chunk-ZC2AAE6J.js.map +0 -1
  230. package/dist/executor-BZKFZVRC.js +0 -8
  231. package/dist/executor-GFZFDQXV.js +0 -8
  232. package/dist/executor-KT2IOZVP.js +0 -11
  233. package/dist/fanout-sidecar-NRBWSLRK.js.map +0 -1
  234. package/dist/issue-BAJ7ZB4S.js +0 -12
  235. package/dist/noydb-XNQSKXGO.js +0 -34
  236. package/dist/registry-2IEARCGT.js +0 -7
  237. package/dist/registry-EMGLZGR6.js +0 -8
  238. package/dist/registry-NQALYR77.js +0 -8
  239. /package/dist/{chunk-5ZGZ6HIZ.js.map → chunk-5VMTAX4Y.js.map} +0 -0
  240. /package/dist/{chunk-75QDHSE4.js.map → chunk-A4JNVBPF.js.map} +0 -0
  241. /package/dist/{chunk-IS5HWQO7.js.map → chunk-ARZAHCCF.js.map} +0 -0
  242. /package/dist/{chunk-4OQWR46B.js.map → chunk-CCC25PA7.js.map} +0 -0
  243. /package/dist/{chunk-NSLTPGEN.js.map → chunk-CGJFCT3X.js.map} +0 -0
  244. /package/dist/{chunk-YK72A4IT.js.map → chunk-CKH247ZR.js.map} +0 -0
  245. /package/dist/{chunk-5YHWBPOT.js.map → chunk-ED3E3OLO.js.map} +0 -0
  246. /package/dist/{chunk-UOF74WQY.js.map → chunk-EKTOYEZ3.js.map} +0 -0
  247. /package/dist/{chunk-SAVQ6E2O.js.map → chunk-G26QAQNI.js.map} +0 -0
  248. /package/dist/{chunk-YMYK7US4.js.map → chunk-HIELMTUK.js.map} +0 -0
  249. /package/dist/{chunk-LOL725S4.js.map → chunk-JSYTGEX4.js.map} +0 -0
  250. /package/dist/{chunk-FBMXWVGP.js.map → chunk-KGFV72WK.js.map} +0 -0
  251. /package/dist/{chunk-K5PVGKE4.js.map → chunk-MDIC4FAU.js.map} +0 -0
  252. /package/dist/{chunk-A6SWRXUQ.js.map → chunk-NONMIU6C.js.map} +0 -0
  253. /package/dist/{chunk-ZUMGGHRB.js.map → chunk-OPD3PZOG.js.map} +0 -0
  254. /package/dist/{chunk-LS3JLEIB.js.map → chunk-PS5G6A3Y.js.map} +0 -0
  255. /package/dist/{chunk-KYKMKLJ6.js.map → chunk-PX3MJ6RB.js.map} +0 -0
  256. /package/dist/{chunk-FCDO7UAO.js.map → chunk-R4LTCI6O.js.map} +0 -0
  257. /package/dist/{chunk-UVPGJXVO.js.map → chunk-SGSHQ4PH.js.map} +0 -0
  258. /package/dist/{chunk-6S3LLAQ5.js.map → chunk-TNBIWSQ7.js.map} +0 -0
  259. /package/dist/{chunk-GD3BGKAR.js.map → chunk-UGVDIOY7.js.map} +0 -0
  260. /package/dist/{chunk-FS7A4XNF.js.map → chunk-WEA4TDTJ.js.map} +0 -0
  261. /package/dist/{chunk-QAU5HM6Q.js.map → chunk-XVJFFGTG.js.map} +0 -0
  262. /package/dist/{chunk-2XLVPKXG.js.map → chunk-YJ46RFCD.js.map} +0 -0
  263. /package/dist/{chunk-KMI2NBBF.js.map → chunk-YZ6JETII.js.map} +0 -0
  264. /package/dist/{chunk-GAUBWHAF.js.map → chunk-ZQMYB56Z.js.map} +0 -0
  265. /package/dist/{crypto-H2Y3DDFW.js.map → crypto-5UDZZL26.js.map} +0 -0
  266. /package/dist/{delegation-QSC7G5QC.js.map → delegation-42LO4WFO.js.map} +0 -0
  267. /package/dist/{executor-BZKFZVRC.js.map → executor-AWCHQ2KN.js.map} +0 -0
  268. /package/dist/{executor-GFZFDQXV.js.map → executor-RWICJI7J.js.map} +0 -0
  269. /package/dist/{executor-KT2IOZVP.js.map → executor-SOLEQVUB.js.map} +0 -0
  270. /package/dist/{issue-BAJ7ZB4S.js.map → issue-IODMTPME.js.map} +0 -0
  271. /package/dist/{ledger-WOEJUYTP.js.map → ledger-UX4QIHWI.js.map} +0 -0
  272. /package/dist/{noydb-XNQSKXGO.js.map → noydb-6TADQIYH.js.map} +0 -0
  273. /package/dist/{public-envelope-OHQ5UZFM.js.map → public-envelope-YKHKP74C.js.map} +0 -0
  274. /package/dist/{registry-2IEARCGT.js.map → registry-446I2NMN.js.map} +0 -0
  275. /package/dist/{registry-CDHASH73.js.map → registry-4NEW7LQY.js.map} +0 -0
  276. /package/dist/{registry-EMGLZGR6.js.map → registry-524KJZG4.js.map} +0 -0
  277. /package/dist/{registry-NQALYR77.js.map → registry-DKEXOJVO.js.map} +0 -0
  278. /package/dist/{revoke-7JOVLZFD.js.map → revoke-R5NIQ74J.js.map} +0 -0
  279. /package/dist/{signer-M4K5HBLD.js.map → signer-WGDJNWSU.js.map} +0 -0
  280. /package/dist/{stale-PAGCS4K5.js.map → stale-74WGLVZ2.js.map} +0 -0
@@ -1,16 +1,16 @@
1
1
  import {
2
2
  ensureCollectionDEK
3
- } from "./chunk-TLFUDXVV.js";
3
+ } from "./chunk-T6MTNGBM.js";
4
4
  import {
5
5
  NOYDB_FORMAT_VERSION
6
- } from "./chunk-FXQYZNOW.js";
6
+ } from "./chunk-5OVIFUQE.js";
7
7
  import {
8
8
  decrypt,
9
9
  encrypt
10
- } from "./chunk-UOF74WQY.js";
10
+ } from "./chunk-EKTOYEZ3.js";
11
11
  import {
12
12
  PermissionDeniedError
13
- } from "./chunk-YDLAFP36.js";
13
+ } from "./chunk-6HJ2ZALB.js";
14
14
 
15
15
  // src/team/sync-credentials.ts
16
16
  var SYNC_CREDENTIALS_COLLECTION = "_sync_credentials";
@@ -76,4 +76,4 @@ export {
76
76
  listCredentials,
77
77
  credentialStatus
78
78
  };
79
- //# sourceMappingURL=chunk-4OQWR46B.js.map
79
+ //# sourceMappingURL=chunk-CCC25PA7.js.map
@@ -2,7 +2,7 @@ import {
2
2
  OverlayBaseIsVirtualError,
3
3
  OverlayCollectionUnavailableError,
4
4
  OverlayNameCollisionError
5
- } from "./chunk-YDLAFP36.js";
5
+ } from "./chunk-6HJ2ZALB.js";
6
6
 
7
7
  // src/overlay-views/registry.ts
8
8
  var OverlayedViewRegistry = class {
@@ -58,4 +58,4 @@ var OverlayedViewRegistry = class {
58
58
  export {
59
59
  OverlayedViewRegistry
60
60
  };
61
- //# sourceMappingURL=chunk-NSLTPGEN.js.map
61
+ //# sourceMappingURL=chunk-CGJFCT3X.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  dekKey
3
- } from "./chunk-6S3LLAQ5.js";
3
+ } from "./chunk-TNBIWSQ7.js";
4
4
  import {
5
5
  generateULID
6
6
  } from "./chunk-FZU343FL.js";
@@ -9,10 +9,10 @@ import {
9
9
  encrypt,
10
10
  unwrapKey,
11
11
  wrapKey
12
- } from "./chunk-UOF74WQY.js";
12
+ } from "./chunk-EKTOYEZ3.js";
13
13
  import {
14
14
  DelegationTargetMissingError
15
- } from "./chunk-YDLAFP36.js";
15
+ } from "./chunk-6HJ2ZALB.js";
16
16
 
17
17
  // src/team/delegation.ts
18
18
  var DELEGATIONS_COLLECTION = "_delegations";
@@ -94,4 +94,4 @@ export {
94
94
  loadActiveDelegations,
95
95
  revokeDelegation
96
96
  };
97
- //# sourceMappingURL=chunk-YK72A4IT.js.map
97
+ //# sourceMappingURL=chunk-CKH247ZR.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  DerivationCapExceededError,
3
3
  DerivationOutputShapeError
4
- } from "./chunk-YDLAFP36.js";
4
+ } from "./chunk-6HJ2ZALB.js";
5
5
 
6
6
  // src/derivations/executor.ts
7
7
  var DerivationExecutor = {
@@ -121,4 +121,4 @@ var DerivationExecutor = {
121
121
  export {
122
122
  DerivationExecutor
123
123
  };
124
- //# sourceMappingURL=chunk-HGZ7DC5H.js.map
124
+ //# sourceMappingURL=chunk-DFCINPB5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/derivations/executor.ts"],"sourcesContent":["import { DerivationCapExceededError, DerivationOutputShapeError } from '../errors.js'\nimport type { DerivationContext, DerivationStrategy, DerivedFromMeta } from './types.js'\n\nexport interface RunResult {\n outputs: Record<string, OutputResult>\n failed: boolean\n}\n\n/**\n * Per-output result of a strategy invocation. Discriminated by\n * `kind`:\n *\n * - `record` — the existing v1 shape: one value (or a \"skipped\"\n * marker if the output was optional and `derive` returned null).\n * - `array` — a list of `(key, value)` entries.\n * The caller diffs these against the previously-emitted key set\n * (loaded from the fanout sidecar) to compute deletes + upserts.\n */\nexport type OutputResult =\n | RecordOutputResult\n | ArrayOutputResult\n | FailedOutputResult\n\nexport interface RecordOutputResult {\n kind: 'record'\n value: Record<string, unknown>\n ok: true\n /**\n * `true` when an optional output returned `null` /\n * `undefined`. The caller deletes any previously-emitted output at\n * the same id (mirrors \"tombstone for derived data\"); a never-emitted\n * output is a silent no-op. `ok: true` because skipping is a\n * successful outcome, not a failure.\n */\n skipped?: boolean\n}\n\nexport interface ArrayOutputResult {\n kind: 'array'\n ok: true\n /** One `(key, value)` per derived row. Empty array means \"all prior outputs for this source go.\" */\n entries: ReadonlyArray<{ readonly key: string; readonly value: Record<string, unknown> }>\n}\n\nexport interface FailedOutputResult {\n kind: 'failed'\n ok: false\n error: Error\n /** Always empty on failure; present so consumers don't have to narrow. */\n value: Record<string, unknown>\n}\n\n/**\n * Stateless functions that execute a derivation strategy. Persistence\n * (encrypt + store.put) is the caller's job — typically\n * `DerivationRegistry.onSourceWrite` which iterates run() results and\n * writes each output via `Collection.put`.\n */\nexport const DerivationExecutor = {\n /**\n * Run `derive` once, validate output shape against the spec, stamp\n * `_derivedFrom` onto every output. Returns per-output success or\n * failure; throws only for shape mismatches (a contract violation).\n */\n async run<\n TSource extends Record<string, unknown>,\n TOutputs extends Record<string, Record<string, unknown>>,\n >(\n strategy: DerivationStrategy<TSource, TOutputs>,\n source: TSource & { id: string },\n sourceVersion: number,\n strategyHash: string,\n ctx: DerivationContext,\n ): Promise<RunResult> {\n const outputs: Record<string, OutputResult> = {}\n let derived: Partial<TOutputs>\n\n try {\n derived = await Promise.resolve(strategy.derive(source as TSource, ctx))\n } catch (err) {\n for (const key of Object.keys(strategy.outputs)) {\n outputs[key] = {\n kind: 'failed',\n value: {},\n ok: false,\n error: err instanceof Error ? err : new Error(String(err)),\n }\n }\n return { outputs, failed: true }\n }\n\n const meta: DerivedFromMeta = {\n source: strategy.source,\n sourceId: source.id,\n sourceVersion,\n derivedAt: new Date().toISOString(),\n strategyHash,\n }\n\n for (const key of Object.keys(strategy.outputs)) {\n const outSpec = strategy.outputs[key]\n if (!outSpec) continue\n const value = (derived as Record<string, unknown>)[key]\n\n // ── Array-shape branch ─────────────────────────────────────\n if (outSpec.shape === 'array') {\n if (value === undefined || value === null) {\n // Treat null/undefined as \"empty array\" — clears all prior\n // outputs for this (source, output) pair. The caller's\n // diff turns that into deletes.\n outputs[key] = { kind: 'array', ok: true, entries: [] }\n continue\n }\n if (!Array.isArray(value)) {\n throw new DerivationOutputShapeError(\n key,\n `shape 'array' expects an array, got ${typeof value}`,\n )\n }\n const maxFanout = outSpec.maxFanout ?? 64\n if (value.length > maxFanout) {\n throw new DerivationCapExceededError(key, value.length, maxFanout)\n }\n const entries: Array<{ key: string; value: Record<string, unknown> }> = []\n const seenKeys = new Set<string>()\n for (let i = 0; i < value.length; i++) {\n const row = value[i] as unknown\n if (row === null || typeof row !== 'object') {\n throw new DerivationOutputShapeError(\n key,\n `array member at index ${i} must be a non-null object (got ${row === null ? 'null' : typeof row})`,\n )\n }\n let derivedKey: string\n try {\n derivedKey = outSpec.key(row as Record<string, unknown>)\n } catch (err) {\n throw new DerivationOutputShapeError(\n key,\n `key extractor threw on array member at index ${i}: `\n + (err instanceof Error ? err.message : String(err)),\n )\n }\n if (typeof derivedKey !== 'string' || derivedKey.length === 0) {\n throw new DerivationOutputShapeError(\n key,\n `key extractor returned ${typeof derivedKey === 'string' ? 'empty string' : typeof derivedKey} at index ${i}; expected non-empty string`,\n )\n }\n if (seenKeys.has(derivedKey)) {\n throw new DerivationOutputShapeError(\n key,\n `duplicate key \"${derivedKey}\" in array output (index ${i}); each derived row must have a unique key within a single derive() invocation`,\n )\n }\n seenKeys.add(derivedKey)\n entries.push({\n key: derivedKey,\n value: { ...(row as Record<string, unknown>), _derivedFrom: meta },\n })\n }\n outputs[key] = { kind: 'array', ok: true, entries }\n continue\n }\n\n // ── Record-shape branch (existing v1 behavior) ─────────────\n if (value === undefined || value === null) {\n if (outSpec.optional === true) {\n // Optional output explicitly skipped. Mark for caller\n // so any prior-emitted output at this id can be deleted.\n outputs[key] = { kind: 'record', value: {}, ok: true, skipped: true }\n continue\n }\n throw new DerivationOutputShapeError(\n key,\n `expected object, got ${value === undefined ? 'undefined' : 'null'}`,\n )\n }\n if (typeof value !== 'object') {\n throw new DerivationOutputShapeError(\n key,\n `expected object, got ${typeof value}`,\n )\n }\n outputs[key] = {\n kind: 'record',\n value: { ...(value as Record<string, unknown>), _derivedFrom: meta },\n ok: true,\n }\n }\n return { outputs, failed: false }\n },\n}\n"],"mappings":"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","names":[]}
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  NOYDB_FORMAT_VERSION
3
- } from "./chunk-FXQYZNOW.js";
3
+ } from "./chunk-5OVIFUQE.js";
4
4
  import {
5
5
  decrypt,
6
6
  encrypt
7
- } from "./chunk-UOF74WQY.js";
7
+ } from "./chunk-EKTOYEZ3.js";
8
8
 
9
9
  // src/persisted-schemas/storage.ts
10
10
  var SCHEMAS_COLLECTION = "_schemas";
@@ -248,4 +248,4 @@ export {
248
248
  loadSealedPassphrase,
249
249
  resolveManagedSecret
250
250
  };
251
- //# sourceMappingURL=chunk-4X2S7PBF.js.map
251
+ //# sourceMappingURL=chunk-E225X5CQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/persisted-schemas/storage.ts","../src/team/managed-passphrase.ts"],"sourcesContent":["/**\n * Read / write the per-collection persisted-schema envelope. Mirrors the\n * standard noy-db record envelope shape and is **AES-GCM encrypted with\n * the collection's DEK** — the schema body (field names, enum values,\n * constraints) is sensitive metadata, so it gets the same encryption\n * envelope as the records it describes.\n *\n * Storage layout:\n *\n * <vault>/_schemas/<collection> → EncryptedEnvelope\n *\n * The DEK passed to {@link savePersistedSchema} / {@link loadPersistedSchema}\n * is the same key the collection uses for its records.\n *\n * @module\n */\n\nimport { encrypt, decrypt } from '../crypto.js'\nimport { NOYDB_FORMAT_VERSION } from '../types.js'\nimport type { NoydbStore, EncryptedEnvelope } from '../types.js'\nimport type { PersistedSchemaEnvelope } from './types.js'\n\n/** Reserved collection name where persisted schemas live. */\nexport const SCHEMAS_COLLECTION = '_schemas' as const\n\n/**\n * Read and decrypt the persisted-schema envelope for one collection.\n * Returns `undefined` when no envelope has been written or when decryption\n * fails (e.g. wrong DEK passed). Tolerates corrupted records — JSON parse\n * failures surface as `undefined`, mirroring `_meta/handle`'s contract.\n */\nexport async function loadPersistedSchema(\n store: NoydbStore,\n vault: string,\n collection: string,\n dek: CryptoKey,\n): Promise<PersistedSchemaEnvelope | undefined> {\n const envelope = await store.get(vault, SCHEMAS_COLLECTION, collection)\n if (!envelope) return undefined\n try {\n const plaintext = await decrypt(envelope._iv, envelope._data, dek)\n const parsed = JSON.parse(plaintext) as PersistedSchemaEnvelope\n if (parsed._noydb_schema !== 1) return undefined\n return parsed\n } catch {\n return undefined\n }\n}\n\n/**\n * Encrypt and persist a schema envelope for one collection. Always\n * overwrites any prior write (callers gate on hash equality before calling\n * to avoid no-op writes).\n */\nexport async function savePersistedSchema(\n store: NoydbStore,\n vault: string,\n collection: string,\n dek: CryptoKey,\n payload: PersistedSchemaEnvelope,\n): Promise<void> {\n const json = JSON.stringify(payload)\n const { iv, data } = await encrypt(json, dek)\n const prior = await store.get(vault, SCHEMAS_COLLECTION, collection)\n const env: EncryptedEnvelope = {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: (prior?._v ?? 0) + 1,\n _ts: new Date().toISOString(),\n _iv: iv,\n _data: data,\n }\n await store.put(vault, SCHEMAS_COLLECTION, collection, env)\n}\n","/**\n * Managed-passphrase mode — rubber-hose-resistant vaults.\n *\n * A vault mode where the passphrase is machine-generated and never\n * exposed to the user, sealed under a developer-provided\n * {@link SealingKeyProvider} (macOS Keychain, Windows Credential\n * Manager, libsecret, AWS KMS, …). The user has no secret to give\n * up to coercion — they can't reveal what they don't know.\n *\n * ## Components in this file\n *\n * - {@link SealingKeyProvider} — the interface concrete providers\n * implement. Provider implementations live OUTSIDE hub (per-\n * platform packages).\n * - {@link MemorySealingKeyProvider} — in-memory test provider; uses\n * a deterministic per-instance \"key\" so two providers with\n * different ids cannot unseal each other's outputs.\n * - {@link RecipientHint} — public material a sender uses to seal\n * plaintext for a specific recipient; published by\n * {@link RecipientSealer.publishRecipientHint} and transported\n * out-of-band to the sender before bundle writes.\n * - {@link RecipientSealer} — interface for asymmetric/granted\n * providers that support recipient-target sealing (RSA-OAEP,\n * cloud-KMS asymmetric, etc.); distinct from self-only\n * {@link SealingKeyProvider} (macOS Keychain, WebAuthn-PRF).\n * - {@link MemoryRecipientSealer} — in-process reference\n * implementation of both `RecipientSealer` and\n * `SealingKeyProvider` using real WebCrypto RSA-OAEP + AES-GCM;\n * safe for tests and same-process sender/recipient scenarios.\n * - {@link loadSealedPassphrase} / {@link saveSealedPassphrase} —\n * plaintext envelope storage at `_meta/sealed-passphrase`.\n * Mirrors the `_meta/handle` and `_meta/public-envelope` AES-\n * GCM-bypassed patterns. The sealing layer (provider's job)\n * is the security boundary; hub doesn't have a key to encrypt\n * with at this layer — that's the whole point of the design.\n * - {@link resolveManagedSecret} — orchestrates the \"generate +\n * seal + persist on first open; unseal on reopen\" flow.\n * Returns the plaintext passphrase string that the rest of the\n * `createNoydb` keyring path consumes.\n *\n * Deferred to follow-ups:\n * - Block `rotate-passphrase` policy gate under managed mode.\n * - Mandatory strong-recovery enforcement.\n * - Recovery flow under managed mode (generates fresh sealed phrase).\n *\n * @see docs/subsystems/session-tiers.md → Managed-passphrase mode\n *\n * @module\n */\n\nimport type { NoydbStore, EncryptedEnvelope } from '../types.js'\nimport { NOYDB_FORMAT_VERSION } from '../types.js'\n\n/**\n * The contract concrete providers (per-platform key stores) implement\n * to seal and unseal a hub-generated random passphrase. The plaintext\n * passphrase NEVER leaves hub-controlled memory in unsealed form —\n * the provider receives the bytes, returns opaque sealed bytes, and\n * later reverses the operation. Hub treats the sealed bytes as\n * fully opaque.\n *\n * Implementations live OUTSIDE `@noy-db/hub` (separate packages\n * per the issue's \"Concrete providers (live outside hub)\" note):\n *\n * | Platform | Package (TBD) | Backing |\n * |---|---|---|\n * | macOS | `@noy-db/seal-macos-keychain` | Security.framework |\n * | Windows | `@noy-db/seal-wincred` | Credential Manager |\n * | Linux | `@noy-db/seal-libsecret` | libsecret / secret-service |\n * | Cloud / server | `@noy-db/seal-aws-kms` | AWS KMS Decrypt |\n */\nexport interface SealingKeyProvider {\n /**\n * Non-sensitive identifier disclosed in the persisted envelope.\n * Surfaced to consumers via `loadSealedPassphrase().providerId` so\n * a vault opened with the wrong provider class can detect the\n * mismatch and surface a clear error. NOT secret — fine to log.\n *\n * Suggested format: `<family>:<scope>` — e.g. `macos-keychain:com.acme.app`,\n * `aws-kms:arn:aws:kms:us-east-1:123:key/abc`. The hub never\n * parses this; it's purely audit metadata.\n */\n readonly id: string\n\n /** Seal raw passphrase bytes. Output bytes are opaque to hub. */\n seal(passphrase: Uint8Array): Promise<Uint8Array>\n\n /**\n * Reverse {@link seal}. MUST throw on tamper, wrong-provider, or\n * any other failure — hub treats a thrown error as \"this provider\n * cannot unlock this vault\" and surfaces it to the caller.\n */\n unseal(sealed: Uint8Array): Promise<Uint8Array>\n}\n\n/**\n * In-memory test provider. NOT secure — uses a deterministic\n * per-instance \"key\" (16-byte SHA-256 of `id`) XOR'd over the\n * passphrase plus a 4-byte provider-id fingerprint prefix. The XOR is\n * sufficient to make different `id` values produce mutually-unsealable\n * outputs (the contract tests for that), but offers ZERO real\n * confidentiality — never use outside tests.\n *\n * Replace with a real platform provider in production.\n */\nexport class MemorySealingKeyProvider implements SealingKeyProvider {\n readonly id: string\n private readonly fingerprint: Uint8Array\n private readonly keyBytes: Uint8Array\n\n constructor(opts: { id: string }) {\n this.id = opts.id\n // Deterministic 4-byte fingerprint of the provider id, prepended\n // to every sealed output so we can detect \"wrong provider\" at\n // unseal time without leaking anything sensitive about either\n // provider's actual key material.\n const encoded = new TextEncoder().encode(opts.id)\n let h = 0\n for (let i = 0; i < encoded.length; i++) {\n h = (h * 31 + encoded[i]!) >>> 0\n }\n this.fingerprint = new Uint8Array([\n (h >>> 24) & 0xff, (h >>> 16) & 0xff, (h >>> 8) & 0xff, h & 0xff,\n ])\n // Deterministic 16-byte \"key\" derived from the id by repeating\n // the fingerprint with offsets. Good enough for the XOR-stream\n // test cipher; never confuse this with real key derivation.\n this.keyBytes = new Uint8Array(16)\n for (let i = 0; i < 16; i++) {\n this.keyBytes[i] = this.fingerprint[i % 4]! ^ (i * 17)\n }\n }\n\n async seal(passphrase: Uint8Array): Promise<Uint8Array> {\n const out = new Uint8Array(4 + passphrase.length)\n out.set(this.fingerprint, 0)\n for (let i = 0; i < passphrase.length; i++) {\n out[4 + i] = passphrase[i]! ^ this.keyBytes[i % 16]!\n }\n return out\n }\n\n async unseal(sealed: Uint8Array): Promise<Uint8Array> {\n if (sealed.length < 4) {\n throw new Error('MemorySealingKeyProvider: sealed input too short')\n }\n for (let i = 0; i < 4; i++) {\n if (sealed[i] !== this.fingerprint[i]) {\n throw new Error(\n `MemorySealingKeyProvider(\"${this.id}\"): provider-id mismatch on unseal `\n + '(sealed bytes were produced by a different provider)',\n )\n }\n }\n const body = sealed.subarray(4)\n const out = new Uint8Array(body.length)\n for (let i = 0; i < body.length; i++) {\n out[i] = body[i]! ^ this.keyBytes[i % 16]!\n }\n return out\n }\n}\n\n/**\n * Public material a sender uses to seal-for-this-recipient. Published by\n * a recipient's RecipientSealer; transported to the sender out-of-band\n * (email, S3, in-app message). The sender obtains the hint, supplies it\n * to writeNoydbBundle's sealedCredentials.perUser[userId].hint, and the\n * hub seals each user's credential against it. Per foundation §11.4.\n */\nexport type RecipientHint = {\n readonly v: 1\n /** Recipient's provider id; matches the SealedAutoUnlockEntry.pid they'll unseal under. */\n readonly pid: string\n /** Algorithm the sender uses to produce the seal. Slice 1 ships RSA-OAEP-SHA256 only. */\n readonly alg: 'rsa-oaep-sha256'\n /** Public material — alg-specific. For 'rsa-oaep-sha256': { publicKeyPem: string }. */\n readonly material: Readonly<Record<string, unknown>>\n}\n\n/**\n * Handover-capable provider. Implemented additionally by asymmetric/granted\n * providers (cloud-KMS asymmetric, Azure RSA Key Vault, AWS KMS with grant).\n * Self-only providers (macOS Keychain, env-var, WebAuthn-PRF) do NOT\n * implement this — the §11.2 capability matrix lives in the type system.\n *\n * Per foundation §11.4. A function that requires recipient-target sealing\n * takes `RecipientSealer`, not `SealingKeyProvider` — the compiler rejects\n * passing a self-only provider at the spec site.\n */\nexport interface RecipientSealer {\n readonly id: string\n /** Produce hint material a sender uses to seal-for-this-recipient. */\n publishRecipientHint(): Promise<RecipientHint>\n /**\n * Seal plaintext for the recipient described by `hint`. Returns opaque\n * bytes — same contract as `SealingKeyProvider.seal()`. The bundle\n * layer base64-encodes the bytes into `SealedAutoUnlockEntry.sealed`\n * without inspecting them.\n */\n sealForRecipient(plaintext: Uint8Array, hint: RecipientHint): Promise<Uint8Array>\n}\n\n/**\n * Reference implementation of `RecipientSealer` + `SealingKeyProvider`.\n * Uses WebCrypto RSA-OAEP-SHA256 (2048-bit) to wrap a fresh 32-byte\n * AES-GCM CEK, AES-GCM-encrypts plaintext under it, and packs the\n * result into a self-describing TLV:\n *\n * byte 0 : version (0x01)\n * bytes 1..256 : RSA-OAEP-wrapped CEK (fixed 256 bytes at RSA-2048)\n * bytes 257..268: AES-GCM IV (12 bytes)\n * bytes 269.. : AES-GCM ciphertext ‖ 16-byte tag\n *\n * Implements BOTH interfaces. `seal(plaintext)` (self-target) is just\n * `sealForRecipient(plaintext, this own hint)` — same TLV. Convenient\n * for tests where one provider plays both ends. Real cloud providers\n * (`at-aws-kms`, etc.) will pick their own internal layouts; the only\n * contract is round-trip identity.\n *\n * SAFE for production within its scope — the cryptography is real\n * (RSA-OAEP + AES-GCM via WebCrypto), but the keypair lives in-process\n * and is regenerated on every construction. Not suitable as a managed\n * keychain; use it for tests and for shipping bundles where the\n * recipient instance lives in the same process as the sender (rare).\n */\nexport class MemoryRecipientSealer implements SealingKeyProvider, RecipientSealer {\n readonly id: string\n private readonly keypair: Promise<CryptoKeyPair>\n\n constructor(opts: { id: string }) {\n this.id = opts.id\n this.keypair = crypto.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\n async publishRecipientHint(): Promise<RecipientHint> {\n const { publicKey } = await this.keypair\n const spki = await crypto.subtle.exportKey('spki', publicKey)\n const pem = '-----BEGIN PUBLIC KEY-----\\n'\n + bytesToBase64(new Uint8Array(spki)).match(/.{1,64}/g)!.join('\\n')\n + '\\n-----END PUBLIC KEY-----\\n'\n return { v: 1, pid: this.id, alg: 'rsa-oaep-sha256', material: { publicKeyPem: pem } }\n }\n\n async sealForRecipient(plaintext: Uint8Array, hint: RecipientHint): Promise<Uint8Array> {\n if (hint.v !== 1) {\n throw new Error(`MemoryRecipientSealer.sealForRecipient: unsupported hint.v ${String(hint.v)} (expected 1)`)\n }\n if (hint.alg !== 'rsa-oaep-sha256') {\n throw new Error(`MemoryRecipientSealer.sealForRecipient: unsupported hint.alg '${String(hint.alg)}' (expected 'rsa-oaep-sha256')`)\n }\n const pem = hint.material['publicKeyPem']\n if (typeof pem !== 'string') {\n throw new Error('MemoryRecipientSealer.sealForRecipient: hint.material.publicKeyPem missing or not a string')\n }\n // Parse PEM → SPKI bytes.\n const b64 = pem.replace(/-----BEGIN PUBLIC KEY-----/, '').replace(/-----END PUBLIC KEY-----/, '').replace(/\\s+/g, '')\n const spki = base64ToBytes(b64)\n const recipientPub = await crypto.subtle.importKey(\n 'spki', spki as BufferSource,\n { name: 'RSA-OAEP', hash: 'SHA-256' },\n false, ['encrypt'],\n )\n // Mint fresh CEK + IV, AES-GCM encrypt plaintext.\n const cekBytes = crypto.getRandomValues(new Uint8Array(32))\n const cek = await crypto.subtle.importKey('raw', cekBytes as BufferSource, 'AES-GCM', false, ['encrypt'])\n const iv = crypto.getRandomValues(new Uint8Array(12))\n const ct = new Uint8Array(await crypto.subtle.encrypt({ name: 'AES-GCM', iv: iv as BufferSource }, cek, plaintext as BufferSource))\n // RSA-OAEP-wrap the CEK bytes.\n const wrapped = new Uint8Array(await crypto.subtle.encrypt({ name: 'RSA-OAEP' }, recipientPub, cekBytes as BufferSource))\n cekBytes.fill(0)\n if (wrapped.length !== 256) {\n throw new Error(`MemoryRecipientSealer.sealForRecipient: expected 256-byte RSA-OAEP wrap, got ${wrapped.length}`)\n }\n // TLV layout.\n const out = new Uint8Array(1 + 256 + 12 + ct.length)\n out[0] = 0x01\n out.set(wrapped, 1)\n out.set(iv, 1 + 256)\n out.set(ct, 1 + 256 + 12)\n return out\n }\n\n async seal(plaintext: Uint8Array): Promise<Uint8Array> {\n const hint = await this.publishRecipientHint()\n return this.sealForRecipient(plaintext, hint)\n }\n\n async unseal(bytes: Uint8Array): Promise<Uint8Array> {\n if (bytes.length < 1 + 256 + 12 + 16) {\n throw new Error('MemoryRecipientSealer.unseal: sealed input too short')\n }\n if (bytes[0] !== 0x01) {\n throw new Error(`MemoryRecipientSealer.unseal: unknown TLV version ${bytes[0]}`)\n }\n const wrapped = bytes.subarray(1, 1 + 256)\n const iv = bytes.subarray(1 + 256, 1 + 256 + 12)\n const ct = bytes.subarray(1 + 256 + 12)\n const { privateKey } = await this.keypair\n const cekBytes = new Uint8Array(await crypto.subtle.decrypt({ name: 'RSA-OAEP' }, privateKey, wrapped as BufferSource))\n const cek = await crypto.subtle.importKey('raw', cekBytes as BufferSource, 'AES-GCM', false, ['decrypt'])\n const pt = new Uint8Array(await crypto.subtle.decrypt({ name: 'AES-GCM', iv: iv as BufferSource }, cek, ct as BufferSource))\n cekBytes.fill(0)\n return pt\n }\n}\n\n// ─── Persisted envelope ────────────────────────────────────────────────\n\n/** Reserved id for the managed-passphrase envelope under `_meta`. */\nexport const SEALED_PASSPHRASE_RECORD_ID = 'sealed-passphrase' as const\n\n/** Plaintext payload stored inside the `_meta/sealed-passphrase` envelope. */\nexport interface SealedPassphrase {\n readonly _noydb_sealed: 1\n readonly providerId: string\n /** Sealed bytes. Base64-encoded on the wire; decoded on load. */\n readonly sealed: Uint8Array\n}\n\n/**\n * Wire-format envelope persisted at `_meta/sealed-passphrase` for\n * managed-mode vaults. The provider produces raw sealed bytes via\n * {@link SealingKeyProvider.seal}; this wrapper carries the dispatch\n * metadata hub needs to pick the right provider on the unseal path.\n *\n * Stability boundary: once shipped, the wire format only grows by\n * adding optional fields. See the at-* sealing dimension foundation\n * doc, §11.9.1.\n *\n * v1 shape (this release): `{ v: 1, _noydb_sealed: 1, pid, payload }`.\n *\n * Legacy shape (earlier releases): `{ _noydb_sealed: 1, providerId, sealed }`\n * — accepted on read for backwards compatibility; never produced on\n * write going forward.\n */\nexport interface SealedEnvelope {\n /** Envelope schema version. v1 is the current shape. */\n readonly v: 1\n /** Magic marker for forensics + legacy-shape detection. */\n readonly _noydb_sealed: 1\n /** Matches the producing provider's `.id`. Dispatch key on unseal. */\n readonly pid: string\n /** Sealed bytes from the provider, base64-encoded on the wire. */\n readonly payload: string\n}\n\nfunction bytesToBase64(bytes: Uint8Array): string {\n let binary = ''\n for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]!)\n return btoa(binary)\n}\n\nfunction base64ToBytes(b64: string): Uint8Array {\n const binary = atob(b64)\n const out = new Uint8Array(binary.length)\n for (let i = 0; i < binary.length; i++) out[i] = binary.charCodeAt(i)\n return out\n}\n\n/**\n * Parse a `_meta/sealed-passphrase` `_data` JSON string into the\n * in-memory {@link SealedPassphrase} representation. Accepts both:\n *\n * 1. v1 wire format `{ v: 1, _noydb_sealed: 1, pid, payload }` —\n * the current shape.\n * 2. Legacy wire format `{ _noydb_sealed: 1, providerId, sealed }` —\n * read-only; never written\n * going forward.\n *\n * Returns `undefined` for any input that doesn't match either shape,\n * so callers can fall back to \"no managed-mode envelope present.\"\n *\n * @internal — exported only for the migration safety-net test suite.\n */\nexport function parseSealedEnvelope(raw: unknown): SealedPassphrase | undefined {\n if (typeof raw !== 'object' || raw === null) return undefined\n const r = raw as Record<string, unknown>\n if (r._noydb_sealed !== 1) return undefined\n\n // v1 shape — preferred.\n if (\n r.v === 1\n && typeof r.pid === 'string'\n && typeof r.payload === 'string'\n ) {\n return {\n _noydb_sealed: 1,\n providerId: r.pid,\n sealed: base64ToBytes(r.payload),\n }\n }\n\n // Legacy shape — earlier releases. Accept on read for compat.\n if (\n typeof r.providerId === 'string'\n && typeof r.sealed === 'string'\n ) {\n return {\n _noydb_sealed: 1,\n providerId: r.providerId,\n sealed: base64ToBytes(r.sealed),\n }\n }\n\n return undefined\n}\n\nexport async function saveSealedPassphrase(\n store: NoydbStore,\n vault: string,\n payload: { readonly providerId: string; readonly sealed: Uint8Array },\n): Promise<void> {\n const persisted: SealedEnvelope = {\n v: 1,\n _noydb_sealed: 1,\n pid: payload.providerId,\n payload: bytesToBase64(payload.sealed),\n }\n const prior = await store.get(vault, '_meta', SEALED_PASSPHRASE_RECORD_ID)\n const env: EncryptedEnvelope = {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: (prior?._v ?? 0) + 1,\n _ts: new Date().toISOString(),\n // AES-GCM bypassed — the sealing layer is the security boundary.\n _iv: '',\n _data: JSON.stringify(persisted),\n }\n await store.put(vault, '_meta', SEALED_PASSPHRASE_RECORD_ID, env)\n}\n\nexport async function loadSealedPassphrase(\n store: NoydbStore,\n vault: string,\n): Promise<SealedPassphrase | undefined> {\n const envelope = await store.get(vault, '_meta', SEALED_PASSPHRASE_RECORD_ID)\n if (!envelope) return undefined\n try {\n return parseSealedEnvelope(JSON.parse(envelope._data))\n } catch {\n return undefined\n }\n}\n\n// ─── createNoydb orchestration ─────────────────────────────────────────\n\n/**\n * Resolve the effective plaintext passphrase string for a managed-mode\n * vault. Two paths:\n *\n * 1. **First open (no envelope persisted):** generate a 256-bit random\n * via `crypto.getRandomValues`, base64-encode for use as a\n * passphrase string, seal the underlying bytes under the\n * provider, persist `_meta/sealed-passphrase`, return the\n * base64 string.\n *\n * 2. **Reopen (envelope exists):** read + unseal + decode → return.\n * A different provider whose `seal` output disagrees on the\n * stored bytes throws here, surfaced as a clear error.\n *\n * The returned string is the same shape that `secret:` would take in\n * standard mode — the rest of the keyring path consumes it\n * unchanged.\n *\n * @internal — called from `createNoydb` / `getKeyringInternal`.\n */\nexport async function resolveManagedSecret(\n store: NoydbStore,\n vault: string,\n provider: SealingKeyProvider,\n): Promise<string> {\n const existing = await loadSealedPassphrase(store, vault)\n if (existing) {\n if (existing.providerId !== provider.id) {\n throw new Error(\n `Managed-mode vault \"${vault}\" was sealed under provider id `\n + `\"${existing.providerId}\" but the current SealingKeyProvider is `\n + `\"${provider.id}\". Pass the same provider that originally enrolled `\n + 'the vault, or treat this as a fresh enrollment and clear '\n + '`_meta/sealed-passphrase` first.',\n )\n }\n const plaintext = await provider.unseal(existing.sealed)\n return bytesToBase64(plaintext)\n }\n\n // First open: mint a 256-bit random, seal, persist.\n const random = new Uint8Array(32)\n globalThis.crypto.getRandomValues(random)\n const sealed = await provider.seal(random)\n await saveSealedPassphrase(store, vault, { providerId: provider.id, sealed })\n return bytesToBase64(random)\n}\n"],"mappings":"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","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  ValidationError
3
- } from "./chunk-YDLAFP36.js";
3
+ } from "./chunk-6HJ2ZALB.js";
4
4
 
5
5
  // src/guards/with-guard.ts
6
6
  function withGuard(strategy) {
@@ -16,4 +16,4 @@ function withGuard(strategy) {
16
16
  export {
17
17
  withGuard
18
18
  };
19
- //# sourceMappingURL=chunk-5YHWBPOT.js.map
19
+ //# sourceMappingURL=chunk-ED3E3OLO.js.map
@@ -2,7 +2,7 @@ import {
2
2
  DecryptionError,
3
3
  InvalidKeyError,
4
4
  TamperedError
5
- } from "./chunk-YDLAFP36.js";
5
+ } from "./chunk-6HJ2ZALB.js";
6
6
 
7
7
  // src/crypto.ts
8
8
  var PBKDF2_ITERATIONS = 6e5;
@@ -272,4 +272,4 @@ export {
272
272
  bufferToBase64,
273
273
  base64ToBuffer
274
274
  };
275
- //# sourceMappingURL=chunk-UOF74WQY.js.map
275
+ //# sourceMappingURL=chunk-EKTOYEZ3.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  FieldFrozenError,
3
3
  InvariantError
4
- } from "./chunk-YDLAFP36.js";
4
+ } from "./chunk-6HJ2ZALB.js";
5
5
 
6
6
  // src/guards/executor.ts
7
7
  var GuardExecutor = {
@@ -70,4 +70,4 @@ function deepEqual(a, b) {
70
70
  export {
71
71
  GuardExecutor
72
72
  };
73
- //# sourceMappingURL=chunk-SAVQ6E2O.js.map
73
+ //# sourceMappingURL=chunk-G26QAQNI.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  readPath
3
- } from "./chunk-MRIBLZL3.js";
3
+ } from "./chunk-ICH4AIGL.js";
4
4
 
5
5
  // src/indexing/eager-indexes.ts
6
6
  var CollectionIndexes = class {
@@ -129,4 +129,4 @@ function removeFromIndex(idx, id, record) {
129
129
  export {
130
130
  CollectionIndexes
131
131
  };
132
- //# sourceMappingURL=chunk-YMYK7US4.js.map
132
+ //# sourceMappingURL=chunk-HIELMTUK.js.map
@@ -83,4 +83,4 @@ export {
83
83
  evaluateFieldClause,
84
84
  evaluateClause
85
85
  };
86
- //# sourceMappingURL=chunk-MRIBLZL3.js.map
86
+ //# sourceMappingURL=chunk-ICH4AIGL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/query/predicate.ts"],"sourcesContent":["/**\n * Operator implementations for the query DSL.\n *\n * All predicates run client-side, AFTER decryption — they never see ciphertext.\n * This file is dependency-free and tree-shakeable.\n */\n\n/** Comparison operators supported by the where() builder. */\nexport type Operator =\n | '=='\n | '!='\n | '<'\n | '<='\n | '>'\n | '>='\n | 'in'\n | 'contains'\n | 'startsWith'\n | 'between'\n\n/**\n * A single field comparison clause inside a query plan.\n * Plans are JSON-serializable, so this type uses primitives only.\n */\nexport interface FieldClause {\n readonly type: 'field'\n readonly field: string\n readonly op: Operator\n readonly value: unknown\n}\n\n/**\n * A user-supplied predicate function escape hatch. Not serializable.\n *\n * The predicate accepts `unknown` at the type level so the surrounding\n * Clause type can stay non-parametric — this keeps Collection<T> covariant\n * in T at the public API surface. Builder methods cast user predicates\n * (typed `(record: T) => boolean`) into this shape on the way in.\n */\nexport interface FilterClause {\n readonly type: 'filter'\n readonly fn: (record: unknown) => boolean\n}\n\n/**\n * A declared deterministic predicate reference. The query\n * builder produces this via `.wherePredicate(name, ctx?)` when a\n * Query has been augmented with a predicates map (typically by the\n * materialized-view registry — see MV v2 spec § Function-based\n * source-row predicates).\n *\n * `predicateHash` is the consumer-supplied stable hash for the\n * function body; `ctxHash` is the canonical-JSON SHA-256 of `ctx`.\n * Both fold into the MV's `queryHash` so a function or ctx change\n * forces refresh on next visit.\n *\n * `fn` is resolved at builder time from the predicates map and\n * embedded directly — so `evaluateClause` can fire it without a\n * runtime lookup.\n */\nexport interface WherePredicateClause {\n readonly type: 'wherePredicate'\n readonly name: string\n readonly ctx: unknown\n readonly predicateHash: string\n readonly ctxHash: string\n readonly fn: (record: unknown, ctx?: unknown) => boolean\n}\n\n/** A logical group of clauses combined by AND or OR. */\nexport interface GroupClause {\n readonly type: 'group'\n readonly op: 'and' | 'or'\n readonly clauses: readonly Clause[]\n}\n\nexport type Clause = FieldClause | FilterClause | WherePredicateClause | GroupClause\n\n/**\n * Read a possibly nested field path like \"address.city\" from a record.\n * Returns undefined if any segment is missing.\n */\nexport function readPath(record: unknown, path: string): unknown {\n if (record === null || record === undefined) return undefined\n if (!path.includes('.')) {\n return (record as Record<string, unknown>)[path]\n }\n const segments = path.split('.')\n let cursor: unknown = record\n for (const segment of segments) {\n if (cursor === null || cursor === undefined) return undefined\n cursor = (cursor as Record<string, unknown>)[segment]\n }\n return cursor\n}\n\n/**\n * Evaluate a single field clause against a record.\n * Returns false on type mismatches rather than throwing — query results\n * exclude non-matching records by definition.\n */\nexport function evaluateFieldClause(record: unknown, clause: FieldClause): boolean {\n const actual = readPath(record, clause.field)\n const { op, value } = clause\n\n switch (op) {\n case '==':\n return actual === value\n case '!=':\n return actual !== value\n case '<':\n return isComparable(actual, value) && (actual as number) < (value as number)\n case '<=':\n return isComparable(actual, value) && (actual as number) <= (value as number)\n case '>':\n return isComparable(actual, value) && (actual as number) > (value as number)\n case '>=':\n return isComparable(actual, value) && (actual as number) >= (value as number)\n case 'in':\n return Array.isArray(value) && value.includes(actual)\n case 'contains':\n if (typeof actual === 'string') return typeof value === 'string' && actual.includes(value)\n if (Array.isArray(actual)) return actual.includes(value)\n return false\n case 'startsWith':\n return typeof actual === 'string' && typeof value === 'string' && actual.startsWith(value)\n case 'between': {\n if (!Array.isArray(value) || value.length !== 2) return false\n const [lo, hi] = value\n if (!isComparable(actual, lo) || !isComparable(actual, hi)) return false\n return (actual as number) >= (lo as number) && (actual as number) <= (hi as number)\n }\n default: {\n // Exhaustiveness — TS will error if a new operator is added without a case.\n const _exhaustive: never = op\n void _exhaustive\n return false\n }\n }\n}\n\n/**\n * Two values are \"comparable\" if they share an order-defined runtime type.\n * Strings compare lexicographically; numbers and Dates numerically; otherwise false.\n */\nfunction isComparable(a: unknown, b: unknown): boolean {\n if (typeof a === 'number' && typeof b === 'number') return true\n if (typeof a === 'string' && typeof b === 'string') return true\n if (a instanceof Date && b instanceof Date) return true\n return false\n}\n\n/**\n * Evaluate any clause (field / filter / group) against a record.\n * The recursion depth is bounded by the user's query expression — no risk of\n * blowing the stack on a 50K-record collection.\n */\nexport function evaluateClause(record: unknown, clause: Clause): boolean {\n switch (clause.type) {\n case 'field':\n return evaluateFieldClause(record, clause)\n case 'filter':\n return clause.fn(record)\n case 'wherePredicate':\n return clause.fn(record, clause.ctx)\n case 'group':\n if (clause.op === 'and') {\n for (const child of clause.clauses) {\n if (!evaluateClause(record, child)) return false\n }\n return true\n } else {\n for (const child of clause.clauses) {\n if (evaluateClause(record, child)) return true\n }\n return false\n }\n }\n}\n"],"mappings":";AAkFO,SAAS,SAAS,QAAiB,MAAuB;AAC/D,MAAI,WAAW,QAAQ,WAAW,OAAW,QAAO;AACpD,MAAI,CAAC,KAAK,SAAS,GAAG,GAAG;AACvB,WAAQ,OAAmC,IAAI;AAAA,EACjD;AACA,QAAM,WAAW,KAAK,MAAM,GAAG;AAC/B,MAAI,SAAkB;AACtB,aAAW,WAAW,UAAU;AAC9B,QAAI,WAAW,QAAQ,WAAW,OAAW,QAAO;AACpD,aAAU,OAAmC,OAAO;AAAA,EACtD;AACA,SAAO;AACT;AAOO,SAAS,oBAAoB,QAAiB,QAA8B;AACjF,QAAM,SAAS,SAAS,QAAQ,OAAO,KAAK;AAC5C,QAAM,EAAE,IAAI,MAAM,IAAI;AAEtB,UAAQ,IAAI;AAAA,IACV,KAAK;AACH,aAAO,WAAW;AAAA,IACpB,KAAK;AACH,aAAO,WAAW;AAAA,IACpB,KAAK;AACH,aAAO,aAAa,QAAQ,KAAK,KAAM,SAAqB;AAAA,IAC9D,KAAK;AACH,aAAO,aAAa,QAAQ,KAAK,KAAM,UAAsB;AAAA,IAC/D,KAAK;AACH,aAAO,aAAa,QAAQ,KAAK,KAAM,SAAqB;AAAA,IAC9D,KAAK;AACH,aAAO,aAAa,QAAQ,KAAK,KAAM,UAAsB;AAAA,IAC/D,KAAK;AACH,aAAO,MAAM,QAAQ,KAAK,KAAK,MAAM,SAAS,MAAM;AAAA,IACtD,KAAK;AACH,UAAI,OAAO,WAAW,SAAU,QAAO,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK;AACzF,UAAI,MAAM,QAAQ,MAAM,EAAG,QAAO,OAAO,SAAS,KAAK;AACvD,aAAO;AAAA,IACT,KAAK;AACH,aAAO,OAAO,WAAW,YAAY,OAAO,UAAU,YAAY,OAAO,WAAW,KAAK;AAAA,IAC3F,KAAK,WAAW;AACd,UAAI,CAAC,MAAM,QAAQ,KAAK,KAAK,MAAM,WAAW,EAAG,QAAO;AACxD,YAAM,CAAC,IAAI,EAAE,IAAI;AACjB,UAAI,CAAC,aAAa,QAAQ,EAAE,KAAK,CAAC,aAAa,QAAQ,EAAE,EAAG,QAAO;AACnE,aAAQ,UAAsB,MAAkB,UAAsB;AAAA,IACxE;AAAA,IACA,SAAS;AAEP,YAAM,cAAqB;AAC3B,WAAK;AACL,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAMA,SAAS,aAAa,GAAY,GAAqB;AACrD,MAAI,OAAO,MAAM,YAAY,OAAO,MAAM,SAAU,QAAO;AAC3D,MAAI,OAAO,MAAM,YAAY,OAAO,MAAM,SAAU,QAAO;AAC3D,MAAI,aAAa,QAAQ,aAAa,KAAM,QAAO;AACnD,SAAO;AACT;AAOO,SAAS,eAAe,QAAiB,QAAyB;AACvE,UAAQ,OAAO,MAAM;AAAA,IACnB,KAAK;AACH,aAAO,oBAAoB,QAAQ,MAAM;AAAA,IAC3C,KAAK;AACH,aAAO,OAAO,GAAG,MAAM;AAAA,IACzB,KAAK;AACH,aAAO,OAAO,GAAG,QAAQ,OAAO,GAAG;AAAA,IACrC,KAAK;AACH,UAAI,OAAO,OAAO,OAAO;AACvB,mBAAW,SAAS,OAAO,SAAS;AAClC,cAAI,CAAC,eAAe,QAAQ,KAAK,EAAG,QAAO;AAAA,QAC7C;AACA,eAAO;AAAA,MACT,OAAO;AACL,mBAAW,SAAS,OAAO,SAAS;AAClC,cAAI,eAAe,QAAQ,KAAK,EAAG,QAAO;AAAA,QAC5C;AACA,eAAO;AAAA,MACT;AAAA,EACJ;AACF;","names":[]}
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  NOYDB_FORMAT_VERSION
3
- } from "./chunk-FXQYZNOW.js";
3
+ } from "./chunk-5OVIFUQE.js";
4
4
  import {
5
5
  encrypt
6
- } from "./chunk-UOF74WQY.js";
6
+ } from "./chunk-EKTOYEZ3.js";
7
7
 
8
8
  // src/blobs/export-blobs.ts
9
9
  var ExportBlobsAbortedError = class extends Error {
@@ -230,4 +230,4 @@ export {
230
230
  BLOB_EVICTION_AUDIT_COLLECTION,
231
231
  runCompaction
232
232
  };
233
- //# sourceMappingURL=chunk-LOL725S4.js.map
233
+ //# sourceMappingURL=chunk-JSYTGEX4.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  NOYDB_FORMAT_VERSION
3
- } from "./chunk-FXQYZNOW.js";
3
+ } from "./chunk-5OVIFUQE.js";
4
4
  import {
5
5
  base64ToBuffer,
6
6
  bufferToBase64,
@@ -10,11 +10,11 @@ import {
10
10
  encryptBytesWithAAD,
11
11
  hmacSha256Hex,
12
12
  sha256Hex
13
- } from "./chunk-UOF74WQY.js";
13
+ } from "./chunk-EKTOYEZ3.js";
14
14
  import {
15
15
  ConflictError,
16
16
  NotFoundError
17
- } from "./chunk-YDLAFP36.js";
17
+ } from "./chunk-6HJ2ZALB.js";
18
18
 
19
19
  // src/blobs/mime-magic.ts
20
20
  function hex(s) {
@@ -820,7 +820,7 @@ var BlobSet = class {
820
820
  return this.buildResponse(slot, result.blob, { inline: true });
821
821
  }
822
822
  const aad = chunkAAD(slot.eTag, 0, result.blob.chunkCount);
823
- const { decryptBytesWithAAD: decryptAAD } = await import("./crypto-H2Y3DDFW.js");
823
+ const { decryptBytesWithAAD: decryptAAD } = await import("./crypto-5UDZZL26.js");
824
824
  const decrypted = await decryptAAD(envelope._iv, envelope._data, blobDEK, aad);
825
825
  const plaintext = result.blob.compression === "gzip" ? await decompressBytes(decrypted) : decrypted;
826
826
  const body = new ReadableStream({
@@ -883,4 +883,4 @@ export {
883
883
  DEFAULT_CHUNK_SIZE,
884
884
  BlobSet
885
885
  };
886
- //# sourceMappingURL=chunk-FBMXWVGP.js.map
886
+ //# sourceMappingURL=chunk-KGFV72WK.js.map
@@ -6,11 +6,11 @@ import {
6
6
  ConflictError,
7
7
  InvariantError,
8
8
  ValidationError
9
- } from "./chunk-YDLAFP36.js";
9
+ } from "./chunk-6HJ2ZALB.js";
10
10
 
11
11
  // src/tx/transaction.ts
12
12
  var TxContext = class {
13
- /** Stable id for this transaction; shared by all writes it performs (#230). */
13
+ /** Stable id for this transaction; shared by all writes it performs. */
14
14
  txId = generateULID();
15
15
  /** @internal */
16
16
  _ops = [];
@@ -20,7 +20,7 @@ var TxContext = class {
20
20
  * restore prior state via `revertExecuted`. Side-effect writes (e.g.
21
21
  * recursive derivation outputs fired inside `Collection.put`) are
22
22
  * appended here in execution order so they roll back alongside the
23
- * main staged ops (#133).
23
+ * main staged ops.
24
24
  */
25
25
  _executed = [];
26
26
  /** @internal */
@@ -209,7 +209,7 @@ async function runTransaction(db, fn, options) {
209
209
  db._clearActiveTxContext(ctx);
210
210
  }
211
211
  if (ctx._amendment) {
212
- const { GuardExecutor } = await import("./executor-BZKFZVRC.js");
212
+ const { GuardExecutor } = await import("./executor-AWCHQ2KN.js");
213
213
  try {
214
214
  for (const [vaultName, v] of ctx._amendmentVaults) {
215
215
  const registry = v._getGuardRegistry();
@@ -293,4 +293,4 @@ export {
293
293
  runTransaction,
294
294
  revertExecuted
295
295
  };
296
- //# sourceMappingURL=chunk-GVXBHCZ2.js.map
296
+ //# sourceMappingURL=chunk-LJO6Q3X6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/tx/transaction.ts"],"sourcesContent":["/**\n * Multi-record atomic transactions.\n *\n * Lets an application stage writes across two or more collections (or\n * vaults) and commit them all-or-nothing.\n *\n * ```ts\n * await db.transaction(async (tx) => {\n * const inv = tx.vault('acme').collection<Invoice>('invoices')\n * const pay = tx.vault('acme').collection<Payment>('payments')\n * await inv.put(invoiceId, { ...invoice, status: 'paid' })\n * await pay.put(paymentId, { invoiceId, amount, paidAt })\n * })\n * // If the body throws before returning: nothing persisted.\n * // If the body returns: all puts committed; any CAS mismatch rolls\n * // the batch back and surfaces as ConflictError.\n * ```\n *\n * ## Atomicity semantics\n *\n * Ops are buffered during the body. On body-return the hub:\n *\n * 1. **Pre-flight** — re-reads every touched envelope and enforces\n * any caller-supplied `expectedVersion`. A mismatch throws\n * `ConflictError` with *no* writes performed.\n * 2. **Execute** — calls `Collection.put()` / `.delete()` for each\n * staged op in declaration order. History snapshots, ledger\n * appends, and change events fire as normal per op.\n * 3. **Unwind on failure** — if step 2 throws mid-batch, each\n * already-committed op is reverted via the raw store (restoring\n * the captured prior envelope, or deleting if none existed). The\n * ledger is NOT rewritten — audit history preserves the partial\n * commit and the revert.\n *\n * **Crash window.** Steps 2–3 are not a storage-layer transaction —\n * if the process dies between two executed ops, the on-disk state is\n * partial. True all-or-nothing atomicity requires a store that\n * implements `NoydbStore.tx()` (DynamoDB `TransactWriteItems`,\n * IndexedDB `readwrite` transaction, …). This executor declares\n * that future integration point via the `tx?()` method + the\n * `StoreCapabilities.txAtomic` bit, but does not yet delegate\n * to it — the cascade into `Fork · Stores` tracks the per-adapter\n * wire-up.\n *\n * ## Not covered\n *\n * - Cross-sync-peer atomicity. Transactions commit against the\n * primary store only; the sync engine pushes on its normal\n * schedule. For cross-peer two-phase commit use `SyncTransaction`\n * via `db.transaction(vaultName)`.\n * - Read-your-writes within the body. `tx.collection().get(id)`\n * returns the most-recently-staged value for that id when one\n * exists; if no staged op has touched the id, it reads the current\n * committed state. Version numbers returned by `get` reflect the\n * pre-transaction state (staged puts have no version yet).\n *\n * @module\n */\n\nimport type { Noydb } from '../noydb.js'\nimport type { Vault } from '../vault.js'\nimport type { Collection } from '../collection.js'\nimport type { EncryptedEnvelope } from '../types.js'\nimport {\n AmendmentForbiddenError,\n ConflictError,\n InvariantError,\n ValidationError,\n} from '../errors.js'\nimport { generateULID } from '../bundle/ulid.js'\nimport type { GuardExecutor as GuardExecutorModule } from '../guards/executor.js'\nimport type { LedgerEntry } from '../history/ledger/entry.js'\n\n/** One op buffered inside a running `TxContext`. @internal */\nexport interface StagedOp {\n type: 'put' | 'delete'\n vaultName: string\n collectionName: string\n id: string\n record?: unknown\n expectedVersion?: number\n /**\n * Optional human-readable tag forwarded to the resulting ledger\n * entry's `reason` field. Set by callers via\n * `tx.vault(v).collection(c).put(id, record, { reason })`.\n */\n reason?: string\n}\n\n/**\n * One executed op (main staged op or recursive side-effect like a\n * derivation output) paired with the envelope captured before the write.\n * `revertExecuted` walks this array in reverse on rollback.\n * @internal\n */\nexport interface ExecutedOp {\n op: StagedOp\n priorEnvelope: EncryptedEnvelope | null\n}\n\n/**\n * Options accepted by `db.transaction({ amendment, reason }, fn)`.\n * Only the amendment variant uses these — a plain `db.transaction(fn)`\n * never sees this shape.\n */\nexport interface AmendmentTxOptions {\n /** Opt into amendment mode. Required to be `true`. */\n readonly amendment: true\n /** Human-readable rationale recorded in the ledger entry. Required. */\n readonly reason: string\n}\n\n/**\n * Transaction handle passed to the user's body. Use\n * `tx.vault(name).collection<T>(name)` to get a per-collection\n * facade; its `put`/`delete`/`get` calls stage ops against the tx.\n */\nexport class TxContext {\n /** Stable id for this transaction; shared by all writes it performs. */\n readonly txId: string = generateULID()\n /** @internal */\n readonly _ops: StagedOp[] = []\n /**\n * @internal — write log built up in Phase 2. Each entry records the\n * envelope captured BEFORE the write so a mid-batch failure can\n * restore prior state via `revertExecuted`. Side-effect writes (e.g.\n * recursive derivation outputs fired inside `Collection.put`) are\n * appended here in execution order so they roll back alongside the\n * main staged ops.\n */\n readonly _executed: ExecutedOp[] = []\n /** @internal */\n readonly _db: Noydb\n /**\n * @internal — true when this TxContext was opened in amendment\n * mode. Toggles the lazy-`beginAmendment` + role-check path on first\n * `tx.vault(name)` and unlocks the post-Phase-2 invariant + audit run.\n */\n readonly _amendment: boolean\n /** @internal — vaults that have already had `beginAmendment` called. */\n readonly _amendmentVaults = new Map<string, Vault>()\n\n /** @internal */\n constructor(db: Noydb, amendment = false) {\n this._db = db\n this._amendment = amendment\n }\n\n /** Scope subsequent `collection()` calls to the named vault. */\n vault(name: string): TxVault {\n const v = this._db.vault(name)\n if (this._amendment && !this._amendmentVaults.has(name)) {\n // Role check is per-vault. The task spec (\"only admin or owner\n // can open an amendment\") is implemented lazy-on-first-touch\n // because the role lives on the vault's keyring, and `tx.vault()`\n // is the first place we know which vault we're addressing. The\n // observable effect is identical to an eager check in the single-\n // vault case the tests exercise; multi-vault amendments check\n // each touched vault as they first appear.\n const role = v.role\n if (role !== 'admin' && role !== 'owner') {\n throw new AmendmentForbiddenError(v.userId, role)\n }\n // Amendments require an initialised guard registry — they\n // produce a structured invariant + change-set audit. A vault\n // opened without `guardStrategies` (or via the sync fallback\n // path) has a null registry and cannot run an amendment.\n const reg = v._getGuardRegistry()\n if (reg === null) {\n throw new ValidationError(\n `Vault \"${name}\": amendment mode requires at least one ` +\n `guardStrategy registered via createNoydb({ guardStrategies }). ` +\n `Open the vault with guardStrategies before calling ` +\n `db.transaction({ amendment: true }).`,\n )\n }\n reg.beginAmendment()\n this._amendmentVaults.set(name, v)\n }\n return new TxVault(this, v)\n }\n}\n\n/** Per-vault facade inside a running transaction. */\nexport class TxVault {\n /** @internal */\n readonly _ctx: TxContext\n /** @internal */\n readonly _vault: Vault\n\n /** @internal */\n constructor(ctx: TxContext, vault: Vault) {\n this._ctx = ctx\n this._vault = vault\n }\n\n /** Scope subsequent op calls to the named collection. */\n collection<T>(name: string): TxCollection<T> {\n const c = this._vault.collection<T>(name)\n return new TxCollection<T>(this._ctx, this._vault, c, name)\n }\n}\n\n/** Per-collection facade inside a running transaction. */\nexport class TxCollection<T> {\n /** @internal */\n readonly _ctx: TxContext\n /** @internal */\n readonly _vault: Vault\n /** @internal */\n readonly _coll: Collection<T>\n /** @internal */\n readonly _name: string\n\n /** @internal */\n constructor(ctx: TxContext, vault: Vault, coll: Collection<T>, name: string) {\n this._ctx = ctx\n this._vault = vault\n this._coll = coll\n this._name = name\n }\n\n /**\n * Read the current committed value, or the most-recently-staged\n * value from the same transaction if one exists.\n */\n async get(id: string): Promise<T | null> {\n for (let i = this._ctx._ops.length - 1; i >= 0; i--) {\n const op = this._ctx._ops[i]!\n if (\n op.vaultName === this._vault.name &&\n op.collectionName === this._name &&\n op.id === id\n ) {\n if (op.type === 'delete') return null\n return op.record as T\n }\n }\n return this._coll.get(id)\n }\n\n /**\n * Stage a put. Does not write until the transaction body returns.\n * Supply `{ expectedVersion }` to enforce optimistic concurrency\n * during the commit pre-flight.\n */\n put(id: string, record: T, options?: { expectedVersion?: number; reason?: string }): void {\n const op: StagedOp = {\n type: 'put',\n vaultName: this._vault.name,\n collectionName: this._name,\n id,\n record,\n }\n if (options?.expectedVersion !== undefined) op.expectedVersion = options.expectedVersion\n if (options?.reason !== undefined) op.reason = options.reason\n this._ctx._ops.push(op)\n }\n\n /**\n * Stage a delete. Does not write until the transaction body returns.\n * Supply `{ expectedVersion }` to enforce optimistic concurrency\n * during the commit pre-flight.\n */\n delete(id: string, options?: { expectedVersion?: number }): void {\n const op: StagedOp = {\n type: 'delete',\n vaultName: this._vault.name,\n collectionName: this._name,\n id,\n }\n if (options?.expectedVersion !== undefined) op.expectedVersion = options.expectedVersion\n this._ctx._ops.push(op)\n }\n}\n\n/**\n * Commit plan: pre-flight check + execution + revert plan.\n *\n * @internal — driven by `withTransactions()` (via `tx/active.ts`) for\n * user-facing `db.transaction(...)` calls and by the `amendment` path\n * in `noydb.ts`. `Collection.putManyAtomic` runs its own Phase 2 loop\n * but shares the `_activeTxContext` mechanism (and the `revertExecuted`\n * helper) so nested side-effect derivation writes get registered for\n * revert alongside the bulk-put source ops.\n */\nexport async function runTransaction<T>(\n db: Noydb,\n fn: (tx: TxContext) => Promise<T> | T,\n options?: AmendmentTxOptions,\n): Promise<T> {\n // ─── Amendment-mode pre-flight ───────────────────────────────\n // `reason` is the only thing we can validate before the body runs;\n // the per-vault role check happens lazily on first `tx.vault(name)`\n // because we don't know which vaults the body will touch ahead of\n // time. Throwing here keeps the failure mode close to the call site\n // so the developer doesn't have to walk an async stack to find the\n // missing-reason mistake.\n if (options?.amendment) {\n if (typeof options.reason !== 'string' || options.reason.trim().length === 0) {\n throw new ValidationError(\n 'db.transaction({ amendment: true }) requires a non-empty `reason` string.',\n )\n }\n }\n\n const ctx = new TxContext(db, options?.amendment === true)\n const bodyResult = await fn(ctx)\n\n if (ctx._ops.length === 0) {\n // Body produced no ops. If amendment mode was active we still\n // need to close any opened windows so a subsequent (unrelated)\n // write doesn't surprise-collect into a stale change-set. Each\n // `beginAmendment` is matched by exactly one `consumeChanges`.\n if (ctx._amendment) {\n for (const v of ctx._amendmentVaults.values()) {\n // Registry is guaranteed non-null here — `tx.vault(name)`\n // threw above if it was null before adding to\n // `_amendmentVaults`.\n const reg = v._getGuardRegistry()\n if (reg !== null) {\n reg.consumeChanges()\n reg.consumeMeta()\n }\n }\n }\n return bodyResult\n }\n\n // Phase 1 — pre-flight: snapshot every touched envelope and enforce\n // any caller-supplied expectedVersion. Same (vault, coll, id) touched\n // more than once in one tx snapshots only the *initial* committed\n // state; the in-order replay in Phase 2 takes care of successor ops.\n const priorEnvelopes = new Map<string, EncryptedEnvelope | null>()\n const store = db._store\n for (const op of ctx._ops) {\n const key = keyOf(op)\n if (!priorEnvelopes.has(key)) {\n const env = await store.get(op.vaultName, op.collectionName, op.id)\n priorEnvelopes.set(key, env)\n }\n if (op.expectedVersion !== undefined) {\n const env = priorEnvelopes.get(key) ?? null\n const actual = env?._v ?? 0\n if (actual !== op.expectedVersion) {\n throw new ConflictError(\n actual,\n `Transaction pre-flight: ${op.vaultName}/${op.collectionName}/${op.id} ` +\n `expected v${op.expectedVersion}, found v${actual}`,\n )\n }\n }\n }\n\n // Phase 2 — execute via the Collection layer so history snapshots,\n // ledger entries, and change events fire normally. We capture each\n // successful op so a mid-batch throw can revert in Phase 3.\n //\n // `_activeTxContext` is published on the Noydb instance for the\n // duration of Phase 2 so recursive writes triggered inside\n // `Collection.put` (today: eager derivation outputs) can register\n // their own envelopes onto `ctx._executed` and roll back alongside\n // the main staged ops. The `finally` clears it before the\n // amendment commit phase runs.\n db._setActiveTxContext(ctx)\n try {\n try {\n for (const op of ctx._ops) {\n const coll = db.vault(op.vaultName).collection(op.collectionName)\n const key = keyOf(op)\n const prior = priorEnvelopes.get(key) ?? null\n // Record the revert plan BEFORE the call so a mid-`coll.put` throw\n // (e.g. strict-mode derivation failure firing after `store.put`\n // has already committed the envelope) still has its source write\n // reverted. `revertExecuted` is best-effort: putting prior back is\n // idempotent when the failing op never actually wrote, and\n // `_invalidateCacheEntry` is a no-op when the collection isn't\n // hydrated.\n ctx._executed.push({ op, priorEnvelope: prior })\n if (op.type === 'put') {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n await coll.put(op.id, op.record as any, op.reason !== undefined ? { reason: op.reason } : undefined)\n } else {\n await coll.delete(op.id)\n }\n }\n } catch (err) {\n // Phase 3 — best-effort revert. See helper docstring.\n await revertExecuted(ctx._executed, store, db)\n // Drain amendment windows so the next transaction starts clean.\n if (ctx._amendment) {\n for (const v of ctx._amendmentVaults.values()) {\n const reg = v._getGuardRegistry()\n if (reg !== null) {\n reg.consumeChanges()\n reg.consumeMeta()\n }\n }\n }\n throw err\n }\n } finally {\n db._clearActiveTxContext(ctx)\n }\n\n // ─── Amendment commit phase (only if amendment === true) ────\n // Body succeeded — now run each touched vault's invariants over the\n // collected change-set, then append a structured ledger entry. If\n // any invariant throws, treat it exactly like a mid-Phase-2 failure:\n // revert every executed op and re-throw the InvariantError.\n if (ctx._amendment) {\n // Lazy-load GuardExecutor at the dispatch site — keeps the floor\n // bundle free of the guards subsystem when amendments aren't used.\n // Mirrors the deferred-load pattern from elsewhere in this module.\n const { GuardExecutor } = (await import('../guards/executor.js')) as {\n GuardExecutor: typeof GuardExecutorModule\n }\n try {\n for (const [vaultName, v] of ctx._amendmentVaults) {\n const registry = v._getGuardRegistry()\n // Registry is guaranteed non-null at this point — the\n // `tx.vault(name)` path that populates `_amendmentVaults`\n // throws if the registry is null. The defensive check here\n // is for TypeScript's narrowing.\n if (registry === null) continue\n const changesByCollection = registry.consumeChanges()\n const meta = registry.consumeMeta()\n if (changesByCollection.size === 0) continue\n\n const readOnlyVault = v._getReadOnlyFacade()\n if (readOnlyVault === null) continue\n\n // Build the invariant ctx once per vault — it's the same shape\n // every guard sees on the normal `check` path, just with a\n // synthetic `existing: null` (invariants get the full change\n // set in their first parameter; `existing` is a per-record\n // concept that doesn't apply here).\n const invariantsPassed: string[] = []\n for (const [collection, changes] of changesByCollection) {\n const guards = registry.guardsFor(collection).filter(g => g.amendment !== undefined)\n for (const guard of guards) {\n await GuardExecutor.runInvariant(guard, changes, {\n existing: null,\n vault: readOnlyVault,\n userId: v.userId,\n role: v.role,\n })\n }\n if (guards.length > 0) invariantsPassed.push(collection)\n }\n\n // Append the audit ledger entry. Silent no-op when the\n // history strategy isn't configured — the records still\n // committed, only the multi-record summary is unavailable.\n const ledger = v._getLedgerOrNull()\n if (ledger) {\n const role = v.role as 'admin' | 'owner'\n const amendment: NonNullable<LedgerEntry['amendment']> = {\n reason: options!.reason,\n role,\n changes: meta,\n invariantsPassed,\n }\n await ledger.append({\n op: 'amendment',\n collection: '',\n id: '',\n version: 0,\n actor: v.userId,\n // No payload to hash — the per-record entries already\n // captured `payloadHash` at their own append time. We use\n // a sha256 of the canonical reason string so the field is\n // populated with something deterministic and non-empty.\n payloadHash: '',\n amendment,\n })\n }\n void vaultName\n }\n } catch (err) {\n await revertExecuted(ctx._executed, store, db)\n throw err instanceof InvariantError ? err : new InvariantError(\n err instanceof Error ? err.message : `invariant violated: ${String(err)}`,\n )\n }\n }\n\n return bodyResult\n}\n\n/**\n * Phase 3 helper — restore captured prior envelopes via the raw store\n * to avoid re-firing Collection-level side effects (we don't want a\n * cascade of change events undoing themselves). The ledger is left\n * as-is: each committed op appended an entry; the revert is\n * deliberately NOT recorded as a compensating entry because the\n * caller-facing contract is \"atomic or not at all,\" not \"every write\n * visible in the audit trail.\" Auditors who need the intermediate\n * state can still reconstruct it by walking the ledger through the\n * failed-tx timestamp.\n *\n * @internal — shared between `runTransaction` and\n * `Collection.putManyAtomic`. Both register source ops + nested\n * derivation side-effect ops onto `_executed`; this helper unwinds the\n * combined list in reverse on rollback.\n */\nexport async function revertExecuted(\n executed: ReadonlyArray<ExecutedOp>,\n store: Noydb['_store'],\n db?: Noydb,\n): Promise<void> {\n for (const { op, priorEnvelope } of executed.slice().reverse()) {\n try {\n if (priorEnvelope) {\n await store.put(op.vaultName, op.collectionName, op.id, priorEnvelope)\n } else {\n await store.delete(op.vaultName, op.collectionName, op.id)\n }\n // Sync the Collection-layer cache with what we just wrote at\n // the raw store. Without this, eager-mode `get` would still\n // return the rolled-back record from its in-memory map. The\n // Collection's `_invalidateCacheEntry` is a no-op when the\n // collection hasn't yet been hydrated.\n if (db) {\n const coll = db.vault(op.vaultName).collection(op.collectionName)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n await (coll as any)._invalidateCacheEntry(op.id)\n }\n } catch {\n // swallow — best-effort. Surfacing the revert error would mask\n // the original one that triggered the rollback.\n }\n }\n}\n\nfunction keyOf(op: StagedOp): string {\n return `${op.vaultName}\\x00${op.collectionName}\\x00${op.id}`\n}\n"],"mappings":"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","names":[]}
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  MaterializedViewConfigError,
3
3
  ValidationError
4
- } from "./chunk-YDLAFP36.js";
4
+ } from "./chunk-6HJ2ZALB.js";
5
5
 
6
6
  // src/materialized-views/with-materialized-view.ts
7
7
  function withMaterializedView(spec) {
@@ -79,4 +79,4 @@ function withMaterializedView(spec) {
79
79
  export {
80
80
  withMaterializedView
81
81
  };
82
- //# sourceMappingURL=chunk-ZC2AAE6J.js.map
82
+ //# sourceMappingURL=chunk-LWFQYT4N.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/materialized-views/with-materialized-view.ts"],"sourcesContent":["import { MaterializedViewConfigError, ValidationError } from '../errors.js'\nimport type { MaterializedViewStrategy, MaterializedViewStrategyHandle } from './types.js'\n\n/**\n * Register a materialized view: a declared query whose result is\n * persisted as a queryable collection and kept fresh as sources\n * change. Writes go through the standard `Collection.put` pipeline;\n * refresh-driven deletes route through `Collection._internalDelete` so\n * user `onDelete` guards on the output collection aren't tripped by\n * housekeeping.\n *\n * Two registration modes:\n * - **single-source** — declare `query: (db) => Query<TRow>`; the\n * dependency analyzer derives source collections from the plan.\n * - **UNION** — declare `unionSources: [{ collection, map }, ...]`\n * plus optional `groupBy` + `aggregate`; the executor reads each\n * arm, maps to the unified row shape, concatenates, then groups\n * and aggregates.\n *\n * The two modes are mutually exclusive — exactly one of `query` /\n * `unionSources` must be set at registration time.\n *\n * See docs/superpowers/specs/2026-05-20-dim14-mv-v2-design.md (single-source v2)\n * and docs/superpowers/specs/2026-05-21-dim14-mv-multikey-and-union.md (UNION).\n */\nexport function withMaterializedView<TRow extends Record<string, unknown>>(\n spec: MaterializedViewStrategy<TRow>,\n): MaterializedViewStrategyHandle {\n if (!spec.name || spec.name.length === 0) {\n throw new ValidationError('withMaterializedView: name is required')\n }\n // Mutual exclusion: query and unionSources cannot coexist.\n if (spec.query && spec.unionSources) {\n throw new MaterializedViewConfigError(\n 'query and unionSources are mutually exclusive — pick one',\n )\n }\n // Strategy must declare one of the two.\n if (!spec.query && !spec.unionSources) {\n throw new MaterializedViewConfigError(\n 'strategy must declare either query or unionSources',\n )\n }\n if (spec.query !== undefined && typeof spec.query !== 'function') {\n throw new ValidationError('withMaterializedView: query must be a function returning a Query<T>')\n }\n // UNION-form invariants.\n if (spec.unionSources) {\n if (spec.unionSources.length < 2) {\n throw new MaterializedViewConfigError(\n 'unionSources requires at least 2 source collections',\n )\n }\n const seen = new Set<string>()\n for (const s of spec.unionSources) {\n if (typeof s?.collection !== 'string' || s.collection.length === 0) {\n throw new MaterializedViewConfigError(\n 'each unionSources entry must declare a non-empty `collection` string',\n )\n }\n if (typeof s.map !== 'function') {\n throw new MaterializedViewConfigError(\n `unionSources entry for \"${s.collection}\" is missing a \\`map\\` function`,\n )\n }\n if (seen.has(s.collection)) {\n throw new MaterializedViewConfigError(\n `unionSources must reference distinct collections (duplicate: \"${s.collection}\")`,\n )\n }\n seen.add(s.collection)\n }\n if (Array.isArray(spec.groupBy) && spec.groupBy.length === 0) {\n throw new MaterializedViewConfigError(\n `withMaterializedView \"${spec.name}\": groupBy must not be an empty array — omit it or provide at least one field name`,\n )\n }\n if (spec.aggregate && !spec.groupBy) {\n throw new MaterializedViewConfigError(\n `withMaterializedView \"${spec.name}\": UNION strategy with aggregate requires groupBy — `\n + `use groupBy to declare the bucketing keys, or remove aggregate for a pure dedup MV`,\n )\n }\n if (spec.predicates) {\n throw new MaterializedViewConfigError(\n `withMaterializedView \"${spec.name}\": predicates are not supported on UNION strategies — `\n + `UNION mode does not use a Query<T> chain, so .wherePredicate() cannot fire. `\n + `Use the query() form, or open an issue if per-arm predicates are needed`,\n )\n }\n }\n if (typeof spec.rowKey !== 'function') {\n throw new ValidationError('withMaterializedView: rowKey is required (no default; see spec § Type surface)')\n }\n if (spec.refresh !== 'eager' && spec.refresh !== 'lazy' && spec.refresh !== 'manual') {\n throw new ValidationError(\n `withMaterializedView: refresh must be 'eager' | 'lazy' | 'manual', got \"${String(spec.refresh)}\"`,\n )\n }\n return {\n __noydb_strategy: 'materialized-view',\n spec,\n }\n}\n"],"mappings":";;;;;;AAyBO,SAAS,qBACd,MACgC;AAChC,MAAI,CAAC,KAAK,QAAQ,KAAK,KAAK,WAAW,GAAG;AACxC,UAAM,IAAI,gBAAgB,wCAAwC;AAAA,EACpE;AAEA,MAAI,KAAK,SAAS,KAAK,cAAc;AACnC,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,MAAI,CAAC,KAAK,SAAS,CAAC,KAAK,cAAc;AACrC,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,MAAI,KAAK,UAAU,UAAa,OAAO,KAAK,UAAU,YAAY;AAChE,UAAM,IAAI,gBAAgB,qEAAqE;AAAA,EACjG;AAEA,MAAI,KAAK,cAAc;AACrB,QAAI,KAAK,aAAa,SAAS,GAAG;AAChC,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,UAAM,OAAO,oBAAI,IAAY;AAC7B,eAAW,KAAK,KAAK,cAAc;AACjC,UAAI,OAAO,GAAG,eAAe,YAAY,EAAE,WAAW,WAAW,GAAG;AAClE,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AAAA,MACF;AACA,UAAI,OAAO,EAAE,QAAQ,YAAY;AAC/B,cAAM,IAAI;AAAA,UACR,2BAA2B,EAAE,UAAU;AAAA,QACzC;AAAA,MACF;AACA,UAAI,KAAK,IAAI,EAAE,UAAU,GAAG;AAC1B,cAAM,IAAI;AAAA,UACR,iEAAiE,EAAE,UAAU;AAAA,QAC/E;AAAA,MACF;AACA,WAAK,IAAI,EAAE,UAAU;AAAA,IACvB;AACA,QAAI,MAAM,QAAQ,KAAK,OAAO,KAAK,KAAK,QAAQ,WAAW,GAAG;AAC5D,YAAM,IAAI;AAAA,QACR,yBAAyB,KAAK,IAAI;AAAA,MACpC;AAAA,IACF;AACA,QAAI,KAAK,aAAa,CAAC,KAAK,SAAS;AACnC,YAAM,IAAI;AAAA,QACR,yBAAyB,KAAK,IAAI;AAAA,MAEpC;AAAA,IACF;AACA,QAAI,KAAK,YAAY;AACnB,YAAM,IAAI;AAAA,QACR,yBAAyB,KAAK,IAAI;AAAA,MAGpC;AAAA,IACF;AAAA,EACF;AACA,MAAI,OAAO,KAAK,WAAW,YAAY;AACrC,UAAM,IAAI,gBAAgB,mFAAgF;AAAA,EAC5G;AACA,MAAI,KAAK,YAAY,WAAW,KAAK,YAAY,UAAU,KAAK,YAAY,UAAU;AACpF,UAAM,IAAI;AAAA,MACR,2EAA2E,OAAO,KAAK,OAAO,CAAC;AAAA,IACjG;AAAA,EACF;AACA,SAAO;AAAA,IACL,kBAAkB;AAAA,IAClB;AAAA,EACF;AACF;","names":[]}
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  decrypt,
6
6
  encrypt
7
- } from "./chunk-UOF74WQY.js";
7
+ } from "./chunk-EKTOYEZ3.js";
8
8
 
9
9
  // src/consent/consent.ts
10
10
  var CONSENT_AUDIT_COLLECTION = "_consent_audit";
@@ -69,4 +69,4 @@ export {
69
69
  writeConsentEntry,
70
70
  loadConsentEntries
71
71
  };
72
- //# sourceMappingURL=chunk-K5PVGKE4.js.map
72
+ //# sourceMappingURL=chunk-MDIC4FAU.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  LocaleNotSpecifiedError,
3
3
  MissingTranslationError
4
- } from "./chunk-YDLAFP36.js";
4
+ } from "./chunk-6HJ2ZALB.js";
5
5
 
6
6
  // src/i18n/core.ts
7
7
  function i18nText(options) {
@@ -115,4 +115,4 @@ export {
115
115
  resolveI18nText,
116
116
  applyI18nLocale
117
117
  };
118
- //# sourceMappingURL=chunk-A6SWRXUQ.js.map
118
+ //# sourceMappingURL=chunk-NONMIU6C.js.map
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  NOYDB_FORMAT_VERSION
3
- } from "./chunk-FXQYZNOW.js";
3
+ } from "./chunk-5OVIFUQE.js";
4
4
  import {
5
5
  decrypt,
6
6
  encrypt
7
- } from "./chunk-UOF74WQY.js";
7
+ } from "./chunk-EKTOYEZ3.js";
8
8
  import {
9
9
  ConflictError
10
- } from "./chunk-YDLAFP36.js";
10
+ } from "./chunk-6HJ2ZALB.js";
11
11
 
12
12
  // src/attestation/signer.ts
13
13
  import { generateDocSigningKeyPair } from "@noy-db/attestation";
@@ -54,4 +54,4 @@ export {
54
54
  loadSigner,
55
55
  loadOrCreateSigner
56
56
  };
57
- //# sourceMappingURL=chunk-ZUMGGHRB.js.map
57
+ //# sourceMappingURL=chunk-OPD3PZOG.js.map
@@ -3,17 +3,17 @@ import {
3
3
  } from "./chunk-2QR2PQTT.js";
4
4
  import {
5
5
  NOYDB_SYNC_VERSION
6
- } from "./chunk-FXQYZNOW.js";
6
+ } from "./chunk-5OVIFUQE.js";
7
7
  import {
8
8
  bufferToBase64,
9
9
  decrypt,
10
10
  derivePresenceKey,
11
11
  encrypt,
12
12
  generateIV
13
- } from "./chunk-UOF74WQY.js";
13
+ } from "./chunk-EKTOYEZ3.js";
14
14
  import {
15
15
  ConflictError
16
- } from "./chunk-YDLAFP36.js";
16
+ } from "./chunk-6HJ2ZALB.js";
17
17
 
18
18
  // src/team/presence.ts
19
19
  var PresenceHandle = class {
@@ -719,4 +719,4 @@ export {
719
719
  SyncEngine,
720
720
  SyncTransaction
721
721
  };
722
- //# sourceMappingURL=chunk-LS3JLEIB.js.map
722
+ //# sourceMappingURL=chunk-PS5G6A3Y.js.map
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  readPath
3
- } from "./chunk-MRIBLZL3.js";
3
+ } from "./chunk-ICH4AIGL.js";
4
4
  import {
5
5
  GroupCardinalityError
6
- } from "./chunk-YDLAFP36.js";
6
+ } from "./chunk-6HJ2ZALB.js";
7
7
 
8
8
  // src/aggregate/aggregation.ts
9
9
  function reduceRecords(records, spec) {
@@ -337,4 +337,4 @@ export {
337
337
  groupAndReduce,
338
338
  GroupedAggregation
339
339
  };
340
- //# sourceMappingURL=chunk-KYKMKLJ6.js.map
340
+ //# sourceMappingURL=chunk-PX3MJ6RB.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  ReadOnlyFrameError
3
- } from "./chunk-YDLAFP36.js";
3
+ } from "./chunk-6HJ2ZALB.js";
4
4
 
5
5
  // src/shadow/vault-frame.ts
6
6
  var VaultFrame = class {
@@ -76,4 +76,4 @@ export {
76
76
  VaultFrame,
77
77
  CollectionFrame
78
78
  };
79
- //# sourceMappingURL=chunk-FCDO7UAO.js.map
79
+ //# sourceMappingURL=chunk-R4LTCI6O.js.map
@@ -30,7 +30,7 @@ async function resolveStaleMVOnRead(accessor, outputCollection) {
30
30
  continue;
31
31
  }
32
32
  if (executor === null) {
33
- ({ MaterializedViewExecutor: executor } = await import("./executor-KT2IOZVP.js"));
33
+ ({ MaterializedViewExecutor: executor } = await import("./executor-RWICJI7J.js"));
34
34
  }
35
35
  await executor.refresh(reg, {
36
36
  getCollection: (n) => accessor.getCollection(n),
@@ -50,4 +50,4 @@ export {
50
50
  resolveStaleMVOnRead,
51
51
  clearMVStale
52
52
  };
53
- //# sourceMappingURL=chunk-BFI3RS42.js.map
53
+ //# sourceMappingURL=chunk-R7JTYCRX.js.map