@noy-db/hub 0.2.0-pre.1 → 0.2.0-pre.11

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 (306) hide show
  1. package/dist/aggregate/index.cjs +9 -0
  2. package/dist/aggregate/index.cjs.map +1 -1
  3. package/dist/aggregate/index.d.cts +2 -2
  4. package/dist/aggregate/index.d.ts +2 -2
  5. package/dist/aggregate/index.js +4 -4
  6. package/dist/attestation/index.cjs +305 -0
  7. package/dist/attestation/index.cjs.map +1 -0
  8. package/dist/attestation/index.d.cts +52 -0
  9. package/dist/attestation/index.d.ts +52 -0
  10. package/dist/attestation/index.js +36 -0
  11. package/dist/attestation/index.js.map +1 -0
  12. package/dist/blobs/index.cjs.map +1 -1
  13. package/dist/blobs/index.d.cts +7 -6
  14. package/dist/blobs/index.d.ts +7 -6
  15. package/dist/blobs/index.js +10 -8
  16. package/dist/blobs/index.js.map +1 -1
  17. package/dist/bundle/index.cjs +18912 -129
  18. package/dist/bundle/index.cjs.map +1 -1
  19. package/dist/bundle/index.d.cts +175 -6
  20. package/dist/bundle/index.d.ts +175 -6
  21. package/dist/bundle/index.js +533 -5
  22. package/dist/bundle/index.js.map +1 -1
  23. package/dist/{chunk-6HPZY4ON.js → chunk-26NK23DZ.js} +9 -4
  24. package/dist/chunk-26NK23DZ.js.map +1 -0
  25. package/dist/{chunk-XGSOTWYX.js → chunk-2LPPNWF6.js} +3 -3
  26. package/dist/{chunk-537VFZTR.js → chunk-3DGHRDCX.js} +4 -4
  27. package/dist/{chunk-HB3Z2GCR.js → chunk-5OEJ6GOT.js} +2 -2
  28. package/dist/chunk-5OEJ6GOT.js.map +1 -0
  29. package/dist/{chunk-UA4RI7OT.js → chunk-6MFH4BMK.js} +5 -5
  30. package/dist/chunk-6MFH4BMK.js.map +1 -0
  31. package/dist/{chunk-UZXLQCHP.js → chunk-6T2UDBKG.js} +2 -2
  32. package/dist/chunk-6T2UDBKG.js.map +1 -0
  33. package/dist/{chunk-23TTQXVO.js → chunk-6YLPHBKR.js} +214 -9
  34. package/dist/chunk-6YLPHBKR.js.map +1 -0
  35. package/dist/chunk-73YLDCNF.js +83 -0
  36. package/dist/chunk-73YLDCNF.js.map +1 -0
  37. package/dist/chunk-77DWLQRY.js +233 -0
  38. package/dist/chunk-77DWLQRY.js.map +1 -0
  39. package/dist/{chunk-Z72JH4KG.js → chunk-7CEGU63S.js} +5 -35
  40. package/dist/chunk-7CEGU63S.js.map +1 -0
  41. package/dist/{chunk-PEULZC6M.js → chunk-A3JMGXPG.js} +8 -1
  42. package/dist/chunk-A3JMGXPG.js.map +1 -0
  43. package/dist/{chunk-I6MX32UC.js → chunk-BDV7INMP.js} +4 -4
  44. package/dist/{chunk-MKSA2V7A.js → chunk-C3WE6UJY.js} +2 -2
  45. package/dist/{chunk-FCXOFQAJ.js → chunk-CH22FZHT.js} +19 -2
  46. package/dist/chunk-CH22FZHT.js.map +1 -0
  47. package/dist/{chunk-DYBQG5PQ.js → chunk-CXFOITNS.js} +2 -2
  48. package/dist/{chunk-5ZGZ6HIZ.js → chunk-CXJG63MA.js} +11 -2
  49. package/dist/chunk-CXJG63MA.js.map +1 -0
  50. package/dist/{chunk-EGQYGYIU.js → chunk-DAP2XL7Q.js} +3 -3
  51. package/dist/chunk-DAP2XL7Q.js.map +1 -0
  52. package/dist/chunk-EBVBE7UK.js +59 -0
  53. package/dist/chunk-EBVBE7UK.js.map +1 -0
  54. package/dist/{chunk-DPMFBCV6.js → chunk-FO3UEG4S.js} +20 -3
  55. package/dist/chunk-FO3UEG4S.js.map +1 -0
  56. package/dist/{chunk-SIZWEV2Y.js → chunk-GAUEWM7D.js} +7 -5
  57. package/dist/chunk-GAUEWM7D.js.map +1 -0
  58. package/dist/chunk-GKI4SDP7.js +57 -0
  59. package/dist/chunk-GKI4SDP7.js.map +1 -0
  60. package/dist/chunk-IMYKDWB4.js +139 -0
  61. package/dist/chunk-IMYKDWB4.js.map +1 -0
  62. package/dist/{chunk-5SCJ5UEF.js → chunk-JQ4NEJJ6.js} +3 -3
  63. package/dist/chunk-LJXYPGRH.js +251 -0
  64. package/dist/chunk-LJXYPGRH.js.map +1 -0
  65. package/dist/{chunk-5DWL3JBF.js → chunk-LSTBFLL2.js} +2 -2
  66. package/dist/chunk-MPOLUAMI.js +10531 -0
  67. package/dist/chunk-MPOLUAMI.js.map +1 -0
  68. package/dist/{chunk-ADQ5MQ54.js → chunk-O6EJ6WTI.js} +163 -2
  69. package/dist/chunk-O6EJ6WTI.js.map +1 -0
  70. package/dist/chunk-PC3ZZBTO.js +79 -0
  71. package/dist/chunk-PC3ZZBTO.js.map +1 -0
  72. package/dist/{chunk-OMLIZL2P.js → chunk-PC6ZEDRL.js} +12 -2
  73. package/dist/{chunk-OMLIZL2P.js.map → chunk-PC6ZEDRL.js.map} +1 -1
  74. package/dist/{chunk-34YSDCDP.js → chunk-PVUUIWHY.js} +2 -2
  75. package/dist/{chunk-PA6R5ZCI.js → chunk-QCXNMCHN.js} +18 -5
  76. package/dist/chunk-QCXNMCHN.js.map +1 -0
  77. package/dist/{chunk-DYECX3IX.js → chunk-QSOYKKMD.js} +4 -4
  78. package/dist/chunk-QSOYKKMD.js.map +1 -0
  79. package/dist/{chunk-WCA2NROQ.js → chunk-R233SLY3.js} +2 -2
  80. package/dist/chunk-RC6SU5NO.js +36 -0
  81. package/dist/chunk-RC6SU5NO.js.map +1 -0
  82. package/dist/{chunk-P7EQ2S5O.js → chunk-RRNA5GKT.js} +2 -2
  83. package/dist/{chunk-ZNOEIM6Y.js → chunk-RYIL3PI2.js} +2 -2
  84. package/dist/{chunk-YS3POABP.js → chunk-SLV4LAKX.js} +1 -1
  85. package/dist/chunk-SLV4LAKX.js.map +1 -0
  86. package/dist/chunk-STNPB3UM.js +9 -0
  87. package/dist/chunk-STNPB3UM.js.map +1 -0
  88. package/dist/{chunk-7H6DOO3E.js → chunk-TGALXXLV.js} +211 -36
  89. package/dist/chunk-TGALXXLV.js.map +1 -0
  90. package/dist/{chunk-MRIBLZL3.js → chunk-TV3YZ35S.js} +5 -1
  91. package/dist/chunk-TV3YZ35S.js.map +1 -0
  92. package/dist/{chunk-VMIO4IXG.js → chunk-V2PZC6AW.js} +6 -229
  93. package/dist/chunk-V2PZC6AW.js.map +1 -0
  94. package/dist/{chunk-YMYK7US4.js → chunk-WIBHRONM.js} +2 -2
  95. package/dist/chunk-WIBHRONM.js.map +1 -0
  96. package/dist/{chunk-KESP7GOK.js → chunk-Y26YV5R3.js} +3 -3
  97. package/dist/{chunk-MIQHZESA.js → chunk-YM7LFCG7.js} +5 -5
  98. package/dist/{chunk-MIQHZESA.js.map → chunk-YM7LFCG7.js.map} +1 -1
  99. package/dist/{chunk-CBAHB2BF.js → chunk-YVZRTCGG.js} +7 -70
  100. package/dist/chunk-YVZRTCGG.js.map +1 -0
  101. package/dist/{chunk-4TFSM22V.js → chunk-YW5DBAPG.js} +4 -4
  102. package/dist/{chunk-2AXFIYHT.js → chunk-Z6FNBOTC.js} +1 -1
  103. package/dist/chunk-Z6FNBOTC.js.map +1 -0
  104. package/dist/{chunk-NIOHFJPJ.js → chunk-ZBBW7YQN.js} +218 -119
  105. package/dist/chunk-ZBBW7YQN.js.map +1 -0
  106. package/dist/{chunk-RD5LYKD6.js → chunk-ZROPXHJY.js} +2 -2
  107. package/dist/chunk-ZROPXHJY.js.map +1 -0
  108. package/dist/consent/index.cjs.map +1 -1
  109. package/dist/consent/index.d.cts +7 -6
  110. package/dist/consent/index.d.ts +7 -6
  111. package/dist/consent/index.js +3 -3
  112. package/dist/{crypto-A7FRXYHC.js → crypto-2CRLG4F4.js} +3 -3
  113. package/dist/{delegation-YBA4X4JN.js → delegation-ZTRT2PRV.js} +5 -5
  114. package/dist/derivations/index.cjs +18 -1
  115. package/dist/derivations/index.cjs.map +1 -1
  116. package/dist/derivations/index.d.cts +10 -9
  117. package/dist/derivations/index.d.ts +10 -9
  118. package/dist/derivations/index.js +4 -4
  119. package/dist/{dev-unlock-D9s-loPr.d.ts → dev-unlock-BH6y3Hx0.d.ts} +1 -1
  120. package/dist/{dev-unlock-DRwVSy2S.d.cts → dev-unlock-H1Xwxc3U.d.cts} +1 -1
  121. package/dist/discriminant-BN9REW3o.d.cts +60 -0
  122. package/dist/discriminant-BN9REW3o.d.ts +60 -0
  123. package/dist/executor-S76VN45G.js +8 -0
  124. package/dist/executor-UCXLIGLW.js +11 -0
  125. package/dist/executor-ZCNZJMGR.js +8 -0
  126. package/dist/{fanout-sidecar-VJ52RIEY.js → fanout-sidecar-F3ZRFU4H.js} +2 -2
  127. package/dist/fanout-sidecar-F3ZRFU4H.js.map +1 -0
  128. package/dist/guards/index.cjs +7 -0
  129. package/dist/guards/index.cjs.map +1 -1
  130. package/dist/guards/index.d.cts +8 -7
  131. package/dist/guards/index.d.ts +8 -7
  132. package/dist/guards/index.js +4 -4
  133. package/dist/{hash-DXXXusyk.d.ts → hash-D89JdDbj.d.ts} +1 -1
  134. package/dist/{hash-DtRih9MQ.d.cts → hash-_sDFvtmX.d.cts} +1 -1
  135. package/dist/history/index.cjs +2 -2
  136. package/dist/history/index.cjs.map +1 -1
  137. package/dist/history/index.d.cts +8 -7
  138. package/dist/history/index.d.ts +8 -7
  139. package/dist/history/index.js +6 -6
  140. package/dist/i18n/index.cjs +287 -27
  141. package/dist/i18n/index.cjs.map +1 -1
  142. package/dist/i18n/index.d.cts +7 -6
  143. package/dist/i18n/index.d.ts +7 -6
  144. package/dist/i18n/index.js +21 -6
  145. package/dist/i18n/index.js.map +1 -1
  146. package/dist/{index-CmVgTkqk.d.cts → index-B8bjExET.d.cts} +214 -18
  147. package/dist/{index-CNwA-B6-.d.ts → index-DfUbNad8.d.ts} +214 -18
  148. package/dist/index.cjs +3343 -447
  149. package/dist/index.cjs.map +1 -1
  150. package/dist/index.d.cts +43 -22
  151. package/dist/index.d.ts +43 -22
  152. package/dist/index.js +179 -8799
  153. package/dist/index.js.map +1 -1
  154. package/dist/indexing/index.cjs +5 -1
  155. package/dist/indexing/index.cjs.map +1 -1
  156. package/dist/indexing/index.d.cts +3 -3
  157. package/dist/indexing/index.d.ts +3 -3
  158. package/dist/indexing/index.js +4 -4
  159. package/dist/issue-IVTVSKWW.js +12 -0
  160. package/dist/{lazy-builder-Rpd-V3jP.d.ts → lazy-builder-Ci5_YG73.d.cts} +2 -2
  161. package/dist/{lazy-builder-C-rPfWG0.d.cts → lazy-builder-D5GU14TS.d.ts} +2 -2
  162. package/dist/{ledger-3TXNP47J.js → ledger-NYCGJX2D.js} +6 -6
  163. package/dist/materialized-views/index.cjs +21 -2
  164. package/dist/materialized-views/index.cjs.map +1 -1
  165. package/dist/materialized-views/index.d.cts +23 -20
  166. package/dist/materialized-views/index.d.ts +23 -20
  167. package/dist/materialized-views/index.js +12 -12
  168. package/dist/noydb-SH4RLE47.js +34 -0
  169. package/dist/overlay-views/index.cjs +11 -1
  170. package/dist/overlay-views/index.cjs.map +1 -1
  171. package/dist/overlay-views/index.d.cts +10 -9
  172. package/dist/overlay-views/index.d.ts +10 -9
  173. package/dist/overlay-views/index.js +6 -4
  174. package/dist/periods/index.cjs.map +1 -1
  175. package/dist/periods/index.d.cts +7 -6
  176. package/dist/periods/index.d.ts +7 -6
  177. package/dist/periods/index.js +6 -6
  178. package/dist/{predicate-Dnu81tsS.d.cts → predicate-Bt5ft-9c.d.cts} +28 -3
  179. package/dist/{predicate-Dnu81tsS.d.ts → predicate-Bt5ft-9c.d.ts} +28 -3
  180. package/dist/{public-envelope-PY6NKFLI.js → public-envelope-QOXZEHKH.js} +4 -4
  181. package/dist/query/index.cjs +255 -6
  182. package/dist/query/index.cjs.map +1 -1
  183. package/dist/query/index.d.cts +3 -3
  184. package/dist/query/index.d.ts +3 -3
  185. package/dist/query/index.js +12 -6
  186. package/dist/registry-DKEXOJVO.js +7 -0
  187. package/dist/{registry-3L3N3PTG.js → registry-ST2VNFZC.js} +3 -3
  188. package/dist/registry-UFIK7CSR.js +8 -0
  189. package/dist/registry-ZGYYSM5I.js +8 -0
  190. package/dist/registry-ZGYYSM5I.js.map +1 -0
  191. package/dist/revoke-RT7QYB4G.js +17 -0
  192. package/dist/revoke-RT7QYB4G.js.map +1 -0
  193. package/dist/session/index.cjs.map +1 -1
  194. package/dist/session/index.d.cts +8 -7
  195. package/dist/session/index.d.ts +8 -7
  196. package/dist/session/index.js +3 -3
  197. package/dist/shadow/index.cjs.map +1 -1
  198. package/dist/shadow/index.d.cts +7 -6
  199. package/dist/shadow/index.d.ts +7 -6
  200. package/dist/shadow/index.js +2 -2
  201. package/dist/signer-QNU66JF5.js +18 -0
  202. package/dist/signer-QNU66JF5.js.map +1 -0
  203. package/dist/snapshots/index.cjs +937 -0
  204. package/dist/snapshots/index.cjs.map +1 -0
  205. package/dist/snapshots/index.d.cts +28 -0
  206. package/dist/snapshots/index.d.ts +28 -0
  207. package/dist/snapshots/index.js +152 -0
  208. package/dist/snapshots/index.js.map +1 -0
  209. package/dist/{stale-HSC5YO2O.js → stale-VKXSXJF4.js} +2 -2
  210. package/dist/stale-VKXSXJF4.js.map +1 -0
  211. package/dist/store/index.cjs.map +1 -1
  212. package/dist/store/index.d.cts +7 -6
  213. package/dist/store/index.d.ts +7 -6
  214. package/dist/store/index.js +2 -2
  215. package/dist/{strategy-DSTrsZ8t.d.cts → strategy-CT2LCKAX.d.cts} +12 -0
  216. package/dist/{strategy-DSTrsZ8t.d.ts → strategy-CT2LCKAX.d.ts} +12 -0
  217. package/dist/sync/index.cjs.map +1 -1
  218. package/dist/sync/index.d.cts +6 -5
  219. package/dist/sync/index.d.ts +6 -5
  220. package/dist/sync/index.js +4 -4
  221. package/dist/team/index.cjs +1 -1
  222. package/dist/team/index.cjs.map +1 -1
  223. package/dist/team/index.d.cts +7 -6
  224. package/dist/team/index.d.ts +7 -6
  225. package/dist/team/index.js +13 -11
  226. package/dist/tx/index.cjs +82 -2
  227. package/dist/tx/index.cjs.map +1 -1
  228. package/dist/tx/index.d.cts +8 -7
  229. package/dist/tx/index.d.ts +8 -7
  230. package/dist/tx/index.js +56 -3
  231. package/dist/tx/index.js.map +1 -1
  232. package/dist/{types-DW9RGSSs.d.ts → types-CD8mc8zR.d.ts} +1279 -259
  233. package/dist/{types-C4lwMKKF.d.cts → types-DiSXn3a4.d.cts} +1279 -259
  234. package/dist/{index-4agOpzqd.d.ts → ulid-8p83wbR4.d.ts} +64 -46
  235. package/dist/{index-hdFvZkBP.d.cts → ulid-DQ1hcJvZ.d.cts} +64 -46
  236. package/dist/util/index.cjs +7 -0
  237. package/dist/util/index.cjs.map +1 -1
  238. package/dist/util/index.d.cts +2 -0
  239. package/dist/util/index.d.ts +2 -0
  240. package/dist/util/index.js +5 -1
  241. package/dist/util/index.js.map +1 -1
  242. package/dist/{with-derivation-C8LDlV7t.d.cts → with-derivation-CVT7-dUt.d.cts} +1 -1
  243. package/dist/{with-derivation-g-pGoMzL.d.ts → with-derivation-DWMTpgEH.d.ts} +1 -1
  244. package/dist/{with-guard-DWOCK4Ca.d.ts → with-guard-BRvt53da.d.ts} +1 -1
  245. package/dist/{with-guard-jI1x9Z3k.d.cts → with-guard-Dx2zZnTA.d.cts} +1 -1
  246. package/dist/{with-materialized-view-DaKR-N6J.d.ts → with-materialized-view-BTTU3BNK.d.cts} +2 -2
  247. package/dist/{with-materialized-view-DcTx4H3j.d.cts → with-materialized-view-X0CoL8-L.d.ts} +2 -2
  248. package/dist/{with-overlayed-view-N7jYuNOS.d.ts → with-overlayed-view-DQjO_DSG.d.ts} +2 -2
  249. package/dist/{with-overlayed-view-D-6oWAgM.d.cts → with-overlayed-view-DcacRRsS.d.cts} +2 -2
  250. package/package.json +27 -4
  251. package/dist/chunk-23TTQXVO.js.map +0 -1
  252. package/dist/chunk-2AXFIYHT.js.map +0 -1
  253. package/dist/chunk-5ZGZ6HIZ.js.map +0 -1
  254. package/dist/chunk-6HPZY4ON.js.map +0 -1
  255. package/dist/chunk-7H6DOO3E.js.map +0 -1
  256. package/dist/chunk-ADQ5MQ54.js.map +0 -1
  257. package/dist/chunk-CBAHB2BF.js.map +0 -1
  258. package/dist/chunk-DPMFBCV6.js.map +0 -1
  259. package/dist/chunk-DYECX3IX.js.map +0 -1
  260. package/dist/chunk-EGQYGYIU.js.map +0 -1
  261. package/dist/chunk-FCXOFQAJ.js.map +0 -1
  262. package/dist/chunk-HB3Z2GCR.js.map +0 -1
  263. package/dist/chunk-MRIBLZL3.js.map +0 -1
  264. package/dist/chunk-NIOHFJPJ.js.map +0 -1
  265. package/dist/chunk-PA6R5ZCI.js.map +0 -1
  266. package/dist/chunk-PEULZC6M.js.map +0 -1
  267. package/dist/chunk-RD5LYKD6.js.map +0 -1
  268. package/dist/chunk-SIZWEV2Y.js.map +0 -1
  269. package/dist/chunk-UA4RI7OT.js.map +0 -1
  270. package/dist/chunk-UZXLQCHP.js.map +0 -1
  271. package/dist/chunk-VMIO4IXG.js.map +0 -1
  272. package/dist/chunk-YMYK7US4.js.map +0 -1
  273. package/dist/chunk-YS3POABP.js.map +0 -1
  274. package/dist/chunk-Z72JH4KG.js.map +0 -1
  275. package/dist/executor-7E3VFGW7.js +0 -11
  276. package/dist/executor-CEWX2FQI.js +0 -8
  277. package/dist/executor-X4SQ3ZLC.js +0 -8
  278. package/dist/fanout-sidecar-VJ52RIEY.js.map +0 -1
  279. package/dist/registry-O47PUPSY.js +0 -8
  280. package/dist/registry-RFGGMVNJ.js +0 -7
  281. package/dist/registry-WLLMODKN.js +0 -8
  282. /package/dist/{chunk-XGSOTWYX.js.map → chunk-2LPPNWF6.js.map} +0 -0
  283. /package/dist/{chunk-537VFZTR.js.map → chunk-3DGHRDCX.js.map} +0 -0
  284. /package/dist/{chunk-I6MX32UC.js.map → chunk-BDV7INMP.js.map} +0 -0
  285. /package/dist/{chunk-MKSA2V7A.js.map → chunk-C3WE6UJY.js.map} +0 -0
  286. /package/dist/{chunk-DYBQG5PQ.js.map → chunk-CXFOITNS.js.map} +0 -0
  287. /package/dist/{chunk-5SCJ5UEF.js.map → chunk-JQ4NEJJ6.js.map} +0 -0
  288. /package/dist/{chunk-5DWL3JBF.js.map → chunk-LSTBFLL2.js.map} +0 -0
  289. /package/dist/{chunk-34YSDCDP.js.map → chunk-PVUUIWHY.js.map} +0 -0
  290. /package/dist/{chunk-WCA2NROQ.js.map → chunk-R233SLY3.js.map} +0 -0
  291. /package/dist/{chunk-P7EQ2S5O.js.map → chunk-RRNA5GKT.js.map} +0 -0
  292. /package/dist/{chunk-ZNOEIM6Y.js.map → chunk-RYIL3PI2.js.map} +0 -0
  293. /package/dist/{chunk-KESP7GOK.js.map → chunk-Y26YV5R3.js.map} +0 -0
  294. /package/dist/{chunk-4TFSM22V.js.map → chunk-YW5DBAPG.js.map} +0 -0
  295. /package/dist/{crypto-A7FRXYHC.js.map → crypto-2CRLG4F4.js.map} +0 -0
  296. /package/dist/{delegation-YBA4X4JN.js.map → delegation-ZTRT2PRV.js.map} +0 -0
  297. /package/dist/{executor-7E3VFGW7.js.map → executor-S76VN45G.js.map} +0 -0
  298. /package/dist/{executor-CEWX2FQI.js.map → executor-UCXLIGLW.js.map} +0 -0
  299. /package/dist/{executor-X4SQ3ZLC.js.map → executor-ZCNZJMGR.js.map} +0 -0
  300. /package/dist/{ledger-3TXNP47J.js.map → issue-IVTVSKWW.js.map} +0 -0
  301. /package/dist/{public-envelope-PY6NKFLI.js.map → ledger-NYCGJX2D.js.map} +0 -0
  302. /package/dist/{registry-3L3N3PTG.js.map → noydb-SH4RLE47.js.map} +0 -0
  303. /package/dist/{registry-O47PUPSY.js.map → public-envelope-QOXZEHKH.js.map} +0 -0
  304. /package/dist/{registry-RFGGMVNJ.js.map → registry-DKEXOJVO.js.map} +0 -0
  305. /package/dist/{registry-WLLMODKN.js.map → registry-ST2VNFZC.js.map} +0 -0
  306. /package/dist/{stale-HSC5YO2O.js.map → registry-UFIK7CSR.js.map} +0 -0
