@noy-db/hub 0.10.0-pre.0 → 0.10.0-pre.2

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 (492) hide show
  1. package/CHANGELOG.md +90 -0
  2. package/README.md +2 -2
  3. package/dist/api-QSEKT4KS.js +15 -0
  4. package/dist/as/index.js +19 -12
  5. package/dist/as/index.js.map +1 -1
  6. package/dist/at/index.js +6 -9
  7. package/dist/attestation/index.js +16 -19
  8. package/dist/attestation/index.js.map +1 -1
  9. package/dist/{backup-E3GBMNDA.js → backup-BHKVK5SD.js} +9 -12
  10. package/dist/{backup-E3GBMNDA.js.map → backup-BHKVK5SD.js.map} +1 -1
  11. package/dist/blobs/index.js +10 -13
  12. package/dist/blobs/index.js.map +1 -1
  13. package/dist/broker/index.js +11 -14
  14. package/dist/broker/index.js.map +1 -1
  15. package/dist/by/index.js +2 -2
  16. package/dist/capsule/contract.d.ts +176 -16
  17. package/dist/capsule/contract.js +35 -30
  18. package/dist/capsule/enclave-aes/bound.d.ts +11 -1
  19. package/dist/capsule/enclave-aes/classify/digest.d.ts +4 -2
  20. package/dist/capsule/enclave-aes/index.d.ts +9 -0
  21. package/dist/capsule/enclave-aes/index.js +643 -78
  22. package/dist/capsule/enclave-aes/index.js.map +1 -1
  23. package/dist/capsule/enclave-aes/primitives.d.ts +2 -2
  24. package/dist/capsule/index.d.ts +1 -1
  25. package/dist/capsule/plumbing/classify-reveal.d.ts +29 -0
  26. package/dist/capsule/plumbing/classify-verify.d.ts +53 -0
  27. package/dist/capsule/plumbing/index.d.ts +17 -0
  28. package/dist/{capsule-YQKQZPH7.js → capsule-YAITMH77.js} +16 -9
  29. package/dist/cargo/index.js +34 -36
  30. package/dist/{chunk-U43RSPPX.js → chunk-23A4SBRR.js} +3 -4
  31. package/dist/{chunk-U43RSPPX.js.map → chunk-23A4SBRR.js.map} +1 -1
  32. package/dist/{chunk-PREYKC76.js → chunk-24AGG4PP.js} +3 -3
  33. package/dist/{chunk-ZVJKHGE5.js → chunk-24IJZA4M.js} +14 -8
  34. package/dist/chunk-24IJZA4M.js.map +1 -0
  35. package/dist/{chunk-4N4OIVK3.js → chunk-2NVQ5SEA.js} +15 -5
  36. package/dist/chunk-2NVQ5SEA.js.map +1 -0
  37. package/dist/{chunk-ZNVBCKMV.js → chunk-2SIREKBR.js} +2 -2
  38. package/dist/{chunk-N6EWQ5VB.js → chunk-37FOG6AE.js} +14 -7
  39. package/dist/chunk-37FOG6AE.js.map +1 -0
  40. package/dist/{chunk-UQRKAM2R.js → chunk-3M2KK7O7.js} +3 -3
  41. package/dist/{chunk-P6FATPXQ.js → chunk-3ZCVY3T6.js} +2 -2
  42. package/dist/{chunk-PBEHTFUG.js → chunk-4CGWLHPQ.js} +6 -6
  43. package/dist/{chunk-PFHDQY5L.js → chunk-56Z4NOC6.js} +3 -3
  44. package/dist/{chunk-GLSCL74M.js → chunk-5AVIUJP4.js} +13 -9
  45. package/dist/chunk-5AVIUJP4.js.map +1 -0
  46. package/dist/{chunk-F7X7MPK4.js → chunk-5BGHAVBN.js} +2 -2
  47. package/dist/{chunk-QHG7GQKM.js → chunk-5JNEDW7I.js} +2 -2
  48. package/dist/{chunk-GHMINSER.js → chunk-5OWJSDTO.js} +4 -4
  49. package/dist/{chunk-GHMINSER.js.map → chunk-5OWJSDTO.js.map} +1 -1
  50. package/dist/{chunk-DYIR6RC3.js → chunk-5Y4MO7UQ.js} +4 -4
  51. package/dist/{chunk-TLIFNRU5.js → chunk-63LZLRWG.js} +2 -2
  52. package/dist/{chunk-GZISWBCJ.js → chunk-74W56QPY.js} +4 -4
  53. package/dist/{chunk-CLOSXHR4.js → chunk-7KNYLHVX.js} +3 -3
  54. package/dist/chunk-7KNYLHVX.js.map +1 -0
  55. package/dist/{chunk-LFUID7OW.js → chunk-7VJ2SIEI.js} +42 -22
  56. package/dist/chunk-7VJ2SIEI.js.map +1 -0
  57. package/dist/{chunk-WVQDY3UM.js → chunk-AHA7UALU.js} +4 -4
  58. package/dist/{chunk-U277K5GR.js → chunk-AIHBYQHF.js} +259 -123
  59. package/dist/chunk-AIHBYQHF.js.map +1 -0
  60. package/dist/{chunk-S2ORTQGS.js → chunk-ANYX2M6P.js} +3 -3
  61. package/dist/{chunk-6WEPFEMJ.js → chunk-ATKYMRBC.js} +4 -4
  62. package/dist/{chunk-7UHLO4ZN.js → chunk-B2HU55QD.js} +2 -2
  63. package/dist/{chunk-Y22JWHCP.js → chunk-BEKMLYQ4.js} +4 -4
  64. package/dist/{chunk-27NCEPKM.js → chunk-BPFXD4EX.js} +23 -3
  65. package/dist/chunk-BPFXD4EX.js.map +1 -0
  66. package/dist/{chunk-7C7OF26T.js → chunk-C2NXAR3D.js} +5 -5
  67. package/dist/{chunk-Z2KP6PNF.js → chunk-CJBWJO5P.js} +6 -6
  68. package/dist/{chunk-Z2KP6PNF.js.map → chunk-CJBWJO5P.js.map} +1 -1
  69. package/dist/{chunk-6WIFF46H.js → chunk-CQLMRCKX.js} +2 -2
  70. package/dist/{chunk-URGHKZPL.js → chunk-CR5UPYIJ.js} +1 -1
  71. package/dist/chunk-CR5UPYIJ.js.map +1 -0
  72. package/dist/{chunk-LMC5L3MM.js → chunk-DS2JXSUA.js} +6 -6
  73. package/dist/{chunk-X6Z2SIRF.js → chunk-E2JIE4S3.js} +2 -2
  74. package/dist/{chunk-EQ6C2ZPT.js → chunk-E7Y4J4GL.js} +2 -2
  75. package/dist/{chunk-LZN6DTFI.js → chunk-ECDM6YRX.js} +2 -2
  76. package/dist/{chunk-WRLWEYHY.js → chunk-EFINFZIF.js} +11 -1
  77. package/dist/chunk-EFINFZIF.js.map +1 -0
  78. package/dist/{chunk-2T2TGRWE.js → chunk-EM56MHN5.js} +6 -6
  79. package/dist/{chunk-NK4LGBGQ.js → chunk-EQXOJH6O.js} +4 -4
  80. package/dist/{chunk-OK44MD3C.js → chunk-ET3U2C3A.js} +2 -2
  81. package/dist/{chunk-RF5WDM25.js → chunk-EU4G7PQH.js} +2 -2
  82. package/dist/{chunk-K5JNK63R.js → chunk-EUCUYK5E.js} +10 -10
  83. package/dist/{chunk-2ODEFG6K.js → chunk-EWSIJDWO.js} +4 -4
  84. package/dist/{chunk-LJ744WXU.js → chunk-F2FD4LSB.js} +2 -2
  85. package/dist/{chunk-L4UL4IAR.js → chunk-F7ENMZYJ.js} +2 -2
  86. package/dist/{chunk-KBIS64X4.js → chunk-FIIVYQOW.js} +5 -5
  87. package/dist/{chunk-TBVDI3LY.js → chunk-FPK2LPLR.js} +8 -8
  88. package/dist/chunk-FPK2LPLR.js.map +1 -0
  89. package/dist/{chunk-BQJ5ORU5.js → chunk-FQEUJGBV.js} +2 -2
  90. package/dist/{chunk-UORWAG7K.js → chunk-FY4FFNKK.js} +2 -2
  91. package/dist/{chunk-MMWX5OT5.js → chunk-GDCYZGPB.js} +2 -2
  92. package/dist/{chunk-7ONMS7QI.js → chunk-H6Q7GKLI.js} +2 -2
  93. package/dist/{chunk-654RE5YC.js → chunk-HDAPQF6Q.js} +3 -3
  94. package/dist/{chunk-5SMCBPJ2.js → chunk-HRLMUZLI.js} +5 -5
  95. package/dist/{chunk-R4GLRJ55.js → chunk-HRNQYGLQ.js} +2 -2
  96. package/dist/{chunk-HTRLQ4ZZ.js → chunk-I4S7IZSS.js} +321 -235
  97. package/dist/chunk-I4S7IZSS.js.map +1 -0
  98. package/dist/{chunk-UNAMWK2Q.js → chunk-IN4XZJYD.js} +4 -3
  99. package/dist/{chunk-UNAMWK2Q.js.map → chunk-IN4XZJYD.js.map} +1 -1
  100. package/dist/{chunk-2RH5SEY7.js → chunk-ISIXU45J.js} +2 -2
  101. package/dist/chunk-ISIXU45J.js.map +1 -0
  102. package/dist/{chunk-NHEKQWFI.js → chunk-J4L4AS2W.js} +2 -2
  103. package/dist/{chunk-UMV5GBTJ.js → chunk-JPSOFWJR.js} +2 -2
  104. package/dist/{chunk-A52BK5AY.js → chunk-JRCO67NG.js} +2 -2
  105. package/dist/{chunk-FVKQ5QUC.js → chunk-JW3I3NNZ.js} +2 -2
  106. package/dist/{chunk-BNYDOF2Q.js → chunk-JZMPSQBH.js} +4 -4
  107. package/dist/{chunk-ZK2WT532.js → chunk-K5TVSOPQ.js} +5 -5
  108. package/dist/{chunk-2IASHJPS.js → chunk-K75SL74I.js} +2 -2
  109. package/dist/{chunk-O3NGOHXQ.js → chunk-KA4AAUST.js} +2 -2
  110. package/dist/chunk-KHSBMLQE.js +161 -0
  111. package/dist/chunk-KHSBMLQE.js.map +1 -0
  112. package/dist/{chunk-QQLXKDGC.js → chunk-KUGUML7H.js} +3 -3
  113. package/dist/{chunk-AMSSAOOB.js → chunk-L4J5NC2Q.js} +2 -2
  114. package/dist/{chunk-AYOQZJDB.js → chunk-LIX4QPMM.js} +2 -2
  115. package/dist/{chunk-WIUH6EJ7.js → chunk-LWQFGR34.js} +3 -3
  116. package/dist/{chunk-QNOWNCZS.js → chunk-MMSSHMHW.js} +2 -2
  117. package/dist/{chunk-T5EXREMW.js → chunk-N25Z6PR4.js} +6 -5
  118. package/dist/chunk-N25Z6PR4.js.map +1 -0
  119. package/dist/{chunk-ND6S2DKC.js → chunk-N5S2BCW3.js} +2 -2
  120. package/dist/{chunk-X5RGG3ZW.js → chunk-NIZH2TYZ.js} +2 -2
  121. package/dist/{chunk-SXPLIRQH.js → chunk-NLDBQHDV.js} +2 -2
  122. package/dist/{chunk-AI35LNWQ.js → chunk-NQQ4MOPC.js} +4 -4
  123. package/dist/{chunk-B6EWMGFX.js → chunk-NUBI6PYH.js} +2 -2
  124. package/dist/{chunk-ID4ZBC3X.js → chunk-NYEXUZDW.js} +4 -4
  125. package/dist/{chunk-GU6QXHPZ.js → chunk-OIBFIWVJ.js} +4 -4
  126. package/dist/chunk-OIBFIWVJ.js.map +1 -0
  127. package/dist/{chunk-PWAMX5KU.js → chunk-OOLF5FU2.js} +2 -2
  128. package/dist/{chunk-WQUIJPN4.js → chunk-OQA7UF2Q.js} +3 -3
  129. package/dist/{chunk-7JRLCP2J.js → chunk-ORJPICJI.js} +2 -2
  130. package/dist/{chunk-IF2M43G4.js → chunk-PBRD75JF.js} +2 -2
  131. package/dist/{chunk-RKBCUP5D.js → chunk-PDCBL23X.js} +39 -17
  132. package/dist/chunk-PDCBL23X.js.map +1 -0
  133. package/dist/{chunk-BSEPI3HD.js → chunk-PR36DD2X.js} +7 -7
  134. package/dist/{chunk-52ZFNK46.js → chunk-PV4HIC4E.js} +2 -2
  135. package/dist/{chunk-TU6ZJTYT.js → chunk-PZNK4HTV.js} +3 -3
  136. package/dist/{chunk-LUQBG637.js → chunk-QBLPLNPE.js} +3 -3
  137. package/dist/{chunk-UADW5NOU.js → chunk-QZXUISRF.js} +5 -5
  138. package/dist/{chunk-BMAXBTYH.js → chunk-RBXYO7MD.js} +5 -5
  139. package/dist/{chunk-PZN76MMV.js → chunk-RIACRFWA.js} +4 -4
  140. package/dist/{chunk-ICHHNI5E.js → chunk-RL6RNDJQ.js} +8 -8
  141. package/dist/{chunk-4WLI37WK.js → chunk-SJ2P7UXD.js} +7 -7
  142. package/dist/{chunk-2QH3I7QC.js → chunk-SWXS4LV3.js} +11 -11
  143. package/dist/{chunk-4KYKRYRT.js → chunk-TOTCZFRF.js} +2 -2
  144. package/dist/{chunk-CSAN22QG.js → chunk-TT4D52EK.js} +6 -6
  145. package/dist/{chunk-VLRY2UH4.js → chunk-U7CMJY5P.js} +10 -10
  146. package/dist/{chunk-NIUHKKMM.js → chunk-UNKTZDA2.js} +11 -11
  147. package/dist/{chunk-NIUHKKMM.js.map → chunk-UNKTZDA2.js.map} +1 -1
  148. package/dist/{chunk-QVUMKG3Z.js → chunk-UXH4AKH3.js} +95 -151
  149. package/dist/chunk-UXH4AKH3.js.map +1 -0
  150. package/dist/{chunk-PU5ZEV65.js → chunk-UZVHSYIF.js} +2 -2
  151. package/dist/{chunk-3EXQXOQ2.js → chunk-VHKAW5OI.js} +29 -5
  152. package/dist/chunk-VHKAW5OI.js.map +1 -0
  153. package/dist/{chunk-XQGKS4OW.js → chunk-VKZ3TDET.js} +3 -3
  154. package/dist/{chunk-ZOFNZLAA.js → chunk-VLZPUG5A.js} +4 -4
  155. package/dist/{chunk-OR3OHKU6.js → chunk-VSN5FLMI.js} +2 -2
  156. package/dist/{chunk-JQMEXCUZ.js → chunk-VYBBE7RN.js} +8 -8
  157. package/dist/chunk-VYBBE7RN.js.map +1 -0
  158. package/dist/{chunk-SVXFCCSX.js → chunk-WHK4JVKF.js} +8 -8
  159. package/dist/{chunk-YVA6UPRN.js → chunk-X4LDBALX.js} +2 -2
  160. package/dist/{chunk-35CNOVQE.js → chunk-X67E7NIJ.js} +3 -3
  161. package/dist/{chunk-IPF5ORDI.js → chunk-XMARKBUC.js} +3 -3
  162. package/dist/{chunk-B3B6HV5S.js → chunk-XMBBTETD.js} +2 -2
  163. package/dist/{chunk-GQ4MF3CM.js → chunk-XMBTAN5E.js} +28 -14
  164. package/dist/chunk-XMBTAN5E.js.map +1 -0
  165. package/dist/{chunk-FUHUGKDN.js → chunk-XROQP6IQ.js} +4 -4
  166. package/dist/chunk-XWWDZKLS.js +196 -0
  167. package/dist/chunk-XWWDZKLS.js.map +1 -0
  168. package/dist/{chunk-DL4GCSTS.js → chunk-Y2RYUWSQ.js} +10 -10
  169. package/dist/{chunk-7IV7GVOS.js → chunk-YCTSQV7K.js} +5 -5
  170. package/dist/{chunk-IFUYLIEY.js → chunk-YF7P2DG7.js} +2 -2
  171. package/dist/{chunk-PIO6NW7O.js → chunk-ZG7DBIVX.js} +2 -2
  172. package/dist/{chunk-NUZ7ROUZ.js → chunk-ZGJ775X7.js} +2 -2
  173. package/dist/{chunk-6BEBWHNL.js → chunk-ZQQLOEWN.js} +3 -3
  174. package/dist/classified/index.js +5 -5
  175. package/dist/{classified-marker-7HXDMYHI.js → classified-marker-HKMRC7SC.js} +3 -3
  176. package/dist/{reveal-UAPBG743.js → classify-reveal-YSJKJEIR.js} +7 -12
  177. package/dist/classify-reveal-YSJKJEIR.js.map +1 -0
  178. package/dist/{verify-QWO5UKD6.js → classify-verify-ZCTKYQ43.js} +31 -41
  179. package/dist/classify-verify-ZCTKYQ43.js.map +1 -0
  180. package/dist/collection-facade-PPKNUR2J.js +38 -0
  181. package/dist/{computed-LZLSYOPG.js → computed-UCYVPMZA.js} +3 -3
  182. package/dist/consent/index.js +6 -9
  183. package/dist/consent/index.js.map +1 -1
  184. package/dist/cover/index.js +6 -9
  185. package/dist/custody/index.js +11 -13
  186. package/dist/{dead-filter-PZIJ4F4G.js → dead-filter-YOBWRG4O.js} +8 -11
  187. package/dist/{dead-filter-PZIJ4F4G.js.map → dead-filter-YOBWRG4O.js.map} +1 -1
  188. package/dist/debug/index.js +5 -8
  189. package/dist/debug/index.js.map +1 -1
  190. package/dist/delegation-SNALWRMO.js +24 -0
  191. package/dist/derivations/index.js +20 -23
  192. package/dist/derive-4GNU4E4I.js +17 -0
  193. package/dist/directory/index.js +7 -10
  194. package/dist/{dispatch-4BUYPWMJ.js → dispatch-QW32QBLW.js} +17 -20
  195. package/dist/{dispatch-4BUYPWMJ.js.map → dispatch-QW32QBLW.js.map} +1 -1
  196. package/dist/{dispatch-KOPDDPEQ.js → dispatch-V5WLDTVX.js} +5 -5
  197. package/dist/executor-7QN22OKI.js +8 -0
  198. package/dist/executor-BJZJNVBB.js +8 -0
  199. package/dist/executor-JEAAEJUM.js +32 -0
  200. package/dist/export-accessible-TVO2KQPG.js +20 -0
  201. package/dist/extract-partition-43CLDRN4.js +33 -0
  202. package/dist/{fanout-sidecar-FYDRL7F3.js → fanout-sidecar-DDONAFJT.js} +6 -9
  203. package/dist/{fanout-sidecar-FYDRL7F3.js.map → fanout-sidecar-DDONAFJT.js.map} +1 -1
  204. package/dist/forget/index.js +6 -9
  205. package/dist/forget/index.js.map +1 -1
  206. package/dist/guards/index.js +4 -4
  207. package/dist/history/index.js +11 -14
  208. package/dist/history/index.js.map +1 -1
  209. package/dist/i18n/index.js +11 -14
  210. package/dist/i18n/index.js.map +1 -1
  211. package/dist/index.d.ts +2 -2
  212. package/dist/index.js +122 -123
  213. package/dist/index.js.map +1 -1
  214. package/dist/indexing/index.js +5 -5
  215. package/dist/introspection/index.js +8 -11
  216. package/dist/issue-EIHEDAXM.js +16 -0
  217. package/dist/kernel/capsule-requirements.d.ts +84 -0
  218. package/dist/kernel/errors.d.ts +19 -3
  219. package/dist/kernel/export-scope.d.ts +28 -1
  220. package/dist/kernel/store-segment-guard.d.ts +29 -0
  221. package/dist/kernel/types.d.ts +169 -13
  222. package/dist/kernel/validation.d.ts +32 -0
  223. package/dist/kernel/vault.d.ts +5 -5
  224. package/dist/{ledger-UFJCB6T5.js → ledger-BMVUFQ3R.js} +8 -11
  225. package/dist/liberate-7KHXCLNJ.js +23 -0
  226. package/dist/link-set-PC2EJRKL.js +26 -0
  227. package/dist/{managed-secret-H5WYSJ46.js → managed-secret-RPRVEYZA.js} +7 -10
  228. package/dist/materialized-views/index.js +23 -26
  229. package/dist/{migrate-cek-SPESQAAO.js → migrate-cek-DTSCWGEF.js} +2 -2
  230. package/dist/money/index.js +5 -5
  231. package/dist/noydb-AYDNOXAX.js +98 -0
  232. package/dist/on/index.js +11 -13
  233. package/dist/overlay-views/index.js +4 -4
  234. package/dist/periods/index.js +9 -12
  235. package/dist/pod/index.js +65 -67
  236. package/dist/{pod-handle-GJLCOUGK.js → pod-handle-KBPQRN6Q.js} +6 -9
  237. package/dist/{pod-handle-GJLCOUGK.js.map → pod-handle-KBPQRN6Q.js.map} +1 -1
  238. package/dist/policy/index.js +7 -10
  239. package/dist/port/at/index.d.ts +1 -0
  240. package/dist/port/with/admission-authority.d.ts +2 -1
  241. package/dist/port/with/collection-registries.d.ts +37 -0
  242. package/dist/portability/index.js +8 -8
  243. package/dist/{post-register-2AC2STHC.js → post-register-RITSNASO.js} +6 -6
  244. package/dist/query/all/index.js +15 -15
  245. package/dist/query/index.js +7 -7
  246. package/dist/query/live/index.js +7 -7
  247. package/dist/query/reduce/index.js +10 -10
  248. package/dist/query/relate/index.js +9 -9
  249. package/dist/reduce/index.js +8 -8
  250. package/dist/register-BB34SK7E.js +27 -0
  251. package/dist/registry-65L6V5TO.js +20 -0
  252. package/dist/registry-HU62GPWA.js +32 -0
  253. package/dist/registry-SMNK6UM4.js +8 -0
  254. package/dist/registry-X5VPBKCO.js +8 -0
  255. package/dist/request-withdrawal-4SKAH46W.js +26 -0
  256. package/dist/{restore-to-OOPKLAPU.js → restore-to-VQHT67OH.js} +7 -10
  257. package/dist/{restore-to-OOPKLAPU.js.map → restore-to-VQHT67OH.js.map} +1 -1
  258. package/dist/revoke-IF5PX2JY.js +21 -0
  259. package/dist/satellites/index.js +1 -1
  260. package/dist/schema-update/index.js +2 -2
  261. package/dist/sealed-record/index.js +9 -12
  262. package/dist/sealed-record/index.js.map +1 -1
  263. package/dist/search/index.js +4 -4
  264. package/dist/{seed-BVYDPVIW.js → seed-F2OSDZJR.js} +11 -13
  265. package/dist/{seed-BVYDPVIW.js.map → seed-F2OSDZJR.js.map} +1 -1
  266. package/dist/sequence/index.js +6 -9
  267. package/dist/session/index.js +6 -9
  268. package/dist/session/index.js.map +1 -1
  269. package/dist/shadow/index.js +2 -2
  270. package/dist/signer-5P7IZC2K.js +20 -0
  271. package/dist/snapshots/index.js +8 -10
  272. package/dist/snapshots/index.js.map +1 -1
  273. package/dist/{stale-CROGJBIJ.js → stale-PUCZH5GJ.js} +7 -10
  274. package/dist/storage-5EGY5OYE.js +18 -0
  275. package/dist/store/index.js +1 -1
  276. package/dist/{store-coordination-provider-2YD2PTTP.js → store-coordination-provider-SEQM7SHJ.js} +7 -10
  277. package/dist/{store-coordination-provider-2YD2PTTP.js.map → store-coordination-provider-SEQM7SHJ.js.map} +1 -1
  278. package/dist/sync/index.js +13 -15
  279. package/dist/sync/index.js.map +1 -1
  280. package/dist/team/index.js +14 -16
  281. package/dist/tiers/index.js +8 -11
  282. package/dist/to/index.js +2 -2
  283. package/dist/transactions/index.js +3 -3
  284. package/dist/util/index.js +1 -1
  285. package/dist/vault-diff-H7LT5ZBJ.js +8 -0
  286. package/dist/vault-head/index.js +5 -8
  287. package/dist/vault-head/index.js.map +1 -1
  288. package/dist/walk-Z4N7PCZ2.js +17 -0
  289. package/dist/with-audit/portability/export-accessible.d.ts +3 -1
  290. package/dist/with-cargo/vault-diff.d.ts +28 -0
  291. package/dist/with-commit/sequence/index.d.ts +22 -0
  292. package/dist/with-party/team/delegation.d.ts +16 -12
  293. package/dist/with-party/team/keyring.d.ts +77 -0
  294. package/dist/with-party/team/managed-secret.d.ts +40 -3
  295. package/dist/with-party/team/noydb-facade.d.ts +2 -2
  296. package/dist/with-party/team/peer-recover.d.ts +2 -2
  297. package/dist/with-party/team/rotate-recover.d.ts +3 -3
  298. package/dist/with-shape/manifest/storage.d.ts +2 -2
  299. package/dist/with-shape/manifest/writer.d.ts +2 -2
  300. package/dist/with-store/store-middleware.d.ts +18 -5
  301. package/dist/with-sync/engine.d.ts +0 -2
  302. package/dist/withdraw-accessible-CRCIQSTL.js +23 -0
  303. package/package.json +3 -3
  304. package/dist/api-H4B7ZQXP.js +0 -18
  305. package/dist/capsule/enclave-aes/classify/reveal.d.ts +0 -10
  306. package/dist/capsule/enclave-aes/classify/verify.d.ts +0 -36
  307. package/dist/chunk-27NCEPKM.js.map +0 -1
  308. package/dist/chunk-2RH5SEY7.js.map +0 -1
  309. package/dist/chunk-3EXQXOQ2.js.map +0 -1
  310. package/dist/chunk-4N4OIVK3.js.map +0 -1
  311. package/dist/chunk-5A3HOTP5.js +0 -591
  312. package/dist/chunk-5A3HOTP5.js.map +0 -1
  313. package/dist/chunk-CLOSXHR4.js.map +0 -1
  314. package/dist/chunk-EPPAEGH5.js +0 -157
  315. package/dist/chunk-EPPAEGH5.js.map +0 -1
  316. package/dist/chunk-GLSCL74M.js.map +0 -1
  317. package/dist/chunk-GQ4MF3CM.js.map +0 -1
  318. package/dist/chunk-GU6QXHPZ.js.map +0 -1
  319. package/dist/chunk-HTRLQ4ZZ.js.map +0 -1
  320. package/dist/chunk-JQMEXCUZ.js.map +0 -1
  321. package/dist/chunk-LFUID7OW.js.map +0 -1
  322. package/dist/chunk-N6EWQ5VB.js.map +0 -1
  323. package/dist/chunk-NH2UOV3B.js +0 -18
  324. package/dist/chunk-NH2UOV3B.js.map +0 -1
  325. package/dist/chunk-O6VOR4NH.js +0 -27
  326. package/dist/chunk-O6VOR4NH.js.map +0 -1
  327. package/dist/chunk-ODBOHPZU.js +0 -22
  328. package/dist/chunk-ODBOHPZU.js.map +0 -1
  329. package/dist/chunk-Q4DBU5RM.js +0 -78
  330. package/dist/chunk-Q4DBU5RM.js.map +0 -1
  331. package/dist/chunk-QVUMKG3Z.js.map +0 -1
  332. package/dist/chunk-RKBCUP5D.js.map +0 -1
  333. package/dist/chunk-T5EXREMW.js.map +0 -1
  334. package/dist/chunk-TBVDI3LY.js.map +0 -1
  335. package/dist/chunk-U277K5GR.js.map +0 -1
  336. package/dist/chunk-URGHKZPL.js.map +0 -1
  337. package/dist/chunk-VZFTON37.js +0 -40
  338. package/dist/chunk-VZFTON37.js.map +0 -1
  339. package/dist/chunk-WRLWEYHY.js.map +0 -1
  340. package/dist/chunk-ZVJKHGE5.js.map +0 -1
  341. package/dist/collection-facade-V63BEBGU.js +0 -41
  342. package/dist/delegation-7SSGIETH.js +0 -26
  343. package/dist/derive-IMI3BMDS.js +0 -20
  344. package/dist/executor-7SY3M6TZ.js +0 -8
  345. package/dist/executor-SNHW4ELF.js +0 -35
  346. package/dist/executor-Z3IKK7G3.js +0 -8
  347. package/dist/export-accessible-O7DIVFUO.js +0 -22
  348. package/dist/extract-partition-ELZEJKXM.js +0 -35
  349. package/dist/find-KWB2RYWJ.js +0 -10
  350. package/dist/issue-5ZHXK4HJ.js +0 -19
  351. package/dist/liberate-OEOSNNFH.js +0 -25
  352. package/dist/link-set-KMUBFN2L.js +0 -29
  353. package/dist/noydb-QDZ4QIKO.js +0 -100
  354. package/dist/register-PIORIMMR.js +0 -30
  355. package/dist/registry-BIMICFUH.js +0 -23
  356. package/dist/registry-JGWLW53D.js +0 -35
  357. package/dist/registry-SELCBYEQ.js +0 -8
  358. package/dist/registry-W327UNYH.js +0 -8
  359. package/dist/request-withdrawal-K3SXXODI.js +0 -28
  360. package/dist/reveal-UAPBG743.js.map +0 -1
  361. package/dist/revoke-6AFVXTWF.js +0 -24
  362. package/dist/signer-TW5MAQJP.js +0 -23
  363. package/dist/storage-SO2L2Z5J.js +0 -21
  364. package/dist/vault-diff-C6WUJFNP.js +0 -8
  365. package/dist/verify-QWO5UKD6.js.map +0 -1
  366. package/dist/walk-3KEOL7BY.js +0 -20
  367. package/dist/withdraw-accessible-OZU525ND.js +0 -25
  368. package/dist/withdraw-accessible-OZU525ND.js.map +0 -1
  369. /package/dist/{api-H4B7ZQXP.js.map → api-QSEKT4KS.js.map} +0 -0
  370. /package/dist/{capsule-YQKQZPH7.js.map → capsule-YAITMH77.js.map} +0 -0
  371. /package/dist/{chunk-PREYKC76.js.map → chunk-24AGG4PP.js.map} +0 -0
  372. /package/dist/{chunk-ZNVBCKMV.js.map → chunk-2SIREKBR.js.map} +0 -0
  373. /package/dist/{chunk-UQRKAM2R.js.map → chunk-3M2KK7O7.js.map} +0 -0
  374. /package/dist/{chunk-P6FATPXQ.js.map → chunk-3ZCVY3T6.js.map} +0 -0
  375. /package/dist/{chunk-PBEHTFUG.js.map → chunk-4CGWLHPQ.js.map} +0 -0
  376. /package/dist/{chunk-PFHDQY5L.js.map → chunk-56Z4NOC6.js.map} +0 -0
  377. /package/dist/{chunk-F7X7MPK4.js.map → chunk-5BGHAVBN.js.map} +0 -0
  378. /package/dist/{chunk-QHG7GQKM.js.map → chunk-5JNEDW7I.js.map} +0 -0
  379. /package/dist/{chunk-DYIR6RC3.js.map → chunk-5Y4MO7UQ.js.map} +0 -0
  380. /package/dist/{chunk-TLIFNRU5.js.map → chunk-63LZLRWG.js.map} +0 -0
  381. /package/dist/{chunk-GZISWBCJ.js.map → chunk-74W56QPY.js.map} +0 -0
  382. /package/dist/{chunk-WVQDY3UM.js.map → chunk-AHA7UALU.js.map} +0 -0
  383. /package/dist/{chunk-S2ORTQGS.js.map → chunk-ANYX2M6P.js.map} +0 -0
  384. /package/dist/{chunk-6WEPFEMJ.js.map → chunk-ATKYMRBC.js.map} +0 -0
  385. /package/dist/{chunk-7UHLO4ZN.js.map → chunk-B2HU55QD.js.map} +0 -0
  386. /package/dist/{chunk-Y22JWHCP.js.map → chunk-BEKMLYQ4.js.map} +0 -0
  387. /package/dist/{chunk-7C7OF26T.js.map → chunk-C2NXAR3D.js.map} +0 -0
  388. /package/dist/{chunk-6WIFF46H.js.map → chunk-CQLMRCKX.js.map} +0 -0
  389. /package/dist/{chunk-LMC5L3MM.js.map → chunk-DS2JXSUA.js.map} +0 -0
  390. /package/dist/{chunk-X6Z2SIRF.js.map → chunk-E2JIE4S3.js.map} +0 -0
  391. /package/dist/{chunk-EQ6C2ZPT.js.map → chunk-E7Y4J4GL.js.map} +0 -0
  392. /package/dist/{chunk-LZN6DTFI.js.map → chunk-ECDM6YRX.js.map} +0 -0
  393. /package/dist/{chunk-2T2TGRWE.js.map → chunk-EM56MHN5.js.map} +0 -0
  394. /package/dist/{chunk-NK4LGBGQ.js.map → chunk-EQXOJH6O.js.map} +0 -0
  395. /package/dist/{chunk-OK44MD3C.js.map → chunk-ET3U2C3A.js.map} +0 -0
  396. /package/dist/{chunk-RF5WDM25.js.map → chunk-EU4G7PQH.js.map} +0 -0
  397. /package/dist/{chunk-K5JNK63R.js.map → chunk-EUCUYK5E.js.map} +0 -0
  398. /package/dist/{chunk-2ODEFG6K.js.map → chunk-EWSIJDWO.js.map} +0 -0
  399. /package/dist/{chunk-LJ744WXU.js.map → chunk-F2FD4LSB.js.map} +0 -0
  400. /package/dist/{chunk-L4UL4IAR.js.map → chunk-F7ENMZYJ.js.map} +0 -0
  401. /package/dist/{chunk-KBIS64X4.js.map → chunk-FIIVYQOW.js.map} +0 -0
  402. /package/dist/{chunk-BQJ5ORU5.js.map → chunk-FQEUJGBV.js.map} +0 -0
  403. /package/dist/{chunk-UORWAG7K.js.map → chunk-FY4FFNKK.js.map} +0 -0
  404. /package/dist/{chunk-MMWX5OT5.js.map → chunk-GDCYZGPB.js.map} +0 -0
  405. /package/dist/{chunk-7ONMS7QI.js.map → chunk-H6Q7GKLI.js.map} +0 -0
  406. /package/dist/{chunk-654RE5YC.js.map → chunk-HDAPQF6Q.js.map} +0 -0
  407. /package/dist/{chunk-5SMCBPJ2.js.map → chunk-HRLMUZLI.js.map} +0 -0
  408. /package/dist/{chunk-R4GLRJ55.js.map → chunk-HRNQYGLQ.js.map} +0 -0
  409. /package/dist/{chunk-NHEKQWFI.js.map → chunk-J4L4AS2W.js.map} +0 -0
  410. /package/dist/{chunk-UMV5GBTJ.js.map → chunk-JPSOFWJR.js.map} +0 -0
  411. /package/dist/{chunk-A52BK5AY.js.map → chunk-JRCO67NG.js.map} +0 -0
  412. /package/dist/{chunk-FVKQ5QUC.js.map → chunk-JW3I3NNZ.js.map} +0 -0
  413. /package/dist/{chunk-BNYDOF2Q.js.map → chunk-JZMPSQBH.js.map} +0 -0
  414. /package/dist/{chunk-ZK2WT532.js.map → chunk-K5TVSOPQ.js.map} +0 -0
  415. /package/dist/{chunk-2IASHJPS.js.map → chunk-K75SL74I.js.map} +0 -0
  416. /package/dist/{chunk-O3NGOHXQ.js.map → chunk-KA4AAUST.js.map} +0 -0
  417. /package/dist/{chunk-QQLXKDGC.js.map → chunk-KUGUML7H.js.map} +0 -0
  418. /package/dist/{chunk-AMSSAOOB.js.map → chunk-L4J5NC2Q.js.map} +0 -0
  419. /package/dist/{chunk-AYOQZJDB.js.map → chunk-LIX4QPMM.js.map} +0 -0
  420. /package/dist/{chunk-WIUH6EJ7.js.map → chunk-LWQFGR34.js.map} +0 -0
  421. /package/dist/{chunk-QNOWNCZS.js.map → chunk-MMSSHMHW.js.map} +0 -0
  422. /package/dist/{chunk-ND6S2DKC.js.map → chunk-N5S2BCW3.js.map} +0 -0
  423. /package/dist/{chunk-X5RGG3ZW.js.map → chunk-NIZH2TYZ.js.map} +0 -0
  424. /package/dist/{chunk-SXPLIRQH.js.map → chunk-NLDBQHDV.js.map} +0 -0
  425. /package/dist/{chunk-AI35LNWQ.js.map → chunk-NQQ4MOPC.js.map} +0 -0
  426. /package/dist/{chunk-B6EWMGFX.js.map → chunk-NUBI6PYH.js.map} +0 -0
  427. /package/dist/{chunk-ID4ZBC3X.js.map → chunk-NYEXUZDW.js.map} +0 -0
  428. /package/dist/{chunk-PWAMX5KU.js.map → chunk-OOLF5FU2.js.map} +0 -0
  429. /package/dist/{chunk-WQUIJPN4.js.map → chunk-OQA7UF2Q.js.map} +0 -0
  430. /package/dist/{chunk-7JRLCP2J.js.map → chunk-ORJPICJI.js.map} +0 -0
  431. /package/dist/{chunk-IF2M43G4.js.map → chunk-PBRD75JF.js.map} +0 -0
  432. /package/dist/{chunk-BSEPI3HD.js.map → chunk-PR36DD2X.js.map} +0 -0
  433. /package/dist/{chunk-52ZFNK46.js.map → chunk-PV4HIC4E.js.map} +0 -0
  434. /package/dist/{chunk-TU6ZJTYT.js.map → chunk-PZNK4HTV.js.map} +0 -0
  435. /package/dist/{chunk-LUQBG637.js.map → chunk-QBLPLNPE.js.map} +0 -0
  436. /package/dist/{chunk-UADW5NOU.js.map → chunk-QZXUISRF.js.map} +0 -0
  437. /package/dist/{chunk-BMAXBTYH.js.map → chunk-RBXYO7MD.js.map} +0 -0
  438. /package/dist/{chunk-PZN76MMV.js.map → chunk-RIACRFWA.js.map} +0 -0
  439. /package/dist/{chunk-ICHHNI5E.js.map → chunk-RL6RNDJQ.js.map} +0 -0
  440. /package/dist/{chunk-4WLI37WK.js.map → chunk-SJ2P7UXD.js.map} +0 -0
  441. /package/dist/{chunk-2QH3I7QC.js.map → chunk-SWXS4LV3.js.map} +0 -0
  442. /package/dist/{chunk-4KYKRYRT.js.map → chunk-TOTCZFRF.js.map} +0 -0
  443. /package/dist/{chunk-CSAN22QG.js.map → chunk-TT4D52EK.js.map} +0 -0
  444. /package/dist/{chunk-VLRY2UH4.js.map → chunk-U7CMJY5P.js.map} +0 -0
  445. /package/dist/{chunk-PU5ZEV65.js.map → chunk-UZVHSYIF.js.map} +0 -0
  446. /package/dist/{chunk-XQGKS4OW.js.map → chunk-VKZ3TDET.js.map} +0 -0
  447. /package/dist/{chunk-ZOFNZLAA.js.map → chunk-VLZPUG5A.js.map} +0 -0
  448. /package/dist/{chunk-OR3OHKU6.js.map → chunk-VSN5FLMI.js.map} +0 -0
  449. /package/dist/{chunk-SVXFCCSX.js.map → chunk-WHK4JVKF.js.map} +0 -0
  450. /package/dist/{chunk-YVA6UPRN.js.map → chunk-X4LDBALX.js.map} +0 -0
  451. /package/dist/{chunk-35CNOVQE.js.map → chunk-X67E7NIJ.js.map} +0 -0
  452. /package/dist/{chunk-IPF5ORDI.js.map → chunk-XMARKBUC.js.map} +0 -0
  453. /package/dist/{chunk-B3B6HV5S.js.map → chunk-XMBBTETD.js.map} +0 -0
  454. /package/dist/{chunk-FUHUGKDN.js.map → chunk-XROQP6IQ.js.map} +0 -0
  455. /package/dist/{chunk-DL4GCSTS.js.map → chunk-Y2RYUWSQ.js.map} +0 -0
  456. /package/dist/{chunk-7IV7GVOS.js.map → chunk-YCTSQV7K.js.map} +0 -0
  457. /package/dist/{chunk-IFUYLIEY.js.map → chunk-YF7P2DG7.js.map} +0 -0
  458. /package/dist/{chunk-PIO6NW7O.js.map → chunk-ZG7DBIVX.js.map} +0 -0
  459. /package/dist/{chunk-NUZ7ROUZ.js.map → chunk-ZGJ775X7.js.map} +0 -0
  460. /package/dist/{chunk-6BEBWHNL.js.map → chunk-ZQQLOEWN.js.map} +0 -0
  461. /package/dist/{classified-marker-7HXDMYHI.js.map → classified-marker-HKMRC7SC.js.map} +0 -0
  462. /package/dist/{collection-facade-V63BEBGU.js.map → collection-facade-PPKNUR2J.js.map} +0 -0
  463. /package/dist/{computed-LZLSYOPG.js.map → computed-UCYVPMZA.js.map} +0 -0
  464. /package/dist/{delegation-7SSGIETH.js.map → delegation-SNALWRMO.js.map} +0 -0
  465. /package/dist/{derive-IMI3BMDS.js.map → derive-4GNU4E4I.js.map} +0 -0
  466. /package/dist/{dispatch-KOPDDPEQ.js.map → dispatch-V5WLDTVX.js.map} +0 -0
  467. /package/dist/{executor-7SY3M6TZ.js.map → executor-7QN22OKI.js.map} +0 -0
  468. /package/dist/{executor-SNHW4ELF.js.map → executor-BJZJNVBB.js.map} +0 -0
  469. /package/dist/{executor-Z3IKK7G3.js.map → executor-JEAAEJUM.js.map} +0 -0
  470. /package/dist/{export-accessible-O7DIVFUO.js.map → export-accessible-TVO2KQPG.js.map} +0 -0
  471. /package/dist/{extract-partition-ELZEJKXM.js.map → extract-partition-43CLDRN4.js.map} +0 -0
  472. /package/dist/{find-KWB2RYWJ.js.map → issue-EIHEDAXM.js.map} +0 -0
  473. /package/dist/{issue-5ZHXK4HJ.js.map → ledger-BMVUFQ3R.js.map} +0 -0
  474. /package/dist/{ledger-UFJCB6T5.js.map → liberate-7KHXCLNJ.js.map} +0 -0
  475. /package/dist/{liberate-OEOSNNFH.js.map → link-set-PC2EJRKL.js.map} +0 -0
  476. /package/dist/{link-set-KMUBFN2L.js.map → managed-secret-RPRVEYZA.js.map} +0 -0
  477. /package/dist/{migrate-cek-SPESQAAO.js.map → migrate-cek-DTSCWGEF.js.map} +0 -0
  478. /package/dist/{managed-secret-H5WYSJ46.js.map → noydb-AYDNOXAX.js.map} +0 -0
  479. /package/dist/{post-register-2AC2STHC.js.map → post-register-RITSNASO.js.map} +0 -0
  480. /package/dist/{noydb-QDZ4QIKO.js.map → register-BB34SK7E.js.map} +0 -0
  481. /package/dist/{register-PIORIMMR.js.map → registry-65L6V5TO.js.map} +0 -0
  482. /package/dist/{registry-BIMICFUH.js.map → registry-HU62GPWA.js.map} +0 -0
  483. /package/dist/{registry-JGWLW53D.js.map → registry-SMNK6UM4.js.map} +0 -0
  484. /package/dist/{registry-SELCBYEQ.js.map → registry-X5VPBKCO.js.map} +0 -0
  485. /package/dist/{registry-W327UNYH.js.map → request-withdrawal-4SKAH46W.js.map} +0 -0
  486. /package/dist/{request-withdrawal-K3SXXODI.js.map → revoke-IF5PX2JY.js.map} +0 -0
  487. /package/dist/{revoke-6AFVXTWF.js.map → signer-5P7IZC2K.js.map} +0 -0
  488. /package/dist/{signer-TW5MAQJP.js.map → stale-PUCZH5GJ.js.map} +0 -0
  489. /package/dist/{stale-CROGJBIJ.js.map → storage-5EGY5OYE.js.map} +0 -0
  490. /package/dist/{storage-SO2L2Z5J.js.map → vault-diff-H7LT5ZBJ.js.map} +0 -0
  491. /package/dist/{vault-diff-C6WUJFNP.js.map → walk-Z4N7PCZ2.js.map} +0 -0
  492. /package/dist/{walk-3KEOL7BY.js.map → withdraw-accessible-CRCIQSTL.js.map} +0 -0
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  buildRecordEnvelope
3
- } from "./chunk-WRLWEYHY.js";
3
+ } from "./chunk-EFINFZIF.js";
4
4
 
