@noy-db/hub 0.6.0-pre.17 → 0.6.0-pre.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (306) hide show
  1. package/dist/{api-AEIN3KAQ.js → api-FRFEJ6WR.js} +6 -6
  2. package/dist/attestation/index.js +12 -12
  3. package/dist/{backup-7X3PFTSI.js → backup-OLBRFYY7.js} +10 -10
  4. package/dist/{backup-7X3PFTSI.js.map → backup-OLBRFYY7.js.map} +1 -1
  5. package/dist/blobs/index.js +8 -8
  6. package/dist/broker/index.js +6 -6
  7. package/dist/cargo/index.js +26 -26
  8. package/dist/{chunk-V3OLO4TK.js → chunk-2ION5ZRH.js} +17 -14
  9. package/dist/chunk-2ION5ZRH.js.map +1 -0
  10. package/dist/{chunk-466KGOQB.js → chunk-2NE7ILO7.js} +2 -2
  11. package/dist/{chunk-GWI65NDQ.js → chunk-3KXIGMZ4.js} +2 -2
  12. package/dist/{chunk-C3YP5KKS.js → chunk-3ODOWQMV.js} +13 -14
  13. package/dist/chunk-3ODOWQMV.js.map +1 -0
  14. package/dist/{chunk-X2FXEEQT.js → chunk-3RZ7QLJ4.js} +5 -5
  15. package/dist/{chunk-5UGEGEIJ.js → chunk-3Y4OFWQJ.js} +1 -1
  16. package/dist/chunk-3Y4OFWQJ.js.map +1 -0
  17. package/dist/{chunk-FZ2SSI5R.js → chunk-6AL6O4CS.js} +2 -2
  18. package/dist/{chunk-67XA44HH.js → chunk-6D3CN2JR.js} +2 -2
  19. package/dist/{chunk-5VVBZ6E4.js → chunk-6QCXMCLZ.js} +3 -3
  20. package/dist/{chunk-4GR422R5.js → chunk-7EH322GJ.js} +14 -7
  21. package/dist/chunk-7EH322GJ.js.map +1 -0
  22. package/dist/{chunk-AMKCY454.js → chunk-7WD2G6K4.js} +7 -2
  23. package/dist/{chunk-AMKCY454.js.map → chunk-7WD2G6K4.js.map} +1 -1
  24. package/dist/{chunk-URVL4EKU.js → chunk-A5QQKWCK.js} +14 -23
  25. package/dist/chunk-A5QQKWCK.js.map +1 -0
  26. package/dist/{chunk-2RGQNFJB.js → chunk-AA2WWTS3.js} +9 -7
  27. package/dist/chunk-AA2WWTS3.js.map +1 -0
  28. package/dist/{chunk-UKKBKEUI.js → chunk-AA7LM2A3.js} +2 -2
  29. package/dist/{chunk-SJOK23XT.js → chunk-AIZNLHKN.js} +4 -4
  30. package/dist/chunk-AIZNLHKN.js.map +1 -0
  31. package/dist/{chunk-UNR6G3EJ.js → chunk-AMMYIT7F.js} +35 -31
  32. package/dist/chunk-AMMYIT7F.js.map +1 -0
  33. package/dist/{chunk-NWPR2V5W.js → chunk-BBU3OD3D.js} +2 -2
  34. package/dist/{chunk-EEBMKMA7.js → chunk-BVIGGV6D.js} +33 -45
  35. package/dist/chunk-BVIGGV6D.js.map +1 -0
  36. package/dist/{chunk-OXRPH6AR.js → chunk-CFTPERGL.js} +14 -11
  37. package/dist/chunk-CFTPERGL.js.map +1 -0
  38. package/dist/{chunk-AKFNLRA2.js → chunk-CGQUSSW7.js} +26 -142
  39. package/dist/chunk-CGQUSSW7.js.map +1 -0
  40. package/dist/{chunk-JHYISAID.js → chunk-DFFSCYIW.js} +9 -9
  41. package/dist/{chunk-BMDF4TLU.js → chunk-DKYEVHZH.js} +7 -10
  42. package/dist/chunk-DKYEVHZH.js.map +1 -0
  43. package/dist/{chunk-YVOW35HH.js → chunk-DL4GDOWL.js} +4 -6
  44. package/dist/chunk-DL4GDOWL.js.map +1 -0
  45. package/dist/{chunk-Z2OFE6IX.js → chunk-DWO55ZWE.js} +13 -22
  46. package/dist/chunk-DWO55ZWE.js.map +1 -0
  47. package/dist/{chunk-XTC5EKST.js → chunk-ER3BQCCE.js} +2 -2
  48. package/dist/{chunk-JU3JKOY5.js → chunk-EWAGI3EM.js} +2 -2
  49. package/dist/{chunk-OAWVM5L6.js → chunk-EZ3UHHND.js} +13 -15
  50. package/dist/chunk-EZ3UHHND.js.map +1 -0
  51. package/dist/{chunk-IEA3TZJE.js → chunk-FDIZHZ3C.js} +29 -47
  52. package/dist/chunk-FDIZHZ3C.js.map +1 -0
  53. package/dist/{chunk-7TZTQS4H.js → chunk-FOABWV7L.js} +45 -18
  54. package/dist/chunk-FOABWV7L.js.map +1 -0
  55. package/dist/{chunk-QKRJUPAC.js → chunk-FRGF56PD.js} +11 -14
  56. package/dist/chunk-FRGF56PD.js.map +1 -0
  57. package/dist/{chunk-N4GAJSRQ.js → chunk-FY33DKPH.js} +2 -2
  58. package/dist/{chunk-JV2CNEX2.js → chunk-GSRW5MTU.js} +220 -169
  59. package/dist/chunk-GSRW5MTU.js.map +1 -0
  60. package/dist/{chunk-C52CJDFO.js → chunk-HJRTFXAA.js} +7 -10
  61. package/dist/chunk-HJRTFXAA.js.map +1 -0
  62. package/dist/chunk-HK67PX4J.js +27 -0
  63. package/dist/chunk-HK67PX4J.js.map +1 -0
  64. package/dist/{chunk-6JRIYG2C.js → chunk-IN5EZWYQ.js} +13 -14
  65. package/dist/chunk-IN5EZWYQ.js.map +1 -0
  66. package/dist/{chunk-QJBXB4WU.js → chunk-ITXPKEDP.js} +23 -29
  67. package/dist/chunk-ITXPKEDP.js.map +1 -0
  68. package/dist/{chunk-EMFFWSAD.js → chunk-JYFJNSTW.js} +9 -9
  69. package/dist/chunk-JYFJNSTW.js.map +1 -0
  70. package/dist/{chunk-D6E5N2O3.js → chunk-KLVGF2D4.js} +11 -9
  71. package/dist/{chunk-D6E5N2O3.js.map → chunk-KLVGF2D4.js.map} +1 -1
  72. package/dist/{chunk-7LLKPODL.js → chunk-LPAGIMXJ.js} +2 -2
  73. package/dist/{chunk-3JQVA527.js → chunk-LU6NPJWN.js} +3 -3
  74. package/dist/{chunk-VUQZYVYX.js → chunk-NAAPSNCS.js} +90 -33
  75. package/dist/chunk-NAAPSNCS.js.map +1 -0
  76. package/dist/{chunk-DEP24EE3.js → chunk-NFPSC2HL.js} +3 -3
  77. package/dist/{chunk-JAHIL6WO.js → chunk-NRNTXBHT.js} +7 -10
  78. package/dist/chunk-NRNTXBHT.js.map +1 -0
  79. package/dist/{chunk-N7HOHWKF.js → chunk-O4QDBAB6.js} +7 -10
  80. package/dist/{chunk-N7HOHWKF.js.map → chunk-O4QDBAB6.js.map} +1 -1
  81. package/dist/{chunk-VQQUOEON.js → chunk-OCCNYGKG.js} +7 -7
  82. package/dist/{chunk-VEA35MQP.js → chunk-OZD3D2DZ.js} +10 -13
  83. package/dist/chunk-OZD3D2DZ.js.map +1 -0
  84. package/dist/{chunk-IRHOQFA7.js → chunk-PBPYQZDW.js} +2 -2
  85. package/dist/{chunk-FHFMWYGM.js → chunk-PBRIHUQ5.js} +5 -5
  86. package/dist/{chunk-FHFMWYGM.js.map → chunk-PBRIHUQ5.js.map} +1 -1
  87. package/dist/{chunk-LUFZPROB.js → chunk-Q67P7S2I.js} +14 -15
  88. package/dist/chunk-Q67P7S2I.js.map +1 -0
  89. package/dist/{chunk-ES36R3U2.js → chunk-RAYGDC4A.js} +50 -63
  90. package/dist/chunk-RAYGDC4A.js.map +1 -0
  91. package/dist/{chunk-RVTOCAHQ.js → chunk-SQSZRCYT.js} +1 -1
  92. package/dist/chunk-SQSZRCYT.js.map +1 -0
  93. package/dist/{chunk-JN64WH3U.js → chunk-T7IR4N2S.js} +1 -1
  94. package/dist/{chunk-JN64WH3U.js.map → chunk-T7IR4N2S.js.map} +1 -1
  95. package/dist/{chunk-SDEHNGWW.js → chunk-TNOQNU3R.js} +5 -4
  96. package/dist/{chunk-SDEHNGWW.js.map → chunk-TNOQNU3R.js.map} +1 -1
  97. package/dist/{chunk-P5ARVLNW.js → chunk-TXDOMADN.js} +9 -6
  98. package/dist/chunk-TXDOMADN.js.map +1 -0
  99. package/dist/{chunk-6VAM5THN.js → chunk-U6D5XTI5.js} +13 -13
  100. package/dist/{chunk-6VAM5THN.js.map → chunk-U6D5XTI5.js.map} +1 -1
  101. package/dist/{chunk-APUP2J5M.js → chunk-UE72AQDZ.js} +6 -6
  102. package/dist/chunk-UIYZ5SOU.js +190 -0
  103. package/dist/chunk-UIYZ5SOU.js.map +1 -0
  104. package/dist/{chunk-QC2HGYFX.js → chunk-VXVKEWYC.js} +3 -3
  105. package/dist/{chunk-BKYQNNO3.js → chunk-X3AXSYBL.js} +198 -132
  106. package/dist/chunk-X3AXSYBL.js.map +1 -0
  107. package/dist/{chunk-I7JF5TNL.js → chunk-ZDATYUYG.js} +2 -2
  108. package/dist/{chunk-WBHQX6ME.js → chunk-ZSOTZ2RZ.js} +12 -13
  109. package/dist/chunk-ZSOTZ2RZ.js.map +1 -0
  110. package/dist/{chunk-RGPB25DB.js → chunk-ZVAFJQZB.js} +25 -19
  111. package/dist/chunk-ZVAFJQZB.js.map +1 -0
  112. package/dist/classified/index.js +4 -4
  113. package/dist/{classified-marker-W2PUYC3K.js → classified-marker-GWQTNDSL.js} +3 -3
  114. package/dist/{collection-facade-CRXN72DU.js → collection-facade-56RTPO4G.js} +12 -12
  115. package/dist/consent/index.js +4 -4
  116. package/dist/cover/index.js +9 -2
  117. package/dist/custody/index.js +6 -6
  118. package/dist/{dead-filter-MVFQCLXY.js → dead-filter-XP7MPHCJ.js} +2 -2
  119. package/dist/{delegation-I7XXO5LL.js → delegation-Q3HEAVLA.js} +18 -19
  120. package/dist/delegation-Q3HEAVLA.js.map +1 -0
  121. package/dist/derivations/index.js +3 -3
  122. package/dist/{derive-NL7X2EFT.js → derive-SVDY36ER.js} +4 -4
  123. package/dist/directory/index.js +5 -5
  124. package/dist/{dispatch-K3MDLCXG.js → dispatch-MG5KNMWG.js} +5 -5
  125. package/dist/{dispatch-PY5RUHJF.js → dispatch-RVJQ4BOL.js} +11 -11
  126. package/dist/{enclave-77K7UDLS.js → enclave-AOZTWFZK.js} +12 -4
  127. package/dist/{executor-FNGVGDW3.js → executor-FRUVM36Q.js} +12 -12
  128. package/dist/{export-accessible-QWUYY2OY.js → export-accessible-HDDHZYPM.js} +7 -7
  129. package/dist/{extract-partition-CGCURVS4.js → extract-partition-TRADP234.js} +12 -12
  130. package/dist/{fanout-sidecar-JI3MUPQV.js → fanout-sidecar-NZA6J7QB.js} +13 -22
  131. package/dist/fanout-sidecar-NZA6J7QB.js.map +1 -0
  132. package/dist/forget/index.js +4 -4
  133. package/dist/history/index.js +18 -15
  134. package/dist/history/index.js.map +1 -1
  135. package/dist/i18n/index.js +9 -9
  136. package/dist/index.d.ts +16 -0
  137. package/dist/index.js +129 -127
  138. package/dist/index.js.map +1 -1
  139. package/dist/introspection/index.js +5 -5
  140. package/dist/{issue-7IPUNAFA.js → issue-GZQDW5TQ.js} +6 -6
  141. package/dist/kernel/enclave/index.d.ts +6 -5
  142. package/dist/kernel/enclave/record-aad.d.ts +79 -7
  143. package/dist/kernel/enclave/record-envelope.d.ts +54 -7
  144. package/dist/kernel/enclave/record-keys/envelope-body.d.ts +34 -2
  145. package/dist/kernel/enclave/record-keys/lifecycle.d.ts +22 -5
  146. package/dist/kernel/enclave/record-keys/record-codec.d.ts +47 -14
  147. package/dist/kernel/enclave/record-keys/rekey.d.ts +8 -2
  148. package/dist/kernel/enclave/record-keys/tombstone.d.ts +3 -3
  149. package/dist/kernel/merge-authority.d.ts +25 -0
  150. package/dist/kernel/tier-visibility.d.ts +15 -0
  151. package/dist/kernel/types.d.ts +8 -0
  152. package/dist/kernel/vault.d.ts +1 -1
  153. package/dist/kernel/via/index.d.ts +11 -2
  154. package/dist/{ledger-3RDSSMGD.js → ledger-KQAJPEMZ.js} +6 -6
  155. package/dist/liberate-Z2EXJY2S.js +24 -0
  156. package/dist/{link-set-VJIWWUZO.js → link-set-XKN5V7VM.js} +5 -5
  157. package/dist/{managed-secret-XGGJ3BC3.js → managed-secret-7WIIVMJ5.js} +11 -3
  158. package/dist/materialized-views/index.js +14 -14
  159. package/dist/money/index.js +3 -3
  160. package/dist/{noydb-CLQP36JR.js → noydb-NPW3C2EX.js} +39 -38
  161. package/dist/periods/index.js +6 -6
  162. package/dist/pod/index.js +42 -41
  163. package/dist/{pod-handle-7BVSWP5B.js → pod-handle-SKDKRPOR.js} +6 -6
  164. package/dist/{pod-handle-7BVSWP5B.js.map → pod-handle-SKDKRPOR.js.map} +1 -1
  165. package/dist/policy/index.js +10 -3
  166. package/dist/port/with/merge-authority.d.ts +52 -0
  167. package/dist/port/with/strategies.d.ts +2 -0
  168. package/dist/portability/index.js +6 -6
  169. package/dist/{post-register-W3T4U57K.js → post-register-CVS7CCJE.js} +4 -4
  170. package/dist/reduce/index.js +3 -3
  171. package/dist/{register-YUVC4G27.js → register-GJ6PW4KP.js} +10 -10
  172. package/dist/{registry-BPKJX562.js → registry-6LUJ5IJW.js} +4 -4
  173. package/dist/{registry-HRFRBFDV.js → registry-KI77RVK7.js} +4 -4
  174. package/dist/{request-withdrawal-CXTQLMJK.js → request-withdrawal-LICOUGXG.js} +9 -9
  175. package/dist/{reveal-G7W7N3AZ.js → reveal-PWM47FQN.js} +3 -3
  176. package/dist/{revoke-ZX3TZUI6.js → revoke-AWZKZLZB.js} +6 -6
  177. package/dist/sealed-record/index.js +14 -7
  178. package/dist/sealed-record/index.js.map +1 -1
  179. package/dist/search/index.js +3 -3
  180. package/dist/{seed-2FUULTQV.js → seed-LNTLU2A3.js} +14 -17
  181. package/dist/seed-LNTLU2A3.js.map +1 -0
  182. package/dist/sequence/index.js +4 -4
  183. package/dist/session/index.js +3 -3
  184. package/dist/{signer-FPUIX63Z.js → signer-JE6NEURY.js} +5 -5
  185. package/dist/snapshots/index.js +5 -5
  186. package/dist/{stale-42FPALK2.js → stale-ZWTKUVZX.js} +5 -5
  187. package/dist/{storage-6QODT6K5.js → storage-WCZOCA46.js} +5 -5
  188. package/dist/{store-coordination-provider-Y3VXBHPL.js → store-coordination-provider-7H62VO2C.js} +18 -12
  189. package/dist/store-coordination-provider-7H62VO2C.js.map +1 -0
  190. package/dist/sync/index.js +5 -5
  191. package/dist/team/index.js +10 -9
  192. package/dist/tiers/index.js +6 -5
  193. package/dist/vault-head/index.js +111 -0
  194. package/dist/vault-head/index.js.map +1 -0
  195. package/dist/{walk-5PGJI3ND.js → walk-HSS3NLQ3.js} +6 -6
  196. package/dist/with-audit/periods/periods.d.ts +1 -1
  197. package/dist/with-audit/periods/strategy.d.ts +1 -1
  198. package/dist/with-audit/sealed-record/index.d.ts +13 -0
  199. package/dist/with-audit/tiers/index.d.ts +17 -2
  200. package/dist/with-commit/history/history.d.ts +26 -0
  201. package/dist/with-commit/history/index.d.ts +2 -1
  202. package/dist/with-commit/history/ledger/store.d.ts +7 -1
  203. package/dist/with-commit/history/strategy.d.ts +11 -1
  204. package/dist/with-commit/vault-head/active.d.ts +2 -0
  205. package/dist/with-commit/vault-head/head.d.ts +28 -0
  206. package/dist/with-commit/vault-head/index.d.ts +10 -0
  207. package/dist/with-commit/vault-head/strategy.d.ts +127 -0
  208. package/dist/with-commit/vault-head/verify.d.ts +50 -0
  209. package/dist/with-party/directory/cover/storage.d.ts +0 -8
  210. package/dist/with-party/directory/storage.d.ts +0 -11
  211. package/dist/with-party/directory/visibility.d.ts +0 -21
  212. package/dist/with-party/policy/storage.d.ts +0 -10
  213. package/dist/with-party/team/tiers.d.ts +2 -1
  214. package/dist/with-sync/engine.d.ts +33 -5
  215. package/dist/with-sync/strategy.d.ts +3 -0
  216. package/dist/{withdraw-accessible-PFCQQGNP.js → withdraw-accessible-GHBA4DAA.js} +8 -8
  217. package/package.json +7 -3
  218. package/dist/chunk-2RGQNFJB.js.map +0 -1
  219. package/dist/chunk-4GR422R5.js.map +0 -1
  220. package/dist/chunk-5UGEGEIJ.js.map +0 -1
  221. package/dist/chunk-6JRIYG2C.js.map +0 -1
  222. package/dist/chunk-7TZTQS4H.js.map +0 -1
  223. package/dist/chunk-AFHQATY4.js +0 -47
  224. package/dist/chunk-AFHQATY4.js.map +0 -1
  225. package/dist/chunk-AKFNLRA2.js.map +0 -1
  226. package/dist/chunk-BKYQNNO3.js.map +0 -1
  227. package/dist/chunk-BMDF4TLU.js.map +0 -1
  228. package/dist/chunk-C3YP5KKS.js.map +0 -1
  229. package/dist/chunk-C52CJDFO.js.map +0 -1
  230. package/dist/chunk-EEBMKMA7.js.map +0 -1
  231. package/dist/chunk-EMFFWSAD.js.map +0 -1
  232. package/dist/chunk-ES36R3U2.js.map +0 -1
  233. package/dist/chunk-IEA3TZJE.js.map +0 -1
  234. package/dist/chunk-JAHIL6WO.js.map +0 -1
  235. package/dist/chunk-JV2CNEX2.js.map +0 -1
  236. package/dist/chunk-LUFZPROB.js.map +0 -1
  237. package/dist/chunk-OAWVM5L6.js.map +0 -1
  238. package/dist/chunk-OXRPH6AR.js.map +0 -1
  239. package/dist/chunk-P5ARVLNW.js.map +0 -1
  240. package/dist/chunk-QJBXB4WU.js.map +0 -1
  241. package/dist/chunk-QKRJUPAC.js.map +0 -1
  242. package/dist/chunk-RGPB25DB.js.map +0 -1
  243. package/dist/chunk-RVTOCAHQ.js.map +0 -1
  244. package/dist/chunk-SJOK23XT.js.map +0 -1
  245. package/dist/chunk-UNR6G3EJ.js.map +0 -1
  246. package/dist/chunk-URVL4EKU.js.map +0 -1
  247. package/dist/chunk-V3OLO4TK.js.map +0 -1
  248. package/dist/chunk-VEA35MQP.js.map +0 -1
  249. package/dist/chunk-VUQZYVYX.js.map +0 -1
  250. package/dist/chunk-WBHQX6ME.js.map +0 -1
  251. package/dist/chunk-YVOW35HH.js.map +0 -1
  252. package/dist/chunk-Z2OFE6IX.js.map +0 -1
  253. package/dist/delegation-I7XXO5LL.js.map +0 -1
  254. package/dist/fanout-sidecar-JI3MUPQV.js.map +0 -1
  255. package/dist/liberate-2DNJ7AJ7.js +0 -24
  256. package/dist/seed-2FUULTQV.js.map +0 -1
  257. package/dist/store-coordination-provider-Y3VXBHPL.js.map +0 -1
  258. /package/dist/{api-AEIN3KAQ.js.map → api-FRFEJ6WR.js.map} +0 -0
  259. /package/dist/{chunk-466KGOQB.js.map → chunk-2NE7ILO7.js.map} +0 -0
  260. /package/dist/{chunk-GWI65NDQ.js.map → chunk-3KXIGMZ4.js.map} +0 -0
  261. /package/dist/{chunk-X2FXEEQT.js.map → chunk-3RZ7QLJ4.js.map} +0 -0
  262. /package/dist/{chunk-FZ2SSI5R.js.map → chunk-6AL6O4CS.js.map} +0 -0
  263. /package/dist/{chunk-67XA44HH.js.map → chunk-6D3CN2JR.js.map} +0 -0
  264. /package/dist/{chunk-5VVBZ6E4.js.map → chunk-6QCXMCLZ.js.map} +0 -0
  265. /package/dist/{chunk-UKKBKEUI.js.map → chunk-AA7LM2A3.js.map} +0 -0
  266. /package/dist/{chunk-NWPR2V5W.js.map → chunk-BBU3OD3D.js.map} +0 -0
  267. /package/dist/{chunk-JHYISAID.js.map → chunk-DFFSCYIW.js.map} +0 -0
  268. /package/dist/{chunk-XTC5EKST.js.map → chunk-ER3BQCCE.js.map} +0 -0
  269. /package/dist/{chunk-JU3JKOY5.js.map → chunk-EWAGI3EM.js.map} +0 -0
  270. /package/dist/{chunk-N4GAJSRQ.js.map → chunk-FY33DKPH.js.map} +0 -0
  271. /package/dist/{chunk-7LLKPODL.js.map → chunk-LPAGIMXJ.js.map} +0 -0
  272. /package/dist/{chunk-3JQVA527.js.map → chunk-LU6NPJWN.js.map} +0 -0
  273. /package/dist/{chunk-DEP24EE3.js.map → chunk-NFPSC2HL.js.map} +0 -0
  274. /package/dist/{chunk-VQQUOEON.js.map → chunk-OCCNYGKG.js.map} +0 -0
  275. /package/dist/{chunk-IRHOQFA7.js.map → chunk-PBPYQZDW.js.map} +0 -0
  276. /package/dist/{chunk-APUP2J5M.js.map → chunk-UE72AQDZ.js.map} +0 -0
  277. /package/dist/{chunk-QC2HGYFX.js.map → chunk-VXVKEWYC.js.map} +0 -0
  278. /package/dist/{chunk-I7JF5TNL.js.map → chunk-ZDATYUYG.js.map} +0 -0
  279. /package/dist/{classified-marker-W2PUYC3K.js.map → classified-marker-GWQTNDSL.js.map} +0 -0
  280. /package/dist/{collection-facade-CRXN72DU.js.map → collection-facade-56RTPO4G.js.map} +0 -0
  281. /package/dist/{dead-filter-MVFQCLXY.js.map → dead-filter-XP7MPHCJ.js.map} +0 -0
  282. /package/dist/{derive-NL7X2EFT.js.map → derive-SVDY36ER.js.map} +0 -0
  283. /package/dist/{dispatch-K3MDLCXG.js.map → dispatch-MG5KNMWG.js.map} +0 -0
  284. /package/dist/{dispatch-PY5RUHJF.js.map → dispatch-RVJQ4BOL.js.map} +0 -0
  285. /package/dist/{enclave-77K7UDLS.js.map → enclave-AOZTWFZK.js.map} +0 -0
  286. /package/dist/{executor-FNGVGDW3.js.map → executor-FRUVM36Q.js.map} +0 -0
  287. /package/dist/{export-accessible-QWUYY2OY.js.map → export-accessible-HDDHZYPM.js.map} +0 -0
  288. /package/dist/{extract-partition-CGCURVS4.js.map → extract-partition-TRADP234.js.map} +0 -0
  289. /package/dist/{issue-7IPUNAFA.js.map → issue-GZQDW5TQ.js.map} +0 -0
  290. /package/dist/{ledger-3RDSSMGD.js.map → ledger-KQAJPEMZ.js.map} +0 -0
  291. /package/dist/{liberate-2DNJ7AJ7.js.map → liberate-Z2EXJY2S.js.map} +0 -0
  292. /package/dist/{link-set-VJIWWUZO.js.map → link-set-XKN5V7VM.js.map} +0 -0
  293. /package/dist/{managed-secret-XGGJ3BC3.js.map → managed-secret-7WIIVMJ5.js.map} +0 -0
  294. /package/dist/{noydb-CLQP36JR.js.map → noydb-NPW3C2EX.js.map} +0 -0
  295. /package/dist/{post-register-W3T4U57K.js.map → post-register-CVS7CCJE.js.map} +0 -0
  296. /package/dist/{register-YUVC4G27.js.map → register-GJ6PW4KP.js.map} +0 -0
  297. /package/dist/{registry-BPKJX562.js.map → registry-6LUJ5IJW.js.map} +0 -0
  298. /package/dist/{registry-HRFRBFDV.js.map → registry-KI77RVK7.js.map} +0 -0
  299. /package/dist/{request-withdrawal-CXTQLMJK.js.map → request-withdrawal-LICOUGXG.js.map} +0 -0
  300. /package/dist/{reveal-G7W7N3AZ.js.map → reveal-PWM47FQN.js.map} +0 -0
  301. /package/dist/{revoke-ZX3TZUI6.js.map → revoke-AWZKZLZB.js.map} +0 -0
  302. /package/dist/{signer-FPUIX63Z.js.map → signer-JE6NEURY.js.map} +0 -0
  303. /package/dist/{stale-42FPALK2.js.map → stale-ZWTKUVZX.js.map} +0 -0
  304. /package/dist/{storage-6QODT6K5.js.map → storage-WCZOCA46.js.map} +0 -0
  305. /package/dist/{walk-5PGJI3ND.js.map → walk-HSS3NLQ3.js.map} +0 -0
  306. /package/dist/{withdraw-accessible-PFCQQGNP.js.map → withdraw-accessible-GHBA4DAA.js.map} +0 -0
