@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,9 +1,9 @@
1
1
  import {
2
2
  envelopePayloadHash
3
- } from "./chunk-N4GAJSRQ.js";
3
+ } from "./chunk-FY33DKPH.js";
4
4
  import {
5
5
  NOYDB_FORMAT_VERSION
6
- } from "./chunk-5UGEGEIJ.js";
6
+ } from "./chunk-3Y4OFWQJ.js";
7
7
  import {
8
8
  DictKeyMissingError,
9
9
  PermissionDeniedError
@@ -102,14 +102,17 @@ var LookupHandle = class {
102
102
  _by: this.keyring.userId
103
103
  };
104
104
  }
105
- const envelope = await this.reservedEnvelopes.encrypt(this.collName, JSON.stringify(entry), version);
106
- return { ...envelope, _by: this.keyring.userId };
105
+ return this.reservedEnvelopes.encrypt(
106
+ { collection: this.collName, id: entry.key, by: this.keyring.userId },
107
+ JSON.stringify(entry),
108
+ version
109
+ );
107
110
  }
108
- async decryptEntry(envelope) {
111
+ async decryptEntry(key, envelope) {
109
112
  if (!this.encrypted) {
110
113
  return JSON.parse(envelope._data);
111
114
  }
112
- const json = await this.reservedEnvelopes.decrypt(this.collName, envelope);
115
+ const json = await this.reservedEnvelopes.decrypt(this.collName, key, envelope);
113
116
  return JSON.parse(json);
114
117
  }
115
118
  /** @internal #650 Task 4 — re-read `key`'s CURRENT adapter truth into `_syncCache` (delete the
@@ -123,7 +126,7 @@ var LookupHandle = class {
123
126
  this._syncCache.delete(key);
124
127
  return;
125
128
  }
126
- this._syncCache.set(key, await this.decryptEntry(envelope));
129
+ this._syncCache.set(key, await this.decryptEntry(key, envelope));
127
130
  }
128
131
  // ─── Public API ───────────────────────────────────────────────────
129
132
  /**
@@ -194,7 +197,7 @@ var LookupHandle = class {
194
197
  key
195
198
  );
196
199
  if (!envelope || isDeleteMarker(envelope)) return null;
197
- const entry = await this.decryptEntry(envelope);
200
+ const entry = await this.decryptEntry(key, envelope);
198
201
  return entry.labels;
199
202
  }
200
203
  /**
@@ -280,7 +283,7 @@ var LookupHandle = class {
280
283
  if (!existing || isDeleteMarker(existing)) {
281
284
  throw new DictKeyMissingError(this.dictionaryName, oldKey);
282
285
  }
283
- const oldEntry = await this.decryptEntry(existing);
286
+ const oldEntry = await this.decryptEntry(oldKey, existing);
284
287
  const newEntry = { key: newKey, labels: oldEntry.labels };
285
288
  const newEnvelope = await this.encryptEntry(newEntry, 1);
286
289
  await this.adapter.put(
@@ -353,7 +356,7 @@ var LookupHandle = class {
353
356
  this._syncCache.delete(key);
354
357
  continue;
355
358
  }
356
- const entry = await this.decryptEntry(envelope);
359
+ const entry = await this.decryptEntry(key, envelope);
357
360
  entries.push(entry);
358
361
  this._syncCache.set(key, entry);
359
362
  }
@@ -389,4 +392,4 @@ export {
389
392
  dictCollectionName,
390
393
  LookupHandle
391
394
  };
392
- //# sourceMappingURL=chunk-OXRPH6AR.js.map
395
+ //# sourceMappingURL=chunk-CFTPERGL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/via/lookup/handle.ts"],"sourcesContent":["/**\n * `_dict_*` reserved-collection storage engine — `LookupHandle`.\n *\n * Verbatim move of `DictionaryHandle` out of `via/i18n/dictionary.ts`\n * (#650 Task 1 — via-lookup extraction, phase D). The class is renamed to\n * `LookupHandle` (the dict tier is one backing kind the eventual lookup\n * layer supports); `via/i18n/dictionary.ts` re-exports it as\n * `DictionaryHandle` for one release so existing importers compile\n * unchanged. `DictEntry` / `DictionaryOptions` / `DICT_COLLECTION_PREFIX` /\n * `dictCollectionName` move with it — they were exclusively consumed by\n * this class's constructor/methods.\n *\n * No behavior change from the pre-move class: same encryption door\n * (`reservedEnvelopes('_dict_')`, #629 Task 4), same ACL, same ledger\n * shape, same sync-cache/snapshot contract for dict joins.\n */\n\nimport type { NoydbStore, EncryptedEnvelope } from '../../kernel/types.js'\nimport type { NoydbEventEmitter } from '../../kernel/events.js'\nimport { NOYDB_FORMAT_VERSION } from '../../kernel/types.js'\nimport type { UnlockedKeyring } from '../../with-party/team/keyring.js'\nimport type { ViaCryptoCtx } from '../../kernel/via/index.js'\nimport type { LedgerStore } from '../../with-commit/history/ledger/store.js'\nimport { envelopePayloadHash } from '../../with-commit/history/ledger/hash.js'\nimport {\n PermissionDeniedError,\n DictKeyMissingError,\n} from '../../kernel/errors.js'\n\n/**\n * Delete-marker predicate, duplicated (not imported) from\n * `kernel/enclave/record-keys/tombstone.ts`'s `isDeleteMarker` (#647 fix wave 1).\n * `via/lookup/**` may not statically import `kernel/enclave/` — not even the barrel\n * (Check 15, `via-enclave-isolation`) — and this predicate carries zero crypto/protected-body\n * surface (just the `_del` protocol-header field, not `_iv`/`_data`), so duplicating it here\n * mirrors the same call `port/with/i18n-strategy.ts` already makes for `isDictCollectionName`\n * (see its doc comment). Keep the two in sync if the marker shape ever changes.\n *\n * `buildDeleteMarker` (which DOES construct the protected `_iv`/`_data` body fields — Check 11,\n * `enclave-body-only`) can't be duplicated the same way; it's injected via the constructor\n * instead, built from the real `kernel/enclave` function at the Vault call site.\n */\nfunction isDeleteMarker(envelope: EncryptedEnvelope): boolean {\n return envelope._del === true\n}\n\n/** Reserved collection name prefix. Never collides with user collections. */\nexport const DICT_COLLECTION_PREFIX = '_dict_'\n\n/** Return the adapter collection name for a named dictionary. */\nexport function dictCollectionName(dictionaryName: string): string {\n return `${DICT_COLLECTION_PREFIX}${dictionaryName}`\n}\n\n// ─── Dictionary entry shape ────────────────────────────────────────────\n\n/**\n * One entry in a `_dict_*` collection. The record `id` (adapter-side\n * key) IS the stable dictionary key (e.g. `'paid'`). The `labels`\n * record maps locale codes to display strings.\n */\nexport interface DictEntry {\n /** Stable key — same as the record id in the adapter. */\n readonly key: string\n /** Locale → label map, e.g. `{ en: 'Paid', th: 'ชำระแล้ว' }`. */\n readonly labels: Record<string, string>\n}\n\n// ─── Per-dictionary options ────────────────────────────────────────────\n\n/**\n * Options for `vault.dictionary(name, options?)`.\n *\n * `writableBy` controls the minimum role for write operations (put,\n * putAll, delete, rename). Defaults to `'admin'` to match the standard\n * \"dictionary contents are owned by admins\" convention; set to\n * `'operator'` for user-editable dictionaries like custom tags.\n */\nexport interface DictionaryOptions {\n /** Minimum role allowed to write dictionary entries. Default: `'admin'`. */\n readonly writableBy?: 'owner' | 'admin' | 'operator'\n}\n\n// ─── LookupHandle ───────────────────────────────────────────────────────\n\n/**\n * Handle to a named dictionary within a vault.\n *\n * Obtained via `vault.dictionary(name)`. Provides strongly-typed\n * CRUD for dictionary entries, plus the `rename()` operation that is the\n * only sanctioned mass-mutation path for dictKey fields.\n *\n * All writes are encrypted under the compartment's DEK for the\n * `_dict_<name>` collection. Adapters never see plaintext.\n */\nexport class LookupHandle<Keys extends string = string> {\n private readonly collName: string\n\n /**\n * Synchronous write-through cache for dict-join support.\n * Populated on every `put()`, `delete()`, and `rename()`. The snapshot\n * is built from this cache by `snapshotEntries()` — the query executor\n * calls this synchronously inside `.toArray()`.\n *\n * `null` means \"not yet initialized\" — callers should use `list()`\n * to warm the cache before using dict joins on pre-existing data.\n */\n private readonly _syncCache = new Map<string, DictEntry>()\n\n /**\n * Return all cached entries as `{ key, labels, ...labels }` records —\n * usable synchronously by the join executor's `snapshot()` call.\n * Returns an empty array when the cache has never been populated.\n */\n snapshotEntries(): readonly Record<string, unknown>[] {\n return Array.from(this._syncCache.values()).map((e) => ({\n key: e.key,\n labels: e.labels,\n ...e.labels,\n }))\n }\n\n constructor(\n private readonly adapter: NoydbStore,\n private readonly compartmentName: string,\n private readonly dictionaryName: string,\n private readonly keyring: UnlockedKeyring,\n /**\n * The `reservedEnvelopes('_dict_')` capability — this handle's sanctioned\n * crypto door onto its `_dict_<name>` collection (#629 Task 4). Bound by\n * the Vault; never a keyring, raw DEK, or enclave import.\n */\n private readonly reservedEnvelopes: ReturnType<ViaCryptoCtx['reservedEnvelopes']>,\n private readonly encrypted: boolean,\n private readonly ledger: LedgerStore | undefined,\n private readonly options: DictionaryOptions,\n /**\n * Callback provided by the Vault to find and rewrite records\n * in any registered collection that has a dictKeyField pointing at\n * this dictionary, used by `rename()`.\n */\n private readonly findAndUpdateReferences:\n | ((\n dictionaryName: string,\n oldKey: string,\n newKey: string,\n ) => Promise<void>)\n | undefined,\n private readonly emitter: NoydbEventEmitter,\n /**\n * #647 fix wave 1 — mints a version-ordered delete-marker envelope (the reserved-tier\n * mirror of #589's ordinary-collection delete marker). Injected rather than imported:\n * `buildDeleteMarker` constructs the envelope's protected-body fields (`_iv`/`_data`), and\n * `via/lookup/**` may not reach `kernel/enclave/` directly (Check 11\n * `enclave-body-only` / Check 15 `via-enclave-isolation`) — the Vault binds the real\n * `kernel/enclave` function at construction time, same pattern as `reservedEnvelopes` above.\n */\n private readonly buildDeleteMarker: (identity: { collection: string; id: string }, version: number, actor: string) => EncryptedEnvelope,\n /** #650 Task 4 (#647) — dirty-log participation hook (origin `local-write`), threaded from `BuildLookupHandleOptions`. */\n private readonly onDirty?: (collection: string, id: string, action: 'put' | 'delete', version: number) => Promise<void>,\n /** #650 Task 4 — thin `graphDispatch.collect`-equivalent; opens/collects/flushes a one-shot wave for this touch. */\n private readonly onRecordMutated?: (collection: string, id: string, action: 'put' | 'delete', version: number) => Promise<void>,\n /** #650 Task 5 (#648) — the real reference check `delete()`'s strict branch calls: restrict\n * throws `DictKeyInUseError`, cascade/nullify apply their propagation. Vault-bound; a no-op\n * when the dimension has no declared lookup-referencing edges. */\n private readonly checkReferencesOnDelete?: (key: string) => Promise<unknown>,\n ) {\n this.collName = dictCollectionName(dictionaryName)\n }\n\n // ─── Access checks ────────────────────────────────────────────────\n\n private requireWriteAccess(): void {\n const minRole = this.options.writableBy ?? 'admin'\n const roleRank: Record<string, number> = {\n client: 1,\n viewer: 2,\n operator: 3,\n admin: 4,\n owner: 5,\n }\n const callerRank = roleRank[this.keyring.role] ?? 0\n const requiredRank = roleRank[minRole] ?? 4\n if (callerRank < requiredRank) {\n throw new PermissionDeniedError(\n `Dictionary \"${this.dictionaryName}\" writes require \"${minRole}\" role or above. ` +\n `Current role: \"${this.keyring.role}\".`,\n )\n }\n }\n\n // ─── Internal helpers ─────────────────────────────────────────────\n\n private async encryptEntry(entry: DictEntry, version: number): Promise<EncryptedEnvelope> {\n if (!this.encrypted) {\n // Plaintext/debug vault: no AEAD, therefore no AAD to bind — this literal\n // has nothing `buildRecordEnvelope` could authenticate, and `via/lookup/**`\n // may not import `kernel/enclave/` to reach it anyway (Check 15,\n // `via-enclave-isolation`). The ENCRYPTED branch below is the one that\n // matters, and it is bound: `reservedEnvelopes.encrypt` holds the DEK, so\n // it is where identity AAD is applied (#1051).\n return {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: version,\n _ts: new Date().toISOString(),\n _iv: '',\n _data: JSON.stringify(entry),\n _by: this.keyring.userId,\n }\n }\n // `entry.key` IS the record id this envelope is stored under. `_by` goes\n // IN, not on afterwards: stamping it on the returned envelope would leave\n // it outside the AAD the door just sealed (#1041).\n return this.reservedEnvelopes.encrypt(\n { collection: this.collName, id: entry.key, by: this.keyring.userId },\n JSON.stringify(entry),\n version,\n )\n }\n\n private async decryptEntry(key: string, envelope: EncryptedEnvelope): Promise<DictEntry> {\n if (!this.encrypted) {\n return JSON.parse(envelope._data) as DictEntry\n }\n // `key` IS the record id this envelope is stored under, and the identity the\n // writer sealed it against (#1041).\n const json = await this.reservedEnvelopes.decrypt(this.collName, key, envelope)\n return JSON.parse(json) as DictEntry\n }\n\n /** @internal #650 Task 4 — re-read `key`'s CURRENT adapter truth into `_syncCache` (delete the\n * cache entry when the key is now gone). Called by `Vault._invalidateSyncApplied` after a\n * reserved-lookup row applies via sync, so an already-warmed snapshot/membership/altIndex read\n * never sees a stale verdict for a pulled vocabulary edit — the same invalidation a local\n * put()/delete()/rename() already triggers via `_syncCache.set`/`delete` above. */\n async _refreshSyncCache(key: string): Promise<void> {\n const envelope = await this.adapter.get(this.compartmentName, this.collName, key)\n if (!envelope || isDeleteMarker(envelope)) { this._syncCache.delete(key); return }\n this._syncCache.set(key, await this.decryptEntry(key, envelope))\n }\n\n // ─── Public API ───────────────────────────────────────────────────\n\n /**\n * Add or overwrite a single dictionary entry.\n *\n * @param key The stable key to store (e.g. `'paid'`).\n * @param labels Locale → label map (e.g. `{ en: 'Paid', th: 'ชำระแล้ว' }`).\n */\n async put(key: Keys, labels: Record<string, string>): Promise<void> {\n this.requireWriteAccess()\n\n const entry: DictEntry = { key, labels }\n const existing = await this.adapter.get(\n this.compartmentName,\n this.collName,\n key,\n )\n const version = existing ? existing._v + 1 : 1\n const envelope = await this.encryptEntry(entry, version)\n\n await this.adapter.put(\n this.compartmentName,\n this.collName,\n key,\n envelope,\n existing ? existing._v : undefined,\n )\n\n // Maintain synchronous cache for dict-join snapshot\n this._syncCache.set(key, entry)\n\n // #650 Task 4 (#647) — choke-point participation: dirty-log tracking BEFORE the emit (mirrors\n // Collection._onRecordMutated's local-write order), then the wave-open hook AFTER.\n await this.onDirty?.(this.collName, key, 'put', version)\n\n this.emitter.emit('change', {\n vault: this.compartmentName,\n collection: this.collName,\n id: key,\n action: 'put',\n })\n\n await this.onRecordMutated?.(this.collName, key, 'put', version)\n\n if (this.ledger) {\n await this.ledger.append({\n op: 'put',\n collection: this.collName,\n id: key,\n version,\n actor: this.keyring.userId,\n // — must be the real envelope hash so\n // vault.verifyBackupIntegrity()'s data-cross-check matches.\n payloadHash: await envelopePayloadHash(envelope),\n })\n }\n }\n\n /**\n * Batch-add or overwrite multiple dictionary entries in one call.\n *\n * @param entries `{ key: { locale: label } }` map.\n */\n async putAll(entries: Record<Keys, Record<string, string>>): Promise<void> {\n this.requireWriteAccess()\n for (const [key, labels] of Object.entries(entries) as [Keys, Record<string, string>][]) {\n await this.put(key, labels)\n }\n }\n\n /**\n * Load the label map for a single key.\n *\n * @returns The label map, or `null` if the key doesn't exist.\n */\n async get(key: Keys): Promise<Record<string, string> | null> {\n const envelope = await this.adapter.get(\n this.compartmentName,\n this.collName,\n key,\n )\n if (!envelope || isDeleteMarker(envelope)) return null\n const entry = await this.decryptEntry(key, envelope)\n return entry.labels\n }\n\n /**\n * Delete a dictionary key.\n *\n * Default mode is `'strict'` — throws `DictKeyInUseError` if any\n * registered collection has a record referencing this key. Pass\n * `{ mode: 'warn' }` to skip the check (dev-mode cleanup only).\n *\n * Under sync, deletion writes a version-ordered delete-marker row rather than removing the\n * adapter key outright (#647 fix wave 1) — markers accumulate over time; GC is future work,\n * acceptable for vocabulary-scale data.\n */\n async delete(key: Keys, opts: { mode?: 'strict' | 'warn' } = {}): Promise<void> {\n this.requireWriteAccess()\n\n const existing = await this.adapter.get(\n this.compartmentName,\n this.collName,\n key,\n )\n if (!existing || isDeleteMarker(existing)) {\n throw new DictKeyMissingError(this.dictionaryName, key)\n }\n\n // #650 Task 5 (#648) — the real reference check: restrict throws `DictKeyInUseError` naming\n // the referencing collection, cascade/nullify apply their propagation. `mode: 'warn'` skips\n // this entirely (today's dev-mode-cleanup escape hatch, unconditional delete). A dimension\n // with no declared lookup-referencing edges is a no-op (undeclared refs keep dangling).\n const mode = opts.mode ?? 'strict'\n if (mode === 'strict') {\n await this.checkReferencesOnDelete?.(key)\n }\n\n // #647 fix wave 1 — mirrors Collection._doDelete's identical `this.onDirty`-gated branch\n // (#589): under sync, a raw adapter.delete() is invisible to a peer's next pull (the key\n // simply stops appearing in remote.list()) — a deleted key never propagates and can be\n // silently resurrected by a later edit. Write a version-ordered DELETE-MARKER instead, so\n // the removal round-trips like any other row. No-op (plain adapter.delete) when sync isn't wired.\n const nextVersion = existing._v + 1\n if (this.onDirty) {\n await this.adapter.put(this.compartmentName, this.collName, key, this.buildDeleteMarker({ collection: this.collName, id: key }, nextVersion, this.keyring.userId))\n } else {\n await this.adapter.delete(this.compartmentName, this.collName, key)\n }\n\n // Maintain synchronous cache for dict-join snapshot\n this._syncCache.delete(key)\n\n // #650 Task 4 (#647) — same choke-point ordering as put() above.\n // #647 fix wave 1: the dirty entry's ACTION is 'put' (not 'delete') — mirrors\n // Collection._onRecordMutated's 'local-delete' case exactly: the marker rides push's\n // CAS-put path, not push's raw remote.delete() path (which would strip the marker off the\n // remote too and reopen this same hole). The version is the MARKER's version, so push's CAS\n // (expectedVersion = entry.version - 1) matches the pre-delete remote copy.\n await this.onDirty?.(this.collName, key, 'put', nextVersion)\n\n this.emitter.emit('change', {\n vault: this.compartmentName,\n collection: this.collName,\n id: key,\n action: 'delete',\n })\n\n await this.onRecordMutated?.(this.collName, key, 'delete', nextVersion)\n\n if (this.ledger) {\n await this.ledger.append({\n op: 'delete',\n collection: this.collName,\n id: key,\n version: existing._v,\n actor: this.keyring.userId,\n // — for delete the prior envelope is what was just\n // removed; we hash it so the chain captures intent. The\n // verifyBackupIntegrity data-cross-check skips delete\n // entries entirely (the live record is gone), but the\n // chain still benefits from a stable non-empty hash.\n payloadHash: await envelopePayloadHash(existing),\n })\n }\n }\n\n /**\n * Rename a dictionary key — the only sanctioned mass-mutation path.\n *\n * Atomically:\n * 1. Adds the new key with the same labels as the old key.\n * 2. Updates every registered record that stores the old key to\n * store the new key instead.\n * 3. Deletes the old key.\n * 4. Appends a single ledger entry recording the rename.\n *\n * Respects ACL: throws `PermissionDeniedError` before any mutation\n * if the caller can't write. The cascade is best-effort atomic\n * within this call — no two-phase commit across adapter calls.\n *\n * Cascade-on-delete is NOT supported. Use `rename()` when you need\n * to change a key that records reference.\n */\n async rename(oldKey: Keys, newKey: string): Promise<void> {\n this.requireWriteAccess()\n\n // 1. Load old entry\n const existing = await this.adapter.get(\n this.compartmentName,\n this.collName,\n oldKey,\n )\n if (!existing || isDeleteMarker(existing)) {\n throw new DictKeyMissingError(this.dictionaryName, oldKey)\n }\n const oldEntry = await this.decryptEntry(oldKey, existing)\n\n // 2. Write new key\n const newEntry: DictEntry = { key: newKey, labels: oldEntry.labels }\n const newEnvelope = await this.encryptEntry(newEntry, 1)\n await this.adapter.put(\n this.compartmentName,\n this.collName,\n newKey,\n newEnvelope,\n )\n\n // #670 — publish newKey to the sync cache BEFORE step 3 rewrites referencing records: a\n // vocabulary:'closed' referencing field's enforceWrite reads checkLookupMembership ->\n // snapshotEntries() -> this._syncCache, so if newKey isn't a member yet, step 3's own write of\n // newKey into those records self-refuses with UnknownLookupKeyError. Transition semantics:\n // mid-rename BOTH oldKey and newKey are legitimately members (records are transitioning\n // old->new during the rewrite) — oldKey stays a member until its removal completes below.\n this._syncCache.set(newKey, newEntry)\n\n // 3. Update all referencing records in registered collections\n if (this.findAndUpdateReferences) {\n await this.findAndUpdateReferences(this.dictionaryName, oldKey, newKey)\n }\n\n // 4. Remove old key — #647 fix wave 1: same delete-marker convention as delete() above, so\n // the old key's removal propagates on sync instead of leaving a phantom stale row on a peer\n // that only observes the new key arriving.\n const oldKeyNextVersion = existing._v + 1\n if (this.onDirty) {\n await this.adapter.put(this.compartmentName, this.collName, oldKey, this.buildDeleteMarker({ collection: this.collName, id: oldKey }, oldKeyNextVersion, this.keyring.userId))\n } else {\n await this.adapter.delete(this.compartmentName, this.collName, oldKey)\n }\n\n // Maintain synchronous cache for dict-join snapshot — oldKey's removal from the cache lands\n // here (after step 3), completing the old->new membership transition begun above.\n this._syncCache.delete(oldKey)\n\n // #650 Task 4 (#647) — same choke-point ordering as put()/delete() above, for BOTH touches.\n // #647 fix wave 1: oldKey's dirty action is 'put' (not 'delete') — see delete()'s comment\n // above for why the marker must ride push's CAS-put path, at the marker's version.\n await this.onDirty?.(this.collName, oldKey, 'put', oldKeyNextVersion)\n this.emitter.emit('change', {\n vault: this.compartmentName,\n collection: this.collName,\n id: oldKey,\n action: 'delete',\n })\n await this.onRecordMutated?.(this.collName, oldKey, 'delete', oldKeyNextVersion)\n\n await this.onDirty?.(this.collName, newKey, 'put', 1)\n this.emitter.emit('change', {\n vault: this.compartmentName,\n collection: this.collName,\n id: newKey,\n action: 'put',\n })\n await this.onRecordMutated?.(this.collName, newKey, 'put', 1)\n\n // 5. Ledger — record the rename as delete(oldKey) + put(newKey)\n // so verifyBackupIntegrity()'s data-cross-check matches reality\n // (the oldKey envelope is gone; the newKey envelope is what was\n // just written). Two entries instead of one — the chain still\n // captures the rename intent via the matching ts + actor.\n if (this.ledger) {\n await this.ledger.append({\n op: 'delete',\n collection: this.collName,\n id: oldKey,\n version: existing._v,\n actor: this.keyring.userId,\n payloadHash: await envelopePayloadHash(existing),\n })\n await this.ledger.append({\n op: 'put',\n collection: this.collName,\n id: newKey,\n version: 1,\n actor: this.keyring.userId,\n payloadHash: await envelopePayloadHash(newEnvelope),\n })\n }\n }\n\n /**\n * List all entries in this dictionary.\n *\n * @returns Array of `{ key, labels }` objects.\n */\n async list(): Promise<DictEntry[]> {\n const keys = await this.adapter.list(this.compartmentName, this.collName)\n const entries: DictEntry[] = []\n for (const key of keys) {\n const envelope = await this.adapter.get(\n this.compartmentName,\n this.collName,\n key,\n )\n // #647 fix wave 1 — a delete-marker row is a removed key, not a live entry: exclude it\n // from the listing and drop any stale cache entry a prior warm may have left under it.\n if (!envelope || isDeleteMarker(envelope)) { this._syncCache.delete(key); continue }\n const entry = await this.decryptEntry(key, envelope)\n entries.push(entry)\n // Warm the synchronous cache\n this._syncCache.set(key, entry)\n }\n return entries\n }\n\n /**\n * Resolve a key to its label for the given locale.\n *\n * Used by the collection's locale-aware read path to populate\n * `<field>Label` virtual fields. Returns `undefined` when the\n * key doesn't exist or has no label for the requested locale\n * (after exhausting the fallback chain).\n */\n async resolveLabel(\n key: string,\n locale: string,\n fallback?: string | readonly string[],\n ): Promise<string | undefined> {\n const labels = await this.get(key as Keys)\n if (!labels) return undefined\n\n // Try primary locale\n if (labels[locale] !== undefined) return labels[locale]\n\n // Try fallback chain\n const chain = Array.isArray(fallback) ? (fallback as readonly string[]) : fallback ? [fallback as string] : []\n for (const fb of chain) {\n if (fb === 'any') {\n // Return any available label\n const any = Object.values(labels)[0]\n if (any !== undefined) return any\n } else if (labels[fb] !== undefined) {\n return labels[fb]\n }\n }\n\n return undefined\n }\n}\n\n// Compat alias — existing importers of `DictionaryHandle` (the pre-#650\n// name) keep compiling unchanged. `via/i18n/dictionary.ts` re-exports\n// this same binding for one release.\nexport { LookupHandle as DictionaryHandle }\n"],"mappings":"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","names":[]}
@@ -1,131 +1,17 @@
1
1
  import {
2
- liveRecordIsElevated
3
- } from "./chunk-AMKCY454.js";
2
+ getHistory,
3
+ historyIdentity
4
+ } from "./chunk-UIYZ5SOU.js";
4
5
  import {
5
- isRewrappedUnder,
6
- openEnvelopeJson,
7
- rewrapEnvelope
8
- } from "./chunk-BKYQNNO3.js";
6
+ liveRecordIsElevated
7
+ } from "./chunk-7WD2G6K4.js";
9
8
  import {
10
- buildRecordEnvelope,
11
- isTombstone,
12
- isTombstoneShape
13
- } from "./chunk-RGPB25DB.js";
9
+ openEnvelopeJson
10
+ } from "./chunk-X3AXSYBL.js";
14
11
  import {
15
12
  ReadOnlyAtInstantError
16
13
  } from "./chunk-I64WQSN3.js";