@@ -0,0 +1,233 @@
1
+ import {
2
+ NOYDB_FORMAT_VERSION
3
+ } from "./chunk-SLV4LAKX.js";
4
+ import {
5
+ encrypt
6
+ } from "./chunk-R233SLY3.js";
7
+
8
+ // src/blobs/export-blobs.ts
9
+ var ExportBlobsAbortedError = class extends Error {
10
+ constructor(reason) {
11
+ super(`exportBlobs aborted: ${reason}`);
12
+ this.name = "ExportBlobsAbortedError";
13
+ }
14
+ };
15
+ var EXPORT_AUDIT_COLLECTION = "_export_audit";
16
+ function createExportBlobsHandle(actor, listAccessibleCollections, getCollection, writeAudit, options) {
17
+ let aborted = false;
18
+ const abort = () => {
19
+ aborted = true;
20
+ };
21
+ if (options.signal) {
22
+ if (options.signal.aborted) aborted = true;
23
+ options.signal.addEventListener("abort", () => {
24
+ aborted = true;
25
+ });
26
+ }
27
+ function assertLive() {
28
+ if (aborted) throw new ExportBlobsAbortedError("aborted by caller");
29
+ }
30
+ const allowlist = options.collections ? new Set(options.collections) : null;
31
+ let auditPromise = null;
32
+ function writeAuditOnce() {
33
+ if (!auditPromise) {
34
+ auditPromise = writeAudit({
35
+ id: generateBatchId(),
36
+ mechanism: "exportBlobs",
37
+ actor,
38
+ startedAt: (/* @__PURE__ */ new Date()).toISOString(),
39
+ collections: options.collections ?? null,
40
+ predicate: Boolean(options.where),
41
+ afterBlobId: options.afterBlobId ?? null
42
+ });
43
+ }
44
+ return auditPromise;
45
+ }
46
+ async function* generate() {
47
+ await writeAuditOnce();
48
+ assertLive();
49
+ const allCollections = await listAccessibleCollections();
50
+ const targets = allCollections.filter((name) => {
51
+ if (name.startsWith("_")) return false;
52
+ if (allowlist && !allowlist.has(name)) return false;
53
+ return true;
54
+ });
55
+ let resumeCursorHit = options.afterBlobId === void 0;
56
+ for (const collectionName of targets) {
57
+ if (aborted) return;
58
+ const coll = getCollection(collectionName);
59
+ const records = await coll.list().catch(() => []);
60
+ for (const record of records) {
61
+ if (aborted) return;
62
+ assertLive();
63
+ const idField = record.id;
64
+ if (typeof idField !== "string") continue;
65
+ if (options.where && !options.where(record, { collection: collectionName, id: idField })) continue;
66
+ const blobSet = coll.blob(idField);
67
+ const slots = await blobSet.list().catch(() => []);
68
+ for (const slot of slots) {
69
+ if (aborted) return;
70
+ if (!resumeCursorHit) {
71
+ if (slot.eTag === options.afterBlobId) {
72
+ resumeCursorHit = true;
73
+ }
74
+ continue;
75
+ }
76
+ const bytes = await blobSet.get(slot.name);
77
+ if (!bytes) continue;
78
+ const item = {
79
+ blobId: slot.eTag,
80
+ recordRef: { collection: collectionName, id: idField, slot: slot.name },
81
+ bytes,
82
+ meta: {
83
+ size: slot.size,
84
+ filename: slot.filename,
85
+ ...slot.mimeType !== void 0 && { mimeType: slot.mimeType },
86
+ ...slot.uploadedAt !== void 0 && { createdAt: slot.uploadedAt }
87
+ }
88
+ };
89
+ yield item;
90
+ }
91
+ }
92
+ }
93
+ }
94
+ const handle = {
95
+ abort,
96
+ get aborted() {
97
+ return aborted;
98
+ },
99
+ [Symbol.asyncIterator]: () => generate()
100
+ };
101
+ return handle;
102
+ }
103
+ function generateBatchId() {
104
+ const raw = globalThis.crypto.getRandomValues(new Uint8Array(16));
105
+ let s = "";
106
+ for (const b of raw) s += b.toString(16).padStart(2, "0");
107
+ return `batch-${Date.now().toString(36)}-${s.slice(0, 12)}`;
108
+ }
109
+
110
+ // src/blobs/blob-compaction.ts
111
+ var BLOB_EVICTION_AUDIT_COLLECTION = "_blob_eviction_audit";
112
+ async function runCompaction(ctx, options = {}) {
113
+ const now = options.now ?? /* @__PURE__ */ new Date();
114
+ const maxEvictions = options.maxEvictions ?? Infinity;
115
+ const dryRun = options.dryRun === true;
116
+ const allCollections = await ctx.listCollections();
117
+ const byCollection = {};
118
+ let evicted = 0;
119
+ let records = 0;
120
+ let auditEntries = 0;
121
+ let collectionsWithPolicy = 0;
122
+ outer: for (const collectionName of allCollections) {
123
+ if (collectionName.startsWith("_")) continue;
124
+ const config = ctx.getBlobFields(collectionName);
125
+ if (!config) continue;
126
+ const configuredSlots = Object.keys(config);
127
+ if (configuredSlots.length === 0) continue;
128
+ collectionsWithPolicy += 1;
129
+ byCollection[collectionName] = { records: 0, evicted: 0 };
130
+ const ids = await ctx.listRecords(collectionName);
131
+ for (const recordId of ids) {
132
+ if (evicted >= maxEvictions) break outer;
133
+ const record = await ctx.getRecord(collectionName, recordId).catch(() => null);
134
+ if (record === null) continue;
135
+ records += 1;
136
+ byCollection[collectionName].records += 1;
137
+ const slots = await ctx.listSlots(collectionName, recordId).catch(() => []);
138
+ for (const slot of slots) {
139
+ if (evicted >= maxEvictions) break outer;
140
+ const policy = config[slot.name];
141
+ if (!policy) continue;
142
+ const reason = evaluatePolicy(policy, record, slot, now);
143
+ if (!reason) continue;
144
+ if (!dryRun) {
145
+ await ctx.deleteSlot(collectionName, recordId, slot.name);
146
+ await writeAuditEntry(ctx, {
147
+ id: generateEvictionId(collectionName, recordId, slot.name),
148
+ collection: collectionName,
149
+ recordId,
150
+ slotName: slot.name,
151
+ blobHash: slot.eTag,
152
+ reason,
153
+ evictedAt: now.toISOString(),
154
+ actor: ctx.actor
155
+ });
156
+ auditEntries += 1;
157
+ }
158
+ evicted += 1;
159
+ byCollection[collectionName].evicted += 1;
160
+ }
161
+ }
162
+ }
163
+ return {
164
+ evicted,
165
+ records,
166
+ collections: collectionsWithPolicy,
167
+ auditEntries,
168
+ byCollection
169
+ };
170
+ }
171
+ function evaluatePolicy(policy, record, slot, now) {
172
+ let ttlTriggered = false;
173
+ let predicateTriggered = false;
174
+ if (policy.retainDays !== void 0 && policy.retainDays > 0) {
175
+ const uploadedAt = Date.parse(slot.uploadedAt);
176
+ if (Number.isFinite(uploadedAt)) {
177
+ const ageMs = now.getTime() - uploadedAt;
178
+ const limitMs = policy.retainDays * 864e5;
179
+ if (ageMs > limitMs) ttlTriggered = true;
180
+ }
181
+ }
182
+ if (policy.evictWhen) {
183
+ try {
184
+ if (policy.evictWhen(record)) predicateTriggered = true;
185
+ } catch {
186
+ }
187
+ }
188
+ if (ttlTriggered && predicateTriggered) return "both";
189
+ if (ttlTriggered) return "ttl";
190
+ if (predicateTriggered) return "predicate";
191
+ return null;
192
+ }
193
+ function generateEvictionId(collection, recordId, slotName) {
194
+ const rand = globalThis.crypto.getRandomValues(new Uint8Array(8));
195
+ let suffix = "";
196
+ for (const b of rand) suffix += b.toString(16).padStart(2, "0");
197
+ return `${collection}__${recordId}__${slotName}__${suffix}`;
198
+ }
199
+ async function writeAuditEntry(ctx, entry) {
200
+ const json = JSON.stringify(entry);
201
+ let envelope;
202
+ if (ctx.encrypted) {
203
+ const dek = await ctx.getDEK(BLOB_EVICTION_AUDIT_COLLECTION);
204
+ const { iv, data } = await encrypt(json, dek);
205
+ envelope = {
206
+ _noydb: NOYDB_FORMAT_VERSION,
207
+ _v: 1,
208
+ _ts: entry.evictedAt,
209
+ _iv: iv,
210
+ _data: data,
211
+ _by: entry.actor
212
+ };
213
+ } else {
214
+ envelope = {
215
+ _noydb: NOYDB_FORMAT_VERSION,
216
+ _v: 1,
217
+ _ts: entry.evictedAt,
218
+ _iv: "",
219
+ _data: json,
220
+ _by: entry.actor
221
+ };
222
+ }
223
+ await ctx.adapter.put(ctx.vault, BLOB_EVICTION_AUDIT_COLLECTION, entry.id, envelope);
224
+ }
225
+
226
+ export {
227
+ ExportBlobsAbortedError,
228
+ EXPORT_AUDIT_COLLECTION,
229
+ createExportBlobsHandle,
230
+ BLOB_EVICTION_AUDIT_COLLECTION,
231
+ runCompaction
232
+ };
233
+ //# sourceMappingURL=chunk-77DWLQRY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/blobs/export-blobs.ts","../src/blobs/blob-compaction.ts"],"sourcesContent":["/**\n * `vault.exportBlobs()` — bulk blob extraction primitive.\n *\n * Async-iterable handle over every blob attached to records in a\n * vault, optionally filtered by collection allowlist and per-record\n * predicate. Emits tuples of `{ blobId, recordRef, bytes, meta }` so\n * the consumer can pipe into any sink (zip stream, S3 multipart, USB\n * copy, cold-storage tape) without pulling the whole export into\n * memory.\n *\n * ## Auth + audit\n *\n * - Capability check runs **once** at handle creation via\n * `Vault.assertCanExport('plaintext', 'blob')`. An operator whose\n * keyring lacks that bit fails before a single byte of ciphertext\n * is decrypted.\n * - Audit entry lands in `_export_audit` at handle creation: the\n * actor, start timestamp, target collections, predicate presence,\n * and batch mechanism. **No content hashes** — per the spec\n * non-correlation invariant.\n *\n * ## Abort + resume\n *\n * - `handle.abort()` flips the internal signal; the next iteration\n * boundary throws `AbortError`. Consumers already in `for await`\n * can catch and exit cleanly.\n * - Restart after a partial failure with `{ afterBlobId }` — the\n * iterator skips tuples up to (and including) that blob id before\n * yielding again. Combined with a blob-count ceiling it supports\n * idempotent batch re-runs.\n *\n * @module\n */\n\nimport type { Collection } from '../collection.js'\nimport type { SlotInfo } from '../types.js'\n\n// ─── Types ──────────────────────────────────────────────────────────────\n\nexport interface ExportBlobsOptions {\n /**\n * Collection allowlist. Omit to export blobs from every collection\n * the caller has read access to.\n */\n readonly collections?: readonly string[]\n /**\n * Per-record predicate. Called on the decrypted record BEFORE any\n * blob bytes are read for that record — returning false skips the\n * record and all its slots without touching their chunks.\n */\n readonly where?: (record: unknown, context: { collection: string; id: string }) => boolean\n /**\n * Resume after a specific blob id. The iterator skips tuples up to\n * and including this id, then yields. Format of the id is the same\n * as `ExportedBlob.blobId` (the HMAC-keyed eTag).\n */\n readonly afterBlobId?: string\n /**\n * External abort signal. When fired, the next iterator tick throws\n * `ExportBlobsAbortedError`. Honored alongside `handle.abort()`.\n */\n readonly signal?: AbortSignal\n}\n\nexport interface ExportedBlob {\n /** Opaque blob identifier — HMAC-keyed eTag, stable across vaults. */\n readonly blobId: string\n /** Where this blob came from in the vault. */\n readonly recordRef: {\n readonly collection: string\n readonly id: string\n readonly slot: string\n }\n /** Decrypted plaintext bytes. */\n readonly bytes: Uint8Array\n /** Best-effort metadata (from the blob slot record). */\n readonly meta: {\n readonly size: number\n /**\n * User-visible filename stored on the slot. Often equal to the\n * slot name; differs when the caller supplied an explicit\n * `filename` to `BlobSet.put()`.\n */\n readonly filename: string\n readonly mimeType?: string\n readonly createdAt?: string\n }\n}\n\nexport interface ExportBlobsHandle extends AsyncIterable<ExportedBlob> {\n /** Abort the export. Safe to call multiple times. */\n abort(): void\n /** True once `abort()` has fired or the external signal aborted. */\n readonly aborted: boolean\n}\n\nexport class ExportBlobsAbortedError extends Error {\n constructor(reason: string) {\n super(`exportBlobs aborted: ${reason}`)\n this.name = 'ExportBlobsAbortedError'\n }\n}\n\n// ─── Audit ──────────────────────────────────────────────────────────────\n\nexport const EXPORT_AUDIT_COLLECTION = '_export_audit'\n\nexport interface ExportBlobsAuditEntry {\n readonly id: string\n readonly mechanism: 'exportBlobs'\n readonly actor: string\n readonly startedAt: string\n readonly collections: readonly string[] | null\n readonly predicate: boolean\n readonly afterBlobId: string | null\n}\n\n// ─── Implementation ─────────────────────────────────────────────────────\n\n/**\n * Build the handle. Factored out of `Vault.exportBlobs` so the\n * implementation can be unit-tested without going through the\n * compartment lifecycle.\n */\nexport function createExportBlobsHandle(\n actor: string,\n listAccessibleCollections: () => Promise<string[]>,\n getCollection: <T>(name: string) => Collection<T>,\n writeAudit: (entry: ExportBlobsAuditEntry) => Promise<void>,\n options: ExportBlobsOptions,\n): ExportBlobsHandle {\n let aborted = false\n\n const abort = (): void => {\n aborted = true\n }\n\n if (options.signal) {\n if (options.signal.aborted) aborted = true\n options.signal.addEventListener('abort', () => { aborted = true })\n }\n\n function assertLive(): void {\n if (aborted) throw new ExportBlobsAbortedError('aborted by caller')\n }\n\n const allowlist = options.collections ? new Set(options.collections) : null\n\n // Write the audit entry BEFORE the first yield so a blocked\n // iteration still leaves an audit trail that the export started.\n let auditPromise: Promise<void> | null = null\n function writeAuditOnce(): Promise<void> {\n if (!auditPromise) {\n auditPromise = writeAudit({\n id: generateBatchId(),\n mechanism: 'exportBlobs',\n actor,\n startedAt: new Date().toISOString(),\n collections: options.collections ?? null,\n predicate: Boolean(options.where),\n afterBlobId: options.afterBlobId ?? null,\n })\n }\n return auditPromise\n }\n\n async function* generate(): AsyncGenerator<ExportedBlob> {\n await writeAuditOnce()\n assertLive()\n\n // Resolve target collections lazily — also keeps the call async.\n const allCollections = await listAccessibleCollections()\n const targets = allCollections.filter(name => {\n if (name.startsWith('_')) return false\n if (allowlist && !allowlist.has(name)) return false\n return true\n })\n\n let resumeCursorHit = options.afterBlobId === undefined\n\n for (const collectionName of targets) {\n if (aborted) return\n\n const coll = getCollection<Record<string, unknown>>(collectionName)\n const records = await coll.list().catch(() => [])\n for (const record of records) {\n if (aborted) return\n assertLive()\n\n const idField = (record as { id?: unknown }).id\n if (typeof idField !== 'string') continue\n\n if (options.where && !options.where(record, { collection: collectionName, id: idField })) continue\n\n const blobSet = coll.blob(idField)\n const slots = await blobSet.list().catch(() => [] as SlotInfo[])\n for (const slot of slots) {\n if (aborted) return\n\n if (!resumeCursorHit) {\n if (slot.eTag === options.afterBlobId) {\n resumeCursorHit = true\n }\n continue\n }\n\n const bytes = await blobSet.get(slot.name)\n if (!bytes) continue\n\n const item: ExportedBlob = {\n blobId: slot.eTag,\n recordRef: { collection: collectionName, id: idField, slot: slot.name },\n bytes,\n meta: {\n size: slot.size,\n filename: slot.filename,\n ...(slot.mimeType !== undefined && { mimeType: slot.mimeType }),\n ...(slot.uploadedAt !== undefined && { createdAt: slot.uploadedAt }),\n },\n }\n yield item\n }\n }\n }\n }\n\n const handle: ExportBlobsHandle = {\n abort,\n get aborted() { return aborted },\n [Symbol.asyncIterator]: () => generate(),\n }\n return handle\n}\n\n// ─── Helpers ────────────────────────────────────────────────────────────\n\nfunction generateBatchId(): string {\n // 16 bytes of crypto randomness, URL-safe base64, no padding.\n const raw = globalThis.crypto.getRandomValues(new Uint8Array(16))\n let s = ''\n for (const b of raw) s += b.toString(16).padStart(2, '0')\n return `batch-${Date.now().toString(36)}-${s.slice(0, 12)}`\n}\n","/**\n * Blob retention + compaction.\n *\n * Declarative per-collection / per-slot eviction policy. Two\n * triggers:\n *\n * - **`retainDays`** — age-based TTL. A slot uploaded more than N\n * days ago is evicted.\n * - **`evictWhen(record)`** — predicate over the **decrypted**\n * record. Lets consumers express \"the image is safe to drop once\n * the structured invoice has been reviewed and confirmed.\"\n *\n * Either trigger (or both) causes the slot to evict. Eviction removes\n * the slot entry from `_blob_slots_{collection}`, decrements the\n * blob's refCount (so unreferenced chunks can be GC'd by the next\n * sweep), and writes one entry to the `_blob_eviction_audit`\n * collection for tamper-evident record-keeping.\n *\n * The audit entry carries the eTag of the evicted blob (opaque HMAC\n * of plaintext under the vault's `_blob` DEK) — no plaintext leakage,\n * per the SPEC non-correlation invariant. Consumers reconstructing\n * \"what used to be attached\" can look up the audit entry by record\n * id.\n *\n * Compaction is **consumer-scheduled** — noy-db never runs a\n * background daemon. Call `vault.compact()` whenever your workflow\n * allows (cron, manual \"tidy\" button, cold-storage export prep, …).\n *\n * @module\n */\n\nimport type { NoydbStore, EncryptedEnvelope, SlotInfo } from '../types.js'\nimport { NOYDB_FORMAT_VERSION } from '../types.js'\nimport { encrypt } from '../crypto.js'\n\n// ─── Config types ───────────────────────────────────────────────────────\n\nexport interface BlobFieldPolicy<T = unknown> {\n /**\n * Age-based TTL in days. A slot whose `uploadedAt` is older than\n * `now - retainDays × 86400s` evicts on the next `vault.compact()`.\n * Omit to disable age-based eviction.\n */\n readonly retainDays?: number\n /**\n * Predicate evaluated against the decrypted record. When it returns\n * `true`, every matching slot on that record evicts. Omit to\n * disable predicate-based eviction.\n */\n readonly evictWhen?: (record: T) => boolean\n}\n\nexport type BlobFieldsConfig<T = unknown> = Record<string, BlobFieldPolicy<T>>\n\n// ─── Audit collection ──────────────────────────────────────────────────\n\nexport const BLOB_EVICTION_AUDIT_COLLECTION = '_blob_eviction_audit'\n\nexport interface BlobEvictionEntry {\n readonly id: string\n readonly collection: string\n readonly recordId: string\n readonly slotName: string\n readonly blobHash: string\n readonly reason: 'ttl' | 'predicate' | 'both'\n readonly evictedAt: string\n readonly actor: string\n}\n\n// ─── Compaction result ──────────────────────────────────────────────────\n\nexport interface CompactionResult {\n /** Number of blob slots evicted across all collections. */\n readonly evicted: number\n /** Number of records touched (iterated + policy checked). */\n readonly records: number\n /** Number of collections with `blobFields` configured. */\n readonly collections: number\n /** Number of audit entries written. Equal to `evicted`. */\n readonly auditEntries: number\n /** Per-collection breakdown for diagnostics. */\n readonly byCollection: Record<string, { records: number; evicted: number }>\n}\n\n// ─── Core ──────────────────────────────────────────────────────────────\n\nexport interface CompactRunOptions {\n /** Override \"now\" for deterministic testing. */\n readonly now?: Date\n /**\n * Stop after this many evictions. Useful for capped batches / cron\n * jobs that need to fit in a time window. `undefined` = unbounded.\n */\n readonly maxEvictions?: number\n /**\n * Dry-run — evaluate policies and return the counts, but do NOT\n * delete slots or write audit entries. Lets a consumer preview\n * what would happen.\n */\n readonly dryRun?: boolean\n}\n\nexport interface CompactionContext {\n readonly adapter: NoydbStore\n readonly vault: string\n readonly actor: string\n readonly encrypted: boolean\n readonly getDEK: (collection: string) => Promise<CryptoKey>\n /**\n * Resolve a collection's declared `blobFields` config. Returns an\n * empty map for collections without the config — the walk skips\n * those.\n */\n readonly getBlobFields: <T>(collection: string) => BlobFieldsConfig<T> | null\n /** List collection names in the vault. */\n readonly listCollections: () => Promise<string[]>\n /** List record ids in a collection. */\n readonly listRecords: (collection: string) => Promise<string[]>\n /** Decrypt and return the record. Null when absent. */\n readonly getRecord: <T>(collection: string, id: string) => Promise<T | null>\n /** Return the BlobSet-like handle for a record's slots. */\n readonly listSlots: (collection: string, id: string) => Promise<SlotInfo[]>\n /** Delete a slot and decrement its blob's refCount. */\n readonly deleteSlot: (collection: string, id: string, slotName: string) => Promise<void>\n}\n\nexport async function runCompaction(\n ctx: CompactionContext,\n options: CompactRunOptions = {},\n): Promise<CompactionResult> {\n const now = options.now ?? new Date()\n const maxEvictions = options.maxEvictions ?? Infinity\n const dryRun = options.dryRun === true\n\n const allCollections = await ctx.listCollections()\n const byCollection: Record<string, { records: number; evicted: number }> = {}\n let evicted = 0\n let records = 0\n let auditEntries = 0\n let collectionsWithPolicy = 0\n\n outer: for (const collectionName of allCollections) {\n if (collectionName.startsWith('_')) continue\n const config = ctx.getBlobFields(collectionName)\n if (!config) continue\n const configuredSlots = Object.keys(config)\n if (configuredSlots.length === 0) continue\n collectionsWithPolicy += 1\n byCollection[collectionName] = { records: 0, evicted: 0 }\n\n const ids = await ctx.listRecords(collectionName)\n for (const recordId of ids) {\n if (evicted >= maxEvictions) break outer\n\n const record = await ctx.getRecord(collectionName, recordId).catch(() => null)\n if (record === null) continue\n records += 1\n byCollection[collectionName].records += 1\n\n const slots = await ctx.listSlots(collectionName, recordId).catch(() => [])\n for (const slot of slots) {\n if (evicted >= maxEvictions) break outer\n const policy = config[slot.name]\n if (!policy) continue\n\n const reason = evaluatePolicy(policy, record, slot, now)\n if (!reason) continue\n\n if (!dryRun) {\n await ctx.deleteSlot(collectionName, recordId, slot.name)\n await writeAuditEntry(ctx, {\n id: generateEvictionId(collectionName, recordId, slot.name),\n collection: collectionName,\n recordId,\n slotName: slot.name,\n blobHash: slot.eTag,\n reason,\n evictedAt: now.toISOString(),\n actor: ctx.actor,\n })\n auditEntries += 1\n }\n evicted += 1\n byCollection[collectionName].evicted += 1\n }\n }\n }\n\n return {\n evicted,\n records,\n collections: collectionsWithPolicy,\n auditEntries,\n byCollection,\n }\n}\n\nfunction evaluatePolicy<T>(\n policy: BlobFieldPolicy<T>,\n record: T,\n slot: SlotInfo,\n now: Date,\n): 'ttl' | 'predicate' | 'both' | null {\n let ttlTriggered = false\n let predicateTriggered = false\n\n if (policy.retainDays !== undefined && policy.retainDays > 0) {\n const uploadedAt = Date.parse(slot.uploadedAt)\n if (Number.isFinite(uploadedAt)) {\n const ageMs = now.getTime() - uploadedAt\n const limitMs = policy.retainDays * 86_400_000\n if (ageMs > limitMs) ttlTriggered = true\n }\n }\n\n if (policy.evictWhen) {\n try {\n if (policy.evictWhen(record)) predicateTriggered = true\n } catch {\n // Predicate error → do NOT evict. Fail closed.\n }\n }\n\n if (ttlTriggered && predicateTriggered) return 'both'\n if (ttlTriggered) return 'ttl'\n if (predicateTriggered) return 'predicate'\n return null\n}\n\nfunction generateEvictionId(collection: string, recordId: string, slotName: string): string {\n const rand = globalThis.crypto.getRandomValues(new Uint8Array(8))\n let suffix = ''\n for (const b of rand) suffix += b.toString(16).padStart(2, '0')\n return `${collection}__${recordId}__${slotName}__${suffix}`\n}\n\nasync function writeAuditEntry(ctx: CompactionContext, entry: BlobEvictionEntry): Promise<void> {\n const json = JSON.stringify(entry)\n let envelope: EncryptedEnvelope\n if (ctx.encrypted) {\n const dek = await ctx.getDEK(BLOB_EVICTION_AUDIT_COLLECTION)\n const { iv, data } = await encrypt(json, dek)\n envelope = {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: 1,\n _ts: entry.evictedAt,\n _iv: iv,\n _data: data,\n _by: entry.actor,\n }\n } else {\n envelope = {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: 1,\n _ts: entry.evictedAt,\n _iv: '',\n _data: json,\n _by: entry.actor,\n }\n }\n await ctx.adapter.put(ctx.vault, BLOB_EVICTION_AUDIT_COLLECTION, entry.id, envelope)\n}\n"],"mappings":"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","names":[]}
@@ -1,35 +1,6 @@
1
1
  import {
2
- OverlayIdMismatchError,
3
- ValidationError
4
- } from "./chunk-ADQ5MQ54.js";
5
-
6
- // src/overlay-views/with-overlayed-view.ts
7
- function withOverlayedView(spec) {
8
- if (!spec.name || spec.name.length === 0) {
9
- throw new ValidationError("withOverlayedView: name is required");
10
- }
11
- if (!spec.base || spec.base.length === 0) {
12
- throw new ValidationError("withOverlayedView: base is required");
13
- }
14
- if (!spec.overlay || spec.overlay.length === 0) {
15
- throw new ValidationError("withOverlayedView: overlay is required");
16
- }
17
- if (spec.base === spec.overlay) {
18
- throw new ValidationError("withOverlayedView: base and overlay must be different collections");
19
- }
20
- if (spec.base === spec.name || spec.overlay === spec.name) {
21
- throw new ValidationError(
22
- "withOverlayedView: virtual name must differ from both base and overlay collection names"
23
- );
24
- }
25
- if (!spec.shadowField || spec.shadowField.length === 0) {
26
- throw new ValidationError("withOverlayedView: shadowField is required");
27
- }
28
- return {
29
- __noydb_strategy: "overlayed-view",
30
- spec
31
- };
32
- }
2
+ OverlayIdMismatchError
3
+ } from "./chunk-O6EJ6WTI.js";
33
4
 