@@ -1,20 +1,20 @@
1
1
  import {
2
2
  UserApi,
3
3
  createUserApi
4
- } from "./chunk-67XA44HH.js";
5
- import "./chunk-QJBXB4WU.js";
6
- import "./chunk-BKYQNNO3.js";
7
- import "./chunk-RGPB25DB.js";
4
+ } from "./chunk-6D3CN2JR.js";
5
+ import "./chunk-ITXPKEDP.js";
6
+ import "./chunk-X3AXSYBL.js";
7
+ import "./chunk-ZVAFJQZB.js";
8
8
  import "./chunk-FSZPQCDR.js";
9
9
  import "./chunk-HVR74IBG.js";
10
10
  import "./chunk-RBTZLXZJ.js";
11
11
  import "./chunk-LP7BEXCT.js";
12
12
  import "./chunk-QTDAPDDV.js";
13
- import "./chunk-5UGEGEIJ.js";
13
+ import "./chunk-3Y4OFWQJ.js";
14
14
  import "./chunk-I64WQSN3.js";
15
15
  import "./chunk-PZ5AY32C.js";
16
16
  export {
17
17
  UserApi,
18
18
  createUserApi
19
19
  };
20
- //# sourceMappingURL=api-AEIN3KAQ.js.map
20
+ //# sourceMappingURL=api-FRFEJ6WR.js.map
@@ -1,27 +1,27 @@
1
1
  import {
2
2
  issueAttestationCore
3
- } from "../chunk-4GR422R5.js";
3
+ } from "../chunk-7EH322GJ.js";
4
4
  import {
5
5
  getRevokedDocIdsCore,
6
6
  publishRevocationListCore,
7
7
  revokeDocCore,
8
8
  unrevokeDocCore
9
- } from "../chunk-LUFZPROB.js";
9
+ } from "../chunk-Q67P7S2I.js";
10
10
  import {
11
11
  ATTESTATIONS_COLLECTION
12
- } from "../chunk-C3YP5KKS.js";
12
+ } from "../chunk-3ODOWQMV.js";
13
13
  import {
14
14
  NO_ATTESTATION
15
15
  } from "../chunk-TQLYMYOK.js";