17
14
 
18
- // src/with-commit/history/history.ts
19
- var HISTORY_COLLECTION = "_history";
20
- var VERSION_PAD = 10;
21
- function historyId(collection, recordId, version) {
22
- return `${collection}:${recordId}:${String(version).padStart(VERSION_PAD, "0")}`;
23
- }
24
- function matchesPrefix(id, collection, recordId) {
25
- if (recordId) {
26
- return id.startsWith(`${collection}:${recordId}:`);
27
- }
28
- return id.startsWith(`${collection}:`);
29
- }
30
- async function saveHistory(adapter, vault, collection, recordId, envelope) {
31
- const id = historyId(collection, recordId, envelope._v);
32
- await adapter.put(vault, HISTORY_COLLECTION, id, envelope);
33
- }
34
- async function getHistory(adapter, vault, collection, recordId, options) {
35
- const allIds = await adapter.list(vault, HISTORY_COLLECTION);
36
- const matchingIds = allIds.filter((id) => matchesPrefix(id, collection, recordId)).sort().reverse();
37
- const entries = [];
38
- for (const id of matchingIds) {
39
- const envelope = await adapter.get(vault, HISTORY_COLLECTION, id);
40
- if (!envelope) continue;
41
- if (options?.from && envelope._ts < options.from) continue;
42
- if (options?.to && envelope._ts > options.to) continue;
43
- entries.push(envelope);
44
- if (options?.limit && entries.length >= options.limit) break;
45
- }
46
- return entries;
47
- }
48
- async function getVersionEnvelope(adapter, vault, collection, recordId, version) {
49
- const id = historyId(collection, recordId, version);
50
- return adapter.get(vault, HISTORY_COLLECTION, id);
51
- }
52
- async function pruneHistory(adapter, vault, collection, recordId, options) {
53
- const allIds = await adapter.list(vault, HISTORY_COLLECTION);
54
- const matchingIds = allIds.filter((id) => recordId ? matchesPrefix(id, collection, recordId) : matchesPrefix(id, collection)).sort();
55
- let toDelete = [];
56
- if (options.keepVersions !== void 0) {
57
- const keep = options.keepVersions;
58
- if (matchingIds.length > keep) {
59
- toDelete = matchingIds.slice(0, matchingIds.length - keep);
60
- }
61
- }
62
- if (options.beforeDate) {
63
- for (const id of matchingIds) {
64
- if (toDelete.includes(id)) continue;
65
- const envelope = await adapter.get(vault, HISTORY_COLLECTION, id);
66
- if (envelope && envelope._ts < options.beforeDate) {
67
- toDelete.push(id);
68
- }
69
- }
70
- }
71
- const uniqueDeletes = [...new Set(toDelete)];
72
- for (const id of uniqueDeletes) {
73
- await adapter.delete(vault, HISTORY_COLLECTION, id);
74
- }
75
- return uniqueDeletes.length;
76
- }
77
- async function clearHistory(adapter, vault, collection, recordId) {
78
- const allIds = await adapter.list(vault, HISTORY_COLLECTION);
79
- let toDelete;
80
- if (collection && recordId) {
81
- toDelete = allIds.filter((id) => matchesPrefix(id, collection, recordId));
82
- } else if (collection) {
83
- toDelete = allIds.filter((id) => matchesPrefix(id, collection));
84
- } else {
85
- toDelete = allIds;
86
- }
87
- for (const id of toDelete) {
88
- await adapter.delete(vault, HISTORY_COLLECTION, id);
89
- }
90
- return toDelete.length;
91
- }
92
- async function tombstoneHistory(adapter, vault, collection, recordId, actor, encrypted) {
93
- const allIds = await adapter.list(vault, HISTORY_COLLECTION);
94
- const matchingIds = allIds.filter((id) => matchesPrefix(id, collection, recordId));
95
- const now = (/* @__PURE__ */ new Date()).toISOString();
96
- let count = 0;
97
- for (const id of matchingIds) {
98
- const env = await adapter.get(vault, HISTORY_COLLECTION, id);
99
- if (!env) continue;
100
- if (isTombstone(env, encrypted)) continue;
101
- const tombstone = buildRecordEnvelope(
102
- { collection: HISTORY_COLLECTION, id },
103
- { version: env._v, ts: now, iv: "", data: "", ...actor ? { by: actor } : {} }
104
- );
105
- await adapter.put(vault, HISTORY_COLLECTION, id, tombstone);
106
- count++;
107
- }
108
- return count;
109
- }
110
- async function rewrapHistory(adapter, vault, collection, recordId, fromDek, toDek, tier0Dek) {
111
- const allIds = await adapter.list(vault, HISTORY_COLLECTION);
112
- const matchingIds = allIds.filter((id) => matchesPrefix(id, collection, recordId));
113
- for (const id of matchingIds) {
114
- const env = await adapter.get(vault, HISTORY_COLLECTION, id);
115
- if (!env) continue;
116
- if (isTombstoneShape(env)) continue;
117
- if (await isRewrappedUnder(env, toDek)) continue;
118
- let next;
119
- try {
120
- next = await rewrapEnvelope(env, fromDek, toDek);
121
- } catch (err) {
122
- if (!tier0Dek) throw err;
123
- next = await rewrapEnvelope(env, tier0Dek, toDek);
124
- }
125
- await adapter.put(vault, HISTORY_COLLECTION, id, next);
126
- }
127
- }
128
-
129
15
  // src/with-commit/history/time-machine.ts