5
5
  // src/with-party/policy/storage.ts
6
6
  var META_COLLECTION = "_meta";
@@ -36,4 +36,4 @@ export {
36
36
  loadVaultPolicy,
37
37
  saveVaultPolicy
38
38
  };
39
- //# sourceMappingURL=chunk-B3B6HV5S.js.map
39
+ //# sourceMappingURL=chunk-XMBBTETD.js.map
@@ -343,6 +343,26 @@ function mergeSnapshots(snapshots) {
343
343
  }
344
344
 
345
345
  // src/with-store/store-middleware.ts
346
+ function overlay(next, overrides) {
347
+ const bound = /* @__PURE__ */ new WeakMap();
348
+ return new Proxy(next, {
349
+ get(target, prop) {
350
+ if (Object.prototype.hasOwnProperty.call(overrides, prop)) {
351
+ return overrides[prop];
352
+ }
353
+ const value = Reflect.get(target, prop, target);
354
+ if (typeof value !== "function") return value;
355
+ const cached = bound.get(value);
356
+ if (cached !== void 0) return cached;
357
+ const forward = (...args) => Reflect.apply(value, target, args);
358
+ bound.set(value, forward);
359
+ return forward;
360
+ },
361
+ has(target, prop) {
362
+ return Object.prototype.hasOwnProperty.call(overrides, prop) || Reflect.has(target, prop);
363
+ }
364
+ });
365
+ }
346
366
  function wrapStore(store, ...middlewares) {
347
367
  let result = store;
348
368
  for (let i = middlewares.length - 1; i >= 0; i--) {
@@ -376,8 +396,7 @@ function withRetry(opts = {}) {
376
396
  }
377
397
  throw lastError;
378
398
  }
379
- return (next) => ({
380
- ...next,
399
+ return (next) => overlay(next, {
381
400
  name: next.name ? `retry(${next.name})` : "retry",
382
401
  get: (v, c, id) => retryable(() => next.get(v, c, id)),
383
402
  put: (v, c, id, env, ev) => retryable(() => next.put(v, c, id, env, ev)),
@@ -411,8 +430,7 @@ function withLogging(opts = {}) {
411
430
  }
412
431
  );
413
432
  }
414
- return (next) => ({
415
- ...next,
433
+ return (next) => overlay(next, {
416
434
  name: next.name ? `log(${next.name})` : "log",
417
435
  get: (v, c, id) => timed("get", { vault: v, collection: c, id }, () => next.get(v, c, id)),
418
436
  put: (v, c, id, env, ev) => timed("put", {
@@ -457,8 +475,7 @@ function withMetrics(opts) {
457
475
  }
458
476
  );
459
477
  }
460
- return (next) => ({
461
- ...next,
478
+ return (next) => overlay(next, {
462
479
  name: next.name ? `metrics(${next.name})` : "metrics",
463
480
  get: (v, c, id) => tracked("get", v, () => next.get(v, c, id), c, id),
464
481
  put: (v, c, id, env, ev) => tracked("put", v, () => next.put(v, c, id, env, ev), c, id),
@@ -512,8 +529,7 @@ function withCircuitBreaker(opts = {}) {
512
529
  throw err;
513
530
  }
514
531
  }
515
- return (next) => ({
516
- ...next,
532
+ return (next) => overlay(next, {
517
533
  name: next.name ? `cb(${next.name})` : "cb",
518
534
  get: (v, c, id) => guarded(() => next.get(v, c, id), null),
519
535
  put: (v, c, id, env, ev) => guarded(() => next.put(v, c, id, env, ev), void 0),
@@ -551,8 +567,7 @@ function withCache(opts = {}) {
551
567
  function invalidate(key) {
552
568
  cache.delete(key);
553
569
  }
554
- return (next) => ({
555
- ...next,
570
+ return (next) => overlay(next, {
556
571
  name: next.name ? `cache(${next.name})` : "cache",
557
572
  async get(vault, collection, id) {
558
573
  const key = cacheKey(vault, collection, id);
@@ -615,8 +630,7 @@ function withHealthCheck(opts = {}) {
615
630
  setInterval(() => {
616
631
  void doCheck();
617
632
  }, intervalMs);
618
- const wrapped = {
619
- ...next,
633
+ const wrapped = overlay(next, {
620
634
  name: next.name ? `health(${next.name})` : "health",
621
635
  async get(v, c, id) {
622
636
  return isSuspended ? null : next.get(v, c, id);
@@ -636,7 +650,7 @@ function withHealthCheck(opts = {}) {
636
650
  async saveAll(v, d) {
637
651
  if (!isSuspended) await next.saveAll(v, d);
638
652
  }
639
- };
653
+ });
640
654
  return wrapped;
641
655
  };
642
656
  }
@@ -651,4 +665,4 @@ export {
651
665
  withCache,
652
666
  withHealthCheck
653
667
  };
654
- //# sourceMappingURL=chunk-GQ4MF3CM.js.map
668
+ //# sourceMappingURL=chunk-XMBTAN5E.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/with-store/route-store.ts","../src/with-store/store-middleware.ts"],"sourcesContent":["/**\n * Store router / multiplexer.\n *\n * Dispatches `NoydbStore` operations to different backends based on\n * collection type, record size, record age, collection name, or vault name.\n *\n * ```ts\n * const db = await createNoydb({\n * store: routeStore({\n * default: dynamo({ table: 'myapp' }),\n * blobs: s3Store({ bucket: 'myapp-blobs' }),\n * }),\n * })\n * ```\n *\n * @module\n */\n\nimport type {\n NoydbStore,\n EncryptedEnvelope,\n VaultSnapshot,\n StoreCapabilities,\n} from '../kernel/types.js'\n\n// ─── Internal collection prefixes (duplicated to avoid circular import) ──\n\nconst BLOB_CHUNKS = '_blob_chunks'\nconst BLOB_INDEX = '_blob_index'\nconst BLOB_SLOTS = '_blob_slots_'\nconst BLOB_VERSIONS = '_blob_versions_'\n\n// ─── Options ─────────────────────────────────────────────────────────────\n\n/**\n * Size-tiered blob routing configuration.\n *\n * Routes blob chunks to different stores based on byte size. Small blobs\n * (under `threshold`) stay in the primary or `small` store; large blobs\n * go to `large`. This lets you keep DynamoDB as the default while sending\n * large binary objects to S3.\n */\nexport interface BlobStoreRoute {\n /** Store for small blobs (under threshold). Falls back to `default`. */\n readonly small?: NoydbStore\n /** Store for large blobs (over threshold). */\n readonly large: NoydbStore\n /** Size threshold in bytes. Default: `400 * 1024` (DynamoDB item limit). */\n readonly threshold?: number\n}\n\n/**\n * Blob lifecycle management policies evaluated during `compact()`.\n *\n * Controls orphan cleanup, cold-tier archival, and hard deletion of\n * blobs that are no longer referenced by any record.\n */\nexport interface BlobLifecyclePolicy {\n /** Delete orphan blobs (refCount: 0) after this many days. Default: 7. */\n readonly orphanRetentionDays?: number\n /** Move blobs not accessed in this many days to the cold blob store. */\n readonly archiveAfterDays?: number\n /** Store for archived blobs. Required if archiveAfterDays is set. */\n readonly archiveStore?: NoydbStore\n /** Hard-delete archived blobs after this many days. */\n readonly expireAfterDays?: number\n}\n\n/**\n * Age-based hot/cold tiering configuration.\n *\n * Records whose `_ts` timestamp is older than `coldAfterDays` are migrated\n * to the `cold` store during `compact()`. Reads transparently fall through\n * to the cold store when the hot store returns null, so callers don't need\n * to know which tier a record lives in.\n */\nexport interface AgeRoute {\n /** Store for records older than the cutoff. */\n readonly cold: NoydbStore\n /**\n * Days after last modification before a record is cold-eligible for the\n * ROLLING `compact(vault)` migrator. Omit for period-driven archival only\n * (`compact(vault, { before })`), where the cutoff is supplied per call.\n */\n readonly coldAfterDays?: number\n /**\n * Collections that participate in age tiering.\n * Empty array or omitted = all user collections (excluding `_` prefixed).\n */\n readonly collections?: string[]\n}\n\n/**\n * Options for `routeStore()` — the store multiplexer.\n *\n * At minimum, provide a `default` store. All other fields are optional\n * extensions for specific routing scenarios (blobs → S3, geographic sharding,\n * age-based tiering, etc.).\n */\nexport interface RouteStoreOptions {\n /** Default store for all unmatched operations. */\n readonly default: NoydbStore\n\n /**\n * Route blob chunk data to a separate store.\n * - Pass a `NoydbStore` for simple prefix routing (all chunks → that store).\n * - Pass `{ small?, large, threshold? }` for size-tiered routing.\n */\n readonly blobs?: NoydbStore | BlobStoreRoute\n\n /** Route all blob metadata (index, slots, versions) to the blobs store too. Default: false. */\n readonly routeBlobMeta?: boolean\n\n /** Route specific user collections to dedicated stores. */\n readonly routes?: Record<string, NoydbStore>\n\n /** Route by vault name (prefix patterns, e.g. `'EU-'`). */\n readonly vaultRoutes?: Record<string, NoydbStore>\n\n /**\n * Age-based tiering: records older than `coldAfterDays` are read from\n * the cold store. A background `compact()` method migrates them.\n */\n readonly age?: AgeRoute\n\n /**\n * Content-aware blob routing.\n * Route blob chunks by MIME type glob pattern. The MIME type is stored\n * in `BlobObject` and matched at read time via `storeHint`.\n */\n readonly blobRoutes?: Record<string, NoydbStore>\n\n /**\n * Blob lifecycle policies.\n * Evaluated during `compact()`.\n */\n readonly blobLifecycle?: BlobLifecyclePolicy\n\n /**\n * Quota-aware overflow.\n * When the default store's usage exceeds the threshold, new writes\n * overflow to the specified store.\n */\n readonly overflow?: NoydbStore\n\n /**\n * Quota threshold (0-1). Default: 0.8 (overflow at 80% usage).\n * Only effective when `overflow` is set.\n */\n readonly quotaThreshold?: number\n}\n\n// ─── Types ───────────────────────────────────────────────────────────────\n\n/**\n * Named route that can be overridden or suspended at runtime.\n *\n * Built-in names: `'default'`, `'blobs'`, `'cold'`.\n * Custom names: any collection name from `routes`, any vault prefix from\n * `vaultRoutes`, or any sync target label.\n */\nexport type OverrideTarget =\n | 'default'\n | 'blobs'\n | 'cold'\n | (string & {}) // named collection route, vault route, or sync target label\n\n/**\n * Options for `RoutedNoydbStore.override()`.\n *\n * Controls whether the new store is pre-populated with data from the\n * original store before the switch takes effect.\n */\nexport interface OverrideOptions {\n /**\n * Hydrate the override store from the original before activating.\n * - `true` — copy all data for all vaults.\n * - `string[]` — copy only named collections.\n * Makes `override()` async — returns a Promise.\n */\n hydrate?: boolean | string[]\n}\n\n/**\n * Options for `RoutedNoydbStore.suspend()`.\n *\n * A suspended route becomes a null store: reads return null/[], writes\n * are dropped (or buffered if `queue: true`). Useful for maintenance\n * windows or restricted-network scenarios.\n */\nexport interface SuspendOptions {\n /**\n * Buffer write operations during suspension. On `resume()`, queued\n * writes are replayed against the restored store.\n */\n queue?: boolean\n /**\n * Maximum queued operations. When exceeded, oldest entries are dropped.\n * Default: 10_000.\n */\n maxQueueSize?: number\n}\n\n/** Queued write operation recorded during suspension. */\ninterface QueuedWrite {\n method: 'put' | 'delete'\n vault: string\n collection: string\n id: string\n envelope?: EncryptedEnvelope\n expectedVersion?: number\n}\n\n/**\n * Snapshot of the current override and suspend state of a `RoutedNoydbStore`.\n * Returned by `routeStatus()` for diagnostics and health dashboards.\n */\nexport interface RouteStatus {\n /** Active overrides: route name → override store name. */\n readonly overrides: Record<string, string>\n /** Currently suspended routes. */\n readonly suspended: string[]\n /** Queued writes per suspended route (only for routes suspended with `queue: true`). */\n readonly queued: Record<string, number>\n}\n\n/**\n * Extended `NoydbStore` returned by `routeStore()`.\n *\n * Satisfies the full `NoydbStore` contract plus adds runtime control\n * methods for overriding, suspending, and inspecting routes.\n */\nexport interface RoutedNoydbStore extends NoydbStore {\n /**\n * Migrate records to the cold store. Only applies when `age.cold` is\n * configured. With `{ before }`, migrates records whose `_ts < before`\n * (period-driven archival); without, uses the rolling `coldAfterDays`.\n * Returns the number of records migrated.\n */\n compact(vault: string, opts?: { before?: string }): Promise<number>\n\n /**\n * Override a named route at runtime.\n *\n * The override persists until `clearOverride()` is called or the\n * instance is closed. In-flight operations complete on the original\n * store; new operations use the override.\n *\n * Options:\n * - `hydrate: true` — async: copies all data from the original store\n * into the override before activating the switch.\n * - `hydrate: ['invoices', 'clients']` — copies only named collections.\n *\n * Use cases:\n * - Shared device: `await store.override('default', toMemory(), { hydrate: true })`\n * - Restricted network: `store.override('blobs', localFile(...))`\n */\n override(route: OverrideTarget, store: NoydbStore, opts?: OverrideOptions): void | Promise<void>\n\n /** Clear a runtime override, reverting to the original store. */\n clearOverride(route: OverrideTarget): void\n\n /**\n * Suspend a route entirely. Operations to suspended stores become\n * no-ops (puts silently dropped, gets return null, lists return []).\n *\n * Options:\n * - `queue: true` — buffer write operations (put/delete) during\n * suspension. When `resume()` is called, queued writes are replayed\n * against the restored store.\n *\n * Returns a `SuspendHandle` when `queue: true`, for inspecting queue state.\n */\n suspend(route: OverrideTarget, opts?: SuspendOptions): void\n\n /**\n * Resume a previously suspended route.\n * If the route was suspended with `queue: true`, replays queued writes.\n * Returns the number of replayed operations.\n */\n resume(route: OverrideTarget): Promise<number>\n\n /** Snapshot the current override/suspend state for diagnostics. */\n routeStatus(): RouteStatus\n\n /**\n * Resolve the physical backend a vault id maps to via the geographic\n * `vaultRoutes` prefix routing (collection-independent), falling back to\n * the `default` store. Used by the federation data-residency guard\n * to read the placement backend's `capabilities.region`.\n */\n resolveBackend(vaultId: string): NoydbStore\n}\n\n// ─── Implementation ──────────────────────────────────────────────────────\n\n/**\n * Create a store multiplexer that dispatches operations to different backends\n * based on collection type, record size, record age, vault prefix, or\n * runtime overrides.\n *\n * ```ts\n * const store = routeStore({\n * default: dynamo({ table: 'myapp' }),\n * blobs: s3({ bucket: 'myapp-blobs' }),\n * routes: { auditLog: s3({ bucket: 'myapp-audit' }) },\n * })\n * ```\n *\n * The returned store satisfies `NoydbStore` and can be passed directly to\n * `createNoydb({ store })`. It also exposes additional methods\n * (`override`, `suspend`, `resume`, `routeStatus`, `compact`) for runtime\n * control and maintenance.\n */\nexport function routeStore(opts: RouteStoreOptions): RoutedNoydbStore {\n const primary = opts.default\n\n // Resolve blob store config\n const blobsIsSimple = opts.blobs && 'get' in opts.blobs\n const simpleBlobStore = blobsIsSimple ? opts.blobs : undefined\n const tieredBlobs = !blobsIsSimple ? opts.blobs : undefined\n const blobThreshold = tieredBlobs?.threshold ?? 400 * 1024\n\n // Collect all stores for loadAll/saveAll/listVaults composition\n const allStores = new Set<NoydbStore>([primary])\n if (simpleBlobStore) allStores.add(simpleBlobStore)\n if (tieredBlobs?.large) allStores.add(tieredBlobs.large)\n if (tieredBlobs?.small) allStores.add(tieredBlobs.small)\n if (opts.age?.cold) allStores.add(opts.age.cold)\n if (opts.routes) for (const s of Object.values(opts.routes)) allStores.add(s)\n if (opts.vaultRoutes) for (const s of Object.values(opts.vaultRoutes)) allStores.add(s)\n if (opts.blobRoutes) for (const s of Object.values(opts.blobRoutes)) allStores.add(s)\n if (opts.overflow) allStores.add(opts.overflow)\n if (opts.blobLifecycle?.archiveStore) allStores.add(opts.blobLifecycle.archiveStore)\n\n // ── Runtime override / suspend state ──────────────────\n\n const overrides = new Map<string, NoydbStore>()\n const suspended = new Set<string>()\n const writeQueues = new Map<string, { writes: QueuedWrite[]; maxSize: number }>()\n\n /** Null store: silently absorbs all operations when a route is suspended. */\n const NULL_STORE: NoydbStore = {\n name: 'suspended',\n async get() { return null },\n async put() {},\n async delete() {},\n async list() { return [] },\n async loadAll() { return {} },\n async saveAll() {},\n }\n\n /**\n * Map a resolved route to its canonical name for override/suspend lookup.\n * Vault routes use the prefix, collection routes use the collection name,\n * blob route is 'blobs', cold route is 'cold', everything else is 'default'.\n */\n function routeNameFor(vault: string, collection: string): string {\n if (opts.vaultRoutes) {\n for (const prefix of Object.keys(opts.vaultRoutes)) {\n if (vault.startsWith(prefix)) return prefix\n }\n }\n if (opts.routes && !collection.startsWith('_') && opts.routes[collection]) {\n return collection\n }\n if (isBlobChunks(collection) && (simpleBlobStore || tieredBlobs)) return 'blobs'\n if (opts.routeBlobMeta && isBlobMeta(collection) && (simpleBlobStore || tieredBlobs)) return 'blobs'\n if (opts.age && !collection.startsWith('_')) {\n // We don't name age 'cold' here — cold is a fallback, not a primary route\n }\n return 'default'\n }\n\n // ── Quota-aware overflow (E8) ───────────────────────────────────────\n\n const quotaExceeded = false\n\n /** Resolve the static (non-overridden) store for a given route name. */\n function resolveOriginalStore(route: string): NoydbStore {\n if (route === 'blobs') return simpleBlobStore ?? tieredBlobs?.large ?? primary\n if (route === 'cold') return opts.age?.cold ?? primary\n if (opts.routes?.[route]) return opts.routes[route]\n if (opts.vaultRoutes?.[route]) return opts.vaultRoutes[route]\n return primary\n }\n\n /**\n * Queue a write operation if the route is suspended with queue: true.\n * Returns true if queued (caller should skip the actual write).\n */\n function maybeQueueWrite(\n routeName: string,\n method: 'put' | 'delete',\n vault: string,\n collection: string,\n id: string,\n envelope?: EncryptedEnvelope,\n expectedVersion?: number,\n ): boolean {\n if (!suspended.has(routeName)) return false\n const queue = writeQueues.get(routeName)\n if (!queue) return false // suspended but no queue — NullStore behavior\n\n // Evict oldest if at capacity\n if (queue.writes.length >= queue.maxSize) {\n queue.writes.shift()\n }\n queue.writes.push({\n method, vault, collection, id,\n ...(envelope !== undefined ? { envelope } : {}),\n ...(expectedVersion !== undefined ? { expectedVersion } : {}),\n })\n return true\n }\n\n // ── Routing logic ──────────────────────────────────────────────────\n\n function isBlobChunks(collection: string): boolean {\n return collection === BLOB_CHUNKS\n }\n\n function isBlobMeta(collection: string): boolean {\n return collection === BLOB_INDEX\n || collection.startsWith(BLOB_SLOTS)\n || collection.startsWith(BLOB_VERSIONS)\n }\n\n function isInternal(collection: string): boolean {\n return collection.startsWith('_')\n }\n\n /**\n * Resolve the store for a given vault + collection.\n * Resolution order: overrides/suspend → vaultRoutes → routes → blobs → default\n */\n function storeFor(vault: string, collection: string): NoydbStore {\n const rName = routeNameFor(vault, collection)\n\n // 0. Runtime override / suspend check\n if (suspended.has(rName)) return NULL_STORE\n if (overrides.has(rName)) return overrides.get(rName)!\n\n // 1. Vault-based geographic routing\n if (opts.vaultRoutes) {\n for (const [prefix, store] of Object.entries(opts.vaultRoutes)) {\n if (vault.startsWith(prefix)) return store\n }\n }\n\n // 2. Per-collection routing (user collections only)\n if (opts.routes && !isInternal(collection) && opts.routes[collection]) {\n return opts.routes[collection]\n }\n\n // 3. Blob chunk routing (simple — no size tiering at the store level)\n if (isBlobChunks(collection)) {\n if (simpleBlobStore) return simpleBlobStore\n // Size-tiered: can't determine here without the envelope.\n // Default to large store — BlobSet will use storeHint for reads.\n if (tieredBlobs) return tieredBlobs.large\n }\n\n // 4. Blob metadata routing\n if (opts.routeBlobMeta && isBlobMeta(collection)) {\n if (simpleBlobStore) return simpleBlobStore\n if (tieredBlobs) return tieredBlobs.large\n }\n\n // 5. Quota-aware overflow (E8)\n if (quotaExceeded && opts.overflow) return opts.overflow\n\n // 6. Default\n return primary\n }\n\n /**\n * For size-tiered blob routing: pick store based on envelope data size.\n */\n function blobStoreForSize(dataSize: number): NoydbStore {\n if (!tieredBlobs) return simpleBlobStore ?? primary\n if (dataSize <= blobThreshold) {\n return tieredBlobs.small ?? primary\n }\n return tieredBlobs.large\n }\n\n /**\n * Age routing: check if a record is cold based on `_ts`.\n */\n function isCold(collection: string, envelope: EncryptedEnvelope, before?: string): boolean {\n if (!opts.age) return false\n if (isInternal(collection)) return false\n if (opts.age.collections && opts.age.collections.length > 0) {\n if (!opts.age.collections.includes(collection)) return false\n }\n // explicit period cutoff wins; else the rolling age cutoff; else nothing is cold\n const cutoffIso =\n before ??\n (opts.age.coldAfterDays != null\n ? new Date(Date.now() - opts.age.coldAfterDays * 24 * 60 * 60 * 1000).toISOString()\n : undefined)\n if (cutoffIso === undefined) return false\n return envelope._ts < cutoffIso\n }\n\n // ── Store methods ──────────────────────────────────────────────────\n\n // #613: advertise cold-archival when a cold route exists. Spread the\n // primary's capabilities so CAS/auth/etc. still surface; layer the flag.\n // A router with no cold route of its own must NOT inherit `coldArchival:\n // true` from a nested cold-capable primary (whole-branch review I1) — force\n // it off explicitly so the consumer's `!== true` gate throws.\n const store: RoutedNoydbStore = {\n name: buildName(),\n ...(opts.age?.cold\n ? { capabilities: { ...primary.capabilities, coldArchival: true } as StoreCapabilities }\n : primary.capabilities\n ? { capabilities: { ...primary.capabilities, coldArchival: false } as StoreCapabilities }\n : {}),\n\n async get(vault, collection, id) {\n const s = storeFor(vault, collection)\n const result = await s.get(vault, collection, id)\n\n // Age tiering: if hot store returned null, try cold\n if (result === null && opts.age && !isInternal(collection)) {\n if (!opts.age.collections?.length || opts.age.collections.includes(collection)) {\n return opts.age.cold.get(vault, collection, id)\n }\n }\n\n return result\n },\n\n async put(vault, collection, id, envelope, expectedVersion) {\n // Write-behind queue: buffer if suspended with queue option\n const rn = routeNameFor(vault, collection)\n if (maybeQueueWrite(rn, 'put', vault, collection, id, envelope, expectedVersion)) return\n\n // Size-tiered blob routing\n if (isBlobChunks(collection) && tieredBlobs) {\n const dataSize = (envelope._data ?? '').length\n const s = blobStoreForSize(dataSize)\n return s.put(vault, collection, id, envelope, expectedVersion)\n }\n\n const s = storeFor(vault, collection)\n\n // Age tiering: if a cold record is being updated, it goes to hot.\n if (opts.age && !isInternal(collection)) {\n opts.age.cold.delete(vault, collection, id).catch(() => {})\n }\n\n return s.put(vault, collection, id, envelope, expectedVersion)\n },\n\n async delete(vault, collection, id) {\n // Write-behind queue: buffer if suspended with queue option\n const rn = routeNameFor(vault, collection)\n if (maybeQueueWrite(rn, 'delete', vault, collection, id)) return\n\n const s = storeFor(vault, collection)\n await s.delete(vault, collection, id)\n\n // Also delete from cold store if age-tiered\n if (opts.age && !isInternal(collection)) {\n await opts.age.cold.delete(vault, collection, id).catch(() => {})\n }\n },\n\n async list(vault, collection) {\n const s = storeFor(vault, collection)\n const ids = await s.list(vault, collection)\n\n // Age tiering: merge IDs from cold store, deduplicate\n if (opts.age && !isInternal(collection)) {\n if (!opts.age.collections?.length || opts.age.collections.includes(collection)) {\n const coldIds = await opts.age.cold.list(vault, collection).catch(() => [] as string[])\n if (coldIds.length > 0) {\n const merged = new Set(ids)\n for (const id of coldIds) merged.add(id)\n return [...merged]\n }\n }\n }\n\n return ids\n },\n\n async loadAll(vault) {\n // Query all distinct stores in parallel, merge snapshots\n const stores = getStoresForVault(vault)\n const snapshots = await Promise.all(\n stores.map(s => s.loadAll(vault).catch(() => ({}) as VaultSnapshot)),\n )\n return mergeSnapshots(snapshots)\n },\n\n async saveAll(vault, data) {\n // Partition snapshot by routing rules\n const partitioned = new Map<NoydbStore, VaultSnapshot>()\n\n for (const [collection, records] of Object.entries(data)) {\n const s = storeFor(vault, collection)\n if (!partitioned.has(s)) partitioned.set(s, {})\n partitioned.get(s)![collection] = records\n }\n\n await Promise.all(\n [...partitioned.entries()].map(([s, snap]) => s.saveAll(vault, snap)),\n )\n },\n\n async compact(vault, compactOpts) {\n if (!opts.age) return 0\n let migrated = 0\n const collections = opts.age.collections?.length\n ? opts.age.collections\n : Object.keys(await primary.loadAll(vault).catch(() => ({}) as VaultSnapshot))\n\n for (const collection of collections) {\n const ids = await primary.list(vault, collection).catch(() => [] as string[])\n for (const id of ids) {\n const envelope = await primary.get(vault, collection, id)\n if (!envelope) continue\n if (isCold(collection, envelope, compactOpts?.before)) {\n await opts.age.cold.put(vault, collection, id, envelope)\n await primary.delete(vault, collection, id)\n migrated++\n }\n }\n }\n return migrated\n },\n\n // ── Runtime override / suspend ──────────────────────\n\n override(route: OverrideTarget, overrideStore: NoydbStore, overrideOpts?: OverrideOptions): void | Promise<void> {\n if (overrideOpts?.hydrate) {\n // Async hydration: copy data from current store, then activate override\n return (async () => {\n // Hydration: caller should copy data from the original store to\n // overrideStore before calling override() with { hydrate: true }.\n // The route is activated immediately after.\n overrides.set(route, overrideStore)\n })()\n }\n overrides.set(route, overrideStore)\n },\n\n clearOverride(route: OverrideTarget): void {\n overrides.delete(route)\n },\n\n suspend(route: OverrideTarget, suspendOpts?: SuspendOptions): void {\n suspended.add(route)\n if (suspendOpts?.queue) {\n writeQueues.set(route, {\n writes: [],\n maxSize: suspendOpts.maxQueueSize ?? 10_000,\n })\n }\n },\n\n async resume(route: OverrideTarget): Promise<number> {\n suspended.delete(route)\n const queue = writeQueues.get(route)\n if (!queue || queue.writes.length === 0) {\n writeQueues.delete(route)\n return 0\n }\n\n // Replay queued writes against the now-active store\n let replayed = 0\n const target = overrides.get(route) ?? resolveOriginalStore(route)\n for (const write of queue.writes) {\n try {\n if (write.method === 'put' && write.envelope) {\n await target.put(write.vault, write.collection, write.id, write.envelope, write.expectedVersion)\n } else if (write.method === 'delete') {\n await target.delete(write.vault, write.collection, write.id)\n }\n replayed++\n } catch {\n // Best-effort replay — conflicts are expected after suspension\n }\n }\n\n writeQueues.delete(route)\n return replayed\n },\n\n routeStatus(): RouteStatus {\n const ov: Record<string, string> = {}\n for (const [k, v] of overrides) ov[k] = v.name ?? 'unnamed'\n const q: Record<string, number> = {}\n for (const [k, v] of writeQueues) q[k] = v.writes.length\n return { overrides: ov, suspended: [...suspended], queued: q }\n },\n\n resolveBackend(vaultId: string): NoydbStore {\n // Geographic routing is vault-prefix based + collection-independent;\n // the region-relevant backend is the vaultRoutes match, else default.\n if (opts.vaultRoutes) {\n for (const [prefix, s] of Object.entries(opts.vaultRoutes)) {\n if (vaultId.startsWith(prefix)) return s\n }\n }\n return primary\n },\n }\n\n // ── Optional method forwarding ─────────────────────────────────────\n\n // Forward listVaults from all stores, deduplicated\n if (anyHas('listVaults')) {\n store.listVaults = async () => {\n const results = await Promise.all(\n [...allStores]\n .filter(s => s.listVaults !== undefined)\n .map(s => s.listVaults!().catch(() => [] as string[])),\n )\n return [...new Set(results.flat())]\n }\n }\n\n // Forward ping — succeed if any store responds\n if (anyHas('ping')) {\n store.ping = async () => {\n const results = await Promise.all(\n [...allStores]\n .filter(s => s.ping !== undefined)\n .map(s => s.ping!().catch(() => false)),\n )\n return results.some(Boolean)\n }\n }\n\n return store\n\n // ── Helpers ────────────────────────────────────────────────────────\n\n function buildName(): string {\n const names = [...allStores].map(s => s.name ?? '?').join('+')\n return `route(${names})`\n }\n\n function anyHas(method: string): boolean {\n return [...allStores].some(s => (s as unknown as Record<string, unknown>)[method])\n }\n\n function getStoresForVault(vault: string): NoydbStore[] {\n const stores = new Set<NoydbStore>()\n\n // Check vault routes first\n if (opts.vaultRoutes) {\n for (const [prefix, s] of Object.entries(opts.vaultRoutes)) {\n if (vault.startsWith(prefix)) {\n stores.add(s)\n return [...stores] // vault-routed: only use that store\n }\n }\n }\n\n // Default topology: primary + blob store + cold store\n stores.add(primary)\n if (simpleBlobStore) stores.add(simpleBlobStore)\n if (tieredBlobs?.large) stores.add(tieredBlobs.large)\n if (tieredBlobs?.small && tieredBlobs.small !== primary) stores.add(tieredBlobs.small)\n if (opts.age?.cold) stores.add(opts.age.cold)\n if (opts.routes) {\n for (const s of Object.values(opts.routes)) stores.add(s)\n }\n\n return [...stores]\n }\n}\n\n// ─── Snapshot merge ──────────────────────────────────────────────────────\n\nfunction mergeSnapshots(snapshots: VaultSnapshot[]): VaultSnapshot {\n const merged: VaultSnapshot = {}\n\n for (const snap of snapshots) {\n for (const [collection, records] of Object.entries(snap)) {\n if (!merged[collection]) {\n merged[collection] = { ...records }\n continue\n }\n for (const [id, envelope] of Object.entries(records)) {\n const existing = merged[collection][id]\n // Last-write-wins by _ts\n if (!existing || envelope._ts >= existing._ts) {\n merged[collection][id] = envelope\n }\n }\n }\n }\n\n return merged\n}\n","/**\n * Store middleware — composable interceptors for NoydbStore.\n *\n * ```ts\n * const resilient = wrapStore(\n * dynamo({ table: 'myapp' }),\n * withRetry({ maxRetries: 3 }),\n * withLogging({ level: 'debug' }),\n * withCache({ ttlMs: 60_000 }),\n * )\n * ```\n *\n * Each middleware is `(next: NoydbStore) => NoydbStore`. They compose\n * left-to-right: first middleware is outermost (processes requests first,\n * responses last).\n *\n * @module\n */\n\nimport type { NoydbStore, EncryptedEnvelope } from '../kernel/types.js'\n\n// ─── Core composition ───────────────────────────────────────────────────\n\n/**\n * A store middleware function.\n *\n * Takes the next store in the chain and returns a wrapped store. Middlewares\n * compose left-to-right via `wrapStore()`: the first argument is outermost\n * (first to intercept requests, last to process responses).\n *\n * ⛔ **Do not write `{ ...next, get() {…} }`** — this example used to, and it\n * taught the defect family#173 fixed. A spread copies own enumerable properties\n * only, so a store implemented as a class loses every prototype method the\n * middleware does not redeclare (`listPage`, `tx`, `getStoreTime`, …) and hub\n * silently takes its fallback paths. Build the wrapper over `next` instead:\n *\n * ```ts\n * const mw: StoreMiddleware = (next) => {\n * const log = async (vault: string, collection: string, id: string) => {\n * console.log('get', id)\n * return next.get(vault, collection, id)\n * }\n * return new Proxy(next, {\n * get: (t, p) => (p === 'get' ? log : Reflect.get(t, p, t)),\n * })\n * }\n * ```\n *\n * ⚠️ The snippet above is the shape, simplified: the real `overlay()` in this\n * module also binds forwarded methods to the wrapped store (so a class store's\n * `#private` fields keep working) and caches them (so a method reference is\n * stable). A middleware doing this by hand should do both.\n */\nexport type StoreMiddleware = (next: NoydbStore) => NoydbStore\n\n/**\n * Compose `overrides` over `next` without a spread (family#173).\n *\n * ⛔ `{ ...next, get() {…} }` WAS THE SHAPE OF ALL SIX MIDDLEWARES AND IT IS A\n * DEFECT, not a style choice. A spread copies OWN ENUMERABLE properties only,\n * so wrapping a store implemented as a CLASS dropped every prototype method the\n * middleware did not itself redeclare — `listPage`, `tx`, `getStoreTime`,\n * `listSince`, `ping`, `presignUrl`, `estimateUsage`. Hub reads those by\n * `typeof store.x === 'function'` to decide whether to delegate, so the\n * capability silently became absent and hub took its fallback path. Nothing\n * failed; a paging store simply stopped paging.\n *\n * ⚠️ NO STORE IN core, to OR in IS CLASS-BASED TODAY, so the exposure is\n * third-party only — which is precisely why it survived: every suite here\n * passes either way, and the bug lives in the one consumer no test in this repo\n * can have.\n *\n * ⚠️ `Reflect.apply(fn, target, args)` binds `this` to the WRAPPED STORE, not\n * the proxy. Load-bearing for a class store with `#private` fields: called with\n * the proxy as receiver, a method touching `#field` throws \"Cannot read private\n * member\" — a failure that looks nothing like a middleware bug.\n *\n * ⚠️ Same shape as `kernel/store-segment-guard.ts`'s guard, kept separate on\n * purpose: that one VALIDATES before forwarding and this one SUBSTITUTES. If a\n * third appears, extract one helper then — two uses is not yet a pattern, and a\n * premature shared abstraction would have to carry both behaviours.\n */\nfunction overlay(next: NoydbStore, overrides: Partial<NoydbStore>): NoydbStore {\n const bound = new WeakMap<object, unknown>()\n return new Proxy(next, {\n get(target, prop) {\n // An override wins, including a deliberately `undefined` one — that is\n // how `{ ...next, listPage: undefined }` used to read, and hub's\n // `typeof === 'function'` check treats it as absent either way.\n if (Object.prototype.hasOwnProperty.call(overrides, prop)) {\n return (overrides as Record<string | symbol, unknown>)[prop]\n }\n const value = Reflect.get(target, prop, target)\n if (typeof value !== 'function') return value\n const cached = bound.get(value as object)\n if (cached !== undefined) return cached\n // Cached so `store.listPage === store.listPage`. A fresh closure per\n // access is observable, and a consumer caching a method reference would\n // get a different function every time.\n const forward = (...args: unknown[]): unknown =>\n Reflect.apply(value as (...a: unknown[]) => unknown, target, args)\n bound.set(value as object, forward)\n return forward\n },\n has(target, prop) {\n return Object.prototype.hasOwnProperty.call(overrides, prop) || Reflect.has(target, prop)\n },\n })\n}\n\n/**\n * Wrap a store with one or more middlewares. Middlewares compose left-to-right.\n */\nexport function wrapStore(store: NoydbStore, ...middlewares: StoreMiddleware[]): NoydbStore {\n let result = store\n // Apply right-to-left so the first middleware is the outermost wrapper\n for (let i = middlewares.length - 1; i >= 0; i--) {\n result = middlewares[i]!(result)\n }\n return result\n}\n\n// ─── withRetry ──────────────────────────────────────────────────────────\n\n/** Options for `withRetry()`. */\nexport interface RetryOptions {\n /** Maximum retry attempts. Default: 3. */\n maxRetries?: number\n /** Base backoff delay in ms. Default: 500. */\n backoffMs?: number\n /** Jitter factor (0-1). Adds random delay up to `backoffMs * jitter`. Default: 0.3. */\n jitter?: number\n /** Only retry on these error codes. Default: retry all errors. */\n retryOn?: string[]\n}\n\n/**\n * Middleware that retries failed store operations with exponential backoff\n * and optional jitter. Useful for transient network errors on DynamoDB/S3.\n *\n * ```ts\n * wrapStore(dynamo({ table: 'myapp' }), withRetry({ maxRetries: 5, retryOn: ['NETWORK_ERROR'] }))\n * ```\n */\nexport function withRetry(opts: RetryOptions = {}): StoreMiddleware {\n const maxRetries = opts.maxRetries ?? 3\n const backoffMs = opts.backoffMs ?? 500\n const jitter = opts.jitter ?? 0.3\n const retryOn = opts.retryOn ? new Set(opts.retryOn) : null\n\n function shouldRetry(err: unknown): boolean {\n if (!retryOn) return true\n if (err && typeof err === 'object' && 'code' in err) {\n return retryOn.has((err as { code: string }).code)\n }\n return true\n }\n\n async function retryable<T>(fn: () => Promise<T>): Promise<T> {\n let lastError: unknown\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n return await fn()\n } catch (err) {\n lastError = err\n if (attempt >= maxRetries || !shouldRetry(err)) throw err\n const delay = backoffMs * Math.pow(2, attempt) * (1 + Math.random() * jitter)\n await new Promise(r => setTimeout(r, delay))\n }\n }\n throw lastError\n }\n\n return (next) => overlay(next, {\n name: next.name ? `retry(${next.name})` : 'retry',\n get: (v, c, id) => retryable(() => next.get(v, c, id)),\n put: (v, c, id, env, ev) => retryable(() => next.put(v, c, id, env, ev)),\n delete: (v, c, id) => retryable(() => next.delete(v, c, id)),\n list: (v, c) => retryable(() => next.list(v, c)),\n loadAll: (v) => retryable(() => next.loadAll(v)),\n saveAll: (v, d) => retryable(() => next.saveAll(v, d)),\n })\n}\n\n// ─── withLogging ────────────────────────────────────────────────────────\n\n/** Log level for `withLogging()`. Maps to standard console method names. */\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error'\n\n/** Options for `withLogging()`. */\nexport interface LoggingOptions {\n /** Minimum log level. Default: 'info'. */\n level?: LogLevel\n /** Custom logger. Default: console. */\n logger?: {\n debug(msg: string, ...args: unknown[]): void\n info(msg: string, ...args: unknown[]): void\n warn(msg: string, ...args: unknown[]): void\n error(msg: string, ...args: unknown[]): void\n }\n /** Log the data payload (envelope contents). Default: false (privacy). */\n logData?: boolean\n}\n\nconst LOG_LEVELS: Record<LogLevel, number> = { debug: 0, info: 1, warn: 2, error: 3 }\n\n/**\n * Middleware that logs every store operation with its method name, arguments,\n * and elapsed duration. Privacy-safe by default: envelope payloads are not\n * logged unless `logData: true` is set.\n */\nexport function withLogging(opts: LoggingOptions = {}): StoreMiddleware {\n const minLevel = LOG_LEVELS[opts.level ?? 'info']\n const logger = opts.logger ?? console\n const logData = opts.logData ?? false\n\n function log(level: LogLevel, method: string, args: Record<string, unknown>, durationMs?: number) {\n if (LOG_LEVELS[level] < minLevel) return\n const parts = [`[noydb:${method}]`, ...Object.entries(args).map(([k, v]) => `${k}=${String(v)}`)]\n if (durationMs !== undefined) parts.push(`${durationMs}ms`)\n logger[level](parts.join(' '))\n }\n\n function timed<T>(method: string, args: Record<string, unknown>, fn: () => Promise<T>): Promise<T> {\n const start = Date.now()\n return fn().then(\n (result) => {\n log('debug', method, args, Date.now() - start)\n return result\n },\n (err) => {\n log('error', method, { ...args, error: (err as Error).message }, Date.now() - start)\n throw err\n },\n )\n }\n\n return (next) => overlay(next, {\n name: next.name ? `log(${next.name})` : 'log',\n get: (v, c, id) => timed('get', { vault: v, collection: c, id }, () => next.get(v, c, id)),\n put: (v, c, id, env, ev) => timed('put', {\n vault: v, collection: c, id, version: env._v,\n ...(logData ? { data: (env._data ?? '').slice(0, 40) + '...' } : {}),\n }, () => next.put(v, c, id, env, ev)),\n delete: (v, c, id) => timed('delete', { vault: v, collection: c, id }, () => next.delete(v, c, id)),\n list: (v, c) => timed('list', { vault: v, collection: c }, () => next.list(v, c)),\n loadAll: (v) => timed('loadAll', { vault: v }, () => next.loadAll(v)),\n saveAll: (v, d) => timed('saveAll', { vault: v }, () => next.saveAll(v, d)),\n })\n}\n\n// ─── withMetrics ────────────────────────────────────────────────────────\n\n/**\n * Data emitted to `MetricsOptions.onOperation` after every store call.\n *\n * Carries method name, vault/collection/id context, elapsed duration,\n * and success/failure status. Wire this into your metrics pipeline\n * (DataDog, Prometheus, CloudWatch) to get per-operation latency histograms.\n */\nexport interface StoreOperation {\n method: 'get' | 'put' | 'delete' | 'list' | 'loadAll' | 'saveAll'\n vault: string\n collection?: string\n id?: string\n durationMs: number\n success: boolean\n error?: Error\n}\n\n/** Options for `withMetrics()`. */\nexport interface MetricsOptions {\n /** Called after every store operation. */\n onOperation: (op: StoreOperation) => void\n}\n\n/**\n * Middleware that calls `onOperation` after every store method with timing\n * and success/failure data. Designed for low-overhead integration with\n * metrics systems — the callback is synchronous and fire-and-forget.\n */\nexport function withMetrics(opts: MetricsOptions): StoreMiddleware {\n function tracked<T>(\n method: StoreOperation['method'],\n vault: string,\n fn: () => Promise<T>,\n collection?: string,\n id?: string,\n ): Promise<T> {\n const start = Date.now()\n return fn().then(\n (result) => {\n opts.onOperation({\n method, vault,\n ...(collection !== undefined ? { collection } : {}),\n ...(id !== undefined ? { id } : {}),\n durationMs: Date.now() - start, success: true,\n })\n return result\n },\n (err) => {\n opts.onOperation({\n method, vault,\n ...(collection !== undefined ? { collection } : {}),\n ...(id !== undefined ? { id } : {}),\n durationMs: Date.now() - start, success: false, error: err as Error,\n })\n throw err\n },\n )\n }\n\n return (next) => overlay(next, {\n name: next.name ? `metrics(${next.name})` : 'metrics',\n get: (v, c, id) => tracked('get', v, () => next.get(v, c, id), c, id),\n put: (v, c, id, env, ev) => tracked('put', v, () => next.put(v, c, id, env, ev), c, id),\n delete: (v, c, id) => tracked('delete', v, () => next.delete(v, c, id), c, id),\n list: (v, c) => tracked('list', v, () => next.list(v, c), c),\n loadAll: (v) => tracked('loadAll', v, () => next.loadAll(v)),\n saveAll: (v, d) => tracked('saveAll', v, () => next.saveAll(v, d)),\n })\n}\n\n// ─── withCircuitBreaker ─────────────────────────────────────────────────\n\n/**\n * Options for `withCircuitBreaker()`.\n *\n * The circuit breaker moves through three states:\n * - `closed`: normal operation.\n * - `open`: store is failing; all calls return fallback values immediately.\n * - `half-open`: one probe call after `resetTimeoutMs` — success closes, failure re-opens.\n */\nexport interface CircuitBreakerOptions {\n /** Number of consecutive failures before opening the circuit. Default: 5. */\n failureThreshold?: number\n /** Time in ms before attempting to half-open the circuit. Default: 30_000. */\n resetTimeoutMs?: number\n /** Called when the circuit opens (store becomes unavailable). */\n onOpen?: () => void\n /** Called when the circuit closes (store recovers). */\n onClose?: () => void\n}\n\ntype CircuitState = 'closed' | 'open' | 'half-open'\n\n/**\n * Middleware that implements the circuit-breaker pattern.\n *\n * When the wrapped store fails `failureThreshold` consecutive times, the\n * circuit opens: subsequent calls return safe fallback values (`null`, `[]`,\n * `{}`) without hitting the store. After `resetTimeoutMs` the circuit\n * half-opens and allows one probe — success closes the circuit, failure\n * keeps it open. Pair with `withRetry` to handle transient errors before\n * they trip the circuit.\n */\nexport function withCircuitBreaker(opts: CircuitBreakerOptions = {}): StoreMiddleware {\n const threshold = opts.failureThreshold ?? 5\n const resetMs = opts.resetTimeoutMs ?? 30_000\n\n let state: CircuitState = 'closed'\n let failures = 0\n let lastFailureTime = 0\n\n function recordSuccess(): void {\n if (state === 'half-open') {\n state = 'closed'\n failures = 0\n opts.onClose?.()\n }\n failures = 0\n }\n\n function recordFailure(): void {\n failures++\n lastFailureTime = Date.now()\n if (failures >= threshold && state === 'closed') {\n state = 'open'\n opts.onOpen?.()\n }\n }\n\n function canAttempt(): boolean {\n if (state === 'closed') return true\n if (state === 'open') {\n if (Date.now() - lastFailureTime >= resetMs) {\n state = 'half-open'\n return true\n }\n return false\n }\n // half-open: allow one attempt\n return true\n }\n\n async function guarded<T>(fn: () => Promise<T>, fallback: T): Promise<T> {\n if (!canAttempt()) return fallback\n try {\n const result = await fn()\n recordSuccess()\n return result\n } catch (err) {\n recordFailure()\n throw err\n }\n }\n\n return (next) => overlay(next, {\n name: next.name ? `cb(${next.name})` : 'cb',\n get: (v, c, id) => guarded(() => next.get(v, c, id), null),\n put: (v, c, id, env, ev) => guarded(() => next.put(v, c, id, env, ev), undefined),\n delete: (v, c, id) => guarded(() => next.delete(v, c, id), undefined),\n list: (v, c) => guarded(() => next.list(v, c), []),\n loadAll: (v) => guarded(() => next.loadAll(v), {}),\n saveAll: (v, d) => guarded(() => next.saveAll(v, d), undefined),\n })\n}\n\n// ─── withCache (read-through) ───────────────────────────────────────────\n\n/**\n * Options for `withCache()`.\n *\n * The cache is a read-through LRU that caches individual record fetches\n * (`get`). Writes (`put`, `delete`) invalidate the relevant cache entry\n * immediately. `list`, `loadAll`, and `saveAll` bypass the cache.\n *\n * Named `StoreCacheOptions` to distinguish from `CacheOptions` in\n * `@noy-db/hub/collection`, which controls the in-memory decrypted-record LRU.\n */\nexport interface StoreCacheOptions {\n /** Maximum cached entries. Default: 500. */\n maxEntries?: number\n /** Cache TTL in ms. Default: 60_000 (1 minute). 0 = no expiry. */\n ttlMs?: number\n}\n\ninterface CacheEntry {\n envelope: EncryptedEnvelope | null\n cachedAt: number\n}\n\n/**\n * Middleware that adds a read-through LRU cache for `get()` calls.\n *\n * Reduces latency for frequently-read records (e.g. lookup tables, user\n * profiles) by serving repeat reads from memory. Because NOYDB records are\n * encrypted at rest, caching envelopes is safe — the cache holds ciphertext,\n * not plaintext. For write-heavy workloads, the cache provides little benefit\n * and should be omitted to avoid the invalidation overhead.\n */\nexport function withCache(opts: StoreCacheOptions = {}): StoreMiddleware {\n const maxEntries = opts.maxEntries ?? 500\n const ttlMs = opts.ttlMs ?? 60_000\n\n // LRU cache: Map preserves insertion order, we delete+re-insert on access\n const cache = new Map<string, CacheEntry>()\n\n function cacheKey(vault: string, collection: string, id: string): string {\n return `${vault}\\0${collection}\\0${id}`\n }\n\n function getFromCache(key: string): EncryptedEnvelope | null | undefined {\n const entry = cache.get(key)\n if (!entry) return undefined\n if (ttlMs > 0 && Date.now() - entry.cachedAt > ttlMs) {\n cache.delete(key)\n return undefined\n }\n // LRU: move to end\n cache.delete(key)\n cache.set(key, entry)\n return entry.envelope\n }\n\n function setInCache(key: string, envelope: EncryptedEnvelope | null): void {\n // Evict oldest if at capacity\n if (cache.size >= maxEntries) {\n const oldest = cache.keys().next().value\n if (oldest !== undefined) cache.delete(oldest)\n }\n cache.set(key, { envelope, cachedAt: Date.now() })\n }\n\n function invalidate(key: string): void {\n cache.delete(key)\n }\n\n return (next) => overlay(next, {\n name: next.name ? `cache(${next.name})` : 'cache',\n\n async get(vault, collection, id) {\n const key = cacheKey(vault, collection, id)\n const cached = getFromCache(key)\n if (cached !== undefined) return cached\n const result = await next.get(vault, collection, id)\n setInCache(key, result)\n return result\n },\n\n async put(vault, collection, id, env, ev) {\n invalidate(cacheKey(vault, collection, id))\n await next.put(vault, collection, id, env, ev)\n setInCache(cacheKey(vault, collection, id), env)\n },\n\n async delete(vault, collection, id) {\n invalidate(cacheKey(vault, collection, id))\n await next.delete(vault, collection, id)\n },\n\n list: (v, c) => next.list(v, c),\n loadAll: (v) => next.loadAll(v),\n saveAll: (v, d) => next.saveAll(v, d),\n })\n}\n\n// ─── withHealthCheck ────────────────────────────────────────────────────\n\nexport interface HealthCheckOptions {\n /** Ping interval in ms. Default: 30_000. */\n checkIntervalMs?: number\n /** Suspend after N consecutive ping failures. Default: 3. */\n suspendAfterFailures?: number\n /** Resume after N consecutive ping successes. Default: 1. */\n resumeAfterSuccess?: number\n /** Called when the store is auto-suspended. */\n onSuspend?: () => void\n /** Called when the store is auto-resumed. */\n onResume?: () => void\n /**\n * Custom health check. Default: calls `store.ping()` if available,\n * otherwise attempts a `list()` on a sentinel collection.\n */\n check?: () => Promise<boolean>\n}\n\n/**\n * Auto-suspends a store when health checks fail, auto-resumes when they recover.\n *\n * When suspended, `get` returns null, `put`/`delete` are no-ops, `list` returns [].\n * This is identical to the `NullStore` behavior from `routeStore.suspend()`.\n */\nexport function withHealthCheck(opts: HealthCheckOptions = {}): StoreMiddleware {\n const intervalMs = opts.checkIntervalMs ?? 30_000\n const failThreshold = opts.suspendAfterFailures ?? 3\n const successThreshold = opts.resumeAfterSuccess ?? 1\n\n let isSuspended = false\n let consecutiveFailures = 0\n let consecutiveSuccesses = 0\n\n return (next) => {\n const checkFn = opts.check ?? (\n next.ping\n ? () => next.ping!()\n : async () => { await next.list('__health__', '__ping__'); return true }\n )\n\n async function doCheck(): Promise<void> {\n try {\n const ok = await checkFn()\n if (ok) {\n consecutiveFailures = 0\n consecutiveSuccesses++\n if (isSuspended && consecutiveSuccesses >= successThreshold) {\n isSuspended = false\n consecutiveSuccesses = 0\n opts.onResume?.()\n }\n } else {\n throw new Error('Health check returned false')\n }\n } catch {\n consecutiveSuccesses = 0\n consecutiveFailures++\n if (!isSuspended && consecutiveFailures >= failThreshold) {\n isSuspended = true\n consecutiveFailures = 0\n opts.onSuspend?.()\n }\n }\n }\n\n // Start checking\n setInterval(() => { void doCheck() }, intervalMs)\n\n const wrapped: NoydbStore = overlay(next, {\n name: next.name ? `health(${next.name})` : 'health',\n\n async get(v, c, id) { return isSuspended ? null : next.get(v, c, id) },\n async put(v, c, id, env, ev) { if (!isSuspended) await next.put(v, c, id, env, ev) },\n async delete(v, c, id) { if (!isSuspended) await next.delete(v, c, id) },\n async list(v, c) { return isSuspended ? [] : next.list(v, c) },\n async loadAll(v) { return isSuspended ? {} : next.loadAll(v) },\n async saveAll(v, d) { if (!isSuspended) await next.saveAll(v, d) },\n })\n\n return wrapped\n }\n}\n"],"mappings":"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","names":["store","s"]}
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  buildAccessibleBundle,
3
3
  resolveAccessibleCollections
4
- } from "./chunk-U43RSPPX.js";
4
+ } from "./chunk-23A4SBRR.js";
5
5
  import {
6
6
  buildRecordEnvelope,
7
7
  sha256Hex
8
- } from "./chunk-WRLWEYHY.js";
8
+ } from "./chunk-EFINFZIF.js";
9
9
  import {
10
10
  ReadOnlyError
11
- } from "./chunk-2RH5SEY7.js";
11
+ } from "./chunk-ISIXU45J.js";
12
12
 
13
13
  // src/with-audit/portability/withdraw-accessible.ts
14
14
  var FROZEN_SNAPSHOTS_COLLECTION = "_frozen_snapshots";
@@ -114,4 +114,4 @@ export {
114
114
  freezeAndDeleteClosure,
115
115
  withdrawAccessibleData
116
116
  };
117
- //# sourceMappingURL=chunk-FUHUGKDN.js.map
117
+ //# sourceMappingURL=chunk-XROQP6IQ.js.map
@@ -0,0 +1,196 @@
1
+ import {
2
+ NOYDB_FORMAT_VERSION
3
+ } from "./chunk-CR5UPYIJ.js";
4
+ import {
5
+ MissingEnvelopeBodyError
6
+ } from "./chunk-ISIXU45J.js";
7
+
8
+ // src/capsule/plumbing/record-aad.ts
9
+ var SCHEME = "noydb-aad/2";
10
+ var encoder = new TextEncoder();
11
+ function buildRecordAad(identity) {
12
+ if (!Number.isFinite(identity.version)) {
13
+ throw new TypeError(
14
+ `record AAD: version must be a finite number for "${identity.collection}/${identity.id}", received ${String(identity.version)}. Sealing without one produces a record no reader can open.`
15
+ );
16
+ }
17
+ for (const [field, value] of [["collection", identity.collection], ["id", identity.id]]) {
18
+ if (typeof value !== "string") {
19
+ throw new TypeError(
20
+ `record AAD: ${field} must be a string, received ${String(value)} (${typeof value}). Sealing against a coerced address produces a record no reader can open, and the failure surfaces on the READ path.`
21
+ );
22
+ }
23
+ }
24
+ const parts = [encoder.encode(SCHEME)];
25
+ const pushField = (value) => {
26
+ const bytes = encoder.encode(value);
27
+ const len = new Uint8Array(4);
28
+ new DataView(len.buffer).setUint32(0, bytes.length, false);
29
+ parts.push(len, bytes);
30
+ };
31
+ pushField(identity.collection);
32
+ pushField(identity.id);
33
+ pushField(String(identity.tier ?? 0));
34
+ parts.push(new Uint8Array([identity.by === void 0 ? 0 : 1]));
35
+ if (identity.by !== void 0) pushField(identity.by);
36
+ pushField(String(identity.version));
37
+ const total = parts.reduce((n, p) => n + p.length, 0);
38
+ const out = new Uint8Array(total);
39
+ let offset = 0;
40
+ for (const p of parts) {
41
+ out.set(p, offset);
42
+ offset += p.length;
43
+ }
44
+ return out;
45
+ }
46
+ function recordAadFor(ref, envelope) {
47
+ return buildRecordAad({
48
+ collection: ref.collection,
49
+ id: ref.id,
50
+ version: envelope._v,
51
+ tier: envelope._tier,
52
+ by: envelope._by
53
+ });
54
+ }
55
+
56
+ // src/capsule/plumbing/envelope-body.ts
57
+ function requireSealedBody(env, where) {
58
+ if (env._iv === void 0 || env._data === void 0) throw new MissingEnvelopeBodyError(where);
59
+ return { iv: env._iv, data: env._data };
60
+ }
61
+ function sealedBodyArgs(env, where) {
62
+ const { iv, data } = requireSealedBody(env, where);
63
+ return [iv, data];
64
+ }
65
+ function envelopeBodySize(env) {
66
+ return (env._data?.length ?? 0) + (env._iv?.length ?? 0);
67
+ }
68
+ function hasPerRecordKey(env) {
69
+ return env._cek !== void 0;
70
+ }
71
+ function envelopeBodyForHash(env) {
72
+ const data = env._data ?? "";
73
+ if (env._sealed === void 0 && env._vdig === void 0 && env._bidx === void 0) return data;
74
+ const mapPart = (key, map) => {
75
+ const parts = Object.keys(map).sort().map(
76
+ (k) => `${JSON.stringify(k)}:${JSON.stringify(map[k])}`
77
+ );
78
+ return `${JSON.stringify(key)}:{${parts.join(",")}}`;
79
+ };
80
+ const segments = [`"_data":${JSON.stringify(data)}`];
81
+ if (env._sealed !== void 0) segments.push(mapPart("_sealed", env._sealed));
82
+ if (env._vdig !== void 0) segments.push(mapPart("_vdig", env._vdig));
83
+ if (env._bidx !== void 0) segments.push(mapPart("_bidx", env._bidx));
84
+ return `{${segments.join(",")}}`;
85
+ }
86
+ function hasSealedBody(env) {
87
+ return env._iv !== void 0 && env._iv !== "";
88
+ }
89
+ function makeEnvelopeBody(p) {
90
+ const { encrypt, decrypt, generateDEK, wrapCek, unwrapCek } = p;
91
+ async function openEnvelopeJson(ref, env, key, opts) {
92
+ if (opts?.encrypted === false) return env._data ?? "";
93
+ const aad = recordAadFor(ref, env);
94
+ const { iv, data } = requireSealedBody(env, "openEnvelopeJson");
95
+ if (env._cek !== void 0) {
96
+ const cek = await unwrapCek(env._cek, key);
97
+ return decrypt(iv, data, cek, aad);
98
+ }
99
+ return decrypt(iv, data, key, aad);
100
+ }
101
+ async function writeEnvelopeBody(identity, json, key, opts) {
102
+ if (opts?.encrypted === false) return { _iv: "", _data: json };
103
+ const aad = buildRecordAad(identity);
104
+ if (opts?.perRecordKey === true) {
105
+ const cek = await generateDEK();
106
+ const { iv: iv2, data: data2 } = await encrypt(json, cek, aad);
107
+ const wrapped = await wrapCek(cek, key);
108
+ return { _iv: iv2, _data: data2, _cek: wrapped };
109
+ }
110
+ const { iv, data } = await encrypt(json, key, aad);
111
+ return { _iv: iv, _data: data };
112
+ }
113
+ async function verifyRecordIdentity(ref, env, key) {
114
+ if (!hasSealedBody(env)) return true;
115
+ try {
116
+ await openEnvelopeJson(ref, env, key);
117
+ return true;
118
+ } catch {
119
+ return false;
120
+ }
121
+ }
122
+ return { openEnvelopeJson, writeEnvelopeBody, verifyRecordIdentity };
123
+ }
124
+
125
+ // src/capsule/plumbing/record-envelope.ts
126
+ function buildRecordEnvelope(identity, body) {
127
+ return {
128
+ _noydb: NOYDB_FORMAT_VERSION,
129
+ _v: identity.version,
130
+ _ts: body.ts ?? (/* @__PURE__ */ new Date()).toISOString(),
131
+ _iv: body.iv,
132
+ _data: body.data,
133
+ ...identity.by !== void 0 ? { _by: identity.by } : {},
134
+ ...identity.tier !== void 0 && identity.tier > 0 ? { _tier: identity.tier } : {},
135
+ ...body.cek !== void 0 ? { _cek: body.cek } : {},
136
+ ...body.provenance !== void 0 ? { _source: body.provenance.source, _sourceTs: body.provenance.sourceTs } : {},
137
+ ...body.extra ?? {}
138
+ };
139
+ }
140
+ async function buildSealedRecordEnvelope(identity, seal, body) {
141
+ const sealed = await seal(identity);
142
+ const { iv, data } = requireSealedBody(sealed, "buildSealedRecordEnvelope");
143
+ return buildRecordEnvelope(identity, {
144
+ ...body,
145
+ iv,
146
+ data,
147
+ cek: sealed._cek
148
+ });
149
+ }
150
+
151
+ // src/capsule/plumbing/tombstone.ts
152
+ function isTombstoneShape(envelope) {
153
+ return envelope._data === "" && envelope._cek === void 0 && envelope._del !== true;
154
+ }
155
+ function isTombstone(envelope, encrypted) {
156
+ if (!encrypted) return false;
157
+ return isTombstoneShape(envelope);
158
+ }
159
+ function buildTombstone(ref, version, actor) {
160
+ return buildRecordEnvelope(
161
+ { ...ref, version, ...actor ? { by: actor } : {} },
162
+ { iv: "", data: "" }
163
+ );
164
+ }
165
+ function isDeleteMarker(envelope) {
166
+ return envelope._del === true;
167
+ }
168
+ function buildDeleteMarker(ref, version, actor) {
169
+ return {
170
+ ...buildRecordEnvelope(
171
+ { ...ref, version, ...actor ? { by: actor } : {} },
172
+ { iv: "", data: "" }
173
+ ),
174
+ _del: true
175
+ };
176
+ }
177
+
178
+ export {
179
+ buildRecordAad,
180
+ recordAadFor,
181
+ requireSealedBody,
182
+ sealedBodyArgs,
183
+ envelopeBodySize,
184
+ hasPerRecordKey,
185
+ envelopeBodyForHash,
186
+ hasSealedBody,
187
+ makeEnvelopeBody,
188
+ buildRecordEnvelope,
189
+ buildSealedRecordEnvelope,
190
+ isTombstoneShape,
191
+ isTombstone,
192
+ buildTombstone,
193
+ isDeleteMarker,
194
+ buildDeleteMarker
195
+ };
196
+ //# sourceMappingURL=chunk-XWWDZKLS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/capsule/plumbing/record-aad.ts","../src/capsule/plumbing/envelope-body.ts","../src/capsule/plumbing/record-envelope.ts","../src/capsule/plumbing/tombstone.ts"],"sourcesContent":["/**\n * Record-identity AAD (#1041).\n *\n * AES-GCM authenticates its *additional authenticated data* alongside the\n * ciphertext without encrypting it. Binding a record's identity here is what\n * stops an untrusted store from silently **relocating** an envelope — moving\n * it to another collection or id, re-tiering it, or rewriting who\n * wrote it — while keeping a body whose auth tag still verifies.\n *\n * Scope, stated plainly: this closes cross-COLLECTION relocation, the `_tier`\n * silent-hide, provenance forgery — and, since #1093, **version rollback**.\n *\n * ## `_v` is bound, and what it took to get there\n *\n * `_v` was deliberately left out at first, for a reason that was real rather\n * than cautious: the sync engine re-stamped `_v` on existing ciphertext without\n * holding a DEK (`advancePastRemote`), so binding it would have made every\n * conflict-superseded record undecryptable. #1042's `MergeAuthority` removed\n * that obstacle by giving the merge a DEK-holding capability, so advancing a\n * version became a **re-seal** instead of a metadata edit — and only then could\n * `_v` join the tuple.\n *\n * ⚠️ **What that buys, stated exactly** — the harness measured this, and the\n * loose version (\"rollback is prevented\") is wrong.\n *\n * A body can no longer be presented at a version it was not sealed at. So the\n * *restamped* rollback — take v1's bytes, label them v9, win the convergence\n * comparison, overwrite the newer copy — is refused, and refused **before**\n * `local.put`, so nothing is lost.\n *\n * A store re-serving the genuine v1 **at its own `_v: 1`** is still served, and\n * has to be: that envelope is internally consistent, and a reader arriving\n * fresh has nothing to compare it against. AAD binds a body to the version it\n * claims; it cannot know which version *should* have arrived.\n *\n * So rollback stops being forgery and becomes **withholding** — hiding the newer\n * version rather than faking one — which is `withVaultHead()`'s job (#1044).\n *\n * ## Why `vault` is not bound\n *\n * It was, briefly, and it broke `adoptPartition`. That path re-homes a whole\n * partition into a new vault name by moving envelopes **verbatim** —\n * `with-cargo/adopt-partition.ts:140` is a bare\n * `destinationStore.saveAll(vaultName, backup.collections)` with no\n * re-encryption, because it does not hold the keys to re-encrypt at that\n * point. Binding the vault name makes every adopted record undecryptable.\n *\n * The uncomfortable truth behind that: **relocation is not purely an attack.**\n * Adoption is a legitimate, supported relocation, and AAD cannot tell the two\n * apart. So the vault boundary has to be defended by something that can\n * distinguish intent — an authenticated head or an explicit re-key — rather\n * than by sealing a name the product deliberately changes.\n *\n * Cross-*collection* relocation has no such legitimate counterpart, so it stays\n * bound.\n *\n * @packageDocumentation\n */\n\n/**\n * Where an envelope was fetched from — the **read** side's half of identity.\n *\n * A reader supplies only the address, because that is genuinely all it knows:\n * `_tier`, `_by` and `_v` are read back off the envelope itself\n * ({@link recordAadFor}). Splitting this out of {@link RecordIdentity} is what\n * lets `version` be *required* on the write side without forcing dozens of read\n * call sites to invent one.\n */\nexport interface RecordRef {\n readonly collection: string\n readonly id: string\n}\n\n/**\n * The identity an envelope's body is sealed against — the **write** side.\n *\n * Every field here is stamped onto the envelope by `buildRecordEnvelope` from\n * this one object, so what a writer *seals* and what it *stamps* cannot drift.\n */\nexport interface RecordIdentity extends RecordRef {\n /**\n * The `_v` this body is sealed at (#1093).\n *\n * Required, and required is the point: a version that could be omitted would\n * be a version some writer forgets, and a record sealed at a version nobody\n * chose is one a reader cannot open. The compiler asks the question at every\n * write site instead of leaving it to review.\n */\n readonly version: number\n /** Absent is identical to `0` — the read paths treat them as one record. */\n readonly tier?: number | undefined\n /** Absent (no `_by` on the envelope) is distinct from an empty string. */\n readonly by?: string | undefined\n}\n\n/** Bumped from `/1` when `_v` joined the tuple (#1093). Nothing branches on it. */\nconst SCHEME = 'noydb-aad/2'\n\nconst encoder = new TextEncoder()\n\n/**\n * Length-prefixed, order-fixed encoding.\n *\n * The obvious `${collection}:${id}` is unsafe: an attacker who\n * controls a collection name can choose one that re-splits the same joined\n * string a different way, so two different identities produce identical AAD\n * and the relocation this exists to prevent goes through. Every field is\n * therefore written as a 4-byte big-endian length followed by its UTF-8 bytes,\n * which no field content can imitate.\n *\n * A one-byte presence flag precedes `by` so that \"no author recorded\" and\n * \"author recorded as the empty string\" cannot be swapped for one another.\n */\nexport function buildRecordAad(identity: RecordIdentity): Uint8Array {\n // ⚠️ Assert on the VALUE, not on the caller's type. `version` is required in\n // TypeScript, so this can only fire for a caller the compiler never saw — a\n // hand-built test fixture, a JS consumer, a `Partial` widened somewhere. It\n // matters because the failure it prevents is invisible: `String(undefined)`\n // is a perfectly good AAD field, so the record seals happily and becomes\n // undecryptable at the next read, with a TamperedError pointing at the READ\n // path where the code is correct. Several fixtures did exactly this (#1093).\n if (!Number.isFinite(identity.version)) {\n throw new TypeError(\n `record AAD: version must be a finite number for \"${identity.collection}/${identity.id}\", ` +\n `received ${String(identity.version)}. Sealing without one produces a record no reader can open.`,\n )\n }\n // Same argument as `version` above, for the two fields that are STRINGS\n // and therefore coerce instead of arriving as NaN (#1220). `String({})` is\n // `\"[object Object]\"` and `String(undefined)` is `\"undefined\"` — both seal\n // perfectly well and both produce a record no reader will ever address.\n // Measured: `collection.put({ id: 'd1', ... })` from JS stores under\n // `\"[object Object]\"`, and an unset identity reaches the store as\n // `undefined`. Assert on the OUTPUT condition — no seal may be computed\n // over a non-string address — rather than on the two calls that found it.\n for (const [field, value] of [['collection', identity.collection], ['id', identity.id]] as const) {\n if (typeof value !== 'string') {\n throw new TypeError(\n `record AAD: ${field} must be a string, received ${String(value)} ` +\n `(${typeof value}). Sealing against a coerced address produces a record ` +\n `no reader can open, and the failure surfaces on the READ path.`,\n )\n }\n }\n\n const parts: Uint8Array[] = [encoder.encode(SCHEME)]\n\n const pushField = (value: string): void => {\n const bytes = encoder.encode(value)\n const len = new Uint8Array(4)\n new DataView(len.buffer).setUint32(0, bytes.length, false)\n parts.push(len, bytes)\n }\n\n pushField(identity.collection)\n pushField(identity.id)\n // Absent tier ≡ tier 0: `collection.ts` reads `(envelope._tier ?? 0) > 0`,\n // so treating them differently here would make a record written without a\n // tier undecryptable once read through a tier-aware path.\n pushField(String(identity.tier ?? 0))\n\n parts.push(new Uint8Array([identity.by === undefined ? 0 : 1]))\n if (identity.by !== undefined) pushField(identity.by)\n // `_v` (#1093). Written as its decimal string through the same length-prefixed\n // field encoding as everything else, so a version cannot be confused with the\n // author beside it.\n pushField(String(identity.version))\n\n const total = parts.reduce((n, p) => n + p.length, 0)\n const out = new Uint8Array(total)\n let offset = 0\n for (const p of parts) {\n out.set(p, offset)\n offset += p.length\n }\n return out\n}\n\n/**\n * The AAD a **reader** must supply to open `envelope`, given where it fetched\n * it from.\n *\n * This is the read-side counterpart of {@link buildRecordAad}, and the split\n * exists because of one asymmetry: **a writer always knows what it is writing;\n * a reader often does not.** Query execution, sync merge and backup restore\n * hold an envelope that arrived from a map or a batch, having discarded the\n * address it came from.\n *\n * What makes the read side tractable is that only `{collection, id}` has to be\n * threaded — precisely what the caller passed to `store.get`. `_tier`, `_by`\n * and `_v` are read back **off the envelope**, so no extra plumbing carries\n * them.\n *\n * That is not a weakening. An attacker who edits `_tier` to hide a record,\n * `_by` to forge provenance, or `_v` to pass an old body off as the current\n * one, changes the AAD the reader computes — and AES-GCM then fails to\n * authenticate. The tampered field defeats itself.\n */\nexport function recordAadFor(\n ref: RecordRef,\n envelope: {\n readonly _v: number\n readonly _tier?: number | undefined\n readonly _by?: string | undefined\n },\n): Uint8Array {\n return buildRecordAad({\n collection: ref.collection,\n id: ref.id,\n version: envelope._v,\n tier: envelope._tier,\n by: envelope._by,\n })\n}\n","/**\n * Enclave body helpers — the C1 protected-body access contract.\n *\n * `EncryptedEnvelope` splits into a protocol header (family-owned; `_noydb`,\n * `_v`, `_ts`, `_by`, `_source`, `_sourceTs`, `_tier`, `_elevatedBy`) and a\n * protected body (enclave-owned; `_iv`, `_data`, `_cek`, `_det`, `_sealed`,\n * `_debug`). The four helpers below are the ONLY sanctioned way for code\n * outside `capsule/enclave-aes/**` to read or construct the protected body —\n * later migration batches move the ~121 direct `_iv`/`_data`/`_cek`/`_sealed`\n * access sites in `with-*` services onto these.\n *\n * Each helper reproduces an EXISTING behavior byte-for-byte (see the\n * per-function doc for its oracle call site) — this file introduces no new\n * crypto or semantics, only a narrower door onto what already runs.\n */\nimport { buildRecordAad, recordAadFor, type RecordIdentity, type RecordRef } from './record-aad.js'\nimport type { CapsuleKey, CapsulePrimitives } from '../contract.js'\nimport type { EncryptedEnvelope } from '../../kernel/types.js'\nimport { MissingEnvelopeBodyError } from '../../kernel/errors.js'\n\n/**\n * The sealed body, or a typed refusal (#15).\n *\n * Since `_iv`/`_data` became optional, every AES path that is about to call\n * `decrypt()` needs this one narrowing. It is deliberately the ONLY place in\n * the enclave that turns absence into an error: the alternative — a `!` or a\n * `?? ''` at each of the two dozen decrypt sites — would have spelled the\n * same decision twenty-four times and produced an AEAD failure (i.e. hub's\n * tamper alert) instead of an honest one.\n *\n * Ask {@link hasSealedBody} FIRST when absence is a legitimate outcome; this\n * helper is for the paths where it is not.\n */\nexport function requireSealedBody(\n env: Pick<EncryptedEnvelope, '_iv' | '_data'>,\n where: string,\n): { iv: string; data: string } {\n if (env._iv === undefined || env._data === undefined) throw new MissingEnvelopeBodyError(where)\n return { iv: env._iv, data: env._data }\n}\n\n/**\n * {@link requireSealedBody} shaped for the `decrypt(iv, data, …)` argument\n * list, so a narrowing can be spliced into an existing call without\n * restructuring the statement around it:\n *\n * ```ts\n * await decrypt(...sealedBodyArgs(env, 'rekeyRecord'), dek, aad)\n * ```\n *\n * The tuple return type is load-bearing — it is what lets the spread satisfy\n * two fixed positional parameters. Widening it to `string[]` would compile\n * here and fail at every call site.\n */\nexport function sealedBodyArgs(\n env: Pick<EncryptedEnvelope, '_iv' | '_data'>,\n where: string,\n): [string, string] {\n const { iv, data } = requireSealedBody(env, where)\n return [iv, data]\n}\n\n/**\n * Approximate protected-body payload size for KPI/telemetry (#807's\n * period-scoped pull download counters): `_data` + `_iv` string length —\n * ≈ ciphertext bytes for base64 payloads, exact for plaintext (`_iv: ''`)\n * collections. A measuring door, not a crypto one: callers get a size\n * without touching the protected fields directly.\n */\nexport function envelopeBodySize(env: EncryptedEnvelope): number {\n // An absent field meters as 0, the same as the emptied spelling it replaces\n // (#15) — a bodyless row has no payload to bill for, and throwing a\n // TypeError out of a telemetry counter would take down the write path.\n return (env._data?.length ?? 0) + (env._iv?.length ?? 0)\n}\n\n/**\n * Discriminant: does this envelope carry a per-record key?\n *\n * Replaces raw `envelope._cek !== undefined` checks scattered across\n * services — `_cek` presence is the format discriminant (see\n * `record-codec.ts`'s `resolveEnvelopeCek` doc).\n */\nexport function hasPerRecordKey(env: EncryptedEnvelope): boolean {\n return env._cek !== undefined\n}\n\n/**\n * Canonical body string for the ledger hash chain — the exact bytes\n * `with-commit/history/ledger/hash.ts`'s `envelopePayloadHash` derives from\n * `_data` + `_sealed` + `_vdig` + `_bidx` before hashing:\n * - no `_sealed`, no `_vdig`, no `_bidx` → `_data` alone (back-compat: every\n * pre-existing ledger entry and non-sealed backup hashes byte-identically).\n * - any map present → canonical JSON of `{ _data, _sealed?, _vdig?, _bidx? }`\n * with sorted keys at every level, each map bound ONLY when present, so\n * the result is independent of the maps' field-insertion / store-\n * serialization order. `_bidx` is always the LAST segment, so a legacy\n * `_vdig`-only / `_bidx`-absent envelope hashes byte-identically to its\n * stage-2 value.\n *\n * Deliberately reimplements the two-key-object canonicalization inline\n * rather than importing `with-commit/history/ledger/entry.ts`'s general\n * `canonicalJson` — `capsule/enclave-aes/**` may import only spine types (C3),\n * never a `with-*` service. For this fixed `{ _data: string; _sealed:\n * Record<string, string> }` shape the two produce byte-identical output\n * (verified against that exact call site's oracle expression in\n * `envelope-body.test.ts`).\n */\nexport function envelopeBodyForHash(env: EncryptedEnvelope): string {\n // Conditional widen (stage 2): bind `_vdig` exactly the way `_sealed` is\n // bound — only when present. No existing envelope carries `_vdig`, so this\n // ships with no flag-day PROVIDED it lands in the same slice as the first\n // `_vdig` writer (it does — Tasks 7/8/11 are one branch). This binding is\n // the temporal-rollback detector completing C1: AAD stops cross-record/\n // cross-field splices; the ledger hash catches same-slot rollbacks.\n //\n // Conditional widen (slice 2b, SM #5): bind `_bidx` the same way, appended\n // LAST (after `_vdig`) so a `_bidx`-absent envelope keeps its stage-2\n // byte-identical hash.\n // `?? ''` (#15): an omitted `_data` must hash identically to an emptied\n // one, or a capsule changing spelling would invalidate every ledger entry\n // written before it.\n const data = env._data ?? ''\n if (env._sealed === undefined && env._vdig === undefined && env._bidx === undefined) return data\n const mapPart = (key: '_sealed' | '_vdig' | '_bidx', map: Record<string, string>): string => {\n const parts = Object.keys(map).sort().map(\n (k) => `${JSON.stringify(k)}:${JSON.stringify(map[k])}`,\n )\n return `${JSON.stringify(key)}:{${parts.join(',')}}`\n }\n const segments = [`\"_data\":${JSON.stringify(data)}`]\n if (env._sealed !== undefined) segments.push(mapPart('_sealed', env._sealed))\n if (env._vdig !== undefined) segments.push(mapPart('_vdig', env._vdig))\n if (env._bidx !== undefined) segments.push(mapPart('_bidx', env._bidx))\n return `{${segments.join(',')}}`\n}\n\n/**\n * Does `env` carry an AEAD-sealed body at all?\n *\n * The one question callers outside the enclave legitimately need to ask about\n * `_iv` — a tombstone and a plaintext-collection record have none, so there is\n * nothing to authenticate and nothing to re-seal. Both {@link\n * verifyRecordIdentity} (which treats them as vacuously authentic) and the\n * merge authority's `advance` (which stamps them without re-sealing) turn on\n * it, and asking it here keeps `_iv` from leaking back out to the callers —\n * which `enclave-body-only` refused, correctly, when `advance` tested it inline.\n */\nexport function hasSealedBody(env: Pick<EncryptedEnvelope, '_iv'>): boolean {\n // ⛔ `env._iv !== ''` alone answered TRUE for an omitted `_iv` (#15) — the\n // exact inversion of what the caller is asking. Absence and `''` are the\n // same statement: there is nothing here to authenticate.\n return env._iv !== undefined && env._iv !== ''\n}\n\n/**\n * The cipher-dependent half: the three doors that actually reach the capsule's\n * `encrypt`/`decrypt`. Everything above this line is cipher-FREE — it inspects\n * envelope fields or derives hash input, so it stays a plain module export that\n * both capsules share with nothing to bind.\n */\nexport function makeEnvelopeBody(p: CapsulePrimitives) {\n const { encrypt, decrypt, generateDEK, wrapCek, unwrapCek } = p\n\n /**\n * Open an envelope's protected body to its JSON text.\n *\n * Mirrors the dominant direct-decrypt call-site shape (e.g.\n * `with-audit/consent/consent.ts`'s `decryptEntry`):\n * - `opts.encrypted === false` (default `true`) → plaintext collection;\n * returns `env._data` as-is, `key` untouched.\n * - `env._cek` present → per-record-key envelope (mirrors\n * `record-codec.ts`'s `resolveEnvelopeCek`): unwrap the CEK under `key`\n * (the collection DEK), decrypt the body under the unwrapped CEK.\n * - `env._cek` absent → legacy path, decrypt the body directly under `key`.\n */\n async function openEnvelopeJson(\n ref: RecordRef,\n env: EncryptedEnvelope,\n key: CapsuleKey,\n opts?: { encrypted?: boolean },\n ): Promise<string> {\n // A plaintext collection has no AEAD, so there is nothing to authenticate —\n // `_data` is returned as-is and identity binding does not apply to it.\n // Absent `_data` reads as `''` here, exactly as an emptied one always has:\n // a plaintext collection with nothing in it is not an error.\n if (opts?.encrypted === false) return env._data ?? ''\n // Recomputed from the ADDRESS this was fetched from plus `_tier`/`_by` read\n // off the envelope. A store that edited either one changes this value, and\n // AES-GCM then refuses the body (#1041).\n const aad = recordAadFor(ref, env)\n const { iv, data } = requireSealedBody(env, 'openEnvelopeJson')\n if (env._cek !== undefined) {\n const cek = await unwrapCek(env._cek, key)\n return decrypt(iv, data, cek, aad)\n }\n return decrypt(iv, data, key, aad)\n }\n\n /**\n * Produce the protected-body fields (`_iv`/`_data`/`_cek`) for an envelope a\n * caller is assembling.\n *\n * - `opts.encrypted === false` (default `true`) → plaintext collection;\n * emits `{ _iv: '', _data: json }` (today's `buildPlaintextEnvelope`\n * shape), `key` untouched.\n * - `opts.perRecordKey === true` → mints a fresh per-record CEK, encrypts\n * the body under it, and AES-KW-wraps the CEK under `key` (mirrors\n * `encryptJsonString`'s `cek !== undefined` branch, except the CEK is\n * generated here rather than supplied by the caller).\n * - otherwise → legacy path, body encrypted directly under `key`.\n */\n async function writeEnvelopeBody(\n identity: RecordIdentity,\n json: string,\n key: CapsuleKey,\n opts?: { encrypted?: boolean; perRecordKey?: boolean },\n ): Promise<Pick<EncryptedEnvelope, '_iv' | '_data' | '_cek'>> {\n if (opts?.encrypted === false) return { _iv: '', _data: json }\n\n const aad = buildRecordAad(identity)\n\n if (opts?.perRecordKey === true) {\n const cek = await generateDEK()\n const { iv, data } = await encrypt(json, cek, aad)\n const wrapped = await wrapCek(cek, key)\n return { _iv: iv, _data: data, _cek: wrapped }\n }\n\n const { iv, data } = await encrypt(json, key, aad)\n return { _iv: iv, _data: data }\n }\n\n /**\n * Does `env` authenticate at the identity `ref` claims, under `key`? (#1042)\n *\n * The merge's fail-closed check, living here because it is envelope surgery:\n * deciding \"is there a sealed body at all\" reads `_iv`, which\n * `enclave-body-only` reserves to this folder. An earlier draft did that test\n * in `kernel/noydb.ts` and the guard refused it — correctly, since a caller\n * outside the enclave inspecting protected fields is how envelope knowledge\n * leaks back out.\n *\n * Returns a boolean rather than throwing: `applyRemote` must be able to reject\n * one poisoned record without halting an entire sync, and a hostile store\n * would very much like the opposite.\n *\n * **A record with no sealed body is vacuously authentic** — a tombstone carries\n * none, and a plaintext collection has no AEAD to verify. Those are pass-through\n * by construction, not by omission.\n */\n async function verifyRecordIdentity(\n ref: RecordRef,\n env: EncryptedEnvelope,\n key: CapsuleKey,\n ): Promise<boolean> {\n if (!hasSealedBody(env)) return true\n try {\n await openEnvelopeJson(ref, env, key)\n return true\n } catch {\n return false\n }\n }\n\n return { openEnvelopeJson, writeEnvelopeBody, verifyRecordIdentity }\n}\n","/**\n * The one place an `EncryptedEnvelope` is constructed (#1051).\n *\n * ## Why this exists\n *\n * 49 files built envelopes with an object literal, bypassing\n * `RecordCodec.buildEnvelope` (which had 4 callers). That is **writer\n * fan-out**: N independent places each had to know the envelope contract, and\n * nothing checked that they agreed.\n *\n * It only became load-bearing with #1041. Binding a record's identity into the\n * AEAD requires every writer to supply that identity — and a writer that\n * doesn't produces data the reader rejects. Reader fan-out you fix by threading\n * an argument through call sites; **writer fan-out cannot be migrated\n * incrementally**, because the first migrated writer emits envelopes the\n * unmigrated readers refuse.\n *\n * ## Why adopting it is safe\n *\n * `identity` is **required but not yet used**. Output is byte-identical to the\n * literals it replaces, so every producer can migrate independently and the\n * existing suite verifies each step. The behaviour change happens **once**,\n * when AAD is switched on here — by which point every writer already supplies\n * identity, and the compiler proved it.\n *\n * That ordering is deliberate: a required-but-unused parameter converts \"did\n * we find every writer?\" from a question into a compile error, the same trick\n * that made the `NOYDB_FORMAT_VERSION` single-sourcing safe in #1048.\n *\n * @packageDocumentation\n */\nimport { NOYDB_FORMAT_VERSION } from '../../kernel/types.js'\nimport type { EncryptedEnvelope } from '../../kernel/types.js'\nimport type { RecordIdentity } from './record-aad.js'\nimport { requireSealedBody } from './envelope-body.js'\n\n/** The body an envelope carries, independent of who is writing it. */\nexport interface RecordEnvelopeBody {\n /** AES-GCM IV, base64. Empty string for a plaintext or tombstone envelope. */\n readonly iv: string\n /** Ciphertext (or plaintext JSON when the collection stores plaintext). */\n readonly data: string\n /** ISO timestamp. Defaults to now — pass it when the caller has a real one. */\n readonly ts?: string | undefined\n /** Wrapped per-record CEK, when the record has one. */\n readonly cek?: string | undefined\n readonly provenance?: { readonly source: string; readonly sourceTs: string } | undefined\n /**\n * Slots the envelope may additionally carry.\n *\n * `_tier`, `_by` and `_v` are deliberately NOT here — they come from\n * `identity`, which is the single source for all three. See\n * {@link buildRecordEnvelope}.\n */\n readonly extra?: Partial<Pick<EncryptedEnvelope, '_det' | '_sealed' | '_vdig' | '_bidx'>> | undefined\n}\n\n/**\n * Build an envelope for `identity`.\n *\n * ## `identity` is the SINGLE SOURCE for `_by`, `_tier` and `_v`\n *\n * All three are stamped from it, and `RecordEnvelopeBody` deliberately cannot\n * carry them. That is not tidiness — it is what makes the AAD binding safe.\n *\n * The caller encrypts the body under AAD derived from `{collection, id, tier,\n * by, version}`. A reader recomputes that AAD from the address it fetched from\n * plus `_tier`/`_by`/`_v` read back **off the envelope** (`recordAadFor`). So if the\n * identity a writer *declares* could differ from the fields it *stamps*, the\n * AAD would not reproduce and the record would be undecryptable — silently, at\n * write time, discoverable only on the next read, and invisible to every gate\n * because the envelope is perfectly well-formed.\n *\n * An earlier draft took both and asserted they agreed. The assertion fired 230\n * times on the existing tree, which is the argument against it: a rule that can\n * be violated is a rule someone must remember. Taking one source removes the\n * violation instead of reporting it.\n */\nexport function buildRecordEnvelope(\n identity: RecordIdentity,\n body: RecordEnvelopeBody,\n): EncryptedEnvelope {\n return {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: identity.version,\n _ts: body.ts ?? new Date().toISOString(),\n _iv: body.iv,\n _data: body.data,\n ...(identity.by !== undefined ? { _by: identity.by } : {}),\n ...(identity.tier !== undefined && identity.tier > 0 ? { _tier: identity.tier } : {}),\n ...(body.cek !== undefined ? { _cek: body.cek } : {}),\n ...(body.provenance !== undefined\n ? { _source: body.provenance.source, _sourceTs: body.provenance.sourceTs }\n : {}),\n ...(body.extra ?? {}),\n }\n}\n\n/**\n * Build an envelope from an already-sealed body — the output of\n * `writeEnvelopeBody` — **without the caller ever naming `_iv`/`_data`/`_cek`**.\n *\n * This exists because of a guard, and the guard was right. Migrating\n * `writeEnvelopeBody` callers to {@link buildRecordEnvelope} meant rewriting\n * `...body` (a spread, which names nothing) into `iv: body._iv, data:\n * body._data, cek: body._cek` — and `enclave-body-only` failed it: three new\n * protected-body accesses in files that previously had zero.\n *\n * That is the correct outcome rather than an obstacle. #1051 exists to move\n * knowledge of the envelope's shape *inward*; a migration that spreads the\n * protected field names outward to every caller would have defeated its own\n * purpose while looking like progress. The pairing belongs here.\n *\n * ## It takes a SEALER, not a sealed body — and that is load-bearing (#1041)\n *\n * The obvious shape is `(identity, alreadySealedBody, rest)`. That requires the\n * caller to name the identity TWICE — once for `writeEnvelopeBody` and once\n * here — and the two must agree byte for byte or the record is sealed under\n * AAD no reader can reproduce.\n *\n * They did not agree. `with-party/broker/seed.ts` sealed against\n * `{collection, id}` and stamped `{collection, id, by}`, so every broker seed\n * became unreadable the moment AAD switched on. Taking the sealer means the\n * identity is written once and handed to both — divergence stops being\n * possible rather than being something to remember.\n */\nexport async function buildSealedRecordEnvelope(\n identity: RecordIdentity,\n seal: (identity: RecordIdentity) => Promise<Pick<EncryptedEnvelope, '_iv' | '_data' | '_cek'>>,\n body: Omit<RecordEnvelopeBody, 'iv' | 'data' | 'cek'>,\n): Promise<EncryptedEnvelope> {\n const sealed = await seal(identity)\n // #15: `seal` returns the widened `Pick<Envelope, …>`, so both fields are\n // optional at the type level. A sealer that returned neither has not sealed\n // anything, and building a record envelope around that would persist a row\n // whose body silently became `''`. Refuse instead.\n const { iv, data } = requireSealedBody(sealed, 'buildSealedRecordEnvelope')\n return buildRecordEnvelope(identity, {\n ...body,\n iv,\n data,\n cek: sealed._cek,\n })\n}\n","/**\n * Tombstone shape + predicate for the per-record-key (CEK) layer.\n *\n * A *tombstone* is the residue a GDPR crypto-shred (`vault.forget()`)\n * leaves on disk: the live envelope rewritten to `{ _noydb, _v, _ts, _by,\n * _iv:'', _data:'' }`, dropping `_iv`/`_data`/`_cek`/`_det`. With the wrapped\n * per-record CEK gone, the body — and every history version under the same\n * CEK — is permanently undecryptable, while the record KEY survives so the\n * version counter and \"record existed and was erased\" persist for the audit\n * ledger.\n *\n * These two helpers are the pure, collection-independent core of that\n * contract: {@link buildTombstone} mints the shape, {@link isTombstone}\n * recognises it on the read path. The orchestration that *writes* a tombstone\n * (`_writeTombstone`) and drives `vault.forget()` lives with the collection /\n * vault; it calls into these.\n */\nimport { type EncryptedEnvelope } from '../../kernel/types.js'\nimport { buildRecordEnvelope } from './record-envelope.js'\nimport type { RecordRef } from './record-aad.js'\n\n/**\n * Shape-only tombstone recognition for layers that have no per-collection\n * context (the sync engine, #590): a tombstone carries an empty `_data` and\n * no wrapped CEK. No live envelope can match — record bodies never serialize\n * to the empty string (the `_sync` meta envelope carries non-empty `_data`,\n * and legacy migration envelopes carry non-empty `_iv`/`_data`).\n */\nexport function isTombstoneShape(envelope: EncryptedEnvelope): boolean {\n return envelope._data === '' && envelope._cek === undefined && envelope._del !== true\n}\n\n/**\n * Is this envelope a crypto-shred tombstone?\n *\n * A tombstone carries no body (`_data` empty) and no wrapped CEK (`_cek`\n * absent) — decrypting it would call `decrypt('', '', dek)` → an AES-GCM\n * throw, so every read choke point must short-circuit to `null` instead.\n *\n * `encrypted` is the collection's encryption flag: on an unencrypted\n * collection there are no envelopes to shred, so nothing is ever a tombstone.\n * (Legacy migration envelopes carry non-empty `_iv`/`_data`, so they are not\n * tombstones and stay readable.)\n */\nexport function isTombstone(envelope: EncryptedEnvelope, encrypted: boolean): boolean {\n if (!encrypted) return false\n return isTombstoneShape(envelope)\n}\n\n/**\n * Mint a tombstone envelope from a record's live version + actor.\n *\n * Keeps `_v` (the displaced version) so the counter is monotonic across the\n * shred, stamps a fresh `_ts`, and records `_by` when an actor is supplied.\n * Deliberately omits `_iv`/`_data`/`_cek`/`_det` — that omission *is* the\n * erasure.\n */\nexport function buildTombstone(\n ref: RecordRef,\n version: number,\n actor: string,\n): EncryptedEnvelope {\n // `actor` rides on the IDENTITY, not the body — it is stamped as `_by` and\n // bound into the AAD from that one source (#1041).\n return buildRecordEnvelope(\n { ...ref, version, ...(actor ? { by: actor } : {}) },\n { iv: '', data: '' },\n )\n}\n\n/** #589: is this envelope an ordinary-delete marker (version-ordered, reads as absent)? */\nexport function isDeleteMarker(envelope: EncryptedEnvelope): boolean {\n return envelope._del === true\n}\n\n/**\n * Mint a delete marker from the deleted record's next version + actor (#589).\n * Minted at the NEXT version (`existing._v + 1`) — unlike `buildTombstone`, which\n * keeps the displaced `_v` — so it wins convergence over the pre-delete copy and a\n * re-create can still win over it at a higher version.\n */\nexport function buildDeleteMarker(\n ref: RecordRef,\n version: number,\n actor: string,\n): EncryptedEnvelope {\n // `_del` is not one of buildRecordEnvelope's declared slots — a delete marker\n // is a distinct envelope class, not a record body — so it is stamped here.\n return {\n ...buildRecordEnvelope(\n { ...ref, version, ...(actor ? { by: actor } : {}) },\n { iv: '', data: '' },\n ),\n _del: true,\n }\n}\n"],"mappings":"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","names":["iv","data"]}