16
16
  import "../chunk-4AOERLTV.js";
17
- import "../chunk-BKYQNNO3.js";
18
- import "../chunk-RGPB25DB.js";
17
+ import "../chunk-X3AXSYBL.js";
18
+ import "../chunk-ZVAFJQZB.js";
19
19
  import "../chunk-FSZPQCDR.js";
20
20
  import "../chunk-HVR74IBG.js";
21
21
  import "../chunk-RBTZLXZJ.js";
22
22
  import "../chunk-LP7BEXCT.js";
23
23
  import "../chunk-QTDAPDDV.js";
24
- import "../chunk-5UGEGEIJ.js";
24
+ import "../chunk-3Y4OFWQJ.js";
25
25
  import {
26
26
  AttestationError,
27
27
  AttestationNotEnabledError
@@ -32,11 +32,11 @@ import "../chunk-PZ5AY32C.js";
32
32
  function withAttestation() {
33
33
  return {
34
34
  async issueAttestation(ctx, args) {
35
- const { issueAttestationCore: issueAttestationCore2 } = await import("../issue-7IPUNAFA.js");
35
+ const { issueAttestationCore: issueAttestationCore2 } = await import("../issue-GZQDW5TQ.js");
36
36
  return issueAttestationCore2(ctx, args);
37
37
  },
38
38
  async getDocumentSigningPublicKey(deps) {
39
- const { loadSigner, loadOrCreateSigner } = await import("../signer-FPUIX63Z.js");
39
+ const { loadSigner, loadOrCreateSigner } = await import("../signer-JE6NEURY.js");
40
40
  const existing = await loadSigner(deps.adapter, deps.vault, deps.getDEK);
41
41
  if (existing) return { keyId: existing.keyId, publicKeyB64: existing.publicKeyB64 };
42
42
  if (deps.role !== "owner") {
@@ -46,19 +46,19 @@ function withAttestation() {
46
46
  return { keyId: signer.keyId, publicKeyB64: signer.publicKeyB64 };
47
47
  },
48
48
  async revokeAttestation(ctx, docId) {
49
- const { revokeDocCore: revokeDocCore2 } = await import("../revoke-ZX3TZUI6.js");
49
+ const { revokeDocCore: revokeDocCore2 } = await import("../revoke-AWZKZLZB.js");
50
50
  return revokeDocCore2(ctx, docId);
51
51
  },
52
52
  async unrevokeAttestation(ctx, docId) {
53
- const { unrevokeDocCore: unrevokeDocCore2 } = await import("../revoke-ZX3TZUI6.js");
53
+ const { unrevokeDocCore: unrevokeDocCore2 } = await import("../revoke-AWZKZLZB.js");
54
54
  return unrevokeDocCore2(ctx, docId);
55
55
  },
56
56
  async getRevokedDocIds(ctx) {
57
- const { getRevokedDocIdsCore: getRevokedDocIdsCore2 } = await import("../revoke-ZX3TZUI6.js");
57
+ const { getRevokedDocIdsCore: getRevokedDocIdsCore2 } = await import("../revoke-AWZKZLZB.js");
58
58
  return getRevokedDocIdsCore2(ctx);
59
59
  },
60
60
  async publishRevocationList(ctx) {
61
- const { publishRevocationListCore: publishRevocationListCore2 } = await import("../revoke-ZX3TZUI6.js");
61
+ const { publishRevocationListCore: publishRevocationListCore2 } = await import("../revoke-AWZKZLZB.js");
62
62
  return publishRevocationListCore2(ctx);
63
63
  }
64
64
  };
@@ -3,7 +3,10 @@ import {
3
3
  } from "./chunk-EPFF7LOX.js";
4
4
  import {
5
5
  SCHEMAS_COLLECTION
6
- } from "./chunk-6JRIYG2C.js";
6
+ } from "./chunk-IN5EZWYQ.js";
7
+ import {
8
+ SEQUENCE_COLLECTION
9
+ } from "./chunk-AA2WWTS3.js";
7
10
  import {
8
11
  PERIODS_COLLECTION,
9
12
  PERIOD_ARCHIVES_COLLECTION,
@@ -11,17 +14,14 @@ import {
11
14
  PERIOD_REOPENS_COLLECTION,
12
15
  PERIOD_TARGET_PURGES_COLLECTION
13
16
  } from "./chunk-V4M4BZNW.js";
14
- import {
15
- SEQUENCE_COLLECTION
16
- } from "./chunk-2RGQNFJB.js";
17
17
  import {
18
18
  LEDGER_COLLECTION,
19
19
  LEDGER_DELTAS_COLLECTION
20
20
  } from "./chunk-I7FD46FF.js";
21
- import "./chunk-BKYQNNO3.js";
21
+ import "./chunk-X3AXSYBL.js";
22
22
  import {
23
23
  buildRecordEnvelope
24
- } from "./chunk-RGPB25DB.js";
24
+ } from "./chunk-ZVAFJQZB.js";
25
25
  import "./chunk-FSZPQCDR.js";
26
26
  import "./chunk-HVR74IBG.js";
27
27
  import "./chunk-RBTZLXZJ.js";
@@ -29,7 +29,7 @@ import "./chunk-LP7BEXCT.js";
29
29
  import "./chunk-QTDAPDDV.js";
30
30
  import {
31
31
  NOYDB_BACKUP_VERSION
32
- } from "./chunk-5UGEGEIJ.js";
32
+ } from "./chunk-3Y4OFWQJ.js";
33
33
  import {
34
34
  BackupCorruptedError,
35
35
  BackupLedgerError
@@ -126,8 +126,8 @@ async function loadVault(ctx, backupJson) {
126
126
  await ctx.adapter.saveAll(ctx.vault, backup.collections);
127
127
  for (const [userId, keyringFile] of Object.entries(backup.keyrings)) {
128
128
  const envelope = buildRecordEnvelope(
129
- { collection: "_keyring", id: userId },
130
- { version: 1, iv: "", data: JSON.stringify(keyringFile) }
129
+ { collection: "_keyring", id: userId, version: 1 },
130
+ { iv: "", data: JSON.stringify(keyringFile) }
131
131
  );
132
132
  await ctx.adapter.put(ctx.vault, "_keyring", userId, envelope);
133
133
  }
@@ -262,4 +262,4 @@ export {
262
262
  loadVault,
263
263
  verifyBackupIntegrity
264
264
  };
265
- //# sourceMappingURL=backup-7X3PFTSI.js.map
265
+ //# sourceMappingURL=backup-OLBRFYY7.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/with-pod/backup.ts"],"sourcesContent":["/**\n * Vault backup / restore / integrity.\n *\n * Holds `dump()` (verifiable encrypted JSON backup, including the blob\n * collections so blob \"covers\" travel in the bundle), `load()` (restore +\n * post-load integrity gate), `verifyBackupIntegrity()` (chain + data-envelope\n * cross-check), and `exportJSON()` (plaintext per-collection export, built on\n * the vault's `exportStream`). Behaviour is byte-identical to the inline\n * `Vault` methods these functions replaced — every dependency the moving code\n * touched on `this.*` arrives via {@link BackupContext}. `Vault` keeps the\n * public methods as thin delegators.\n *\n * Internal — reached through `vault.dump()` / `vault.load()` / etc.\n */\nimport { NOYDB_BACKUP_VERSION } from '../kernel/types.js'\nimport { BackupLedgerError, BackupCorruptedError } from '../kernel/errors.js'\nimport { LEDGER_COLLECTION, LEDGER_DELTAS_COLLECTION } from '../with-commit/history/ledger/constants.js'\nimport { SCHEMAS_COLLECTION } from '../with-shape/persisted-schemas/storage.js'\nimport { SEQUENCE_COLLECTION } from '../with-commit/sequence/index.js'\nimport { MANIFEST_COLLECTION } from '../with-shape/manifest/reserved-collections.js'\n// #1025 — imported from the dependency-light `window.ts`, not `periods.ts`: that\n// module exists precisely so a consumer can name the period collections without\n// dragging the ledger hash-chain machinery (`sha256Hex`/`canonicalJson`) into a\n// bundle that opted out of the periods service. Same reason the sync engine's\n// period-scoped pull imports it.\nimport {\n PERIODS_COLLECTION,\n PERIOD_FREEZES_COLLECTION,\n PERIOD_ARCHIVES_COLLECTION,\n PERIOD_TARGET_PURGES_COLLECTION,\n PERIOD_REOPENS_COLLECTION,\n} from '../with-audit/periods/window.js'\nimport type {\n NoydbStore,\n EncryptedEnvelope,\n VaultBackup,\n VaultSnapshot,\n ExportStreamOptions,\n ExportChunk,\n} from '../kernel/types.js'\nimport type { LedgerStore } from '../with-commit/history/ledger/store.js'\nimport { buildRecordEnvelope } from '../kernel/enclave/index.js'\n\n/** Everything the moving backup methods touched on the vault's `this.*`. */\nexport interface BackupContext {\n /** The ciphertext store. */\n readonly adapter: NoydbStore\n /** Vault namespace name. */\n readonly vault: string\n /** The invoking keyring's user id (read fresh per call). */\n userId(): string\n /** The vault's ledger store, or null when history is off. */\n getLedgerOrNull(): LedgerStore | null\n /** Recompute an envelope's `payloadHash` (bound `historyStrategy.envelopePayloadHash`). */\n envelopePayloadHash(envelope: EncryptedEnvelope): Promise<string>\n /**\n * Refresh the in-memory keyring from the freshly-loaded keyring file and\n * rebuild the DEK resolver. No-op when the vault has no `reloadKeyring`\n * callback (plaintext vaults / test constructions).\n */\n reloadKeyringAndRebuildDEK(): Promise<void>\n /** Clear the vault's collection cache (post-load). */\n clearCollectionCache(): void\n /** Reset the ledger store so the next `ledger()` rebuilds its head cache. */\n resetLedgerStore(): void\n /** The vault's decrypt+ACL export stream (used by `exportJSON`). */\n exportStream(opts: ExportStreamOptions): AsyncIterableIterator<ExportChunk>\n}\n\n/** Result of {@link verifyBackupIntegrity}. */\nexport type VerifyBackupResult =\n | { readonly ok: true; readonly head: string; readonly length: number }\n | {\n readonly ok: false\n readonly kind: 'chain'\n readonly divergedAt: number\n readonly message: string\n }\n | {\n readonly ok: false\n readonly kind: 'data'\n readonly collection: string\n readonly id: string\n readonly message: string\n }\n\n/**\n * Dump vault as a verifiable encrypted JSON backup string.\n *\n * backups embed the current ledger head and the full `_ledger` +\n * `_ledger_deltas` internal collections so the receiver can run\n * `verifyBackupIntegrity()` after `load()` and detect any tampering between\n * dump and restore. Backups produced without a ledger skip the integrity check\n * with a warning — both modes round-trip cleanly.\n */\nexport async function dumpVault(ctx: BackupContext): Promise<string> {\n const snapshot = await ctx.adapter.loadAll(ctx.vault)\n\n // Load keyrings (separate path because loadAll filters them out\n // along with all other underscore-prefixed internal collections).\n const keyringIds = await ctx.adapter.list(ctx.vault, '_keyring')\n const keyrings: Record<string, unknown> = {}\n for (const keyringId of keyringIds) {\n const envelope = await ctx.adapter.get(ctx.vault, '_keyring', keyringId)\n if (envelope) {\n keyrings[keyringId] = JSON.parse(envelope._data)\n }\n }\n\n // Load the ledger entries + deltas so the receiver can replay\n // the chain after restore. Without this, `load()` would have an\n // empty ledger and `verifyBackupIntegrity()` would have nothing\n // to compare against.\n //\n // Also enumerate the blob collections so blob content (\"covers\")\n // travels in the bundle (the blob DEK already travels in `_keyring`).\n // Literals are inlined (not imported from blobs/blob-set.ts) to keep\n // the blob runtime out of this kernel hot path — they mirror\n // BLOB_INDEX/CHUNKS/EVICTION_AUDIT_COLLECTION and SLOTS/VERSIONS_PREFIX.\n // The collect-loop skips empty ids, so this no-ops without blobs.\n const internalSnapshot: VaultSnapshot = {}\n const internalNames = [\n LEDGER_COLLECTION, LEDGER_DELTAS_COLLECTION, SCHEMAS_COLLECTION, SEQUENCE_COLLECTION,\n MANIFEST_COLLECTION, // #941: the pod's manifest-set record(s) travel in the bundle too\n // #1025: the accounting-period close state + its companions. The bundle is\n // the backup/restore path, so without these a restore discarded the\n // hash-chained evidence that a month was ever closed — the artifact\n // `closePeriod` exists to produce — and dropped the write gate with it, so\n // the restored vault silently accepted back-dated writes into a sealed\n // month. The companions matter as much as the close: a bounded reopen\n // window (`reopenPeriod({ until })`) is state a restore must not lose.\n PERIODS_COLLECTION,\n PERIOD_REOPENS_COLLECTION,\n PERIOD_FREEZES_COLLECTION,\n PERIOD_ARCHIVES_COLLECTION,\n PERIOD_TARGET_PURGES_COLLECTION,\n '_history', // full-snapshot version history — so history()/getVersion()/diff() survive the bundle\n '_blob_index', '_blob_chunks', '_blob_eviction_audit',\n // #753 spec §7 Q3: `_blob_intent` markers travel too — restoring mid-op\n // state (a blob row without its marker) would reproduce the ambiguity\n // the journal exists to prevent. Note: `_mv_stale` does NOT travel\n // today (a pre-existing, separate gap) — observed here, tracked on\n // #761, not fixed in this pass.\n '_blob_intent',\n // #769: `_blob_slots_<c>` envelopes travel verbatim (raw ciphertext,\n // same DEK, same vault) — including any `SlotRecord.pendingRelease`\n // resume breadcrumb they carry. This is INTENTIONALLY the opposite of\n // `extract-partition`'s `reKeyBlobs`, which STRIPS `pendingRelease`:\n // a full-vault backup restores into the SAME vault it was taken from,\n // so a breadcrumb taken mid-rehome (together with its `_blob_intent`\n // marker, carried above) is resumable on restore — carry-and-resume is\n // correct here. A partition extraction crosses vaults: the breadcrumb's\n // old eTag may not exist in the destination, so it must be stripped\n // there instead. Asymmetry: backup = same-vault-resumable = carry;\n // partition = cross-vault = strip-breadcrumb-carry-marker.\n ...Object.keys(snapshot).flatMap((c) => [`_blob_slots_${c}`, `_blob_versions_${c}`]),\n ]\n for (const internalName of internalNames) {\n const ids = await ctx.adapter.list(ctx.vault, internalName)\n if (ids.length === 0) continue\n const records: Record<string, EncryptedEnvelope> = {}\n for (const id of ids) {\n const envelope = await ctx.adapter.get(ctx.vault, internalName, id)\n if (envelope) records[id] = envelope\n }\n internalSnapshot[internalName] = records\n }\n\n // Embed the ledger head if there's a chain. An empty ledger\n // (fresh vault) leaves `ledgerHead` undefined, which\n // load() treats the same as a legacy backup (no integrity\n // check, console warning). If history is not opted in,\n // `getLedgerOrNull` returns null and we skip embedding entirely\n // — the backup is still valid, just without the integrity head.\n const ledgerForHead = ctx.getLedgerOrNull()\n const head = ledgerForHead ? await ledgerForHead.head() : null\n const backup: VaultBackup = {\n _noydb_backup: NOYDB_BACKUP_VERSION,\n _compartment: ctx.vault,\n _exported_at: new Date().toISOString(),\n _exported_by: ctx.userId(),\n keyrings: keyrings as VaultBackup['keyrings'],\n collections: snapshot,\n ...(Object.keys(internalSnapshot).length > 0\n ? { _internal: internalSnapshot }\n : {}),\n ...(head\n ? {\n ledgerHead: {\n hash: head.hash,\n index: head.entry.index,\n ts: head.entry.ts,\n },\n }\n : {}),\n }\n\n return JSON.stringify(backup)\n}\n\n/**\n * Restore a vault from a verifiable backup. After loading, runs\n * `verifyBackupIntegrity()` to confirm the hash chain, the embedded head, and\n * every data envelope's payload hash. Legacy backups (no `ledgerHead`) load\n * with a console warning and skip the integrity check.\n */\nexport async function loadVault(ctx: BackupContext, backupJson: string): Promise<void> {\n const backup = JSON.parse(backupJson) as VaultBackup\n\n // 1. Restore data collections.\n await ctx.adapter.saveAll(ctx.vault, backup.collections)\n\n // 2. Restore keyrings.\n for (const [userId, keyringFile] of Object.entries(backup.keyrings)) {\n const envelope = buildRecordEnvelope({ collection: '_keyring', id: userId },\n { version: 1, iv: '', data: JSON.stringify(keyringFile) })\n await ctx.adapter.put(ctx.vault, '_keyring', userId, envelope)\n }\n\n // 3. Restore internal collections (`_ledger`, `_ledger_deltas`).\n // Required so verifyBackupIntegrity has the chain to walk.\n if (backup._internal) {\n for (const [internalName, records] of Object.entries(backup._internal)) {\n for (const [id, envelope] of Object.entries(records)) {\n await ctx.adapter.put(ctx.vault, internalName, id, envelope)\n }\n }\n }\n\n // 4. Refresh the in-memory keyring from the freshly-loaded\n // keyring file. Without this, the Vault's getDEK\n // closure still holds the OLD session's DEKs, and every\n // decrypt of a loaded ledger entry / data envelope fails\n // with TamperedError because the DEK doesn't match the\n // ciphertext that was encrypted with the SOURCE user's DEK.\n // Skipped for plaintext vaults and for tests that\n // construct Vault without a reloadKeyring callback.\n await ctx.reloadKeyringAndRebuildDEK()\n\n // 5. Clear collection cache + reset the ledger store so the\n // next ledger() call rebuilds its head cache from the\n // freshly-loaded entries.\n ctx.clearCollectionCache()\n ctx.resetLedgerStore()\n\n // 5. Run the verification gate. Legacy backups (no ledgerHead)\n // skip this with a one-line warning so existing consumers can\n // still read them while migrating.\n if (!backup.ledgerHead) {\n console.warn(\n `[noy-db] Loaded a legacy backup with no ledgerHead — ` +\n `verifiable-backup integrity check skipped. ` +\n `Re-export with a ledger-aware build to get tamper detection.`,\n )\n return\n }\n\n const result = await verifyBackupIntegrity(ctx)\n if (!result.ok) {\n // Surface the most specific error class we can. The result\n // shape carries enough info for callers to inspect.\n if (result.kind === 'data') {\n throw new BackupCorruptedError(\n result.collection,\n result.id,\n result.message,\n )\n }\n throw new BackupLedgerError(result.message, result.divergedAt)\n }\n\n // 6. Cross-check: the freshly-verified head must match the\n // value embedded at dump time. A mismatch means someone\n // truncated or extended the chain after dump.\n if (result.head !== backup.ledgerHead.hash) {\n throw new BackupLedgerError(\n `Backup ledger head mismatch: embedded \"${backup.ledgerHead.hash}\" ` +\n `but reconstructed \"${result.head}\".`,\n )\n }\n}\n\n/**\n * End-to-end backup integrity check: `ledger.verify()` (hash chain) plus a data\n * envelope cross-check (every current record's `_data` hash must match the\n * latest `put` entry's `payloadHash`). Returns a discriminated union so callers\n * can distinguish chain vs data failures.\n */\nexport async function verifyBackupIntegrity(ctx: BackupContext): Promise<VerifyBackupResult> {\n // Step 1: chain verification. Without the history strategy there\n // is no ledger; an unaudited backup verifies trivially as `ok`\n // because there's nothing to diverge from.\n const ledgerForVerify = ctx.getLedgerOrNull()\n if (!ledgerForVerify) {\n return { ok: true, head: '', length: 0 }\n }\n const chainResult = await ledgerForVerify.verify()\n if (!chainResult.ok) {\n return {\n ok: false,\n kind: 'chain',\n divergedAt: chainResult.divergedAt,\n message:\n `Ledger chain diverged at index ${chainResult.divergedAt}: ` +\n `expected prevHash \"${chainResult.expected}\" but found \"${chainResult.actual}\".`,\n }\n }\n\n // Step 2: data envelope cross-check. Walk every entry in the\n // ledger and, for the LATEST `put` per (collection, id), recompute\n // the data envelope's payloadHash and compare. Earlier puts of the\n // same id are skipped because the data collection only holds the\n // current version — historical envelopes live in the deltas\n // collection (which is itself protected by the chain).\n // Reuse the ledger we already resolved in step 1.\n const allEntries = await ledgerForVerify.loadAllEntries()\n\n // Find the latest non-delete entry per (collection, id). Walk\n // the entries in reverse so we hit the latest first; mark each\n // (collection, id) as seen and skip subsequent entries.\n const seen = new Set<string>()\n const latest = new Map<\n string,\n { collection: string; id: string; expectedHash: string }\n >()\n for (let i = allEntries.length - 1; i >= 0; i--) {\n const entry = allEntries[i]\n if (!entry) continue\n // Amendment entries are multi-record audit entries whose\n // `collection` and `id` are empty strings — building a `\"/\"`\n // key here would mark that synthetic slot as seen and falsely\n // trip the data check on a record that never existed. Skip\n // them BEFORE the key/seen bookkeeping so they neither\n // tombstone real entries nor enter the latest map.\n if (entry.op === 'amendment' || entry.op === 'lifecycle') continue\n const key = `${entry.collection}/${entry.id}`\n if (seen.has(key)) continue\n seen.add(key)\n // For deletes the data collection should NOT have the record,\n // so we skip — there's nothing to cross-check. Marking the key\n // as seen above ensures any earlier `put` of the same id is\n // also skipped (the record was subsequently deleted).\n if (entry.op === 'delete') continue\n latest.set(key, {\n collection: entry.collection,\n id: entry.id,\n expectedHash: entry.payloadHash,\n })\n }\n\n for (const { collection, id, expectedHash } of latest.values()) {\n const envelope = await ctx.adapter.get(ctx.vault, collection, id)\n if (!envelope) {\n return {\n ok: false,\n kind: 'data',\n collection,\n id,\n message:\n `Ledger expects data record \"${collection}/${id}\" to exist, ` +\n `but the adapter has no envelope for it.`,\n }\n }\n const actualHash = await ctx.envelopePayloadHash(envelope)\n if (actualHash !== expectedHash) {\n return {\n ok: false,\n kind: 'data',\n collection,\n id,\n message:\n `Data envelope \"${collection}/${id}\" has been tampered with: ` +\n `expected payloadHash \"${expectedHash}\", got \"${actualHash}\".`,\n }\n }\n }\n\n return {\n ok: true,\n head: chainResult.head,\n length: chainResult.length,\n }\n}\n\n/**\n * Plaintext per-collection export, built on the vault's `exportStream`. Forces\n * collection granularity (record-by-record output makes no sense in a single\n * string) and merges dictionary snapshots across collections.\n */\nexport async function exportVaultJSON(ctx: BackupContext, opts: ExportStreamOptions = {}): Promise<string> {\n // Force per-collection granularity regardless of caller setting:\n // record-by-record output doesn't make sense in a single string.\n const collections: Record<\n string,\n {\n schema: null\n refs: Record<string, { target: string; mode: 'strict' | 'warn' | 'cascade' }>\n records: unknown[]\n }\n > = {}\n let ledgerHead: ExportChunk['ledgerHead'] | undefined\n // Merged dictionary snapshot across all collections.\n // Only populated when `resolveLabels` is not set.\n const allDictionaries: Record<\n string, // collection name\n Record<string, Record<string, Record<string, string>>>\n > = {}\n\n for await (const chunk of ctx.exportStream({\n granularity: 'collection',\n withLedgerHead: opts.withLedgerHead === true,\n // Thread the export locale so records are read at the\n // `export` layer (i18nText collapsed + dictKey/staticDict labels resolved).\n ...(opts.resolveLabels !== undefined ? { resolveLabels: opts.resolveLabels } : {}),\n })) {\n collections[chunk.collection] = {\n schema: null, // Standard Schema validators are not JSON-serializable\n refs: chunk.refs,\n records: chunk.records,\n }\n if (chunk.ledgerHead) ledgerHead = chunk.ledgerHead\n // Collect dictionary snapshots unless resolveLabels is set\n if (!opts.resolveLabels && chunk.dictionaries) {\n allDictionaries[chunk.collection] = chunk.dictionaries\n }\n }\n\n const hasDictionaries = Object.keys(allDictionaries).length > 0\n return JSON.stringify({\n _noydb_export: 1,\n _compartment: ctx.vault,\n _exported_at: new Date().toISOString(),\n _exported_by: ctx.userId(),\n collections,\n ...(hasDictionaries ? { _dictionaries: allDictionaries } : {}),\n ...(ledgerHead ? { ledgerHead } : {}),\n })\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+FA,eAAsB,UAAU,KAAqC;AACnE,QAAM,WAAW,MAAM,IAAI,QAAQ,QAAQ,IAAI,KAAK;AAIpD,QAAM,aAAa,MAAM,IAAI,QAAQ,KAAK,IAAI,OAAO,UAAU;AAC/D,QAAM,WAAoC,CAAC;AAC3C,aAAW,aAAa,YAAY;AAClC,UAAM,WAAW,MAAM,IAAI,QAAQ,IAAI,IAAI,OAAO,YAAY,SAAS;AACvE,QAAI,UAAU;AACZ,eAAS,SAAS,IAAI,KAAK,MAAM,SAAS,KAAK;AAAA,IACjD;AAAA,EACF;AAaA,QAAM,mBAAkC,CAAC;AACzC,QAAM,gBAAgB;AAAA,IACpB;AAAA,IAAmB;AAAA,IAA0B;AAAA,IAAoB;AAAA,IACjE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAQA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA,IACA;AAAA,IAAe;AAAA,IAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAM/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAYA,GAAG,OAAO,KAAK,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,kBAAkB,CAAC,EAAE,CAAC;AAAA,EACrF;AACA,aAAW,gBAAgB,eAAe;AACxC,UAAM,MAAM,MAAM,IAAI,QAAQ,KAAK,IAAI,OAAO,YAAY;AAC1D,QAAI,IAAI,WAAW,EAAG;AACtB,UAAM,UAA6C,CAAC;AACpD,eAAW,MAAM,KAAK;AACpB,YAAM,WAAW,MAAM,IAAI,QAAQ,IAAI,IAAI,OAAO,cAAc,EAAE;AAClE,UAAI,SAAU,SAAQ,EAAE,IAAI;AAAA,IAC9B;AACA,qBAAiB,YAAY,IAAI;AAAA,EACnC;AAQA,QAAM,gBAAgB,IAAI,gBAAgB;AAC1C,QAAM,OAAO,gBAAgB,MAAM,cAAc,KAAK,IAAI;AAC1D,QAAM,SAAsB;AAAA,IAC1B,eAAe;AAAA,IACf,cAAc,IAAI;AAAA,IAClB,eAAc,oBAAI,KAAK,GAAE,YAAY;AAAA,IACrC,cAAc,IAAI,OAAO;AAAA,IACzB;AAAA,IACA,aAAa;AAAA,IACb,GAAI,OAAO,KAAK,gBAAgB,EAAE,SAAS,IACvC,EAAE,WAAW,iBAAiB,IAC9B,CAAC;AAAA,IACL,GAAI,OACA;AAAA,MACE,YAAY;AAAA,QACV,MAAM,KAAK;AAAA,QACX,OAAO,KAAK,MAAM;AAAA,QAClB,IAAI,KAAK,MAAM;AAAA,MACjB;AAAA,IACF,IACA,CAAC;AAAA,EACP;AAEA,SAAO,KAAK,UAAU,MAAM;AAC9B;AAQA,eAAsB,UAAU,KAAoB,YAAmC;AACrF,QAAM,SAAS,KAAK,MAAM,UAAU;AAGpC,QAAM,IAAI,QAAQ,QAAQ,IAAI,OAAO,OAAO,WAAW;AAGvD,aAAW,CAAC,QAAQ,WAAW,KAAK,OAAO,QAAQ,OAAO,QAAQ,GAAG;AACnE,UAAM,WAAW;AAAA,MAAoB,EAAE,YAAY,YAAY,IAAI,OAAO;AAAA,MACxE,EAAE,SAAS,GAAG,IAAI,IAAI,MAAM,KAAK,UAAU,WAAW,EAAE;AAAA,IAAC;AAC3D,UAAM,IAAI,QAAQ,IAAI,IAAI,OAAO,YAAY,QAAQ,QAAQ;AAAA,EAC/D;AAIA,MAAI,OAAO,WAAW;AACpB,eAAW,CAAC,cAAc,OAAO,KAAK,OAAO,QAAQ,OAAO,SAAS,GAAG;AACtE,iBAAW,CAAC,IAAI,QAAQ,KAAK,OAAO,QAAQ,OAAO,GAAG;AACpD,cAAM,IAAI,QAAQ,IAAI,IAAI,OAAO,cAAc,IAAI,QAAQ;AAAA,MAC7D;AAAA,IACF;AAAA,EACF;AAUA,QAAM,IAAI,2BAA2B;AAKrC,MAAI,qBAAqB;AACzB,MAAI,iBAAiB;AAKrB,MAAI,CAAC,OAAO,YAAY;AACtB,YAAQ;AAAA,MACN;AAAA,IAGF;AACA;AAAA,EACF;AAEA,QAAM,SAAS,MAAM,sBAAsB,GAAG;AAC9C,MAAI,CAAC,OAAO,IAAI;AAGd,QAAI,OAAO,SAAS,QAAQ;AAC1B,YAAM,IAAI;AAAA,QACR,OAAO;AAAA,QACP,OAAO;AAAA,QACP,OAAO;AAAA,MACT;AAAA,IACF;AACA,UAAM,IAAI,kBAAkB,OAAO,SAAS,OAAO,UAAU;AAAA,EAC/D;AAKA,MAAI,OAAO,SAAS,OAAO,WAAW,MAAM;AAC1C,UAAM,IAAI;AAAA,MACR,0CAA0C,OAAO,WAAW,IAAI,wBAC1C,OAAO,IAAI;AAAA,IACnC;AAAA,EACF;AACF;AAQA,eAAsB,sBAAsB,KAAiD;AAI3F,QAAM,kBAAkB,IAAI,gBAAgB;AAC5C,MAAI,CAAC,iBAAiB;AACpB,WAAO,EAAE,IAAI,MAAM,MAAM,IAAI,QAAQ,EAAE;AAAA,EACzC;AACA,QAAM,cAAc,MAAM,gBAAgB,OAAO;AACjD,MAAI,CAAC,YAAY,IAAI;AACnB,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,MAAM;AAAA,MACN,YAAY,YAAY;AAAA,MACxB,SACE,kCAAkC,YAAY,UAAU,wBAClC,YAAY,QAAQ,gBAAgB,YAAY,MAAM;AAAA,IAChF;AAAA,EACF;AASA,QAAM,aAAa,MAAM,gBAAgB,eAAe;AAKxD,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,SAAS,oBAAI,IAGjB;AACF,WAAS,IAAI,WAAW,SAAS,GAAG,KAAK,GAAG,KAAK;AAC/C,UAAM,QAAQ,WAAW,CAAC;AAC1B,QAAI,CAAC,MAAO;AAOZ,QAAI,MAAM,OAAO,eAAe,MAAM,OAAO,YAAa;AAC1D,UAAM,MAAM,GAAG,MAAM,UAAU,IAAI,MAAM,EAAE;AAC3C,QAAI,KAAK,IAAI,GAAG,EAAG;AACnB,SAAK,IAAI,GAAG;AAKZ,QAAI,MAAM,OAAO,SAAU;AAC3B,WAAO,IAAI,KAAK;AAAA,MACd,YAAY,MAAM;AAAA,MAClB,IAAI,MAAM;AAAA,MACV,cAAc,MAAM;AAAA,IACtB,CAAC;AAAA,EACH;AAEA,aAAW,EAAE,YAAY,IAAI,aAAa,KAAK,OAAO,OAAO,GAAG;AAC9D,UAAM,WAAW,MAAM,IAAI,QAAQ,IAAI,IAAI,OAAO,YAAY,EAAE;AAChE,QAAI,CAAC,UAAU;AACb,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,MAAM;AAAA,QACN;AAAA,QACA;AAAA,QACA,SACE,+BAA+B,UAAU,IAAI,EAAE;AAAA,MAEnD;AAAA,IACF;AACA,UAAM,aAAa,MAAM,IAAI,oBAAoB,QAAQ;AACzD,QAAI,eAAe,cAAc;AAC/B,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,MAAM;AAAA,QACN;AAAA,QACA;AAAA,QACA,SACE,kBAAkB,UAAU,IAAI,EAAE,mDACT,YAAY,WAAW,UAAU;AAAA,MAC9D;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,MAAM,YAAY;AAAA,IAClB,QAAQ,YAAY;AAAA,EACtB;AACF;AAOA,eAAsB,gBAAgB,KAAoB,OAA4B,CAAC,GAAoB;AAGzG,QAAM,cAOF,CAAC;AACL,MAAI;AAGJ,QAAM,kBAGF,CAAC;AAEL,mBAAiB,SAAS,IAAI,aAAa;AAAA,IACzC,aAAa;AAAA,IACb,gBAAgB,KAAK,mBAAmB;AAAA;AAAA;AAAA,IAGxC,GAAI,KAAK,kBAAkB,SAAY,EAAE,eAAe,KAAK,cAAc,IAAI,CAAC;AAAA,EAClF,CAAC,GAAG;AACF,gBAAY,MAAM,UAAU,IAAI;AAAA,MAC9B,QAAQ;AAAA;AAAA,MACR,MAAM,MAAM;AAAA,MACZ,SAAS,MAAM;AAAA,IACjB;AACA,QAAI,MAAM,WAAY,cAAa,MAAM;AAEzC,QAAI,CAAC,KAAK,iBAAiB,MAAM,cAAc;AAC7C,sBAAgB,MAAM,UAAU,IAAI,MAAM;AAAA,IAC5C;AAAA,EACF;AAEA,QAAM,kBAAkB,OAAO,KAAK,eAAe,EAAE,SAAS;AAC9D,SAAO,KAAK,UAAU;AAAA,IACpB,eAAe;AAAA,IACf,cAAc,IAAI;AAAA,IAClB,eAAc,oBAAI,KAAK,GAAE,YAAY;AAAA,IACrC,cAAc,IAAI,OAAO;AAAA,IACzB;AAAA,IACA,GAAI,kBAAkB,EAAE,eAAe,gBAAgB,IAAI,CAAC;AAAA,IAC5D,GAAI,aAAa,EAAE,WAAW,IAAI,CAAC;AAAA,EACrC,CAAC;AACH;","names":[]}
1
+ {"version":3,"sources":["../src/with-pod/backup.ts"],"sourcesContent":["/**\n * Vault backup / restore / integrity.\n *\n * Holds `dump()` (verifiable encrypted JSON backup, including the blob\n * collections so blob \"covers\" travel in the bundle), `load()` (restore +\n * post-load integrity gate), `verifyBackupIntegrity()` (chain + data-envelope\n * cross-check), and `exportJSON()` (plaintext per-collection export, built on\n * the vault's `exportStream`). Behaviour is byte-identical to the inline\n * `Vault` methods these functions replaced — every dependency the moving code\n * touched on `this.*` arrives via {@link BackupContext}. `Vault` keeps the\n * public methods as thin delegators.\n *\n * Internal — reached through `vault.dump()` / `vault.load()` / etc.\n */\nimport { NOYDB_BACKUP_VERSION } from '../kernel/types.js'\nimport { BackupLedgerError, BackupCorruptedError } from '../kernel/errors.js'\nimport { LEDGER_COLLECTION, LEDGER_DELTAS_COLLECTION } from '../with-commit/history/ledger/constants.js'\nimport { SCHEMAS_COLLECTION } from '../with-shape/persisted-schemas/storage.js'\nimport { SEQUENCE_COLLECTION } from '../with-commit/sequence/index.js'\nimport { MANIFEST_COLLECTION } from '../with-shape/manifest/reserved-collections.js'\n// #1025 — imported from the dependency-light `window.ts`, not `periods.ts`: that\n// module exists precisely so a consumer can name the period collections without\n// dragging the ledger hash-chain machinery (`sha256Hex`/`canonicalJson`) into a\n// bundle that opted out of the periods service. Same reason the sync engine's\n// period-scoped pull imports it.\nimport {\n PERIODS_COLLECTION,\n PERIOD_FREEZES_COLLECTION,\n PERIOD_ARCHIVES_COLLECTION,\n PERIOD_TARGET_PURGES_COLLECTION,\n PERIOD_REOPENS_COLLECTION,\n} from '../with-audit/periods/window.js'\nimport type {\n NoydbStore,\n EncryptedEnvelope,\n VaultBackup,\n VaultSnapshot,\n ExportStreamOptions,\n ExportChunk,\n} from '../kernel/types.js'\nimport type { LedgerStore } from '../with-commit/history/ledger/store.js'\nimport { buildRecordEnvelope } from '../kernel/enclave/index.js'\n\n/** Everything the moving backup methods touched on the vault's `this.*`. */\nexport interface BackupContext {\n /** The ciphertext store. */\n readonly adapter: NoydbStore\n /** Vault namespace name. */\n readonly vault: string\n /** The invoking keyring's user id (read fresh per call). */\n userId(): string\n /** The vault's ledger store, or null when history is off. */\n getLedgerOrNull(): LedgerStore | null\n /** Recompute an envelope's `payloadHash` (bound `historyStrategy.envelopePayloadHash`). */\n envelopePayloadHash(envelope: EncryptedEnvelope): Promise<string>\n /**\n * Refresh the in-memory keyring from the freshly-loaded keyring file and\n * rebuild the DEK resolver. No-op when the vault has no `reloadKeyring`\n * callback (plaintext vaults / test constructions).\n */\n reloadKeyringAndRebuildDEK(): Promise<void>\n /** Clear the vault's collection cache (post-load). */\n clearCollectionCache(): void\n /** Reset the ledger store so the next `ledger()` rebuilds its head cache. */\n resetLedgerStore(): void\n /** The vault's decrypt+ACL export stream (used by `exportJSON`). */\n exportStream(opts: ExportStreamOptions): AsyncIterableIterator<ExportChunk>\n}\n\n/** Result of {@link verifyBackupIntegrity}. */\nexport type VerifyBackupResult =\n | { readonly ok: true; readonly head: string; readonly length: number }\n | {\n readonly ok: false\n readonly kind: 'chain'\n readonly divergedAt: number\n readonly message: string\n }\n | {\n readonly ok: false\n readonly kind: 'data'\n readonly collection: string\n readonly id: string\n readonly message: string\n }\n\n/**\n * Dump vault as a verifiable encrypted JSON backup string.\n *\n * backups embed the current ledger head and the full `_ledger` +\n * `_ledger_deltas` internal collections so the receiver can run\n * `verifyBackupIntegrity()` after `load()` and detect any tampering between\n * dump and restore. Backups produced without a ledger skip the integrity check\n * with a warning — both modes round-trip cleanly.\n */\nexport async function dumpVault(ctx: BackupContext): Promise<string> {\n const snapshot = await ctx.adapter.loadAll(ctx.vault)\n\n // Load keyrings (separate path because loadAll filters them out\n // along with all other underscore-prefixed internal collections).\n const keyringIds = await ctx.adapter.list(ctx.vault, '_keyring')\n const keyrings: Record<string, unknown> = {}\n for (const keyringId of keyringIds) {\n const envelope = await ctx.adapter.get(ctx.vault, '_keyring', keyringId)\n if (envelope) {\n keyrings[keyringId] = JSON.parse(envelope._data)\n }\n }\n\n // Load the ledger entries + deltas so the receiver can replay\n // the chain after restore. Without this, `load()` would have an\n // empty ledger and `verifyBackupIntegrity()` would have nothing\n // to compare against.\n //\n // Also enumerate the blob collections so blob content (\"covers\")\n // travels in the bundle (the blob DEK already travels in `_keyring`).\n // Literals are inlined (not imported from blobs/blob-set.ts) to keep\n // the blob runtime out of this kernel hot path — they mirror\n // BLOB_INDEX/CHUNKS/EVICTION_AUDIT_COLLECTION and SLOTS/VERSIONS_PREFIX.\n // The collect-loop skips empty ids, so this no-ops without blobs.\n const internalSnapshot: VaultSnapshot = {}\n const internalNames = [\n LEDGER_COLLECTION, LEDGER_DELTAS_COLLECTION, SCHEMAS_COLLECTION, SEQUENCE_COLLECTION,\n MANIFEST_COLLECTION, // #941: the pod's manifest-set record(s) travel in the bundle too\n // #1025: the accounting-period close state + its companions. The bundle is\n // the backup/restore path, so without these a restore discarded the\n // hash-chained evidence that a month was ever closed — the artifact\n // `closePeriod` exists to produce — and dropped the write gate with it, so\n // the restored vault silently accepted back-dated writes into a sealed\n // month. The companions matter as much as the close: a bounded reopen\n // window (`reopenPeriod({ until })`) is state a restore must not lose.\n PERIODS_COLLECTION,\n PERIOD_REOPENS_COLLECTION,\n PERIOD_FREEZES_COLLECTION,\n PERIOD_ARCHIVES_COLLECTION,\n PERIOD_TARGET_PURGES_COLLECTION,\n '_history', // full-snapshot version history — so history()/getVersion()/diff() survive the bundle\n '_blob_index', '_blob_chunks', '_blob_eviction_audit',\n // #753 spec §7 Q3: `_blob_intent` markers travel too — restoring mid-op\n // state (a blob row without its marker) would reproduce the ambiguity\n // the journal exists to prevent. Note: `_mv_stale` does NOT travel\n // today (a pre-existing, separate gap) — observed here, tracked on\n // #761, not fixed in this pass.\n '_blob_intent',\n // #769: `_blob_slots_<c>` envelopes travel verbatim (raw ciphertext,\n // same DEK, same vault) — including any `SlotRecord.pendingRelease`\n // resume breadcrumb they carry. This is INTENTIONALLY the opposite of\n // `extract-partition`'s `reKeyBlobs`, which STRIPS `pendingRelease`:\n // a full-vault backup restores into the SAME vault it was taken from,\n // so a breadcrumb taken mid-rehome (together with its `_blob_intent`\n // marker, carried above) is resumable on restore — carry-and-resume is\n // correct here. A partition extraction crosses vaults: the breadcrumb's\n // old eTag may not exist in the destination, so it must be stripped\n // there instead. Asymmetry: backup = same-vault-resumable = carry;\n // partition = cross-vault = strip-breadcrumb-carry-marker.\n ...Object.keys(snapshot).flatMap((c) => [`_blob_slots_${c}`, `_blob_versions_${c}`]),\n ]\n for (const internalName of internalNames) {\n const ids = await ctx.adapter.list(ctx.vault, internalName)\n if (ids.length === 0) continue\n const records: Record<string, EncryptedEnvelope> = {}\n for (const id of ids) {\n const envelope = await ctx.adapter.get(ctx.vault, internalName, id)\n if (envelope) records[id] = envelope\n }\n internalSnapshot[internalName] = records\n }\n\n // Embed the ledger head if there's a chain. An empty ledger\n // (fresh vault) leaves `ledgerHead` undefined, which\n // load() treats the same as a legacy backup (no integrity\n // check, console warning). If history is not opted in,\n // `getLedgerOrNull` returns null and we skip embedding entirely\n // — the backup is still valid, just without the integrity head.\n const ledgerForHead = ctx.getLedgerOrNull()\n const head = ledgerForHead ? await ledgerForHead.head() : null\n const backup: VaultBackup = {\n _noydb_backup: NOYDB_BACKUP_VERSION,\n _compartment: ctx.vault,\n _exported_at: new Date().toISOString(),\n _exported_by: ctx.userId(),\n keyrings: keyrings as VaultBackup['keyrings'],\n collections: snapshot,\n ...(Object.keys(internalSnapshot).length > 0\n ? { _internal: internalSnapshot }\n : {}),\n ...(head\n ? {\n ledgerHead: {\n hash: head.hash,\n index: head.entry.index,\n ts: head.entry.ts,\n },\n }\n : {}),\n }\n\n return JSON.stringify(backup)\n}\n\n/**\n * Restore a vault from a verifiable backup. After loading, runs\n * `verifyBackupIntegrity()` to confirm the hash chain, the embedded head, and\n * every data envelope's payload hash. Legacy backups (no `ledgerHead`) load\n * with a console warning and skip the integrity check.\n */\nexport async function loadVault(ctx: BackupContext, backupJson: string): Promise<void> {\n const backup = JSON.parse(backupJson) as VaultBackup\n\n // 1. Restore data collections.\n await ctx.adapter.saveAll(ctx.vault, backup.collections)\n\n // 2. Restore keyrings.\n for (const [userId, keyringFile] of Object.entries(backup.keyrings)) {\n const envelope = buildRecordEnvelope({ collection: '_keyring', id: userId, version: 1 },\n { iv: '', data: JSON.stringify(keyringFile) })\n await ctx.adapter.put(ctx.vault, '_keyring', userId, envelope)\n }\n\n // 3. Restore internal collections (`_ledger`, `_ledger_deltas`).\n // Required so verifyBackupIntegrity has the chain to walk.\n if (backup._internal) {\n for (const [internalName, records] of Object.entries(backup._internal)) {\n for (const [id, envelope] of Object.entries(records)) {\n await ctx.adapter.put(ctx.vault, internalName, id, envelope)\n }\n }\n }\n\n // 4. Refresh the in-memory keyring from the freshly-loaded\n // keyring file. Without this, the Vault's getDEK\n // closure still holds the OLD session's DEKs, and every\n // decrypt of a loaded ledger entry / data envelope fails\n // with TamperedError because the DEK doesn't match the\n // ciphertext that was encrypted with the SOURCE user's DEK.\n // Skipped for plaintext vaults and for tests that\n // construct Vault without a reloadKeyring callback.\n await ctx.reloadKeyringAndRebuildDEK()\n\n // 5. Clear collection cache + reset the ledger store so the\n // next ledger() call rebuilds its head cache from the\n // freshly-loaded entries.\n ctx.clearCollectionCache()\n ctx.resetLedgerStore()\n\n // 5. Run the verification gate. Legacy backups (no ledgerHead)\n // skip this with a one-line warning so existing consumers can\n // still read them while migrating.\n if (!backup.ledgerHead) {\n console.warn(\n `[noy-db] Loaded a legacy backup with no ledgerHead — ` +\n `verifiable-backup integrity check skipped. ` +\n `Re-export with a ledger-aware build to get tamper detection.`,\n )\n return\n }\n\n const result = await verifyBackupIntegrity(ctx)\n if (!result.ok) {\n // Surface the most specific error class we can. The result\n // shape carries enough info for callers to inspect.\n if (result.kind === 'data') {\n throw new BackupCorruptedError(\n result.collection,\n result.id,\n result.message,\n )\n }\n throw new BackupLedgerError(result.message, result.divergedAt)\n }\n\n // 6. Cross-check: the freshly-verified head must match the\n // value embedded at dump time. A mismatch means someone\n // truncated or extended the chain after dump.\n if (result.head !== backup.ledgerHead.hash) {\n throw new BackupLedgerError(\n `Backup ledger head mismatch: embedded \"${backup.ledgerHead.hash}\" ` +\n `but reconstructed \"${result.head}\".`,\n )\n }\n}\n\n/**\n * End-to-end backup integrity check: `ledger.verify()` (hash chain) plus a data\n * envelope cross-check (every current record's `_data` hash must match the\n * latest `put` entry's `payloadHash`). Returns a discriminated union so callers\n * can distinguish chain vs data failures.\n */\nexport async function verifyBackupIntegrity(ctx: BackupContext): Promise<VerifyBackupResult> {\n // Step 1: chain verification. Without the history strategy there\n // is no ledger; an unaudited backup verifies trivially as `ok`\n // because there's nothing to diverge from.\n const ledgerForVerify = ctx.getLedgerOrNull()\n if (!ledgerForVerify) {\n return { ok: true, head: '', length: 0 }\n }\n const chainResult = await ledgerForVerify.verify()\n if (!chainResult.ok) {\n return {\n ok: false,\n kind: 'chain',\n divergedAt: chainResult.divergedAt,\n message:\n `Ledger chain diverged at index ${chainResult.divergedAt}: ` +\n `expected prevHash \"${chainResult.expected}\" but found \"${chainResult.actual}\".`,\n }\n }\n\n // Step 2: data envelope cross-check. Walk every entry in the\n // ledger and, for the LATEST `put` per (collection, id), recompute\n // the data envelope's payloadHash and compare. Earlier puts of the\n // same id are skipped because the data collection only holds the\n // current version — historical envelopes live in the deltas\n // collection (which is itself protected by the chain).\n // Reuse the ledger we already resolved in step 1.\n const allEntries = await ledgerForVerify.loadAllEntries()\n\n // Find the latest non-delete entry per (collection, id). Walk\n // the entries in reverse so we hit the latest first; mark each\n // (collection, id) as seen and skip subsequent entries.\n const seen = new Set<string>()\n const latest = new Map<\n string,\n { collection: string; id: string; expectedHash: string }\n >()\n for (let i = allEntries.length - 1; i >= 0; i--) {\n const entry = allEntries[i]\n if (!entry) continue\n // Amendment entries are multi-record audit entries whose\n // `collection` and `id` are empty strings — building a `\"/\"`\n // key here would mark that synthetic slot as seen and falsely\n // trip the data check on a record that never existed. Skip\n // them BEFORE the key/seen bookkeeping so they neither\n // tombstone real entries nor enter the latest map.\n if (entry.op === 'amendment' || entry.op === 'lifecycle') continue\n const key = `${entry.collection}/${entry.id}`\n if (seen.has(key)) continue\n seen.add(key)\n // For deletes the data collection should NOT have the record,\n // so we skip — there's nothing to cross-check. Marking the key\n // as seen above ensures any earlier `put` of the same id is\n // also skipped (the record was subsequently deleted).\n if (entry.op === 'delete') continue\n latest.set(key, {\n collection: entry.collection,\n id: entry.id,\n expectedHash: entry.payloadHash,\n })\n }\n\n for (const { collection, id, expectedHash } of latest.values()) {\n const envelope = await ctx.adapter.get(ctx.vault, collection, id)\n if (!envelope) {\n return {\n ok: false,\n kind: 'data',\n collection,\n id,\n message:\n `Ledger expects data record \"${collection}/${id}\" to exist, ` +\n `but the adapter has no envelope for it.`,\n }\n }\n const actualHash = await ctx.envelopePayloadHash(envelope)\n if (actualHash !== expectedHash) {\n return {\n ok: false,\n kind: 'data',\n collection,\n id,\n message:\n `Data envelope \"${collection}/${id}\" has been tampered with: ` +\n `expected payloadHash \"${expectedHash}\", got \"${actualHash}\".`,\n }\n }\n }\n\n return {\n ok: true,\n head: chainResult.head,\n length: chainResult.length,\n }\n}\n\n/**\n * Plaintext per-collection export, built on the vault's `exportStream`. Forces\n * collection granularity (record-by-record output makes no sense in a single\n * string) and merges dictionary snapshots across collections.\n */\nexport async function exportVaultJSON(ctx: BackupContext, opts: ExportStreamOptions = {}): Promise<string> {\n // Force per-collection granularity regardless of caller setting:\n // record-by-record output doesn't make sense in a single string.\n const collections: Record<\n string,\n {\n schema: null\n refs: Record<string, { target: string; mode: 'strict' | 'warn' | 'cascade' }>\n records: unknown[]\n }\n > = {}\n let ledgerHead: ExportChunk['ledgerHead'] | undefined\n // Merged dictionary snapshot across all collections.\n // Only populated when `resolveLabels` is not set.\n const allDictionaries: Record<\n string, // collection name\n Record<string, Record<string, Record<string, string>>>\n > = {}\n\n for await (const chunk of ctx.exportStream({\n granularity: 'collection',\n withLedgerHead: opts.withLedgerHead === true,\n // Thread the export locale so records are read at the\n // `export` layer (i18nText collapsed + dictKey/staticDict labels resolved).\n ...(opts.resolveLabels !== undefined ? { resolveLabels: opts.resolveLabels } : {}),\n })) {\n collections[chunk.collection] = {\n schema: null, // Standard Schema validators are not JSON-serializable\n refs: chunk.refs,\n records: chunk.records,\n }\n if (chunk.ledgerHead) ledgerHead = chunk.ledgerHead\n // Collect dictionary snapshots unless resolveLabels is set\n if (!opts.resolveLabels && chunk.dictionaries) {\n allDictionaries[chunk.collection] = chunk.dictionaries\n }\n }\n\n const hasDictionaries = Object.keys(allDictionaries).length > 0\n return JSON.stringify({\n _noydb_export: 1,\n _compartment: ctx.vault,\n _exported_at: new Date().toISOString(),\n _exported_by: ctx.userId(),\n collections,\n ...(hasDictionaries ? { _dictionaries: allDictionaries } : {}),\n ...(ledgerHead ? { ledgerHead } : {}),\n })\n}\n"],"mappings":"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","names":[]}
@@ -16,7 +16,7 @@ import {
16
16
  detectMimeType,
17
17
  isPreCompressed,
18
18
  memoryBlobPinStore
19
- } from "../chunk-ES36R3U2.js";
19
+ } from "../chunk-RAYGDC4A.js";
20
20
  import {
21
21
  BLOB_EVICTION_AUDIT_COLLECTION,
22
22
  EXPORT_AUDIT_COLLECTION,
@@ -24,18 +24,18 @@ import {
24
24
  NO_BLOBS,
25
25
  createExportBlobsHandle,
26
26
  runCompaction
27
- } from "../chunk-Z2OFE6IX.js";
28
- import "../chunk-RVTOCAHQ.js";
29
- import "../chunk-YVOW35HH.js";
30
- import "../chunk-AMKCY454.js";
31
- import "../chunk-BKYQNNO3.js";
32
- import "../chunk-RGPB25DB.js";
27
+ } from "../chunk-DWO55ZWE.js";
28
+ import "../chunk-SQSZRCYT.js";
29
+ import "../chunk-DL4GDOWL.js";
30
+ import "../chunk-7WD2G6K4.js";
31
+ import "../chunk-X3AXSYBL.js";
32
+ import "../chunk-ZVAFJQZB.js";
33
33
  import "../chunk-FSZPQCDR.js";
34
34
  import "../chunk-HVR74IBG.js";
35
35
  import "../chunk-RBTZLXZJ.js";
36
36
  import "../chunk-LP7BEXCT.js";
37
37
  import "../chunk-QTDAPDDV.js";
38
- import "../chunk-5UGEGEIJ.js";
38
+ import "../chunk-3Y4OFWQJ.js";
39
39
  import {
40
40
  BlobOfflineError
41
41
  } from "../chunk-I64WQSN3.js";
@@ -4,14 +4,14 @@ import {
4
4
  import {
5
5
  issueChallenge,
6
6
  verifyBrokerProof
7
- } from "../chunk-BKYQNNO3.js";
8
- import "../chunk-RGPB25DB.js";
7
+ } from "../chunk-X3AXSYBL.js";
8
+ import "../chunk-ZVAFJQZB.js";
9
9
  import "../chunk-FSZPQCDR.js";
10
10
  import "../chunk-HVR74IBG.js";
11
11
  import "../chunk-RBTZLXZJ.js";
12
12
  import "../chunk-LP7BEXCT.js";
13
13
  import "../chunk-QTDAPDDV.js";
14
- import "../chunk-5UGEGEIJ.js";
14
+ import "../chunk-3Y4OFWQJ.js";
15
15
  import {
16
16
  BrokerEnrolmentError,
17
17
  BrokerNotEnabledError,
@@ -30,7 +30,7 @@ function withBroker(config) {
30
30
  const cache = /* @__PURE__ */ new Map();
31
31
  return {
32
32
  async enroll(ctx) {
33
- const { enrollSeed } = await import("../seed-2FUULTQV.js");
33
+ const { enrollSeed } = await import("../seed-LNTLU2A3.js");
34
34
  return enrollSeed({ ...ctx, config });
35
35
  },
36
36
  async rotate(ctx) {
@@ -39,7 +39,7 @@ function withBroker(config) {
39
39
  const inFlight = scoped.map(([, e]) => e.inFlight).filter((p) => p !== void 0);
40
40
  await Promise.allSettled(inFlight);
41
41
  for (const [key] of scoped) cache.delete(key);
42
- const { rotateSeed } = await import("../seed-2FUULTQV.js");
42
+ const { rotateSeed } = await import("../seed-LNTLU2A3.js");
43
43
  return rotateSeed({ ...ctx, config });
44
44
  },
45
45
  credentialSource(ctx, profile) {
@@ -56,7 +56,7 @@ function withBroker(config) {
56
56
  const skewMs = config.skewMs ?? DEFAULT_SKEW_MS;
57
57
  const capturedEntry = entry;
58
58
  const inFlight = (async () => {
59
- const { mintStoreCredentials } = await import("../seed-2FUULTQV.js");
59
+ const { mintStoreCredentials } = await import("../seed-LNTLU2A3.js");
60
60
  const creds = await mintStoreCredentials({ ...ctx, config }, profile);
61
61
  capturedEntry.cached = { creds, validUntil: cacheFloor(creds, skewMs) };
62
62
  return creds;
@@ -6,59 +6,59 @@ import {
6
6
  diffVault,
7
7
  unsealDeks,
8
8
  withCargo
9
- } from "../chunk-6VAM5THN.js";
9
+ } from "../chunk-U6D5XTI5.js";
10
10
  import {
11
11
  extractPartition,
12
12
  walkClosure
13
- } from "../chunk-UNR6G3EJ.js";
13
+ } from "../chunk-AMMYIT7F.js";
14
14
  import {
15
15
  createDeedOwner,
16
16
  isDeedVault,
17
17
  liberateVault,
18
18
  loadDeedMarker
19
- } from "../chunk-QKRJUPAC.js";
20
- import "../chunk-P5ARVLNW.js";
21
- import "../chunk-NWPR2V5W.js";
22
- import "../chunk-ES36R3U2.js";
23
- import {
24
- groupAndReduce,
25
- reduceRecords
26
- } from "../chunk-3JQVA527.js";
19
+ } from "../chunk-FRGF56PD.js";
20
+ import "../chunk-TXDOMADN.js";
21
+ import "../chunk-BBU3OD3D.js";
27
22
  import {
28
23
  NO_CARGO,
29
24
  isQuorum,
30
25
  runDrainBarrier
31
26
  } from "../chunk-42IDLU5V.js";
32
- import "../chunk-JAHIL6WO.js";
33
- import "../chunk-6JRIYG2C.js";
27
+ import "../chunk-NRNTXBHT.js";
28
+ import "../chunk-IN5EZWYQ.js";
34
29
  import {
35
30
  CustodyApi
36
- } from "../chunk-QC2HGYFX.js";
37
- import "../chunk-SDEHNGWW.js";
38
- import "../chunk-N7HOHWKF.js";
31
+ } from "../chunk-VXVKEWYC.js";
32
+ import "../chunk-TNOQNU3R.js";
33
+ import "../chunk-O4QDBAB6.js";
39
34
  import {
40
35
  fuseRetrieval
41
36
  } from "../chunk-AURFOK3D.js";
37
+ import "../chunk-RAYGDC4A.js";
38
+ import {
39
+ groupAndReduce,
40
+ reduceRecords
41
+ } from "../chunk-LU6NPJWN.js";
42
42
  import "../chunk-XZHEOSQ2.js";
43
43
  import "../chunk-CADUYBQD.js";
44
44
  import {
45
45
  readPath
46
46
  } from "../chunk-IGJCYUT5.js";
47
- import "../chunk-7LLKPODL.js";
48
- import "../chunk-RVTOCAHQ.js";
49
- import "../chunk-WBHQX6ME.js";
50
- import "../chunk-QJBXB4WU.js";
51
- import "../chunk-YVOW35HH.js";
47
+ import "../chunk-LPAGIMXJ.js";
48
+ import "../chunk-SQSZRCYT.js";
49
+ import "../chunk-ZSOTZ2RZ.js";
50
+ import "../chunk-ITXPKEDP.js";
51
+ import "../chunk-DL4GDOWL.js";
52
52
  import {
53
53
  generateULID
54
54
  } from "../chunk-4AOERLTV.js";
55
55
  import "../chunk-SVLR4POP.js";
56
- import "../chunk-IEA3TZJE.js";
56
+ import "../chunk-FDIZHZ3C.js";
57
57
  import "../chunk-I7FD46FF.js";
58
- import "../chunk-AMKCY454.js";
59
- import "../chunk-N4GAJSRQ.js";
60
- import "../chunk-BKYQNNO3.js";
61
- import "../chunk-RGPB25DB.js";
58
+ import "../chunk-FY33DKPH.js";
59
+ import "../chunk-7WD2G6K4.js";
60
+ import "../chunk-X3AXSYBL.js";
61
+ import "../chunk-ZVAFJQZB.js";
62
62
  import "../chunk-FSZPQCDR.js";
63
63
  import "../chunk-HVR74IBG.js";
64
64
  import "../chunk-RBTZLXZJ.js";
@@ -66,7 +66,7 @@ import "../chunk-LP7BEXCT.js";
66
66
  import {
67
67
  sha256Hex
68
68
  } from "../chunk-QTDAPDDV.js";
69
- import "../chunk-5UGEGEIJ.js";
69
+ import "../chunk-3Y4OFWQJ.js";
70
70
  import {
71
71
  AdoptionStateError,
72
72
  CargoNotEnabledError,
@@ -3,14 +3,15 @@ import {
3
3
  linkRowKey
4
4
  } from "./chunk-S6CP5FWF.js";
5
5
  import {
6
+ buildRecordAad,
6
7
  openEnvelopeJson
7
- } from "./chunk-BKYQNNO3.js";
8
+ } from "./chunk-X3AXSYBL.js";
9
+ import {
10
+ buildRecordEnvelope
11
+ } from "./chunk-ZVAFJQZB.js";
8
12
  import {
9
13
  encrypt
10
14
  } from "./chunk-QTDAPDDV.js";
11
- import {
12
- NOYDB_FORMAT_VERSION
13
- } from "./chunk-5UGEGEIJ.js";
14
15
  import {
15
16
  NoydbError
16
17
  } from "./chunk-I64WQSN3.js";
@@ -44,15 +45,17 @@ var LinkSet = class {
44
45
  if (!this.dekPromise) this.dekPromise = this.getDEK(this.collName);
45
46
  return this.dekPromise;
46
47
  }
47
- async encryptEntry(entry, version) {
48
+ async encryptEntry(entry, version, key) {
48
49
  const json = JSON.stringify(entry);
49
- const base = { _noydb: NOYDB_FORMAT_VERSION, _v: version, _ts: (/* @__PURE__ */ new Date()).toISOString(), _by: this.actor };
50
- if (!this.encrypted) return { ...base, _iv: "", _data: json };
51
- const { iv, data } = await encrypt(json, await this.dek());
52
- return { ...base, _iv: iv, _data: data };
50
+ const identity = { collection: this.collName, id: key, by: this.actor, version };
51
+ if (!this.encrypted) {
52
+ return buildRecordEnvelope(identity, { iv: "", data: json });
53
+ }
54
+ const { iv, data } = await encrypt(json, await this.dek(), buildRecordAad(identity));
55
+ return buildRecordEnvelope(identity, { iv, data });
53
56
  }
54
- async decryptEntry(env) {
55
- const json = this.encrypted ? await openEnvelopeJson(env, await this.dek()) : env._data;
57
+ async decryptEntry(key, env) {
58
+ const json = this.encrypted ? await openEnvelopeJson({ collection: this.collName, id: key }, env, await this.dek()) : env._data;
56
59
  return JSON.parse(json);
57
60
  }
58
61
  async connect(aId, bId, meta) {
@@ -65,7 +68,7 @@ var LinkSet = class {
65
68
  const key = linkRowKey(aId, bId);
66
69
  const entry = meta !== void 0 ? { a: aId, b: bId, meta } : { a: aId, b: bId };
67
70
  const existing = await this.adapter.get(this.vault, this.collName, key);
68
- const env = await this.encryptEntry(entry, (existing?._v ?? 0) + 1);
71
+ const env = await this.encryptEntry(entry, (existing?._v ?? 0) + 1, key);
69
72
  await this.adapter.put(this.vault, this.collName, key, env, existing?._v);
70
73
  this.emitter.emit("change", { vault: this.vault, collection: this.collName, id: key, action: "put" });
71
74
  }
@@ -89,7 +92,7 @@ var LinkSet = class {
89
92
  for (const key of keys) {
90
93
  const env = await this.adapter.get(this.vault, this.collName, key);
91
94
  if (!env) continue;
92
- const e = await this.decryptEntry(env);
95
+ const e = await this.decryptEntry(key, env);
93
96
  out.push(e.meta !== void 0 ? { a: e.a, b: e.b, meta: e.meta } : { a: e.a, b: e.b });
94
97
  }
95
98
  return out;
@@ -127,4 +130,4 @@ export {
127
130
  LinkSet,
128
131
  LinkEndpointError
129
132
  };
130
- //# sourceMappingURL=chunk-V3OLO4TK.js.map
133
+ //# sourceMappingURL=chunk-2ION5ZRH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/with-shape/links/link-set.ts"],"sourcesContent":["/**\n * `_links_*` reserved collections — managed bidirectional many-to-many\n * junctions (design B).\n *\n * Where `refArray` (design A) stores an id-array on one owning record,\n * `vault.link()` creates a first-class junction: a dedicated encrypted\n * `_links_<name>` collection whose rows are `{ a, b, meta? }` link tuples.\n * It is queryable from BOTH sides (`of(id)`), carries optional per-link\n * metadata, and cascades on endpoint delete.\n *\n * Each link is slot-typed: `a` is an id in the `a` endpoint collection,\n * `b` an id in the `b` endpoint collection (they may be the same\n * collection for self-links). A link's identity is the ordered pair\n * `(a, b)`; `of(id)` matches either slot.\n *\n * Rows are encrypted under a dedicated `_links_<name>` DEK — same\n * zero-knowledge stack as every other collection (the store sees only\n * ciphertext). Backup/restore rides the normal `loadAll` path.\n */\n\nimport type { NoydbStore, EncryptedEnvelope } from '../../kernel/types.js'\nimport type { NoydbEventEmitter } from '../../kernel/events.js'\nimport { buildRecordAad, buildRecordEnvelope, encrypt, openEnvelopeJson, type EnclaveKey } from '../../kernel/enclave/index.js'\nimport { NoydbError } from '../../kernel/errors.js'\n\n// Naming helpers, declaration types, and LinkIntegrityError live in\n// `names.ts` (the always-loadable slice — #553); re-exported here so\n// existing import paths and the root barrel are unchanged.\nexport {\n LINK_COLLECTION_PREFIX,\n linkCollectionName,\n isLinkCollectionName,\n linkRowKey,\n LinkIntegrityError,\n} from './names.js'\nexport type { LinkOnDelete, LinkSpec, LinkRow, LinkSetHandle } from './names.js'\nimport { linkCollectionName, linkRowKey } from './names.js'\nimport type { LinkSpec, LinkRow, LinkSetHandle } from './names.js'\n\n/** Stored form (also the row key derivation source). */\ninterface LinkEntry {\n a: string\n b: string\n meta?: Record<string, unknown>\n}\n\n/**\n * @internal — the concrete handle. The Vault owns construction (one per\n * link name) and the cascade hooks; consumers use the {@link LinkSetHandle}\n * surface via `vault.links(name)`.\n */\nexport class LinkSet implements LinkSetHandle {\n private readonly collName: string\n private dekPromise: Promise<EnclaveKey> | null = null\n\n constructor(\n private readonly adapter: NoydbStore,\n private readonly vault: string,\n private readonly name: string,\n private readonly spec: LinkSpec,\n private readonly encrypted: boolean,\n private readonly getDEK: (collectionName: string) => Promise<EnclaveKey>,\n private readonly actor: string,\n private readonly emitter: NoydbEventEmitter,\n /** Vault-provided existence check for endpoint validation on connect(). */\n private readonly endpointExists: (collection: string, id: string) => Promise<boolean>,\n ) {\n this.collName = linkCollectionName(name)\n }\n\n private dek(): Promise<EnclaveKey> {\n if (!this.dekPromise) this.dekPromise = this.getDEK(this.collName)\n return this.dekPromise\n }\n\n private async encryptEntry(entry: LinkEntry, version: number, key: string): Promise<EncryptedEnvelope> {\n const json = JSON.stringify(entry)\n const identity = { collection: this.collName, id: key, by: this.actor, version }\n if (!this.encrypted) {\n return buildRecordEnvelope(identity, { iv: '', data: json})\n }\n const { iv, data } = await encrypt(json, await this.dek(), buildRecordAad(identity))\n return buildRecordEnvelope(identity, { iv, data})\n }\n\n private async decryptEntry(key: string, env: EncryptedEnvelope): Promise<LinkEntry> {\n const json = this.encrypted ? await openEnvelopeJson({ collection: this.collName, id: key }, env, await this.dek()) : env._data\n return JSON.parse(json) as LinkEntry\n }\n\n async connect(aId: string, bId: string, meta?: Record<string, unknown>): Promise<void> {\n if (!(await this.endpointExists(this.spec.a, aId))) {\n throw new LinkEndpointError(this.name, this.spec.a, aId)\n }\n if (!(await this.endpointExists(this.spec.b, bId))) {\n throw new LinkEndpointError(this.name, this.spec.b, bId)\n }\n const key = linkRowKey(aId, bId)\n const entry: LinkEntry = meta !== undefined ? { a: aId, b: bId, meta } : { a: aId, b: bId }\n const existing = await this.adapter.get(this.vault, this.collName, key)\n const env = await this.encryptEntry(entry, (existing?._v ?? 0) + 1, key)\n await this.adapter.put(this.vault, this.collName, key, env, existing?._v)\n this.emitter.emit('change', { vault: this.vault, collection: this.collName, id: key, action: 'put' })\n }\n\n async disconnect(aId: string, bId: string): Promise<void> {\n const key = linkRowKey(aId, bId)\n const existing = await this.adapter.get(this.vault, this.collName, key)\n if (!existing) return\n await this.adapter.delete(this.vault, this.collName, key)\n this.emitter.emit('change', { vault: this.vault, collection: this.collName, id: key, action: 'delete' })\n }\n\n async has(aId: string, bId: string): Promise<boolean> {\n return (await this.adapter.get(this.vault, this.collName, linkRowKey(aId, bId))) !== null\n }\n\n async of(id: string): Promise<LinkRow[]> {\n const rows = await this.list()\n return rows.filter((r) => r.a === id || r.b === id)\n }\n\n async list(): Promise<LinkRow[]> {\n const keys = await this.adapter.list(this.vault, this.collName)\n const out: LinkRow[] = []\n for (const key of keys) {\n const env = await this.adapter.get(this.vault, this.collName, key)\n if (!env) continue\n const e = await this.decryptEntry(key, env)\n out.push(e.meta !== undefined ? { a: e.a, b: e.b, meta: e.meta } : { a: e.a, b: e.b })\n }\n return out\n }\n\n // ── Vault-internal cascade helpers ──────────────────────────────────\n\n /** @internal — rows where the deleted endpoint id matches the relevant slot. */\n async _rowsTouchingEndpoint(collection: string, id: string): Promise<LinkRow[]> {\n const rows = await this.list()\n return rows.filter(\n (r) => (this.spec.a === collection && r.a === id) || (this.spec.b === collection && r.b === id),\n )\n }\n\n /** @internal — the storage collection name (for tx pre-image capture). */\n get _collectionName(): string {\n return this.collName\n }\n}\n\n/** Thrown by `connect()` when an endpoint record does not exist. */\nexport class LinkEndpointError extends NoydbError {\n readonly link: string\n readonly endpoint: string\n readonly missingId: string\n constructor(link: string, endpoint: string, missingId: string) {\n super(\n 'LINK_ENDPOINT',\n `link(\"${link}\").connect: endpoint \"${endpoint}\" has no record \"${missingId}\".`,\n )\n this.name = 'LinkEndpointError'\n this.link = link\n this.endpoint = endpoint\n this.missingId = missingId\n }\n}\n"],"mappings":"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","names":[]}
@@ -4,7 +4,7 @@ import {
4
4
  formatScaledInt,
5
5
  parseToScaledInt,
6
6
  rescaleScaledInt
7
- } from "./chunk-JU3JKOY5.js";
7
+ } from "./chunk-EWAGI3EM.js";
8
8
 
9
9
  // src/via/money/arith.ts
10
10
  function parseAmount(label, amount, scale, rounding) {
@@ -120,4 +120,4 @@ export {
120
120
  isMoneyString,
121
121
  moneyNumber
122
122
  };
123
- //# sourceMappingURL=chunk-466KGOQB.js.map
123
+ //# sourceMappingURL=chunk-2NE7ILO7.js.map
@@ -201,7 +201,7 @@ var engineCtx = (ctx) => ({
201
201
  function withClassified() {
202
202
  return {
203
203
  async reveal(ctx, id, field) {
204
- const { revealSealedField } = await import("./reveal-G7W7N3AZ.js");
204
+ const { revealSealedField } = await import("./reveal-PWM47FQN.js");
205
205
  const value = await revealSealedField({
206
206
  collection: ctx.collection,
207
207
  encrypted: ctx.encrypted,
@@ -244,4 +244,4 @@ export {
244
244
  classified,
245
245
  withClassified
246
246
  };
247
- //# sourceMappingURL=chunk-GWI65NDQ.js.map
247
+ //# sourceMappingURL=chunk-3KXIGMZ4.js.map
@@ -1,12 +1,13 @@
1
1
  import {
2
+ buildRecordAad,
2
3
  openEnvelopeJson
3
- } from "./chunk-BKYQNNO3.js";
4
+ } from "./chunk-X3AXSYBL.js";
5
+ import {
6
+ buildRecordEnvelope
7
+ } from "./chunk-ZVAFJQZB.js";
4
8
  import {
5
9
  encrypt
6
10
  } from "./chunk-QTDAPDDV.js";
7
- import {
8
- NOYDB_FORMAT_VERSION
9
- } from "./chunk-5UGEGEIJ.js";
10
11
  import {
11
12
  ConflictError
12
13
  } from "./chunk-I64WQSN3.js";
@@ -20,7 +21,7 @@ async function loadSigner(store, vault, getDEK) {
20
21
  const existing = await store.get(vault, ATTESTATIONS_COLLECTION, SIGNER_RECORD_ID);
21
22
  if (!existing) return null;
22
23
  const dek = await getDEK(ATTESTATIONS_COLLECTION);
23
- const json = await openEnvelopeJson(existing, dek);
24
+ const json = await openEnvelopeJson({ collection: ATTESTATIONS_COLLECTION, id: SIGNER_RECORD_ID }, existing, dek);
24
25
  return JSON.parse(json);
25
26
  }
26
27
  async function loadOrCreateSigner(store, vault, getDEK) {
@@ -28,14 +29,12 @@ async function loadOrCreateSigner(store, vault, getDEK) {
28
29
  if (existing) return existing;
29
30
  const dek = await getDEK(ATTESTATIONS_COLLECTION);
30
31
  const signer = await generateDocSigningKeyPair();
31
- const { iv, data } = await encrypt(JSON.stringify(signer), dek);
32
- const env = {
33
- _noydb: NOYDB_FORMAT_VERSION,
34
- _v: 1,
35
- _ts: (/* @__PURE__ */ new Date()).toISOString(),
36
- _iv: iv,
37
- _data: data
38
- };
32
+ const identity = { collection: ATTESTATIONS_COLLECTION, id: SIGNER_RECORD_ID, version: 1 };
33
+ const { iv, data } = await encrypt(JSON.stringify(signer), dek, buildRecordAad(identity));
34
+ const env = buildRecordEnvelope(
35
+ identity,
36
+ { iv, data }
37
+ );
39
38
  try {
40
39
  await store.put(vault, ATTESTATIONS_COLLECTION, SIGNER_RECORD_ID, env, 0);
41
40
  return signer;
@@ -56,4 +55,4 @@ export {
56
55
  loadSigner,
57
56
  loadOrCreateSigner
58
57
  };
59
- //# sourceMappingURL=chunk-C3YP5KKS.js.map
58
+ //# sourceMappingURL=chunk-3ODOWQMV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/with-audit/attestation/signer.ts"],"sourcesContent":["import type { NoydbStore } from '../../kernel/types.js'\nimport { buildRecordAad, buildRecordEnvelope, encrypt, openEnvelopeJson, type EnclaveKey } from '../../kernel/enclave/index.js'\nimport { ConflictError } from '../../kernel/errors.js'\nimport { generateDocSigningKeyPair } from '@noy-db/attestation'\n\nexport const ATTESTATIONS_COLLECTION = '_attestations'\nexport const SIGNER_RECORD_ID = '_signer'\nexport const REVOKED_RECORD_ID = '_revoked'\n\nexport interface DocSigner {\n readonly keyId: string\n readonly publicKeyB64: string\n readonly privateKeyPkcs8B64: string\n}\n\n/**\n * Pure read: return the firm's persisted document-signing keypair, or `null`\n * if none has been minted yet. Never writes — callers that must NOT mint\n * (e.g. an ungated public-key getter) use this instead of `loadOrCreateSigner`.\n *\n * Stored as an encrypted record `_attestations/_signer` under the\n * `_attestations` collection DEK (resolved via `getDEK`, which is\n * AES-KW-wrapped under the owner KEK + persisted by the keyring). The KEK\n * itself is AES-KW-only and cannot AES-GCM-encrypt these bytes — hence\n * storage under a normal collection DEK.\n */\nexport async function loadSigner(\n store: NoydbStore,\n vault: string,\n getDEK: (collection: string) => Promise<EnclaveKey>,\n): Promise<DocSigner | null> {\n const existing = await store.get(vault, ATTESTATIONS_COLLECTION, SIGNER_RECORD_ID)\n if (!existing) return null\n const dek = await getDEK(ATTESTATIONS_COLLECTION)\n const json = await openEnvelopeJson({ collection: ATTESTATIONS_COLLECTION, id: SIGNER_RECORD_ID }, existing, dek)\n return JSON.parse(json) as DocSigner\n}\n\n/**\n * Lazily mint (or load) the firm's Ed25519 document-signing keypair.\n *\n * On a concurrent first-mint, two callers can both read `null` and both mint\n * distinct keypairs. The `put(…, expectedVersion: 0)` (\"must not already\n * exist\") lets exactly one win; the loser catches `ConflictError`, re-reads,\n * and returns the winner's signer — converging on a single keypair rather than\n * clobbering it or surfacing a raw conflict. (All real stores treat a missing\n * record + `ev: 0` as a no-conflict write, so the catch fires on lost-race only.)\n */\nexport async function loadOrCreateSigner(\n store: NoydbStore,\n vault: string,\n getDEK: (collection: string) => Promise<EnclaveKey>,\n): Promise<DocSigner> {\n const existing = await loadSigner(store, vault, getDEK)\n if (existing) return existing\n\n const dek = await getDEK(ATTESTATIONS_COLLECTION)\n const signer = await generateDocSigningKeyPair()\n const identity = { collection: ATTESTATIONS_COLLECTION, id: SIGNER_RECORD_ID, version: 1 }\n const { iv, data } = await encrypt(JSON.stringify(signer), dek, buildRecordAad(identity))\n const env = buildRecordEnvelope(\n identity,\n { iv, data },\n )\n try {\n await store.put(vault, ATTESTATIONS_COLLECTION, SIGNER_RECORD_ID, env, 0)\n return signer\n } catch (e) {\n if (!(e instanceof ConflictError)) throw e\n // Lost the race — another writer minted first. Adopt the winner.\n const winner = await loadSigner(store, vault, getDEK)\n if (!winner) {\n throw new ConflictError(0, 'loadOrCreateSigner: signer mint lost a concurrent race but the winning record could not be re-read.')\n }\n return winner\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;AAGA,SAAS,iCAAiC;AAEnC,IAAM,0BAA0B;AAChC,IAAM,mBAAmB;AACzB,IAAM,oBAAoB;AAmBjC,eAAsB,WACpB,OACA,OACA,QAC2B;AAC3B,QAAM,WAAW,MAAM,MAAM,IAAI,OAAO,yBAAyB,gBAAgB;AACjF,MAAI,CAAC,SAAU,QAAO;AACtB,QAAM,MAAM,MAAM,OAAO,uBAAuB;AAChD,QAAM,OAAO,MAAM,iBAAiB,EAAE,YAAY,yBAAyB,IAAI,iBAAiB,GAAG,UAAU,GAAG;AAChH,SAAO,KAAK,MAAM,IAAI;AACxB;AAYA,eAAsB,mBACpB,OACA,OACA,QACoB;AACpB,QAAM,WAAW,MAAM,WAAW,OAAO,OAAO,MAAM;AACtD,MAAI,SAAU,QAAO;AAErB,QAAM,MAAM,MAAM,OAAO,uBAAuB;AAChD,QAAM,SAAS,MAAM,0BAA0B;AAC/C,QAAM,WAAW,EAAE,YAAY,yBAAyB,IAAI,kBAAkB,SAAS,EAAE;AACzF,QAAM,EAAE,IAAI,KAAK,IAAI,MAAM,QAAQ,KAAK,UAAU,MAAM,GAAG,KAAK,eAAe,QAAQ,CAAC;AACxF,QAAM,MAAM;AAAA,IACV;AAAA,IACA,EAAE,IAAI,KAAK;AAAA,EACb;AACA,MAAI;AACF,UAAM,MAAM,IAAI,OAAO,yBAAyB,kBAAkB,KAAK,CAAC;AACxE,WAAO;AAAA,EACT,SAAS,GAAG;AACV,QAAI,EAAE,aAAa,eAAgB,OAAM;AAEzC,UAAM,SAAS,MAAM,WAAW,OAAO,OAAO,MAAM;AACpD,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,cAAc,GAAG,qGAAqG;AAAA,IAClI;AACA,WAAO;AAAA,EACT;AACF;","names":[]}