130
16
  var VaultInstant = class {
131
17
  constructor(engine, timestamp) {
@@ -164,9 +50,9 @@ var CollectionInstant = class {
164
50
  * DEK directly.
165
51
  */
166
52
  async get(id) {
167
- const envelope = await this.resolveVisibleEnvelope(id);
168
- if (!envelope) return null;
169
- const plaintext = this.engine.encrypted ? await openEnvelopeJson(envelope, await this.engine.getDEK(this.name)) : envelope._data;
53
+ const found = await this.resolveVisibleEnvelope(id);
54
+ if (!found) return null;
55
+ const plaintext = this.engine.encrypted ? await openEnvelopeJson(found.ref, found.envelope, await this.engine.getDEK(this.name)) : found.envelope._data;
170
56
  return JSON.parse(plaintext);
171
57
  }
172
58
  /**
@@ -213,10 +99,10 @@ var CollectionInstant = class {
213
99
  * just a decrypt failure.
214
100
  */
215
101
  async resolveVisibleEnvelope(id) {
216
- const envelope = await this.resolveEnvelope(id);
217
- if (!envelope || (envelope._tier ?? 0) > 0) return null;
102
+ const found = await this.resolveEnvelope(id);
103
+ if (!found || (found.envelope._tier ?? 0) > 0) return null;
218
104
  if (await liveRecordIsElevated(this.engine.adapter, this.engine.name, this.name, id)) return null;
219
- return envelope;
105
+ return found;
220
106
  }
221
107
  /**
222
108
  * Return the envelope that represents the record's state at
@@ -277,12 +163,14 @@ var CollectionInstant = class {
277
163
  );
278
164
  const live = await this.engine.adapter.get(this.engine.name, this.name, id);
279
165
  const byVersion = /* @__PURE__ */ new Map();
280
- for (const e of history) byVersion.set(e._v, e);
281
- if (live) byVersion.set(live._v, live);
166
+ for (const e of history) {
167
+ byVersion.set(e._v, { envelope: e, ref: historyIdentity(this.name, id, e._v) });
168
+ }
169
+ if (live) byVersion.set(live._v, { envelope: live, ref: { collection: this.name, id } });
282
170
  const sorted = [...byVersion.values()].sort(
283
- (a, b) => a._ts < b._ts ? 1 : a._ts > b._ts ? -1 : 0
171
+ (a, b) => a.envelope._ts < b.envelope._ts ? 1 : a.envelope._ts > b.envelope._ts ? -1 : 0
284
172
  );
285
- return sorted.find((e) => e._ts <= this.targetTs) ?? null;
173
+ return sorted.find((e) => e.envelope._ts <= this.targetTs) ?? null;
286
174
  }
287
175
  /**
288
176
  * Fetch the envelope for a specific version. The live record (most
@@ -294,9 +182,12 @@ var CollectionInstant = class {
294
182
  */
295
183
  async loadVersion(id, version) {
296
184
  const live = await this.engine.adapter.get(this.engine.name, this.name, id);
297
- if (live && live._v === version) return live;
298
- const historyId2 = `${this.name}:${id}:${String(version).padStart(10, "0")}`;
299
- return await this.engine.adapter.get(this.engine.name, "_history", historyId2);
185
+ if (live && live._v === version) {
186
+ return { envelope: live, ref: { collection: this.name, id } };
187
+ }
188
+ const ref = historyIdentity(this.name, id, version);
189
+ const envelope = await this.engine.adapter.get(this.engine.name, ref.collection, ref.id);
190
+ return envelope ? { envelope, ref } : null;
300
191
  }
301
192
  };
302
193
  async function collectHistoryIds(adapter, vault, collection) {
@@ -314,14 +205,7 @@ async function collectHistoryIds(adapter, vault, collection) {
314
205
  }
315
206
 
316
207
  export {
317
- saveHistory,
318
- getHistory,
319
- getVersionEnvelope,
320
- pruneHistory,
321
- clearHistory,
322
- tombstoneHistory,
323
- rewrapHistory,
324
208
  VaultInstant,
325
209
  CollectionInstant
326
210
  };
327
- //# sourceMappingURL=chunk-AKFNLRA2.js.map
211
+ //# sourceMappingURL=chunk-CGQUSSW7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/with-commit/history/time-machine.ts"],"sourcesContent":["/**\n * Time-machine queries — point-in-time reads reconstructed from the\n * existing history + ledger infrastructure.\n *\n * ## Usage\n *\n * ```ts\n * const vault = await db.openVault('acme', { secret })\n * const q1End = vault.at('2026-03-31T23:59:59Z')\n * const invoice = await q1End.collection<Invoice>('invoices').get('inv-001')\n * // → the record as it stood at the close of Q1 2026\n * ```\n *\n * ## How it works\n *\n * Every write path already fans out into two persistence lanes:\n *\n * 1. `saveHistory(...)` persists a **full encrypted envelope snapshot**\n * per version under the `_history` collection (one envelope per\n * version, keyed by `{collection}:{id}:{paddedVersion}`). Each\n * envelope carries its own `_ts` (the write timestamp).\n * 2. `ledger.append(...)` appends a hash-chained audit entry that\n * records the `op` (put / delete), `version`, and `ts`.\n *\n * Reconstruction at a target timestamp T is therefore:\n *\n * - Find the newest history envelope for `(collection, id)` whose\n * `_ts ≤ T` — that's the state the record was in at T.\n * - Check the ledger for any `op: 'delete'` entry for the same\n * `(collection, id)` with `entry.ts` in `(latestEnvelope._ts, T]` —\n * if present, the record was deleted before T, so return `null`.\n * - Decrypt the surviving envelope with the current collection DEK\n * (DEKs are per-collection but stable across versions — the same\n * key encrypts v1 and v15 of a record).\n *\n * No delta replay. The existing `history.ts` module already stores\n * complete snapshots; we just pick the right one.\n *\n * ## Read-only contract\n *\n * Every write method on `CollectionInstant` throws\n * {@link ReadOnlyAtInstantError}. A historical view is a *read*\n * surface — mutating the past would require either a branch/shadow\n * mechanism (tracked under shadow vaults) or a rewrite of\n * history, which breaks the ledger's tamper-evidence guarantee.\n *\n * @module\n */\nimport type { EncryptedEnvelope, NoydbStore } from '../../kernel/types.js'\nimport type { LedgerStore } from './ledger/store.js'\nimport { getHistory, historyIdentity } from './history.js'\n\n/**\n * An envelope together with **the address it was fetched from**.\n *\n * The time machine resolves a record's state at an instant from two different\n * places — the live collection, or a `_history` snapshot — and those are sealed\n * against different identities (#1041). Returning the envelope alone discards\n * the one fact the reader needs to open it, which is precisely the read-side\n * data-flow gap that binding identity exposes.\n */\ninterface ResolvedEnvelope {\n readonly envelope: EncryptedEnvelope\n readonly ref: { readonly collection: string; readonly id: string }\n}\nimport { openEnvelopeJson, type EnclaveKey } from '../../kernel/enclave/index.js'\nimport { ReadOnlyAtInstantError } from '../../kernel/errors.js'\nimport { liveRecordIsElevated } from '../../kernel/tier-visibility.js'\n\n/**\n * Narrow view of a {@link Vault}'s internals that\n * {@link VaultInstant} needs. Passed in by `Vault.at()` rather than\n * constructed here so all crypto + adapter access stays inside the\n * Vault class.\n *\n * Not exported from the public barrel — consumers should get a\n * `VaultInstant` via `vault.at(ts)`, never by constructing one\n * directly.\n */\nexport interface VaultEngine {\n readonly adapter: NoydbStore\n /** Vault name (the compartment). */\n readonly name: string\n /**\n * `true` when the vault was opened with a secret (the normal\n * case). `false` in plaintext-mode vaults (`encrypt: false`) — in\n * that case `envelope._data` is raw JSON and we skip the DEK lookup.\n */\n readonly encrypted: boolean\n /**\n * Resolves the DEK used to decrypt a given collection's envelopes.\n * Not called when `encrypted` is false.\n */\n getDEK(collection: string): Promise<EnclaveKey>\n /**\n * Lazily-initialised ledger. We consult it to detect deletes that\n * happened between the latest history snapshot and the target\n * timestamp. `null` when history is disabled for this vault — in\n * that case time-machine reads fall back to history-only\n * reconstruction (which may miss deletes).\n */\n getLedger(): LedgerStore | null\n}\n\n/**\n * A vault at a fixed instant. Produced by `vault.at(timestamp)`.\n * Carries no session state of its own — every read is a fresh\n * lookup through the vault's adapter.\n *\n * Cheap to construct; safe to throw away. Create one per query.\n */\nexport class VaultInstant {\n constructor(\n private readonly engine: VaultEngine,\n /** Fully-resolved target timestamp (ISO-8601 UTC). */\n public readonly timestamp: string,\n ) {}\n\n /** Get a point-in-time view of a collection. */\n collection<T = unknown>(name: string): CollectionInstant<T> {\n return new CollectionInstant<T>(this.engine, this.timestamp, name)\n }\n}\n\n/**\n * A read-only collection view anchored to a past instant.\n *\n * Every write method throws {@link ReadOnlyAtInstantError} — see the\n * module docstring for why. The read surface is intentionally smaller\n * than the live {@link Collection}: `get` and `list` cover the\n * \"what did the books look like on date X\" use case without pulling\n * in the full query DSL / joins / aggregates at this stage. Follow-up\n * work tracked under.\n */\nexport class CollectionInstant<T = unknown> {\n constructor(\n private readonly engine: VaultEngine,\n private readonly targetTs: string,\n public readonly name: string,\n ) {}\n\n /**\n * Return the record as it existed at the target timestamp, or\n * `null` if the record had not been created yet or had already been\n * deleted by then.\n *\n * Gated on the LIVE record's current tier — #730, mirroring the #712\n * read-gate `history()`/`getVersion()` already apply: an elevated record\n * is invisible through the whole time-machine surface, not just a\n * decrypt failure. See {@link resolveVisibleEnvelope}.\n *\n * Decrypts through {@link openEnvelopeJson}, the `_cek`-aware envelope\n * body opener — a snapshot from a `perRecordKeys` collection is encrypted\n * under its own per-record CEK (wrapped in `_cek`), not the collection\n * DEK directly.\n */\n async get(id: string): Promise<T | null> {\n const found = await this.resolveVisibleEnvelope(id)\n if (!found) return null\n // The envelope may be the LIVE record or a `_history` snapshot, and the two\n // are sealed against different identities (#1041). `resolveEnvelope` carries\n // the address down with the bytes precisely so this read can name it.\n const plaintext = this.engine.encrypted\n ? await openEnvelopeJson(found.ref, found.envelope, await this.engine.getDEK(this.name))\n : found.envelope._data\n return JSON.parse(plaintext) as T\n }\n\n /**\n * IDs of records that existed (had at least one `put` and were not\n * subsequently deleted) at the target timestamp.\n *\n * Implemented as a linear scan over history + ledger. Performance\n * is bounded by total history size (not live-vault size), so the\n * memory-first vault-scale cap (1K–50K records × average history\n * depth) still applies.\n */\n async list(): Promise<string[]> {\n const historyIds = await collectHistoryIds(this.engine.adapter, this.engine.name, this.name)\n const liveIds = await this.engine.adapter.list(this.engine.name, this.name)\n const candidateIds = new Set<string>([...historyIds, ...liveIds])\n const alive: string[] = []\n for (const id of candidateIds) {\n const env = await this.resolveVisibleEnvelope(id)\n if (env) alive.push(id)\n }\n return alive.sort()\n }\n\n // ── write guards ───────────────────────────────────────────────────\n\n async put(_id: string, _record: T): Promise<never> {\n throw new ReadOnlyAtInstantError('put', this.targetTs)\n }\n async delete(_id: string): Promise<never> {\n throw new ReadOnlyAtInstantError('delete', this.targetTs)\n }\n async update(_id: string, _patch: Partial<T>): Promise<never> {\n throw new ReadOnlyAtInstantError('update', this.targetTs)\n }\n\n // ── internals ─────────────────────────────────────────────────────\n\n /**\n * {@link resolveEnvelope}, additionally gated on the record's LIVE\n * (current, not historical) tier — #730. Mirrors the #712 read-gate\n * `history()`/`getVersion()` apply: history snapshots keep their\n * tier-0-wrapped CEKs and carry no `_tier` of their own, so an elevated\n * record's prior versions would otherwise stay tier-0-decryptable here.\n * `null` for a resolved envelope carrying its own `_tier > 0` (a\n * tier-aware snapshot reached some other way) or whose LIVE record is\n * currently elevated — both `get()` and `list()` route through this so\n * the invisibility law holds on the whole time-machine read surface, not\n * just a decrypt failure.\n */\n private async resolveVisibleEnvelope(id: string): Promise<ResolvedEnvelope | null> {\n const found = await this.resolveEnvelope(id)\n if (!found || (found.envelope._tier ?? 0) > 0) return null\n if (await liveRecordIsElevated(this.engine.adapter, this.engine.name, this.name, id)) return null\n return found\n }\n\n /**\n * Return the envelope that represents the record's state at\n * `targetTs`, accounting for deletes. `null` if the record didn't\n * exist at that instant.\n *\n * ## Why we use the ledger as the authoritative timeline\n *\n * The per-version history snapshots saved by `saveHistory()` do\n * carry a `_ts` field, but that timestamp is the moment the\n * snapshot was *captured* (i.e. the instant right before the\n * subsequent overwrite), not the original write time. The ledger,\n * by contrast, records `ts` at the moment of each `put` / `delete`\n * — it's the only source that tracks the real timeline. So:\n *\n * 1. Walk the ledger; find the latest entry for `(collection, id)`\n * with `ts ≤ targetTs`.\n * 2. If that entry is a `delete`, the record was gone at the\n * target instant — return null.\n * 3. Otherwise it's a `put` with a specific `version`. Load the\n * envelope for that version from history, falling back to the\n * live collection for the most recent version.\n *\n * ## Fallback when the ledger is disabled\n *\n * If the vault has history disabled, `getLedger()` returns null and\n * we fall back to comparing envelope `_ts` fields. This is\n * approximate and gets the *last write* right but may confuse the\n * intermediate versions; adopters needing accurate time-machine\n * reads should leave history enabled.\n */\n private async resolveEnvelope(id: string): Promise<ResolvedEnvelope | null> {\n const ledger = this.engine.getLedger()\n if (ledger) {\n return this.resolveViaLedger(id, ledger)\n }\n return this.resolveViaEnvelopeTs(id)\n }\n\n private async resolveViaLedger(id: string, ledger: LedgerStore): Promise<ResolvedEnvelope | null> {\n const entries = await ledger.entries()\n // Entries are already ordered by index which is the mutation order.\n let latest: { op: 'put' | 'delete'; version: number } | null = null\n for (const e of entries) {\n if (e.collection !== this.name || e.id !== id) continue\n if (e.ts > this.targetTs) break // entries are time-ordered by index\n // `amendment` + `lifecycle` entries are audit-only summaries — they\n // carry no (collection, id) tuple of their own and would never match\n // the filter above. The narrow here is a type guard, not a runtime\n // skip.\n // `forget` is a subject-erasure summary with empty (collection, id) —\n // never matches the filter above; the narrow is a type guard.\n if (e.op === 'amendment' || e.op === 'lifecycle' || e.op === 'forget') continue\n // `migration` is a record rewrite (cutover) — resolve it like a put.\n latest = { op: e.op === 'migration' ? 'put' : e.op, version: e.version }\n }\n if (!latest) return null\n if (latest.op === 'delete') return null\n return this.loadVersion(id, latest.version)\n }\n\n private async resolveViaEnvelopeTs(id: string): Promise<ResolvedEnvelope | null> {\n const history = await getHistory(\n this.engine.adapter, this.engine.name, this.name, id,\n )\n const live = await this.engine.adapter.get(this.engine.name, this.name, id)\n // Each candidate keeps the address it came from — a snapshot and the live\n // record are sealed against different identities, and this map is exactly\n // where that provenance used to be discarded (#1041).\n const byVersion = new Map<number, ResolvedEnvelope>()\n for (const e of history) {\n byVersion.set(e._v, { envelope: e, ref: historyIdentity(this.name, id, e._v) })\n }\n if (live) byVersion.set(live._v, { envelope: live, ref: { collection: this.name, id } })\n const sorted = [...byVersion.values()].sort((a, b) =>\n a.envelope._ts < b.envelope._ts ? 1 : a.envelope._ts > b.envelope._ts ? -1 : 0,\n )\n return sorted.find((e) => e.envelope._ts <= this.targetTs) ?? null\n }\n\n /**\n * Fetch the envelope for a specific version. The live record (most\n * recent put) lives in the main collection; prior versions live in\n * `_history`. We check live first because the common case after a\n * delete is that we're trying to load the last-live version from\n * history, and skipping live for the current-version case avoids a\n * redundant lookup.\n */\n private async loadVersion(id: string, version: number): Promise<ResolvedEnvelope | null> {\n const live = await this.engine.adapter.get(this.engine.name, this.name, id)\n if (live && live._v === version) {\n return { envelope: live, ref: { collection: this.name, id } }\n }\n\n // Direct lookup by (collection, id, version) — avoids scanning all history.\n //\n // This used to rebuild the key inline as\n // `${name}:${id}:${padStart(10,'0')}` — a SECOND definition of the history\n // layout, free to drift from `historyId`'s. It now goes through\n // `historyIdentity`, the same function `saveHistory` writes with, so the\n // read address and the write address cannot disagree (#1041).\n const ref = historyIdentity(this.name, id, version)\n const envelope = await this.engine.adapter.get(this.engine.name, ref.collection, ref.id)\n return envelope ? { envelope, ref } : null\n }\n}\n\n/**\n * Scan the `_history` collection once and collect every distinct\n * `recordId` for the given collection. History keys follow the\n * shape `<collection>:<recordId>:<paddedVersion>`; we split on the\n * last two colons (delimiter-safe because `paddedVersion` is\n * exactly 10 digits).\n */\nasync function collectHistoryIds(\n adapter: NoydbStore,\n vault: string,\n collection: string,\n): Promise<string[]> {\n const all = await adapter.list(vault, '_history')\n const prefix = `${collection}:`\n const seen = new Set<string>()\n for (const key of all) {\n if (!key.startsWith(prefix)) continue\n const lastColon = key.lastIndexOf(':')\n if (lastColon <= prefix.length) continue\n const middle = key.slice(prefix.length, lastColon)\n seen.add(middle)\n }\n return [...seen]\n}\n"],"mappings":"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","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getAtPath
3
- } from "./chunk-7LLKPODL.js";
3
+ } from "./chunk-LPAGIMXJ.js";
4
4
  import {
5
5
  SearchNotEnabledError
6
6
  } from "./chunk-I64WQSN3.js";