34
5
  // src/overlay-views/virtual-collection.ts
35
6
  var OverlayedCollection = class {
@@ -145,7 +116,7 @@ var OverlayedCollection = class {
145
116
  // error pointing at the relevant issue — so consumers don't hit a
146
117
  // cryptic `undefined is not a function` runtime crash.
147
118
  //
148
- // Closes niwat-review of PR #160.
119
+ // Throw-stubs so consumers get actionable errors rather than cryptic crashes.
149
120
  /** @throws — chainable Query<T> over a virtual collection is deferred. */
150
121
  query() {
151
122
  throw new Error(
@@ -203,7 +174,6 @@ var OverlayedCollection = class {
203
174
  };
204
175
 
205
176
  export {
206
- OverlayedCollection,
207
- withOverlayedView
177
+ OverlayedCollection
208
178
  };
209
- //# sourceMappingURL=chunk-Z72JH4KG.js.map
179
+ //# sourceMappingURL=chunk-7CEGU63S.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/overlay-views/virtual-collection.ts"],"sourcesContent":["import { OverlayIdMismatchError } from '../errors.js'\nimport type { Collection } from '../collection.js'\nimport type { OverlayedViewStrategy } from './types.js'\n\n/**\n * Virtual-collection proxy returned by `vault.collection(overlayName)`\n * when `overlayName` is a registered `withOverlayedView`.\n *\n * Implements the core `Collection<T>`-shaped read/write surface with\n * merge-on-read semantics:\n * - `get(id)`: overlay row wins iff `overlay[shadowField] === shadowValue`\n * - `list()` / `.query()`: union of ids, per-id merge applied\n * - `put(record)` / `put(id, record)`: routes to overlay; id derived\n * via the base MV's `rowKey` (validated on the two-arg form)\n * - `delete(id)`: removes the overlay row only; base stays\n *\n * Reactive APIs (`live`, `subscribe`, `query().live()`) are out of\n * scope for this release and surface as \"not yet implemented\" — wired in a\n * future sub-issue.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport class OverlayedCollection<T extends Record<string, unknown> = any> {\n constructor(\n private readonly spec: OverlayedViewStrategy,\n private readonly baseCollection: Collection<T>,\n private readonly overlayCollection: Collection<T>,\n private readonly baseRowKey: ((row: Record<string, unknown>) => string) | undefined,\n ) {}\n\n /**\n * Convenience accessors for advanced callers that need to bypass the\n * virtual layer (bulk imports, direct overlay queries). Mirrors the\n * spec's \"direct writes to the underlying overlay collection skip\n * the validation\" escape hatch.\n */\n readonly overlay = {\n rowKey: (row: Record<string, unknown>): string => {\n if (!this.baseRowKey) {\n throw new Error(\n `Overlay \"${this.spec.name}\": base \"${this.spec.base}\" is not an MV — ` +\n `cannot auto-derive id from the row. Use \\`put(id, record)\\` instead.`,\n )\n }\n return this.baseRowKey(row)\n },\n }\n\n /** Get the merged row by id. */\n async get(id: string): Promise<T | null> {\n const overlayRow = await this.overlayCollection.get(id)\n if (overlayRow !== null && this.shadowPredicateApplies(overlayRow)) {\n return overlayRow\n }\n const baseRow = await this.baseCollection.get(id)\n if (baseRow !== null) return baseRow\n // No base row — but if an overlay row exists with the shadow\n // predicate true, we returned it above. If overlay exists but\n // predicate is false, return null (overlay exists but doesn't\n // qualify, and there's no base to fall back to) — per spec\n // operations table row \"overlay exists, predicate false, no base\".\n return null\n }\n\n /** List union of base + overlay ids, applying the merge per row. */\n async list(): Promise<T[]> {\n const baseRows = await this.baseCollection.list()\n const overlayRows = await this.overlayCollection.list()\n // Build id → merged row, base-first then overlay applies shadow rule.\n const merged = new Map<string, T>()\n const idOf = (row: T): string => {\n // Best-effort: use baseRowKey if available, else assume the row\n // has a `.id` field (common pattern). The spec requires every\n // base MV to declare `rowKey`, so the first branch is the\n // canonical path.\n if (this.baseRowKey) return this.baseRowKey(row as Record<string, unknown>)\n const idField = (row as Record<string, unknown>).id\n return typeof idField === 'string' ? idField : ''\n }\n for (const row of baseRows) {\n const id = idOf(row)\n if (id) merged.set(id, row)\n }\n for (const row of overlayRows) {\n const id = idOf(row)\n if (!id) continue\n if (this.shadowPredicateApplies(row)) {\n merged.set(id, row) // overlay shadow wins\n } else if (!merged.has(id)) {\n // Overlay-only + predicate false + no base → don't surface\n // (matches spec operations table)\n continue\n }\n // else: overlay exists but predicate is false and base is\n // present → keep the base row already in `merged`\n }\n return [...merged.values()]\n }\n\n /**\n * Write to the overlay. Two forms:\n * - `put(record)`: id is derived via the base MV's `rowKey(record)`.\n * Throws if the base isn't an MV.\n * - `put(id, record)`: validates `id === rowKey(record)`; throws\n * `OverlayIdMismatchError` on mismatch.\n */\n async put(idOrRecord: string | T, maybeRecord?: T): Promise<void> {\n let id: string\n let record: T\n if (maybeRecord === undefined) {\n // Single-arg form: put(record). Derive id via base rowKey.\n record = idOrRecord as T\n if (!this.baseRowKey) {\n throw new Error(\n `Overlay \"${this.spec.name}\".put(record): base \"${this.spec.base}\" is not an MV. ` +\n `Use put(id, record) explicitly.`,\n )\n }\n id = this.baseRowKey(record as Record<string, unknown>)\n } else {\n // Two-arg form: put(id, record). Validate against rowKey.\n id = idOrRecord as string\n record = maybeRecord\n if (this.baseRowKey) {\n const expected = this.baseRowKey(record as Record<string, unknown>)\n if (id !== expected) {\n throw new OverlayIdMismatchError(id, expected)\n }\n }\n }\n await this.overlayCollection.put(id, record)\n }\n\n /**\n * Remove the overlay row only. Idempotent (no-op on absent).\n * The base row is untouched — if a base row exists for `id`,\n * subsequent reads return it.\n */\n async delete(id: string): Promise<void> {\n await this.overlayCollection.delete(id)\n }\n\n /** True when `overlay[shadowField] === shadowValue`. */\n private shadowPredicateApplies(row: T): boolean {\n return (row as Record<string, unknown>)[this.spec.shadowField] === this.spec.shadowValue\n }\n\n // ─── Throw-stubs for the unimplemented Collection<T> surface ───────\n //\n // `Vault.collection(name)` widens the return type to `Collection<T>`\n // for the overlay intercept, but `OverlayedCollection` doesn't\n // implement the full surface. These stubs catch the common\n // reactive / chainable APIs with a clear \"not yet implemented\"\n // error pointing at the relevant issue — so consumers don't hit a\n // cryptic `undefined is not a function` runtime crash.\n //\n // Throw-stubs so consumers get actionable errors rather than cryptic crashes.\n\n /** @throws — chainable Query<T> over a virtual collection is deferred. */\n query(): never {\n throw new Error(\n `OverlayedCollection \"${this.spec.name}\".query() is not yet implemented for overlay views (#154). ` +\n `Use \\`list()\\` + filter for now, or read from the underlying \\`${this.spec.base}\\` / \\`${this.spec.overlay}\\` collections directly. ` +\n `Reactive APIs land in a future MV sub-issue.`,\n )\n }\n\n /** @throws — change-stream subscription over a virtual collection is deferred. */\n subscribe(): never {\n throw new Error(\n `OverlayedCollection \"${this.spec.name}\".subscribe() is not yet implemented for overlay views (#154). ` +\n `Subscribe to the underlying \\`${this.spec.base}\\` / \\`${this.spec.overlay}\\` collections individually for now. ` +\n `Merged change-stream lands in a future MV sub-issue.`,\n )\n }\n\n /** @throws — live query over a virtual collection is deferred. */\n live(): never {\n throw new Error(\n `OverlayedCollection \"${this.spec.name}\".live() is not yet implemented for overlay views (#154). ` +\n `Reactive APIs land in a future MV sub-issue.`,\n )\n }\n\n /** @throws — async iteration over a virtual collection is deferred. */\n scan(): never {\n throw new Error(\n `OverlayedCollection \"${this.spec.name}\".scan() is not yet implemented for overlay views (#154). ` +\n `Use \\`list()\\` for now (no row-count ceiling at niwat scale), or scan the underlying collections directly.`,\n )\n }\n\n /** @throws — lazy-mode query is not applicable to virtual collections. */\n lazyQuery(): never {\n throw new Error(\n `OverlayedCollection \"${this.spec.name}\".lazyQuery() is not supported. ` +\n `Virtual collections always materialize through base + overlay reads — lazy-mode indexed lookups don't apply.`,\n )\n }\n\n /** @throws — bulk-atomic put is deferred to a future MV sub-issue. */\n putManyAtomic(): never {\n throw new Error(\n `OverlayedCollection \"${this.spec.name}\".putManyAtomic() is not yet implemented for overlay views (#154). ` +\n `Use sequential \\`.put(record)\\` calls for now, or write to \\`${this.spec.overlay}\\` directly.`,\n )\n }\n\n /** @throws — bulk delete is deferred to a future MV sub-issue. */\n deleteMany(): never {\n throw new Error(\n `OverlayedCollection \"${this.spec.name}\".deleteMany() is not yet implemented for overlay views (#154). ` +\n `Use sequential \\`.delete(id)\\` calls for now, or operate on \\`${this.spec.overlay}\\` directly.`,\n )\n }\n\n /** @throws — `.first()` over a virtual collection is deferred. */\n first(): never {\n throw new Error(\n `OverlayedCollection \"${this.spec.name}\".first() is not yet implemented for overlay views (#154). ` +\n `Use \\`(await list())[0]\\` for now.`,\n )\n }\n\n /** @throws — `.count()` over a virtual collection is deferred. */\n count(): never {\n throw new Error(\n `OverlayedCollection \"${this.spec.name}\".count() is not yet implemented for overlay views (#154). ` +\n `Use \\`(await list()).length\\` for now.`,\n )\n }\n}\n"],"mappings":"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","names":[]}
@@ -13,6 +13,13 @@ var GuardRegistry = class {
13
13
  guardsFor(collection) {
14
14
  return this._byCollection.get(collection) ?? [];
15
15
  }
16
+ /** Per-collection guard counts, for introspection. */
17
+ summary() {
18
+ return [...this._byCollection.entries()].map(([collection, guards]) => ({
19
+ collection,
20
+ count: guards.length
21
+ }));
22
+ }
16
23
  /**
17
24
  * Run every guard's `check` for this collection. First throw wins —
18
25
  * remaining guards are not invoked. Guards without a `check` skip.
@@ -115,4 +122,4 @@ var GuardRegistry = class {
115
122
  export {
116
123
  GuardRegistry
117
124
  };
118
- //# sourceMappingURL=chunk-PEULZC6M.js.map
125
+ //# sourceMappingURL=chunk-A3JMGXPG.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/guards/registry.ts"],"sourcesContent":["import type { GuardStrategy, GuardContext, GuardChange } from './types.js'\n\n/**\n * Per-record metadata attached to every entry in an amendment's\n * change-set. Carried in a parallel map alongside `_amendmentChanges`\n * so the public {@link GuardChange} shape (`{ before, after }`) stays\n * clean for invariant authors — the audit ledger reads this side\n * structure to produce the `{ collection, id, vBefore, vAfter }`\n * tuples for the amendment entry.\n *\n * @internal\n */\nexport interface AmendmentChangeMeta {\n readonly id: string\n readonly vBefore: number\n readonly vAfter: number\n}\n\n/**\n * Vault-internal singleton that holds the guard graph and dispatches\n * per-collection guard execution. Owned by `Vault`; not exported.\n *\n * @internal\n */\n// Internal storage alias — guards are heterogeneous in their record type T,\n// so the registry stores them at the upper bound of GuardStrategy's T constraint.\ntype AnyGuard = GuardStrategy<Record<string, unknown>>\ntype AnyChange = GuardChange<Record<string, unknown>>\n\nexport class GuardRegistry {\n private readonly _byCollection = new Map<string, AnyGuard[]>()\n private _amendmentChanges: Map<string, AnyChange[]> | null = null\n private _amendmentMeta: Map<string, AmendmentChangeMeta[]> | null = null\n\n /** Register a guard. Multiple guards per collection are allowed. */\n register<T extends Record<string, unknown>>(spec: GuardStrategy<T>): void {\n const existing = this._byCollection.get(spec.collection)\n if (existing) existing.push(spec as unknown as AnyGuard)\n else this._byCollection.set(spec.collection, [spec as unknown as AnyGuard])\n }\n\n /** All guards registered against `collection` in registration order. */\n guardsFor(collection: string): ReadonlyArray<AnyGuard> {\n return this._byCollection.get(collection) ?? []\n }\n\n /** Per-collection guard counts, for introspection. */\n summary(): { collection: string; count: number }[] {\n return [...this._byCollection.entries()].map(([collection, guards]) => ({\n collection,\n count: guards.length,\n }))\n }\n\n /**\n * Run every guard's `check` for this collection. First throw wins —\n * remaining guards are not invoked. Guards without a `check` skip.\n */\n async runChecks<T>(\n collection: string,\n incoming: T,\n ctx: GuardContext<T>,\n ): Promise<void> {\n const guards = this._byCollection.get(collection)\n if (!guards) return\n for (const g of guards) {\n if (g.check) {\n await g.check(\n incoming as unknown as Record<string, unknown>,\n ctx as unknown as GuardContext<Record<string, unknown>>,\n )\n }\n }\n }\n\n /**\n * Run every guard's `onDelete` for this collection. First throw wins —\n * remaining guards are not invoked. Guards without an `onDelete` skip.\n * Mirrors {@link runChecks} but for the delete path.\n */\n async runOnDelete<T>(\n collection: string,\n existing: T,\n ctx: GuardContext<T>,\n ): Promise<void> {\n const guards = this._byCollection.get(collection)\n if (!guards) return\n for (const g of guards) {\n if (g.onDelete) {\n await g.onDelete(\n existing as unknown as Record<string, unknown>,\n ctx as unknown as GuardContext<Record<string, unknown>>,\n )\n }\n }\n }\n\n /** True if any guard for `collection` declares an `amendment` block. */\n hasAmendment(collection: string): boolean {\n const guards = this._byCollection.get(collection)\n if (!guards) return false\n return guards.some(g => g.amendment !== undefined)\n }\n\n /** Open a new amendment change-collection window. */\n beginAmendment(): void {\n this._amendmentChanges = new Map()\n this._amendmentMeta = new Map()\n }\n\n /** True iff we're currently inside an amendment transaction. */\n isAmendmentActive(): boolean {\n return this._amendmentChanges !== null\n }\n\n /**\n * Record a {before, after} pair for the active amendment. `vBefore`\n * and `vAfter` are stored in a parallel meta structure so the public\n * {@link GuardChange} shape handed to invariant callbacks stays\n * `{ before, after }` only — the audit ledger reads version metadata\n * via {@link consumeMeta}.\n */\n collectChange<T>(\n collection: string,\n id: string,\n before: T | null,\n after: T,\n vBefore = 0,\n vAfter = 0,\n ): void {\n if (this._amendmentChanges === null || this._amendmentMeta === null) {\n throw new Error('GuardRegistry.collectChange called outside an amendment')\n }\n const list = this._amendmentChanges.get(collection)\n const entry = { before, after } as unknown as AnyChange\n if (list) list.push(entry)\n else this._amendmentChanges.set(collection, [entry])\n\n const metaList = this._amendmentMeta.get(collection)\n const metaEntry: AmendmentChangeMeta = { id, vBefore, vAfter }\n if (metaList) metaList.push(metaEntry)\n else this._amendmentMeta.set(collection, [metaEntry])\n }\n\n /**\n * Drain the change-set and close the amendment window. The caller\n * (transaction commit) feeds these to each affected guard's invariant.\n */\n consumeChanges(): ReadonlyMap<string, ReadonlyArray<AnyChange>> {\n const out = this._amendmentChanges ?? new Map()\n this._amendmentChanges = null\n return out\n }\n\n /**\n * Drain the parallel id/version metadata captured during the\n * amendment. Returned as a flat list with `collection` denormalised\n * so the audit ledger can emit one `{ collection, id, vBefore,\n * vAfter }` tuple per record. Must be called AFTER\n * {@link consumeChanges} (or independently) — calling it closes the\n * meta window in the same way.\n */\n consumeMeta(): ReadonlyArray<{ collection: string; id: string; vBefore: number; vAfter: number }> {\n const out: { collection: string; id: string; vBefore: number; vAfter: number }[] = []\n if (this._amendmentMeta) {\n for (const [collection, list] of this._amendmentMeta) {\n for (const m of list) {\n out.push({ collection, id: m.id, vBefore: m.vBefore, vAfter: m.vAfter })\n }\n }\n }\n this._amendmentMeta = null\n return out\n }\n}\n"],"mappings":";AA6BO,IAAM,gBAAN,MAAoB;AAAA,EACR,gBAAgB,oBAAI,IAAwB;AAAA,EACrD,oBAAqD;AAAA,EACrD,iBAA4D;AAAA;AAAA,EAGpE,SAA4C,MAA8B;AACxE,UAAM,WAAW,KAAK,cAAc,IAAI,KAAK,UAAU;AACvD,QAAI,SAAU,UAAS,KAAK,IAA2B;AAAA,QAClD,MAAK,cAAc,IAAI,KAAK,YAAY,CAAC,IAA2B,CAAC;AAAA,EAC5E;AAAA;AAAA,EAGA,UAAU,YAA6C;AACrD,WAAO,KAAK,cAAc,IAAI,UAAU,KAAK,CAAC;AAAA,EAChD;AAAA;AAAA,EAGA,UAAmD;AACjD,WAAO,CAAC,GAAG,KAAK,cAAc,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC,YAAY,MAAM,OAAO;AAAA,MACtE;AAAA,MACA,OAAO,OAAO;AAAA,IAChB,EAAE;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,UACJ,YACA,UACA,KACe;AACf,UAAM,SAAS,KAAK,cAAc,IAAI,UAAU;AAChD,QAAI,CAAC,OAAQ;AACb,eAAW,KAAK,QAAQ;AACtB,UAAI,EAAE,OAAO;AACX,cAAM,EAAE;AAAA,UACN;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,YACJ,YACA,UACA,KACe;AACf,UAAM,SAAS,KAAK,cAAc,IAAI,UAAU;AAChD,QAAI,CAAC,OAAQ;AACb,eAAW,KAAK,QAAQ;AACtB,UAAI,EAAE,UAAU;AACd,cAAM,EAAE;AAAA,UACN;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,aAAa,YAA6B;AACxC,UAAM,SAAS,KAAK,cAAc,IAAI,UAAU;AAChD,QAAI,CAAC,OAAQ,QAAO;AACpB,WAAO,OAAO,KAAK,OAAK,EAAE,cAAc,MAAS;AAAA,EACnD;AAAA;AAAA,EAGA,iBAAuB;AACrB,SAAK,oBAAoB,oBAAI,IAAI;AACjC,SAAK,iBAAiB,oBAAI,IAAI;AAAA,EAChC;AAAA;AAAA,EAGA,oBAA6B;AAC3B,WAAO,KAAK,sBAAsB;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,cACE,YACA,IACA,QACA,OACA,UAAU,GACV,SAAS,GACH;AACN,QAAI,KAAK,sBAAsB,QAAQ,KAAK,mBAAmB,MAAM;AACnE,YAAM,IAAI,MAAM,yDAAyD;AAAA,IAC3E;AACA,UAAM,OAAO,KAAK,kBAAkB,IAAI,UAAU;AAClD,UAAM,QAAQ,EAAE,QAAQ,MAAM;AAC9B,QAAI,KAAM,MAAK,KAAK,KAAK;AAAA,QACpB,MAAK,kBAAkB,IAAI,YAAY,CAAC,KAAK,CAAC;AAEnD,UAAM,WAAW,KAAK,eAAe,IAAI,UAAU;AACnD,UAAM,YAAiC,EAAE,IAAI,SAAS,OAAO;AAC7D,QAAI,SAAU,UAAS,KAAK,SAAS;AAAA,QAChC,MAAK,eAAe,IAAI,YAAY,CAAC,SAAS,CAAC;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,iBAAgE;AAC9D,UAAM,MAAM,KAAK,qBAAqB,oBAAI,IAAI;AAC9C,SAAK,oBAAoB;AACzB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,cAAkG;AAChG,UAAM,MAA6E,CAAC;AACpF,QAAI,KAAK,gBAAgB;AACvB,iBAAW,CAAC,YAAY,IAAI,KAAK,KAAK,gBAAgB;AACpD,mBAAW,KAAK,MAAM;AACpB,cAAI,KAAK,EAAE,YAAY,IAAI,EAAE,IAAI,SAAS,EAAE,SAAS,QAAQ,EAAE,OAAO,CAAC;AAAA,QACzE;AAAA,MACF;AAAA,IACF;AACA,SAAK,iBAAiB;AACtB,WAAO;AAAA,EACT;AACF;","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  dekKey
3
- } from "./chunk-DYBQG5PQ.js";
3
+ } from "./chunk-CXFOITNS.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-WCA2NROQ.js";
12
+ } from "./chunk-R233SLY3.js";
13
13
  import {
14
14
  DelegationTargetMissingError
15
- } from "./chunk-ADQ5MQ54.js";
15
+ } from "./chunk-O6EJ6WTI.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-I6MX32UC.js.map
97
+ //# sourceMappingURL=chunk-BDV7INMP.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  ValidationError
3
- } from "./chunk-ADQ5MQ54.js";
3
+ } from "./chunk-O6EJ6WTI.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-MKSA2V7A.js.map
19
+ //# sourceMappingURL=chunk-C3WE6UJY.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  DerivationCycleError
3
- } from "./chunk-ADQ5MQ54.js";
3
+ } from "./chunk-O6EJ6WTI.js";
4
4
 
