@noy-db/hub 0.5.0 → 0.6.0-pre.0

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 (429) hide show
  1. package/dist/api-67SBPMMH.js +20 -0
  2. package/dist/attestation/index.js +18 -18
  3. package/dist/{backup-ENTZYW37.js → backup-GAYWQAFN.js} +16 -11
  4. package/dist/backup-GAYWQAFN.js.map +1 -0
  5. package/dist/blobs/index.js +20 -20
  6. package/dist/broker/index.js +12 -12
  7. package/dist/bundle-handle-5OUAI7CV.js +36 -0
  8. package/dist/bundle-handle-5OUAI7CV.js.map +1 -0
  9. package/dist/cargo/index.js +36 -36
  10. package/dist/{chunk-V3EGXDFN.js → chunk-24UICKTB.js} +3 -3
  11. package/dist/{chunk-77AEMXFA.js → chunk-24ZLWWEO.js} +1 -1
  12. package/dist/chunk-24ZLWWEO.js.map +1 -0
  13. package/dist/{chunk-6PFST3FC.js → chunk-27TCYH6G.js} +5 -5
  14. package/dist/{chunk-PTSVGKSR.js → chunk-2KIV7BEK.js} +2 -2
  15. package/dist/{chunk-3LYMOSY7.js → chunk-2LGDCNFJ.js} +2 -2
  16. package/dist/{chunk-NWK6SVBM.js → chunk-35EBKWQU.js} +3 -3
  17. package/dist/{chunk-QMCWYN6O.js → chunk-3737A6EA.js} +3 -3
  18. package/dist/{chunk-5UKUOMO6.js → chunk-3CLZY46Y.js} +464 -237
  19. package/dist/chunk-3CLZY46Y.js.map +1 -0
  20. package/dist/{chunk-G7ZIMGPQ.js → chunk-3EO7RZLJ.js} +6 -6
  21. package/dist/{chunk-GYJRDALN.js → chunk-3FSX6LDG.js} +2 -2
  22. package/dist/{chunk-4SG5TOXK.js → chunk-3HYWYLXL.js} +2 -2
  23. package/dist/{chunk-653KOQ7A.js → chunk-3IIPWA75.js} +11 -11
  24. package/dist/{chunk-IQ423YMK.js → chunk-3UK6STWO.js} +3 -3
  25. package/dist/chunk-46V67XP5.js +117 -0
  26. package/dist/chunk-46V67XP5.js.map +1 -0
  27. package/dist/{chunk-F5UWVF6Z.js → chunk-4HDYQL3J.js} +2 -2
  28. package/dist/{chunk-J7YVY7TW.js → chunk-4MQDV3HZ.js} +2 -2
  29. package/dist/{chunk-UC5Y7OEJ.js → chunk-4UVDI4XE.js} +3 -3
  30. package/dist/{chunk-4DGBZEV6.js → chunk-4VCWI42L.js} +2 -2
  31. package/dist/{chunk-GIGLOQL7.js → chunk-747LRSOO.js} +2 -2
  32. package/dist/{chunk-W7C7MMIS.js → chunk-7F4DBNSP.js} +3 -3
  33. package/dist/{chunk-5EKL6BXI.js → chunk-7G6VDWXB.js} +3 -3
  34. package/dist/{chunk-PZRYKOKP.js → chunk-AHLJSVRL.js} +2 -2
  35. package/dist/{chunk-L67H6FAQ.js → chunk-AR2JDFAE.js} +2 -2
  36. package/dist/{chunk-TJOUKMWF.js → chunk-BPTZ4K5L.js} +11 -11
  37. package/dist/{chunk-MFW466PX.js → chunk-CCZJJ4I2.js} +4 -4
  38. package/dist/{chunk-OKBNFUUX.js → chunk-CJ73OLMW.js} +2 -2
  39. package/dist/{chunk-FHK6WWUE.js → chunk-CYQOUTMY.js} +3 -3
  40. package/dist/{chunk-LQVRK2XJ.js → chunk-DCMQR46R.js} +5 -5
  41. package/dist/{chunk-QTMZDMJ6.js → chunk-DG27IUVI.js} +2 -2
  42. package/dist/{chunk-XVK7TULT.js → chunk-DMQCLZ4Z.js} +8 -6
  43. package/dist/chunk-DMQCLZ4Z.js.map +1 -0
  44. package/dist/{chunk-IHYSIPEK.js → chunk-DPJTDNUF.js} +68 -34
  45. package/dist/chunk-DPJTDNUF.js.map +1 -0
  46. package/dist/{chunk-PKBONLCP.js → chunk-E6427JU2.js} +2 -2
  47. package/dist/{chunk-KDWBVCIX.js → chunk-EK7DT5BT.js} +220 -13
  48. package/dist/chunk-EK7DT5BT.js.map +1 -0
  49. package/dist/chunk-EPFF7LOX.js +14 -0
  50. package/dist/chunk-EPFF7LOX.js.map +1 -0
  51. package/dist/{chunk-XID22NOA.js → chunk-F3GVO44K.js} +6 -6
  52. package/dist/{chunk-U2ID5A2I.js → chunk-FAXZQ5UF.js} +2 -2
  53. package/dist/{chunk-P6UIVLZK.js → chunk-FNSMZQS4.js} +2 -2
  54. package/dist/{chunk-NIKQQXI2.js → chunk-FUHKW252.js} +2 -2
  55. package/dist/{chunk-623QEHDB.js → chunk-FY343IZR.js} +8 -8
  56. package/dist/{chunk-KPZS5QAQ.js → chunk-GQ3BX5EA.js} +9 -1
  57. package/dist/chunk-GQ3BX5EA.js.map +1 -0
  58. package/dist/{chunk-7P4LL3JH.js → chunk-GS5RT2KK.js} +4 -4
  59. package/dist/{chunk-IM2KST7E.js → chunk-HFKGIBMD.js} +3 -3
  60. package/dist/{chunk-AR5D76T2.js → chunk-HNGSV2YC.js} +129 -1
  61. package/dist/chunk-HNGSV2YC.js.map +1 -0
  62. package/dist/chunk-HNHCQ556.js +63 -0
  63. package/dist/chunk-HNHCQ556.js.map +1 -0
  64. package/dist/chunk-HS7HNYBD.js +91 -0
  65. package/dist/chunk-HS7HNYBD.js.map +1 -0
  66. package/dist/{chunk-FT5Y4VSP.js → chunk-HVQGCKY4.js} +2 -2
  67. package/dist/{chunk-MYSNNMJ3.js → chunk-HXGUIPQB.js} +3 -3
  68. package/dist/{chunk-GTQF32TP.js → chunk-JEM2IGS3.js} +9 -9
  69. package/dist/chunk-JH3OHQM4.js +260 -0
  70. package/dist/chunk-JH3OHQM4.js.map +1 -0
  71. package/dist/{chunk-ALUVACKT.js → chunk-JIUVJ4M7.js} +2 -2
  72. package/dist/{chunk-NJHQE4LT.js → chunk-JRCYZEHU.js} +2 -2
  73. package/dist/{chunk-G3ORJ3IQ.js → chunk-JSRU5W2M.js} +5 -5
  74. package/dist/{chunk-SBGXQK5I.js → chunk-JXIDGFKS.js} +2 -2
  75. package/dist/{chunk-VYYM3MEN.js → chunk-KHKKD62N.js} +16 -2
  76. package/dist/chunk-KHKKD62N.js.map +1 -0
  77. package/dist/{chunk-FQ5CHJR7.js → chunk-KUDZVJKQ.js} +21 -2
  78. package/dist/chunk-KUDZVJKQ.js.map +1 -0
  79. package/dist/{chunk-MGXUAID4.js → chunk-KZ3KMDN3.js} +2 -2
  80. package/dist/{chunk-HGDXJVK2.js → chunk-LBGPO5RL.js} +6 -6
  81. package/dist/{chunk-F2WWHKO7.js → chunk-LTU4FLHG.js} +57 -27
  82. package/dist/chunk-LTU4FLHG.js.map +1 -0
  83. package/dist/{chunk-CLE3TMIS.js → chunk-MC2LFTQM.js} +5 -2
  84. package/dist/{chunk-ECGDJU5R.js → chunk-MJWCLSQL.js} +17 -8
  85. package/dist/chunk-MJWCLSQL.js.map +1 -0
  86. package/dist/{chunk-EAN4TAPC.js → chunk-MSWYQLMQ.js} +2 -2
  87. package/dist/{chunk-WK7ULBTP.js → chunk-MVOWXQHN.js} +5 -3
  88. package/dist/chunk-MVOWXQHN.js.map +1 -0
  89. package/dist/{chunk-K5OFKXUG.js → chunk-MXZ5TSTR.js} +118 -4
  90. package/dist/chunk-MXZ5TSTR.js.map +1 -0
  91. package/dist/{chunk-OKRXXFZZ.js → chunk-MZ5ZFO2D.js} +3 -3
  92. package/dist/{chunk-RQILGK3N.js → chunk-NQCNSVGI.js} +5 -5
  93. package/dist/{chunk-EFJAAFBW.js → chunk-NQRJ5AJO.js} +2 -2
  94. package/dist/{chunk-Q2SEJMP2.js → chunk-NVU7ZMPN.js} +2 -2
  95. package/dist/{chunk-Y2PTKKIN.js → chunk-OF3L2SD6.js} +2 -2
  96. package/dist/{chunk-MDRCEA56.js → chunk-OMSAULZM.js} +11 -11
  97. package/dist/{chunk-SL3PLML2.js → chunk-OSFPNKY4.js} +3 -3
  98. package/dist/{chunk-XX7YB5BI.js → chunk-P7NGLLUF.js} +5 -5
  99. package/dist/{chunk-QITP2JGX.js → chunk-PGAPBZEK.js} +7 -7
  100. package/dist/{chunk-KJNMTE2W.js → chunk-PP5CO2PR.js} +6 -6
  101. package/dist/{chunk-FZAP4JNC.js → chunk-RLWY6Z44.js} +227 -41
  102. package/dist/chunk-RLWY6Z44.js.map +1 -0
  103. package/dist/{chunk-NG4AQIYJ.js → chunk-ROWL352P.js} +5 -5
  104. package/dist/{chunk-V4O6YZSP.js → chunk-RPXL6KSX.js} +4 -4
  105. package/dist/{chunk-ODCEOSJF.js → chunk-SKONR2OL.js} +3 -3
  106. package/dist/{chunk-RM4FIXY2.js → chunk-SRGJET2F.js} +16 -5
  107. package/dist/chunk-SRGJET2F.js.map +1 -0
  108. package/dist/{chunk-QQL6XPPG.js → chunk-T4GPR2IR.js} +2 -2
  109. package/dist/{chunk-WFYKIDCS.js → chunk-TFZ7LLOQ.js} +88 -30
  110. package/dist/chunk-TFZ7LLOQ.js.map +1 -0
  111. package/dist/{chunk-NMYH55MW.js → chunk-TLNNHG3A.js} +4 -4
  112. package/dist/{chunk-DDB626I7.js → chunk-UHXCLPGC.js} +2 -2
  113. package/dist/{chunk-Q6MXHDSE.js → chunk-V5C5NNBR.js} +4 -4
  114. package/dist/{chunk-ELJOLQIG.js → chunk-VBY6ZLJT.js} +7 -7
  115. package/dist/{chunk-RPWMDIGK.js → chunk-VCETL77O.js} +34 -16
  116. package/dist/chunk-VCETL77O.js.map +1 -0
  117. package/dist/{chunk-IJV56FWY.js → chunk-VJFMXYKP.js} +2 -2
  118. package/dist/{chunk-BFG7LD6Z.js → chunk-VMCCGUQB.js} +2 -2
  119. package/dist/{chunk-PWEMRXPO.js → chunk-W3TVWF6N.js} +2 -2
  120. package/dist/{chunk-4TXO442D.js → chunk-WLYIROCJ.js} +2 -2
  121. package/dist/{chunk-MPW6AHTC.js → chunk-XB7LUDKM.js} +4 -4
  122. package/dist/{chunk-YA7Y3EZP.js → chunk-XBLKM73C.js} +10 -10
  123. package/dist/{chunk-LXRVTJ5D.js → chunk-YAWK6AWF.js} +2 -2
  124. package/dist/{chunk-6RDTG6E5.js → chunk-ZGGVOADG.js} +5 -5
  125. package/dist/{chunk-JLBCK7XM.js → chunk-ZK4CO2KZ.js} +6 -6
  126. package/dist/{chunk-DSDXAKIP.js → chunk-ZVF37PKE.js} +34 -5
  127. package/dist/chunk-ZVF37PKE.js.map +1 -0
  128. package/dist/{chunk-NZEGQWQ5.js → chunk-ZWMO5GL5.js} +5 -5
  129. package/dist/{chunk-4MSNAB64.js → chunk-ZXJXDHNK.js} +4 -4
  130. package/dist/classified/index.js +5 -5
  131. package/dist/{classified-marker-ZALWKOBC.js → classified-marker-MH3ON5OL.js} +3 -3
  132. package/dist/collection-facade-AHT7FATG.js +45 -0
  133. package/dist/{computed-YOQCGUCS.js → computed-6G5M3UPH.js} +3 -3
  134. package/dist/consent/index.js +9 -9
  135. package/dist/cover/index.js +3 -3
  136. package/dist/custody/index.js +11 -11
  137. package/dist/{dead-filter-6DVWST6U.js → dead-filter-U575NGSH.js} +2 -2
  138. package/dist/debug/index.js +1 -1
  139. package/dist/{delegation-WMO3Q3O5.js → delegation-PDYL6RWT.js} +10 -10
  140. package/dist/derivations/index.js +12 -12
  141. package/dist/derive-AKT4KU36.js +22 -0
  142. package/dist/directory/index.js +10 -10
  143. package/dist/{dispatch-VNR3TLBX.js → dispatch-4XIJSFTT.js} +5 -5
  144. package/dist/{dispatch-TKV4UCKB.js → dispatch-N5HGVUGU.js} +18 -18
  145. package/dist/{enclave-YWP3QAIQ.js → enclave-OPK24QDR.js} +13 -9
  146. package/dist/executor-3JZ4POTW.js +28 -0
  147. package/dist/executor-CYJQLKKI.js +9 -0
  148. package/dist/executor-S4QIKEHW.js +9 -0
  149. package/dist/export-accessible-CPTP5STN.js +23 -0
  150. package/dist/extract-partition-TWXPHVU7.js +38 -0
  151. package/dist/{fanout-sidecar-WYXO6QQT.js → fanout-sidecar-T2ZGLQFE.js} +9 -9
  152. package/dist/find-RBBYKXI7.js +11 -0
  153. package/dist/forget/index.js +9 -9
  154. package/dist/guards/index.js +4 -4
  155. package/dist/history/index.js +15 -15
  156. package/dist/i18n/index.js +14 -14
  157. package/dist/index.d.ts +35 -7
  158. package/dist/index.js +276 -201
  159. package/dist/index.js.map +1 -1
  160. package/dist/indexing/index.js +3 -3
  161. package/dist/introspection/index.js +12 -12
  162. package/dist/issue-N74C55X6.js +19 -0
  163. package/dist/kernel/collection.d.ts +10 -2
  164. package/dist/kernel/cutover-transform.d.ts +64 -0
  165. package/dist/kernel/enclave/crypto.d.ts +24 -0
  166. package/dist/kernel/enclave/index.d.ts +2 -1
  167. package/dist/kernel/errors.d.ts +123 -0
  168. package/dist/kernel/noydb.d.ts +10 -1
  169. package/dist/kernel/secret-mode.d.ts +59 -0
  170. package/dist/kernel/types.d.ts +98 -7
  171. package/dist/kernel/validation.d.ts +33 -0
  172. package/dist/kernel/vault.d.ts +18 -6
  173. package/dist/{ledger-BLYDYRTQ.js → ledger-DONWFC5M.js} +11 -11
  174. package/dist/liberate-KICI7AJN.js +24 -0
  175. package/dist/{link-set-7F5ZPDEB.js → link-set-2TTP4VLO.js} +11 -11
  176. package/dist/managed-secret-EAOYWRYF.js +27 -0
  177. package/dist/materialized-views/index.js +24 -24
  178. package/dist/money/index.js +3 -3
  179. package/dist/noydb-6W2XGQCS.js +83 -0
  180. package/dist/overlay-views/index.js +6 -6
  181. package/dist/periods/index.js +16 -16
  182. package/dist/pod/index.js +121 -12
  183. package/dist/policy/index.js +4 -4
  184. package/dist/port/to/index.d.ts +3 -1
  185. package/dist/port/to/locator.d.ts +84 -0
  186. package/dist/port/with/device-seal-strategy.d.ts +16 -0
  187. package/dist/port/with/strategies.d.ts +2 -0
  188. package/dist/portability/index.js +8 -8
  189. package/dist/{post-register-PQSY544J.js → post-register-ORQOQJCS.js} +6 -6
  190. package/dist/query/index.js +4 -4
  191. package/dist/reduce/index.js +4 -4
  192. package/dist/register-LHETZRJM.js +32 -0
  193. package/dist/registry-AMAZ6QRZ.js +19 -0
  194. package/dist/registry-CZVINVQH.js +9 -0
  195. package/dist/registry-IKUR2MXD.js +9 -0
  196. package/dist/registry-JRIN447B.js +18 -0
  197. package/dist/request-withdrawal-2DN2RGCO.js +31 -0
  198. package/dist/{reveal-HY7DZST4.js → reveal-AG4SCHUQ.js} +6 -6
  199. package/dist/revoke-ZX4NM2CJ.js +24 -0
  200. package/dist/satellites/index.js +1 -1
  201. package/dist/schema-update/index.js +6 -6
  202. package/dist/sealed-record/index.js +12 -12
  203. package/dist/search/index.js +4 -4
  204. package/dist/{seed-ALU3BHFS.js → seed-IRCDGIRK.js} +11 -11
  205. package/dist/sequence/index.js +9 -9
  206. package/dist/session/index.js +9 -9
  207. package/dist/shadow/index.js +2 -2
  208. package/dist/signer-7KHD4OL2.js +25 -0
  209. package/dist/snapshots/index.js +10 -10
  210. package/dist/{stale-U3WO5MYN.js → stale-K734VACF.js} +10 -10
  211. package/dist/storage-4H2GF6RQ.js +23 -0
  212. package/dist/{store-coordination-provider-AHGFEMFA.js → store-coordination-provider-4SKLSFUG.js} +3 -3
  213. package/dist/sync/index.js +10 -10
  214. package/dist/team/index.js +27 -15
  215. package/dist/tiers/index.js +10 -10
  216. package/dist/to/index.js +28 -3
  217. package/dist/to/index.js.map +1 -1
  218. package/dist/transactions/index.js +3 -3
  219. package/dist/util/index.js +1 -1
  220. package/dist/{verify-JEIXSK5U.js → verify-RO5RTZOJ.js} +5 -5
  221. package/dist/walk-MQHYNDLZ.js +21 -0
  222. package/dist/with-audit/guards/registry.d.ts +8 -1
  223. package/dist/with-audit/guards/types.d.ts +5 -0
  224. package/dist/with-audit/periods/index.d.ts +1 -1
  225. package/dist/with-audit/periods/periods.d.ts +7 -0
  226. package/dist/with-formula/derivations/registry.d.ts +6 -0
  227. package/dist/with-formula/derivations/types.d.ts +5 -0
  228. package/dist/with-lookup/indexing/eager-indexes.d.ts +10 -0
  229. package/dist/with-party/team/device-seal.d.ts +25 -0
  230. package/dist/with-party/team/echo-ceremony.d.ts +74 -0
  231. package/dist/with-party/team/echo-secret.d.ts +56 -0
  232. package/dist/with-party/team/index.d.ts +8 -0
  233. package/dist/with-party/team/keyring.d.ts +71 -9
  234. package/dist/with-party/team/rotate-recover.d.ts +99 -5
  235. package/dist/with-pod/bundle-handle.d.ts +9 -0
  236. package/dist/with-pod/bundle.d.ts +100 -2
  237. package/dist/with-pod/format.d.ts +92 -1
  238. package/dist/with-pod/index.d.ts +22 -1
  239. package/dist/with-pod/open.d.ts +117 -0
  240. package/dist/with-pod/redirect.d.ts +78 -0
  241. package/dist/with-pod/signature.d.ts +13 -0
  242. package/dist/with-shape/introspection/behaviors.d.ts +100 -0
  243. package/dist/with-shape/introspection/derivation-key.d.ts +17 -0
  244. package/dist/with-shape/introspection/describe.d.ts +36 -0
  245. package/dist/with-shape/introspection/index.d.ts +1 -0
  246. package/dist/with-shape/introspection/subsystem-matrix.d.ts +22 -0
  247. package/dist/with-shape/introspection/types.d.ts +2 -1
  248. package/dist/with-shape/links/names.d.ts +14 -0
  249. package/dist/with-shape/manifest/derive.d.ts +86 -0
  250. package/dist/with-shape/manifest/reserved-collections.d.ts +27 -0
  251. package/dist/with-shape/manifest/storage.d.ts +62 -0
  252. package/dist/with-shape/manifest/sync.d.ts +135 -0
  253. package/dist/with-shape/manifest/types.d.ts +49 -0
  254. package/dist/with-shape/manifest/writer.d.ts +32 -0
  255. package/dist/with-shape/persisted-schemas/field-ids.d.ts +29 -0
  256. package/dist/with-shape/persisted-schemas/register.d.ts +3 -0
  257. package/dist/with-shape/persisted-schemas/types.d.ts +17 -0
  258. package/dist/with-shape/schema-update/fence-controller.d.ts +34 -0
  259. package/dist/with-shape/schema-update/fence.d.ts +9 -0
  260. package/dist/with-shape/schema-update/strategies.d.ts +18 -2
  261. package/dist/with-shape/schema-update/types.d.ts +11 -0
  262. package/dist/with-sync/engine.d.ts +4 -0
  263. package/dist/with-sync/presence.d.ts +31 -1
  264. package/dist/withdraw-accessible-JSDQHXHE.js +28 -0
  265. package/dist/withdraw-accessible-JSDQHXHE.js.map +1 -0
  266. package/package.json +3 -3
  267. package/dist/api-M7REIE7H.js +0 -20
  268. package/dist/backup-ENTZYW37.js.map +0 -1
  269. package/dist/chunk-5UKUOMO6.js.map +0 -1
  270. package/dist/chunk-77AEMXFA.js.map +0 -1
  271. package/dist/chunk-AJAOXFCF.js +0 -129
  272. package/dist/chunk-AJAOXFCF.js.map +0 -1
  273. package/dist/chunk-AR5D76T2.js.map +0 -1
  274. package/dist/chunk-DSDXAKIP.js.map +0 -1
  275. package/dist/chunk-EBETHILL.js +0 -41
  276. package/dist/chunk-EBETHILL.js.map +0 -1
  277. package/dist/chunk-ECGDJU5R.js.map +0 -1
  278. package/dist/chunk-F2WWHKO7.js.map +0 -1
  279. package/dist/chunk-FQ5CHJR7.js.map +0 -1
  280. package/dist/chunk-FUECZSRM.js +0 -23
  281. package/dist/chunk-FUECZSRM.js.map +0 -1
  282. package/dist/chunk-FZAP4JNC.js.map +0 -1
  283. package/dist/chunk-IHYSIPEK.js.map +0 -1
  284. package/dist/chunk-K5OFKXUG.js.map +0 -1
  285. package/dist/chunk-KDWBVCIX.js.map +0 -1
  286. package/dist/chunk-KPZS5QAQ.js.map +0 -1
  287. package/dist/chunk-RM4FIXY2.js.map +0 -1
  288. package/dist/chunk-RPWMDIGK.js.map +0 -1
  289. package/dist/chunk-US2AR4BI.js +0 -25
  290. package/dist/chunk-US2AR4BI.js.map +0 -1
  291. package/dist/chunk-VYYM3MEN.js.map +0 -1
  292. package/dist/chunk-WFYKIDCS.js.map +0 -1
  293. package/dist/chunk-WK7ULBTP.js.map +0 -1
  294. package/dist/chunk-XVK7TULT.js.map +0 -1
  295. package/dist/collection-facade-KI53O6QB.js +0 -45
  296. package/dist/derive-P2NXWUNB.js +0 -22
  297. package/dist/executor-M4ZZNX6S.js +0 -28
  298. package/dist/executor-TI64S4LE.js +0 -9
  299. package/dist/executor-YBK3I2OT.js +0 -9
  300. package/dist/export-accessible-GBLYLGW4.js +0 -23
  301. package/dist/extract-partition-SFV35U2R.js +0 -38
  302. package/dist/find-HUSSZRBR.js +0 -11
  303. package/dist/issue-6TIJYWKS.js +0 -19
  304. package/dist/liberate-TSOW7IG5.js +0 -24
  305. package/dist/noydb-KFN6M6UJ.js +0 -81
  306. package/dist/register-S3ECUZPV.js +0 -25
  307. package/dist/registry-BWD2ED52.js +0 -8
  308. package/dist/registry-FZOHKUME.js +0 -18
  309. package/dist/registry-RISV7IDZ.js +0 -19
  310. package/dist/registry-ZE35A7WC.js +0 -9
  311. package/dist/request-withdrawal-KXVTQKR5.js +0 -31
  312. package/dist/revoke-J473JJ22.js +0 -24
  313. package/dist/signer-XLUKCCH3.js +0 -25
  314. package/dist/storage-IQONEOYY.js +0 -23
  315. package/dist/walk-BF36V4SR.js +0 -21
  316. package/dist/withdraw-accessible-TYTA23XH.js +0 -28
  317. /package/dist/{api-M7REIE7H.js.map → api-67SBPMMH.js.map} +0 -0
  318. /package/dist/{chunk-V3EGXDFN.js.map → chunk-24UICKTB.js.map} +0 -0
  319. /package/dist/{chunk-6PFST3FC.js.map → chunk-27TCYH6G.js.map} +0 -0
  320. /package/dist/{chunk-PTSVGKSR.js.map → chunk-2KIV7BEK.js.map} +0 -0
  321. /package/dist/{chunk-3LYMOSY7.js.map → chunk-2LGDCNFJ.js.map} +0 -0
  322. /package/dist/{chunk-NWK6SVBM.js.map → chunk-35EBKWQU.js.map} +0 -0
  323. /package/dist/{chunk-QMCWYN6O.js.map → chunk-3737A6EA.js.map} +0 -0
  324. /package/dist/{chunk-G7ZIMGPQ.js.map → chunk-3EO7RZLJ.js.map} +0 -0
  325. /package/dist/{chunk-GYJRDALN.js.map → chunk-3FSX6LDG.js.map} +0 -0
  326. /package/dist/{chunk-4SG5TOXK.js.map → chunk-3HYWYLXL.js.map} +0 -0
  327. /package/dist/{chunk-653KOQ7A.js.map → chunk-3IIPWA75.js.map} +0 -0
  328. /package/dist/{chunk-IQ423YMK.js.map → chunk-3UK6STWO.js.map} +0 -0
  329. /package/dist/{chunk-F5UWVF6Z.js.map → chunk-4HDYQL3J.js.map} +0 -0
  330. /package/dist/{chunk-J7YVY7TW.js.map → chunk-4MQDV3HZ.js.map} +0 -0
  331. /package/dist/{chunk-UC5Y7OEJ.js.map → chunk-4UVDI4XE.js.map} +0 -0
  332. /package/dist/{chunk-4DGBZEV6.js.map → chunk-4VCWI42L.js.map} +0 -0
  333. /package/dist/{chunk-GIGLOQL7.js.map → chunk-747LRSOO.js.map} +0 -0
  334. /package/dist/{chunk-W7C7MMIS.js.map → chunk-7F4DBNSP.js.map} +0 -0
  335. /package/dist/{chunk-5EKL6BXI.js.map → chunk-7G6VDWXB.js.map} +0 -0
  336. /package/dist/{chunk-PZRYKOKP.js.map → chunk-AHLJSVRL.js.map} +0 -0
  337. /package/dist/{chunk-L67H6FAQ.js.map → chunk-AR2JDFAE.js.map} +0 -0
  338. /package/dist/{chunk-TJOUKMWF.js.map → chunk-BPTZ4K5L.js.map} +0 -0
  339. /package/dist/{chunk-MFW466PX.js.map → chunk-CCZJJ4I2.js.map} +0 -0
  340. /package/dist/{chunk-OKBNFUUX.js.map → chunk-CJ73OLMW.js.map} +0 -0
  341. /package/dist/{chunk-FHK6WWUE.js.map → chunk-CYQOUTMY.js.map} +0 -0
  342. /package/dist/{chunk-LQVRK2XJ.js.map → chunk-DCMQR46R.js.map} +0 -0
  343. /package/dist/{chunk-QTMZDMJ6.js.map → chunk-DG27IUVI.js.map} +0 -0
  344. /package/dist/{chunk-PKBONLCP.js.map → chunk-E6427JU2.js.map} +0 -0
  345. /package/dist/{chunk-XID22NOA.js.map → chunk-F3GVO44K.js.map} +0 -0
  346. /package/dist/{chunk-U2ID5A2I.js.map → chunk-FAXZQ5UF.js.map} +0 -0
  347. /package/dist/{chunk-P6UIVLZK.js.map → chunk-FNSMZQS4.js.map} +0 -0
  348. /package/dist/{chunk-NIKQQXI2.js.map → chunk-FUHKW252.js.map} +0 -0
  349. /package/dist/{chunk-623QEHDB.js.map → chunk-FY343IZR.js.map} +0 -0
  350. /package/dist/{chunk-7P4LL3JH.js.map → chunk-GS5RT2KK.js.map} +0 -0
  351. /package/dist/{chunk-IM2KST7E.js.map → chunk-HFKGIBMD.js.map} +0 -0
  352. /package/dist/{chunk-FT5Y4VSP.js.map → chunk-HVQGCKY4.js.map} +0 -0
  353. /package/dist/{chunk-MYSNNMJ3.js.map → chunk-HXGUIPQB.js.map} +0 -0
  354. /package/dist/{chunk-GTQF32TP.js.map → chunk-JEM2IGS3.js.map} +0 -0
  355. /package/dist/{chunk-ALUVACKT.js.map → chunk-JIUVJ4M7.js.map} +0 -0
  356. /package/dist/{chunk-NJHQE4LT.js.map → chunk-JRCYZEHU.js.map} +0 -0
  357. /package/dist/{chunk-G3ORJ3IQ.js.map → chunk-JSRU5W2M.js.map} +0 -0
  358. /package/dist/{chunk-SBGXQK5I.js.map → chunk-JXIDGFKS.js.map} +0 -0
  359. /package/dist/{chunk-MGXUAID4.js.map → chunk-KZ3KMDN3.js.map} +0 -0
  360. /package/dist/{chunk-HGDXJVK2.js.map → chunk-LBGPO5RL.js.map} +0 -0
  361. /package/dist/{chunk-CLE3TMIS.js.map → chunk-MC2LFTQM.js.map} +0 -0
  362. /package/dist/{chunk-EAN4TAPC.js.map → chunk-MSWYQLMQ.js.map} +0 -0
  363. /package/dist/{chunk-OKRXXFZZ.js.map → chunk-MZ5ZFO2D.js.map} +0 -0
  364. /package/dist/{chunk-RQILGK3N.js.map → chunk-NQCNSVGI.js.map} +0 -0
  365. /package/dist/{chunk-EFJAAFBW.js.map → chunk-NQRJ5AJO.js.map} +0 -0
  366. /package/dist/{chunk-Q2SEJMP2.js.map → chunk-NVU7ZMPN.js.map} +0 -0
  367. /package/dist/{chunk-Y2PTKKIN.js.map → chunk-OF3L2SD6.js.map} +0 -0
  368. /package/dist/{chunk-MDRCEA56.js.map → chunk-OMSAULZM.js.map} +0 -0
  369. /package/dist/{chunk-SL3PLML2.js.map → chunk-OSFPNKY4.js.map} +0 -0
  370. /package/dist/{chunk-XX7YB5BI.js.map → chunk-P7NGLLUF.js.map} +0 -0
  371. /package/dist/{chunk-QITP2JGX.js.map → chunk-PGAPBZEK.js.map} +0 -0
  372. /package/dist/{chunk-KJNMTE2W.js.map → chunk-PP5CO2PR.js.map} +0 -0
  373. /package/dist/{chunk-NG4AQIYJ.js.map → chunk-ROWL352P.js.map} +0 -0
  374. /package/dist/{chunk-V4O6YZSP.js.map → chunk-RPXL6KSX.js.map} +0 -0
  375. /package/dist/{chunk-ODCEOSJF.js.map → chunk-SKONR2OL.js.map} +0 -0
  376. /package/dist/{chunk-QQL6XPPG.js.map → chunk-T4GPR2IR.js.map} +0 -0
  377. /package/dist/{chunk-NMYH55MW.js.map → chunk-TLNNHG3A.js.map} +0 -0
  378. /package/dist/{chunk-DDB626I7.js.map → chunk-UHXCLPGC.js.map} +0 -0
  379. /package/dist/{chunk-Q6MXHDSE.js.map → chunk-V5C5NNBR.js.map} +0 -0
  380. /package/dist/{chunk-ELJOLQIG.js.map → chunk-VBY6ZLJT.js.map} +0 -0
  381. /package/dist/{chunk-IJV56FWY.js.map → chunk-VJFMXYKP.js.map} +0 -0
  382. /package/dist/{chunk-BFG7LD6Z.js.map → chunk-VMCCGUQB.js.map} +0 -0
  383. /package/dist/{chunk-PWEMRXPO.js.map → chunk-W3TVWF6N.js.map} +0 -0
  384. /package/dist/{chunk-4TXO442D.js.map → chunk-WLYIROCJ.js.map} +0 -0
  385. /package/dist/{chunk-MPW6AHTC.js.map → chunk-XB7LUDKM.js.map} +0 -0
  386. /package/dist/{chunk-YA7Y3EZP.js.map → chunk-XBLKM73C.js.map} +0 -0
  387. /package/dist/{chunk-LXRVTJ5D.js.map → chunk-YAWK6AWF.js.map} +0 -0
  388. /package/dist/{chunk-6RDTG6E5.js.map → chunk-ZGGVOADG.js.map} +0 -0
  389. /package/dist/{chunk-JLBCK7XM.js.map → chunk-ZK4CO2KZ.js.map} +0 -0
  390. /package/dist/{chunk-NZEGQWQ5.js.map → chunk-ZWMO5GL5.js.map} +0 -0
  391. /package/dist/{chunk-4MSNAB64.js.map → chunk-ZXJXDHNK.js.map} +0 -0
  392. /package/dist/{classified-marker-ZALWKOBC.js.map → classified-marker-MH3ON5OL.js.map} +0 -0
  393. /package/dist/{collection-facade-KI53O6QB.js.map → collection-facade-AHT7FATG.js.map} +0 -0
  394. /package/dist/{computed-YOQCGUCS.js.map → computed-6G5M3UPH.js.map} +0 -0
  395. /package/dist/{dead-filter-6DVWST6U.js.map → dead-filter-U575NGSH.js.map} +0 -0
  396. /package/dist/{delegation-WMO3Q3O5.js.map → delegation-PDYL6RWT.js.map} +0 -0
  397. /package/dist/{derive-P2NXWUNB.js.map → derive-AKT4KU36.js.map} +0 -0
  398. /package/dist/{dispatch-VNR3TLBX.js.map → dispatch-4XIJSFTT.js.map} +0 -0
  399. /package/dist/{dispatch-TKV4UCKB.js.map → dispatch-N5HGVUGU.js.map} +0 -0
  400. /package/dist/{enclave-YWP3QAIQ.js.map → enclave-OPK24QDR.js.map} +0 -0
  401. /package/dist/{executor-M4ZZNX6S.js.map → executor-3JZ4POTW.js.map} +0 -0
  402. /package/dist/{executor-TI64S4LE.js.map → executor-CYJQLKKI.js.map} +0 -0
  403. /package/dist/{executor-YBK3I2OT.js.map → executor-S4QIKEHW.js.map} +0 -0
  404. /package/dist/{export-accessible-GBLYLGW4.js.map → export-accessible-CPTP5STN.js.map} +0 -0
  405. /package/dist/{extract-partition-SFV35U2R.js.map → extract-partition-TWXPHVU7.js.map} +0 -0
  406. /package/dist/{fanout-sidecar-WYXO6QQT.js.map → fanout-sidecar-T2ZGLQFE.js.map} +0 -0
  407. /package/dist/{find-HUSSZRBR.js.map → find-RBBYKXI7.js.map} +0 -0
  408. /package/dist/{issue-6TIJYWKS.js.map → issue-N74C55X6.js.map} +0 -0
  409. /package/dist/{ledger-BLYDYRTQ.js.map → ledger-DONWFC5M.js.map} +0 -0
  410. /package/dist/{liberate-TSOW7IG5.js.map → liberate-KICI7AJN.js.map} +0 -0
  411. /package/dist/{link-set-7F5ZPDEB.js.map → link-set-2TTP4VLO.js.map} +0 -0
  412. /package/dist/{noydb-KFN6M6UJ.js.map → managed-secret-EAOYWRYF.js.map} +0 -0
  413. /package/dist/{register-S3ECUZPV.js.map → noydb-6W2XGQCS.js.map} +0 -0
  414. /package/dist/{post-register-PQSY544J.js.map → post-register-ORQOQJCS.js.map} +0 -0
  415. /package/dist/{registry-BWD2ED52.js.map → register-LHETZRJM.js.map} +0 -0
  416. /package/dist/{registry-FZOHKUME.js.map → registry-AMAZ6QRZ.js.map} +0 -0
  417. /package/dist/{registry-RISV7IDZ.js.map → registry-CZVINVQH.js.map} +0 -0
  418. /package/dist/{registry-ZE35A7WC.js.map → registry-IKUR2MXD.js.map} +0 -0
  419. /package/dist/{request-withdrawal-KXVTQKR5.js.map → registry-JRIN447B.js.map} +0 -0
  420. /package/dist/{revoke-J473JJ22.js.map → request-withdrawal-2DN2RGCO.js.map} +0 -0
  421. /package/dist/{reveal-HY7DZST4.js.map → reveal-AG4SCHUQ.js.map} +0 -0
  422. /package/dist/{signer-XLUKCCH3.js.map → revoke-ZX4NM2CJ.js.map} +0 -0
  423. /package/dist/{seed-ALU3BHFS.js.map → seed-IRCDGIRK.js.map} +0 -0
  424. /package/dist/{stale-U3WO5MYN.js.map → signer-7KHD4OL2.js.map} +0 -0
  425. /package/dist/{storage-IQONEOYY.js.map → stale-K734VACF.js.map} +0 -0
  426. /package/dist/{walk-BF36V4SR.js.map → storage-4H2GF6RQ.js.map} +0 -0
  427. /package/dist/{store-coordination-provider-AHGFEMFA.js.map → store-coordination-provider-4SKLSFUG.js.map} +0 -0
  428. /package/dist/{verify-JEIXSK5U.js.map → verify-RO5RTZOJ.js.map} +0 -0
  429. /package/dist/{withdraw-accessible-TYTA23XH.js.map → walk-MQHYNDLZ.js.map} +0 -0
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Keep the persisted `_manifest/schema` record in sync with the
3
+ * per-collection `_schemas/<collection>` source of truth (#941 Task 3).
4
+ *
5
+ * Called from `persisted-schemas/register.ts`'s `persistSchemaIfNeeded`
6
+ * right after a `_schemas/<collection>` write succeeds.
7
+ *
8
+ * ## Reconciling strict-CAS-refuse with the derived nature of the manifest
9
+ *
10
+ * `writer.ts`'s `writeSchemaManifest` is deliberately strict-CAS: a
11
+ * concurrent *direct* edit to the manifest is refused, never retried (AC
12
+ * #1). But this call site is not a direct edit — it is a re-derivation
13
+ * from the source of truth, triggered as a side effect of a `_schemas`
14
+ * write that has ALREADY succeeded. When N collections are declared
15
+ * together (one `openVault()` call registering several `persistJsonSchema:
16
+ * true` collections), their `persistSchemaIfNeeded` calls run CONCURRENTLY
17
+ * — each one's own `_schemas/<collection>` write lands independently, and
18
+ * each then calls this function. A single derive-then-write with no
19
+ * feedback loop is NOT enough here: a call whose `deriveSchemaManifest`
20
+ * snapshot ran before a sibling's `_schemas` write landed would persist a
21
+ * manifest that's missing that sibling forever (nothing re-triggers it) —
22
+ * this was a REAL bug (not a test-isolation artifact — reproduced with 0
23
+ * shared state, purely from concurrent `_schemas` writes racing the derive
24
+ * snapshot; see #941 flake fix commit). `syncSchemaManifest` therefore
25
+ * loops (bounded by {@link MAX_SYNC_ATTEMPTS}):
26
+ *
27
+ * 1. Derive fresh, compare to what's persisted. Already converged → done.
28
+ * 2. Write via strict-CAS. `ManifestConflictError` (another writer moved
29
+ * the manifest first) → loop: re-derive against the NEW state and
30
+ * retry, exactly like a normal optimistic-CAS retry.
31
+ * 3. On a successful write, derive ONE more time. If a sibling's
32
+ * `_schemas` write landed while we were deriving/writing, the state
33
+ * has already moved past what we just wrote — loop again to catch it
34
+ * up. If the re-derive matches what we wrote, we're the last writer
35
+ * and the manifest is provably converged: return.
36
+ *
37
+ * This guarantees that whichever collection's `_schemas` write is the LAST
38
+ * to land (in real wall-clock order — there is always exactly one, even
39
+ * though no single caller knows which) ends up running a sync whose own
40
+ * derive sees every sibling's write already committed, and whose
41
+ * recheck-after-write confirms nothing moved further — so it converges the
42
+ * manifest deterministically, regardless of interleaving. If attempts are
43
+ * exhausted under pathological contention, the loop gives up — with a
44
+ * `console.warn` (see cap-exhaustion note below), not silently — leaving
45
+ * the last successful write in place; the manifest is a derivable cache
46
+ * (not a correctness invariant), so a next schema write or `open()`'s
47
+ * re-derive still converges it, matching how `persistSchemaIfNeeded`
48
+ * already treats its own write failures.
49
+ * Any error OTHER than `ManifestConflictError` (store failure, DEK
50
+ * resolution failure, etc.) is NOT swallowed — it propagates to the
51
+ * caller immediately, matching how `persistSchemaIfNeeded` already treats
52
+ * its own write failures as a visible (not silently discarded) fingerprint
53
+ * failure.
54
+ *
55
+ * ## CRITICAL fix (#941 review): a scoped principal must never write a
56
+ * partial manifest
57
+ *
58
+ * `deriveSchemaManifest` returns `undecodableCollections` for any
59
+ * `_schemas/<collection>` entry this principal's `lookupDEK` couldn't
60
+ * resolve — e.g. a member `grant()`-scoped to one collection can decrypt
61
+ * `_manifest` itself (system-prefixed DEKs propagate to every role) but
62
+ * NOT a sibling data collection's `_schemas/<sibling>` entry. Before this
63
+ * fix, `deriveSchemaManifest` silently treated "can't decrypt" the same as
64
+ * "no derivable content" and omitted the sibling — so a scoped member's
65
+ * OWN schema declare would derive a manifest missing every collection they
66
+ * can't see, load the real (complete) persisted manifest as a valid CAS
67
+ * token, observe a hash mismatch, and OVERWRITE it — permanently dropping
68
+ * the siblings, silently, ledger-audited as a legitimate migration. The
69
+ * converging recheck loop above made this WORSE, not better: re-deriving
70
+ * from the same restricted view just re-confirms the same partial result
71
+ * and declares it "stable."
72
+ *
73
+ * Fix: if `undecodableCollections` is non-empty, `syncSchemaManifest`
74
+ * `SKIP`s entirely — no read-compare, no write, no audit, no loop. It does
75
+ * NOT try to merge-preserve the undecodable entries from what's currently
76
+ * persisted: an `aggregateHash` computed over entries this principal can't
77
+ * verify would be a hash asserting something it never actually checked,
78
+ * which is worse than not writing at all. This is safe because:
79
+ *
80
+ * - The source of truth, `_schemas/<their-collection>`, was ALREADY
81
+ * updated by their declare — nothing about their own change is lost.
82
+ * - The pod-wide `_manifest` cache simply isn't rewritten by a principal
83
+ * who'd corrupt it by omission — it stays whatever a full-visibility
84
+ * principal (owner/admin/custodian) last wrote.
85
+ * - `open()` re-derives from `_schemas` directly (not from the cached
86
+ * manifest) for whoever opens it, so a stale cache is never load-bearing.
87
+ * - The NEXT full-visibility principal's declare (or any subsequent sync
88
+ * by someone with complete access) naturally refreshes the cache,
89
+ * including the scoped member's own just-landed change.
90
+ *
91
+ * ## Ledger audit (AC #5)
92
+ *
93
+ * Schema-generation transitions are not ledger-audited anywhere else today
94
+ * (neither the `_schemas/<collection>` write in `register.ts` nor the fence
95
+ * bump in `schema-update/fence-controller.ts#runCutover`). This is the
96
+ * first ledger-audited signal for a schema change: every manifest write
97
+ * that actually happens (i.e. every time the derived manifest differs from
98
+ * what's stored) appends an `op: 'migration'` entry via the optional
99
+ * `getLedgerOrNull` callback — `null`/absent when the history strategy
100
+ * isn't opted in, matching every other optional-ledger call site
101
+ * (`vault._getLedgerOrNull()?.append(...)`, see `liberate.ts`,
102
+ * `with-audit/periods/vault-facade.ts`). No audit fires on the no-op path
103
+ * (derived manifest unchanged), on a swallowed conflict (the winning
104
+ * writer's own sync already audits its write), or on the scoped-principal
105
+ * SKIP path above (nothing was written).
106
+ *
107
+ * @module
108
+ */
109
+ import type { LedgerStore } from '../../with-commit/history/ledger/store.js';
110
+ import type { NoydbStore } from '../../kernel/types.js';
111
+ import { type LookupDEK } from './derive.js';
112
+ import { type GetManifestDEK } from './storage.js';
113
+ export interface ManifestSyncDeps {
114
+ /** Resolver for `_manifest`'s OWN DEK — mints if absent (this principal's declare is about to write it). */
115
+ readonly getDEK: GetManifestDEK;
116
+ /**
117
+ * NON-MINTING lookup for every OTHER (sibling data) collection's DEK,
118
+ * used by `deriveSchemaManifest` to build the index — see `derive.ts`'s
119
+ * `LookupDEK` doc for why minting here would be actively harmful.
120
+ */
121
+ readonly lookupDEK: LookupDEK;
122
+ /** Optional ledger handle — absent when the history strategy isn't opted in (no-op audit). */
123
+ readonly getLedgerOrNull?: () => LedgerStore | null;
124
+ }
125
+ /**
126
+ * Re-derive the schema manifest and write it if it changed, looping until
127
+ * the write is provably stable against concurrent sibling `_schemas`
128
+ * writes (see module doc). SKIPS entirely (no write, no audit) when this
129
+ * principal's view is incomplete (`undecodableCollections` non-empty) —
130
+ * see the module doc's CRITICAL fix section. Swallows a
131
+ * {@link ManifestConflictError} by retrying against the fresher state; any
132
+ * other error propagates. Ledger-audits (`op: 'migration'`) once per
133
+ * successful write.
134
+ */
135
+ export declare function syncSchemaManifest(store: NoydbStore, vault: string, deps: ManifestSyncDeps): Promise<void>;
@@ -0,0 +1,49 @@
1
+ /**
2
+ * The pod-wide **schema manifest** record type (#941).
3
+ *
4
+ * This is an INDEX, not a full-inline manifest: `SchemaManifest.collections`
5
+ * carries per-collection *metadata* (generation / content hash / field ids),
6
+ * never the JSON Schema body itself. The JSON Schema stays the source of
7
+ * truth at `_schemas/<collection>`, encrypted under that collection's own
8
+ * DEK (see `with-shape/persisted-schemas`). Inlining full schemas into one
9
+ * pod-wide manifest record would either leak every collection's schema to a
10
+ * principal scoped to a single collection, or force the manifest itself
11
+ * onto a collection-DEK it has no business holding — the index preserves
12
+ * per-collection DEK isolation while still giving a single place to answer
13
+ * "what schema generation is this pod at, and does collection X's stored
14
+ * schema match its declared content hash."
15
+ *
16
+ * `aggregateHash` binds the whole per-collection index's content: it is
17
+ * `sha256Hex(canonicalJson(collections))`, so any change to any collection's
18
+ * entry (a new generation, a changed hash, added/renamed field ids) changes
19
+ * `aggregateHash` too. Canonical JSON (sorted object keys, no whitespace)
20
+ * makes the hash independent of the map's key insertion order.
21
+ *
22
+ * @module
23
+ */
24
+ /** Per-collection entry inside a {@link SchemaManifest}'s `collections` index. */
25
+ export interface SchemaManifestEntry {
26
+ /** The vault-wide schema-fence generation this collection's schema was last written at. */
27
+ readonly generation: number;
28
+ /** SHA-256 (hex) of the collection's canonicalised JSON Schema (see `persisted-schemas/derive.ts`). */
29
+ readonly contentHash: string;
30
+ /** Stable per-field ids (#946), keyed by the field's current name. Absent when the collection has none. */
31
+ readonly fieldIds?: Record<string, string>;
32
+ }
33
+ /**
34
+ * The pod-wide schema manifest — one record per pod, stored at
35
+ * `_manifest/schema` (see `storage.ts`). An INDEX over the per-collection
36
+ * `_schemas/<collection>` entries, not the schemas themselves.
37
+ */
38
+ export interface SchemaManifest {
39
+ readonly v: 1;
40
+ readonly kind: 'schema';
41
+ /** Pod-wide schema-fence generation (`FenceDoc.currentSchemaVersion`) as of this manifest's derivation. */
42
+ readonly generation: number;
43
+ /** Per-collection index: collection name → its manifest entry. */
44
+ readonly collections: Record<string, SchemaManifestEntry>;
45
+ /** `sha256Hex(canonicalJson(collections))` — the pod-wide content binding over the index. */
46
+ readonly aggregateHash: string;
47
+ }
48
+ /** The record id the schema manifest is stored under inside `_manifest`. */
49
+ export declare const MANIFEST_SCHEMA_RECORD_ID: "schema";
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Strict-CAS schema-manifest writer (#941, AC #1).
3
+ *
4
+ * Every other reserved-collection writer in the hub (`persisted-schemas`'s
5
+ * `savePersistedSchema` callers, the classified/satellite marker writers)
6
+ * retries on a CAS conflict: re-read, re-apply, try again. The schema
7
+ * manifest deliberately does NOT — two concurrent *direct* edits to the
8
+ * manifest must be refused and surfaced, never silently merged or
9
+ * retry-resolved, because a manifest write encodes a specific point-in-time
10
+ * claim about the pod's schema generation/content-hash set. A caller that
11
+ * lost the race must re-derive against the fresh state and decide what to
12
+ * do, not have its stale write quietly re-applied on top of someone else's.
13
+ *
14
+ * Ledger audit: this writer does not have a `LedgerStore` handle at this
15
+ * seam (mirroring `persisted-schemas`, whose `_schemas/<collection>` writes
16
+ * are likewise not ledger-audited today). Wiring `LedgerStore.append({ op:
17
+ * 'migration', ... })` around a manifest write belongs at the call site
18
+ * where a ledger handle is already in scope (the open/write integration —
19
+ * #941 Task 3/4), not here.
20
+ *
21
+ * @module
22
+ */
23
+ import { type GetManifestDEK } from './storage.js';
24
+ import type { NoydbStore } from '../../kernel/types.js';
25
+ import type { SchemaManifest } from './types.js';
26
+ /**
27
+ * Write the schema manifest as a strict CAS: `expectedVersion` must match
28
+ * the stored envelope's `_v` (0 when no manifest exists yet). On a
29
+ * conflict, throws {@link ManifestConflictError} — this function never
30
+ * retries.
31
+ */
32
+ export declare function writeSchemaManifest(store: NoydbStore, vault: string, manifest: SchemaManifest, expectedVersion: number, getDEK: GetManifestDEK): Promise<void>;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Stable field-identifier minting (#946).
3
+ *
4
+ * A field's `id` is opaque and permanent — minted once, from randomness
5
+ * only, with no timestamp and no name-derivation. A name-derived id would
6
+ * change when the field is renamed, defeating the whole point (identity
7
+ * must survive a rename). See `PersistedSchemaEnvelope.fieldIds`.
8
+ *
9
+ * @module
10
+ */
11
+ /**
12
+ * Resolve the `fieldIds` map for a freshly-derived schema against the
13
+ * previously-stored envelope's map (if any). Existing ids are preserved by
14
+ * name — a field keeps its id across re-derivation as long as its name is
15
+ * unchanged; a genuinely new field name mints a fresh id. Returns
16
+ * `undefined` when the fresh schema has no derivable top-level field set
17
+ * (e.g. a stub envelope, or a non-object root schema).
18
+ *
19
+ * `renamed` (#946 Task 2) — unambiguous rename pairs from
20
+ * `computeSchemaDelta`'s `SchemaDelta.renamed`. When the fresh name is a
21
+ * rename target (`to`), the id is looked up under its OLD name (`from`)
22
+ * instead of the fresh name itself — the whole point of a stable field id
23
+ * is that it survives exactly this case; without it, a rename would mint a
24
+ * fresh id for the new name and silently drop the old one.
25
+ */
26
+ export declare function resolveFieldIds(freshJsonSchema: object | null, priorFieldIds: Record<string, string> | undefined, renamed?: readonly {
27
+ readonly from: string;
28
+ readonly to: string;
29
+ }[]): Record<string, string> | undefined;
@@ -13,6 +13,7 @@
13
13
  *
14
14
  * @module
15
15
  */
16
+ import { type ManifestSyncDeps } from '../manifest/sync.js';
16
17
  import type { SchemaUpdateStrategy, UpdateDecision } from '../schema-update/types.js';
17
18
  import type { NoydbStore, ClassifiedMarker } from '../../kernel/types.js';
18
19
  import type { PersistedSchemaEnvelope } from './types.js';
@@ -35,6 +36,8 @@ export declare function persistSchemaIfNeeded(opts: {
35
36
  readonly validator: unknown;
36
37
  readonly dek: EnclaveKey;
37
38
  readonly strategies?: readonly SchemaUpdateStrategy[];
39
+ /** #941 Task 3: re-derive + sync the `_manifest/schema` INDEX after a write. Omitted → no sync (e.g. tests that don't care). */
40
+ readonly manifestSync?: ManifestSyncDeps;
38
41
  }): Promise<PersistSchemaResult>;
39
42
  /**
40
43
  * Persist (or refresh) the C-A / R10 classified marker into the collection's
@@ -51,4 +51,21 @@ export interface PersistedSchemaEnvelope {
51
51
  * the satellite-pair analogue of {@link classified}'s config-drift guard.
52
52
  */
53
53
  readonly satellite?: PairingMarker;
54
+ /**
55
+ * Stable per-field identifiers (#946), keyed by the field's current name
56
+ * (top-level JSON Schema `properties` key) and mapping to an opaque,
57
+ * permanent id minted once via `mintFieldId()`. IDs are preserved by name
58
+ * across re-derivation (a field keeps its id as long as its name is
59
+ * unchanged) so a field's identity survives a rename — the name is a
60
+ * label, the id is the stable key. Absent on a legacy (pre-#946) envelope
61
+ * and on a stub envelope with no derivable field set (`jsonSchema === null`).
62
+ */
63
+ readonly fieldIds?: Record<string, string>;
64
+ /**
65
+ * The vault-wide schema-fence generation (`FenceDoc.currentSchemaVersion`)
66
+ * as of this envelope's most recent write. Together with
67
+ * `FenceDoc.schemaHash`, answers "generation N = which schema content
68
+ * hash" (#946). Absent on a legacy (pre-#946) envelope.
69
+ */
70
+ readonly generation?: number;
54
71
  }
@@ -17,6 +17,37 @@ import type { TransformFn } from './types.js';
17
17
  import { type CoordinationProvider } from '../../port/by/index.js';
18
18
  /** Runs one collection's transform; supplied by the Vault (binds to a Collection). */
19
19
  export type RunTransform = (collection: string, transform: TransformFn) => Promise<void>;
20
+ /** Structural (no static import — kernel-spine port-layering carve-out, same rationale as
21
+ * `kernel/via/dispatch.ts`'s `AuditLedgerLike`) shape of the with-history `LedgerStore.append`
22
+ * seam {@link schemaBumpAuditHook} needs. */
23
+ interface AuditLedgerLike {
24
+ append(input: {
25
+ readonly op: 'lifecycle';
26
+ readonly collection: string;
27
+ readonly id: string;
28
+ readonly version: number;
29
+ readonly actor: string;
30
+ readonly payloadHash: string;
31
+ readonly reason?: string;
32
+ }): Promise<unknown>;
33
+ }
34
+ /**
35
+ * #965 — a bare `runCutover` generation bump (no re-declare, no per-record
36
+ * migrations) otherwise leaves zero ledger evidence: per-record `migration`
37
+ * entries only fire from `applyCutoverTransform` when records + a transform
38
+ * exist. Mirrors `ledgerAuditHook` (`kernel/via/dispatch.ts`): encoded as a
39
+ * `'lifecycle'` entry (no ciphertext to hash, `payloadHash: ''`), distinct
40
+ * from the per-record `op: 'migration'` entries via its
41
+ * `reason: 'schema:generation-bump=<n>'`. Fires once per successful bump,
42
+ * always — even when the same cutover also produced per-record entries —
43
+ * so "one bump entry per generation bump" stays a simple, unconditional
44
+ * invariant to audit against.
45
+ *
46
+ * `getLedger` is called lazily (at bump time, not at wiring time) — same
47
+ * lazy-init contract as `Vault.getLedgerOrNull`; calling it eagerly during
48
+ * `Vault` construction (before `this.strategies` is assigned) would throw.
49
+ */
50
+ export declare function schemaBumpAuditHook(getLedger: () => AuditLedgerLike | null, actor: string): (generation: number) => Promise<void>;
20
51
  export declare class SchemaFenceController {
21
52
  #private;
22
53
  constructor(opts: {
@@ -38,6 +69,8 @@ export declare class SchemaFenceController {
38
69
  currentSchemaVersion: number;
39
70
  fenceState: FenceState;
40
71
  }) => void;
72
+ /** #965 — best-effort ledger audit for a bare (no-record) generation bump. See {@link schemaBumpAuditHook}. */
73
+ auditBump?: ((generation: number) => Promise<void>) | undefined;
41
74
  });
42
75
  /** Capture the generation snapshot at vault-open. */
43
76
  init(): Promise<void>;
@@ -60,3 +93,4 @@ export declare class SchemaFenceController {
60
93
  /** Recover a stuck drain: reset fenceState to normal at the current version (no bump). */
61
94
  abort(): Promise<void>;
62
95
  }
96
+ export {};
@@ -8,6 +8,15 @@ export type FenceState = 'normal' | 'draining' | 'migrating' | 'complete';
8
8
  export interface FenceDoc {
9
9
  readonly currentSchemaVersion: number;
10
10
  readonly fenceState: FenceState;
11
+ /**
12
+ * Content hash (`PersistedSchemaEnvelope.hash`) of the schema most
13
+ * recently persisted while the vault sat at `currentSchemaVersion` —
14
+ * binds "generation N" to a concrete schema-content hash (#946), so
15
+ * "which schema is generation N" is answerable from `schemaFenceState()`
16
+ * alone. Optional: absent on a fresh vault (generation 0, nothing
17
+ * persisted yet) and on a fence document written before #946.
18
+ */
19
+ readonly schemaHash?: string;
11
20
  }
12
21
  export declare const FENCE_RECORD_ID = "schema-fence";
13
22
  export declare const DEFAULT_FENCE: FenceDoc;
@@ -1,11 +1,27 @@
1
1
  import type { SchemaUpdateStrategy } from './types.js';
2
2
  /** Allow any schema change. Explicit blind / back-compat. */
3
3
  export declare function blindUpdate(): SchemaUpdateStrategy;
4
- /** Allow additive changes; reject non-additive ones. The safety backstop. */
4
+ /**
5
+ * Allow additive changes; reject non-additive ones. The safety backstop.
6
+ *
7
+ * #946: a `renamed` pair is NOT additive-safe *for this gate* — the delta
8
+ * itself carries no data migration, so an allowed rename would orphan
9
+ * existing record values under the old key. `computeSchemaDelta` classifies
10
+ * a pure rename as `kind: 'additive'` (it IS additive-safe as far as the
11
+ * name-change itself is concerned, and the id-carry through `SchemaDelta.
12
+ * renamed` is real), but a guard whose whole job is "don't admit anything
13
+ * that isn't a mechanical additive write" must still block it — the same as
14
+ * it blocks any other non-additive change — forcing a `coordinatedCutover()`
15
+ * (or `blindUpdate()`) to actually move the data.
16
+ */
5
17
  export declare function additiveOnly(): SchemaUpdateStrategy;
6
18
  /**
7
19
  * Reject schema changes. With `fields`, reject only when one of those
8
- * fields is added/removed/changed; otherwise reject any non-`none` delta.
20
+ * fields is added/removed/changed/renamed; otherwise reject any non-`none`
21
+ * delta. #946: a `renamed` pair's `from` AND `to` both count as touching a
22
+ * locked field — a rename away from a locked name (or onto one) still
23
+ * violates the lock, and a blanket `lockSchema()` (no `fields`) already
24
+ * blocks any rename since a pure rename's `kind` is never `'none'`.
9
25
  */
10
26
  export declare function lockSchema(opts?: {
11
27
  readonly fields?: readonly string[];
@@ -23,6 +23,17 @@ export interface SchemaDelta {
23
23
  readonly removed: readonly string[];
24
24
  /** Top-level properties present in both but altered. */
25
25
  readonly changed: readonly FieldChange[];
26
+ /**
27
+ * Unambiguous rename pairs detected by shape-matching a removed name
28
+ * against an added name (#946) — same field, new label. Present only
29
+ * when at least one pairing was found; the paired names are excluded
30
+ * from `added`/`removed` (a pure rename is additive-safe, not a
31
+ * drop+add). See `computeSchemaDelta`'s doc comment for the pairing rule.
32
+ */
33
+ readonly renamed?: readonly {
34
+ readonly from: string;
35
+ readonly to: string;
36
+ }[];
26
37
  }
27
38
  /** Context handed to a strategy alongside the delta. */
28
39
  export interface UpdateContext {
@@ -19,6 +19,10 @@ export declare class SyncEngine {
19
19
  private readonly vault;
20
20
  readonly role: SyncTargetRole;
21
21
  readonly label: string | undefined;
22
+ /** #948: the resolved policy this engine was constructed with, retained for
23
+ * introspection (`Noydb.listSyncTargets()`) — otherwise lost once consumed
24
+ * into the scheduler below. */
25
+ readonly policy: SyncPolicy | undefined;
22
26
  private dirty;
23
27
  private lastPush;
24
28
  private lastPull;
@@ -26,7 +26,14 @@ export interface PresenceHandleOpts {
26
26
  vault: string;
27
27
  /** Collection name — used as HKDF `info` and channel suffix. */
28
28
  collectionName: string;
29
- /** Calling user's ID, embedded unencrypted in storage records. */
29
+ /**
30
+ * Calling user's ID. In encrypted mode it is encrypted inside the
31
+ * storage-poll record's `data` field — the record id is an
32
+ * adapter-opaque HMAC tag, not the userId, so the adapter never learns
33
+ * peer identities. Unencrypted vaults have no key to tag or encrypt
34
+ * with, so the userId is used as the record id in cleartext (dev posture
35
+ * only — identity privacy requires encryption).
36
+ */
30
37
  userId: string;
31
38
  /** Whether encryption is active. When false, presence payloads are stored as JSON. */
32
39
  encrypted: boolean;
@@ -51,6 +58,7 @@ export declare class PresenceHandle<P> {
51
58
  private readonly channel;
52
59
  private readonly storageCollection;
53
60
  private presenceKey;
61
+ private presenceTagKey;
54
62
  private subscribers;
55
63
  private unsubscribePubSub;
56
64
  private pollTimer;
@@ -71,6 +79,28 @@ export declare class PresenceHandle<P> {
71
79
  /** Stop all listening and clear resources. */
72
80
  stop(): void;
73
81
  private getPresenceKey;
82
+ /**
83
+ * Derive (and cache) the presence-tag key — a non-extractable, sign-only
84
+ * HMAC-SHA256 key HKDF-derived from the collection DEK, domain-separated
85
+ * from the presence payload key by {@link PRESENCE_TAG_KEY_DOMAIN}.
86
+ * Mirrors `deriveClassifyIndexKey` (kernel/enclave/classify/bidx.ts). No
87
+ * PBKDF2 stretch — the adapter never holds this key, so a plain keyed HMAC
88
+ * tag is sufficient and deterministic. Returns `null` when unencrypted
89
+ * (no DEK to derive from).
90
+ */
91
+ private getPresenceTagKey;
92
+ /**
93
+ * Deterministic, adapter-opaque tag for `userId` — used as the
94
+ * storage-poll record id in encrypted mode so the adapter never sees the
95
+ * userId. Falls back to the raw `userId` when unencrypted (no key exists
96
+ * to tag with — see {@link PresenceHandleOpts.userId}).
97
+ *
98
+ * Signs directly via `subtle.sign` (like `bidx.ts`'s `mintAt`) rather than
99
+ * the barrel's `hmacSha256Hex` helper: that helper re-exports its key
100
+ * argument's raw bytes internally, which only works for extractable keys
101
+ * (e.g. an AES-GCM DEK) — `presenceTagKey` is deliberately non-extractable.
102
+ */
103
+ private presenceTag;
74
104
  private getPubSubAdapter;
75
105
  private startListening;
76
106
  private stopListening;
@@ -0,0 +1,28 @@
1
+ import {
2
+ FROZEN_SNAPSHOTS_COLLECTION,
3
+ freezeAndDeleteClosure,
4
+ freezeSnapshotOnly,
5
+ randomId,
6
+ withdrawAccessibleData
7
+ } from "./chunk-JSRU5W2M.js";
8
+ import "./chunk-4MQDV3HZ.js";
9
+ import "./chunk-EK7DT5BT.js";
10
+ import "./chunk-CYQOUTMY.js";
11
+ import "./chunk-FY343IZR.js";
12
+ import "./chunk-NQRJ5AJO.js";
13
+ import "./chunk-HXGUIPQB.js";
14
+ import "./chunk-AR2JDFAE.js";
15
+ import "./chunk-747LRSOO.js";
16
+ import "./chunk-LP7BEXCT.js";
17
+ import "./chunk-VCETL77O.js";
18
+ import "./chunk-24ZLWWEO.js";
19
+ import "./chunk-HNGSV2YC.js";
20
+ import "./chunk-PZ5AY32C.js";
21
+ export {
22
+ FROZEN_SNAPSHOTS_COLLECTION,
23
+ freezeAndDeleteClosure,
24
+ freezeSnapshotOnly,
25
+ randomId,
26
+ withdrawAccessibleData
27
+ };
28
+ //# sourceMappingURL=withdraw-accessible-JSDQHXHE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@noy-db/hub",
3
- "version": "0.5.0",
3
+ "version": "0.6.0-pre.0",
4
4
  "description": "Zero-knowledge, offline-first, encrypted document store — core library with AES-256-GCM, PBKDF2, multi-user keyring, and sync engine",
5
5
  "license": "MIT",
6
6
  "author": "vLannaAi <vicio@lanna.ai>",
@@ -208,14 +208,14 @@
208
208
  "node": ">=22.0.0"
209
209
  },
210
210
  "dependencies": {
211
- "@noy-db/attestation": "0.5.0"
211
+ "@noy-db/attestation": "0.6.0-pre.0"
212
212
  },
213
213
  "devDependencies": {
214
214
  "@types/node": "^22.0.0",
215
215
  "esbuild": "^0.25.0",
216
216
  "zod": "^4.0.0",
217
217
  "zod-to-json-schema": "^3.25.2",
218
- "@noy-db/on-shamir": "0.5.0"
218
+ "@noy-db/on-shamir": "0.6.0-pre.0"
219
219
  },
220
220
  "peerDependencies": {
221
221
  "zod-to-json-schema": "^3.25.0"
@@ -1,20 +0,0 @@
1
- import {
2
- UserApi,
3
- createUserApi
4
- } from "./chunk-SL3PLML2.js";
5
- import "./chunk-6PFST3FC.js";
6
- import "./chunk-623QEHDB.js";
7
- import "./chunk-EFJAAFBW.js";
8
- import "./chunk-MYSNNMJ3.js";
9
- import "./chunk-L67H6FAQ.js";
10
- import "./chunk-GIGLOQL7.js";
11
- import "./chunk-LP7BEXCT.js";
12
- import "./chunk-RPWMDIGK.js";
13
- import "./chunk-77AEMXFA.js";
14
- import "./chunk-AR5D76T2.js";
15
- import "./chunk-PZ5AY32C.js";
16
- export {
17
- UserApi,
18
- createUserApi
19
- };
20
- //# sourceMappingURL=api-M7REIE7H.js.map
@@ -1 +0,0 @@
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 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'\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 '_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 = {\n _noydb: 1 as const,\n _v: 1,\n _ts: new Date().toISOString(),\n _iv: '',\n _data: JSON.stringify(keyringFile),\n }\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":[]}