@@ -294,31 +294,31 @@ function buildBlobFieldEntries(filenamesByField) {
294
294
  function withSearch() {
295
295
  return {
296
296
  async search(ctx, field, query, opts) {
297
- const { search } = await import("./collection-facade-CRXN72DU.js");
297
+ const { search } = await import("./collection-facade-56RTPO4G.js");
298
298
  return search(ctx, field, query, opts);
299
299
  },
300
300
  async retrieve(ctx, query, opts) {
301
- const { retrieve } = await import("./collection-facade-CRXN72DU.js");
301
+ const { retrieve } = await import("./collection-facade-56RTPO4G.js");
302
302
  return retrieve(ctx, query, opts);
303
303
  },
304
304
  async similarTo(ctx, vector, opts) {
305
- const { similarTo } = await import("./collection-facade-CRXN72DU.js");
305
+ const { similarTo } = await import("./collection-facade-56RTPO4G.js");
306
306
  return similarTo(ctx, vector, opts);
307
307
  },
308
308
  async warmIndex(ctx) {
309
- const { warmIndex } = await import("./collection-facade-CRXN72DU.js");
309
+ const { warmIndex } = await import("./collection-facade-56RTPO4G.js");
310
310
  return warmIndex(ctx);
311
311
  },
312
312
  async flushIndex(ctx) {
313
- const { flushIndex } = await import("./collection-facade-CRXN72DU.js");
313
+ const { flushIndex } = await import("./collection-facade-56RTPO4G.js");
314
314
  return flushIndex(ctx);
315
315
  },
316
316
  async embedOnWrite(ctx, id, record, version) {
317
- const { embedOnWrite } = await import("./collection-facade-CRXN72DU.js");
317
+ const { embedOnWrite } = await import("./collection-facade-56RTPO4G.js");
318
318
  return embedOnWrite(ctx, id, record, version);
319
319
  },
320
320
  async rebuildEmbeddings(ctx) {
321
- const { rebuildEmbeddings } = await import("./collection-facade-CRXN72DU.js");
321
+ const { rebuildEmbeddings } = await import("./collection-facade-56RTPO4G.js");
322
322
  return rebuildEmbeddings(ctx);
323
323
  }
324
324
  };
@@ -364,4 +364,4 @@ export {
364
364
  buildBlobFieldEntries,
365
365
  withSearch
366
366
  };
367
- //# sourceMappingURL=chunk-JHYISAID.js.map
367
+ //# sourceMappingURL=chunk-DFFSCYIW.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
- NOYDB_FORMAT_VERSION
3
- } from "./chunk-5UGEGEIJ.js";
2
+ buildRecordEnvelope
3
+ } from "./chunk-ZVAFJQZB.js";
4
4
 