5
5
  // src/derivations/strategy-hash.ts
6
6
  async function computeStrategyHash(source, outputKeys, derive) {
@@ -41,6 +41,23 @@ var DerivationRegistry = class {
41
41
  strategiesProducingOutput(collection) {
42
42
  return this._byOutput.get(collection) ?? [];
43
43
  }
44
+ /**
45
+ * All registered strategies as a flat, deduplicated array.
46
+ * Each strategy is indexed once per source (not once per output key),
47
+ * so iterating `_bySource.values()` naturally yields each strategy
48
+ * exactly once per source — deduplication is handled by flattening
49
+ * the per-source arrays and collecting into a Set by identity.
50
+ *
51
+ * Used by `dumpSchema()` / `describeDerivations()` in the introspection
52
+ * walker to populate the derivations map.
53
+ */
54
+ all() {
55
+ const seen = /* @__PURE__ */ new Set();
56
+ for (const strategies of this._bySource.values()) {
57
+ for (const s of strategies) seen.add(s);
58
+ }
59
+ return [...seen];
60
+ }
44
61
  /**
45
62
  * Cycle detection over the source → output → … graph. Call after all
46
63
  * `register()` calls complete (i.e. at vault open). Throws
@@ -76,4 +93,4 @@ var DerivationRegistry = class {
76
93
  export {
77
94
  DerivationRegistry
78
95
  };
79
- //# sourceMappingURL=chunk-FCXOFQAJ.js.map
96
+ //# sourceMappingURL=chunk-CH22FZHT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/derivations/strategy-hash.ts","../src/derivations/registry.ts"],"sourcesContent":["/**\n * Deterministic hash of a derivation strategy's \"shape\": source\n * collection, output keys, derive function source. Used to detect\n * strategy drift: a record whose `_derivedFrom.strategyHash` doesn't\n * match the current strategy is considered stale.\n *\n * Web Crypto SHA-256 — no extra deps.\n */\nexport async function computeStrategyHash(\n source: string,\n outputKeys: readonly string[],\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n derive: (...args: any[]) => any,\n): Promise<string> {\n const canonical = JSON.stringify({\n source,\n outputs: [...outputKeys].sort(),\n derive: derive.toString(),\n })\n const bytes = new TextEncoder().encode(canonical)\n const digest = await crypto.subtle.digest('SHA-256', bytes)\n return Array.from(new Uint8Array(digest))\n .map(b => b.toString(16).padStart(2, '0'))\n .join('')\n}\n","import { DerivationCycleError } from '../errors.js'\nimport { computeStrategyHash } from './strategy-hash.js'\nimport type { DerivationStrategy } from './types.js'\n\ninterface RegisteredStrategy {\n // Type-erased to allow the registry to hold heterogeneous strategies.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n spec: DerivationStrategy<any, any>\n strategyHash: string\n}\n\n/**\n * Vault-internal registry of derivation strategies. Owned by `Vault`;\n * not exported.\n *\n * @internal\n */\nexport class DerivationRegistry {\n private readonly _bySource = new Map<string, RegisteredStrategy[]>()\n private readonly _byOutput = new Map<string, RegisteredStrategy[]>()\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n async register(spec: DerivationStrategy<any, any>): Promise<void> {\n const outputKeys = Object.keys(spec.outputs)\n const strategyHash = await computeStrategyHash(spec.source, outputKeys, spec.derive)\n const reg: RegisteredStrategy = { spec, strategyHash }\n\n const fromSource = this._bySource.get(spec.source)\n if (fromSource) fromSource.push(reg)\n else this._bySource.set(spec.source, [reg])\n\n for (const key of outputKeys) {\n const output = spec.outputs[key]\n if (!output) continue\n const outputCollection = output.collection\n const arr = this._byOutput.get(outputCollection)\n if (arr) arr.push(reg)\n else this._byOutput.set(outputCollection, [reg])\n }\n }\n\n strategiesForSource(source: string): ReadonlyArray<RegisteredStrategy> {\n return this._bySource.get(source) ?? []\n }\n\n strategiesProducingOutput(collection: string): ReadonlyArray<RegisteredStrategy> {\n return this._byOutput.get(collection) ?? []\n }\n\n /**\n * All registered strategies as a flat, deduplicated array.\n * Each strategy is indexed once per source (not once per output key),\n * so iterating `_bySource.values()` naturally yields each strategy\n * exactly once per source — deduplication is handled by flattening\n * the per-source arrays and collecting into a Set by identity.\n *\n * Used by `dumpSchema()` / `describeDerivations()` in the introspection\n * walker to populate the derivations map.\n */\n all(): ReadonlyArray<RegisteredStrategy> {\n const seen = new Set<RegisteredStrategy>()\n for (const strategies of this._bySource.values()) {\n for (const s of strategies) seen.add(s)\n }\n return [...seen]\n }\n\n /**\n * Cycle detection over the source → output → … graph. Call after all\n * `register()` calls complete (i.e. at vault open). Throws\n * `DerivationCycleError` on the first cycle found.\n */\n validate(): void {\n const visited = new Set<string>()\n const stack: string[] = []\n\n const visit = (node: string): void => {\n if (stack.includes(node)) {\n const cycle = stack.slice(stack.indexOf(node)).concat(node)\n throw new DerivationCycleError(cycle)\n }\n if (visited.has(node)) return\n stack.push(node)\n const strategies = this._bySource.get(node)\n if (strategies) {\n for (const s of strategies) {\n for (const key of Object.keys(s.spec.outputs)) {\n const output = s.spec.outputs[key]\n if (!output) continue\n visit(output.collection)\n }\n }\n }\n stack.pop()\n visited.add(node)\n }\n\n for (const src of this._bySource.keys()) visit(src)\n }\n}\n"],"mappings":";;;;;AAQA,eAAsB,oBACpB,QACA,YAEA,QACiB;AACjB,QAAM,YAAY,KAAK,UAAU;AAAA,IAC/B;AAAA,IACA,SAAS,CAAC,GAAG,UAAU,EAAE,KAAK;AAAA,IAC9B,QAAQ,OAAO,SAAS;AAAA,EAC1B,CAAC;AACD,QAAM,QAAQ,IAAI,YAAY,EAAE,OAAO,SAAS;AAChD,QAAM,SAAS,MAAM,OAAO,OAAO,OAAO,WAAW,KAAK;AAC1D,SAAO,MAAM,KAAK,IAAI,WAAW,MAAM,CAAC,EACrC,IAAI,OAAK,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EACxC,KAAK,EAAE;AACZ;;;ACPO,IAAM,qBAAN,MAAyB;AAAA,EACb,YAAY,oBAAI,IAAkC;AAAA,EAClD,YAAY,oBAAI,IAAkC;AAAA;AAAA,EAGnE,MAAM,SAAS,MAAmD;AAChE,UAAM,aAAa,OAAO,KAAK,KAAK,OAAO;AAC3C,UAAM,eAAe,MAAM,oBAAoB,KAAK,QAAQ,YAAY,KAAK,MAAM;AACnF,UAAM,MAA0B,EAAE,MAAM,aAAa;AAErD,UAAM,aAAa,KAAK,UAAU,IAAI,KAAK,MAAM;AACjD,QAAI,WAAY,YAAW,KAAK,GAAG;AAAA,QAC9B,MAAK,UAAU,IAAI,KAAK,QAAQ,CAAC,GAAG,CAAC;AAE1C,eAAW,OAAO,YAAY;AAC5B,YAAM,SAAS,KAAK,QAAQ,GAAG;AAC/B,UAAI,CAAC,OAAQ;AACb,YAAM,mBAAmB,OAAO;AAChC,YAAM,MAAM,KAAK,UAAU,IAAI,gBAAgB;AAC/C,UAAI,IAAK,KAAI,KAAK,GAAG;AAAA,UAChB,MAAK,UAAU,IAAI,kBAAkB,CAAC,GAAG,CAAC;AAAA,IACjD;AAAA,EACF;AAAA,EAEA,oBAAoB,QAAmD;AACrE,WAAO,KAAK,UAAU,IAAI,MAAM,KAAK,CAAC;AAAA,EACxC;AAAA,EAEA,0BAA0B,YAAuD;AAC/E,WAAO,KAAK,UAAU,IAAI,UAAU,KAAK,CAAC;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAyC;AACvC,UAAM,OAAO,oBAAI,IAAwB;AACzC,eAAW,cAAc,KAAK,UAAU,OAAO,GAAG;AAChD,iBAAW,KAAK,WAAY,MAAK,IAAI,CAAC;AAAA,IACxC;AACA,WAAO,CAAC,GAAG,IAAI;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,WAAiB;AACf,UAAM,UAAU,oBAAI,IAAY;AAChC,UAAM,QAAkB,CAAC;AAEzB,UAAM,QAAQ,CAAC,SAAuB;AACpC,UAAI,MAAM,SAAS,IAAI,GAAG;AACxB,cAAM,QAAQ,MAAM,MAAM,MAAM,QAAQ,IAAI,CAAC,EAAE,OAAO,IAAI;AAC1D,cAAM,IAAI,qBAAqB,KAAK;AAAA,MACtC;AACA,UAAI,QAAQ,IAAI,IAAI,EAAG;AACvB,YAAM,KAAK,IAAI;AACf,YAAM,aAAa,KAAK,UAAU,IAAI,IAAI;AAC1C,UAAI,YAAY;AACd,mBAAW,KAAK,YAAY;AAC1B,qBAAW,OAAO,OAAO,KAAK,EAAE,KAAK,OAAO,GAAG;AAC7C,kBAAM,SAAS,EAAE,KAAK,QAAQ,GAAG;AACjC,gBAAI,CAAC,OAAQ;AACb,kBAAM,OAAO,UAAU;AAAA,UACzB;AAAA,QACF;AAAA,MACF;AACA,YAAM,IAAI;AACV,cAAQ,IAAI,IAAI;AAAA,IAClB;AAEA,eAAW,OAAO,KAAK,UAAU,KAAK,EAAG,OAAM,GAAG;AAAA,EACpD;AACF;","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  TierNotGrantedError
3
- } from "./chunk-ADQ5MQ54.js";
3
+ } from "./chunk-O6EJ6WTI.js";
4
4
 
5
5
  // src/team/tiers.ts
6
6
  function dekKey(collection, tier) {
@@ -31,4 +31,4 @@ export {
31
31
  effectiveClearance,
32
32
  assertTierAccess
33
33
  };
34
- //# sourceMappingURL=chunk-DYBQG5PQ.js.map
34
+ //# sourceMappingURL=chunk-CXFOITNS.js.map
@@ -1,12 +1,13 @@
1
1
  import {
2
2
  readPath
3
- } from "./chunk-MRIBLZL3.js";
3
+ } from "./chunk-TV3YZ35S.js";
4
4
 
5
5
  // src/aggregate/reducers.ts
6
6
  function count(opts) {
7
7
  const _seed = opts?.seed;
8
8
  void _seed;
9
9
  return {
10
+ op: "count",
10
11
  init: () => 0,
11
12
  step: (state) => state + 1,
12
13
  remove: (state) => state - 1,
@@ -17,6 +18,8 @@ function sum(field, opts) {
17
18
  const _seed = opts?.seed;
18
19
  void _seed;
19
20
  return {
21
+ op: "sum",
22
+ field,
20
23
  init: () => 0,
21
24
  step: (state, record) => state + readNumber(record, field),
22
25
  remove: (state, record) => state - readNumber(record, field),
@@ -27,6 +30,8 @@ function avg(field, opts) {
27
30
  const _seed = opts?.seed;
28
31
  void _seed;
29
32
  return {
33
+ op: "avg",
34
+ field,
30
35
  init: () => ({ sum: 0, count: 0 }),
31
36
  step: (state, record) => ({
32
37
  sum: state.sum + readNumber(record, field),
@@ -53,6 +58,8 @@ function min(field, opts) {
53
58
  const _seed = opts?.seed;
54
59
  void _seed;
55
60
  return {
61
+ op: "min",
62
+ field,
56
63
  init: () => ({ values: [] }),
57
64
  step: (state, record) => pushValue(state, readNumber(record, field)),
58
65
  remove: (state, record) => removeValue(state, readNumber(record, field)),
@@ -71,6 +78,8 @@ function max(field, opts) {
71
78
  const _seed = opts?.seed;
72
79
  void _seed;
73
80
  return {
81
+ op: "max",
82
+ field,
74
83
  init: () => ({ values: [] }),
75
84
  step: (state, record) => pushValue(state, readNumber(record, field)),
76
85
  remove: (state, record) => removeValue(state, readNumber(record, field)),
@@ -97,4 +106,4 @@ export {
97
106
  min,
98
107
  max
99
108
  };
100
- //# sourceMappingURL=chunk-5ZGZ6HIZ.js.map
109
+ //# sourceMappingURL=chunk-CXJG63MA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/aggregate/reducers.ts"],"sourcesContent":["/**\n * Aggregation reducers for the query DSL.\n *\n * the reducer protocol plus five built-in factories\n * (`count`, `sum`, `avg`, `min`, `max`) consumed by `Query.aggregate()`\n * and, in the future, `Scan.aggregate()`. Every factory accepts\n * an optional `{ seed }` parameter that is plumbed through the\n * protocol but unused by the executor — that's the load-bearing\n * half of constraint #2. When partition-aware aggregation\n * lands, the seed carries the previous partition's running total into\n * the next partition without requiring a protocol change.\n *\n * Reducers are intentionally generic over their internal state type\n * `S` so compound reducers (avg keeps `{sum, count}`, min/max keep a\n * value bag) can model internal bookkeeping without leaking the\n * implementation through the accumulator's public shape. `finalize`\n * collapses `S` back into the user-visible `R`.\n *\n * Reducers are pure data — `init` / `step` / `finalize` / optional\n * `remove` are stateless functions that receive and return `S`. This\n * is the shape that admits O(1) incremental maintenance in a future\n * optimization (delta-aware `LiveAggregation` applies `step` or\n * `remove` per delta), without blocking the simpler \"full re-run on\n * source change\" that ships.\n */\n\nimport { readPath } from '../query/predicate.js'\n\n/**\n * A single reducer: factory-produced, ready to plug into an\n * `.aggregate()` spec.\n *\n * Type parameters:\n * - `R` — user-visible result type (what the aggregation returns\n * for this slot, e.g. `number` for `sum()`)\n * - `S` — internal state type, defaults to `R` for simple reducers\n * that don't need compound bookkeeping\n *\n * A reducer is stateless: every method is pure over `S`. `init()` is\n * called once per aggregation run to build the initial state; `step()`\n * folds a record into the state; `remove()` (optional) un-folds a\n * record, enabling incremental live maintenance; `finalize()` reads\n * the final answer out of the state at the end of the run.\n */\nexport interface Reducer<R, S = R> {\n /** Build the initial state for a fresh aggregation run. */\n init(): S\n /** Fold a record into the state. Returns the new state. */\n step(state: S, record: unknown): S\n /**\n * Un-fold a record from the state. Returns the new state.\n *\n * Optional — reducers without `remove` cannot be maintained\n * incrementally and must be re-run from scratch when the underlying\n * record set changes. `sum`, `count`, `avg` implement `remove` in\n * O(1); `min` and `max` implement it in O(N) worst case (when the\n * extremum itself is removed and the next extremum must be\n * recomputed from the remaining contributing values).\n */\n remove?(state: S, record: unknown): S\n /** Collapse the internal state into the user-visible result. */\n finalize(state: S): R\n /**\n * Identifying operation tag stamped by each built-in factory.\n * Used by `summariseAggregateOp` in the introspection walker to\n * render human-readable aggregate descriptors in `dumpSchema()`.\n * Optional so third-party custom reducers are unaffected.\n */\n readonly op?: 'count' | 'sum' | 'avg' | 'min' | 'max'\n /**\n * Field name for field-based reducers (`sum`, `avg`, `min`, `max`).\n * Absent on `count` which aggregates over record count, not a field.\n */\n readonly field?: string\n}\n\n/**\n * Common options accepted by every reducer factory.\n *\n * `seed` — optional initial value for the internal state. **Unused by\n * the executor**, plumbed through the protocol for constraint\n * #2 (partition-aware aggregation seam). In, partitioned\n * aggregations will pass the previous partition's carry as `seed` so\n * a long time series can be rolled forward one partition at a time\n * without re-aggregating closed partitions.\n *\n * always uses `init()` with the factory's zero value, regardless\n * of whether `seed` was passed. Do not remove the parameter — that's\n * the whole point of having it exist now.\n */\nexport interface ReducerOptions<TSeed = unknown> {\n /** constraint #2 — seed is plumbed through but unused in. */\n readonly seed?: TSeed\n}\n\n// ---------------------------------------------------------------------------\n// Factories\n// ---------------------------------------------------------------------------\n\n/**\n * Count the number of records that match the query. Ignores field\n * values entirely — the count is over the number of records, not over\n * the number of non-null field values in any column.\n */\nexport function count(opts?: ReducerOptions<number>): Reducer<number> {\n // Seed captured on the closure but unused at execution time in\n //. The reference in _seed keeps lint happy.\n const _seed = opts?.seed\n void _seed\n return {\n op: 'count',\n init: () => 0,\n step: (state) => state + 1,\n remove: (state) => state - 1,\n finalize: (state) => state,\n }\n}\n\n/**\n * Sum a numeric field across all matching records. Non-number values\n * at the field path are coerced to 0 — consumers who want a different\n * behavior (throw, skip, treat as NaN) should filter upstream via\n * `.where()` or write a custom reducer.\n */\nexport function sum(\n field: string,\n opts?: ReducerOptions<number>,\n): Reducer<number> {\n const _seed = opts?.seed\n void _seed\n return {\n op: 'sum',\n field,\n init: () => 0,\n step: (state, record) => state + readNumber(record, field),\n remove: (state, record) => state - readNumber(record, field),\n finalize: (state) => state,\n }\n}\n\n/**\n * Arithmetic mean of a numeric field across all matching records.\n *\n * Returns `null` for an empty result set (zero records is not a\n * well-defined denominator — returning NaN would poison downstream\n * arithmetic, and throwing would force every consumer to wrap in\n * try/catch just to handle \"no matches\"). Consumers who want an\n * explicit zero should coalesce with `?? 0`.\n *\n * Internal state is `{sum, count}` so the running average can be\n * maintained incrementally — on each delta, both fields update in\n * O(1) and `finalize` divides. Directly storing `avg` as state would\n * not admit incremental removal without also tracking count.\n */\nexport function avg(\n field: string,\n opts?: ReducerOptions<{ sum: number; count: number }>,\n): Reducer<number | null, { sum: number; count: number }> {\n const _seed = opts?.seed\n void _seed\n return {\n op: 'avg',\n field,\n init: () => ({ sum: 0, count: 0 }),\n step: (state, record) => ({\n sum: state.sum + readNumber(record, field),\n count: state.count + 1,\n }),\n remove: (state, record) => ({\n sum: state.sum - readNumber(record, field),\n count: state.count - 1,\n }),\n finalize: (state) => (state.count === 0 ? null : state.sum / state.count),\n }\n}\n\ninterface MinMaxState {\n /**\n * Multiset of contributing field values. Stored as a plain array\n * because we need to support `remove` and a plain array gives us\n * O(1) push + O(N) worst-case removal — which matches the\n * documented min/max removal complexity. A sorted structure would\n * let us drop the O(N) rescan but adds complexity that doesn't\n * need; consumers hitting the O(N) ceiling should file an issue.\n */\n readonly values: number[]\n}\n\nfunction pushValue(state: MinMaxState, value: number): MinMaxState {\n return { values: [...state.values, value] }\n}\n\nfunction removeValue(state: MinMaxState, value: number): MinMaxState {\n // Remove the first matching value — duplicates are fine, we only\n // need to drop one instance per `remove()` call so the multiset\n // count stays consistent with the record count.\n const idx = state.values.indexOf(value)\n if (idx < 0) return state\n const next = state.values.slice()\n next.splice(idx, 1)\n return { values: next }\n}\n\n/**\n * Smallest numeric value of a field across all matching records.\n * Returns `null` for an empty result set. See `avg()` for the\n * reasoning on `null` vs NaN vs throwing.\n *\n * Incremental complexity: O(1) for `step`, O(N) worst case for\n * `remove` when the current minimum is removed (the state holds the\n * full multiset of contributing values and `finalize` scans for the\n * new minimum). Consumers with very large result sets and frequent\n * removals of the current extremum should either accept the cost or\n * wait for a future optimization.\n */\nexport function min(\n field: string,\n opts?: ReducerOptions<number>,\n): Reducer<number | null, MinMaxState> {\n const _seed = opts?.seed\n void _seed\n return {\n op: 'min',\n field,\n init: () => ({ values: [] }),\n step: (state, record) => pushValue(state, readNumber(record, field)),\n remove: (state, record) => removeValue(state, readNumber(record, field)),\n finalize: (state) => {\n if (state.values.length === 0) return null\n let out = state.values[0]!\n for (let i = 1; i < state.values.length; i++) {\n const v = state.values[i]!\n if (v < out) out = v\n }\n return out\n },\n }\n}\n\n/**\n * Largest numeric value of a field across all matching records.\n * Mirror of `min()` — see that doc for semantics, null-on-empty\n * behavior, and the O(N) removal caveat.\n */\nexport function max(\n field: string,\n opts?: ReducerOptions<number>,\n): Reducer<number | null, MinMaxState> {\n const _seed = opts?.seed\n void _seed\n return {\n op: 'max',\n field,\n init: () => ({ values: [] }),\n step: (state, record) => pushValue(state, readNumber(record, field)),\n remove: (state, record) => removeValue(state, readNumber(record, field)),\n finalize: (state) => {\n if (state.values.length === 0) return null\n let out = state.values[0]!\n for (let i = 1; i < state.values.length; i++) {\n const v = state.values[i]!\n if (v > out) out = v\n }\n return out\n },\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Read a numeric field from a record. Non-number values (null,\n * undefined, strings, objects) coerce to 0 so sum/avg/min/max don't\n * produce NaN on one bad row. Consumers who want strict typing should\n * validate upstream with Standard Schema, which NOYDB already runs on\n * every `put()`.\n */\nfunction readNumber(record: unknown, field: string): number {\n const value = readPath(record, field)\n return typeof value === 'number' && Number.isFinite(value) ? value : 0\n}\n"],"mappings":"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","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  ValidationError
3
- } from "./chunk-ADQ5MQ54.js";
3
+ } from "./chunk-O6EJ6WTI.js";
4
4
 
5
5
  // src/derivations/with-derivation.ts
6
6
  function withDerivation(spec) {
@@ -21,7 +21,7 @@ function withDerivation(spec) {
21
21
  if (outputSpec.shape === "array") {
22
22
  if (lifecycleMode !== "eager") {
23
23
  throw new ValidationError(
24
- `withDerivation: shape 'array' supports lifecycle 'eager' only in this release (#200 slice 1). Output "${outputKey}" declared lifecycle '${lifecycleMode}'. Switch to \`lifecycle: "eager"\` or use shape: "record".`
24
+ `withDerivation: shape 'array' supports lifecycle 'eager' only in this release Output "${outputKey}" declared lifecycle '${lifecycleMode}'. Switch to \`lifecycle: "eager"\` or use shape: "record".`
25
25
  );
26
26
  }
27
27
  if (typeof outputSpec.key !== "function") {
@@ -48,4 +48,4 @@ function withDerivation(spec) {
48
48
  export {
49
49
  withDerivation
50
50
  };
51
- //# sourceMappingURL=chunk-EGQYGYIU.js.map
51
+ //# sourceMappingURL=chunk-DAP2XL7Q.js.map