5
5
  // src/with-party/policy/storage.ts
6
6
  var META_COLLECTION = "_meta";
@@ -17,13 +17,10 @@ async function loadVaultPolicy(store, vault) {
17
17
  }
18
18
  }
19
19
  async function saveVaultPolicy(store, vault, policy) {
20
- const envelope = {
21
- _noydb: NOYDB_FORMAT_VERSION,
22
- _v: 1,
23
- _ts: (/* @__PURE__ */ new Date()).toISOString(),
24
- _iv: "",
25
- _data: JSON.stringify(policy)
26
- };
20
+ const envelope = buildRecordEnvelope(
21
+ { collection: META_COLLECTION, id: POLICY_RECORD_ID, version: 1 },
22
+ { iv: "", data: JSON.stringify(policy) }
23
+ );
27
24
  await store.put(vault, META_COLLECTION, POLICY_RECORD_ID, envelope);
28
25
  }
29
26
  function isVaultPolicy(x) {
@@ -39,4 +36,4 @@ export {
39
36
  loadVaultPolicy,
40
37
  saveVaultPolicy
41
38
  };
42
- //# sourceMappingURL=chunk-BMDF4TLU.js.map
39
+ //# sourceMappingURL=chunk-DKYEVHZH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/with-party/policy/storage.ts"],"sourcesContent":["/**\n * Persistence helpers for the vault-level policy document\n * (`_meta/policy`). Mirrors the bypass-AES pattern used by\n * `_meta/handle` — the policy document is plain JSON, the envelope's\n * `_iv` field is left empty.\n *\n * @see https://github.com/vLannaAi/noy-db-docs/blob/main/content/docs/services/session-tiers.md → Storage location\n *\n * @module\n */\nimport { buildRecordEnvelope } from '../../kernel/enclave/index.js'\nimport type { NoydbStore, VaultPolicy } from '../../kernel/types.js'\n\n/** Reserved collection name for vault-level metadata documents. */\nexport const META_COLLECTION = '_meta'\n/** Reserved id for the vault-level policy document. */\nexport const POLICY_RECORD_ID = 'policy'\n\n/**\n * Read the vault-level policy from `_meta/policy`. Returns `undefined`\n * when no policy has been persisted (fresh vault, or a vault written\n * before the policy module landed). The caller falls back to the\n * default preset.\n *\n * Tolerates corrupted documents the same way `_meta/handle` does: a\n * JSON parse failure surfaces as `undefined`, not a thrown error, so\n * a bad write never permanently locks a vault.\n */\nexport async function loadVaultPolicy(\n store: NoydbStore,\n vault: string,\n): Promise<VaultPolicy | undefined> {\n const envelope = await store.get(vault, META_COLLECTION, POLICY_RECORD_ID)\n if (!envelope) return undefined\n try {\n const parsed = JSON.parse(envelope._data) as unknown\n if (!isVaultPolicy(parsed)) return undefined\n return parsed\n } catch {\n return undefined\n }\n}\n\n/**\n * Persist the vault-level policy at `_meta/policy`. Idempotent — call\n * once at vault creation and again on `db.updatePolicy()` invocations.\n */\nexport async function saveVaultPolicy(\n store: NoydbStore,\n vault: string,\n policy: VaultPolicy,\n): Promise<void> {\n const envelope = buildRecordEnvelope(\n { collection: META_COLLECTION, id: POLICY_RECORD_ID, version: 1 },\n { iv: '', data: JSON.stringify(policy) },\n )\n await store.put(vault, META_COLLECTION, POLICY_RECORD_ID, envelope)\n}\n\nfunction isVaultPolicy(x: unknown): x is VaultPolicy {\n if (x === null || typeof x !== 'object') return false\n if (!('gates' in x)) return false\n const gates = (x as { gates: unknown }).gates\n return gates !== null && typeof gates === 'object'\n}\n"],"mappings":";;;;;AAcO,IAAM,kBAAkB;AAExB,IAAM,mBAAmB;AAYhC,eAAsB,gBACpB,OACA,OACkC;AAClC,QAAM,WAAW,MAAM,MAAM,IAAI,OAAO,iBAAiB,gBAAgB;AACzE,MAAI,CAAC,SAAU,QAAO;AACtB,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,SAAS,KAAK;AACxC,QAAI,CAAC,cAAc,MAAM,EAAG,QAAO;AACnC,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAMA,eAAsB,gBACpB,OACA,OACA,QACe;AACf,QAAM,WAAW;AAAA,IACf,EAAE,YAAY,iBAAiB,IAAI,kBAAkB,SAAS,EAAE;AAAA,IAChE,EAAE,IAAI,IAAI,MAAM,KAAK,UAAU,MAAM,EAAE;AAAA,EACzC;AACA,QAAM,MAAM,IAAI,OAAO,iBAAiB,kBAAkB,QAAQ;AACpE;AAEA,SAAS,cAAc,GAA8B;AACnD,MAAI,MAAM,QAAQ,OAAO,MAAM,SAAU,QAAO;AAChD,MAAI,EAAE,WAAW,GAAI,QAAO;AAC5B,QAAM,QAAS,EAAyB;AACxC,SAAO,UAAU,QAAQ,OAAO,UAAU;AAC5C;","names":[]}
@@ -1,12 +1,11 @@
1
+ import {
2
+ dekKey
3
+ } from "./chunk-7WD2G6K4.js";
1
4
  import {
2
5
  TierNotGrantedError
3
6
  } from "./chunk-I64WQSN3.js";
4
7
 
5
8
  // src/with-party/team/tiers.ts
6
- function dekKey(collection, tier) {
7
- if (tier <= 0) return collection;
8
- return `${collection}#${tier}`;
9
- }
10
9
  function assertTierAccess(keyring, collection, tier) {
11
10
  if (tier <= 0) return;
12
11
  if (keyring.role === "owner" || keyring.role === "admin" || keyring.role === "custodian") return;
@@ -16,7 +15,6 @@ function assertTierAccess(keyring, collection, tier) {
16
15
  }
17
16
 
18
17
  export {
19
- dekKey,
20
18
  assertTierAccess
21
19
  };
22
- //# sourceMappingURL=chunk-YVOW35HH.js.map
20
+ //# sourceMappingURL=chunk-DL4GDOWL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/with-party/team/tiers.ts"],"sourcesContent":["/**\n * Hierarchical access — tier-aware keyring helpers.\n *\n * The keyring's existing `deks: Map<string, CryptoKey>` is keyed by\n * collection name. extends the key space:\n *\n * `'invoices'` — tier-0 DEK (unchanged from v0.x)\n * `'invoices#1'` — tier-1 DEK\n * `'invoices#2'` — tier-2 DEK\n *\n * Tier 0 keeps the bare collection name so any keyring written\n * before tiers existed loads without migration. Tiers ≥ 1 use `#N`\n * suffixes that\n * would be invalid as user-supplied collection names (see\n * `ReservedCollectionNameError` — `#` is reserved).\n *\n * @module\n */\n\nimport type { UnlockedKeyring } from './keyring.js'\nimport { TierNotGrantedError } from '../../kernel/errors.js'\n\n/** Canonical DEK key for a given collection + tier. Tier 0 → bare name. */\n// Moved to `kernel/tier-visibility.ts` (#1042): the kernel needs it to resolve\n// a pulled envelope's DEK, and `port-layering` forbids the spine importing a\n// `with-*` service. Re-exported so every existing importer is unchanged.\nimport { dekKey } from '../../kernel/tier-visibility.js'\nexport { dekKey }\n\n/**\n * Returns the user's effective clearance for a given collection: the\n * maximum tier for which their keyring holds a DEK. Falls back to 0\n * when the user has only the tier-0 DEK (or none — the getDEK caller\n * will raise separately).\n */\nexport function effectiveClearance(keyring: UnlockedKeyring, collection: string): number {\n let max = 0\n const prefix = `${collection}#`\n for (const key of keyring.deks.keys()) {\n if (!key.startsWith(prefix)) continue\n const suffix = key.slice(prefix.length)\n const n = Number.parseInt(suffix, 10)\n if (Number.isFinite(n) && n > max) max = n\n }\n return max\n}\n\n/**\n * Assert the caller is cleared for the requested tier. Owners and\n * admins always pass (they can mint any new tier DEK on demand);\n * other roles must already hold the tier DEK — via a prior grant or\n * an active delegation — otherwise this throws `TierNotGrantedError`.\n *\n * This gate runs BEFORE `getDEK()` on the mutation path so a\n * non-cleared operator never has the opportunity to silently\n * auto-create a tier DEK they shouldn't have.\n */\nexport function assertTierAccess(\n keyring: UnlockedKeyring,\n collection: string,\n tier: number,\n): void {\n if (tier <= 0) return\n // FR-6: custodian operates every collection at every tier (admin-level\n // operational authority), so it may mint a tier DEK on demand like admin.\n if (keyring.role === 'owner' || keyring.role === 'admin' || keyring.role === 'custodian') return\n if (!keyring.deks.has(dekKey(collection, tier))) {\n throw new TierNotGrantedError(collection, tier)\n }\n}\n"],"mappings":";;;;;;;;AAyDO,SAAS,iBACd,SACA,YACA,MACM;AACN,MAAI,QAAQ,EAAG;AAGf,MAAI,QAAQ,SAAS,WAAW,QAAQ,SAAS,WAAW,QAAQ,SAAS,YAAa;AAC1F,MAAI,CAAC,QAAQ,KAAK,IAAI,OAAO,YAAY,IAAI,CAAC,GAAG;AAC/C,UAAM,IAAI,oBAAoB,YAAY,IAAI;AAAA,EAChD;AACF;","names":[]}
@@ -1,12 +1,15 @@
1
1
  import {
2
2
  installViaBinder
3
- } from "./chunk-RVTOCAHQ.js";
3
+ } from "./chunk-SQSZRCYT.js";
4
+ import {
5
+ buildRecordAad
6
+ } from "./chunk-X3AXSYBL.js";
7
+ import {
8
+ buildRecordEnvelope
9
+ } from "./chunk-ZVAFJQZB.js";
4
10
  import {
5
11
  encrypt
6
12
  } from "./chunk-QTDAPDDV.js";
7
- import {
8
- NOYDB_FORMAT_VERSION
9
- } from "./chunk-5UGEGEIJ.js";
10
13
  import {
11
14
  ValidationError
12
15
  } from "./chunk-I64WQSN3.js";
@@ -367,27 +370,15 @@ function generateEvictionId(collection, recordId, slotName) {
367
370
  }
368
371
  async function writeAuditEntry(ctx, entry) {
369
372
  const json = JSON.stringify(entry);
373
+ const identity = { collection: BLOB_EVICTION_AUDIT_COLLECTION, id: entry.id, by: entry.actor, version: 1 };
374
+ const body = { ts: entry.evictedAt };
370
375
  let envelope;
371
376
  if (ctx.encrypted) {
372
377
  const dek = await ctx.getDEK(BLOB_EVICTION_AUDIT_COLLECTION);
373
- const { iv, data } = await encrypt(json, dek);
374
- envelope = {
375
- _noydb: NOYDB_FORMAT_VERSION,
376
- _v: 1,
377
- _ts: entry.evictedAt,
378
- _iv: iv,
379
- _data: data,
380
- _by: entry.actor
381
- };
378
+ const { iv, data } = await encrypt(json, dek, buildRecordAad(identity));
379
+ envelope = buildRecordEnvelope(identity, { ...body, iv, data });
382
380
  } else {
383
- envelope = {
384
- _noydb: NOYDB_FORMAT_VERSION,
385
- _v: 1,
386
- _ts: entry.evictedAt,
387
- _iv: "",
388
- _data: json,
389
- _by: entry.actor
390
- };
381
+ envelope = buildRecordEnvelope(identity, { ...body, iv: "", data: json });
391
382
  }
392
383
  await ctx.adapter.put(ctx.vault, BLOB_EVICTION_AUDIT_COLLECTION, entry.id, envelope);
393
384
  }
@@ -400,4 +391,4 @@ export {
400
391
  BLOB_EVICTION_AUDIT_COLLECTION,
401
392
  runCompaction
402
393
  };
403
- //# sourceMappingURL=chunk-Z2OFE6IX.js.map
394
+ //# sourceMappingURL=chunk-DWO55ZWE.js.map