@noy-db/hub 0.2.0-pre.15 → 0.2.0-pre.17
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.
- package/dist/aggregate/index.cjs +106 -10
- package/dist/aggregate/index.cjs.map +1 -1
- package/dist/aggregate/index.d.cts +3 -2
- package/dist/aggregate/index.d.ts +3 -2
- package/dist/aggregate/index.js +4 -4
- package/dist/attestation/index.cjs.map +1 -1
- package/dist/attestation/index.d.cts +5 -3
- package/dist/attestation/index.d.ts +5 -3
- package/dist/attestation/index.js +6 -6
- package/dist/blobs/index.cjs +226 -11
- package/dist/blobs/index.cjs.map +1 -1
- package/dist/blobs/index.d.cts +6 -4
- package/dist/blobs/index.d.ts +6 -4
- package/dist/blobs/index.js +6 -5
- package/dist/blobs/index.js.map +1 -1
- package/dist/bundle/index.cjs +1268 -141
- package/dist/bundle/index.cjs.map +1 -1
- package/dist/bundle/index.d.cts +7 -5
- package/dist/bundle/index.d.ts +7 -5
- package/dist/bundle/index.js +21 -10
- package/dist/bundle/index.js.map +1 -1
- package/dist/{chunk-5LQG6ZO2.js → chunk-2FU2FTXD.js} +9 -4
- package/dist/chunk-2FU2FTXD.js.map +1 -0
- package/dist/{chunk-JD3OZAI4.js → chunk-3G3W65EQ.js} +2 -2
- package/dist/{chunk-XWH4MXIU.js → chunk-5AXTH4QZ.js} +2 -2
- package/dist/{chunk-4TBBMHVC.js → chunk-5LIROIDM.js} +2 -2
- package/dist/{chunk-3EWXMOK3.js → chunk-7H2GEJ3O.js} +28 -13
- package/dist/chunk-7H2GEJ3O.js.map +1 -0
- package/dist/{chunk-WGHU7BLI.js → chunk-AEIKD3PP.js} +52 -38
- package/dist/chunk-AEIKD3PP.js.map +1 -0
- package/dist/{chunk-KI6HAJWL.js → chunk-BH3X5L6A.js} +4 -4
- package/dist/{chunk-BQ65SS5A.js → chunk-BJSLBUJ7.js} +2 -2
- package/dist/{chunk-L2FE64BU.js → chunk-BL5GYANC.js} +3 -3
- package/dist/{chunk-A5ZOOZFB.js → chunk-BSZOCSDZ.js} +4 -4
- package/dist/{chunk-ZNQYHJXX.js → chunk-C3HYQPV4.js} +2 -2
- package/dist/{chunk-PE4AQGFH.js → chunk-CD2AVTEM.js} +5 -5
- package/dist/{chunk-7EFFHEN5.js → chunk-D77ZQSQQ.js} +852 -143
- package/dist/chunk-D77ZQSQQ.js.map +1 -0
- package/dist/{chunk-56DJ7JVK.js → chunk-DWEBTE2W.js} +5 -5
- package/dist/{chunk-Z4DO7YSI.js → chunk-DYYYUW5D.js} +2 -2
- package/dist/{chunk-NSCVNK5K.js → chunk-E77UKJYL.js} +5 -5
- package/dist/{chunk-KIP6JLTF.js → chunk-F4G63NTZ.js} +2 -2
- package/dist/{chunk-NU6Q3FOR.js → chunk-FEJDVE3Z.js} +12 -2
- package/dist/{chunk-NU6Q3FOR.js.map → chunk-FEJDVE3Z.js.map} +1 -1
- package/dist/{chunk-DQU36Q7I.js → chunk-GP3SDSH2.js} +14 -5
- package/dist/chunk-GP3SDSH2.js.map +1 -0
- package/dist/{chunk-IQLVUT37.js → chunk-H2MRGONI.js} +2 -2
- package/dist/{chunk-EYVQHAGH.js → chunk-HGVSHKZW.js} +8 -5
- package/dist/chunk-HGVSHKZW.js.map +1 -0
- package/dist/chunk-I5IUYN7B.js +125 -0
- package/dist/chunk-I5IUYN7B.js.map +1 -0
- package/dist/{chunk-CJORTUJ2.js → chunk-J7RWBXFY.js} +2 -2
- package/dist/{chunk-AAVWKNZW.js → chunk-JDWE6JMX.js} +2 -2
- package/dist/{chunk-6AJBSQU4.js → chunk-KCEHMDZF.js} +3 -3
- package/dist/{chunk-TS26M2SB.js → chunk-M476FOQ7.js} +2 -2
- package/dist/{chunk-F4OJZIWQ.js → chunk-NBBMMJ2H.js} +4 -4
- package/dist/{chunk-CZI2A4MQ.js → chunk-NYSYPFXJ.js} +3 -3
- package/dist/{chunk-EGD5DXFT.js → chunk-PDULVIBY.js} +14 -2
- package/dist/chunk-PDULVIBY.js.map +1 -0
- package/dist/{chunk-Z6FNBOTC.js → chunk-PDVP3C2I.js} +1 -1
- package/dist/{chunk-Z6FNBOTC.js.map → chunk-PDVP3C2I.js.map} +1 -1
- package/dist/{chunk-COFPAMX6.js → chunk-QHM6XEAH.js} +6 -6
- package/dist/{chunk-C5T5AFWN.js → chunk-QO6RGLLD.js} +12 -6
- package/dist/chunk-QO6RGLLD.js.map +1 -0
- package/dist/{chunk-7HT2MEZ5.js → chunk-ROPJVUG3.js} +23 -6
- package/dist/chunk-ROPJVUG3.js.map +1 -0
- package/dist/{chunk-VU7SWWT5.js → chunk-ROVO6NPJ.js} +11 -7
- package/dist/chunk-ROVO6NPJ.js.map +1 -0
- package/dist/{chunk-6RR3MNMG.js → chunk-SHX5QBCI.js} +3 -3
- package/dist/{chunk-GC4V7RU7.js → chunk-SISBMAPO.js} +1 -1
- package/dist/chunk-SISBMAPO.js.map +1 -0
- package/dist/{chunk-BIYRQQV6.js → chunk-SNMJ7SB3.js} +5 -5
- package/dist/{chunk-7PS7EOCF.js → chunk-TIDXB5DF.js} +4 -4
- package/dist/chunk-U5QCMH3W.js +151 -0
- package/dist/chunk-U5QCMH3W.js.map +1 -0
- package/dist/{chunk-YULZKK4F.js → chunk-UNTGHX5A.js} +37 -2
- package/dist/chunk-UNTGHX5A.js.map +1 -0
- package/dist/{chunk-FWPKCXTN.js → chunk-WIAOUFFB.js} +2 -2
- package/dist/{chunk-LX3CB26H.js → chunk-WV7WV6JO.js} +195 -17
- package/dist/chunk-WV7WV6JO.js.map +1 -0
- package/dist/{chunk-X73VS74Y.js → chunk-XJV6OB4D.js} +2 -2
- package/dist/{chunk-OHVFWCJP.js → chunk-XMHUK5PN.js} +49 -19
- package/dist/chunk-XMHUK5PN.js.map +1 -0
- package/dist/{chunk-WBAYSNUQ.js → chunk-XMVHEWF6.js} +4 -4
- package/dist/{chunk-HOR4R722.js → chunk-XPIHJ34I.js} +30 -4
- package/dist/chunk-XPIHJ34I.js.map +1 -0
- package/dist/{chunk-DKO2QFSA.js → chunk-YYVZYTWW.js} +3 -3
- package/dist/{chunk-535SSHBS.js → chunk-ZEGSDPB7.js} +81 -2
- package/dist/chunk-ZEGSDPB7.js.map +1 -0
- package/dist/{chunk-YHPM5D7Y.js → chunk-ZNGPEV5J.js} +63 -4
- package/dist/chunk-ZNGPEV5J.js.map +1 -0
- package/dist/consent/index.cjs.map +1 -1
- package/dist/consent/index.d.cts +6 -4
- package/dist/consent/index.d.ts +6 -4
- package/dist/consent/index.js +3 -3
- package/dist/{crypto-QXQOHMHF.js → crypto-7BN2HDWG.js} +7 -3
- package/dist/{delegation-NIQ43IPU.js → delegation-MGH5SODX.js} +5 -5
- package/dist/derivations/index.cjs +24 -3
- package/dist/derivations/index.cjs.map +1 -1
- package/dist/derivations/index.d.cts +7 -5
- package/dist/derivations/index.d.ts +7 -5
- package/dist/derivations/index.js +4 -4
- package/dist/{dev-unlock-iAS8z9jc.d.ts → dev-unlock-CI1ijTML.d.ts} +1 -1
- package/dist/{dev-unlock-nVkuRLLe.d.cts → dev-unlock-iXbYFAWl.d.cts} +1 -1
- package/dist/{strategy-CbneC7bS.d.ts → errors-Dz64FA65.d.cts} +98 -727
- package/dist/{strategy-CbneC7bS.d.cts → errors-Dz64FA65.d.ts} +98 -727
- package/dist/executor-3W63Y44O.js +11 -0
- package/dist/executor-CFFWPWBJ.js +8 -0
- package/dist/executor-VDQQOR4F.js +8 -0
- package/dist/{fanout-sidecar-N6OJX6QR.js → fanout-sidecar-FIJJ46YG.js} +2 -2
- package/dist/forget/index.cjs +43 -0
- package/dist/forget/index.cjs.map +1 -0
- package/dist/forget/index.d.cts +1 -0
- package/dist/forget/index.d.ts +1 -0
- package/dist/forget/index.js +14 -0
- package/dist/guards/index.cjs +9 -5
- package/dist/guards/index.cjs.map +1 -1
- package/dist/guards/index.d.cts +7 -5
- package/dist/guards/index.d.ts +7 -5
- package/dist/guards/index.js +6 -6
- package/dist/{hash-DHOnRarj.d.ts → hash-blk7Bkes.d.ts} +1 -1
- package/dist/{hash-Cv6byZs7.d.cts → hash-tEcM5fnv.d.cts} +1 -1
- package/dist/history/index.cjs +27 -4
- package/dist/history/index.cjs.map +1 -1
- package/dist/history/index.d.cts +7 -5
- package/dist/history/index.d.ts +7 -5
- package/dist/history/index.js +9 -7
- package/dist/history/index.js.map +1 -1
- package/dist/i18n/index.cjs +53 -0
- package/dist/i18n/index.cjs.map +1 -1
- package/dist/i18n/index.d.cts +6 -4
- package/dist/i18n/index.d.ts +6 -4
- package/dist/i18n/index.js +16 -8
- package/dist/i18n/index.js.map +1 -1
- package/dist/{immutable-guard-BehB1YGB.d.ts → immutable-guard-B5M95nbq.d.ts} +16 -1
- package/dist/{immutable-guard-yBEOYmif.d.cts → immutable-guard-qN3zF8o1.d.cts} +16 -1
- package/dist/index-C-SSRIxP.d.cts +348 -0
- package/dist/index-C-SSRIxP.d.ts +348 -0
- package/dist/{index-XNB2r6bX.d.ts → index-DpU6KWof.d.ts} +9 -1
- package/dist/{index-D95VK1Qy.d.cts → index-u-kWzSrL.d.cts} +9 -1
- package/dist/index.cjs +2715 -1302
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -12
- package/dist/index.d.ts +16 -12
- package/dist/index.js +132 -106
- package/dist/index.js.map +1 -1
- package/dist/indexing/index.cjs.map +1 -1
- package/dist/indexing/index.js +4 -4
- package/dist/issue-TTMGHQ2J.js +12 -0
- package/dist/{ledger-CWSE3BLF.js → ledger-LFVLHE5H.js} +6 -6
- package/dist/materialized-views/index.cjs +407 -5
- package/dist/materialized-views/index.cjs.map +1 -1
- package/dist/materialized-views/index.d.cts +7 -5
- package/dist/materialized-views/index.d.ts +7 -5
- package/dist/materialized-views/index.js +12 -12
- package/dist/noydb-36S6GQNC.js +37 -0
- package/dist/overlay-views/index.cjs +47 -17
- package/dist/overlay-views/index.cjs.map +1 -1
- package/dist/overlay-views/index.d.cts +28 -8
- package/dist/overlay-views/index.d.ts +28 -8
- package/dist/overlay-views/index.js +4 -4
- package/dist/periods/index.cjs.map +1 -1
- package/dist/periods/index.d.cts +6 -4
- package/dist/periods/index.d.ts +6 -4
- package/dist/periods/index.js +6 -6
- package/dist/{public-envelope-SYHEYQ3X.js → public-envelope-RXZNP3V6.js} +4 -4
- package/dist/query/index.cjs +28 -11
- package/dist/query/index.cjs.map +1 -1
- package/dist/query/index.d.cts +3 -2
- package/dist/query/index.d.ts +3 -2
- package/dist/query/index.js +6 -6
- package/dist/registry-3YFLZ7WD.js +8 -0
- package/dist/{registry-DK5YWAAA.js → registry-SECUWSGY.js} +3 -3
- package/dist/registry-TGZISEWC.js +8 -0
- package/dist/{revoke-ZDFKMR5E.js → revoke-B54H2S2W.js} +6 -6
- package/dist/sealed-record/index.cjs +139 -0
- package/dist/sealed-record/index.cjs.map +1 -0
- package/dist/sealed-record/index.d.cts +123 -0
- package/dist/sealed-record/index.d.ts +123 -0
- package/dist/sealed-record/index.js +42 -0
- package/dist/sealed-record/index.js.map +1 -0
- package/dist/session/index.cjs.map +1 -1
- package/dist/session/index.d.cts +7 -5
- package/dist/session/index.d.ts +7 -5
- package/dist/session/index.js +3 -3
- package/dist/shadow/index.cjs.map +1 -1
- package/dist/shadow/index.d.cts +6 -4
- package/dist/shadow/index.d.ts +6 -4
- package/dist/shadow/index.js +2 -2
- package/dist/{signer-P5D7Y72U.js → signer-YSXZT574.js} +5 -5
- package/dist/snapshots/index.cjs.map +1 -1
- package/dist/snapshots/index.d.cts +6 -4
- package/dist/snapshots/index.d.ts +6 -4
- package/dist/snapshots/index.js +4 -4
- package/dist/{stale-JH67FU57.js → stale-TOA36SRK.js} +2 -2
- package/dist/stale-TOA36SRK.js.map +1 -0
- package/dist/{state-vault-TMXZRTY5.js → state-vault-W2OEABNO.js} +3 -3
- package/dist/store/index.cjs.map +1 -1
- package/dist/store/index.d.cts +6 -4
- package/dist/store/index.d.ts +6 -4
- package/dist/store/index.js +2 -2
- package/dist/strategy-4M9jo172.d.ts +739 -0
- package/dist/strategy-CLC1j79g.d.cts +739 -0
- package/dist/sync/index.cjs.map +1 -1
- package/dist/sync/index.d.cts +5 -3
- package/dist/sync/index.d.ts +5 -3
- package/dist/sync/index.js +4 -4
- package/dist/team/index.cjs.map +1 -1
- package/dist/team/index.d.cts +6 -4
- package/dist/team/index.d.ts +6 -4
- package/dist/team/index.js +8 -8
- package/dist/tx/index.cjs +66 -3
- package/dist/tx/index.cjs.map +1 -1
- package/dist/tx/index.d.cts +24 -6
- package/dist/tx/index.d.ts +24 -6
- package/dist/tx/index.js +9 -5
- package/dist/tx/index.js.map +1 -1
- package/dist/{types-4t1-tWS4.d.ts → types-CljIHm_J.d.ts} +1127 -606
- package/dist/{types-BpPV5uyy.d.cts → types-CrSpRDuG.d.cts} +1127 -606
- package/dist/{ulid-DAfenvFd.d.ts → ulid-CWfL2Vfv.d.ts} +1 -1
- package/dist/{ulid-CiPrpGqm.d.cts → ulid-CrI7PPbA.d.cts} +1 -1
- package/dist/util/index.cjs.map +1 -1
- package/dist/util/index.js +1 -1
- package/dist/{vault-group-KOM7QRJG.js → vault-group-DHAHFX2A.js} +4 -4
- package/dist/{with-derivation-OK9M2sJE.d.ts → with-derivation-BZ2y4bzF.d.ts} +1 -1
- package/dist/{with-derivation-DBqJB3dQ.d.cts → with-derivation-Bozs8DmD.d.cts} +1 -1
- package/dist/{with-materialized-view-Dt-ufPWQ.d.ts → with-materialized-view-B892zYZV.d.ts} +1 -1
- package/dist/{with-materialized-view-NzuxYPDF.d.cts → with-materialized-view-NzF71cG_.d.cts} +1 -1
- package/dist/{with-overlayed-view-eDvMs6LO.d.ts → with-overlayed-view-CR6m7CHe.d.ts} +1 -1
- package/dist/{with-overlayed-view-CC0_ocy-.d.cts → with-overlayed-view-UI8qSGL4.d.cts} +1 -1
- package/package.json +23 -3
- package/dist/chunk-3EWXMOK3.js.map +0 -1
- package/dist/chunk-535SSHBS.js.map +0 -1
- package/dist/chunk-5LQG6ZO2.js.map +0 -1
- package/dist/chunk-7EFFHEN5.js.map +0 -1
- package/dist/chunk-7HT2MEZ5.js.map +0 -1
- package/dist/chunk-C5T5AFWN.js.map +0 -1
- package/dist/chunk-DQU36Q7I.js.map +0 -1
- package/dist/chunk-EGD5DXFT.js.map +0 -1
- package/dist/chunk-EYVQHAGH.js.map +0 -1
- package/dist/chunk-GC4V7RU7.js.map +0 -1
- package/dist/chunk-HOR4R722.js.map +0 -1
- package/dist/chunk-LX3CB26H.js.map +0 -1
- package/dist/chunk-OHVFWCJP.js.map +0 -1
- package/dist/chunk-VU7SWWT5.js.map +0 -1
- package/dist/chunk-WGHU7BLI.js.map +0 -1
- package/dist/chunk-YHPM5D7Y.js.map +0 -1
- package/dist/chunk-YULZKK4F.js.map +0 -1
- package/dist/executor-6ZDSDZ6V.js +0 -8
- package/dist/executor-HSSRXDOB.js +0 -11
- package/dist/executor-IDZDAFNH.js +0 -8
- package/dist/issue-ADVS4OVP.js +0 -12
- package/dist/noydb-GZGFBA4E.js +0 -35
- package/dist/registry-IUZQVVBB.js +0 -8
- package/dist/registry-XGLNADIE.js +0 -8
- /package/dist/{chunk-JD3OZAI4.js.map → chunk-3G3W65EQ.js.map} +0 -0
- /package/dist/{chunk-XWH4MXIU.js.map → chunk-5AXTH4QZ.js.map} +0 -0
- /package/dist/{chunk-4TBBMHVC.js.map → chunk-5LIROIDM.js.map} +0 -0
- /package/dist/{chunk-KI6HAJWL.js.map → chunk-BH3X5L6A.js.map} +0 -0
- /package/dist/{chunk-BQ65SS5A.js.map → chunk-BJSLBUJ7.js.map} +0 -0
- /package/dist/{chunk-L2FE64BU.js.map → chunk-BL5GYANC.js.map} +0 -0
- /package/dist/{chunk-A5ZOOZFB.js.map → chunk-BSZOCSDZ.js.map} +0 -0
- /package/dist/{chunk-ZNQYHJXX.js.map → chunk-C3HYQPV4.js.map} +0 -0
- /package/dist/{chunk-PE4AQGFH.js.map → chunk-CD2AVTEM.js.map} +0 -0
- /package/dist/{chunk-56DJ7JVK.js.map → chunk-DWEBTE2W.js.map} +0 -0
- /package/dist/{chunk-Z4DO7YSI.js.map → chunk-DYYYUW5D.js.map} +0 -0
- /package/dist/{chunk-NSCVNK5K.js.map → chunk-E77UKJYL.js.map} +0 -0
- /package/dist/{chunk-KIP6JLTF.js.map → chunk-F4G63NTZ.js.map} +0 -0
- /package/dist/{chunk-IQLVUT37.js.map → chunk-H2MRGONI.js.map} +0 -0
- /package/dist/{chunk-CJORTUJ2.js.map → chunk-J7RWBXFY.js.map} +0 -0
- /package/dist/{chunk-AAVWKNZW.js.map → chunk-JDWE6JMX.js.map} +0 -0
- /package/dist/{chunk-6AJBSQU4.js.map → chunk-KCEHMDZF.js.map} +0 -0
- /package/dist/{chunk-TS26M2SB.js.map → chunk-M476FOQ7.js.map} +0 -0
- /package/dist/{chunk-F4OJZIWQ.js.map → chunk-NBBMMJ2H.js.map} +0 -0
- /package/dist/{chunk-CZI2A4MQ.js.map → chunk-NYSYPFXJ.js.map} +0 -0
- /package/dist/{chunk-COFPAMX6.js.map → chunk-QHM6XEAH.js.map} +0 -0
- /package/dist/{chunk-6RR3MNMG.js.map → chunk-SHX5QBCI.js.map} +0 -0
- /package/dist/{chunk-BIYRQQV6.js.map → chunk-SNMJ7SB3.js.map} +0 -0
- /package/dist/{chunk-7PS7EOCF.js.map → chunk-TIDXB5DF.js.map} +0 -0
- /package/dist/{chunk-FWPKCXTN.js.map → chunk-WIAOUFFB.js.map} +0 -0
- /package/dist/{chunk-X73VS74Y.js.map → chunk-XJV6OB4D.js.map} +0 -0
- /package/dist/{chunk-WBAYSNUQ.js.map → chunk-XMVHEWF6.js.map} +0 -0
- /package/dist/{chunk-DKO2QFSA.js.map → chunk-YYVZYTWW.js.map} +0 -0
- /package/dist/{crypto-QXQOHMHF.js.map → crypto-7BN2HDWG.js.map} +0 -0
- /package/dist/{delegation-NIQ43IPU.js.map → delegation-MGH5SODX.js.map} +0 -0
- /package/dist/{executor-6ZDSDZ6V.js.map → executor-3W63Y44O.js.map} +0 -0
- /package/dist/{executor-HSSRXDOB.js.map → executor-CFFWPWBJ.js.map} +0 -0
- /package/dist/{executor-IDZDAFNH.js.map → executor-VDQQOR4F.js.map} +0 -0
- /package/dist/{fanout-sidecar-N6OJX6QR.js.map → fanout-sidecar-FIJJ46YG.js.map} +0 -0
- /package/dist/{issue-ADVS4OVP.js.map → forget/index.js.map} +0 -0
- /package/dist/{ledger-CWSE3BLF.js.map → issue-TTMGHQ2J.js.map} +0 -0
- /package/dist/{noydb-GZGFBA4E.js.map → ledger-LFVLHE5H.js.map} +0 -0
- /package/dist/{public-envelope-SYHEYQ3X.js.map → noydb-36S6GQNC.js.map} +0 -0
- /package/dist/{registry-DK5YWAAA.js.map → public-envelope-RXZNP3V6.js.map} +0 -0
- /package/dist/{registry-IUZQVVBB.js.map → registry-3YFLZ7WD.js.map} +0 -0
- /package/dist/{registry-XGLNADIE.js.map → registry-SECUWSGY.js.map} +0 -0
- /package/dist/{revoke-ZDFKMR5E.js.map → registry-TGZISEWC.js.map} +0 -0
- /package/dist/{signer-P5D7Y72U.js.map → revoke-B54H2S2W.js.map} +0 -0
- /package/dist/{stale-JH67FU57.js.map → signer-YSXZT574.js.map} +0 -0
- /package/dist/{state-vault-TMXZRTY5.js.map → state-vault-W2OEABNO.js.map} +0 -0
- /package/dist/{vault-group-KOM7QRJG.js.map → vault-group-DHAHFX2A.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/policy/storage.ts","../src/auth-introspection/index.ts","../src/crdt/strategy.ts","../src/computed/index.ts","../src/i18n/strategy.ts","../src/schema.ts","../src/history/strategy.ts","../src/indexing/strategy.ts","../src/indexing/unique-constraints.ts","../src/cache/lru.ts","../src/cache/policy.ts","../src/team/sync-strategy.ts","../src/blobs/strategy.ts","../src/derivations/stale.ts","../src/collection.ts","../src/archive/engine.ts","../src/archive/index.ts","../src/sequence/index.ts","../src/numbering/index.ts","../src/shadow/strategy.ts","../src/consent/strategy.ts","../src/periods/strategy.ts","../src/refs.ts","../src/meta/user-envelope/api.ts","../src/persisted-schemas/canonicalize.ts","../src/persisted-schemas/derive.ts","../src/schema-update/delta.ts","../src/schema-update/dispatch.ts","../src/persisted-schemas/register.ts","../src/schema-update/gate.ts","../src/schema-update/fence.ts","../src/schema-update/client-registry.ts","../src/schema-update/fence-controller.ts","../src/schema-update/fence-watcher.ts","../src/introspection/fields.ts","../src/introspection/walk.ts","../src/vault.ts","../src/events.ts","../src/write-queue.ts","../src/write-hooks.ts","../src/subsystem-bus.ts","../src/tab-coordination.ts","../src/tab-write-relay.ts","../src/session/unlock-state.ts","../src/snapshots/strategy.ts","../src/snapshots/scheduler.ts","../src/tx/strategy.ts","../src/session/strategy.ts","../src/policy/presets.ts","../src/policy/engine.ts","../src/noydb.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 docs/subsystems/session-tiers.md → Storage location\n *\n * @module\n */\nimport type { NoydbStore, EncryptedEnvelope } from '../types.js'\nimport { NOYDB_FORMAT_VERSION } from '../types.js'\nimport type { VaultPolicy } from './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: EncryptedEnvelope = {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: 1,\n _ts: new Date().toISOString(),\n _iv: '',\n _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","/**\n * Authentication introspection.\n *\n * Three surfaces over the configured tier model and the actual\n * per-user enrollment state:\n *\n * 1. **Vault-wide English summary** — {@link describeAuthConfig}.\n * 2. **Vault-wide Mermaid diagram** — {@link diagramAuthConfig}.\n * 3. **Per-user introspection** — {@link describeUserAuth}, gated by\n * the `view-user-auth` policy gate (off by default).\n *\n * The per-user surface is held to a strict allowlist — fields not on\n * the allowlist are dropped, never rendered. The negative test in\n * `auth-introspection.test.ts` exercises the allowlist by feeding a\n * contrived keyring with fake \"secret\" fields and asserting that none\n * of them appear in the output.\n *\n * @module\n */\nimport type { NoydbStore, KeyringFile, KeyringAuthenticator } from '../types.js'\nimport type { VaultPolicy, GatePolicy } from '../policy/types.js'\nimport { loadVaultPolicy } from '../policy/storage.js'\nimport { loadPaperRecoveryEntries } from '../team/recovery.js'\n\n/** Vault-wide English summary of the configured authentication graph. */\nexport async function describeAuthConfig(\n store: NoydbStore,\n vault: string,\n): Promise<string> {\n const policy = (await loadVaultPolicy(store, vault)) ?? defaultPolicySnapshot()\n const recoveryProfiles = await listRecoveryProfilesEnrolled(store, vault)\n\n const lines: string[] = []\n lines.push(`Vault \"${vault}\" — three-tier authentication`)\n lines.push('')\n lines.push('Tier 1 — Passphrase (master)')\n lines.push(` Phrase format: ${policy.passphrase?.minWords ?? 6}+ words, lowercase letters, ≥${policy.passphrase?.minWordLength ?? 3} chars/word`)\n lines.push(' Strength validator: enforced (override available for tests only)')\n lines.push('')\n lines.push('Tier 2 — Authenticate (routine login)')\n lines.push(' Allowed methods: WebAuthn (passkey), OIDC, Password')\n lines.push(' Slots per user: unlimited')\n lines.push('')\n lines.push('Tier 3 — Unlock (quick resume)')\n lines.push(' Method: PIN (per-app configurable)')\n lines.push('')\n lines.push(`Recovery profiles enrolled: ${recoveryProfiles.length === 0 ? 'none' : recoveryProfiles.join(', ')}`)\n lines.push('Managed-passphrase mode: off (post-1.0)')\n lines.push('')\n lines.push('Sensitive-action gates:')\n for (const [gate, gp] of Object.entries(policy.gates) as Array<[string, GatePolicy]>) {\n lines.push(` ${gate} — ${describeGatePolicy(gp)}`)\n }\n return lines.join('\\n')\n}\n\n/**\n * Render the vault's auth graph as Mermaid `flowchart TB` source. The\n * caller pipes this through Mermaid (CLI or browser) to get an SVG.\n */\nexport async function diagramAuthConfig(\n store: NoydbStore,\n vault: string,\n): Promise<string> {\n const policy = (await loadVaultPolicy(store, vault)) ?? defaultPolicySnapshot()\n const lines: string[] = []\n lines.push('flowchart TB')\n lines.push(` vault[\"Vault: ${escapeMermaid(vault)}\"]`)\n lines.push(' tier1[\"Tier 1<br/>Passphrase\"]')\n lines.push(' tier2[\"Tier 2<br/>Multi-slot Authenticate\"]')\n lines.push(' tier3[\"Tier 3<br/>PIN / Quick-resume\"]')\n lines.push(' vault --> tier1')\n lines.push(' tier1 --> tier2')\n lines.push(' tier2 --> tier3')\n for (const [gateName, gp] of Object.entries(policy.gates) as Array<[string, GatePolicy]>) {\n if (gp.enabled === false) continue\n const id = sanitizeId(gateName)\n const label = `${gateName}<br/>tier ≥ ${gp.minTier}`\n lines.push(` ${id}[\"${escapeMermaid(label)}\"]`)\n const tierNode = gp.minTier === 1 ? 'tier1' : gp.minTier === 2 ? 'tier2' : 'tier3'\n lines.push(` ${tierNode} --> ${id}`)\n }\n return lines.join('\\n')\n}\n\n/**\n * Render the per-user enrollment summary. Returns an empty\n * (non-throwing) string when the user has no keyring file — never\n * confirms or denies the existence of the user from the document\n * alone.\n *\n * Sanitization is strict: only the slot list, enrollment dates, and\n * recovery-profile counts are rendered. WebAuthn cred ids, OIDC\n * subject ids, password hashes, recovery codes, TOTP secrets — all\n * dropped at the allowlist boundary, not redacted.\n */\nexport async function describeUserAuth(\n store: NoydbStore,\n vault: string,\n userId: string,\n): Promise<string> {\n const env = await store.get(vault, '_keyring', userId)\n if (!env) return ''\n const file = JSON.parse(env._data) as KeyringFile\n\n const lines: string[] = []\n lines.push(\n `User: ${file.user_id} (joined ${file.created_at.slice(0, 10)}, role: ${file.role})`,\n )\n lines.push('')\n lines.push('Tier 2 enrollments:')\n if (!file.authenticators || file.authenticators.length === 0) {\n lines.push(' (none enrolled)')\n } else {\n for (const slot of file.authenticators) {\n lines.push(` - ${describeSlot(slot)}`)\n }\n }\n return lines.join('\\n')\n}\n\n/** Bulk variant for owner dashboards. */\nexport async function describeAllUsersAuth(\n store: NoydbStore,\n vault: string,\n): Promise<Array<{ userId: string; description: string }>> {\n const ids = await store.list(vault, '_keyring')\n const results: Array<{ userId: string; description: string }> = []\n for (const userId of ids) {\n const description = await describeUserAuth(store, vault, userId)\n if (description !== '') results.push({ userId, description })\n }\n return results\n}\n\n// ─── Helpers ───────────────────────────────────────────────────────────\n\nconst SLOT_FIELD_ALLOWLIST: ReadonlyArray<keyof KeyringAuthenticator> = [\n 'id',\n 'method',\n 'enrolled_at',\n 'enrolled_via_tier',\n] as const\n\nfunction describeSlot(slot: KeyringAuthenticator): string {\n // Project to the allowlist FIRST — never read meta/wrapped_kek into\n // any user-facing string. The allowlist is the only path values\n // take to the renderer; off-allowlist fields are dropped, not redacted.\n const sanitized: Partial<KeyringAuthenticator> = {}\n for (const key of SLOT_FIELD_ALLOWLIST) {\n if (key in slot) {\n // @ts-expect-error narrow assignment from allowlist iteration\n sanitized[key] = slot[key]\n }\n }\n const date = (sanitized.enrolled_at ?? '').slice(0, 10)\n return `${sanitized.method ?? '?'} (id=${sanitized.id ?? '?'}, enrolled ${date}, via tier ${sanitized.enrolled_via_tier ?? '?'})`\n}\n\nfunction describeGatePolicy(gp: GatePolicy): string {\n if (gp.enabled === false) return 'disabled'\n const parts: string[] = []\n parts.push(`tier ${gp.minTier}`)\n if (gp.factors && gp.factors.length > 0) {\n for (const f of gp.factors) {\n parts.push(`+ ${f.count ?? 1}× ${f.anyOf.join('|')}`)\n }\n }\n if (gp.warn?.sharedDevice === 'block') parts.push('block-on-shared-device')\n return parts.join(' ')\n}\n\nfunction defaultPolicySnapshot(): VaultPolicy {\n return {\n passphrase: { minWords: 6, minWordLength: 3, rejectRepeatedAdjacent: true },\n gates: {},\n }\n}\n\nasync function listRecoveryProfilesEnrolled(\n store: NoydbStore,\n vault: string,\n): Promise<ReadonlyArray<string>> {\n const enrolled: string[] = []\n const paper = await loadPaperRecoveryEntries(store, vault)\n if (paper.length > 0) enrolled.push(`paper (${paper.length} codes)`)\n return enrolled\n}\n\nfunction escapeMermaid(s: string): string {\n return s.replace(/\"/g, '\\\\\"').replace(/\\n/g, ' ')\n}\n\nfunction sanitizeId(s: string): string {\n return s.replace(/[^a-zA-Z0-9]/g, '_')\n}\n","/**\n * Strategy seam between core Collection and the optional CRDT\n * subsystem. Core imports `CrdtStrategy` as a TYPE-ONLY symbol and\n * `NO_CRDT` as a minimal runtime stub.\n *\n * The state-construction / merge / snapshot-resolution helpers —\n * `buildLwwMapState`, `buildRgaState`, `mergeCrdtStates`,\n * `resolveCrdtSnapshot` — are only reachable from `withCrdt()` in\n * `./active.ts`, which is only exported through the `@noy-db/hub/crdt`\n * subpath. Consumers without CRDT mode configured never pull the\n * ~221 LOC into their bundle.\n *\n * @internal\n */\n\nimport type { CrdtState, LwwMapState, RgaState } from './crdt.js'\n\n/**\n * Seam interface. `@internal`.\n *\n * @internal\n */\nexport interface CrdtStrategy {\n buildLwwMapState(\n record: Record<string, unknown>,\n previous: LwwMapState | undefined,\n now: string,\n ): LwwMapState\n buildRgaState(\n items: readonly unknown[],\n previous: RgaState | undefined,\n idGen: () => string,\n ): RgaState\n mergeCrdtStates(local: CrdtState, remote: CrdtState): CrdtState\n resolveCrdtSnapshot(state: CrdtState): unknown\n}\n\nconst NOT_ENABLED = new Error(\n 'CRDT mode requires the CRDT strategy. Import `{ withCrdt }` from ' +\n '\"@noy-db/hub/crdt\" and pass it to `createNoydb({ crdtStrategy: withCrdt() })`.',\n)\n\n/**\n * No-CRDT stub. Every method throws with a pointer at the subpath.\n * If a Collection declares `crdt: '...'` without this strategy wired,\n * the first put/sync-merge/read that hits the CRDT path surfaces the\n * error immediately.\n *\n * @internal\n */\nexport const NO_CRDT: CrdtStrategy = {\n buildLwwMapState() { throw NOT_ENABLED },\n buildRgaState() { throw NOT_ENABLED },\n mergeCrdtStates() { throw NOT_ENABLED },\n resolveCrdtSnapshot() { throw NOT_ENABLED },\n}\n","/**\n * Computed scalar fields — schema-owned derived values evaluated on\n * write and materialized onto the record.\n *\n * A `computed` map declares pure, synchronous functions keyed by field\n * path. {@link evalComputedFields} runs them in declaration order — each\n * function sees the record with all prior computed fields already\n * injected, so a later field can read an earlier one (`total` reads\n * `netAmount`). The result is stored like any field: queryable,\n * indexable, and `aggregate(sum())`-able (exactly, when the field is also\n * a `money()` field).\n *\n * Computed evaluation is the FIRST stage of the write pipeline (before\n * schema validation), so the user need not supply computed fields and the\n * schema validates the computed result. Cross-record / async derivation\n * is out of scope here — see the validation subsystem (#299).\n */\n\nimport { NoydbError } from '../errors.js'\n\nexport type ComputedFn<T = Record<string, unknown>> = (record: T) => unknown\n\nexport type ComputedFields<T = Record<string, unknown>> = Record<string, ComputedFn<T>>\n\n/** Raised when a computed function throws during a write. */\nexport class ComputedFieldError extends NoydbError {\n constructor(\n public readonly field: string,\n public readonly id: string,\n public readonly cause: unknown,\n ) {\n super(\n 'COMPUTED_FIELD',\n `computed field \"${field}\" threw for record \"${id}\": ` +\n (cause instanceof Error ? cause.message : String(cause)),\n )\n this.name = 'ComputedFieldError'\n }\n}\n\n/**\n * Evaluate every computed field in declaration order, injecting each\n * result into a shallow clone. A computed field overwrites any\n * user-supplied value of the same name — the field is schema-owned.\n * Returns the new record; the input is not mutated.\n */\nexport function evalComputedFields<T extends Record<string, unknown>>(\n record: T,\n computed: ComputedFields,\n id: string,\n): T {\n const out: Record<string, unknown> = { ...record }\n for (const [field, fn] of Object.entries(computed)) {\n try {\n out[field] = fn(out)\n } catch (cause) {\n throw new ComputedFieldError(field, id, cause)\n }\n }\n return out as T\n}\n","/**\n * Strategy seam for the optional i18n (multi-locale + dictionary)\n * subsystem. Core imports `I18nStrategy` type-only + `NO_I18N` stub;\n * real `applyI18nLocale` / `validateI18nTextValue` /\n * `DictionaryHandle` are only reachable via `withI18n()` in\n * `./active.ts`.\n *\n * Solo apps that don't use `i18nText()` fields, don't declare\n * `dictKey()` fields, and don't open a `vault.dictionary(...)` handle\n * ship none of the ~854 LOC behind this seam.\n *\n * Behavior under NO_I18N:\n *\n * - **applyI18nLocale** — returns the record unchanged. Apps without\n * any i18n descriptors never observe a difference; apps that\n * *did* declare i18nText/dictKey fields without opting into the\n * strategy still get raw values back (locale resolution silently\n * skipped). The validators below ensure the misconfiguration is\n * caught at write time instead.\n * - **validateI18nTextValue** — throws when called. Only fires when\n * a collection declared `i18nFields`; if you declared the field,\n * you must opt in.\n * - **buildDictionaryHandle** — throws when called. Only fires when\n * user code calls `vault.dictionary(...)`.\n *\n * @internal\n */\n\nimport type { NoydbStore } from '../types.js'\nimport type { LedgerStore } from '../history/ledger/store.js'\nimport type { UnlockedKeyring } from '../team/keyring.js'\nimport type { NoydbEventEmitter } from '../events.js'\nimport type { I18nTextDescriptor } from './core.js'\nimport type { Layer } from './policy.js'\nimport type { ScriptWarning } from './script.js'\nimport type { DictionaryHandle, DictionaryOptions } from './dictionary.js'\n\n/**\n * Options accepted by `I18nStrategy.buildDictionaryHandle`. Mirrors\n * the `DictionaryHandle` constructor verbatim — kept here so core\n * code never imports the dictionary module at runtime.\n *\n * @internal\n */\nexport interface BuildDictionaryHandleOptions<Keys extends string = string> {\n adapter: NoydbStore\n compartmentName: string\n dictionaryName: string\n keyring: UnlockedKeyring\n getDEK: (collectionName: string) => Promise<CryptoKey>\n encrypted: boolean\n ledger: LedgerStore | undefined\n options: DictionaryOptions\n findAndUpdateReferences:\n | ((\n dictionaryName: string,\n oldKey: string,\n newKey: string,\n ) => Promise<void>)\n | undefined\n emitter: NoydbEventEmitter\n /**\n * Used by the active strategy to satisfy the generic-key parameter\n * on the returned handle. The NO_I18N stub never reads it.\n */\n // marker generic — runtime sees no value\n _keyMarker?: Keys\n}\n\n/**\n * @internal\n */\nexport interface I18nStrategy {\n /**\n * Resolve `i18nText` fields on a record to the requested locale and\n * return a new object. Returns the input unchanged under\n * `NO_I18N`.\n */\n applyI18nLocale(\n record: Record<string, unknown>,\n fields: Record<string, I18nTextDescriptor>,\n locale: string,\n fallback?: string | readonly string[],\n layer?: Layer,\n ): Record<string, unknown>\n\n /**\n * Validate that an i18nText field's value satisfies its descriptor\n * (required locales present, etc.). Throws under `NO_I18N` —\n * declaring i18nFields without opting in is a misconfiguration.\n */\n validateI18nTextValue(\n value: unknown,\n field: string,\n descriptor: I18nTextDescriptor,\n ): void\n\n /**\n * Enforce per-locale script constraints over an i18nText value map\n * (write-time). Returns the (possibly filtered) value plus any\n * non-fatal warnings. Returns the value unchanged when the field has\n * no `script` option, or under `NO_I18N`.\n */\n enforceScript(\n value: Record<string, unknown>,\n field: string,\n descriptor: I18nTextDescriptor,\n ): { value: Record<string, unknown>; warnings: ScriptWarning[] }\n\n /**\n * Construct a typed `DictionaryHandle` for the named dictionary.\n * Throws under `NO_I18N`.\n */\n buildDictionaryHandle<Keys extends string = string>(\n opts: BuildDictionaryHandleOptions<Keys>,\n ): DictionaryHandle<Keys>\n}\n\nfunction notEnabled(op: string): Error {\n return new Error(\n `${op} requires the i18n strategy. Import ` +\n '`{ withI18n }` from \"@noy-db/hub/i18n\" and pass it to ' +\n '`createNoydb({ i18nStrategy: withI18n() })`.',\n )\n}\n\n/**\n * No-i18n stub. Locale resolution is the identity; validation and\n * dictionary construction throw with an actionable pointer.\n *\n * @internal\n */\nexport const NO_I18N: I18nStrategy = {\n applyI18nLocale(record) { return record },\n validateI18nTextValue() { throw notEnabled('i18nText field validation') },\n enforceScript(value) { return { value, warnings: [] } },\n buildDictionaryHandle() { throw notEnabled('vault.dictionary()') },\n}\n","/**\n * Standard Schema v1 integration.\n *\n * This file is the entry point for **schema validation**. Any\n * validator that implements the [Standard Schema v1\n * protocol](https://standardschema.dev) — Zod, Valibot, ArkType, Effect\n * Schema, etc. — can be attached to a `Collection` or `defineNoydbStore`\n * and will:\n *\n * 1. Validate the record BEFORE encryption on `put()` — bad data is\n * rejected at the store boundary with a rich issue list.\n * 2. Validate the record AFTER decryption on `get()`/`list()`/`query()`\n * — stored data that has drifted from the current schema throws\n * loudly instead of silently propagating garbage to the UI.\n *\n * ## Why vendor the types?\n *\n * Standard Schema is a protocol, not a library. The spec is <200 lines of\n * TypeScript and has no runtime. There's an official `@standard-schema/spec`\n * types package on npm, but pulling it in would add a dependency edge\n * purely for type definitions. Vendoring the minimal surface keeps\n * `@noy-db/core` at **zero runtime dependencies** and gives us freedom to\n * evolve the helpers without a version-lock on the spec package.\n *\n * If the spec changes in a breaking way (unlikely — it's frozen at v1),\n * we update this file and bump our minor.\n *\n * ## Why not just run `schema.parse(value)` directly?\n *\n * Because then we'd be locked to whichever validator happens to have\n * `.parse`. Standard Schema's `'~standard'.validate` contract is the same\n * across every implementation and includes a structured issues list,\n * which is much more useful than a thrown error for programmatic error\n * handling (e.g., rendering field-level messages in a Vue component).\n */\n\nimport { SchemaValidationError } from './errors.js'\n\n/**\n * The Standard Schema v1 protocol. A schema is any object that exposes a\n * `'~standard'` property with `version: 1` and a `validate` function.\n *\n * The type parameters are:\n * - `Input` — the type accepted by `validate` (what the user passes in)\n * - `Output` — the type produced by `validate` (what we store/return,\n * may differ from Input if the schema transforms or coerces)\n *\n * In most cases `Input === Output`, but validators that transform\n * (Zod's `.transform`, Valibot's `transform`, etc.) can narrow or widen.\n *\n * We intentionally keep the `types` field `readonly` and optional — the\n * spec marks it as optional because it's only used for inference, and\n * not every implementation bothers populating it at runtime.\n */\nexport interface StandardSchemaV1<Input = unknown, Output = Input> {\n readonly '~standard': {\n readonly version: 1\n readonly vendor: string\n readonly validate: (\n value: unknown,\n ) =>\n | StandardSchemaV1SyncResult<Output>\n | Promise<StandardSchemaV1SyncResult<Output>>\n readonly types?:\n | {\n readonly input: Input\n readonly output: Output\n }\n | undefined\n }\n}\n\n/**\n * The result of a single call to `schema['~standard'].validate`. Either\n * `{ value }` on success or `{ issues }` on failure — never both.\n *\n * The spec allows `issues` to be undefined on success (and some\n * validators leave it that way), so consumers should discriminate on\n * `issues?.length` rather than on truthiness of `value`.\n */\nexport type StandardSchemaV1SyncResult<Output> =\n | { readonly value: Output; readonly issues?: undefined }\n | {\n readonly value?: undefined\n readonly issues: readonly StandardSchemaV1Issue[]\n }\n\n/**\n * A single validation issue. The `message` is always present; the `path`\n * is optional and points at the offending field when the schema tracks\n * it (virtually every validator does for object types).\n *\n * The path is deliberately permissive — both a plain `PropertyKey` and a\n * `{ key }` wrapper are allowed so validators that wrap path segments in\n * objects (Zod does this in some modes) don't need special handling.\n */\nexport interface StandardSchemaV1Issue {\n readonly message: string\n readonly path?:\n | ReadonlyArray<PropertyKey | { readonly key: PropertyKey }>\n | undefined\n}\n\n/**\n * Infer the output type of a Standard Schema. Consumers use this to\n * pull the type out of a schema instance when they want to declare a\n * Collection<T> or defineNoydbStore<T> with `T` derived from the schema.\n *\n * Example:\n * ```ts\n * const InvoiceSchema = z.object({ id: z.string(), amount: z.number() })\n * type Invoice = InferOutput<typeof InvoiceSchema>\n * ```\n */\nexport type InferOutput<T extends StandardSchemaV1> =\n T extends StandardSchemaV1<unknown, infer O> ? O : never\n\n/**\n * Validate an input value against a schema. Throws\n * `SchemaValidationError` if the schema rejects, with the rich issue\n * list attached. Otherwise returns the (possibly transformed) output\n * value.\n *\n * The `context` string is included in the thrown error's message so the\n * caller knows where the failure happened (e.g. `\"put(inv-001)\"`) without\n * every caller having to wrap the throw in a try/catch.\n *\n * This function is ALWAYS async because some validators (notably Effect\n * Schema and Zod's `.refine` with async predicates) can return a\n * Promise. We `await` the result unconditionally to normalize the\n * contract — the extra microtask is free compared to the cost of an\n * encrypt/decrypt round-trip.\n */\nexport async function validateSchemaInput<Output>(\n schema: StandardSchemaV1<unknown, Output>,\n value: unknown,\n context: string,\n): Promise<Output> {\n const result = await schema['~standard'].validate(value)\n if (result.issues !== undefined && result.issues.length > 0) {\n throw new SchemaValidationError(\n `Schema validation failed on ${context}: ${summarizeIssues(result.issues)}`,\n result.issues,\n 'input',\n )\n }\n // Safe: the spec guarantees `value` is present when `issues` is absent.\n return result.value as Output\n}\n\n/**\n * Validate an already-stored value coming OUT of the collection. This\n * is a distinct helper from `validateSchemaInput` because the error\n * semantics differ: an output-validation failure means the data in\n * storage has drifted from the current schema (an unexpected state),\n * whereas an input-validation failure means the user passed bad data\n * (an expected state for a UI that isn't guarding its inputs).\n *\n * We still throw — silently returning bad data would be worse — but\n * the error carries `direction: 'output'` so upstream code (and a\n * potential migrate hook) can distinguish the two cases.\n */\nexport async function validateSchemaOutput<Output>(\n schema: StandardSchemaV1<unknown, Output>,\n value: unknown,\n context: string,\n): Promise<Output> {\n const result = await schema['~standard'].validate(value)\n if (result.issues !== undefined && result.issues.length > 0) {\n throw new SchemaValidationError(\n `Stored data for ${context} does not match the current schema — ` +\n `schema drift? ${summarizeIssues(result.issues)}`,\n result.issues,\n 'output',\n )\n }\n return result.value as Output\n}\n\n/**\n * Produce a short human-readable summary of an issue list for the\n * thrown error's message. The full issue array is still attached to the\n * error as a property — this is only for the `.message` string that\n * shows up in console.error / stack traces.\n *\n * Format: `field: message; field2: message2` (up to 3 issues, then `…`).\n * Issues without a path are shown as `root: message`.\n */\nfunction summarizeIssues(\n issues: readonly StandardSchemaV1Issue[],\n): string {\n const shown = issues.slice(0, 3).map((issue) => {\n const pathStr = formatPath(issue.path)\n return `${pathStr}: ${issue.message}`\n })\n const suffix = issues.length > 3 ? ` (+${issues.length - 3} more)` : ''\n return shown.join('; ') + suffix\n}\n\nfunction formatPath(\n path: StandardSchemaV1Issue['path'],\n): string {\n if (!path || path.length === 0) return 'root'\n return path\n .map((segment) =>\n typeof segment === 'object' && segment !== null\n ? String(segment.key)\n : String(segment),\n )\n .join('.')\n}\n","/**\n * Strategy seam for the optional history + ledger + time-machine\n * subsystem. Core imports `HistoryStrategy` type-only + `NO_HISTORY`\n * stub; real implementations of `saveHistory`, `LedgerStore`,\n * `VaultInstant`, `computePatch`, `diff` etc. are only reachable via\n * `withHistory()` in `./active.ts`.\n *\n * Applications that don't track per-record versioning, don't need the\n * hash-chained audit ledger, and don't restore to past instants ship\n * none of the ~1,880 LOC behind this seam.\n *\n * Strategy contract:\n *\n * - **saveHistory / pruneHistory / clearHistory** — no-ops under\n * NO_HISTORY. Writes still succeed; no snapshot is captured.\n * - **getHistoryEntries / getVersionEnvelope / diff** — throw under\n * NO_HISTORY. These are read APIs the consumer would only call\n * after explicitly asking for history; the throw guides them to\n * `@noy-db/hub/history`.\n * - **envelopePayloadHash / computePatch** — return empty / `[]`\n * under NO_HISTORY. These are only used inside the\n * `if (this.ledger)` branch, which is itself gated by\n * `buildLedger()` returning null.\n * - **buildLedger** — returns `null` under NO_HISTORY. The Vault's\n * public `vault.ledger()` accessor throws when null.\n * - **buildVaultInstant** — throws under NO_HISTORY. `vault.at()`\n * propagates the throw.\n *\n * @internal\n */\n\nimport type {\n EncryptedEnvelope,\n NoydbStore,\n HistoryOptions,\n PruneOptions,\n} from '../types.js'\nimport type { LedgerStore } from './ledger/store.js'\nimport type { JsonPatch } from './ledger/patch.js'\nimport type { DiffEntry } from './diff.js'\nimport type { VaultInstant, VaultEngine } from './time-machine.js'\n\n/**\n * Options accepted by `HistoryStrategy.buildLedger`. Mirrors the\n * `LedgerStore` constructor verbatim — kept in this file so `core`\n * code never imports the LedgerStore module at runtime.\n *\n * @internal\n */\nexport interface BuildLedgerOptions {\n adapter: NoydbStore\n vault: string\n encrypted: boolean\n getDEK: (collectionName: string) => Promise<CryptoKey>\n actor: string\n}\n\n/**\n * @internal\n */\nexport interface HistoryStrategy {\n /**\n * Persist a full encrypted envelope snapshot of the prior version\n * under `_history/{collection}:{id}:{paddedVersion}`. No-op under\n * `NO_HISTORY`.\n */\n saveHistory(\n adapter: NoydbStore,\n vault: string,\n collection: string,\n recordId: string,\n envelope: EncryptedEnvelope,\n ): Promise<void>\n\n /**\n * List history envelopes for a record, newest first. Throws under\n * `NO_HISTORY` — callers reach this via `collection.history()` /\n * `collection.getVersion()` / `collection.diff()`, which only work\n * with the strategy enabled.\n */\n getHistoryEntries(\n adapter: NoydbStore,\n vault: string,\n collection: string,\n recordId: string,\n options?: HistoryOptions,\n ): Promise<EncryptedEnvelope[]>\n\n /**\n * Fetch a specific version's envelope. Throws under `NO_HISTORY`.\n */\n getVersionEnvelope(\n adapter: NoydbStore,\n vault: string,\n collection: string,\n recordId: string,\n version: number,\n ): Promise<EncryptedEnvelope | null>\n\n /**\n * Prune history entries by retention rule. Returns `0` under\n * `NO_HISTORY`.\n */\n pruneHistory(\n adapter: NoydbStore,\n vault: string,\n collection: string,\n recordId: string | undefined,\n options: PruneOptions,\n ): Promise<number>\n\n /**\n * Clear all history for vault/collection/record. Returns `0` under\n * `NO_HISTORY`.\n */\n clearHistory(\n adapter: NoydbStore,\n vault: string,\n collection?: string,\n recordId?: string,\n ): Promise<number>\n\n /**\n * Crypto-shred (overwrite-to-tombstone) every `_history` version of a\n * record for GDPR erasure (#304). Returns the number of versions newly\n * tombstoned, or `0` under `NO_HISTORY` (no history = nothing to shred).\n */\n tombstoneHistory(\n adapter: NoydbStore,\n vault: string,\n collection: string,\n recordId: string,\n actor: string,\n ): Promise<number>\n\n /**\n * Compute the SHA-256 hash of an envelope's encrypted payload, used\n * by `LedgerStore.append` to track tamper-evidence. Returns the\n * empty string under `NO_HISTORY` (the call site is gated by\n * `if (this.ledger)`, so the value is never observed).\n */\n envelopePayloadHash(envelope: EncryptedEnvelope | null): Promise<string>\n\n /**\n * Compute the JSON patch from `from` → `to`. Returns `[]` under\n * `NO_HISTORY`.\n */\n computePatch(from: unknown, to: unknown): JsonPatch\n\n /**\n * Compute the typed diff between two records. Throws under\n * `NO_HISTORY` — `collection.diff()` is a history-read API.\n */\n diff(recordA: unknown, recordB: unknown): DiffEntry[]\n\n /**\n * Construct (or return null) a `LedgerStore` for the vault. Returns\n * `null` under `NO_HISTORY`; the Vault treats null as \"no ledger\n * attached\" — collection write paths skip the append branch and the\n * public `vault.ledger()` accessor throws.\n */\n buildLedger(opts: BuildLedgerOptions): LedgerStore | null\n\n /**\n * Construct a `VaultInstant` for time-machine reads. Throws under\n * `NO_HISTORY`.\n */\n buildVaultInstant(engine: VaultEngine, timestamp: string): VaultInstant\n}\n\n/**\n * Error thrown when the consumer reaches a history-gated surface\n * without opting into the strategy. The message names the offending\n * operation and points to the subpath import.\n *\n * @internal\n */\nfunction notEnabled(op: string): Error {\n return new Error(\n `${op} requires the history strategy. Import ` +\n '`{ withHistory }` from \"@noy-db/hub/history\" and pass it to ' +\n '`createNoydb({ historyStrategy: withHistory() })`.',\n )\n}\n\n/**\n * No-history stub. Snapshots and prune/clear are no-ops; reads and\n * time-machine throw with an actionable message; ledger construction\n * returns null so the write-path's `if (this.ledger)` branch is dead\n * code in the bundle.\n *\n * @internal\n */\nexport const NO_HISTORY: HistoryStrategy = {\n async saveHistory() {},\n async getHistoryEntries() { throw notEnabled('collection.history()') },\n async getVersionEnvelope() { throw notEnabled('collection.getVersion()') },\n async pruneHistory() { return 0 },\n async clearHistory() { return 0 },\n async tombstoneHistory() { return 0 },\n async envelopePayloadHash() { return '' },\n computePatch() { return [] },\n diff() { throw notEnabled('collection.diff()') },\n buildLedger() { return null },\n buildVaultInstant() { throw notEnabled('vault.at() / vault.timeMachine()') },\n}\n","/**\n * Strategy seam between core Collection and the optional indexing\n * subsystem. Core imports `IndexStrategy` and `IndexState` as\n * TYPE-ONLY symbols and `NO_INDEXING` as a tiny runtime stub.\n *\n * The heavy classes — `CollectionIndexes`, `PersistedCollectionIndex`,\n * `LazyQuery` — are only instantiated inside the `withIndexing()`\n * factory under `./active.ts`, which in turn is only reachable through\n * the `@noy-db/hub/indexing` subpath export. A consumer that never\n * imports the subpath ships none of those classes in their bundle\n * (ESM tree-shaking + hub's `\"sideEffects\": false`).\n *\n * @internal\n */\n\nimport type { CollectionIndexes, IndexDef } from './eager-indexes.js'\nimport type { PersistedCollectionIndex } from './persisted-indexes.js'\n\n/**\n * Per-collection container for whatever mirrors the active strategy\n * decided to materialize. Both accessors may return `null` — they do\n * for `NO_INDEXING`, and `getEagerIndexes` returns null in a\n * lazy-mode collection even when indexing is active (lazy uses the\n * persisted mirror instead).\n *\n * `isEnabled` is a cheap guard so collection code can short-circuit\n * the full indexing path without inspecting either mirror.\n *\n * @internal\n */\nexport interface IndexState {\n readonly isEnabled: boolean\n getEagerIndexes(): CollectionIndexes | null\n getPersistedIndexes(): PersistedCollectionIndex | null\n}\n\n/**\n * Factory that builds one `IndexState` per Collection. Called exactly\n * once inside each Collection constructor with the declared\n * `IndexDef[]` and the lazy-mode flag (so lazy collections get the\n * persisted mirror and eager collections get the in-memory one).\n *\n * @internal\n */\nexport interface IndexStrategy {\n createState(args: {\n readonly defs: readonly IndexDef[]\n readonly lazy: boolean\n }): IndexState\n}\n\n/**\n * No-indexing stub. Every Collection defaults to this; it returns a\n * cheap `IndexState` whose mirrors are both `null`. Collection code\n * null-checks both accessors and short-circuits, so no indexing code\n * path runs and the heavy classes never arrive in the bundle.\n *\n * @internal\n */\nexport const NO_INDEXING: IndexStrategy = {\n createState() {\n return DISABLED_STATE\n },\n}\n\nconst DISABLED_STATE: IndexState = {\n isEnabled: false,\n getEagerIndexes: () => null,\n getPersistedIndexes: () => null,\n}\n","/**\n * In-memory unique-constraint enforcement for eager-mode collections.\n *\n * Each `UniqueConstraintSet` holds one or more constraints, each covering\n * an ordered tuple of field names. On every `put()` the caller invokes\n * `check()` BEFORE the store write; on success it calls `upsert()` to\n * update the maps. `remove()` is called on `delete()`.\n *\n * Null-distinct semantics: if ANY constrained field is `null` or\n * `undefined` in the record, that record is exempt from the constraint —\n * `keyFor` returns `null` and the record is silently skipped.\n * This matches standard SQL NULL-distinct behavior.\n *\n * Only used in eager mode (`prefetch !== false`). Lazy-mode collections\n * throw at registration instead (see Collection constructor).\n */\n\nimport { readPath } from '../query/predicate.js'\nimport { canonicalGroupKey } from '../aggregate/canonical-key.js'\nimport { UniqueConstraintError, UnsupportedIndexOptionError } from '../errors.js'\nimport type { IndexDef } from './eager-indexes.js'\n\ninterface Constraint {\n readonly fields: readonly string[]\n /** canonicalKey → id of the record holding that key */\n readonly map: Map<string, string>\n}\n\nexport class UniqueConstraintSet {\n private readonly constraints: Constraint[]\n\n constructor(\n private readonly collectionName: string,\n uniqueDefs: readonly (readonly string[])[],\n ) {\n this.constraints = uniqueDefs.map(fields => ({ fields, map: new Map() }))\n }\n\n get size(): number {\n return this.constraints.length\n }\n\n /**\n * Compute the canonical key for a record under a given constraint.\n * Returns `null` if any constrained field is `null` or `undefined`\n * (the record is exempt — no constraint is checked).\n */\n private keyFor(fields: readonly string[], record: unknown): string | null {\n const row: Record<string, unknown> = {}\n for (const f of fields) {\n const v = readPath(record, f)\n if (v === null || v === undefined) return null\n row[f] = v\n }\n return canonicalGroupKey(fields, row)\n }\n\n /**\n * Throw `UniqueConstraintError` if writing `id` with `record` would\n * collide with a DIFFERENT existing record. Call BEFORE the store write.\n */\n check(id: string, record: unknown): void {\n for (const c of this.constraints) {\n const key = this.keyFor(c.fields, record)\n if (key === null) continue\n const holder = c.map.get(key)\n if (holder !== undefined && holder !== id) {\n throw new UniqueConstraintError(this.collectionName, id, c.fields, holder)\n }\n }\n }\n\n /**\n * Update the constraint maps after a successful write.\n * Pass `previous` when updating an existing record (so the old key\n * is removed first). Pass `null` or `undefined` for a fresh insert.\n */\n upsert(id: string, record: unknown, previous?: unknown): void {\n if (previous != null) this.remove(id, previous)\n for (const c of this.constraints) {\n const key = this.keyFor(c.fields, record)\n if (key !== null) c.map.set(key, id)\n }\n }\n\n /**\n * Remove a record from all constraint maps.\n * Called by `Collection.delete()`.\n */\n remove(id: string, record: unknown): void {\n for (const c of this.constraints) {\n const key = this.keyFor(c.fields, record)\n if (key !== null && c.map.get(key) === id) c.map.delete(key)\n }\n }\n\n /**\n * Rebuild all constraint maps from a full snapshot.\n * Called after hydration (ensureHydrated / hydrateFromSnapshot).\n *\n * **Last-writer-wins**: this method does NOT validate pre-existing data\n * for duplicates. If the store already contains two records sharing a\n * constrained value (written before the unique index was declared), the\n * last one processed wins the map slot and the duplicate is silently\n * displaced — no error is thrown, and the earlier holder is evicted from\n * the map. Callers retrofitting a unique index onto populated data should\n * run a one-time uniqueness scan before relying on enforcement.\n */\n build(entries: Iterable<readonly [string, unknown]>): void {\n for (const c of this.constraints) c.map.clear()\n for (const [id, record] of entries) {\n this.upsert(id, record)\n }\n }\n}\n\n/**\n * Build the `UniqueConstraintSet` for a collection from its `IndexDef[]`,\n * or return `null` when no `unique: true` index is declared.\n *\n * Unique enforcement is **eager-mode only**. If any `unique` index is\n * declared on a lazy (`prefetch:false`), CRDT, or tiered collection, this\n * throws `UnsupportedIndexOptionError` at registration rather than letting\n * those write paths (which bypass `check()`/`upsert()`) silently skip\n * enforcement. Kept out of the Collection constructor to keep that\n * always-on kernel file lean (kernel-surface invariant).\n */\nexport function buildUniqueConstraintSet(\n collectionName: string,\n indexes: readonly IndexDef[] | undefined,\n mode: { readonly lazy: boolean; readonly crdt: boolean; readonly tiered: boolean },\n): UniqueConstraintSet | null {\n const uniqueDefs: (readonly string[])[] = []\n for (const def of indexes ?? []) {\n if (\n def !== null &&\n typeof def === 'object' &&\n !Array.isArray(def) &&\n (def as { unique?: boolean }).unique === true\n ) {\n uniqueDefs.push((def as { fields: readonly string[] }).fields)\n }\n }\n if (uniqueDefs.length === 0) return null\n\n if (mode.lazy) {\n throw new UnsupportedIndexOptionError(\n 'unique',\n `unique indexes are not yet supported in lazy mode (prefetch:false) — use the default eager mode. Collection \"${collectionName}\".`,\n )\n }\n if (mode.crdt) {\n throw new UnsupportedIndexOptionError(\n 'unique',\n `unique indexes are not supported on CRDT collections (crdt mode is incompatible with eager unique enforcement). Collection \"${collectionName}\".`,\n )\n }\n if (mode.tiered) {\n throw new UnsupportedIndexOptionError(\n 'unique',\n `unique indexes are not supported on tiered collections (tier writes use a separate path that bypasses unique enforcement). Collection \"${collectionName}\".`,\n )\n }\n return new UniqueConstraintSet(collectionName, uniqueDefs)\n}\n","/**\n * Generic LRU cache for `Collection`'s lazy hydration mode.\n *\n * Backed by a JavaScript `Map`, which preserves insertion order. Promotion\n * is implemented as `delete()` + `set()` — O(1) on `Map` since both\n * operations are constant-time. Eviction walks the iterator from the front\n * (least recently used) until both budgets are satisfied.\n *\n * ships in-memory only. The cache is never persisted; on collection\n * close every entry is dropped. Persisting cache state is a follow-up\n * once the access patterns from real consumers tell us whether it would\n * pay back the complexity.\n */\n\nexport interface LruEntry<V> {\n /** The cached value. */\n readonly value: V\n /**\n * Approximate decrypted byte size of the entry. Used by the byte-budget\n * eviction path. Callers compute this once at insert time and pass it\n * in — recomputing on every access would dominate the per-record cost.\n */\n readonly size: number\n}\n\nexport interface LruOptions {\n /** Maximum number of entries before eviction. Required if `maxBytes` is unset. */\n maxRecords?: number\n /** Maximum total bytes before eviction. Computed from per-entry `size`. */\n maxBytes?: number\n}\n\nexport interface LruStats {\n /** Total cache hits since construction (or `resetStats()`). */\n hits: number\n /** Total cache misses since construction (or `resetStats()`). */\n misses: number\n /** Total entries evicted since construction (or `resetStats()`). */\n evictions: number\n /** Current number of cached entries. */\n size: number\n /** Current sum of cached entry sizes (in bytes, approximate). */\n bytes: number\n}\n\n/**\n * O(1) LRU cache. Both `get()` and `set()` promote the touched entry to\n * the most-recently-used end. Eviction happens after every insert and\n * walks the front of the Map iterator dropping entries until both\n * budgets are satisfied.\n */\nexport class Lru<K, V> {\n private readonly entries = new Map<K, LruEntry<V>>()\n private readonly maxRecords: number | undefined\n private readonly maxBytes: number | undefined\n private currentBytes = 0\n private hits = 0\n private misses = 0\n private evictions = 0\n\n constructor(options: LruOptions) {\n if (options.maxRecords === undefined && options.maxBytes === undefined) {\n throw new Error('Lru: must specify maxRecords, maxBytes, or both')\n }\n this.maxRecords = options.maxRecords\n this.maxBytes = options.maxBytes\n }\n\n /**\n * Look up a key. Hits promote the entry to most-recently-used; misses\n * return undefined. Both update the running stats counters.\n */\n get(key: K): V | undefined {\n const entry = this.entries.get(key)\n if (!entry) {\n this.misses++\n return undefined\n }\n // Promote: re-insert moves the entry to the end of the iteration order.\n this.entries.delete(key)\n this.entries.set(key, entry)\n this.hits++\n return entry.value\n }\n\n /**\n * Insert or update a key. If the key already exists, its size is\n * accounted for and the entry is promoted to MRU. After insertion,\n * eviction runs to maintain both budgets.\n */\n set(key: K, value: V, size: number): void {\n const existing = this.entries.get(key)\n if (existing) {\n // Update path: subtract the old size before adding the new one.\n this.currentBytes -= existing.size\n this.entries.delete(key)\n }\n this.entries.set(key, { value, size })\n this.currentBytes += size\n this.evictUntilUnderBudget()\n }\n\n /**\n * Remove a key without affecting hit/miss stats. Used by `Collection.delete()`.\n * Returns true if the key was present.\n */\n remove(key: K): boolean {\n const existing = this.entries.get(key)\n if (!existing) return false\n this.currentBytes -= existing.size\n this.entries.delete(key)\n return true\n }\n\n /** True if the cache currently holds an entry for the given key. */\n has(key: K): boolean {\n return this.entries.has(key)\n }\n\n /**\n * Drop every entry. Stats counters survive — call `resetStats()` if you\n * want a clean slate. Used by `Collection.invalidate()` on key rotation.\n */\n clear(): void {\n this.entries.clear()\n this.currentBytes = 0\n }\n\n /** Reset hit/miss/eviction counters to zero. Does NOT touch entries. */\n resetStats(): void {\n this.hits = 0\n this.misses = 0\n this.evictions = 0\n }\n\n /** Snapshot of current cache statistics. Cheap — no copying. */\n stats(): LruStats {\n return {\n hits: this.hits,\n misses: this.misses,\n evictions: this.evictions,\n size: this.entries.size,\n bytes: this.currentBytes,\n }\n }\n\n /**\n * Iterate over all currently-cached values. Order is least-recently-used\n * first. Used by tests and devtools — production callers should use\n * `Collection.scan()` instead.\n */\n *values(): IterableIterator<V> {\n for (const entry of this.entries.values()) yield entry.value\n }\n\n /**\n * Walk the cache from the LRU end and drop entries until both budgets\n * are satisfied. Called after every `set()`. Single pass — entries are\n * never re-promoted during eviction.\n */\n private evictUntilUnderBudget(): void {\n while (this.overBudget()) {\n const oldest = this.entries.keys().next()\n if (oldest.done) return // empty cache; nothing more to evict\n const key = oldest.value\n const entry = this.entries.get(key)\n if (entry) this.currentBytes -= entry.size\n this.entries.delete(key)\n this.evictions++\n }\n }\n\n private overBudget(): boolean {\n if (this.maxRecords !== undefined && this.entries.size > this.maxRecords) return true\n if (this.maxBytes !== undefined && this.currentBytes > this.maxBytes) return true\n return false\n }\n}\n","/**\n * Cache policy helpers — parse human-friendly byte budgets into raw numbers.\n *\n * Accepted shapes (case-insensitive on suffix):\n * number — interpreted as raw bytes\n * '1024' — string of digits, raw bytes\n * '50KB' — kilobytes (×1024)\n * '50MB' — megabytes (×1024²)\n * '1GB' — gigabytes (×1024³)\n *\n * Decimals are accepted (`'1.5GB'` → 1610612736 bytes).\n *\n * Anything else throws — better to fail loud at construction time than\n * to silently treat a typo as 0 bytes (which would evict everything).\n */\n\nconst UNITS: Record<string, number> = {\n '': 1,\n 'B': 1,\n 'KB': 1024,\n 'MB': 1024 * 1024,\n 'GB': 1024 * 1024 * 1024,\n // 'TB' deliberately not supported — if you need it, you're not using NOYDB.\n}\n\n/** Parse a byte budget into a positive integer number of bytes. */\nexport function parseBytes(input: number | string): number {\n if (typeof input === 'number') {\n if (!Number.isFinite(input) || input <= 0) {\n throw new Error(`parseBytes: numeric input must be a positive finite number, got ${String(input)}`)\n }\n return Math.floor(input)\n }\n\n const trimmed = input.trim()\n if (trimmed === '') {\n throw new Error('parseBytes: empty string is not a valid byte budget')\n }\n\n // Accept either a bare number or a number followed by a unit suffix.\n // Regex: optional sign, digits with optional decimal, optional unit.\n const match = /^([0-9]+(?:\\.[0-9]+)?)\\s*([A-Za-z]*)$/.exec(trimmed)\n if (!match) {\n throw new Error(`parseBytes: invalid byte budget \"${input}\". Expected format: \"1024\", \"50KB\", \"50MB\", \"1GB\"`)\n }\n\n const value = parseFloat(match[1]!)\n const unit = (match[2] ?? '').toUpperCase()\n\n if (!(unit in UNITS)) {\n throw new Error(`parseBytes: unknown unit \"${match[2]}\" in \"${input}\". Supported: B, KB, MB, GB`)\n }\n\n const bytes = Math.floor(value * UNITS[unit]!)\n if (bytes <= 0) {\n throw new Error(`parseBytes: byte budget must be > 0, got ${bytes} from \"${input}\"`)\n }\n return bytes\n}\n\n/**\n * Estimate the in-memory byte size of a decrypted record.\n *\n * Uses `JSON.stringify().length` as a stand-in for actual heap usage.\n * It's a deliberate approximation: real V8 heap size includes pointer\n * overhead, hidden classes, and string interning that we can't measure\n * from JavaScript. The JSON length is a stable, monotonic proxy that\n * costs O(record size) per insert — fine when records are typically\n * < 1 KB and the cache eviction is the slow path anyway.\n *\n * Returns `0` (and the caller must treat it as 1 for accounting) if\n * stringification throws on circular references; this is documented\n * but in practice records always come from JSON-decoded envelopes.\n */\nexport function estimateRecordBytes(record: unknown): number {\n try {\n return JSON.stringify(record).length\n } catch {\n return 0\n }\n}\n","/**\n * Strategy seam for the optional sync engine + presence subsystem.\n * Core imports `SyncStrategy` type-only + `NO_SYNC` stub; the real\n * `SyncEngine`, `SyncTransaction`, and `PresenceHandle` constructors\n * are only reachable via `withSync()` in `./sync-active.ts`.\n *\n * Solo apps that never configure `sync` and never call\n * `collection.presence()` ship none of the ~856 LOC behind this seam\n * (`sync.ts` + `sync-transaction.ts` + `presence.ts`).\n *\n * Note: `keyring.ts` (~746 LOC) stays in core because it's required\n * for any multi-user vault — even single-owner vaults use a keyring\n * to wrap the DEK. The team package's grant/revoke/magic-link/\n * delegation modules tree-shake naturally via direct named imports.\n *\n * Behavior under NO_SYNC:\n *\n * - **buildSyncEngine** — throws. Only fires when `createNoydb({ sync })`\n * passes a remote target.\n * - **buildSyncTransaction** — throws. Only fires when `db.transaction(vault)`\n * is called on a vault with sync configured.\n * - **buildPresence** — throws. Only fires when user code calls\n * `collection.presence()`.\n *\n * @internal\n */\n\nimport type {\n NoydbStore,\n ConflictStrategy,\n SyncTargetRole,\n} from '../types.js'\nimport type { NoydbEventEmitter } from '../events.js'\nimport type { SyncPolicy } from '../store/sync-policy.js'\nimport type { SyncEngine } from './sync.js'\nimport type { SyncTransaction } from './sync-transaction.js'\nimport type { PresenceHandle, PresenceHandleOpts } from './presence.js'\nimport type { Vault } from '../vault.js'\n\n/**\n * Options accepted by `SyncStrategy.buildSyncEngine`. Mirrors the\n * `SyncEngine` constructor verbatim — kept here so core code never\n * imports the sync module at runtime.\n *\n * @internal\n */\nexport interface BuildSyncEngineOptions {\n local: NoydbStore\n remote: NoydbStore\n vault: string\n strategy: ConflictStrategy\n emitter: NoydbEventEmitter\n syncPolicy?: SyncPolicy\n role?: SyncTargetRole\n label?: string\n}\n\n/**\n * @internal\n */\nexport interface SyncStrategy {\n buildSyncEngine(opts: BuildSyncEngineOptions): SyncEngine\n buildSyncTransaction(vault: Vault, engine: SyncEngine): SyncTransaction\n buildPresence<P>(opts: PresenceHandleOpts): PresenceHandle<P>\n}\n\nfunction notEnabled(op: string): Error {\n return new Error(\n `${op} requires the sync strategy. Import ` +\n '`{ withSync }` from \"@noy-db/hub/sync\" and pass it to ' +\n '`createNoydb({ syncStrategy: withSync() })`.',\n )\n}\n\n/**\n * No-sync stub. Every constructor throws with an actionable pointer\n * — there is no useful \"off\" mode for sync engine / presence /\n * sync-transaction; if the consumer reached one of these surfaces,\n * they intended to use it.\n *\n * @internal\n */\nexport const NO_SYNC: SyncStrategy = {\n buildSyncEngine() { throw notEnabled('SyncEngine') },\n buildSyncTransaction() { throw notEnabled('SyncTransaction') },\n buildPresence() { throw notEnabled('collection.presence()') },\n}\n","/**\n * Strategy seam between core Collection and the optional blob subsystem.\n *\n * Core imports `BlobStrategy` as a TYPE-ONLY symbol and `NO_BLOBS` as a\n * minimal runtime stub. Neither pulls in the heavy `BlobSet` / chunk /\n * MIME machinery — those only arrive when the consumer explicitly\n * imports `@noy-db/hub/blobs` (see `./index.ts` → `withBlobs()` factory).\n *\n * This file is intentionally tiny and free of side effects so the\n * bundler keeps it in the graph without dragging everything else in.\n *\n * @internal\n */\n\nimport type { BlobSet } from './blob-set.js'\nimport type { NoydbStore } from '../types.js'\n\n/**\n * Args forwarded by `Collection.blob(id)` to the active strategy's\n * `openSlot`. The strategy is responsible for returning a live\n * `BlobSet` bound to the given record.\n *\n * @internal\n */\nexport interface BlobStrategyOpenArgs {\n readonly store: NoydbStore\n readonly vault: string\n readonly collection: string\n readonly recordId: string\n readonly getDEK: (collectionName: string) => Promise<CryptoKey>\n readonly encrypted: boolean\n readonly userId: string\n /**\n * Collection opts into per-record keys (`perRecordKeys`), so its blobs are\n * erasable: new uploads mint a per-blob content CEK (crypto-shreddable at\n * `refCount → 0`). Off → legacy shared-`_blob`-DEK chunks. See the per-blob\n * CEK design spec.\n */\n readonly erasableBlobs?: boolean\n}\n\n/**\n * The seam interface. `@internal` — do not build public APIs on this\n * shape; it can evolve freely until blobs are extracted into their\n * own package, at which point it will be promoted to public.\n *\n * @internal\n */\nexport interface BlobStrategy {\n openSlot(args: BlobStrategyOpenArgs): BlobSet\n}\n\n/**\n * Default strategy for collections that did not opt into blob storage.\n * Every operation surfaces an actionable error that points the caller\n * at the opt-in path.\n *\n * @internal\n */\nexport const NO_BLOBS: BlobStrategy = {\n openSlot() {\n throw new Error(\n 'Blob storage is not enabled on this Noydb instance. ' +\n 'Import `{ withBlobs }` from \"@noy-db/hub/blobs\" and pass `withBlobs()` to `createNoydb({ blobStrategy: withBlobs() })`.',\n )\n },\n}\n","import type { Collection } from '../collection.js'\nimport type { ReadOnlyVaultFacade } from '../guards/types.js'\nimport type { TxContext } from '../tx/transaction.js'\nimport type { DerivationRegistry } from './registry.js'\n// Type-only — runtime class loaded via dynamic import in\n// `resolveStaleOnRead` only when a stale flag actually fires. Keeps\n// the executor chunk out of the floor bundle.\nimport type { DerivationExecutor as DerivationExecutorType } from './executor.js'\nimport type { DerivationStrategy } from './types.js'\n\n/**\n * Accessor shape passed through from the owning Vault. Provides the\n * registry (used to look up strategies and as the WeakMap key) and a\n * resolver from collection name to the live `Collection` instance.\n * Same shape as `Collection.derivationSource` so callers can pass it\n * through directly.\n */\nexport interface DerivationStaleAccessor {\n registry(): DerivationRegistry\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n getCollection(name: string): Collection<any>\n /**\n * Read-only vault facade handed to `derive(source, ctx)` on the lazy\n * resolve-on-read path. Same instance/shape as the eager path uses.\n */\n getReadOnlyFacade(): ReadOnlyVaultFacade\n /**\n * Active multi-record TxContext or `null`. The lazy resolve-on-read\n * path uses this to register tombstone deletes on `_executed` so a\n * later rollback restores the prior emission. Mirrors the eager\n * path's rollback tracking; the lazy `put` was historically\n * unregistered but the tombstone delete (a NEW write path)\n * matches the eager registration for symmetry.\n */\n getActiveTxContext(): TxContext | null\n}\n\n/**\n * In-memory stale map keyed by `DerivationRegistry` instance (stable\n * per vault). Maps `${source}/${sourceId}` → set of pending strategies.\n *\n * Persistence across vault close is NOT implemented in v1 (concern\n * flagged in the dim14 spec). On vault re-open, derived records'\n * `_derivedFrom.strategyHash` will still match the registered\n * strategies' hash, so an unset stale flag is interpreted as \"fresh.\"\n * `vault.deriveAll()` (Task D13) is the explicit recompute escape\n * hatch.\n *\n * @internal\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst _staleByRegistry = new WeakMap<DerivationRegistry, Map<string, Set<DerivationStrategy<any, any>>>>()\n\nconst keyFor = (source: string, sourceId: string): string => `${source}/${sourceId}`\n\n/** Mark every output of (strategy, sourceId) as stale. */\nexport async function markStale(\n registry: DerivationRegistry,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n strategy: DerivationStrategy<any, any>,\n sourceId: string,\n): Promise<void> {\n let map = _staleByRegistry.get(registry)\n if (!map) {\n map = new Map()\n _staleByRegistry.set(registry, map)\n }\n const k = keyFor(strategy.source, sourceId)\n let set = map.get(k)\n if (!set) {\n set = new Set()\n map.set(k, set)\n }\n set.add(strategy)\n}\n\n/**\n * Called from `Collection.get` on lazy-mode output collections. If the\n * id has a pending stale flag for any strategy producing this output\n * collection, re-derive before returning the record. No-op when there\n * is no pending work — keeps the read fast path negligible.\n */\nexport async function resolveStaleOnRead(\n accessor: DerivationStaleAccessor,\n outputCollection: string,\n id: string,\n): Promise<void> {\n const registry = accessor.registry()\n const producers = registry.strategiesProducingOutput(outputCollection)\n if (producers.length === 0) return\n\n const map = _staleByRegistry.get(registry)\n if (!map) return\n\n // Dynamic-import the executor only when at least one stale flag\n // actually fires. Vaults with no derivation strategies never call\n // this function (gated on `derivationSource` in `Collection.get`);\n // vaults with strategies but no pending stale ids reach the\n // `pending.has(spec)` short-circuit below without ever touching\n // the executor chunk.\n let DerivationExecutor: typeof DerivationExecutorType | null = null\n\n for (const { spec, strategyHash } of producers) {\n const k = keyFor(spec.source, id)\n const pending = map.get(k)\n if (!pending || !pending.has(spec)) continue\n\n // Read the source record from the source collection and re-derive.\n // We use the same getCollection accessor that eager dispatch uses\n // — it returns the live `Collection<any>` instance with full\n // crypto / keyring wiring.\n const sourceColl = accessor.getCollection(spec.source)\n const source = await sourceColl.get(id)\n if (!source) {\n pending.delete(spec)\n continue\n }\n const sourceWithId = { ...(source as Record<string, unknown>), id } as Record<string, unknown> & { id: string }\n // sourceVersion: not tracked in v1 stale map; pass 0 — matches the\n // forthcoming v0 semantics, `_derivedFrom.sourceVersion` is\n // informational, not load-bearing for correctness.\n if (DerivationExecutor === null) {\n ({ DerivationExecutor } = (await import('./executor.js')) as { DerivationExecutor: typeof DerivationExecutorType })\n }\n const ctx = { vault: accessor.getReadOnlyFacade() }\n const result = await DerivationExecutor.run(spec, sourceWithId, 0, strategyHash, ctx)\n for (const key of Object.keys(spec.outputs)) {\n const out = result.outputs[key]\n if (!out) continue\n if (out.kind === 'failed') {\n const err = out.error\n if (spec.strict) {\n // Leave the stale flag set so a future read retries.\n throw err\n }\n console.warn(\n `[derivation] lazy output \"${key}\" for source \"${spec.source}\" id=\"${id}\" failed:`,\n err,\n )\n continue\n }\n if (out.kind === 'array') {\n // Defensive — array-shape requires `lifecycle: 'eager'`\n // (validated at withDerivation registration).\n // Reaching the lazy-resolve path for array-shape would mean\n // a registration check was bypassed. Log and skip.\n console.warn(\n `[derivation] unexpected array-shape output \"${key}\" in lazy resolve path; `\n + 'array-shape derivations require lifecycle: \"eager\".',\n )\n continue\n }\n const outSpec = spec.outputs[key]\n if (!outSpec) continue\n const outputColl = accessor.getCollection(outSpec.collection)\n if (out.skipped === true) {\n // Optional output skipped on lazy resolve — delete any\n // prior emission so the read returns null (matches eager-path\n // tombstone semantics). Routed through `_internalDelete` so a\n // user-registered `onDelete` on the output collection\n // does NOT fire. The active TxContext (if any) is forwarded:\n // `resolveStaleOnRead` is reachable from `Collection.get()`\n // which can be called from inside a transaction, so the\n // tombstone must be observable to `revertExecuted` on\n // rollback.\n await outputColl._internalDelete(id, accessor.getActiveTxContext())\n continue\n }\n await outputColl.put(id, out.value)\n }\n pending.delete(spec)\n }\n}\n","import type { NoydbStore, EncryptedEnvelope, ChangeEvent, HistoryConfig, HistoryOptions, HistoryEntry, PruneOptions, ListPageResult, LocaleReadOptions, ConflictPolicy, CollectionConflictResolver, PutManyItemOptions, PutManyOptions, PutManyResult, DeleteManyResult } from './types.js'\nimport { NOYDB_FORMAT_VERSION } from './types.js'\nimport type { CrdtMode, CrdtState, LwwMapState, RgaState } from './crdt/crdt.js'\nimport { NO_CRDT, type CrdtStrategy } from './crdt/strategy.js'\nimport type { I18nTextDescriptor } from './i18n/core.js'\nimport { getAtPath, setAtPathInPlace } from './i18n/core.js'\nimport type { DictKeyDescriptor, StaticDictDescriptor } from './i18n/dictionary.js'\nimport { isStaticDictDescriptor } from './i18n/dictionary.js'\nimport type { MoneyDescriptor } from './money/descriptor.js'\nimport { quantizeMoneyFields, decodeMoneyFields, canonicalizeStoredMoney, canonicalizeIncomingMoney } from './money/normalize.js'\nimport { validateMoneyFieldPaths } from './money/paths.js'\nimport type { ComputedFields } from './computed/index.js'\nimport { evalComputedFields } from './computed/index.js'\nimport { NO_I18N, type I18nStrategy } from './i18n/strategy.js'\nimport { resolvePolicy } from './i18n/policy.js'\nimport { encrypt, decrypt, encryptDeterministic } from './crypto.js'\nimport {\n wrapCek,\n unwrapCek,\n isTombstone,\n buildTombstone,\n resolveStableCek,\n rewrapBodyToDek,\n} from './record-keys/index.js'\nimport { ConflictError, ReadOnlyError, TranslatorNotConfiguredError, TierDemoteDeniedError, LocaleNotSpecifiedError } from './errors.js'\nimport { dekKey, assertTierAccess } from './team/tiers.js'\nimport type { GhostRecord, TierMode, CrossTierAccessEvent } from './types.js'\nimport type { UnlockedKeyring } from './team/keyring.js'\nimport { hasWritePermission } from './team/keyring.js'\nimport type { NoydbEventEmitter } from './events.js'\nimport type { WriteQueueTracker } from './write-queue.js'\nimport type { WriteHookRegistry, WriteEvent } from './write-hooks.js'\nimport type { SubsystemBus, GatePutEvent } from './subsystem-bus.js'\nimport type { SchemaUpdateGate } from './schema-update/gate.js'\nimport type { SchemaFenceController } from './schema-update/fence-controller.js'\nimport type { StandardSchemaV1 } from './schema.js'\nimport { validateSchemaInput, validateSchemaOutput } from './schema.js'\nimport type { LedgerStore } from './history/ledger/index.js'\nimport type { DiffEntry } from './history/diff.js'\nimport { NO_HISTORY, type HistoryStrategy } from './history/strategy.js'\nimport { Query, ScanBuilder } from './query/index.js'\nimport type { QuerySource, JoinContext, JoinableSource } from './query/index.js'\nimport type { CollectionIndexes, IndexDef } from './indexing/eager-indexes.js'\nimport { encodeIdxId, decodeIdxId } from './indexing/persisted-indexes.js'\nimport type { PersistedCollectionIndex, PersistedIndexDef } from './indexing/persisted-indexes.js'\nimport { LazyQuery } from './indexing/lazy-builder.js'\nimport type { LazyQuerySource } from './indexing/lazy-builder.js'\nimport { NO_INDEXING, type IndexStrategy, type IndexState } from './indexing/strategy.js'\nimport { IndexWriteFailureError } from './errors.js'\nimport { buildUniqueConstraintSet, type UniqueConstraintSet } from './indexing/unique-constraints.js'\nimport type { RefDescriptor } from './refs.js'\nimport { Lru, parseBytes, estimateRecordBytes, type LruStats } from './cache/index.js'\nimport { generateULID } from './bundle/ulid.js'\nimport type { PresenceHandle, PresenceHandleOpts } from './team/presence.js'\nimport { NO_SYNC, type SyncStrategy } from './team/sync-strategy.js'\nimport type { BlobSet } from './blobs/blob-set.js'\nimport { NO_BLOBS, type BlobStrategy } from './blobs/strategy.js'\nimport { NO_AGGREGATE, type AggregateStrategy } from './aggregate/strategy.js'\nimport type { ReadOnlyVaultFacade } from './guards/types.js'\nimport type { DerivationRegistry } from './derivations/registry.js'\nimport type { TxContext, ExecutedOp } from './tx/transaction.js'\nimport { revertExecuted } from './tx/transaction.js'\n// Type-only — runtime class loaded via dynamic import in\n// `dispatchDerivations` when an eager-mode strategy fires. Keeps the\n// derivation executor chunk out of the floor bundle.\nimport type { DerivationExecutor as DerivationExecutorType } from './derivations/executor.js'\nimport type {\n loadFanoutSidecar as LoadFanoutSidecarType,\n deleteFanoutSidecar as DeleteFanoutSidecarType,\n saveFanoutSidecar as SaveFanoutSidecarType,\n} from './derivations/fanout-sidecar.js'\nimport { markStale, resolveStaleOnRead } from './derivations/stale.js'\nimport type { MaterializedViewRegistry } from './materialized-views/registry.js'\nimport type { MVQueryContext } from './materialized-views/types.js'\nimport type { MaterializedViewExecutor as MVExecutorType } from './materialized-views/executor.js'\nimport type * as MVStaleModule from './materialized-views/stale.js'\n\n/** Callback for dirty tracking (sync engine integration). */\nexport type OnDirtyCallback = (collection: string, id: string, action: 'put' | 'delete', version: number) => Promise<void>\n\n/**\n * Event delivered to a `collection.subscribe()` callback. Distinct\n * from the hub-level `ChangeEvent` — this one is bound to a single\n * collection's type `T` and hydrates the record from cache on put.\n *\n * - `type: 'put'` — `record` is the current decrypted value, or\n * `null` in the rare case where another op deleted the record\n * between the emit and the handler firing.\n * - `type: 'delete'` — `record` is always `null`; the deletion is\n * the only information.\n */\nexport interface CollectionChangeEvent<T> {\n readonly type: 'put' | 'delete'\n readonly id: string\n readonly record: T | null\n}\n\n/**\n * Per-collection cache configuration. Only meaningful when paired with\n * `prefetch: false` (lazy mode); eager mode keeps the entire decrypted\n * cache in memory and ignores these bounds.\n */\nexport interface CacheOptions {\n /** Maximum number of records to keep in memory before LRU eviction. */\n maxRecords?: number\n /**\n * Maximum total decrypted byte size before LRU eviction. Accepts a raw\n * number or a human-friendly string: `'50KB'`, `'50MB'`, `'1GB'`.\n * Eviction picks the least-recently-used entry until both budgets\n * (maxRecords AND maxBytes, if both are set) are satisfied.\n */\n maxBytes?: number | string\n}\n\n/** Statistics exposed via `Collection.cacheStats()`. */\nexport interface CacheStats extends LruStats {\n /** True if this collection is in lazy mode. */\n lazy: boolean\n}\n\n/**\n * Track which adapter names have already triggered the listPage fallback\n * warning. We only emit once per adapter per process so consumers see the\n * heads-up without log spam.\n */\nconst fallbackWarned = new Set<string>()\nfunction warnOnceFallback(adapterName: string): void {\n if (fallbackWarned.has(adapterName)) return\n fallbackWarned.add(adapterName)\n // Only warn in non-test environments — vitest runs are noisy enough.\n if (typeof process !== 'undefined' && process.env['NODE_ENV'] === 'test') return\n console.warn(\n `[noy-db] Store \"${adapterName}\" does not implement listPage(); ` +\n `Collection.scan()/listPage() are using a synthetic fallback (slower). ` +\n `Add a listPage method to opt into the streaming fast path.`,\n )\n}\n\n/** A typed collection of records within a vault. */\nexport class Collection<T> {\n private readonly adapter: NoydbStore\n private readonly vault: string\n private readonly name: string\n private readonly keyring: UnlockedKeyring\n private readonly encrypted: boolean\n private readonly emitter: NoydbEventEmitter\n private readonly writeQueue: WriteQueueTracker | undefined\n private readonly schemaUpdateGate: SchemaUpdateGate | undefined\n private readonly schemaFence: SchemaFenceController | undefined\n private readonly writeHooks: WriteHookRegistry | undefined\n private readonly subsystemBus: SubsystemBus | undefined\n private readonly activeTxId: (() => string | null) | undefined\n private readonly getDEK: (collectionName: string) => Promise<CryptoKey>\n private readonly onDirty: OnDirtyCallback | undefined\n private readonly historyConfig: HistoryConfig\n\n /**\n * tree-shake seam — the strategy that backs `collection.blob(id)`.\n * Defaults to `NO_BLOBS`, a ~10-line stub that throws with an actionable\n * message. Consumers opt into real blob storage by importing\n * `{ blobs }` from `@noy-db/hub/blobs` and passing the returned\n * strategy to `createNoydb({ blobStrategy: blobs() })`. With the\n * default stub, none of the BlobSet / chunk / MIME-magic machinery\n * reaches the bundle.\n */\n private readonly blobStrategy: BlobStrategy\n private readonly aggregateStrategy: AggregateStrategy\n private readonly crdtStrategy: CrdtStrategy\n private readonly historyStrategy: HistoryStrategy\n private readonly i18nStrategy: I18nStrategy\n private readonly syncStrategy: SyncStrategy\n\n // In-memory cache of decrypted records (eager mode only). Lazy mode\n // uses `lru` instead. Both fields exist so a single Collection instance\n // doesn't need a runtime branch on every cache access.\n private readonly cache = new Map<string, { record: T; version: number }>()\n private hydrated = false\n\n /**\n * Lazy mode flag. `true` when constructed with `prefetch: false`.\n * In lazy mode the cache is bounded by an LRU and `list()`/`query()`\n * throw — callers must use `scan()` or per-id `get()` instead.\n */\n private readonly lazy: boolean\n\n /**\n * LRU cache for lazy mode. Only allocated when `prefetch: false` is set.\n * Stores `{ record, version }` entries the same shape as `this.cache`.\n * Tree-shaking note: importing Collection without setting `prefetch:false`\n * still pulls in the Lru class today; future bundle-size work could\n * lazy-import the cache module.\n */\n private readonly lru: Lru<string, { record: T; version: number }> | null\n\n /**\n * tree-shake seam — per-Collection indexing state. Owned by the\n * `IndexStrategy` passed through from `createNoydb({ indexStrategy })`.\n * Defaults to a disabled state (both accessors return null) so the\n * `CollectionIndexes` / `PersistedCollectionIndex` / `LazyQuery`\n * classes never reach the bundle when indexing is unused.\n *\n * Accessor helpers below (`get indexes()`, `get persistedIndexes()`)\n * preserve the field-access ergonomics without changing every\n * caller site.\n */\n private readonly indexState: IndexState\n\n /**\n * In-memory unique-constraint enforcement for eager mode.\n * `null` when no `unique:true` indexes are declared on this collection,\n * or when the collection is in lazy mode (which throws at registration).\n */\n private readonly uniqueConstraints: UniqueConstraintSet | null\n\n /**\n * True once `_idx/*` side-cars have been bulk-loaded into\n * `persistedIndexes`. Flipped by `ensurePersistedIndexesLoaded()` on\n * first lazy-mode query so subsequent queries skip the adapter round\n * trip. Invalidation (remote sync, rotation) resets it alongside\n * `persistedIndexes.clear()`.\n */\n private persistedIndexesLoaded = false\n\n /**\n * Accessor for the in-memory eager-mode index mirror. Returns `null`\n * when indexing is disabled on this Noydb instance (the\n * `NO_INDEXING` default) or when the collection is in lazy mode\n * (which uses the persisted mirror instead).\n */\n private get indexes(): CollectionIndexes | null {\n return this.indexState.getEagerIndexes()\n }\n\n /**\n * Accessor for the persisted-mirror (lazy-mode) index. Returns `null`\n * when indexing is disabled or the collection is in eager mode.\n */\n private get persistedIndexes(): PersistedCollectionIndex | null {\n return this.indexState.getPersistedIndexes()\n }\n\n /**\n * per-collection reconcile-on-open policy. Read once\n * from `CollectionOptions.reconcileOnOpen` and applied by\n * `ensurePersistedIndexesLoaded()` on the first lazy-mode query.\n */\n private readonly reconcileOnOpen: 'off' | 'dry-run' | 'auto'\n\n /**\n * Re-entrancy guard for the auto-reconcile path. `reconcileIndex`\n * reloads the mirror after applying fixes, which re-enters\n * `ensurePersistedIndexesLoaded`; without this flag we'd trigger a\n * second auto-reconcile pass and potentially infinite recursion.\n */\n private autoReconciling = false\n\n /**\n * Optional Standard Schema v1 validator. When set, every `put()` runs\n * the input through `validateSchemaInput` before encryption, and every\n * record coming OUT of `decryptRecord` runs through\n * `validateSchemaOutput`. A rejected input throws\n * `SchemaValidationError` with `direction: 'input'`; drifted stored\n * data throws with `direction: 'output'`. Both carry the rich issue\n * list from the validator so UI code can render field-level messages.\n *\n * The schema is stored as `StandardSchemaV1<unknown, T>` because the\n * collection type parameter `T` is the OUTPUT type — whatever the\n * validator produces after transforms and coercion. Users who pass a\n * schema to `defineNoydbStore` (or `Collection.constructor`) get their\n * `T` inferred automatically via `InferOutput<Schema>`.\n */\n private readonly schema: StandardSchemaV1<unknown, T> | undefined\n\n /**\n * Vault-default locale. Used as the fallback when no per-call\n * locale option is passed to `get()`/`list()`. Provided by Vault\n * at collection construction time via the `collection({ locale })` or\n * `openVault(name, { locale })` path.\n *\n * `undefined` means \"no default locale set\" — i18nText fields will\n * throw `LocaleNotSpecifiedError` unless a per-call locale is passed.\n */\n private readonly defaultLocale: string | undefined\n\n /**\n * Map of field name → `I18nTextDescriptor` for fields declared with\n * `i18nText()`. Used by:\n * - `put()` via `i18nPutValidator` to enforce required translations\n * - `get()`/`list()` to apply locale resolution after decryption\n *\n * Declared via the `i18nFields` collection option.\n */\n private readonly i18nFields: Record<string, I18nTextDescriptor> | undefined\n\n /**\n * Map of field name → `DictKeyDescriptor` for fields declared with\n * `dictKey()`. Used by `get()`/`list()` to add `<field>Label` virtual\n * fields when a locale is requested.\n */\n private readonly dictKeyFields: Record<string, DictKeyDescriptor | StaticDictDescriptor> | undefined\n\n /**\n * Money field descriptors keyed by field path. Declared via the\n * `moneyFields` collection option: `put()` quantizes to a scaled-int\n * string, `get()`/`list()` decode back. Mutable so {@link _applyMoneyFields}\n * can attach descriptors to a collection MV-analysis pre-created.\n */\n private moneyFields: Record<string, MoneyDescriptor> | undefined\n\n /**\n * Computed scalar fields, evaluated first on every `put()`. Mutable for\n * the same MV-pre-creation reconcile as {@link moneyFields}.\n */\n private computed: ComputedFields | undefined\n\n /**\n * Async callback provided by the Vault that resolves a dict key\n * to its label for a given locale. Used by the locale-read path for\n * dictKey fields.\n *\n * Signature: `(dictName, key, locale, fallback?) => Promise<string | undefined>`\n */\n private readonly dictLabelResolver:\n | ((\n dictName: string,\n key: string,\n locale: string,\n fallback?: string | readonly string[],\n ) => Promise<string | undefined>)\n | undefined\n\n /**\n * Synchronous callback provided by the Vault that validates\n * i18nText fields on `put()`. Throws `MissingTranslationError` when\n * a required translation is absent. Called after schema validation,\n * before encryption.\n */\n private readonly i18nPutValidator: ((record: unknown) => void) | undefined\n\n /**\n * declared deterministic fields. `null` when the feature\n * is inactive for this collection; a frozen `Set` otherwise.\n */\n private readonly deterministicFields: ReadonlySet<string> | null\n\n /**\n * Per-record CEK opt-in (`perRecordKeys: true`). When set, writes mint /\n * reuse a per-record content-encryption key and stamp `_cek` on the\n * envelope (see {@link EncryptedEnvelope._cek}). OFF by default — a\n * non-adopting collection takes the byte-identical legacy path. The READ\n * path does not consult this flag: `_cek` presence on the envelope is the\n * format discriminant, so a mixed vault (and a recipient that never set the\n * flag) still decrypts CEK records.\n */\n private readonly perRecordCek: boolean\n\n /**\n * Session-scoped `(id) → CEK` cache for this collection. Lets updates\n * reuse a record's stable CEK and lets repeated reads skip the AES-KW\n * unwrap. Bounded by LRU; never persisted. Dropped when the owning\n * collection instance is discarded — `vault.load()` clears the\n * collectionCache, so a keyring refresh drops every CEK alongside the\n * DEK cache. `null` unless `perRecordCek` is set.\n */\n private readonly cekCache: Lru<string, CryptoKey> | null\n\n /**\n * declared tiers for this collection. `null` when\n * tier-aware methods are disabled. Tier 0 is implicit and never\n * stored here.\n */\n private readonly tiers: ReadonlySet<number> | null\n private readonly tierMode: TierMode\n private readonly onCrossTierAccess: ((event: CrossTierAccessEvent) => void) | undefined\n\n /**\n * Async translator callback provided by Noydb via Vault for\n * `i18nText` fields with `autoTranslate: true`. Called\n * before i18n validation so translated values are present when the\n * validator runs. `undefined` when no `plaintextTranslator` was\n * configured on `createNoydb()`.\n */\n private readonly autoTranslateHook:\n | ((text: string, from: string, to: string, field: string, collection: string) => Promise<string>)\n | undefined\n\n /**\n * Optional reference to the vault-level hash-chained audit\n * log. When present, every successful `put()` and `delete()` appends\n * an entry to the ledger AFTER the adapter write succeeds (so a\n * failed adapter write never produces an orphan ledger entry).\n *\n * The ledger is always a vault-wide singleton — all\n * collections in the same vault share the same LedgerStore.\n * Vault.ledger() does the lazy init; this field just holds\n * the reference so Collection doesn't need to reach back up to the\n * vault on every mutation.\n *\n * `undefined` means \"no ledger attached\" — supported for tests that\n * construct a Collection directly without a vault, and for\n * future backwards-compat scenarios. Production usage always has a\n * ledger because Vault.collection() passes one through.\n */\n private readonly ledger: LedgerStore | undefined\n\n /** — per-collection CRDT mode, or undefined for normal LWW-at-record-level. */\n private readonly crdtMode: CrdtMode | undefined\n\n /** — optional remote/sync adapter for presence broadcasting. */\n private readonly syncAdapter: NoydbStore | undefined\n\n /** — consent-audit hook, no-op when no scope is active. */\n private readonly onAccess:\n | ((op: 'get' | 'put' | 'delete', id: string) => Promise<void>)\n | undefined\n\n /**\n * Vault-internal hook for derivation dispatch. When set,\n * `Collection.put` consults the registry after the source-write\n * commits and writes derived outputs through `getCollection(name).put`.\n */\n private readonly derivationSource:\n | {\n registry(): DerivationRegistry\n getCollection(name: string): Collection<Record<string, unknown>>\n getReadOnlyFacade(): ReadOnlyVaultFacade\n getActiveTxContext(): TxContext | null\n /**\n * Construct a fresh transient TxContext bound to the owning\n * Noydb. Used by `Collection.putManyAtomic` to publish an\n * `_activeTxContext` for the duration of its Phase 2 loop so\n * recursive derived-output writes register their pre-write\n * envelopes on `ctx._executed` and roll back alongside the\n * bulk-put source ops.\n */\n createTxContext(): TxContext\n /** Publish a TxContext for the duration of a bulk-atomic loop. */\n setActiveTxContext(ctx: TxContext): void\n /** Drop a previously-published TxContext (defensive no-op if mismatched). */\n clearActiveTxContext(ctx: TxContext): void\n }\n | undefined\n\n /**\n * Vault-internal hook for materialized-view dispatch.\n * Parallel to `derivationSource` — when set, `Collection.put` fires\n * `MaterializedViewRegistry.onSourceWrite` after the source-write\n * commits + after `dispatchDerivations` has run.\n */\n private readonly materializedViewSource:\n | {\n \n registry(): MaterializedViewRegistry\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n getCollection(name: string): Collection<any>\n getActiveTxContext(): TxContext | null\n getQueryContext(): MVQueryContext\n }\n | undefined\n\n /**\n * Optional back-reference to the owning compartment's ref\n * enforcer. When present, `Collection.put` calls\n * `refEnforcer.enforceRefsOnPut(name, record)` before the adapter\n * write, and `Collection.delete` calls\n * `refEnforcer.enforceRefsOnDelete(name, id)` before its own\n * adapter delete. The Vault handles the actual registry\n * lookup and cross-collection enforcement — Collection just\n * notifies it at the right points in the lifecycle.\n *\n * Typed as a structural interface rather than `Vault`\n * directly to avoid a circular import. Vault implements\n * these two methods; any other object with the same shape would\n * work too (used only in unit tests).\n */\n private readonly refEnforcer:\n | {\n enforceRefsOnPut(collectionName: string, record: unknown): Promise<void>\n enforceRefsOnDelete(collectionName: string, id: string): Promise<void>\n }\n | undefined\n\n /**\n * Optional back-reference to the owning compartment's join resolver\n *`). When present,\n * `Collection.query()` builds a `JoinContext` that lets the Query\n * resolve `.join(field)` calls into target collections via this\n * resolver.\n *\n * Two methods:\n * - `resolveSource(name)` — fetch a `JoinableSource` for the\n * right-side collection by name. Returning `null` means \"no\n * such collection in this compartment\" — the executor then\n * throws an actionable error naming the missing target.\n * - `resolveRef(leftCollection, field)` — look up the ref\n * descriptor the left collection declared for this field.\n * `null` when the field has no ref, which makes `.join()`\n * throw at plan time before any records are touched.\n *\n * Typed structurally rather than as `Vault` to avoid a\n * circular import. Vault implements these two methods; any\n * other object with the same shape works too (used only in unit\n * tests against a plain object).\n */\n private readonly joinResolver:\n | {\n resolveSource(collectionName: string): JoinableSource | null\n resolveRef(leftCollection: string, field: string): RefDescriptor | null\n resolveDictSource?: (leftCollection: string, field: string) => JoinableSource | null\n }\n | undefined\n\n constructor(opts: {\n adapter: NoydbStore\n vault: string\n name: string\n keyring: UnlockedKeyring\n encrypted: boolean\n emitter: NoydbEventEmitter\n /**\n * Vault-level in-flight write tracker. When present,\n * `put`/`delete` run inside `writeQueue.track()` so `hub.writeQueue`\n * reflects outstanding writes. Optional so direct Collection\n * construction in tests still works untracked.\n */\n writeQueue?: WriteQueueTracker | undefined\n /** Per-collection schema-update gate; `put`/`delete` await it. */\n schemaUpdateGate?: SchemaUpdateGate | undefined\n /** Vault-level fence controller; `put`/`delete` consult it. */\n schemaFence?: SchemaFenceController | undefined\n /** Hub-level write-hook registry; fired around put/delete. */\n writeHooks?: WriteHookRegistry | undefined\n /** The observe bus, threaded from Noydb. */\n subsystemBus?: SubsystemBus | undefined\n /** Active transaction id supplier (null outside a transaction). */\n activeTxId?: (() => string | null) | undefined\n getDEK: (collectionName: string) => Promise<CryptoKey>\n historyConfig?: HistoryConfig | undefined\n onDirty?: OnDirtyCallback | undefined\n /**\n * tree-shake seam. When omitted, `collection.blob(id)` throws\n * with a pointer at the `@noy-db/hub/blobs` subpath. When set (via\n * `createNoydb({ blobStrategy: blobs() })`), blob storage is live.\n * `@internal` by virtue of `BlobStrategy` being `@internal`.\n */\n blobStrategy?: BlobStrategy | undefined\n aggregateStrategy?: AggregateStrategy | undefined\n crdtStrategy?: CrdtStrategy | undefined\n /**\n * tree-shake seam — strategy for optional history/ledger/\n * time-machine. When omitted, history snapshots and ledger appends\n * become silent no-ops (data still writes); the read APIs\n * (`history`, `getVersion`, `revert`, `diff`, `clearHistory`,\n * `pruneRecordHistory`) throw with a pointer at `@noy-db/hub/history`.\n */\n historyStrategy?: HistoryStrategy | undefined\n i18nStrategy?: I18nStrategy | undefined\n syncStrategy?: SyncStrategy | undefined\n /**\n * tree-shake seam. When omitted, indexing is off for this\n * collection — every `.lazyQuery()` call throws, `.rebuildIndexes()`\n * is a no-op, and `indexes: [...]` declarations are ignored. Enable\n * by passing `withIndexing()` from `@noy-db/hub/indexing` at\n * `createNoydb` time.\n */\n indexStrategy?: IndexStrategy | undefined\n indexes?: IndexDef[] | undefined\n /**\n * Auto-reconcile behavior for persisted-index drift on lazy-mode\n * collections. Defaults to `'off'` — operators call\n * `collection.reconcileIndex(field)` explicitly.\n *\n * - `'off'` (default): no implicit work. Same semantics as.\n * - `'dry-run'`: on first lazy-mode query, run\n * `reconcileIndex(field, { dryRun: true })` per declared field\n * and emit `index:reconciled` with the diff. Nothing is written.\n * - `'auto'`: same walk as `'dry-run'` but with `dryRun: false`.\n * Drift is repaired in-place and the fix count surfaces on the\n * event.\n *\n * Unattended long-lived processes (Workers, Node services with no\n * human operator) should set `'auto'`. Attended desktop apps should\n * leave it `'off'` and surface a manual \"rebuild indexes\" button.\n */\n reconcileOnOpen?: 'off' | 'dry-run' | 'auto'\n /**\n * Hydration mode. `'eager'` (default) loads everything into memory on\n * first access — matches behavior exactly. `'lazy'` defers loads\n * to per-id `get()` calls and bounds memory via the `cache` option.\n */\n prefetch?: boolean\n /**\n * LRU cache options. Only meaningful when `prefetch: false`. At least\n * one of `maxRecords` or `maxBytes` must be set in lazy mode — an\n * unbounded lazy cache defeats the purpose.\n */\n cache?: CacheOptions | undefined\n /**\n * Optional Standard Schema v1 validator (Zod, Valibot, ArkType,\n * Effect Schema, etc.). When set, every `put()` is validated before\n * encryption and every read is validated after decryption. See the\n * `schema` field docstring for the error semantics.\n */\n schema?: StandardSchemaV1<unknown, T> | undefined\n /**\n * Optional reference to the compartment's hash-chained ledger.\n * When present, successful mutations append a ledger entry via\n * `LedgerStore.append()`. Constructed at the Vault level and\n * threaded through — see the Vault.collection() source for\n * the wiring.\n */\n ledger?: LedgerStore | undefined\n /**\n * Optional back-reference to the owning compartment's ref\n * enforcer`).\n * Collection.put calls `enforceRefsOnPut` before the adapter\n * write; Collection.delete calls `enforceRefsOnDelete` before\n * its own adapter delete. See the `refEnforcer` field docstring\n * for the full protocol.\n */\n refEnforcer?:\n | {\n enforceRefsOnPut(collectionName: string, record: unknown): Promise<void>\n enforceRefsOnDelete(collectionName: string, id: string): Promise<void>\n }\n | undefined\n /**\n * Optional back-reference to the owning compartment's join\n * resolver. When present, `query()` builds a\n * `JoinContext` so `.join(field)` can resolve through the\n * existing `ref()` declaration into the target collection.\n * Absent in tests that construct a Collection directly without\n * a vault; production usage always has one because\n * Vault.collection() passes `this` through.\n */\n joinResolver?:\n | {\n resolveSource(collectionName: string): JoinableSource | null\n resolveRef(leftCollection: string, field: string): RefDescriptor | null\n }\n | undefined\n /** — i18nText field descriptors for locale-aware reads. */\n i18nFields?: Record<string, I18nTextDescriptor> | undefined\n /** — dictKey field descriptors for label resolution on reads. */\n dictKeyFields?: Record<string, DictKeyDescriptor | StaticDictDescriptor> | undefined\n moneyFields?: Record<string, MoneyDescriptor> | undefined\n computed?: ComputedFields | undefined\n /**\n * async callback that resolves a dict key to its label\n * for a given locale. Provided by the Vault.\n */\n dictLabelResolver?:\n | ((\n dictName: string,\n key: string,\n locale: string,\n fallback?: string | readonly string[],\n ) => Promise<string | undefined>)\n | undefined\n /**\n * synchronous callback that validates i18nText fields\n * on put. Provided by the Vault. Throws MissingTranslationError.\n */\n i18nPutValidator?: ((record: unknown) => void) | undefined\n /**\n * translator callback from Noydb. When present, missing\n * translations for `autoTranslate: true` i18nText fields are generated\n * before the i18n validator runs.\n */\n autoTranslateHook?:\n | ((text: string, from: string, to: string, field: string, collection: string) => Promise<string>)\n | undefined\n /**\n * vault-default locale, inherited from\n * `openVault(name, { locale })` or `vault.setLocale()`.\n */\n defaultLocale?: string | undefined\n /**\n * collection-level conflict resolution policy.\n * Overrides the db-level `conflict` option for this collection only.\n */\n conflictPolicy?: ConflictPolicy<T> | undefined\n /**\n * callback to register an envelope-level resolver with the\n * SyncEngine. Provided by the Vault (wired from the SyncEngine).\n */\n onRegisterConflictResolver?: ((name: string, resolver: CollectionConflictResolver) => void) | undefined\n /**\n * CRDT mode for this collection. When set, `put()` stores\n * CRDT state in the envelope and `get()` returns the resolved snapshot.\n * `getRaw(id)` returns the full CRDT state for merge operations.\n */\n crdt?: CrdtMode | undefined\n /**\n * optional remote/sync adapter. When present, `presence()`\n * writes heartbeats to this adapter so other devices can read them.\n * If the adapter implements pub/sub, presence updates are real-time.\n */\n syncAdapter?: NoydbStore | undefined\n /**\n * called by the collection after every successful\n * `get` / `put` / `delete`. The Vault installs a callback that\n * appends a consent-audit entry when `withConsent` is active;\n * outside a consent scope the callback is a no-op. Awaited so a\n * thrown audit write surfaces to the caller.\n */\n onAccess?: (op: 'get' | 'put' | 'delete', id: string) => Promise<void>\n /**\n * invoked by `put`/`delete` before any adapter\n * write. Receives the prior envelope timestamp + decrypted\n * record (or `null` if no prior) and the incoming record (or\n * `null` for delete). Throws `PeriodClosedError` to abort.\n */\n /**\n * opt-in deterministic-encryption index.\n *\n * Field names listed here get a deterministic AES-GCM ciphertext\n * attached to every envelope's `_det` map, which enables blind\n * equality search via `collection.findByDet(field, value)`.\n *\n * **Leaks equality.** Two records with the same value in a\n * deterministic field produce identical ciphertexts, so anyone\n * with store access can tell which records share a value without\n * learning the value itself. This is the textbook trade-off of\n * deterministic encryption — strictly opt-in for that reason.\n *\n * Declaring any field here without also passing\n * `acknowledgeDeterministicRisk: true` throws at construction,\n * so the risk must be explicitly acknowledged.\n */\n deterministicFields?: readonly string[] | undefined\n /**\n * gate for `deterministicFields`. Must be `true` when\n * any deterministic field is declared. Any other value throws.\n */\n acknowledgeDeterministicRisk?: boolean | undefined\n /**\n * Per-record content-encryption keys. When `true`, every record body\n * (and every history version of it) is encrypted under a fresh\n * per-record CEK, AES-KW-wrapped under the collection DEK and stored\n * on the envelope's `_cek`. Off by default. Foundation for per-record\n * erasure (#304) and record-scoped sealing (#306). `_det` slots stay\n * keyed to the collection DEK regardless.\n */\n perRecordKeys?: boolean | undefined\n /**\n * declared tiers this collection supports. An\n * undefined or empty list disables the hierarchical-tier surface\n * on this collection (`putAtTier`, `getAtTier`, `elevate`, `demote`\n * throw). Tier 0 is implicit and always available.\n */\n tiers?: readonly number[] | undefined\n /**\n * what a lower-tier caller sees for above-tier\n * records. Default `'invisibility'`.\n */\n tierMode?: TierMode | undefined\n /**\n * optional callback fired on every cross-tier access.\n * Provided by the Vault; collects notification events and writes\n * to the ledger.\n */\n onCrossTierAccess?: ((event: CrossTierAccessEvent) => void) | undefined\n /**\n /**\n * Optional back-reference to the owning vault's derivation\n * registry + collection accessor. When present, successful\n * `put()` dispatches registered derivation strategies for the\n * source collection.\n */\n derivationSource?: {\n registry(): DerivationRegistry\n getCollection(name: string): Collection<Record<string, unknown>>\n /**\n * Read-only vault facade handed to `derive(source, ctx)` so a\n * derivation can fetch sibling records. Same shape and\n * instance the guards subsystem uses for `check(incoming, ctx)`.\n */\n getReadOnlyFacade(): ReadOnlyVaultFacade\n /**\n * Read access to the owning Noydb's currently-active multi-record\n * transaction context, or `null` when no transaction is running.\n * `dispatchDerivations` consults this so a recursive derived-output\n * write can register its pre-write envelope onto `ctx._executed`\n * and roll back alongside the source op on mid-batch failure.\n */\n getActiveTxContext(): TxContext | null\n /**\n * Construct a transient TxContext bound to the owning Noydb. Used\n * by `Collection.putManyAtomic` to publish an active context for\n * its Phase 2 loop.\n */\n createTxContext(): TxContext\n /** Publish a TxContext for the duration of a bulk-atomic loop. */\n setActiveTxContext(ctx: TxContext): void\n /** Drop a previously-published TxContext. */\n clearActiveTxContext(ctx: TxContext): void\n } | undefined\n /**\n * Vault-internal hook for materialized-view dispatch.\n * Parallel to `derivationSource`. When set, `Collection.put` fires\n * registered MV `onSourceWrite` after the standard derivation\n * dispatch.\n */\n materializedViewSource?: {\n \n registry(): MaterializedViewRegistry\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n getCollection(name: string): Collection<any>\n getActiveTxContext(): TxContext | null\n getQueryContext(): MVQueryContext\n } | undefined\n }) {\n this.adapter = opts.adapter\n this.vault = opts.vault\n this.name = opts.name\n this.keyring = opts.keyring\n this.encrypted = opts.encrypted\n this.emitter = opts.emitter\n this.writeQueue = opts.writeQueue\n this.schemaUpdateGate = opts.schemaUpdateGate\n this.schemaFence = opts.schemaFence\n this.writeHooks = opts.writeHooks\n this.subsystemBus = opts.subsystemBus\n this.activeTxId = opts.activeTxId\n this.blobStrategy = opts.blobStrategy ?? NO_BLOBS\n this.aggregateStrategy = opts.aggregateStrategy ?? NO_AGGREGATE\n this.crdtStrategy = opts.crdtStrategy ?? NO_CRDT\n this.historyStrategy = opts.historyStrategy ?? NO_HISTORY\n this.i18nStrategy = opts.i18nStrategy ?? NO_I18N\n this.syncStrategy = opts.syncStrategy ?? NO_SYNC\n this.reconcileOnOpen = opts.reconcileOnOpen ?? 'off'\n this.getDEK = opts.getDEK\n this.onDirty = opts.onDirty\n this.historyConfig = opts.historyConfig ?? { enabled: true }\n this.schema = opts.schema\n this.ledger = opts.ledger\n this.refEnforcer = opts.refEnforcer\n this.joinResolver = opts.joinResolver\n this.i18nFields = opts.i18nFields\n this.dictKeyFields = opts.dictKeyFields\n if (opts.moneyFields) validateMoneyFieldPaths(opts.moneyFields)\n this.moneyFields = opts.moneyFields\n this.computed = opts.computed\n this.dictLabelResolver = opts.dictLabelResolver\n this.i18nPutValidator = opts.i18nPutValidator\n this.autoTranslateHook = opts.autoTranslateHook\n this.defaultLocale = opts.defaultLocale\n this.crdtMode = opts.crdt\n this.syncAdapter = opts.syncAdapter\n this.onAccess = opts.onAccess\n this.derivationSource = opts.derivationSource\n this.materializedViewSource = opts.materializedViewSource\n\n // hierarchical-tier wiring\n this.tiers = opts.tiers && opts.tiers.length > 0 ? new Set(opts.tiers) : null\n this.tierMode = opts.tierMode ?? 'invisibility'\n this.onCrossTierAccess = opts.onCrossTierAccess\n\n // deterministic-encryption wiring\n if (opts.deterministicFields && opts.deterministicFields.length > 0) {\n if (opts.acknowledgeDeterministicRisk !== true) {\n throw new Error(\n `Collection \"${opts.name}\": deterministicFields requires \\`acknowledgeDeterministicRisk: true\\`. ` +\n `Deterministic encryption leaks equality between records — two records with the same field value ` +\n `produce identical ciphertexts visible to anyone with store access. If that trade-off is acceptable ` +\n `for your threat model, set \\`acknowledgeDeterministicRisk: true\\` to enable.`,\n )\n }\n this.deterministicFields = Object.freeze(new Set(opts.deterministicFields))\n } else {\n this.deterministicFields = null\n }\n\n // per-record CEK wiring. The cache is bounded by record count; CEKs\n // are tiny CryptoKey handles, so a generous entry budget is cheap.\n this.perRecordCek = opts.perRecordKeys === true\n this.cekCache = this.perRecordCek ? new Lru<string, CryptoKey>({ maxRecords: 4096 }) : null\n\n // register CRDT conflict resolver with SyncEngine\n if (opts.crdt && opts.onRegisterConflictResolver) {\n const crdtMode = opts.crdt\n const crdtResolver: CollectionConflictResolver = async (id, local, remote) => {\n if (crdtMode === 'yjs') {\n // Core cannot merge Yjs without the yjs package — take the higher version\n return local._v >= remote._v ? local : remote\n }\n const localJson = await this.decryptJsonString(local, id)\n const remoteJson = await this.decryptJsonString(remote, id)\n // Tombstone (shredded) on either side: the live envelope is the\n // authoritative merge result — a shred must win and stay shredded.\n if (localJson === null) return local\n if (remoteJson === null) return remote\n const localState = JSON.parse(localJson) as CrdtState\n const remoteState = JSON.parse(remoteJson) as CrdtState\n const merged = this.crdtStrategy.mergeCrdtStates(localState, remoteState)\n const mergedVersion = Math.max(local._v, remote._v) + 1\n const cek = this.perRecordCek ? await this.resolveRecordCek(id) : undefined\n return this.encryptJsonString(JSON.stringify(merged), mergedVersion, cek)\n }\n opts.onRegisterConflictResolver(this.name, crdtResolver)\n }\n\n // build and register per-collection conflict resolver with SyncEngine\n if (opts.conflictPolicy !== undefined && opts.onRegisterConflictResolver) {\n const policy = opts.conflictPolicy\n const compartmentName = this.vault\n const collectionName = this.name\n const emitter = this.emitter\n let resolver: CollectionConflictResolver\n\n if (policy === 'last-writer-wins') {\n resolver = async (_id, local, remote) => (local._ts >= remote._ts ? local : remote)\n } else if (policy === 'first-writer-wins') {\n resolver = async (_id, local, remote) => (local._v <= remote._v ? local : remote)\n } else if (policy === 'manual') {\n resolver = (id, local, remote) =>\n new Promise<EncryptedEnvelope | null>(resolvePromise => {\n let settled = false\n const resolveCallback = (winner: EncryptedEnvelope | null) => {\n if (!settled) {\n settled = true\n resolvePromise(winner)\n }\n }\n emitter.emit('sync:conflict', {\n vault: compartmentName,\n collection: collectionName,\n id,\n local,\n remote,\n localVersion: local._v,\n remoteVersion: remote._v,\n resolve: resolveCallback,\n })\n // Defer if no handler called resolve synchronously\n if (!settled) {\n settled = true\n resolvePromise(null)\n }\n })\n } else {\n // Custom merge fn: decrypt both → merge → re-encrypt\n const mergeFn = policy as (local: T, remote: T) => T\n resolver = async (id, local, remote) => {\n const localRecord = await this.decryptRecord(local, { skipValidation: true, id })\n const remoteRecord = await this.decryptRecord(remote, { skipValidation: true, id })\n // Tombstone on either side wins — a shredded record must not be\n // resurrected by a merge against a still-live peer.\n if (localRecord === null) return local\n if (remoteRecord === null) return remote\n const merged = mergeFn(localRecord, remoteRecord)\n const mergedVersion = Math.max(local._v, remote._v) + 1\n const cek = this.perRecordCek ? await this.resolveRecordCek(id) : undefined\n return this.encryptRecord(merged, mergedVersion, cek)\n }\n }\n\n opts.onRegisterConflictResolver(collectionName, resolver)\n }\n\n // Default `prefetch: true` keeps semantics. Only opt-in to lazy\n // mode when the consumer explicitly sets `prefetch: false`.\n this.lazy = opts.prefetch === false\n\n if (this.lazy) {\n if (!opts.cache || (opts.cache.maxRecords === undefined && opts.cache.maxBytes === undefined)) {\n throw new Error(\n `Collection \"${this.name}\": lazy mode (prefetch: false) requires a cache option ` +\n `with maxRecords and/or maxBytes. An unbounded lazy cache defeats the purpose.`,\n )\n }\n const lruOptions: { maxRecords?: number; maxBytes?: number } = {}\n if (opts.cache.maxRecords !== undefined) lruOptions.maxRecords = opts.cache.maxRecords\n if (opts.cache.maxBytes !== undefined) lruOptions.maxBytes = parseBytes(opts.cache.maxBytes)\n this.lru = new Lru<string, { record: T; version: number }>(lruOptions)\n this.hydrated = true // lazy mode is always \"hydrated\" — no bulk load\n } else {\n this.lru = null\n }\n\n // delegate mirror construction + declaration to the active\n // indexing strategy. `NO_INDEXING` returns a state whose accessors\n // both return null; the active strategy (from `@noy-db/hub/indexing`)\n // constructs the appropriate mirror based on lazy vs eager mode and\n // declares every IndexDef. With NO_INDEXING the heavy index classes\n // never reach the bundle.\n const strategy = opts.indexStrategy ?? NO_INDEXING\n this.indexState = strategy.createState({\n defs: opts.indexes ?? [],\n lazy: this.lazy,\n })\n\n // Unique-constraint enforcement (eager mode only). Declaring `unique` on\n // a lazy/CRDT/tiered collection throws UnsupportedIndexOptionError here —\n // see buildUniqueConstraintSet (kept out of this kernel file).\n this.uniqueConstraints = buildUniqueConstraintSet(this.name, opts.indexes, {\n lazy: this.lazy,\n crdt: this.crdtMode != null,\n tiered: this.tiers != null,\n })\n }\n\n /**\n * Return the Standard Schema validator attached to this collection,\n * or `undefined` if none was provided at construction time.\n *\n * Exposed (read-only) for the Vault-level export primitive,\n * which surfaces each collection's schema in the per-chunk metadata\n * so downstream serializers (`@noy-db/as-*` packages, custom\n * exporters) can produce schema-aware output without poking at\n * collection internals. The validator object is returned by\n * reference — callers must treat it as immutable.\n */\n getSchema(): StandardSchemaV1<unknown, T> | undefined {\n return this.schema\n }\n\n /**\n * @internal — attach money descriptors post-construction. MV dependency\n * analysis auto-creates a source collection (without options) during\n * `openVault`, before the user's `collection(name, { moneyFields })`\n * declaration; this reconciles that ordering. First-wins. Not public.\n */\n _applyMoneyFields(moneyFields: Record<string, MoneyDescriptor>): void {\n if (this.moneyFields !== undefined) return\n validateMoneyFieldPaths(moneyFields)\n this.moneyFields = moneyFields\n }\n\n /** @internal — attach computed fields post-construction. See {@link _applyMoneyFields}. */\n _applyComputed(computed: ComputedFields): void {\n if (this.computed === undefined) this.computed = computed\n }\n\n /**\n * Get a single record by ID.\n *\n * @param id Record identifier.\n * @param locale Optional locale options. When provided,\n * `i18nText` fields are resolved to the requested locale\n * string, and `dictKey` fields get a `<field>Label`\n * virtual field added. Pass `{ locale: 'raw' }` to\n * return the full `{ [locale]: string }` map instead.\n *\n * @returns The decrypted (and optionally locale-resolved) record, or\n * `null` if not found.\n */\n async get(id: string, locale?: LocaleReadOptions): Promise<T | null> {\n // --- Lazy derivation resolution ---\n // If this collection is the output of a lazy-mode derivation\n // strategy, consult the stale map and re-derive on demand before\n // reading. No-op when nothing is pending — keeps the read fast\n // path cheap.\n if (this.derivationSource !== undefined) {\n const registry = this.derivationSource.registry()\n if (registry.strategiesProducingOutput(this.name).length > 0) {\n await resolveStaleOnRead(this.derivationSource, this.name, id)\n }\n }\n\n // Lazy-MV resolve-on-read. When the collection being read\n // is the output of a registered lazy MV that has at least one\n // pending stale flag, run the executor before returning. No-op\n // when nothing is pending.\n if (this.materializedViewSource !== undefined) {\n const { resolveStaleMVOnRead } = await import('./materialized-views/stale.js')\n await resolveStaleMVOnRead(this.materializedViewSource, this.name)\n }\n\n let record: T | null\n\n if (this.lazy && this.lru) {\n // Cache hit: promote and return.\n const cached = this.lru.get(id)\n if (cached) {\n record = cached.record\n } else {\n // Cache miss: hit the adapter, decrypt, populate the LRU.\n const envelope = await this.adapter.get(this.vault, this.name, id)\n if (!envelope) return null\n // Tombstone tolerance (decision 5): a shredded record carries no\n // body / CEK. Reads return null rather than throwing TamperedError.\n if (isTombstone(envelope, this.encrypted)) return null\n record = await this.decryptRecord(envelope, { id })\n if (record === null) return null\n this.lru.set(id, { record, version: envelope._v }, estimateRecordBytes(record))\n }\n } else {\n // Eager mode: load everything once, then serve from the in-memory map.\n await this.ensureHydrated()\n const entry = this.cache.get(id)\n record = entry ? entry.record : null\n }\n\n if (record === null) return null\n await this.onAccess?.('get', id)\n return this.applyLocaleToRecord(record, locale)\n }\n\n /**\n * Return the raw CRDT state for a record.\n * Only available on collections configured with `crdt: 'lww-map' | 'rga' | 'yjs'`.\n * Use this for merge operations or to pass to `@noy-db/yjs`.\n * Throws if the collection is not in CRDT mode.\n */\n async getRaw(id: string): Promise<CrdtState | null> {\n if (!this.crdtMode) {\n throw new Error(\n `Collection \"${this.name}\": getRaw() is only available when the collection ` +\n `is created with a 'crdt' option ('lww-map', 'rga', or 'yjs').`,\n )\n }\n const envelope = await this.adapter.get(this.vault, this.name, id)\n if (!envelope) return null\n const json = await this.decryptJsonString(envelope)\n if (json === null) return null // shredded (tombstone)\n return JSON.parse(json) as CrdtState\n }\n\n /**\n * Return a presence handle for this collection.\n *\n * The handle manages an encrypted ephemeral presence channel keyed by an\n * HKDF derivation of this collection's DEK. Presence payloads are invisible\n * to the adapter.\n *\n * @param opts.staleMs Milliseconds before a peer is considered inactive.\n * Default: 30 000.\n * @param opts.pollIntervalMs Milliseconds between storage polls (fallback mode).\n * Default: 5 000.\n */\n presence<P = unknown>(opts?: { staleMs?: number; pollIntervalMs?: number }): PresenceHandle<P> {\n const presenceOpts: PresenceHandleOpts = {\n adapter: this.adapter,\n vault: this.vault,\n collectionName: this.name,\n userId: this.keyring.userId,\n encrypted: this.encrypted,\n getDEK: this.getDEK,\n }\n if (this.syncAdapter !== undefined) presenceOpts.syncAdapter = this.syncAdapter\n if (opts?.staleMs !== undefined) presenceOpts.staleMs = opts.staleMs\n if (opts?.pollIntervalMs !== undefined) presenceOpts.pollIntervalMs = opts.pollIntervalMs\n return this.syncStrategy.buildPresence<P>(presenceOpts)\n }\n\n /**\n * Create or update a record. Runs inside the hub's write-queue tracker\n * so `hub.writeQueue.pending` reflects this write.\n *\n * @param id Record identifier.\n * @param record The record body (validated by the collection's schema\n * if one was attached at `vault.collection(...)` time).\n * @param options Optional metadata for audit + import workflows.\n * `reason` is stamped onto the resulting ledger entry\n * so audit consumers can filter via\n * `entries.filter(e => e.reason?.startsWith('import:'))`.\n */\n async put(id: string, record: T, options?: { readonly reason?: string }): Promise<void> {\n // Refuse the write if an update strategy rejected the schema\n // change. Awaited OUTSIDE track() so a rejected write never counts\n // toward writeQueue.depth.\n await this.schemaUpdateGate?.assertWritable()\n await this.schemaFence?.assertWritable(this.name)\n // TODO: putManyAtomic / tx-execute / CRDT /\n // blob write paths are not yet tracked by writeQueue nor fired through\n // the write hooks.\n // User write-hooks AND the observe bus both need the\n // WriteEvent. Build it if EITHER consumer is active so the bus is not\n // coupled to write-hooks being present.\n const hooksActive = this.#hooksActive()\n const busAfterPut = (this.subsystemBus?.hasHandlers('afterPut') ?? false)\n && !(this.subsystemBus?.dispatching ?? false)\n let event: WriteEvent | undefined\n if (hooksActive || busAfterPut) {\n const prior = await this.#priorForHook(id)\n event = {\n op: prior.record === null ? 'create' : 'update',\n vault: this.vault, collection: this.name, docId: id, before: prior.record, after: record,\n userId: this.keyring.userId, timestamp: Date.now(), txId: this.#txIdForHook(),\n baseVersion: prior.version, version: prior.version + 1,\n }\n if (hooksActive) await this.writeHooks!.runBefore(event) // throw → aborts the write\n }\n if (this.writeQueue) await this.writeQueue.track(() => this.putInternal(id, record, options))\n else await this.putInternal(id, record, options)\n if (event) {\n // Ordering: user afterWrite hooks run BEFORE observe-bus dispatch in\n // slice 1. Revisit when internal observe subsystems (e.g. MV-refresh\n // notification) need to settle before user hooks observe state.\n if (hooksActive) await this.writeHooks!.runAfter(event)\n if (busAfterPut) await this.subsystemBus!.dispatch('afterPut', event)\n }\n }\n\n /** @internal — true when hooks should fire for this write (handlers exist, not re-entrant). */\n #hooksActive(): boolean {\n return this.writeHooks !== undefined && this.writeHooks.hasHandlers && !this.writeHooks.suppressed\n }\n\n /**\n * @internal — resolve the prior record for a hook's `before` and\n * its version. Critically, this uses the SAME basis `putInternal` writes from\n * (the in-memory cache in eager mode; lru-then-adapter in lazy) — NOT a fresh\n * store read — so `baseVersion`/`version` match the version actually written.\n * A separate store read would diverge once another tab has advanced the shared\n * store past this tab's cache, breaking cross-tab conflict detection.\n */\n async #priorForHook(id: string): Promise<{ record: unknown; version: number }> {\n if (this.lazy && this.lru) {\n const cached = this.lru.get(id)\n if (cached) return { record: cached.record, version: cached.version }\n const env = await this.adapter.get(this.vault, this.name, id)\n if (!env) return { record: null, version: 0 }\n return { record: (await this.decryptRecord(env, { skipValidation: true })) as unknown ?? null, version: env._v }\n }\n await this.ensureHydrated()\n const cached = this.cache.get(id)\n return cached ? { record: cached.record, version: cached.version } : { record: null, version: 0 }\n }\n\n #txIdForHook(): string {\n return this.activeTxId?.() ?? generateULID()\n }\n\n /** @internal Untracked put body — call {@link put}, not this. */\n private async putInternal(id: string, record: T, options?: { readonly reason?: string }): Promise<void> {\n if (!hasWritePermission(this.keyring, this.name)) {\n throw new ReadOnlyError()\n }\n\n // One canonical money encoding from the FIRST pipeline stage (#335):\n // gates, computed fields, and schema validation all see the decoded\n // `get()` shape. Best-effort — bad input passes through and the\n // quantize stage below throws the real error.\n record = canonicalizeIncomingMoney(record, this.moneyFields) as T\n\n // Gate bus (Track A) — write-gating subsystems (guards: record-lock /\n // field-freeze / amendment-collect; periods: closed-period guard) run here,\n // before any schema/i18n/history work. A throwing gate handler propagates\n // and aborts the write; the amendment branch collects without throwing.\n // Zero-cost when no gate handler is registered.\n if (this.subsystemBus?.hasGateHandlers('beforePut')) {\n const existingEnv = await this.adapter.get(this.vault, this.name, id)\n let existingRecord: unknown = null\n if (existingEnv) {\n try {\n existingRecord = await this.decryptRecord(existingEnv, { skipValidation: true })\n } catch {\n existingRecord = null\n }\n }\n const gateEvent: GatePutEvent = {\n op: existingEnv ? 'update' : 'create',\n vault: this.vault, collection: this.name, docId: id,\n incoming: record,\n existing: canonicalizeStoredMoney(existingRecord, this.moneyFields),\n existingVersion: existingEnv?._v ?? 0,\n existingTs: existingEnv?._ts,\n userId: this.keyring.userId,\n role: this.keyring.role,\n ...(this.computed !== undefined\n ? { computedFieldNames: new Set(Object.keys(this.computed)) }\n : {}),\n }\n await this.subsystemBus.dispatchGate('beforePut', gateEvent)\n }\n\n // Computed scalar fields — evaluated FIRST so the user need not supply\n // them and the schema validates the computed result. Throws\n // ComputedFieldError if a function throws.\n if (this.computed !== undefined) {\n record = evalComputedFields(record as Record<string, unknown>, this.computed, id) as T\n }\n\n // Schema validation — runs BEFORE encryption so invalid records are\n // rejected at the store boundary. The validator may transform the\n // input (e.g., coerce strings → numbers, strip unknown fields), in\n // which case we persist the validated value rather than the raw one.\n // Users who pass a bad shape get a SchemaValidationError with a\n // structured issue list, not a stack trace from deep inside the\n // encrypt path.\n if (this.schema !== undefined) {\n record = await validateSchemaInput(this.schema, record, `put(${id})`)\n }\n\n // Quantize money fields to their stored form (scaled-int string).\n // After schema validation — descriptor owns precision/scale/currency.\n if (this.moneyFields) {\n record = quantizeMoneyFields(record as Record<string, unknown>, this.moneyFields) as T\n }\n\n // Auto-translate missing i18nText translations.\n // Runs BEFORE i18n validation so translated values satisfy the\n // required-locale constraint. Throws TranslatorNotConfiguredError\n // when a field has autoTranslate: true but no hook was configured.\n if (this.i18nFields) {\n const obj = record as Record<string, unknown>\n for (const [field, descriptor] of Object.entries(this.i18nFields)) {\n if (!descriptor.options.autoTranslate) continue\n // getAtPath returns [] for array-wildcard paths — auto-translate on\n // 'contacts[].field' style paths is not supported; skip silently.\n const leafValues = getAtPath(obj, field)\n if (leafValues.length !== 1) continue\n const value = leafValues[0]\n if (!value || typeof value !== 'object' || Array.isArray(value)) continue\n const map = value as Record<string, string>\n // Determine which locales need translation. For 'all', translate all\n // declared languages that are missing. For 'any', only translate if\n // none are present. For string[], translate the listed required ones.\n const { languages, required } = descriptor.options\n const missing: string[] = languages.filter(\n (lang) => !(lang in map) || map[lang] === '',\n )\n if (missing.length === 0) continue\n // Find a source locale (first present non-empty value)\n const sourceLocale = languages.find((l) => l in map && map[l] !== '')\n if (!sourceLocale) continue\n if (!this.autoTranslateHook) {\n throw new TranslatorNotConfiguredError(field, this.name)\n }\n // Only translate locales that are actually needed\n const toTranslate =\n required === 'any'\n ? [] // 'any' is already satisfied since sourceLocale exists\n : required === 'all'\n ? missing\n : missing.filter((l) => required.includes(l))\n const translated = { ...map }\n for (const targetLocale of toTranslate) {\n translated[targetLocale] = await this.autoTranslateHook(\n map[sourceLocale]!,\n sourceLocale,\n targetLocale,\n field,\n this.name,\n )\n }\n setAtPathInPlace(obj, field, translated)\n }\n }\n\n // i18nText script enforcement — runs AFTER auto-translate (so\n // generated values are checked too). Throws ScriptViolationError\n // under the default 'reject'; 'filter' strips disallowed chars in\n // place (getAtPath returns live leaf references, so the write-back\n // covers nested and array-wildcard paths uniformly); 'warn' leaves\n // the value unchanged.\n if (this.i18nFields) {\n const obj = record as Record<string, unknown>\n for (const [field, descriptor] of Object.entries(this.i18nFields)) {\n if (!descriptor.options.script) continue\n for (const leaf of getAtPath(obj, field)) {\n if (!leaf || typeof leaf !== 'object' || Array.isArray(leaf)) continue\n const leafMap = leaf as Record<string, unknown>\n const { value: cleaned } = this.i18nStrategy.enforceScript(\n leafMap,\n field,\n descriptor,\n )\n if (cleaned !== leafMap) Object.assign(leafMap, cleaned)\n }\n }\n }\n\n // i18nText validation — runs AFTER schema validation so\n // the record shape is trustworthy. Throws MissingTranslationError\n // when required translations are absent.\n if (this.i18nPutValidator !== undefined) {\n this.i18nPutValidator(record)\n }\n\n // Foreign-key ref enforcement. Runs AFTER schema\n // validation (so the record shape is trustworthy) but BEFORE\n // any write (so a failed strict ref leaves no trace on disk,\n // in history, or in the ledger). The Vault handles the\n // actual target lookups — see `enforceRefsOnPut` over there.\n if (this.refEnforcer !== undefined) {\n await this.refEnforcer.enforceRefsOnPut(this.name, record)\n }\n\n // ─── CRDT mode ─────────────────────────────────────────\n // In CRDT mode we always read the raw envelope from the adapter to get\n // the existing CRDT state, merge the incoming record into it, then\n // encrypt the merged CRDT state — bypassing the normal version path.\n if (this.crdtMode) {\n const existingEnvelope = await this.adapter.get(this.vault, this.name, id)\n const existingVersion = existingEnvelope?._v ?? 0\n const now = new Date().toISOString()\n\n let crdtState: CrdtState\n\n if (this.crdtMode === 'lww-map') {\n let existingState: LwwMapState | undefined\n if (existingEnvelope) {\n const prevJson = await this.decryptJsonString(existingEnvelope)\n if (prevJson !== null) {\n const prevParsed = JSON.parse(prevJson) as unknown\n if (prevParsed !== null && typeof prevParsed === 'object' && '_crdt' in prevParsed) {\n existingState = prevParsed as LwwMapState\n }\n }\n }\n crdtState = this.crdtStrategy.buildLwwMapState(record as Record<string, unknown>, existingState, now)\n } else if (this.crdtMode === 'rga') {\n let existingState: RgaState | undefined\n if (existingEnvelope) {\n const prevJson = await this.decryptJsonString(existingEnvelope)\n if (prevJson !== null) {\n const prevParsed = JSON.parse(prevJson) as unknown\n if (prevParsed !== null && typeof prevParsed === 'object' && '_crdt' in prevParsed) {\n existingState = prevParsed as RgaState\n }\n }\n }\n const arr = Array.isArray(record) ? record : [record]\n crdtState = this.crdtStrategy.buildRgaState(arr, existingState, generateULID)\n } else {\n // yjs: record is the base64 update string (produced by @noy-db/yjs)\n crdtState = { _crdt: 'yjs', update: record as unknown as string }\n }\n\n const version = existingVersion + 1\n // Stable per-record CEK shared by the new CRDT body and its history\n // snapshot (undefined on non-CEK collections → legacy path).\n const cek = this.perRecordCek ? await this.resolveRecordCek(id) : undefined\n const envelope = await this.encryptJsonString(JSON.stringify(crdtState), version, cek)\n await this.adapter.put(this.vault, this.name, id, envelope)\n\n // Resolve snapshot for cache and history\n const resolvedRecord = this.crdtStrategy.resolveCrdtSnapshot(crdtState) as T\n // A tombstone (shredded) prior envelope yields a null record → treat as\n // \"no previous version\" so we don't snapshot/diff an erased value.\n const existingResolvedRecord = existingEnvelope\n ? await this.decryptRecord(existingEnvelope, { skipValidation: true })\n : null\n const existingResolved = existingResolvedRecord !== null\n ? { record: existingResolvedRecord, version: existingVersion }\n : undefined\n\n if (existingResolved && this.historyConfig.enabled !== false) {\n const histEnvelope = await this.encryptRecord(existingResolved.record, existingResolved.version, cek)\n await this.historyStrategy.saveHistory(this.adapter, this.vault, this.name, id, histEnvelope)\n this.emitter.emit('history:save', { vault: this.vault, collection: this.name, id, version: existingResolved.version })\n if (this.historyConfig.maxVersions) {\n await this.historyStrategy.pruneHistory(this.adapter, this.vault, this.name, id, { keepVersions: this.historyConfig.maxVersions })\n }\n }\n\n if (this.ledger) {\n const appendInput: Parameters<typeof this.ledger.append>[0] = {\n op: 'put', collection: this.name, id, version, actor: this.keyring.userId,\n payloadHash: await this.historyStrategy.envelopePayloadHash(envelope),\n }\n if (existingResolved) appendInput.delta = this.historyStrategy.computePatch(resolvedRecord, existingResolved.record)\n if (options?.reason !== undefined) appendInput.reason = options.reason\n await this.ledger.append(appendInput)\n }\n\n if (this.lazy && this.lru) {\n this.lru.set(id, { record: resolvedRecord, version }, estimateRecordBytes(resolvedRecord))\n await this.maintainPersistedIndexesOnPut(\n id,\n resolvedRecord,\n existingResolved ? existingResolved.record : null,\n version,\n )\n } else {\n this.cache.set(id, { record: resolvedRecord, version })\n this.indexes?.upsert(id, resolvedRecord, existingResolved ? existingResolved.record : null)\n }\n\n await this.onDirty?.(this.name, id, 'put', version)\n this.emitter.emit('change', { vault: this.vault, collection: this.name, id, action: 'put' } satisfies ChangeEvent)\n await this.onAccess?.('put', id)\n await this.dispatchDerivations(id, record, version)\n await this.dispatchMaterializedViews(id, record)\n return\n }\n // ─── End CRDT mode ──────────────────────────────────────────────────\n\n // Resolve the previous record. In eager mode this comes from the\n // in-memory map (no I/O); in lazy mode we have to ask the adapter\n // because the record may have been evicted (or never loaded).\n let existing: { record: T; version: number } | undefined\n if (this.lazy && this.lru) {\n existing = this.lru.get(id)\n if (!existing) {\n const previousEnvelope = await this.adapter.get(this.vault, this.name, id)\n if (previousEnvelope) {\n const previousRecord = await this.decryptRecord(previousEnvelope)\n // Tombstone (shredded) prior → treat as no previous version.\n if (previousRecord !== null) {\n existing = { record: previousRecord, version: previousEnvelope._v }\n }\n }\n }\n } else {\n await this.ensureHydrated()\n existing = this.cache.get(id)\n }\n\n const version = existing ? existing.version + 1 : 1\n\n // Unique-constraint pre-flight — BEFORE history-save so a violation\n // never writes a history snapshot or fires 'history:save'. Runs after\n // ensureHydrated() (eager path above) so the constraint map already\n // reflects records from prior sessions. No-op when no unique indexes\n // are declared.\n this.uniqueConstraints?.check(id, record)\n\n // Per-record CEK: resolve the record's stable CEK ONCE (insert mints,\n // update reuses the live envelope's CEK), then encrypt BOTH the history\n // snapshot of the prior version AND the new body under it — so every\n // version of a record carries the same `_cek` and dies together on a\n // future shred. `undefined` on a legacy / non-CEK collection → the\n // byte-identical legacy write path.\n const cek = this.perRecordCek ? await this.resolveRecordCek(id) : undefined\n\n // Save history snapshot of the PREVIOUS version before overwriting\n if (existing && this.historyConfig.enabled !== false) {\n const historyEnvelope = await this.encryptRecord(existing.record, existing.version, cek)\n await this.historyStrategy.saveHistory(this.adapter, this.vault, this.name, id, historyEnvelope)\n\n this.emitter.emit('history:save', {\n vault: this.vault,\n collection: this.name,\n id,\n version: existing.version,\n })\n\n // Auto-prune if maxVersions configured\n if (this.historyConfig.maxVersions) {\n await this.historyStrategy.pruneHistory(this.adapter, this.vault, this.name, id, {\n keepVersions: this.historyConfig.maxVersions,\n })\n }\n }\n\n const envelope = await this.encryptRecord(record, version, cek)\n await this.adapter.put(this.vault, this.name, id, envelope)\n\n // Ledger append — AFTER the adapter write succeeds so a failed\n // write never produces an orphan ledger entry. Computing the\n // payloadHash here uses the envelope we just wrote, which is the\n // exact bytes the adapter now holds. The ledger entry records\n // only metadata (collection, id, version, hash) — NOT the record\n // itself — and is then encrypted with the compartment's ledger\n // DEK, preserving zero-knowledge. See `LedgerStore.append`.\n //\n // **Delta history**: if there was a previous version, we\n // compute a JSON Patch from it to the new record and pass it\n // through `append.delta`. The LedgerStore stores the patch in\n // the sibling `_ledger_deltas/` collection and records its hash\n // in the entry's `deltaHash` field. Genesis puts (no existing\n // record) leave `delta` undefined — there's nothing to diff\n // against — and the ledger entry has no `deltaHash`.\n if (this.ledger) {\n const appendInput: Parameters<typeof this.ledger.append>[0] = {\n op: 'put',\n collection: this.name,\n id,\n version,\n actor: this.keyring.userId,\n payloadHash: await this.historyStrategy.envelopePayloadHash(envelope),\n }\n if (existing) {\n // REVERSE patch: describes how to undo this put — i.e., how\n // to transform the NEW record back into the PREVIOUS one.\n // Storing reverse patches lets `ledger.reconstruct()` walk\n // backward from the current state (readily available in the\n // data collection) without needing a forward-walking base\n // snapshot, which would double the storage cost of the\n // delta scheme. See `LedgerStore.reconstruct` for the walk.\n appendInput.delta = this.historyStrategy.computePatch(record, existing.record)\n }\n if (options?.reason !== undefined) appendInput.reason = options.reason\n await this.ledger.append(appendInput)\n }\n\n if (this.lazy && this.lru) {\n this.lru.set(id, { record, version }, estimateRecordBytes(record))\n // Maintain persisted-index side-cars. Lazy mode is the\n // only place `persistedIndexes` is populated; eager mode uses the\n // in-memory `CollectionIndexes` above.\n await this.maintainPersistedIndexesOnPut(id, record, existing ? existing.record : null, version)\n } else {\n this.cache.set(id, { record, version })\n // Update secondary indexes incrementally — no-op if no indexes are\n // declared. Pass the previous record (if any) so old buckets are\n // cleaned up before the new value is added.\n this.indexes?.upsert(id, record, existing ? existing.record : null)\n // Update unique-constraint maps to reflect the successful write.\n this.uniqueConstraints?.upsert(id, record, existing?.record)\n }\n\n await this.onDirty?.(this.name, id, 'put', version)\n\n this.emitter.emit('change', {\n vault: this.vault,\n collection: this.name,\n id,\n action: 'put',\n } satisfies ChangeEvent)\n\n await this.onAccess?.('put', id)\n\n // Derivation dispatch — AFTER store + ledger + emitter commit so a\n // failed source-write never produces orphan derived outputs. The\n // recursive `put` into output collections re-enters this pipeline\n // (encrypt + ledger + emit) intentionally; cycle detection at vault\n // open is the primary defense against infinite recursion.\n await this.dispatchDerivations(id, record, version)\n await this.dispatchMaterializedViews(id, record)\n }\n\n /**\n * Fire registered MV strategies whose dependency set includes this\n * collection. Eager-mode MVs re-materialize inline via\n * `MaterializedViewExecutor.refresh`; lazy / manual modes are\n * no-ops in the foundation; wired in the lazy-mode implementation.\n *\n * Skips entirely when the record being written is itself an\n * MV-emitted row (carries `_materializedFrom`) — defensive guard\n * against missed cycle detection.\n *\n * @internal\n */\n private async dispatchMaterializedViews(id: string, record: T): Promise<void> {\n void id\n if (this.materializedViewSource === undefined) return\n const incoming = record as unknown as Record<string, unknown>\n if (incoming && typeof incoming === 'object' && '_materializedFrom' in incoming) return\n const registry = this.materializedViewSource.registry()\n const mvs = registry.mvsForSource(this.name)\n if (mvs.length === 0) return\n // Dynamic-import the executor only on first eager-MV dispatch —\n // keeps the MV executor chunk out of the floor bundle (mirrors the\n // dynamic-import pattern used for derivations). Lazy mode\n // uses the pure-helper `markMVStale` which lives in `stale.js` and\n // is also dynamic-imported (only when at least one lazy MV depends\n // on this source).\n let executor: typeof MVExecutorType | null = null\n let staleHelpers: typeof MVStaleModule | null = null\n for (const reg of mvs) {\n const mode = reg.spec.refresh\n if (mode === 'eager') {\n if (executor === null) {\n ;({ MaterializedViewExecutor: executor } = await import('./materialized-views/executor.js'))\n }\n await executor.refresh(reg, {\n getCollection: (name) => this.materializedViewSource!.getCollection(name),\n getActiveTxContext: () => this.materializedViewSource!.getActiveTxContext(),\n getQueryContext: () => this.materializedViewSource!.getQueryContext(),\n })\n } else if (mode === 'lazy') {\n if (staleHelpers === null) {\n staleHelpers = await import('./materialized-views/stale.js')\n }\n staleHelpers.markMVStale(registry, reg.spec.name)\n }\n // manual: no-op on source-write. `vault.refreshView(name)` is\n // the only path that materializes a manual MV.\n }\n }\n\n /**\n * Fire registered derivation strategies for this source collection.\n * Eager mode runs `derive` inline and writes each output via the\n * sibling `Collection.put`; lazy mode marks dependent outputs stale\n * (D11 stub today). Errors in non-strict mode are logged and\n * skipped; strict mode propagates the first failing output's error.\n *\n * Skips entirely when the record being written is itself a derived\n * output (carries `_derivedFrom`) — defensive guard against missed\n * cycle detection.\n */\n private async dispatchDerivations(id: string, record: T, version: number): Promise<void> {\n if (this.derivationSource === undefined) return\n // `record` is the stored form here (post-quantize) — decode so\n // derive(source, ctx) sees the canonical money shape (#335).\n const incoming = canonicalizeStoredMoney(record, this.moneyFields) as Record<string, unknown>\n if (incoming && typeof incoming === 'object' && '_derivedFrom' in incoming) return\n const registry = this.derivationSource.registry()\n const strategies = registry.strategiesForSource(this.name)\n if (strategies.length === 0) return\n // Dynamic-import the executor only on the first eager-mode\n // dispatch. Lazy-mode dispatches use `markStale` (a pure helper)\n // which doesn't reach into the executor at all. Keeps the\n // derivation executor chunk out of the floor bundle for any\n // consumer that doesn't fire an eager derivation.\n let DerivationExecutor: typeof DerivationExecutorType | null = null\n for (const { spec, strategyHash } of strategies) {\n const mode = typeof spec.lifecycle === 'string' ? spec.lifecycle : spec.lifecycle.mode\n if (mode === 'eager') {\n if (DerivationExecutor === null) {\n ({ DerivationExecutor } = (await import('./derivations/executor.js')) as { DerivationExecutor: typeof DerivationExecutorType })\n }\n // #344: a sibling-triggered strategy (spec.source !== this.name)\n // derives against the PRIMARY source record at the same id — not\n // the incoming sibling record. Read it through the primary\n // collection so its own money/crypto wiring applies; silent\n // no-op if no primary record exists at that id (same-id rule).\n let sourceWithId: Record<string, unknown> & { id: string }\n let sourceVersion = version\n if (spec.source === this.name) {\n sourceWithId = { ...incoming, id } as Record<string, unknown> & { id: string }\n } else {\n const primary = await this.derivationSource.getCollection(spec.source).get(id)\n if (primary === null || primary === undefined) continue\n sourceWithId = { ...primary, id } as Record<string, unknown> & { id: string }\n sourceVersion = 0\n }\n const ctx = { vault: this.derivationSource.getReadOnlyFacade() }\n const result = await DerivationExecutor.run(spec, sourceWithId, sourceVersion, strategyHash, ctx)\n for (const key of Object.keys(spec.outputs)) {\n const out = result.outputs[key]\n if (!out) continue\n if (out.kind === 'failed') {\n const err = out.error\n if (spec.strict) throw err\n console.warn(`[derivation] output \"${key}\" for source \"${spec.source}\" id=\"${id}\" failed:`, err)\n continue\n }\n const outSpec = spec.outputs[key]\n if (!outSpec) continue\n const outputCollection = this.derivationSource.getCollection(outSpec.collection)\n // If we're inside a multi-record transaction, register\n // derived writes as side-effect ops on the active ctx\n // BEFORE they fire. `revertExecuted` walks `_executed` in\n // reverse on rollback, so capturing the pre-write envelope\n // here lets a later mid-batch failure restore this output's\n // prior state alongside the source op. Outside a transaction\n // the context is null and tracking is skipped.\n const txCtx = this.derivationSource.getActiveTxContext()\n\n // ── Array-shape branch ─────────────────────────────────\n if (out.kind === 'array') {\n // Load the prior key set from the fanout sidecar.\n const { loadFanoutSidecar, saveFanoutSidecar } = await import('./derivations/fanout-sidecar.js')\n const prior = await loadFanoutSidecar(\n this.adapter,\n this.vault,\n spec.source,\n id,\n key,\n )\n const prevKeys = new Set<string>(prior?.keys ?? [])\n const newKeysList = out.entries.map(e => e.key)\n const newKeysSet = new Set<string>(newKeysList)\n\n // Diff — delete keys that were in prev but not in new.\n for (const k of prevKeys) {\n if (newKeysSet.has(k)) continue\n await outputCollection._internalDelete(k, txCtx)\n }\n\n // Upsert every entry in the new set. (Slice 1: no\n // identity-skip optimisation; write every row, idempotent\n // at the (collection, id) level.)\n for (const entry of out.entries) {\n if (txCtx !== null) {\n const priorEnvelope = await this.adapter.get(this.vault, outSpec.collection, entry.key)\n txCtx._executed.push({\n op: {\n type: 'put',\n vaultName: this.vault,\n collectionName: outSpec.collection,\n id: entry.key,\n },\n priorEnvelope,\n })\n }\n await outputCollection.put(entry.key, entry.value)\n }\n\n // Persist the new key set (last step — see spec §5.1\n // on failure-mode symmetry).\n await saveFanoutSidecar(this.adapter, this.vault, {\n source: spec.source,\n sourceId: id,\n outputKey: key,\n outputCollection: outSpec.collection,\n keys: newKeysList,\n })\n continue\n }\n\n // ── Record-shape branch (existing v1 behavior) ─────────\n if (out.skipped === true) {\n // Optional output returned null. Delete the\n // previously-emitted output at this id, if any. Routed\n // through `_internalDelete` so a user-registered\n // `onDelete` on the output collection does NOT\n // fire — this is a system-internal tombstone, not a\n // user-initiated delete. The txCtx hookup captures the\n // prior envelope inside `_internalDelete` for rollback\n // symmetry; delete-of-absent is a silent no-op.\n await outputCollection._internalDelete(id, txCtx)\n continue\n }\n if (txCtx !== null) {\n const prior = await this.adapter.get(this.vault, outSpec.collection, id)\n txCtx._executed.push({\n op: {\n type: 'put',\n vaultName: this.vault,\n collectionName: outSpec.collection,\n id,\n },\n priorEnvelope: prior,\n })\n }\n await outputCollection.put(id, out.value)\n }\n } else {\n await markStale(registry, spec, id)\n }\n }\n }\n\n /**\n * Delete a record by ID. Runs inside the hub's write-queue tracker\n * so `hub.writeQueue.pending` reflects this write.\n */\n async delete(id: string): Promise<void> {\n await this.schemaUpdateGate?.assertWritable()\n await this.schemaFence?.assertWritable(this.name)\n // #230 user write-hooks AND the Track A observe bus both need the\n // WriteEvent. Build it if EITHER consumer is active so the bus is not\n // coupled to write-hooks being present. Mirrors the put() path.\n const hooksActive = this.#hooksActive()\n const busAfterDelete = (this.subsystemBus?.hasHandlers('afterDelete') ?? false)\n && !(this.subsystemBus?.dispatching ?? false)\n let event: WriteEvent | undefined\n if (hooksActive || busAfterDelete) {\n const prior = await this.#priorForHook(id)\n event = {\n op: 'delete', vault: this.vault, collection: this.name, docId: id, before: prior.record, after: null,\n userId: this.keyring.userId, timestamp: Date.now(), txId: this.#txIdForHook(),\n baseVersion: prior.version, version: prior.version + 1,\n }\n if (hooksActive) await this.writeHooks!.runBefore(event)\n }\n if (this.writeQueue) await this.writeQueue.track(() => this.deleteInternal(id))\n else await this.deleteInternal(id)\n if (event) {\n // Ordering: user afterWrite hooks run before observe-bus dispatch.\n if (hooksActive) await this.writeHooks!.runAfter(event)\n if (busAfterDelete) await this.subsystemBus!.dispatch('afterDelete', event)\n }\n }\n\n /**\n * @internal — bulk-rewrite every record through a cutover transform.\n * Raw adapter path (bypasses the write gate + guards — the transform is\n * trusted and runs only during the `migrating` phase). Bumps each\n * record's `_v` and appends a ledger `op:'migration'` entry.\n */\n async _applyCutoverTransform(\n transform: (doc: Record<string, unknown>) => Record<string, unknown>,\n ): Promise<number> {\n const ids = await this.adapter.list(this.vault, this.name)\n let count = 0\n for (const id of ids) {\n const env = await this.adapter.get(this.vault, this.name, id)\n if (!env || isTombstone(env, this.encrypted)) continue\n const decoded = await this.decryptRecord(env, { skipValidation: true, id })\n if (decoded === null) continue // defensive: shredded between list and get\n const record = decoded as unknown as Record<string, unknown>\n const next = transform(record)\n const nextVersion = (env._v ?? 0) + 1\n // Migration pass: on a `perRecordKeys` collection, a legacy (no-`_cek`)\n // record gets a freshly minted CEK here (legacy → CEK re-encrypt), while\n // an already-CEK record reuses its stable CEK. This is the\n // erasure-completeness pass — once migrated, the record body is keyed\n // off a per-record CEK and a future shred can erase it. Until then it\n // stays directly under the collection DEK. `forget()`/shred (step 2,\n // #304) reports un-migrated records explicitly rather than claiming\n // erasure.\n const cek = this.perRecordCek ? await this.resolveRecordCek(id) : undefined\n const newEnv = await this.encryptRecord(next as unknown as T, nextVersion, cek)\n await this.adapter.put(this.vault, this.name, id, newEnv)\n await this._invalidateCacheEntry(id) // refresh in-memory cache after the raw write\n if (this.ledger) {\n await this.ledger.append({\n op: 'migration', collection: this.name, id, version: nextVersion,\n actor: this.keyring.userId, payloadHash: '', reason: 'schema:coordinated-cutover',\n }).catch(() => { /* ledger is best-effort here */ })\n }\n count++\n }\n return count\n }\n\n /** @internal Untracked delete body — call {@link delete}, not this. */\n private async deleteInternal(id: string): Promise<void> {\n await this._doDelete(id, false)\n }\n\n /**\n * @internal — system-internal delete that bypasses user-facing\n * delete hooks (`onDelete`, FK ref enforcer). Used by derivation tombstones and MV refresh\n * (Dim 14 v2) — system housekeeping shouldn't trip user invariants\n * registered against the output collection. The ledger entry and\n * history snapshot still fire so backup integrity and time-travel\n * reconstruction stay consistent.\n *\n * Returns silently for delete-of-absent (idempotent contract — both\n * paths honour this: the `txCtx === null` path also reads the prior\n * envelope and short-circuits before the ledger/event side-effects).\n *\n * When a `txCtx` is supplied, the prior envelope is captured and\n * pushed onto `txCtx._executed` BEFORE the delete fires — mirrors\n * the rollback hardening for puts. Callers outside a\n * multi-record transaction pass `null` and skip the tracking.\n *\n * Amendment composition: if `_internalDelete` runs while a vault's\n * `GuardRegistry` has an amendment window open, the `{before, after:\n * null}` change pair is pushed onto the amendment change-set the\n * same way a user-initiated delete would. The `onDelete` user-hook\n * is still skipped (housekeeping must not trip user invariants in\n * normal mode), but the amendment's invariant DOES see the change\n * — so a `RCT-CANCEL-001`-style invariant pairing can reject a\n * derivation-driven tombstone fired during an admin amendment.\n *\n * Constraint to surface to consumers: output collections of\n * derivations with `optional: true` outputs should not be the\n * targets of `strict` or `cascade` inbound foreign-key refs —\n * `_internalDelete` bypasses the ref enforcer by design (the\n * `onDelete` bypass primitive). Treat the housekeeping path as\n * \"system can tombstone its own emissions regardless of FK shape.\"\n *\n * Permission handling is unchanged: the caller must still hold\n * write permission on the collection (derivations run under the\n * user's keyring).\n */\n async _internalDelete(id: string, txCtx: TxContext | null = null): Promise<void> {\n // Idempotency contract: short-circuit before any ledger/event\n // side-effect when the target is absent. Both txCtx-aware and\n // txCtx-null callers honour this — `deriveAll` recomputes\n // expense-only allocations that never emitted a receipt without\n // writing spurious v0 ledger entries.\n const prior = await this.adapter.get(this.vault, this.name, id)\n if (prior === null) return\n if (txCtx !== null) {\n txCtx._executed.push({\n op: {\n type: 'delete',\n vaultName: this.vault,\n collectionName: this.name,\n id,\n },\n priorEnvelope: prior,\n })\n }\n await this._doDelete(id, true)\n }\n\n private async _doDelete(id: string, internal: boolean): Promise<void> {\n if (!hasWritePermission(this.keyring, this.name)) {\n throw new ReadOnlyError()\n }\n\n // Gate bus (Track A) — fires for ALL deletes (carrying `internal`), so a\n // gate handler can collect amendment changes on system-internal deletes\n // while branching off `onDelete`/period checks for them. Delete-of-absent\n // (no envelope) does not fire.\n if (this.subsystemBus?.hasGateHandlers('beforeDelete')) {\n const existingEnv = await this.adapter.get(this.vault, this.name, id)\n if (existingEnv) {\n let existingRecord: unknown = null\n try {\n existingRecord = await this.decryptRecord(existingEnv, { skipValidation: true })\n } catch {\n existingRecord = null\n }\n await this.subsystemBus.dispatchGate('beforeDelete', {\n vault: this.vault, collection: this.name, docId: id,\n existing: canonicalizeStoredMoney(existingRecord, this.moneyFields),\n existingVersion: existingEnv._v,\n existingTs: existingEnv._ts,\n internal,\n userId: this.keyring.userId,\n role: this.keyring.role,\n })\n }\n }\n\n // Foreign-key ref enforcement on delete. Runs BEFORE\n // the adapter delete so a `strict` inbound ref with existing\n // references blocks the delete entirely (no partial state, no\n // history churn, no ledger entry for a rejected op). `cascade`\n // recursively deletes the referencing records first, then falls\n // through to the normal delete path below. `warn` is a no-op\n // here — violations surface through `checkIntegrity()`.\n if (!internal && this.refEnforcer !== undefined) {\n await this.refEnforcer.enforceRefsOnDelete(this.name, id)\n }\n\n // In lazy mode the record may not be cached; ask the adapter so we\n // can still write a history snapshot if history is enabled.\n let existing: { record: T; version: number } | undefined\n if (this.lazy && this.lru) {\n existing = this.lru.get(id)\n if (!existing && this.historyConfig.enabled !== false) {\n const previousEnvelope = await this.adapter.get(this.vault, this.name, id)\n if (previousEnvelope) {\n const previousRecord = await this.decryptRecord(previousEnvelope)\n // Tombstone (shredded) prior → no record to snapshot on delete.\n if (previousRecord !== null) {\n existing = { record: previousRecord, version: previousEnvelope._v }\n }\n }\n }\n } else {\n existing = this.cache.get(id)\n }\n\n // Save history snapshot before deleting. On a CEK collection the\n // snapshot reuses the record's stable CEK so the displaced version\n // stays in the same key chain as the rest of its history.\n if (existing && this.historyConfig.enabled !== false) {\n const cek = this.perRecordCek ? await this.resolveRecordCek(id) : undefined\n const historyEnvelope = await this.encryptRecord(existing.record, existing.version, cek)\n await this.historyStrategy.saveHistory(this.adapter, this.vault, this.name, id, historyEnvelope)\n }\n\n // Capture the previous envelope's payloadHash BEFORE delete so we\n // have a stable reference for the ledger entry. The hash is of\n // whatever was last visible to readers — for a `delete` of a\n // never-existed record, we use the empty string (which the\n // ledger entry's `payloadHash` field tolerates).\n const previousEnvelope = await this.adapter.get(this.vault, this.name, id)\n const previousPayloadHash = await this.historyStrategy.envelopePayloadHash(previousEnvelope)\n\n await this.adapter.delete(this.vault, this.name, id)\n\n // Ledger append — same after-write timing as put(). The recorded\n // version is the version that WAS deleted (existing?.version), not\n // a successor. A delete of a missing record still appends an\n // entry with version 0 so the chain captures the intent.\n if (this.ledger) {\n await this.ledger.append({\n op: 'delete',\n collection: this.name,\n id,\n version: existing?.version ?? 0,\n actor: this.keyring.userId,\n payloadHash: previousPayloadHash,\n })\n }\n\n if (this.lazy && this.lru) {\n this.lru.remove(id)\n // Tear down persisted-index side-cars for any declared fields on\n // this record. No-op when no fields are declared or the record\n // had never been indexed (e.g. a delete of a missing id).\n if (existing) {\n await this.maintainPersistedIndexesOnDelete(id, existing.record)\n }\n } else {\n this.cache.delete(id)\n // Remove from secondary indexes — no-op if no indexes are declared\n // or the record wasn't previously indexed.\n if (existing) {\n this.indexes?.remove(id, existing.record)\n // Remove from unique-constraint maps so the deleted value is freed.\n this.uniqueConstraints?.remove(id, existing.record)\n }\n }\n\n await this.onDirty?.(this.name, id, 'delete', existing?.version ?? 0)\n\n this.emitter.emit('change', {\n vault: this.vault,\n collection: this.name,\n id,\n action: 'delete',\n } satisfies ChangeEvent)\n\n await this.onAccess?.('delete', id)\n\n // Symmetric to put: user-initiated deletes must fire MV\n // refresh so `onEmpty: 'delete'` MVs tombstone their now-orphan\n // output rows. Gated on `!internal` to prevent recursion — the\n // MV executor's own tombstoning round-trips through\n // `_internalDelete → _doDelete(_, true)` and must NOT re-fire\n // dispatch (matches put's `_materializedFrom` skip in spirit).\n //\n // Record-shape derivations intentionally NOT dispatched on delete:\n // their derived-output id equals the source id, so the user can\n // delete the output directly with `outputCollection.delete(id)` if\n // they want. Array-shape derivations DO cascade on delete\n // because their derived ids are opaque (from the `key(out)`\n // extractor) — without cascade the rows become unfindable orphans.\n if (!internal) {\n await this.dispatchMaterializedViewsOnDelete(id)\n await this.dispatchArrayDerivationsOnDelete(id)\n }\n }\n\n /**\n * @internal — GDPR crypto-shred a LIVE record to a tombstone (#304).\n *\n * Rewrites the on-disk envelope to `{ _noydb, _v, _ts, _by, _iv:'', _data:'' }`,\n * dropping `_iv`/`_data`/`_cek`/`_det`. The wrapped per-record CEK is gone, so\n * the body — and (via {@link tombstoneHistory}) every history version under\n * the same CEK — is permanently undecryptable; the collection DEK and every\n * other record are untouched. `_det` is stripped too, so `findByDet` no\n * longer matches the shredded record (avoiding a post-shred TamperedError).\n *\n * Unlike `delete()`/`_internalDelete`, this:\n * - does NOT fire onDelete guards / MV / derivation dispatch (a shred is an\n * erasure, not a domain delete — re-running those would be wrong),\n * - does NOT append a per-record ledger entry (`vault.forget()` appends a\n * single `op:'forget'` summary for the whole subject),\n * - keeps the record KEY present (it's an overwrite, not an adapter delete)\n * so the version counter + \"record existed\" survive for audit.\n *\n * Idempotent: returns `null` when the record is absent or already a tombstone.\n * Otherwise returns `{ previousVersion }`. Invalidates the eager cache, the\n * lazy LRU, and the per-record CEK cache for this id.\n */\n /**\n * @internal — decrypt an envelope to a plain record for subject-index\n * rebuild (#304). Returns `null` for a tombstone or unreadable envelope.\n * Skips schema validation — the rebuild only reads the subject field.\n */\n async _decodeEnvelope(envelope: EncryptedEnvelope, id: string): Promise<Record<string, unknown> | null> {\n try {\n const rec = await this.decryptRecord(envelope, { skipValidation: true, id })\n return rec === null ? null : (rec as unknown as Record<string, unknown>)\n } catch {\n return null\n }\n }\n\n async _writeTombstone(id: string, actor: string): Promise<{ previousVersion: number } | null> {\n const live = await this.adapter.get(this.vault, this.name, id)\n if (!live || isTombstone(live, this.encrypted)) return null\n\n await this.adapter.put(this.vault, this.name, id, buildTombstone(live._v, actor))\n\n // Invalidate every in-memory view of this record so subsequent reads see\n // the tombstone (→ null), not a stale decrypted value.\n this.cache.delete(id)\n this.lru?.remove(id)\n this.cekCache?.remove(id)\n\n return { previousVersion: live._v }\n }\n\n /**\n * Cascade deletes of array-shape derived rows when a source row is\n * deleted. Reads each registered strategy's fanout sidecar\n * for this source id, deletes every listed derived row, then\n * deletes the sidecar itself.\n *\n * Record-shape derivations are skipped — see _doDelete's comment\n * for why the asymmetry is correct.\n *\n * @internal\n */\n private async dispatchArrayDerivationsOnDelete(id: string): Promise<void> {\n if (this.derivationSource === undefined) return\n const registry = this.derivationSource.registry()\n const strategies = registry.strategiesForSource(this.name)\n if (strategies.length === 0) return\n\n // Dynamic-import the sidecar helpers — keeps the derivation\n // chunk out of the floor bundle for consumers that don't use\n // array-shape derivations.\n let helpers: {\n loadFanoutSidecar: typeof LoadFanoutSidecarType\n deleteFanoutSidecar: typeof DeleteFanoutSidecarType\n saveFanoutSidecar: typeof SaveFanoutSidecarType\n } | null = null\n const txCtx = this.derivationSource.getActiveTxContext()\n\n for (const { spec } of strategies) {\n for (const [outputKey, outSpec] of Object.entries(spec.outputs)) {\n if (outSpec.shape !== 'array') continue\n if (helpers === null) {\n helpers = await import('./derivations/fanout-sidecar.js')\n }\n const sidecar = await helpers.loadFanoutSidecar(\n this.adapter,\n this.vault,\n spec.source,\n id,\n outputKey,\n )\n if (!sidecar) continue\n const outputCollection = this.derivationSource.getCollection(outSpec.collection)\n for (const derivedId of sidecar.keys) {\n await outputCollection._internalDelete(derivedId, txCtx)\n }\n await helpers.deleteFanoutSidecar(this.adapter, this.vault, spec.source, id, outputKey)\n }\n }\n }\n\n /**\n * Mirror of {@link dispatchMaterializedViews} for the delete path.\n * No record content is available (it's gone), so the\n * `_materializedFrom` skip used by the put-side dispatch doesn't\n * apply here — instead, the recursion guard is the `internal` gate\n * at the `_doDelete` call site above.\n *\n * @internal\n */\n private async dispatchMaterializedViewsOnDelete(id: string): Promise<void> {\n void id\n if (this.materializedViewSource === undefined) return\n const registry = this.materializedViewSource.registry()\n const mvs = registry.mvsForSource(this.name)\n if (mvs.length === 0) return\n let executor: typeof MVExecutorType | null = null\n let staleHelpers: typeof MVStaleModule | null = null\n for (const reg of mvs) {\n const mode = reg.spec.refresh\n if (mode === 'eager') {\n if (executor === null) {\n ;({ MaterializedViewExecutor: executor } = await import('./materialized-views/executor.js'))\n }\n await executor.refresh(reg, {\n getCollection: (name) => this.materializedViewSource!.getCollection(name),\n getActiveTxContext: () => this.materializedViewSource!.getActiveTxContext(),\n getQueryContext: () => this.materializedViewSource!.getQueryContext(),\n })\n } else if (mode === 'lazy') {\n if (staleHelpers === null) {\n staleHelpers = await import('./materialized-views/stale.js')\n }\n staleHelpers.markMVStale(registry, reg.spec.name)\n }\n // manual: no-op — `vault.refreshView(name)` is the only path.\n }\n }\n\n /**\n * List all records in the collection.\n *\n * Throws in lazy mode — bulk listing defeats the purpose of lazy\n * hydration. Use `scan()` to iterate over the full collection\n * page-by-page without holding more than `pageSize` records in memory.\n *\n * @param locale Optional locale options. When provided,\n * each record is locale-resolved before being returned.\n */\n async list(locale?: LocaleReadOptions): Promise<T[]> {\n if (this.lazy) {\n throw new Error(\n `Collection \"${this.name}\": list() is not available in lazy mode (prefetch: false). ` +\n `Use collection.scan({ pageSize }) to iterate over the full collection.`,\n )\n }\n // Lazy-MV resolve-on-read: if this collection is the\n // output of a registered lazy MV with a pending stale flag, run\n // the executor before returning so callers see fresh data. No-op\n // when nothing is pending — keeps the read path negligible.\n if (this.materializedViewSource !== undefined) {\n const { resolveStaleMVOnRead } = await import('./materialized-views/stale.js')\n await resolveStaleMVOnRead(this.materializedViewSource, this.name)\n }\n await this.ensureHydrated()\n const records = [...this.cache.values()].map(e => e.record)\n // #322 — money decode (stored scaled-int → canonical decimal) must run\n // even with no locale, so list() matches get(). applyLocaleToRecord\n // decodes money regardless of locale and only resolves i18n/dict virtuals\n // when a locale is active. Keep the no-transform fast path.\n if (!this.hasReadTransforms()) return records\n return Promise.all(records.map(r => this.applyLocaleToRecord(r, locale)))\n }\n\n /**\n * @internal — whether any read-side record transform is registered\n * (money decode, i18nText resolution, dictKey labels). Gates the\n * no-transform fast path in {@link list}.\n */\n private hasReadTransforms(): boolean {\n return (\n (this.moneyFields !== undefined && Object.keys(this.moneyFields).length > 0) ||\n (this.i18nFields !== undefined && Object.keys(this.i18nFields).length > 0) ||\n (this.dictKeyFields !== undefined && Object.keys(this.dictKeyFields).length > 0)\n )\n }\n\n // ─── Bulk operations ─────────────────────────────────────\n\n /**\n * Put many records in one call. Each item is processed sequentially\n * through the normal `put()` path — meaning per-item validation,\n * history snapshots, ledger appends, and change events all still\n * fire. The round-trip saving comes from the adapter staying hot\n * across the batch (no connection re-open, no keyring re-unlock).\n *\n * ## Semantics\n *\n * **Best-effort with per-item results.** If item 5 of 10 fails, items\n * 1–4 are already persisted and items 6–10 are still attempted.\n * The returned {@link PutManyResult} lists every success and failure\n * individually so the caller can decide whether to roll forward\n * (retry the failures) or roll back (manually delete the successes).\n *\n * **True tx-atomic putMany** — pass `{ atomic: true }` to switch\n * to the transaction executor: pre-flight CAS against every\n * item's `expectedVersion`, then commit all ops with best-effort\n * revert on mid-batch failure. Atomic mode throws on failure rather\n * than returning a mixed-results object.\n *\n * ## Change events\n *\n * One `change` event per successfully-written record, same as N\n * single-record puts. Subscribers don't need to special-case bulk.\n */\n async putMany(\n entries: ReadonlyArray<readonly [id: string, record: T, opts?: PutManyItemOptions]>,\n options?: PutManyOptions,\n ): Promise<PutManyResult> {\n if (options?.atomic) {\n return this.putManyAtomic(entries)\n }\n const success: string[] = []\n const failures: Array<{ id: string; error: Error }> = []\n for (const entry of entries) {\n const [id, record] = entry\n try {\n await this.put(id, record)\n success.push(id)\n } catch (error) {\n failures.push({ id, error: error as Error })\n }\n }\n return { ok: failures.length === 0, success, failures }\n }\n\n /**\n * Atomic-mode implementation of {@link putMany}. Pre-flights every\n * `expectedVersion`, executes all puts in declaration order, and\n * reverts executed ops via the raw adapter on mid-batch failure.\n * See `runTransaction` for the shared semantics + crash-window caveat.\n *\n * @internal\n */\n private async putManyAtomic(\n entries: ReadonlyArray<readonly [id: string, record: T, opts?: PutManyItemOptions]>,\n ): Promise<PutManyResult> {\n // Phase 1 — pre-flight CAS + prior-envelope snapshot for revert.\n const priors = new Map<string, EncryptedEnvelope | null>()\n for (const [id, , opts] of entries) {\n if (!priors.has(id)) {\n priors.set(id, await this.adapter.get(this.vault, this.name, id))\n }\n if (opts?.expectedVersion !== undefined) {\n const env = priors.get(id) ?? null\n const actual = env?._v ?? 0\n if (actual !== opts.expectedVersion) {\n throw new ConflictError(\n actual,\n `putMany atomic: ${this.vault}/${this.name}/${id} ` +\n `expected v${opts.expectedVersion}, found v${actual}`,\n )\n }\n }\n }\n // Phase 2 — execute; revert on failure.\n //\n // When a derivation registry is wired, publish a transient\n // TxContext for the duration of this loop so `dispatchDerivations`\n // can register recursive derived-output writes onto `ctx._executed`.\n // The shared `revertExecuted` helper then unwinds the combined list\n // (source ops + side-effect ops) in reverse, matching the\n // `runTransaction` rollback semantics. When no derivation registry\n // is configured, we still build a local `executed` list and revert\n // it via `revertExecuted` — keeps a single code path.\n const txCtx = this.derivationSource?.createTxContext() ?? null\n if (txCtx !== null && this.derivationSource) {\n this.derivationSource.setActiveTxContext(txCtx)\n }\n const localExecuted: ExecutedOp[] = []\n try {\n for (const [id, record] of entries) {\n // Record the revert plan BEFORE the call so a mid-`put` throw\n // (e.g. strict derivation failure firing after `store.put`\n // already committed the source envelope) still has the source\n // write reverted. Mirrors `runTransaction`'s Phase 2 pattern.\n const entry: ExecutedOp = {\n op: { type: 'put', vaultName: this.vault, collectionName: this.name, id },\n priorEnvelope: priors.get(id) ?? null,\n }\n if (txCtx !== null) txCtx._executed.push(entry)\n else localExecuted.push(entry)\n await this.put(id, record)\n }\n return { ok: true, success: entries.map(([id]) => id), failures: [] }\n } catch (err) {\n const executedForRevert = txCtx !== null ? txCtx._executed : localExecuted\n // Restore prior envelopes via the raw store. Same helper as\n // `runTransaction` for symmetric semantics — walks in reverse,\n // best-effort on each restore.\n await revertExecuted(executedForRevert, this.adapter)\n // Cache desync guard. `revertExecuted` only invalidates caches\n // when given a `Noydb` reference (which we don't have here\n // without widening the constructor surface). Walk the executed\n // ops and invalidate caches via the source collection (this)\n // for entries that target this collection, and via\n // `derivationSource.getCollection(name)` for nested derived\n // outputs that live in sibling collections — otherwise an eager\n // cache on a derived-output collection still serves the\n // rolled-back record.\n for (const { op } of [...executedForRevert].reverse()) {\n if (op.vaultName !== this.vault) continue\n try {\n if (op.collectionName === this.name) {\n await this._invalidateCacheEntry(op.id)\n } else if (this.derivationSource) {\n const sibling = this.derivationSource.getCollection(op.collectionName)\n await sibling._invalidateCacheEntry(op.id)\n }\n } catch { /* best-effort */ }\n }\n throw err\n } finally {\n if (txCtx !== null && this.derivationSource) {\n this.derivationSource.clearActiveTxContext(txCtx)\n }\n }\n }\n\n /**\n * Get many records in one call. Returns a `Map<id, T | null>` —\n * missing records surface as `null` entries so the caller can\n * distinguish \"not found\" from \"lookup failed\". Order-stable\n * iteration (Map preserves insertion order = input `ids` order).\n *\n * Reads go through the per-id `get()` path, which means the cache\n * / hydration logic stays consistent with single-record reads.\n */\n async getMany(ids: readonly string[]): Promise<Map<string, T | null>> {\n const result = new Map<string, T | null>()\n for (const id of ids) {\n result.set(id, await this.get(id))\n }\n return result\n }\n\n /**\n * Delete many records in one call. Same best-effort contract as\n * {@link putMany}: if item 5 fails, items 1–4 are already deleted\n * and items 6–10 are still attempted.\n *\n * Deleting a non-existent id is not a failure — matches the\n * idempotent semantics of single-record `delete()`.\n */\n async deleteMany(ids: readonly string[]): Promise<DeleteManyResult> {\n const success: string[] = []\n const failures: Array<{ id: string; error: Error }> = []\n for (const id of ids) {\n try {\n await this.delete(id)\n success.push(id)\n } catch (error) {\n failures.push({ id, error: error as Error })\n }\n }\n return { ok: failures.length === 0, success, failures }\n }\n\n /**\n * Build a chainable query against the collection. Returns a `Query<T>`\n * builder when called with no arguments.\n *\n * Backward-compatible overload: passing a predicate function returns\n * the filtered records directly (the API). Prefer the chainable\n * form for new code.\n *\n * **Lazy-MV gap:** `query()` is synchronous and does NOT\n * trigger lazy materialized-view resolve-on-read. If this\n * collection is a lazy MV's output and the MV is currently stale,\n * `query().toArray()` returns the pre-stale snapshot. To force a\n * fresh read on a lazy MV, either call `list()` (which DOES\n * trigger resolve) or `vault.refreshView(mvName)` before querying.\n * The proper fix — extending `QuerySource` with an async prepare\n * hook — is a separate PR.\n *\n * @example\n * ```ts\n * // New chainable API:\n * const overdue = invoices.query()\n * .where('status', '==', 'open')\n * .where('dueDate', '<', new Date())\n * .orderBy('dueDate')\n * .toArray();\n *\n * // Legacy predicate form (still supported):\n * const drafts = invoices.query(i => i.status === 'draft');\n * ```\n */\n query(): Query<T>\n query(predicate: (record: T) => boolean): T[]\n query(predicate?: (record: T) => boolean): Query<T> | T[] {\n if (this.lazy) {\n throw new Error(\n `Collection \"${this.name}\": query() is not available in lazy mode (prefetch: false). ` +\n `Use collection.lazyQuery() for indexed reads, or collection.scan({ pageSize }) ` +\n `and filter the streamed records with a regular for-await loop.`,\n )\n }\n if (predicate !== undefined) {\n // Legacy form: synchronous predicate filter against the cache.\n return [...this.cache.values()].map(e => e.record).filter(predicate)\n }\n // New form: return a chainable builder bound to this collection's cache.\n const source: QuerySource<T> = {\n snapshot: () => [...this.cache.values()].map(e => e.record),\n subscribe: (cb: () => void) => {\n const handler = (event: ChangeEvent): void => {\n if (event.vault === this.vault && event.collection === this.name) {\n cb()\n }\n }\n this.emitter.on('change', handler)\n return () => this.emitter.off('change', handler)\n },\n // Index-aware fast path for `==` and `in` operators on indexed\n // fields. The Query builder consults these when present and falls\n // back to a linear scan otherwise.\n getIndexes: () => this.getIndexes(),\n lookupById: (id: string) => this.cache.get(id)?.record,\n ...(this.moneyFields ? { moneyFields: this.moneyFields } : {}),\n }\n // Build a JoinContext if the vault passed a join resolver.\n // Without one, .join() on the resulting Query will throw with an\n // actionable error — the case is unreachable in production but\n // matters for unit tests that construct Collection directly.\n const resolver = this.joinResolver\n const leftCollection = this.name\n const joinContext: JoinContext | undefined = resolver\n ? {\n leftCollection,\n resolveRef: (field: string) => resolver.resolveRef(leftCollection, field),\n resolveSource: (collectionName: string) => resolver.resolveSource(collectionName),\n ...(resolver.resolveDictSource\n ? { resolveDictSource: (field: string) => resolver.resolveDictSource!(leftCollection, field) }\n : {}),\n }\n : undefined\n return new Query<T>(source, undefined, joinContext, this.aggregateStrategy)\n }\n\n /**\n * Subscribe to every put/delete on this collection. Returns an\n * unsubscribe function.\n *\n * Fires **after** the store write has committed — subscribers see\n * only materialised state, never in-flight or rolled-back writes.\n *\n * This is an event stream, not a reactive value. For reactive\n * \"current array state\" semantics use `query().live()`. Typical\n * use cases for `subscribe()`:\n * - audit-trail / activity-feed UI that lists events as they happen\n * - Pinia-per-collection wiring where each store subscribes once\n * - outbox-style workers that process every new record\n *\n * The callback receives a `CollectionChangeEvent<T>`:\n * - `{ type: 'put', id, record }` — record is the current\n * decrypted value. May be `null` if another op deleted the\n * record between the emit and the handler firing (rare race).\n * - `{ type: 'delete', id, record: null }` — deletion event;\n * the record content is gone by the time the handler runs.\n *\n * The callback is invoked synchronously *with respect to the emit\n * moment*, but the record lookup is async (cache hit for eager\n * collections; one `get()` for lazy collections). If your handler\n * does not need the record, cast it away and ignore — the lookup\n * is still performed, but it's cheap on the hydrated path.\n *\n * ergonomic wrapper over `db.on('change', …)` that\n * filters to this collection and hydrates the record.\n */\n subscribe(cb: (event: CollectionChangeEvent<T>) => void): () => void {\n const handler = (event: ChangeEvent): void => {\n if (event.vault !== this.vault || event.collection !== this.name) return\n if (event.action === 'put') {\n // Cache hit in eager mode; get() in lazy mode.\n void this.get(event.id).then(record => {\n cb({ type: 'put', id: event.id, record: record ?? null })\n }).catch(() => {\n // Record vanished between emit + lookup (race). Emit with null\n // so subscribers still see the event they were promised.\n cb({ type: 'put', id: event.id, record: null })\n })\n } else {\n // delete\n cb({ type: 'delete', id: event.id, record: null })\n }\n }\n this.emitter.on('change', handler)\n return () => {\n this.emitter.off('change', handler)\n }\n }\n\n /**\n * Return a minimal JoinableSource view of this collection's\n * in-memory cache. Used by the Vault's `resolveSource`\n * method when another collection's `.join()` needs to probe this\n * one as the right side.\n *\n * The returned object captures the cache reference through a\n * closure, so subsequent mutations to the cache are visible to\n * the joined query. That's intentional: a join that fires after\n * the right-side collection has been updated should see the\n * fresh data.\n *\n * Throws in lazy mode because the cache is bounded and could\n * silently miss records — consistent with the `query()` /\n * `list()` lazy-mode policy. If this becomes a blocker for a\n * real consumer, the fix is to add an async `scan()`-backed\n * variant of this method, which is exactly what streaming\n * joins will need anyway.\n */\n querySourceForJoin(): JoinableSource {\n if (this.lazy) {\n throw new Error(\n `Collection \"${this.name}\": .join() cannot use a lazy-mode ` +\n `collection as the right side. Opening it in eager mode ` +\n `(prefetch: true, default) makes it joinable. Streaming joins ` +\n `over lazy collections are not yet supported.`,\n )\n }\n // Structural source — the join executor calls snapshot() and\n // lookupById(); the live-join executor additionally calls\n // subscribe() so right-side mutations propagate. We capture\n // `this.cache` and `this.emitter` by closure so later mutations\n // are visible to the snapshot view AND drive live re-fires.\n return {\n snapshot: () => [...this.cache.values()].map(e => e.record),\n lookupById: (id: string) => this.cache.get(id)?.record,\n subscribe: (cb: () => void) => {\n const handler = (event: ChangeEvent): void => {\n if (event.vault === this.vault && event.collection === this.name) {\n cb()\n }\n }\n this.emitter.on('change', handler)\n return () => this.emitter.off('change', handler)\n },\n }\n }\n\n /**\n * Cache statistics — useful for devtools, monitoring, and verifying\n * that LRU eviction is happening as expected in lazy mode.\n *\n * In eager mode, returns size only (no hits/misses are tracked because\n * every read is a cache hit by construction). In lazy mode, returns\n * the full LRU stats: `{ hits, misses, evictions, size, bytes }`.\n */\n cacheStats(): CacheStats {\n if (this.lazy && this.lru) {\n return { ...this.lru.stats(), lazy: true }\n }\n return {\n hits: 0,\n misses: 0,\n evictions: 0,\n size: this.cache.size,\n bytes: 0,\n lazy: false,\n }\n }\n\n // ─── History Methods ────────────────────────────────────────────\n\n /** Get version history for a record, newest first. */\n async history(id: string, options?: HistoryOptions): Promise<HistoryEntry<T>[]> {\n const envelopes = await this.historyStrategy.getHistoryEntries(\n this.adapter, this.vault, this.name, id, options,\n )\n\n const entries: HistoryEntry<T>[] = []\n for (const env of envelopes) {\n // History reads skip schema validation — see getVersion() docs.\n const record = await this.decryptRecord(env, { skipValidation: true })\n // Shredded (tombstoned) history version: the body is permanently gone,\n // so there is nothing to return — skip it. The version still counted in\n // the audit ledger; history() just can't surface its erased content.\n if (record === null) continue\n entries.push({\n version: env._v,\n timestamp: env._ts,\n userId: env._by ?? '',\n record,\n })\n }\n return entries\n }\n\n /**\n * Get a specific past version of a record.\n *\n * History reads intentionally **skip schema validation** — historical\n * records predate the current schema by definition, so validating them\n * against today's shape would be a false positive on any schema\n * evolution. If a caller needs validated history, they should filter\n * and re-put the records through the normal `put()` path.\n */\n async getVersion(id: string, version: number): Promise<T | null> {\n const envelope = await this.historyStrategy.getVersionEnvelope(\n this.adapter, this.vault, this.name, id, version,\n )\n if (!envelope) return null\n return this.decryptRecord(envelope, { skipValidation: true })\n }\n\n /** Revert a record to a past version. Creates a new version with the old content. */\n async revert(id: string, version: number): Promise<void> {\n const oldRecord = await this.getVersion(id, version)\n if (!oldRecord) {\n throw new Error(`Version ${version} not found for record \"${id}\"`)\n }\n await this.put(id, oldRecord)\n }\n\n /**\n * Compare two versions of a record and return the differences.\n * Use version 0 to represent \"before creation\" (empty).\n * Omit versionB to compare against the current version.\n */\n async diff(id: string, versionA: number, versionB?: number): Promise<DiffEntry[]> {\n const recordA = versionA === 0 ? null : await this.resolveVersion(id, versionA)\n const recordB = versionB === undefined || versionB === 0\n ? (versionB === 0 ? null : await this.resolveCurrentOrVersion(id))\n : await this.resolveVersion(id, versionB)\n return this.historyStrategy.diff(recordA, recordB)\n }\n\n /** Resolve a version: try history first, then check if it's the current version. */\n private async resolveVersion(id: string, version: number): Promise<T | null> {\n // Check history\n const fromHistory = await this.getVersion(id, version)\n if (fromHistory) return fromHistory\n // Check if it's the current live version\n await this.ensureHydrated()\n const current = this.cache.get(id)\n if (current && current.version === version) return current.record\n return null\n }\n\n private async resolveCurrentOrVersion(id: string): Promise<T | null> {\n await this.ensureHydrated()\n return this.cache.get(id)?.record ?? null\n }\n\n /** Prune history entries for a record (or all records if id is undefined). */\n async pruneRecordHistory(id: string | undefined, options: PruneOptions): Promise<number> {\n const pruned = await this.historyStrategy.pruneHistory(\n this.adapter, this.vault, this.name, id, options,\n )\n if (pruned > 0) {\n this.emitter.emit('history:prune', {\n vault: this.vault,\n collection: this.name,\n id: id ?? '*',\n pruned,\n })\n }\n return pruned\n }\n\n /** Clear all history for this collection (or a specific record). */\n async clearHistory(id?: string): Promise<number> {\n return this.historyStrategy.clearHistory(this.adapter, this.vault, this.name, id)\n }\n\n // ─── Core Methods ─────────────────────────────────────────────\n\n /**\n * Count records in the collection.\n *\n * In eager mode this returns the in-memory cache size (instant). In\n * lazy mode it asks the adapter via `list()` to enumerate ids — slower\n * but still correct, and avoids loading any record bodies into memory.\n */\n async count(): Promise<number> {\n if (this.lazy) {\n const ids = await this.adapter.list(this.vault, this.name)\n return ids.length\n }\n await this.ensureHydrated()\n return this.cache.size\n }\n\n // ─── Pagination & Streaming ───────────────────────────────────\n\n /**\n * Fetch a single page of records via the adapter's optional `listPage`\n * extension. Returns the decrypted records for this page plus an opaque\n * cursor for the next page.\n *\n * Pass `cursor: undefined` (or omit it) to start from the beginning.\n * The final page returns `nextCursor: null`.\n *\n * If the adapter does NOT implement `listPage`, this falls back to a\n * synthetic implementation: it loads all ids via `list()`, sorts them,\n * and slices a window. The first call emits a one-time console.warn so\n * developers can spot adapters that should opt into the fast path.\n */\n async listPage(opts: { cursor?: string; limit?: number } = {}): Promise<{\n items: T[]\n nextCursor: string | null\n }> {\n const limit = opts.limit ?? 100\n\n if (this.adapter.listPage) {\n const result = await this.adapter.listPage(this.vault, this.name, opts.cursor, limit)\n const decrypted: T[] = []\n for (const { record, version, id } of await this.decryptPage(result.items)) {\n // Update cache opportunistically — if the page-fetched record isn't\n // in cache yet, populate it. This makes a subsequent .get(id) free.\n // In LAZY mode we deliberately do NOT populate the LRU here:\n // streaming a 100K-record collection should not turn the LRU into\n // a giant write-once buffer that immediately evicts everything.\n // Random-access workloads via .get() are what the LRU is for.\n if (!this.lazy && !this.cache.has(id)) {\n this.cache.set(id, { record, version })\n }\n decrypted.push(record)\n }\n return { items: decrypted, nextCursor: result.nextCursor }\n }\n\n // Fallback: synthetic pagination over list() + get(). Slower than the\n // native path because every id requires its own round-trip, but\n // correct for adapters that haven't opted in.\n warnOnceFallback(this.adapter.name ?? 'unknown')\n const ids = (await this.adapter.list(this.vault, this.name)).slice().sort()\n const start = opts.cursor ? parseInt(opts.cursor, 10) : 0\n const end = Math.min(start + limit, ids.length)\n const items: T[] = []\n for (let i = start; i < end; i++) {\n const id = ids[i]!\n const envelope = await this.adapter.get(this.vault, this.name, id)\n if (envelope) {\n const record = await this.decryptRecord(envelope)\n if (record === null) continue // shredded (tombstone) — skip\n items.push(record)\n // Same lazy-mode skip as the native path: don't pollute the LRU\n // with sequential scan results.\n if (!this.lazy && !this.cache.has(id)) {\n this.cache.set(id, { record, version: envelope._v })\n }\n }\n }\n return {\n items,\n nextCursor: end < ids.length ? String(end) : null,\n }\n }\n\n /**\n * Stream every record in the collection page-by-page as an async\n * iterable, with chainable `.where()` / `.filter()` clauses and a\n * memory-bounded `.aggregate(spec)` terminal.\n *\n * The whole point: process collections larger than RAM without\n * ever holding more than `pageSize` records decrypted at once.\n *\n * @example\n * ```ts\n * // Backward-compatible iteration — unchanged from the previous\n * // async-generator shape. `ScanBuilder` implements AsyncIterable.\n * for await (const record of invoices.scan({ pageSize: 500 })) {\n * await processOne(record)\n * }\n *\n * // — streaming aggregation with O(reducers) memory.\n * const { total, n } = await invoices.scan()\n * .where('year', '==', 2025)\n * .aggregate({ total: sum('amount'), n: count() })\n * ```\n *\n * **Lazy-MV gap:** `scan()` is synchronous-build and does\n * NOT trigger lazy materialized-view resolve-on-read. For lazy\n * MVs, call `list()` (which DOES resolve) or `vault.refreshView(name)`\n * before scanning. Same shape as the `query()` limitation.\n *\n * Returns a `ScanBuilder<T>` instead of the raw async iterator\n * that previous versions used. The builder implements\n * `AsyncIterable<T>`, so every existing `for await … of` call\n * continues to work unchanged. Direct `.next()` calls on the\n * iterator — not idiomatic, not used in the codebase — are no\n * longer supported; upgrade to `for await` or call the new\n * `.aggregate()` terminal.\n *\n * Uses `adapter.listPage` when available; otherwise falls back\n * to the synthetic pagination path with the same one-time\n * warning (`listPage()` routes through that fallback internally).\n */\n scan(opts: { pageSize?: number } = {}): ScanBuilder<T> {\n const pageSize = opts.pageSize ?? 100\n // Build a JoinContext if the vault passed a join resolver\n // — same machinery as `query()`. Without one, `.join()`\n // on the resulting ScanBuilder will throw with an actionable\n // error. The resolver is unreachable in production but matters\n // for unit tests that construct Collection directly.\n const resolver = this.joinResolver\n const leftCollection = this.name\n const joinContext: JoinContext | undefined = resolver\n ? {\n leftCollection,\n resolveRef: (field: string) => resolver.resolveRef(leftCollection, field),\n resolveSource: (collectionName: string) => resolver.resolveSource(collectionName),\n ...(resolver.resolveDictSource\n ? { resolveDictSource: (field: string) => resolver.resolveDictSource!(leftCollection, field) }\n : {}),\n }\n : undefined\n // The page provider closure is bound to this collection's\n // listPage method so the builder is free of any `this`\n // coupling. Rebinding through the arrow keeps the unbound-\n // method lint rule happy — matches the pattern used in\n // builder.ts's candidateRecords helper.\n return new ScanBuilder<T>(\n {\n listPage: (listOpts) => this.listPage(listOpts),\n },\n pageSize,\n [],\n [],\n joinContext,\n this.moneyFields,\n )\n }\n\n /** Decrypt a page of envelopes returned by `adapter.listPage`. */\n private async decryptPage(\n items: ListPageResult['items'],\n ): Promise<Array<{ id: string; record: T; version: number }>> {\n const out: Array<{ id: string; record: T; version: number }> = []\n for (const { id, envelope } of items) {\n const record = await this.decryptRecord(envelope)\n if (record === null) continue // shredded (tombstone) — skip the page row\n out.push({ id, record, version: envelope._v })\n }\n return out\n }\n\n // ─── Internal ──────────────────────────────────────────────────\n\n /** Load all records from adapter into memory cache. */\n /**\n * @internal — refresh the in-memory cache entry for a single id by\n * re-reading from the adapter. Used by the transaction executor's\n * Phase-3 revert path: that path writes the prior envelope directly\n * via the raw store (to avoid re-firing Collection-level side\n * effects), which would otherwise leave this Collection's eager\n * cache holding the rolled-back value. After revert, the executor\n * calls this hook so subsequent `get` / `query` reads see the\n * actual on-disk state.\n *\n * Lazy mode: drops the LRU entry; the next `get` repopulates from\n * the adapter. Eager mode: re-reads the envelope and either sets\n * the cache entry (record still present) or deletes it (record was\n * gone before the tx and the revert deleted it again).\n */\n /**\n * @internal — evict ONLY the per-record CEK cache entry for `id`. Used by\n * `vault.rotateRecordCek()`: after a hard CEK rotation the cached unwrapped\n * CEK is stale (it would decrypt the pre-rotation body and fail GCM auth on\n * the post-rotation body). Eviction must be synchronous with the live-envelope\n * rewrite so no concurrent read observes the old CEK. Paired with\n * {@link _invalidateCacheEntry} (which refreshes the decrypted-record cache).\n * No-op when the collection is not `perRecordKeys`.\n */\n _invalidateCekCacheEntry(id: string): void {\n this.cekCache?.remove(id)\n }\n\n async _invalidateCacheEntry(id: string): Promise<void> {\n if (this.lazy && this.lru) {\n this.lru.remove(id)\n return\n }\n if (!this.hydrated) return\n const previous = this.cache.get(id)\n const envelope = await this.adapter.get(this.vault, this.name, id)\n if (!envelope) {\n this.cache.delete(id)\n if (previous) {\n this.indexes?.remove(id, previous.record)\n this.uniqueConstraints?.remove(id, previous.record)\n }\n return\n }\n const record = await this.decryptRecord(envelope)\n if (record === null) {\n // The on-disk envelope is now a tombstone (shredded). Treat exactly\n // like a deleted record: drop the cache entry and its index rows.\n this.cache.delete(id)\n if (previous) {\n this.indexes?.remove(id, previous.record)\n this.uniqueConstraints?.remove(id, previous.record)\n }\n return\n }\n this.cache.set(id, { record, version: envelope._v })\n this.indexes?.upsert(id, record, previous ? previous.record : null)\n this.uniqueConstraints?.upsert(id, record, previous?.record)\n }\n\n /**\n * Apply a peer tab's committed write to THIS tab's in-memory view:\n * re-read the (already-persisted) envelope from the shared store + refresh\n * cache/indexes, then emit a `change` event so reactive consumers re-render.\n * Never writes to the store and never fires write hooks, so it cannot loop.\n */\n async _applyRemoteChange(id: string, action: 'put' | 'delete'): Promise<void> {\n await this._invalidateCacheEntry(id)\n this.emitter.emit('change', { vault: this.vault, collection: this.name, id, action })\n }\n\n /** @internal — the current in-memory record without a store read (for conflict capture). */\n _peekCached(id: string): T | null {\n const entry = this.lazy && this.lru ? this.lru.get(id) : this.cache.get(id)\n return entry ? entry.record : null\n }\n\n private async ensureHydrated(): Promise<void> {\n if (this.hydrated) return\n\n const ids = await this.adapter.list(this.vault, this.name)\n for (const id of ids) {\n const envelope = await this.adapter.get(this.vault, this.name, id)\n if (envelope && !isTombstone(envelope, this.encrypted)) {\n const record = await this.decryptRecord(envelope, { id })\n if (record === null) continue\n this.cache.set(id, { record, version: envelope._v })\n }\n }\n this.hydrated = true\n this.rebuildEagerIndexesFromCache()\n this.rebuildUniqueConstraintsFromCache()\n }\n\n /** Hydrate from a pre-loaded snapshot (used by Vault). */\n async hydrateFromSnapshot(records: Record<string, EncryptedEnvelope>): Promise<void> {\n for (const [id, envelope] of Object.entries(records)) {\n if (isTombstone(envelope, this.encrypted)) continue\n const record = await this.decryptRecord(envelope, { id })\n if (record === null) continue\n this.cache.set(id, { record, version: envelope._v })\n }\n this.hydrated = true\n this.rebuildEagerIndexesFromCache()\n this.rebuildUniqueConstraintsFromCache()\n }\n\n /**\n * Rebuild secondary indexes from the current in-memory cache.\n *\n * Called after any bulk hydration. Incremental put/delete updates\n * are handled by `indexes.upsert()` / `indexes.remove()` directly,\n * so this only fires for full reloads.\n *\n * Synchronous and O(N × indexes.size); for the target scale of\n * 1K–50K records this completes in single-digit milliseconds.\n */\n private rebuildEagerIndexesFromCache(): void {\n const eager = this.indexes\n if (!eager || eager.fields().length === 0) return\n const snapshot: Array<{ id: string; record: T }> = []\n for (const [id, entry] of this.cache) {\n snapshot.push({ id, record: entry.record })\n }\n eager.build(snapshot)\n }\n\n /**\n * Rebuild unique-constraint maps from the current in-memory cache.\n * Called after any bulk hydration alongside `rebuildEagerIndexesFromCache`.\n */\n private rebuildUniqueConstraintsFromCache(): void {\n if (!this.uniqueConstraints) return\n this.uniqueConstraints.build(\n (function* (cache: Map<string, { record: T }>) {\n for (const [id, entry] of cache) yield [id, entry.record] as const\n })(this.cache),\n )\n }\n\n /**\n * Rebuild every declared index from scratch.\n *\n * Eager mode: refreshes the in-memory `CollectionIndexes` from the\n * current cache — O(records × declaredFields).\n *\n * Lazy mode: tears down every `_idx/<field>/<recordId>`\n * side-car, walks the canonical record namespace, and materialises\n * fresh side-cars for every declared field. The in-memory mirror is\n * cleared and re-ingested. Intended for two scenarios:\n * 1. Adding a new indexed field to a collection that already holds\n * records — after the schema change, call `rebuildIndexes()` to\n * backfill the side-cars.\n * 2. Recovery from a catastrophic drift (audit noticed many\n * `index:write-partial` events, operator wants a clean slate).\n *\n * The rebuild is NOT incremental — it's a full bulk-replace. For\n * per-field drift repair, use `reconcileIndex(field)` instead.\n */\n async rebuildIndexes(): Promise<void> {\n if (!this.lazy) {\n await this.ensureHydrated()\n this.rebuildEagerIndexesFromCache()\n return\n }\n\n const persisted = this.persistedIndexes\n if (!persisted) return\n const fields = persisted.fields()\n if (fields.length === 0) return\n\n // 1. Collect canonical ids (skip every reserved-namespace id —\n // `_idx/`, `_keyring`, `_history/`, `_ledger_deltas/`, `_meta/`,\n // `_ledger`, `_blob_`, etc. User records may not start with `_`\n // per the monorepo convention used across the hub).\n const allIds = await this.adapter.list(this.vault, this.name)\n const canonicalIds: string[] = []\n const staleIdxIds: string[] = []\n for (const id of allIds) {\n if (decodeIdxId(id)) {\n staleIdxIds.push(id)\n } else if (!id.startsWith('_')) {\n canonicalIds.push(id)\n }\n }\n\n // 2. Drop every existing side-car. Errors here are tolerated — the\n // next step overwrites any remnants. If a side-car is for a\n // field that is no longer declared, the delete still removes\n // the stale row from storage.\n for (const id of staleIdxIds) {\n try { await this.adapter.delete(this.vault, this.name, id) } catch { /* ignore */ }\n }\n persisted.clear()\n\n // 3. Walk records and write fresh side-cars for every declared field.\n for (const recordId of canonicalIds) {\n const envelope = await this.adapter.get(this.vault, this.name, recordId)\n if (!envelope) continue\n const record = await this.decryptRecord(envelope, { skipValidation: true })\n if (record === null) continue // shredded (tombstone) — no side-car to build\n await this.maintainPersistedIndexesOnPut(recordId, record, null, envelope._v)\n }\n\n this.persistedIndexesLoaded = true\n }\n\n /**\n * Compare the persisted `_idx/<field>/*` side-cars against the\n * canonical records for a single field, reporting the drift (and\n * optionally repairing it).\n *\n * Lazy mode only. Eager mode throws — the in-memory index cannot\n * drift.\n *\n * `missing` — record ids whose value is indexable but no side-car\n * exists. Happens when a `put()` succeeded but the side-car put\n * failed (surfaced as `index:write-partial`).\n * `stale` — side-car ids pointing to a record that no longer exists\n * or whose current value no longer matches the side-car body.\n * `applied` — number of writes that were actually applied (always 0\n * when `dryRun: true`).\n *\n * Design reference: acceptance criteria.\n */\n async reconcileIndex(\n field: string,\n opts: { dryRun?: boolean } = {},\n ): Promise<{ field: string; missing: string[]; stale: string[]; applied: number }> {\n if (!this.lazy) {\n throw new Error(\n `Collection \"${this.name}\": reconcileIndex is only meaningful in lazy mode ` +\n `(prefetch: false). Eager mode maintains indexes in memory with no drift.`,\n )\n }\n const persisted = this.persistedIndexes\n if (!persisted) {\n throw new Error(\n `Collection \"${this.name}\": indexing is disabled on this Noydb instance. ` +\n `Pass \\`withIndexing()\\` from \"@noy-db/hub/indexing\" to \\`createNoydb({ indexStrategy })\\`.`,\n )\n }\n if (!persisted.has(field)) {\n throw new Error(\n `Collection \"${this.name}\": field \"${field}\" is not declared in indexes. ` +\n `Declare it in the collection options before reconciling.`,\n )\n }\n\n const dryRun = opts.dryRun === true\n const allIds = await this.adapter.list(this.vault, this.name)\n\n // Map side-car recordId → stored value (if readable). Also capture\n // \"stale\" side-cars whose field matches but whose record is gone.\n const sidecar = new Map<string, unknown>()\n const sidecarIds = new Map<string, string>() // recordId -> sidecar id\n for (const id of allIds) {\n const decoded = decodeIdxId(id)\n if (!decoded || decoded.field !== field) continue\n sidecarIds.set(decoded.recordId, id)\n const env = await this.adapter.get(this.vault, this.name, id)\n if (!env) continue\n try {\n const sidecarJson = await this.decryptJsonString(env)\n if (sidecarJson === null) {\n // Tombstone side-car (shredded) — treat as stale so it's rewritten.\n sidecar.set(decoded.recordId, undefined)\n } else {\n const body = JSON.parse(sidecarJson) as { value: unknown }\n sidecar.set(decoded.recordId, body.value)\n }\n } catch {\n // Unreadable — treat as stale so it gets rewritten.\n sidecar.set(decoded.recordId, undefined)\n }\n }\n\n // Walk canonical records and compare against side-car state.\n const missing: string[] = []\n const stale: string[] = []\n const fixesPut: Array<{ recordId: string; record: T; version: number }> = []\n for (const id of allIds) {\n if (decodeIdxId(id)) continue\n if (id.startsWith('_')) continue\n const env = await this.adapter.get(this.vault, this.name, id)\n if (!env) continue\n const record = await this.decryptRecord(env, { skipValidation: true })\n // Shredded (tombstone) canonical record: treat like a vanished record —\n // leave its `id` in `sidecarIds` so any lingering side-car is marked\n // stale (and deleted) by the leftover loop below.\n if (record === null) continue\n const live = readPersistedValue(record as unknown as Record<string, unknown>, field)\n const stored = sidecar.get(id)\n const hasSidecar = sidecarIds.has(id)\n const indexable = live !== null && live !== undefined\n\n if (indexable && !hasSidecar) {\n missing.push(id)\n fixesPut.push({ recordId: id, record, version: env._v })\n } else if (indexable && hasSidecar && !valuesMatch(stored, live)) {\n // Side-car body drifted from live value (e.g. partial write\n // after an update). Rewrite so lookups agree with reality.\n missing.push(id)\n fixesPut.push({ recordId: id, record, version: env._v })\n } else if (!indexable && hasSidecar) {\n // Record exists but its value is no longer indexable (null/\n // undefined). The side-car is stale.\n stale.push(sidecarIds.get(id)!)\n }\n sidecarIds.delete(id)\n }\n // Any side-car whose canonical record vanished is stale.\n for (const [, idxId] of sidecarIds) stale.push(idxId)\n\n let applied = 0\n if (!dryRun) {\n for (const idxId of stale) {\n try {\n await this.adapter.delete(this.vault, this.name, idxId)\n applied++\n } catch { /* ignore — next reconcile picks it up */ }\n }\n for (const fix of fixesPut) {\n await this.maintainPersistedIndexesOnPut(fix.recordId, fix.record, null, fix.version)\n applied++\n }\n // In-memory mirror is authoritative for query dispatch — make\n // sure it matches what's on disk now.\n persisted.clear()\n this.persistedIndexesLoaded = false\n await this.ensurePersistedIndexesLoaded()\n }\n\n return { field, missing, stale, applied }\n }\n\n /**\n * Get the in-memory index store. Used by `Query` to short-circuit\n * `==` and `in` lookups when an index covers the where clause.\n *\n * Returns `null` if no indexes are declared on this collection.\n */\n getIndexes(): CollectionIndexes | null {\n const eager = this.indexes\n return eager && eager.fields().length > 0 ? eager : null\n }\n\n /**\n * Return a `BlobSet` for the given record id.\n *\n * No I/O is performed until you call a method on the handle.\n *\n * ```ts\n * const blobs = invoices.blob('inv-001')\n *\n * // Upload a PDF (deduplicates automatically, MIME auto-detected)\n * await blobs.put('receipt.pdf', pdfBytes)\n *\n * // List slots\n * const files = await blobs.list() // SlotInfo[]\n *\n * // Serve as HTTP response (Content-Type, ETag, streaming body)\n * const res = await blobs.response('receipt.pdf', { inline: true })\n *\n * // Publish a named version (amendment versioning)\n * await blobs.publish('receipt.pdf', 'issued-2025-01')\n *\n * // Raw bytes\n * const bytes = await blobs.get('receipt.pdf')\n * ```\n *\n * Blobs are stored in internal collections (`_blob_slots_*`, `_blob_index`,\n * `_blob_chunks`, `_blob_versions_*`) that are excluded from queries and\n * `list()`. Slot metadata uses this collection's DEK; chunk data uses a\n * vault-shared `_blob` DEK (enabling cross-collection deduplication).\n */\n blob(id: string): BlobSet {\n // tree-shake refactor: delegate to `blobStrategy`. The default\n // is `NO_BLOBS` (throws with a message pointing at the `@noy-db/hub/blobs`\n // subpath). Users who want blob storage pass `blobs()` from that\n // subpath into `createNoydb({ blobStrategy: blobs() })`, which\n // threads the active strategy through Vault → Collection.\n return this.blobStrategy.openSlot({\n store: this.adapter,\n vault: this.vault,\n collection: this.name,\n recordId: id,\n getDEK: this.getDEK,\n encrypted: this.encrypted,\n userId: this.keyring.userId,\n erasableBlobs: this.perRecordCek,\n })\n }\n\n /** Get all records as encrypted envelopes (for dump). */\n async dumpEnvelopes(): Promise<Record<string, EncryptedEnvelope>> {\n await this.ensureHydrated()\n const result: Record<string, EncryptedEnvelope> = {}\n for (const [id, entry] of this.cache) {\n // Reuse the record's stable CEK on a `perRecordKeys` collection so the\n // dumped envelope matches the stored format and stays in the same key\n // chain. `undefined` → legacy path.\n const cek = this.perRecordCek ? await this.resolveRecordCek(id) : undefined\n result[id] = await this.encryptRecord(entry.record, entry.version, cek)\n }\n return result\n }\n\n /**\n * Apply locale resolution to a record.\n *\n * Called from `get()` and `list()` when locale options are present.\n * Uses the effective locale: per-call `locale` takes precedence over\n * `this.defaultLocale`.\n *\n * - i18nText fields: replaced with the resolved string (or the full\n * map when `locale === 'raw'`).\n * - dictKey fields: `<field>Label` virtual fields added.\n *\n * Returns the record unchanged when no locale is active and no i18n/dict\n * fields are registered.\n */\n private async applyLocaleToRecord(\n record: T,\n localeOpts?: LocaleReadOptions,\n ): Promise<T> {\n const hasI18n = this.i18nFields && Object.keys(this.i18nFields).length > 0\n const hasDict = this.dictKeyFields && Object.keys(this.dictKeyFields).length > 0\n const hasMoney = this.moneyFields && Object.keys(this.moneyFields).length > 0\n if (!hasI18n && !hasDict && !hasMoney) return record\n\n const locale = localeOpts?.locale ?? this.defaultLocale\n\n let result = record as unknown as Record<string, unknown>\n\n // Money decode runs regardless of locale (stored int → decimal string);\n // virtuals are gated on `locale !== 'raw'` inside decodeMoneyFields.\n if (hasMoney && this.moneyFields) {\n result = decodeMoneyFields(result, this.moneyFields, typeof locale === 'string' ? locale : undefined)\n }\n\n // i18nText / dictKey resolution require an active locale — EXCEPT a\n // static dict declaring a `displayLocale`, which resolves its\n // `<field>Label` even under a locale-less read (the #291 hybrid hinge).\n // The first early-return (above, `!hasI18n && !hasDict && !hasMoney`) is\n // UNCHANGED; only this second return relaxes, and ONLY for static-display\n // fields — folding `hasI18n` in here would let an i18nText-only\n // collection fall through to applyI18nLocale(…, undefined) on a\n // locale-less read, breaking the raw-{th,en}-map invariant.\n const hasStaticDisplay =\n hasDict &&\n this.dictKeyFields !== undefined &&\n Object.values(this.dictKeyFields).some(\n (d) => isStaticDictDescriptor(d) && d.displayLocale !== undefined,\n )\n if (!locale && !hasStaticDisplay) return result as T\n\n // 1. i18nText resolution — guarded on `locale`, because the relaxed gate\n // above can now be entered with `locale === undefined` (static-display).\n if (locale && hasI18n && this.i18nFields) {\n result = this.i18nStrategy.applyI18nLocale(result, this.i18nFields, locale, localeOpts?.fallback)\n }\n\n // 2. dictKey / staticDict label resolution\n if (hasDict && this.dictKeyFields && this.dictLabelResolver && locale !== 'raw') {\n const withLabels = { ...result }\n const resolver = this.dictLabelResolver\n for (const [field, desc] of Object.entries(this.dictKeyFields)) {\n // dictKey default policy is 'null' (omit/null on miss) — today's\n // behavior — unless the field declares onMissing. 'substitute'\n // walks the declared substitute chain (passed as the resolver's\n // fallback); 'throw' raises LocaleNotSpecifiedError.\n const policy = desc.onMissing ? resolvePolicy(desc.onMissing, 'read') : 'null'\n const fallback =\n policy === 'substitute'\n ? (localeOpts?.fallback ?? desc.substitute)\n : localeOpts?.fallback\n // Per-field effective locale: a static dict falls back to its\n // `displayLocale` when no locale is active (the #291 hybrid hinge);\n // a plain dictKey with no displayLocale gets `undefined` → its\n // <field>Label is omitted on a locale-less read (today's behavior).\n const effLocale =\n locale ??\n (isStaticDictDescriptor(desc) ? desc.displayLocale : undefined)\n // Resolve one key → label | null, honoring the policy. With no\n // effective locale there is nothing to resolve against.\n const resolveKey = async (key: string): Promise<string | null> => {\n if (!effLocale) {\n if (policy === 'throw') {\n throw new LocaleNotSpecifiedError(\n field,\n `dictKey \"${field}\": no locale active to resolve key \"${key}\".`,\n )\n }\n return null\n }\n const label = await resolver(desc.name, key, effLocale, fallback)\n if (label === undefined) {\n if (policy === 'throw') {\n throw new LocaleNotSpecifiedError(\n field,\n `dictKey \"${field}\": no label for key \"${key}\" in locale \"${effLocale}\".`,\n )\n }\n return null\n }\n return label\n }\n\n if (field.includes('[].')) {\n // Wildcard path `arrayKey[].leaf` (#282): add a per-element\n // sibling `<leaf>Label`. Single level + simple leaf.\n const parts = field.split('[].')\n const arrayKey = parts[0]!\n const leaf = parts[1]\n if (!leaf || leaf.includes('.')) continue\n const arr = (withLabels as Record<string, unknown>)[arrayKey]\n if (!Array.isArray(arr)) continue\n const labelKey = `${leaf}Label`\n ;(withLabels as Record<string, unknown>)[arrayKey] = await Promise.all(\n arr.map(async (el) => {\n if (!el || typeof el !== 'object' || Array.isArray(el)) return el\n const k = (el as Record<string, unknown>)[leaf]\n if (typeof k !== 'string') return el\n return { ...(el as Record<string, unknown>), [labelKey]: await resolveKey(k) }\n }),\n )\n continue\n }\n\n const val = result[field]\n if (Array.isArray(val)) {\n // Array-of-keys → [{ key, label }] pair objects (key preserved).\n withLabels[`${field}Label`] = await Promise.all(\n val.map(async (k) => ({\n key: k,\n label: typeof k === 'string' ? await resolveKey(k) : null,\n })),\n )\n } else if (typeof val === 'string') {\n const label = await resolveKey(val)\n // Scalar under 'null'/default omits the label key (today's\n // behavior); 'substitute' returns a value; 'throw' threw above.\n if (label !== null) withLabels[`${field}Label`] = label\n }\n }\n result = withLabels\n }\n\n return result as T\n }\n\n /**\n * Low-level: encrypt a pre-serialised JSON string into an EncryptedEnvelope.\n * Used by both the normal record path and the CRDT path (which serialises\n * a CrdtState rather than a T).\n */\n /**\n * Write / update / delete the `_idx/<field>/<recordId>` side-cars for\n * every declared persistence-index field on this collection after a\n * successful main-record `put()`.\n *\n * Timing: called AFTER `adapter.put()` of the main record succeeds, so\n * a failed main write never leaves a stale index entry. Side-car write\n * failures do NOT fail the overall `put()` — the main record is already\n * durably committed. Per-field failures surface as\n * `IndexWriteFailureError` on the emitter's `index:write-partial`\n * channel and the operator runs a reconcile pass later.\n *\n * Null/undefined field values are not indexed — matches the\n * `PersistedCollectionIndex.stringifyKey` contract. If the prior value\n * was non-null and the new value is null, the side-car is deleted.\n */\n private async maintainPersistedIndexesOnPut(\n id: string,\n newRecord: T,\n previousRecord: T | null,\n version: number,\n ): Promise<void> {\n const persisted = this.persistedIndexes\n if (!persisted) return\n const defs = persisted.definitions()\n if (defs.length === 0) return\n\n const newRec = newRecord as unknown as Record<string, unknown>\n const prevRec = previousRecord as unknown as Record<string, unknown> | null\n\n for (const def of defs) {\n const newValue = extractIndexValue(newRec, def)\n const previousValue = prevRec ? extractIndexValue(prevRec, def) : null\n\n // Update the in-memory mirror first — it's the authoritative source\n // for query dispatch. If the adapter write below fails, the mirror\n // still reflects intended state; the reconciler compares mirror\n // against side-cars on next run.\n persisted.upsert(id, def.key, newValue, previousValue)\n\n const idxId = encodeIdxId(def.key, id)\n try {\n if (newValue === null || newValue === undefined) {\n // Clear any pre-existing side-car for this (field, record).\n if (previousValue !== null && previousValue !== undefined) {\n await this.adapter.delete(this.vault, this.name, idxId)\n }\n } else {\n const body = JSON.stringify({\n field: def.key,\n value: serializeIndexValue(newValue),\n recordId: id,\n writtenAt: new Date().toISOString(),\n })\n const envelope = await this.encryptJsonString(body, version)\n await this.adapter.put(this.vault, this.name, idxId, envelope)\n }\n } catch (cause) {\n this.emitter.emit('index:write-partial', {\n vault: this.vault,\n collection: this.name,\n id,\n action: 'put',\n error: new IndexWriteFailureError({ recordId: id, field: def.key, op: 'put', cause }),\n })\n }\n }\n }\n\n /**\n * Tear down `_idx/<field>/<recordId>` side-cars for a deleted record.\n * Mirror state updates regardless of adapter outcome; adapter failures\n * surface on `index:write-partial` the same way put does.\n */\n private async maintainPersistedIndexesOnDelete(id: string, previousRecord: T): Promise<void> {\n const persisted = this.persistedIndexes\n if (!persisted) return\n const defs = persisted.definitions()\n if (defs.length === 0) return\n\n const prevRec = previousRecord as unknown as Record<string, unknown>\n for (const def of defs) {\n const previousValue = extractIndexValue(prevRec, def)\n if (previousValue !== null && previousValue !== undefined) {\n persisted.remove(id, def.key, previousValue)\n }\n\n const idxId = encodeIdxId(def.key, id)\n try {\n await this.adapter.delete(this.vault, this.name, idxId)\n } catch (cause) {\n this.emitter.emit('index:write-partial', {\n vault: this.vault,\n collection: this.name,\n id,\n action: 'delete',\n error: new IndexWriteFailureError({ recordId: id, field: def.key, op: 'delete', cause }),\n })\n }\n }\n }\n\n /**\n * Bulk-load the persisted-index mirror from `_idx/<field>/*` side-cars\n * on first lazy-mode query. Idempotent — subsequent calls short-circuit\n * on the `persistedIndexesLoaded` flag.\n *\n * Listing the whole id namespace is acceptable here because the caller\n * has already decided to pay a first-query cost (this is the indexed\n * equivalent of lazy-mode hydration, not a per-query scan).\n */\n private async ensurePersistedIndexesLoaded(): Promise<void> {\n if (this.persistedIndexesLoaded) return\n const persisted = this.persistedIndexes\n if (!persisted || persisted.fields().length === 0) {\n this.persistedIndexesLoaded = true\n return\n }\n\n const ids = await this.adapter.list(this.vault, this.name)\n const byField = new Map<string, Array<{ recordId: string; value: unknown }>>()\n for (const id of ids) {\n const decoded = decodeIdxId(id)\n if (!decoded) continue\n if (!persisted.has(decoded.field)) continue\n const envelope = await this.adapter.get(this.vault, this.name, id)\n if (!envelope) continue\n try {\n const json = await this.decryptJsonString(envelope)\n if (json === null) continue // tombstone side-car — skip\n const body = JSON.parse(json) as { value: unknown; recordId: string }\n if (typeof body.recordId !== 'string') continue\n const rows = byField.get(decoded.field) ?? []\n rows.push({ recordId: body.recordId, value: body.value })\n byField.set(decoded.field, rows)\n } catch {\n // Skip unreadable side-cars — the reconciler picks them up later.\n }\n }\n for (const [field, rows] of byField) {\n persisted.ingest(field, rows)\n }\n this.persistedIndexesLoaded = true\n\n // auto-reconcile on first query. The mirror is now\n // populated from whatever side-cars existed; reconcileIndex will\n // diff that against the canonical records and repair (or just\n // report) drift per-field. Skip on the inner reload triggered by\n // reconcileIndex itself — see `autoReconciling` guard.\n if (this.reconcileOnOpen !== 'off' && !this.autoReconciling) {\n await this.autoReconcile()\n }\n }\n\n /**\n * Walk every declared persisted-index field, run `reconcileIndex`\n * per the configured policy, and emit `index:reconciled` for each.\n * Called internally by `ensurePersistedIndexesLoaded()` — exposed as\n * a private helper for readability, not as a public API (the public\n * entry points are `reconcileIndex` and `rebuildIndexes`).\n */\n private async autoReconcile(): Promise<void> {\n const persisted = this.persistedIndexes\n if (!persisted) return\n this.autoReconciling = true\n try {\n const dryRun = this.reconcileOnOpen === 'dry-run'\n for (const def of persisted.definitions()) {\n try {\n const report = await this.reconcileIndex(def.key, { dryRun })\n this.emitter.emit('index:reconciled', {\n vault: this.vault,\n collection: this.name,\n field: def.key,\n missing: report.missing,\n stale: report.stale,\n applied: report.applied,\n skipped: false,\n })\n } catch {\n // Tolerate a single field's failure — a broken reconcile\n // shouldn't prevent the rest of the collection from\n // working. The `index:write-partial` channel captures\n // per-field failures during put/delete; this is its\n // sibling for the reconcile path.\n }\n }\n } finally {\n this.autoReconciling = false\n }\n }\n\n /**\n * Construct a `LazyQuery<T>` bound to this collection. Used by the\n * lazy-mode branch of `query()` and kept private because callers should\n * always go through `query()` to pick up the eager/lazy dispatch.\n */\n /**\n * Build a chainable indexed-read query against a lazy-mode collection.\n *\n * Companion to `query()`, which is eager-mode only and materialises a\n * snapshot. `lazyQuery()` dispatches every read through the persisted\n * index side-cars — no bulk decrypt, no snapshot. Every field touched by\n * `.where(...)` or `.orderBy(...)` MUST be declared in `indexes`;\n * otherwise `.toArray()` throws `IndexRequiredError`.\n *\n * The returned builder is always Promise-returning on its terminals\n * (`toArray`, `first`, `count`) because candidate records are decrypted\n * from the adapter on demand.\n *\n * @example\n * ```ts\n * const disbursements = vault.collection<Disbursement>('disbursements', {\n * prefetch: false,\n * cache: { maxRecords: 1000 },\n * indexes: ['clientId', 'period'],\n * })\n * const rows = await disbursements.lazyQuery()\n * .where('clientId', '==', 'c-42')\n * .orderBy('period', 'desc')\n * .limit(50)\n * .toArray()\n * ```\n *\n * Throws at call time when the collection is in eager mode — use\n * `query()` there. Throws if no index is declared, because a lazy\n * query with no index would need to enumerate the whole collection.\n */\n lazyQuery(): LazyQuery<T> {\n if (!this.lazy) {\n throw new Error(\n `Collection \"${this.name}\": lazyQuery() is only available in lazy mode ` +\n `(prefetch: false). Use collection.query() for eager-mode chainable reads.`,\n )\n }\n const persisted = this.persistedIndexes\n if (!persisted) {\n throw new Error(\n `Collection \"${this.name}\": lazyQuery() requires indexing to be enabled. ` +\n `Pass \\`withIndexing()\\` from \"@noy-db/hub/indexing\" to ` +\n `\\`createNoydb({ indexStrategy: withIndexing() })\\`.`,\n )\n }\n if (persisted.fields().length === 0) {\n throw new Error(\n `Collection \"${this.name}\": lazyQuery() requires at least one field declared ` +\n `in \\`indexes\\`. Declare the fields you'll filter or sort by, or use ` +\n `collection.scan({ pageSize }) for non-indexed iteration.`,\n )\n }\n const source: LazyQuerySource<T> = {\n collectionName: this.name,\n persistedIndexes: persisted,\n ensurePersistedIndexesLoaded: () => this.ensurePersistedIndexesLoaded(),\n getRecord: (id: string) => this.get(id),\n }\n return new LazyQuery<T>(source)\n }\n\n /**\n * Resolve the stable CEK for a record on the WRITE path — see\n * {@link resolveStableCek}. Thin delegate that supplies the collection's\n * CEK cache, live-envelope reader, and DEK resolver.\n */\n private resolveRecordCek(id: string): Promise<CryptoKey> {\n return resolveStableCek(\n {\n cache: this.cekCache,\n getLive: (rid) => this.adapter.get(this.vault, this.name, rid),\n getDEK: () => this.getDEK(this.name),\n },\n id,\n )\n }\n\n /**\n * Encrypt a JSON body into an envelope.\n *\n * When `cek` is supplied (per-record CEK collections), the body is\n * encrypted under the CEK and the CEK is AES-KW-wrapped under the\n * collection DEK and stamped on `_cek`. When `cek` is omitted, the legacy\n * path encrypts the body directly under the collection DEK — byte-identical\n * to pre-CEK behaviour, so non-adopting collections pay nothing.\n */\n private async encryptJsonString(\n json: string,\n version: number,\n cek?: CryptoKey,\n ): Promise<EncryptedEnvelope> {\n const by = this.keyring.userId\n\n if (!this.encrypted) {\n return {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: version,\n _ts: new Date().toISOString(),\n _iv: '',\n _data: json,\n _by: by,\n }\n }\n\n const dek = await this.getDEK(this.name)\n\n if (cek !== undefined) {\n const { iv, data } = await encrypt(json, cek)\n const wrapped = await wrapCek(cek, dek)\n return {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: version,\n _ts: new Date().toISOString(),\n _iv: iv,\n _data: data,\n _by: by,\n _cek: wrapped,\n }\n }\n\n const { iv, data } = await encrypt(json, dek)\n\n return {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: version,\n _ts: new Date().toISOString(),\n _iv: iv,\n _data: data,\n _by: by,\n }\n }\n\n private async encryptRecord(\n record: T,\n version: number,\n cek?: CryptoKey,\n ): Promise<EncryptedEnvelope> {\n const base = await this.encryptJsonString(JSON.stringify(record), version, cek)\n if (!this.deterministicFields || !this.encrypted) return base\n\n // compute deterministic-ciphertext slots for every\n // declared field. Non-primitive values are JSON-stringified so\n // objects/arrays still dedupe on structural equality.\n const dek = await this.getDEK(this.name)\n const rec = record as unknown as Record<string, unknown>\n const det: Record<string, string> = {}\n for (const field of this.deterministicFields) {\n const value = rec[field]\n if (value === undefined || value === null) continue\n const plaintext = typeof value === 'string' ? value : JSON.stringify(value)\n const { iv, data } = await encryptDeterministic(plaintext, dek, `${this.name}/${field}`)\n det[field] = `${iv}:${data}`\n }\n if (Object.keys(det).length === 0) return base\n return { ...base, _det: det }\n }\n\n /**\n * find the first record whose deterministic field matches\n * the given plaintext. Returns `null` when no match exists.\n *\n * Reads every envelope via the adapter and compares the stored\n * `_det[field]` to a freshly computed deterministic ciphertext — no\n * record bodies are decrypted during the search, which is the whole\n * point of a deterministic index.\n *\n * Throws when the field is not declared in `deterministicFields`, so a\n * typo fails loudly at the call site rather than silently returning\n * null forever.\n */\n async findByDet(field: string, value: unknown): Promise<T | null> {\n if (!this.deterministicFields || !this.deterministicFields.has(field)) {\n throw new Error(\n `Collection \"${this.name}\": field \"${field}\" is not declared in deterministicFields`,\n )\n }\n if (!this.encrypted) {\n throw new Error(\n `Collection \"${this.name}\": findByDet is only meaningful on encrypted collections`,\n )\n }\n const dek = await this.getDEK(this.name)\n const plaintext = typeof value === 'string' ? value : JSON.stringify(value)\n const { iv, data } = await encryptDeterministic(plaintext, dek, `${this.name}/${field}`)\n const target = `${iv}:${data}`\n\n const ids = await this.adapter.list(this.vault, this.name)\n for (const id of ids) {\n const env = await this.adapter.get(this.vault, this.name, id)\n if (!env || !env._det) continue\n if (env._det[field] === target) {\n return this.decryptRecord(env)\n }\n }\n return null\n }\n\n /**\n * return every record whose deterministic field matches.\n * Same semantics as {@link findByDet} but without the short-circuit.\n */\n async queryByDet(field: string, value: unknown): Promise<T[]> {\n if (!this.deterministicFields || !this.deterministicFields.has(field)) {\n throw new Error(\n `Collection \"${this.name}\": field \"${field}\" is not declared in deterministicFields`,\n )\n }\n if (!this.encrypted) {\n throw new Error(\n `Collection \"${this.name}\": queryByDet is only meaningful on encrypted collections`,\n )\n }\n const dek = await this.getDEK(this.name)\n const plaintext = typeof value === 'string' ? value : JSON.stringify(value)\n const { iv, data } = await encryptDeterministic(plaintext, dek, `${this.name}/${field}`)\n const target = `${iv}:${data}`\n\n const ids = await this.adapter.list(this.vault, this.name)\n const matches: T[] = []\n for (const id of ids) {\n const env = await this.adapter.get(this.vault, this.name, id)\n if (!env || !env._det) continue\n if (env._det[field] === target) {\n const rec = await this.decryptRecord(env)\n if (rec !== null) matches.push(rec) // skip tombstone (defensive)\n }\n }\n return matches\n }\n\n // ─── Hierarchical Access ──────────────────────────\n\n private assertTiersEnabled(): void {\n if (!this.tiers) {\n throw new Error(\n `Collection \"${this.name}\": hierarchical tiers are not enabled. ` +\n `Pass { tiers: [0, 1, 2, …] } to vault.collection() to opt in.`,\n )\n }\n }\n\n private assertDeclaredTier(tier: number): void {\n if (tier < 0 || !Number.isInteger(tier)) {\n throw new Error(`Collection \"${this.name}\": tier must be a non-negative integer, got ${tier}`)\n }\n if (tier === 0) return\n if (!this.tiers || !this.tiers.has(tier)) {\n throw new Error(\n `Collection \"${this.name}\": tier ${tier} is not declared in { tiers: [...] }`,\n )\n }\n }\n\n /**\n * tier-aware put. Encrypts the record with the\n * collection's tier-N DEK and stamps `_tier: N` on the envelope. The\n * caller's keyring must hold the tier-N DEK (directly, by\n * delegation, or by virtue of being the grantor); otherwise throws\n * `TierNotGrantedError`.\n *\n * accepts an optional `elevation` context. When\n * present, the emitted cross-tier event is stamped with\n * `authorization: 'elevation'`, the elevation's reason, and the\n * caller's pre-elevation tier. `vault.elevate(...).collection().put`\n * threads this through; direct `putAtTier` calls leave it undefined\n * and fall back to the inherent-write event shape.\n */\n async putAtTier(\n id: string,\n record: T,\n tier: number,\n opts?: { elevation?: { reason: string; fromTier: number } },\n ): Promise<void> {\n this.assertTiersEnabled()\n this.assertDeclaredTier(tier)\n assertTierAccess(this.keyring, this.name, tier)\n\n const key = dekKey(this.name, tier)\n const dek = await this.getDEK(key)\n\n const existing = await this.adapter.get(this.vault, this.name, id)\n const version = existing ? existing._v + 1 : 1\n const json = JSON.stringify(record)\n const { iv, data } = await encrypt(json, dek)\n const envelope: EncryptedEnvelope = {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: version,\n _ts: new Date().toISOString(),\n _iv: iv,\n _data: data,\n _by: this.keyring.userId,\n ...(tier > 0 && { _tier: tier }),\n }\n\n await this.adapter.put(this.vault, this.name, id, envelope)\n\n if (tier > 0) {\n this.emitCrossTierEvent({\n actor: this.keyring.userId,\n collection: this.name,\n id,\n tier,\n authorization: opts?.elevation ? 'elevation' : 'inherent',\n op: 'put',\n ts: envelope._ts,\n ...(opts?.elevation && {\n reason: opts.elevation.reason,\n elevatedFrom: opts.elevation.fromTier,\n }),\n })\n }\n }\n\n /**\n * tier-aware get. When the stored record is at a\n * tier the caller cannot decrypt:\n * - `'invisibility'` mode (default) → returns `null`.\n * - `'ghost'` mode → returns a `GhostRecord` placeholder with the\n * tier and the record id (the record exists but contents are\n * withheld).\n *\n * Fully-cleared reads return the plaintext record and fire a\n * cross-tier event when `_tier > 0`.\n */\n async getAtTier(id: string): Promise<T | GhostRecord | null> {\n this.assertTiersEnabled()\n const envelope = await this.adapter.get(this.vault, this.name, id)\n if (!envelope) return null\n const tier = envelope._tier ?? 0\n if (tier === 0) {\n return this.decryptRecord(envelope)\n }\n\n const key = dekKey(this.name, tier)\n if (!this.keyring.deks.has(key)) {\n if (this.tierMode === 'ghost') {\n return { _ghost: true, _tier: tier } as GhostRecord\n }\n return null\n }\n\n const dek = await this.getDEK(key)\n // A tiered record may carry a per-record CEK (e.g. a CEK record\n // elevated via `elevate()`): the CEK is wrapped under the TIER DEK, so\n // unwrap under the tier DEK then decrypt the body under the CEK. Legacy\n // tiered records decrypt directly under the tier DEK.\n let plaintext: string\n if (envelope._cek !== undefined) {\n const cek = await unwrapCek(envelope._cek, dek)\n this.cekCache?.set(id, cek, 1)\n plaintext = await decrypt(envelope._iv, envelope._data, cek)\n } else {\n plaintext = await decrypt(envelope._iv, envelope._data, dek)\n }\n const record = JSON.parse(plaintext) as T\n\n this.emitCrossTierEvent({\n actor: this.keyring.userId,\n collection: this.name,\n id,\n tier,\n authorization: this.isElevatorOrOwner() ? 'inherent' : 'delegation',\n op: 'get',\n ts: new Date().toISOString(),\n })\n\n return record\n }\n\n /**\n * list ids grouped by the caller's readability.\n * Returns only ids whose tier the caller can read. Above-tier ids\n * are omitted in `'invisibility'` mode and included (with tier\n * metadata) in `'ghost'` mode.\n */\n async listAtTier(): Promise<Array<{ id: string; tier: number; readable: boolean }>> {\n this.assertTiersEnabled()\n const ids = await this.adapter.list(this.vault, this.name)\n const out: Array<{ id: string; tier: number; readable: boolean }> = []\n for (const id of ids) {\n const env = await this.adapter.get(this.vault, this.name, id)\n if (!env) continue\n const tier = env._tier ?? 0\n const readable = tier === 0 || this.keyring.deks.has(dekKey(this.name, tier))\n if (!readable && this.tierMode === 'invisibility') continue\n out.push({ id, tier, readable })\n }\n return out\n }\n\n /**\n * elevate a record to a higher tier. Re-encrypts with\n * the target tier's DEK. The caller must hold DEKs for both the\n * current tier (to decrypt) and the target tier (to re-encrypt).\n * Stamps `_elevatedBy` with the caller id so `demote()` can check\n * the reverse operation.\n */\n async elevate(id: string, toTier: number): Promise<void> {\n this.assertTiersEnabled()\n this.assertDeclaredTier(toTier)\n assertTierAccess(this.keyring, this.name, toTier)\n\n const envelope = await this.adapter.get(this.vault, this.name, id)\n if (!envelope) throw new Error(`Record \"${id}\" not found in collection \"${this.name}\"`)\n const fromTier = envelope._tier ?? 0\n if (toTier === fromTier) return\n if (toTier < fromTier) {\n throw new Error(`Use demote() to lower the tier of \"${id}\" from ${fromTier} to ${toTier}`)\n }\n // Caller must have access at the existing tier to decrypt.\n if (fromTier > 0) assertTierAccess(this.keyring, this.name, fromTier)\n\n const fromKey = dekKey(this.name, fromTier)\n const toKey = dekKey(this.name, toTier)\n const fromDek = await this.getDEK(fromKey)\n const toDek = await this.getDEK(toKey)\n\n // Per-record CEK composes with tiers: the body key is unchanged (history\n // chain identity preserved); only the wrapping key moves with the tier.\n // Legacy (no `_cek`) records take the direct-DEK path unchanged.\n const now = new Date().toISOString()\n const body = await rewrapBodyToDek(envelope, fromDek, toDek)\n if (body.cek) this.cekCache?.set(id, body.cek, 1)\n const next: EncryptedEnvelope = {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: envelope._v + 1,\n _ts: now,\n _iv: body._iv,\n _data: body._data,\n _by: this.keyring.userId,\n _tier: toTier,\n _elevatedBy: this.keyring.userId,\n ...(body._cek !== undefined ? { _cek: body._cek } : {}),\n }\n await this.adapter.put(this.vault, this.name, id, next)\n\n this.emitCrossTierEvent({\n actor: this.keyring.userId,\n collection: this.name,\n id,\n tier: toTier,\n authorization: 'elevation',\n op: 'elevate',\n ts: now,\n })\n }\n\n /**\n * demote a record to a lower tier. Allowed only for\n * the user who performed the last elevation or an owner.\n */\n async demote(id: string, toTier: number): Promise<void> {\n this.assertTiersEnabled()\n if (toTier < 0) throw new Error(`Cannot demote to negative tier ${toTier}`)\n\n const envelope = await this.adapter.get(this.vault, this.name, id)\n if (!envelope) throw new Error(`Record \"${id}\" not found in collection \"${this.name}\"`)\n const fromTier = envelope._tier ?? 0\n if (toTier === fromTier) return\n if (toTier > fromTier) {\n throw new Error(`Use elevate() to raise the tier of \"${id}\" from ${fromTier} to ${toTier}`)\n }\n const isOwner = this.keyring.role === 'owner'\n const isOriginalElevator = envelope._elevatedBy === this.keyring.userId\n if (!isOwner && !isOriginalElevator) {\n throw new TierDemoteDeniedError(id, fromTier)\n }\n // Caller must still hold the DEK of the current tier to decrypt.\n assertTierAccess(this.keyring, this.name, fromTier)\n if (toTier > 0) this.assertDeclaredTier(toTier)\n\n const fromDek = await this.getDEK(dekKey(this.name, fromTier))\n const toDek = await this.getDEK(dekKey(this.name, toTier))\n\n // CEK re-wrap on demote — same body key, moved from the source tier\n // DEK to the target tier DEK. Legacy records take the direct-DEK path.\n const now = new Date().toISOString()\n const body = await rewrapBodyToDek(envelope, fromDek, toDek)\n if (body.cek) this.cekCache?.set(id, body.cek, 1)\n const next: EncryptedEnvelope = {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: envelope._v + 1,\n _ts: now,\n _iv: body._iv,\n _data: body._data,\n _by: this.keyring.userId,\n ...(toTier > 0 && { _tier: toTier }),\n ...(body._cek !== undefined ? { _cek: body._cek } : {}),\n }\n await this.adapter.put(this.vault, this.name, id, next)\n\n this.emitCrossTierEvent({\n actor: this.keyring.userId,\n collection: this.name,\n id,\n tier: fromTier,\n authorization: 'elevation',\n op: 'demote',\n ts: now,\n })\n }\n\n private isElevatorOrOwner(): boolean {\n return this.keyring.role === 'owner' || this.keyring.role === 'admin'\n }\n\n private emitCrossTierEvent(event: CrossTierAccessEvent): void {\n try {\n this.onCrossTierAccess?.(event)\n } catch {\n // notification sink failures must never block a tier operation\n }\n }\n\n /**\n * Low-level: decrypt an envelope and return the raw JSON string.\n *\n * `_cek` presence is the format discriminant (NOT `this.perRecordCek`),\n * so a mixed vault — and a recipient that never opted into\n * `perRecordKeys` — decrypts both legacy and CEK records:\n * - `_cek` present → unwrap the CEK under the collection DEK, decrypt the\n * body under the CEK (cache the unwrapped CEK so repeated reads skip it).\n * - `_cek` absent → legacy path, body decrypts directly under the\n * collection DEK.\n *\n * The optional `id` lets reads populate the CEK cache; it is omitted by\n * callers (history, conflict merge) that have only the envelope.\n */\n private async decryptJsonString(envelope: EncryptedEnvelope, id?: string): Promise<string | null> {\n // RISK #1 (forget cascade): a shred tombstone carries `_data: ''` and no\n // `_cek`. Decrypting it would call `decrypt('', '', dek)` → AES-GCM\n // OperationError → TamperedError. Return null so every read callsite\n // treats it as \"absent / skip\", matching how get()/list already drop\n // tombstones. Legacy plaintext collections (`!this.encrypted`) legitimately\n // have empty `_iv`/`_data`, so `isTombstone` is false for them — preserved.\n if (isTombstone(envelope, this.encrypted)) return null\n if (!this.encrypted) return envelope._data\n const dek = await this.getDEK(this.name)\n if (envelope._cek !== undefined) {\n const cached = id !== undefined ? this.cekCache?.get(id) : undefined\n const cek = cached ?? (await unwrapCek(envelope._cek, dek))\n if (cached === undefined && id !== undefined) this.cekCache?.set(id, cek, 1)\n return decrypt(envelope._iv, envelope._data, cek)\n }\n return decrypt(envelope._iv, envelope._data, dek)\n }\n\n /**\n * Decrypt an envelope into a record of type `T`.\n *\n * When a schema is attached, the decrypted value is validated before\n * being returned. A divergence between the stored bytes and the\n * current schema throws `SchemaValidationError` with\n * `direction: 'output'` — silently returning drifted data would\n * propagate garbage into the UI and break the whole point of having\n * a schema.\n *\n * `skipValidation` exists for history reads: when calling\n * `getVersion()` the caller is explicitly asking for an old snapshot\n * that may predate a schema change, so validating it would be a\n * false positive. Every non-history read leaves this flag `false`.\n */\n private async decryptRecord(\n envelope: EncryptedEnvelope,\n opts: { skipValidation?: boolean; id?: string } = {},\n ): Promise<T | null> {\n const json = await this.decryptJsonString(envelope, opts.id)\n // Tombstone (shredded record) → null, propagated from decryptJsonString.\n // Callers skip null exactly as they already skip a tombstone envelope.\n if (json === null) return null\n let parsed: unknown = JSON.parse(json)\n\n // CRDT resolution: if this collection is in CRDT mode, the\n // stored JSON is a CrdtState, not T directly. Resolve to the snapshot.\n if (this.crdtMode && parsed !== null && typeof parsed === 'object' && '_crdt' in parsed) {\n parsed = this.crdtStrategy.resolveCrdtSnapshot(parsed as CrdtState)\n }\n\n let record = parsed as T\n\n if (this.schema !== undefined && !opts.skipValidation) {\n // Context string deliberately avoids leaking the record id — the\n // envelope only carries the version, not the id (the id lives in\n // the adapter-side key). `<collection>@v<n>` is enough for the\n // developer to find the offending record.\n record = await validateSchemaOutput(\n this.schema,\n record,\n `${this.name}@v${envelope._v}`,\n )\n }\n\n return record\n }\n}\n\n/**\n * Read a field value from a plain record for persisted-index maintenance.\n * Supports dotted paths so declarations like `indexes: ['billing.clientId']`\n * work the same way `readPath` handles them for the eager-mode builder.\n */\nfunction readPersistedValue(record: Record<string, unknown>, field: string): unknown {\n if (!field.includes('.')) return record[field]\n const segments = field.split('.')\n let cursor: unknown = record\n for (const segment of segments) {\n if (cursor === null || cursor === undefined) return undefined\n cursor = (cursor as Record<string, unknown>)[segment]\n }\n return cursor\n}\n\n/**\n * Canonicalize a typed value for storage inside the side-car body so it\n * round-trips through `JSON.parse` without losing fidelity. Dates are\n * serialised as ISO strings; everything else passes through.\n *\n * The in-memory mirror compares on the stringified bucket key, so the\n * exact storage form is not query-critical — this just protects the\n * reconciler, which compares the stored body against the\n * live record value and would otherwise mismatch on Date objects.\n */\nfunction serializeIndexValue(value: unknown): unknown {\n if (value instanceof Date) return value.toISOString()\n return value\n}\n\n/**\n * Extract the indexable value for a declaration — a scalar for\n * single-field, or a tuple array for composite. Returns `null` when\n * the value is not indexable (single-field null/undefined, composite\n * with any null/undefined component — the whole composite is skipped\n * if any part is missing).\n */\nfunction extractIndexValue(\n record: Record<string, unknown>,\n def: PersistedIndexDef,\n): unknown {\n if (def.kind === 'single') {\n const v = readPersistedValue(record, def.field)\n return v === undefined || v === null ? null : v\n }\n const tuple: unknown[] = []\n for (const f of def.fields) {\n const v = readPersistedValue(record, f)\n if (v === undefined || v === null) return null\n tuple.push(v)\n }\n return tuple\n}\n\n/**\n * Compare the decrypted side-car body's `value` against the live record\n * field value, in the same canonical form used for storage. Handles the\n * Date-is-ISO-string round trip so reconcile doesn't flag a false drift.\n */\nfunction valuesMatch(stored: unknown, live: unknown): boolean {\n const serialized = serializeIndexValue(live)\n if (stored === serialized) return true\n if (stored === undefined || serialized === undefined) return stored === serialized\n // JSON-stringify both sides for structural equality on arrays/objects.\n try {\n return JSON.stringify(stored) === JSON.stringify(serialized)\n } catch {\n return false\n }\n}\n","/**\n * Record cold-storage archival engine.\n *\n * Archival relocates a sealed record's **encrypted envelope** from the\n * primary store to a cold archive store — no re-encryption, the envelope\n * is opaque ciphertext. Because relocation goes through low-level store\n * ops (and the collection's `_internalDelete`), it bypasses guards (an\n * issued/immutable record can still be archived) and never fires\n * materialized-view dispatch (finalized aggregates over a sealed period\n * don't recompute). The archive store's contents are themselves the\n * archived-set index — `listArchived` lists it; `restore` relocates an\n * envelope back to the primary store.\n *\n * A `legalHold` predicate blocks archival; `archiveWhen` (typically\n * derived from the record's fiscal period / business date) selects\n * eligible records.\n */\n\nimport type { NoydbStore, EncryptedEnvelope } from '../types.js'\n\nexport interface ArchivePolicy<T = unknown> {\n /** Select records eligible for archival — typically a business-date / period test. */\n readonly archiveWhen: (record: T) => boolean\n /** Block archival while true (litigation / audit hold). Fail-closed on throw. */\n readonly legalHold?: (record: T) => boolean\n}\n\nexport interface ArchiveResult {\n /** Records relocated to the archive store. */\n readonly archived: number\n /** Records eligible by `archiveWhen` but retained by a `legalHold`. */\n readonly held: number\n /** Records scanned across policy collections. */\n readonly scanned: number\n readonly byCollection: Record<string, { archived: number; held: number }>\n}\n\nexport interface ArchiveRunOptions {\n /** Stop after this many archivals. `undefined` = unbounded. */\n readonly maxArchives?: number\n /** Preview without relocating. */\n readonly dryRun?: boolean\n}\n\n/**\n * Everything the engine needs from the Vault, injected so the engine\n * stays unit-testable without a live vault.\n */\nexport interface ArchiveContext {\n readonly vaultId: string\n readonly archiveStore: NoydbStore\n /** Collections that declared an `archive` policy. */\n collectionsWithPolicy(): readonly string[]\n getPolicy(collection: string): ArchivePolicy | null\n listRecordIds(collection: string): Promise<readonly string[]>\n /** Decrypted record for policy evaluation, or null if unreadable. */\n getRecord(collection: string, id: string): Promise<Record<string, unknown> | null>\n /** Raw encrypted envelope from the primary store. */\n getEnvelope(collection: string, id: string): Promise<EncryptedEnvelope | null>\n /** Remove from the primary store + cache, bypassing guards/MV (`_internalDelete`). */\n removeFromPrimary(collection: string, id: string): Promise<void>\n /** Write an envelope back to the primary store + refresh cache. */\n restoreToPrimary(collection: string, id: string, env: EncryptedEnvelope): Promise<void>\n}\n\nfunction isHeld<T>(policy: ArchivePolicy<T>, record: T): boolean {\n if (!policy.legalHold) return false\n try {\n return policy.legalHold(record)\n } catch {\n return true // fail-closed: a throwing hold predicate retains the record\n }\n}\n\n/** Sweep eligible records into the archive store. */\nexport async function runArchive(ctx: ArchiveContext, options: ArchiveRunOptions = {}): Promise<ArchiveResult> {\n const maxArchives = options.maxArchives ?? Infinity\n const dryRun = options.dryRun === true\n let archived = 0\n let held = 0\n let scanned = 0\n const byCollection: Record<string, { archived: number; held: number }> = {}\n\n outer: for (const collection of ctx.collectionsWithPolicy()) {\n const policy = ctx.getPolicy(collection)\n if (!policy) continue\n byCollection[collection] = { archived: 0, held: 0 }\n for (const id of await ctx.listRecordIds(collection)) {\n if (archived >= maxArchives) break outer\n const record = await ctx.getRecord(collection, id).catch(() => null)\n if (record === null) continue\n scanned += 1\n let eligible = false\n try {\n eligible = policy.archiveWhen(record)\n } catch {\n eligible = false // fail-closed: don't archive on predicate error\n }\n if (!eligible) continue\n if (isHeld(policy, record)) {\n held += 1\n byCollection[collection].held += 1\n continue\n }\n if (!dryRun) {\n const env = await ctx.getEnvelope(collection, id)\n if (!env) continue\n await ctx.archiveStore.put(ctx.vaultId, collection, id, env)\n await ctx.removeFromPrimary(collection, id)\n }\n archived += 1\n byCollection[collection].archived += 1\n }\n }\n\n return { archived, held, scanned, byCollection }\n}\n\n/** Relocate one archived record back to the primary store. Returns false if not archived. */\nexport async function runRestore(ctx: ArchiveContext, collection: string, id: string): Promise<boolean> {\n const env = await ctx.archiveStore.get(ctx.vaultId, collection, id)\n if (!env) return false\n await ctx.restoreToPrimary(collection, id, env)\n await ctx.archiveStore.delete(ctx.vaultId, collection, id)\n return true\n}\n\n/** List archived record ids for a collection (or all policy collections). */\nexport async function runListArchived(\n ctx: ArchiveContext,\n collection?: string,\n): Promise<Array<{ collection: string; id: string }>> {\n const collections = collection ? [collection] : ctx.collectionsWithPolicy()\n const out: Array<{ collection: string; id: string }> = []\n for (const c of collections) {\n const ids = await ctx.archiveStore.list(ctx.vaultId, c)\n for (const id of ids) out.push({ collection: c, id })\n }\n return out\n}\n","/**\n * `@noy-db/hub` record cold-storage archival subsystem.\n *\n * `withArchive({ store })` designates a cold {@link NoydbStore} as the\n * archive target. Declare a per-collection `archive` policy, then call\n * `vault.archive()` to relocate eligible sealed records there,\n * `vault.restore(collection, id)` to pull one back, and\n * `vault.listArchived()` to enumerate the cold set.\n *\n * @see ./engine for the relocation logic.\n */\n\nimport type { NoydbStore } from '../types.js'\n\nexport interface WithArchiveOptions {\n /** The cold store that holds archived record envelopes. */\n store: NoydbStore\n}\n\nexport interface ArchiveStrategy {\n readonly store: NoydbStore\n}\n\n/** Enable record cold-storage archival against the given cold store. */\nexport function withArchive(opts: WithArchiveOptions): ArchiveStrategy {\n return { store: opts.store }\n}\n\nexport type {\n ArchivePolicy,\n ArchiveResult,\n ArchiveRunOptions,\n ArchiveContext,\n} from './engine.js'\nexport { runArchive, runRestore, runListArchived } from './engine.js'\n","/**\n * Atomic sequence primitive — online-coordinated gap-free numbering.\n *\n * `vault.sequence('invoice-2026').next()` returns 1, 2, 3, … with no\n * gaps and no duplicates, even under concurrent callers. Each named\n * sequence is an independent counter record at `_sequences/<name>`,\n * incremented with an optimistic compare-and-swap retry loop — the same\n * proven pattern as the ledger head (`history/ledger/store.ts`).\n *\n * **Explicitly online-only.** Gap-free numbering requires single-authority\n * serialization, which an offline / non-CAS store cannot provide. `next()`\n * throws {@link SequenceOfflineError} unless the backing store advertises\n * `capabilities.casAtomic`. This is a deliberate, honest wall — an offline\n * writer cannot safely allocate a global sequence number.\n *\n * Note on \"gap-free\": the *sequence* is gap-free (each `next()` yields a\n * unique, +1 value). If a caller discards a value without using it, that\n * is a gap in *usage*, not in the sequence — assign each `next()` result\n * to its record in the same operation.\n */\n\nimport type { NoydbStore, EncryptedEnvelope } from '../types.js'\nimport { NOYDB_FORMAT_VERSION } from '../types.js'\nimport { encrypt, decrypt } from '../crypto.js'\nimport { ConflictError, SequenceContentionError, SequenceOfflineError, ValidationError } from '../errors.js'\n\nexport const SEQUENCE_COLLECTION = '_sequences'\n// A sequence is a single hot CAS row — higher contention than a ledger\n// append. A larger budget + jittered backoff absorbs moderate concurrency;\n// a genuine burst beyond this surfaces SequenceContentionError so the\n// caller can retry / queue (the honest online-only contract).\nconst MAX_NEXT_ATTEMPTS = 16\n\ninterface SequenceState {\n value: number\n}\n\n/** Options for `SequenceHandle.next`. Deferred-numbering series use `for`; the CAS counter ignores all of these. */\nexport interface NextOptions {\n /** Deferred mode: the record id to number. Ignored by the CAS counter. */\n readonly for?: string\n /** Deferred mode: reject after this many ms if still unsealed (reserved; not yet enforced in this slice). */\n readonly timeoutMs?: number\n}\n\n/**\n * Partitioning for a CAS sequence (#345). A partitioned sequence is an\n * independent counter scoped to one tuple of values — e.g.\n * `sequence('invoice', { partition: [2026, 'EU'] })` numbers EU-2026 invoices\n * separately from `[2026, 'US']` and from the bare `invoice` series.\n *\n * Partition components are URI-encoded (so `/`, null bytes and other\n * separators in a value can never collide with the structural separators) and\n * `'/'`-joined, then appended to the series with a null-byte (`\\x00`)\n * separator. The null byte is illegal in a plain series name, which guarantees\n * a partitioned key is always disjoint from any unpartitioned series.\n */\nexport interface SequenceOptions {\n /** Partition tuple. Each component is URI-encoded and `'/'`-joined. */\n readonly partition?: readonly (string | number)[]\n}\n\n/**\n * Resolve the CAS storage key for a (series, partition) pair.\n *\n * With no partition the key is `series` verbatim. With a partition the key is\n * `${series}\\x00${parts}` where `parts` is each component passed through\n * `encodeURIComponent(String(part))` and `'/'`-joined. The null-byte separator\n * is illegal in a plain series name, so partitioned keys never collide with\n * unpartitioned ones; URI-encoding keeps any component containing `/` distinct\n * from a multi-component partition.\n *\n * @throws {ValidationError} if any partition component is empty after `String()`\n * or is a non-finite number (`NaN`, `±Infinity`).\n */\nexport function resolveSequenceKey(series: string, opts?: SequenceOptions): string {\n const partition = opts?.partition\n if (!partition || partition.length === 0) return series\n const parts = partition.map((p) => {\n if (typeof p === 'number' && !Number.isFinite(p)) {\n throw new ValidationError(`sequence partition component must be a finite number, got ${p}`)\n }\n const s = String(p)\n if (s === '') {\n throw new ValidationError('sequence partition component must not be empty')\n }\n return encodeURIComponent(s)\n })\n return `${series}\\x00${parts.join('/')}`\n}\n\nexport interface SequenceHandle {\n /** Atomically allocate and return the next value (1, 2, 3, …). Deferred series resolve at the next pass. */\n next(opts?: NextOptions): Promise<number>\n /** Read the current value without allocating. Returns 0 if never used. */\n peek(): Promise<number>\n /**\n * Set-if-greater: advance the counter to at least `n`. A no-op if the\n * current value is already `>= n` (so it never rewinds), and `seedTo(0)` is\n * a no-op. Idempotent and CAS-safe under concurrent `next()` / `seedTo()`.\n *\n * Use after a bundle / CSV import to fast-forward the counter past the\n * highest imported serial, so subsequent `next()` calls cannot re-use a\n * number that is already on a record.\n *\n * Online-only: throws {@link SequenceOfflineError} on a non-CAS store.\n */\n seedTo(n: number): Promise<void>\n}\n\nasync function sleepBackoff(attempt: number): Promise<void> {\n // Exponential backoff with full jitter to break the thundering herd\n // when many writers contend on the same counter row.\n const ceil = Math.min(2 ** attempt, 32)\n const ms = Math.floor(Math.random() * ceil)\n await new Promise((r) => setTimeout(r, ms))\n}\n\nexport class SequenceStore {\n private readonly adapter: NoydbStore\n private readonly vault: string\n private readonly encrypted: boolean\n private readonly getDEK: (collectionName: string) => Promise<CryptoKey>\n private readonly actor: string\n /**\n * Memoized DEK promise. The `_sequences` collection DEK is created on\n * first access; without sharing one promise, a burst of concurrent\n * `next()` calls would each trigger DEK creation and diverge (one\n * writer's ciphertext unreadable by another). One shared promise → one\n * DEK.\n */\n private dekPromise: Promise<CryptoKey> | null = null\n\n constructor(opts: {\n adapter: NoydbStore\n vault: string\n encrypted: boolean\n getDEK: (collectionName: string) => Promise<CryptoKey>\n actor: string\n }) {\n this.adapter = opts.adapter\n this.vault = opts.vault\n this.encrypted = opts.encrypted\n this.getDEK = opts.getDEK\n this.actor = opts.actor\n }\n\n /** A handle bound to one sequence name. */\n handle(name: string): SequenceHandle {\n return {\n next: () => this.next(name),\n peek: () => this.peek(name),\n seedTo: (n) => this.seedTo(name, n),\n }\n }\n\n private assertOnline(): void {\n if (this.adapter.capabilities?.casAtomic !== true) {\n throw new SequenceOfflineError()\n }\n }\n\n private dek(): Promise<CryptoKey> {\n if (!this.dekPromise) this.dekPromise = this.getDEK(SEQUENCE_COLLECTION)\n return this.dekPromise\n }\n\n private async read(name: string): Promise<{ env: EncryptedEnvelope | null; value: number }> {\n const env = await this.adapter.get(this.vault, SEQUENCE_COLLECTION, name)\n if (!env) return { env: null, value: 0 }\n const json = this.encrypted ? await decrypt(env._iv, env._data, await this.dek()) : env._data\n const state = JSON.parse(json) as SequenceState\n return { env, value: state.value }\n }\n\n private async encryptState(state: SequenceState, version: number): Promise<EncryptedEnvelope> {\n const json = JSON.stringify(state)\n if (!this.encrypted) {\n return { _noydb: NOYDB_FORMAT_VERSION, _v: version, _ts: new Date().toISOString(), _iv: '', _data: json, _by: this.actor }\n }\n const { iv, data } = await encrypt(json, await this.dek())\n return { _noydb: NOYDB_FORMAT_VERSION, _v: version, _ts: new Date().toISOString(), _iv: iv, _data: data, _by: this.actor }\n }\n\n async peek(name: string): Promise<number> {\n return (await this.read(name)).value\n }\n\n async next(name: string): Promise<number> {\n this.assertOnline()\n let lastConflict: ConflictError | undefined\n for (let attempt = 0; attempt < MAX_NEXT_ATTEMPTS; attempt++) {\n const { env, value } = await this.read(name)\n const nextValue = value + 1\n const expectedVersion = env?._v ?? 0 // 0 ≡ \"must not yet exist\" (create)\n const envelope = await this.encryptState({ value: nextValue }, expectedVersion + 1)\n try {\n await this.adapter.put(this.vault, SEQUENCE_COLLECTION, name, envelope, expectedVersion)\n return nextValue\n } catch (err) {\n if (err instanceof ConflictError) {\n lastConflict = err\n if (attempt < MAX_NEXT_ATTEMPTS - 1) await sleepBackoff(attempt)\n continue\n }\n throw err\n }\n }\n void lastConflict\n throw new SequenceContentionError(name, MAX_NEXT_ATTEMPTS)\n }\n\n async seedTo(name: string, n: number): Promise<void> {\n this.assertOnline()\n if (n <= 0) return // set-if-greater: 0 (and any non-positive seed) is a no-op\n let lastConflict: ConflictError | undefined\n for (let attempt = 0; attempt < MAX_NEXT_ATTEMPTS; attempt++) {\n const { env, value } = await this.read(name)\n if (value >= n) return // already at or past the floor — no write, idempotent\n const expectedVersion = env?._v ?? 0 // 0 ≡ \"must not yet exist\" (create)\n const envelope = await this.encryptState({ value: n }, expectedVersion + 1)\n try {\n await this.adapter.put(this.vault, SEQUENCE_COLLECTION, name, envelope, expectedVersion)\n return\n } catch (err) {\n if (err instanceof ConflictError) {\n lastConflict = err\n if (attempt < MAX_NEXT_ATTEMPTS - 1) await sleepBackoff(attempt)\n continue\n }\n throw err\n }\n }\n void lastConflict\n throw new SequenceContentionError(name, MAX_NEXT_ATTEMPTS)\n }\n}\n","/**\n * @category capability\n * Deferred numbering engine — store-clock-ordered, gap-free serials assigned\n * at an explicit numbering pass. See the design spec.\n */\nimport type { NoydbStore, EncryptedEnvelope, StoreTime } from '../types.js'\nimport { NOYDB_FORMAT_VERSION } from '../types.js'\nimport { encrypt, decrypt } from '../crypto.js'\nimport { ConflictError, NumberingUncertaintyError } from '../errors.js'\nimport type { DeferredNumberingConfig } from './descriptor.js'\n\nexport const NUMBERING_HEAD_COLLECTION = '_numbering_head'\nexport const NUMBERING_PENDING_COLLECTION = '_numbering_pending'\n\ninterface PendingEntry {\n series: string\n recordId: string\n collection: string\n field: string\n storeEarliest: number\n storeLatest: number\n enqueuedAt: number\n}\ninterface NumberingHead { series: string; lastSerial: number; watermark: number }\nexport interface Assignment { recordId: string; serial: number }\n\ntype PendingPromise = { resolve: (n: number) => void; reject: (e: Error) => void }\n\nexport class DeferredNumberingStore {\n private readonly adapter: NoydbStore\n private readonly vault: string\n private readonly encrypted: boolean\n private readonly getDEK: (collectionName: string) => Promise<CryptoKey>\n private readonly actor: string\n private readonly configs: Map<string, DeferredNumberingConfig>\n /**\n * Stamp a serial onto a USER record THROUGH the Collection layer (so the\n * cache, indexes, and MVs stay coherent — the engine must NOT write user\n * collections at the raw adapter level). Returns false if the record is\n * gone (the engine then skips it without burning a serial). Provided by the\n * vault; unit tests pass a Map-backed double.\n */\n private readonly stamp: (collection: string, recordId: string, field: string, serial: number) => Promise<boolean>\n /** In-process registry: `${series}::${recordId}` → resolver for the live next() Promise. */\n private readonly waiters = new Map<string, PendingPromise>()\n private readonly dekCache = new Map<string, Promise<CryptoKey>>()\n\n constructor(opts: {\n adapter: NoydbStore\n vault: string\n encrypted: boolean\n getDEK: (collectionName: string) => Promise<CryptoKey>\n actor: string\n configs: Map<string, DeferredNumberingConfig>\n stamp: (collection: string, recordId: string, field: string, serial: number) => Promise<boolean>\n }) {\n this.adapter = opts.adapter\n this.vault = opts.vault\n this.encrypted = opts.encrypted\n this.getDEK = opts.getDEK\n this.actor = opts.actor\n this.configs = opts.configs\n this.stamp = opts.stamp\n }\n\n has(series: string): boolean {\n return this.configs.has(series)\n }\n\n private dek(collection: string): Promise<CryptoKey> {\n let p = this.dekCache.get(collection)\n if (!p) { p = this.getDEK(collection); this.dekCache.set(collection, p) }\n return p\n }\n\n private async readJson<T>(collection: string, id: string): Promise<{ env: EncryptedEnvelope | null; value: T | null }> {\n const env = await this.adapter.get(this.vault, collection, id)\n if (!env) return { env: null, value: null }\n const json = this.encrypted ? await decrypt(env._iv, env._data, await this.dek(collection)) : env._data\n return { env, value: JSON.parse(json) as T }\n }\n\n private async writeJson(collection: string, id: string, value: unknown, expectedVersion: number): Promise<void> {\n const json = JSON.stringify(value)\n let env: EncryptedEnvelope\n if (!this.encrypted) {\n env = { _noydb: NOYDB_FORMAT_VERSION, _v: expectedVersion + 1, _ts: new Date().toISOString(), _iv: '', _data: json, _by: this.actor }\n } else {\n const { iv, data } = await encrypt(json, await this.dek(collection))\n env = { _noydb: NOYDB_FORMAT_VERSION, _v: expectedVersion + 1, _ts: new Date().toISOString(), _iv: iv, _data: data, _by: this.actor }\n }\n await this.adapter.put(this.vault, collection, id, env, expectedVersion)\n }\n\n private pendingId(series: string, recordId: string): string {\n return `${series}::${recordId}`\n }\n\n /** Current last-assigned serial for a series (0 if none). */\n async peek(series: string): Promise<number> {\n const { value } = await this.readJson<NumberingHead>(NUMBERING_HEAD_COLLECTION, series)\n return value?.lastSerial ?? 0\n }\n\n /**\n * Enqueue a record for numbering: stamp it with the current store clock and\n * durably write a pending entry. The returned Promise resolves once the\n * record is durably enqueued; its `assigned` field resolves with the serial\n * at the next pass (the record's `field` is the durable source of truth —\n * `assigned` is an in-process convenience that a crash may drop).\n */\n async enqueue(series: string, recordId: string): Promise<{ assigned: Promise<number> }> {\n const cfg = this.configs.get(series)\n if (!cfg) throw new NumberingUncertaintyError(series)\n if (typeof this.adapter.getStoreTime !== 'function') throw new NumberingUncertaintyError(series)\n const st: StoreTime = await this.adapter.getStoreTime()\n const id = this.pendingId(series, recordId)\n const { env } = await this.readJson<PendingEntry>(NUMBERING_PENDING_COLLECTION, id)\n const entry: PendingEntry = {\n series, recordId, collection: cfg.collection, field: cfg.field,\n storeEarliest: st.earliest, storeLatest: st.latest, enqueuedAt: Date.now(),\n }\n await this.writeJson(NUMBERING_PENDING_COLLECTION, id, entry, env?._v ?? 0)\n const assigned = new Promise<number>((resolve, reject) => { this.waiters.set(id, { resolve, reject }) })\n return { assigned }\n }\n\n private async listPending(series: string): Promise<Array<{ id: string; entry: PendingEntry }>> {\n const ids = await this.adapter.list(this.vault, NUMBERING_PENDING_COLLECTION)\n const prefix = `${series}::`\n const out: Array<{ id: string; entry: PendingEntry }> = []\n for (const id of ids) {\n if (!id.startsWith(prefix)) continue\n const { value } = await this.readJson<PendingEntry>(NUMBERING_PENDING_COLLECTION, id)\n if (value) out.push({ id, entry: value })\n }\n return out\n }\n\n /**\n * Run a numbering pass for `series`: select entries provably settled\n * (`storeLatest ≤ now.earliest` — commit-wait), order by\n * `(storeEarliest, recordId)`, assign serials after the head, stamp each\n * record's field, advance the head with one CAS, and consume the entries.\n * Idempotent/convergent: a losing concurrent pass returns `[]` and the next\n * pass reconciles. Resolves any in-process enqueue() `assigned` Promises.\n */\n async runPass(series: string): Promise<Assignment[]> {\n const cfg = this.configs.get(series)\n if (!cfg) throw new NumberingUncertaintyError(series)\n if (typeof this.adapter.getStoreTime !== 'function') throw new NumberingUncertaintyError(series)\n\n const now = await this.adapter.getStoreTime()\n const settled = (await this.listPending(series))\n .filter(p => p.entry.storeLatest <= now.earliest) // commit-wait\n .sort((a, b) =>\n a.entry.storeEarliest - b.entry.storeEarliest ||\n (a.entry.recordId < b.entry.recordId ? -1 : a.entry.recordId > b.entry.recordId ? 1 : 0),\n )\n if (settled.length === 0) return []\n\n const { env: headEnv, value: head } = await this.readJson<NumberingHead>(NUMBERING_HEAD_COLLECTION, series)\n let serial = head?.lastSerial ?? 0\n const assignments: Assignment[] = []\n\n // Stamp each user record THROUGH the Collection layer (cache-coherent).\n for (const { entry } of settled) {\n serial += 1\n const ok = await this.stamp(entry.collection, entry.recordId, entry.field, serial)\n if (!ok) { serial -= 1; continue } // record gone — skip, do not burn a number\n assignments.push({ recordId: entry.recordId, serial })\n }\n\n // Advance the head with one CAS. On conflict another pass ran; bail — the\n // next pass reconciles (idempotent: consumed entries won't reappear).\n try {\n await this.writeJson(NUMBERING_HEAD_COLLECTION, series, { series, lastSerial: serial, watermark: now.earliest }, headEnv?._v ?? 0)\n } catch (err) {\n if (err instanceof ConflictError) return []\n throw err\n }\n\n // Consume pending entries + resolve in-process waiters.\n for (const { id, entry } of settled) {\n await this.adapter.delete(this.vault, NUMBERING_PENDING_COLLECTION, id)\n const a = assignments.find(x => x.recordId === entry.recordId)\n if (a) { this.waiters.get(id)?.resolve(a.serial); this.waiters.delete(id) }\n }\n return assignments\n }\n}\n","/**\n * Strategy seam for the optional VaultFrame snapshot primitive.\n * Core imports `ShadowStrategy` as TYPE-ONLY and `NO_SHADOW` as a\n * 4-line stub. `VaultFrame` is only constructed inside `withShadow()`\n * — consumers who never import `@noy-db/hub/shadow` ship none of\n * the ~129 LOC.\n *\n * @internal\n */\n\nimport type { VaultFrame } from './vault-frame.js'\n\n/**\n * @internal\n */\nexport interface ShadowStrategy {\n /**\n * Build a `VaultFrame` bound to the given vault. The factory type\n * is kept loose (`unknown`) to avoid a core → shadow type\n * dependency — the consumer always calls this through\n * `vault.frame()`, which returns `VaultFrame` at its surface.\n */\n buildFrame(vault: unknown): VaultFrame\n}\n\nconst NOT_ENABLED = new Error(\n 'VaultFrame requires the shadow strategy. Import `{ withShadow }` ' +\n 'from \"@noy-db/hub/shadow\" and pass it to ' +\n '`createNoydb({ shadowStrategy: withShadow() })`.',\n)\n\n/**\n * No-shadow stub.\n *\n * @internal\n */\nexport const NO_SHADOW: ShadowStrategy = {\n buildFrame() { throw NOT_ENABLED },\n}\n","/**\n * Strategy seam for the optional consent-audit subsystem. Core\n * imports `ConsentStrategy` as a TYPE-ONLY symbol and `NO_CONSENT`\n * as a tiny runtime stub.\n *\n * `writeConsentEntry` / `loadConsentEntries` are only reachable from\n * `withConsent()` in `./active.ts`, exported through\n * `@noy-db/hub/consent`. Applications without a consent scope ship\n * none of the ~194 LOC.\n *\n * @internal\n */\n\nimport type { NoydbStore } from '../types.js'\nimport type {\n ConsentAuditEntry,\n ConsentAuditFilter,\n} from './consent.js'\n\n/**\n * @internal\n */\nexport interface ConsentStrategy {\n /**\n * Record one consent audit entry. No-op under NO_CONSENT.\n */\n write(\n adapter: NoydbStore,\n vault: string,\n encrypted: boolean,\n entry: Omit<ConsentAuditEntry, 'id' | 'timestamp'>,\n getDEK: (collectionName: string) => Promise<CryptoKey>,\n ): Promise<void>\n\n /**\n * Read filtered consent entries. Returns `[]` under NO_CONSENT.\n */\n read(\n adapter: NoydbStore,\n vault: string,\n encrypted: boolean,\n getDEK: (collectionName: string) => Promise<CryptoKey>,\n filter?: ConsentAuditFilter,\n ): Promise<ConsentAuditEntry[]>\n}\n\n/**\n * No-consent stub. `write` is a no-op (returns a resolved promise);\n * `read` returns `[]`. Consumers get a consistent API surface without\n * pulling the consent module into the bundle.\n *\n * @internal\n */\nexport const NO_CONSENT: ConsentStrategy = {\n async write() {},\n async read() { return [] },\n}\n","/**\n * Strategy seam for the optional accounting-periods subsystem. Core\n * imports `PeriodsStrategy` type-only + `NO_PERIODS` stub; the real\n * `loadPeriods` / `chainAnchor` / `assertTsWritable` /\n * `validatePeriodName` / `appendPeriodLedgerEntry` functions are\n * only reachable via `withPeriods()` in `./active.ts`.\n *\n * Applications that never call `vault.closePeriod()` /\n * `vault.openPeriod()` ship none of the ~363 LOC.\n *\n * @internal\n */\n\nimport type { EncryptedEnvelope, NoydbStore } from '../types.js'\nimport type { LedgerStore } from '../history/ledger/store.js'\nimport type { PeriodRecord } from './periods.js'\n\n/**\n * @internal\n */\nexport interface PeriodsStrategy {\n loadPeriods(\n adapter: NoydbStore,\n vault: string,\n decrypt: (envelope: EncryptedEnvelope) => Promise<PeriodRecord>,\n ): Promise<PeriodRecord[]>\n chainAnchor(records: readonly PeriodRecord[]): Promise<{\n priorPeriodName?: string\n priorPeriodHash: string\n }>\n assertTsWritable(\n existing: { ts: string | null; record: Record<string, unknown> | null } | null,\n incoming: Record<string, unknown> | null,\n periods: readonly PeriodRecord[],\n ): void\n validatePeriodName(name: string, existing: readonly PeriodRecord[]): void\n appendPeriodLedgerEntry(\n ledger: LedgerStore | null,\n actor: string,\n envelope: EncryptedEnvelope,\n periodName: string,\n ): Promise<void>\n}\n\n/**\n * No-periods stub. `loadPeriods` returns `[]`; the write-guards do\n * nothing (vaults without closed periods never reject writes);\n * `validatePeriodName` / `appendPeriodLedgerEntry` throw because\n * those paths are only reached when the user explicitly called\n * `closePeriod()` / `openPeriod()` — if they did that without the\n * strategy, they need to wire it.\n *\n * @internal\n */\nconst NOT_ENABLED = new Error(\n 'Accounting periods require the periods strategy. Import ' +\n '`{ withPeriods }` from \"@noy-db/hub/periods\" and pass it to ' +\n '`createNoydb({ periodsStrategy: withPeriods() })`.',\n)\n\nexport const NO_PERIODS: PeriodsStrategy = {\n async loadPeriods() { return [] },\n async chainAnchor() { return { priorPeriodHash: '' } },\n assertTsWritable() {},\n validatePeriodName() { throw NOT_ENABLED },\n async appendPeriodLedgerEntry() { throw NOT_ENABLED },\n}\n","/**\n * Foreign-key references — the soft-FK mechanism.\n *\n * A collection declares its references as metadata at construction\n * time:\n *\n * ```ts\n * import { ref } from '@noy-db/hub'\n *\n * const invoices = company.collection<Invoice>('invoices', {\n * refs: {\n * clientId: ref('clients'), // default: strict\n * categoryId: ref('categories', 'warn'),\n * parentId: ref('invoices', 'cascade'), // self-reference OK\n * },\n * })\n * ```\n *\n * Three modes:\n *\n * - **strict** — the default. `put()` rejects records whose\n * reference target doesn't exist, and `delete()` of the target\n * rejects if any strict-referencing records still exist.\n * Matches SQL's default FK semantics.\n *\n * - **warn** — both operations succeed unconditionally. Broken\n * references surface only through\n * `vault.checkIntegrity()`, which walks every collection\n * and reports orphans. Use when you want soft validation for\n * imports from messy sources.\n *\n * - **cascade** — `put()` is same as warn. `delete()` of the\n * target deletes every referencing record. Cycles are detected\n * and broken via an in-progress set, so mutual cascades\n * terminate instead of recursing forever.\n *\n * Cross-vault refs are explicitly rejected: if the target\n * name contains a `/`, `ref()` throws `RefScopeError`. Cross-\n * vault refs need an auth story (multi-keyring reads) that\n * doesn't ship — tracked for.\n */\n\nimport { NoydbError } from './errors.js'\n\n/** The three enforcement modes. Default for new refs is `'strict'`. */\nexport type RefMode = 'strict' | 'warn' | 'cascade'\n\n/**\n * Descriptor returned by `ref()`. Collections accept a\n * `Record<string, RefDescriptor>` in their options. The key is the\n * field name on the record (top-level only — dotted paths are out of\n * scope), the value describes which target collection the\n * field references and under what mode.\n *\n * The descriptor carries only plain data so it can be serialized,\n * passed around, and introspected without any class machinery.\n */\nexport interface RefDescriptor {\n readonly target: string\n readonly mode: RefMode\n}\n\n/**\n * Thrown when a strict reference is violated — either `put()` with a\n * missing target id, or `delete()` of a target that still has\n * strict-referencing records.\n *\n * Carries structured detail so UI code (and a potential future\n * devtools panel) can render \"client X cannot be deleted because\n * invoices 1, 2, and 3 reference it\" instead of a bare error string.\n */\nexport class RefIntegrityError extends NoydbError {\n readonly collection: string\n readonly id: string\n readonly field: string\n readonly refTo: string\n readonly refId: string | null\n\n constructor(opts: {\n collection: string\n id: string\n field: string\n refTo: string\n refId: string | null\n message: string\n }) {\n super('REF_INTEGRITY', opts.message)\n this.name = 'RefIntegrityError'\n this.collection = opts.collection\n this.id = opts.id\n this.field = opts.field\n this.refTo = opts.refTo\n this.refId = opts.refId\n }\n}\n\n/**\n * Thrown when `ref()` is called with a target name that looks like\n * a cross-vault reference (contains a `/`). Separate error\n * class because the fix is different: RefIntegrityError means \"data\n * is wrong\"; RefScopeError means \"the ref declaration is wrong\".\n */\nexport class RefScopeError extends NoydbError {\n constructor(target: string) {\n super(\n 'REF_SCOPE',\n `Cross-vault references are not supported in — got target \"${target}\". ` +\n `Use a simple collection name (e.g. \"clients\"), not a path. ` +\n `Cross-vault refs are tracked for a future release.`,\n )\n this.name = 'RefScopeError'\n }\n}\n\n/**\n * Helper constructor. Thin wrapper around the object literal so user\n * code reads like `ref('clients')` instead of `{ target: 'clients',\n * mode: 'strict' }` — this is the only ergonomics reason it exists.\n *\n * Validates the target name eagerly so a misconfigured ref declaration\n * fails at collection construction time, not at the first put.\n */\nexport function ref(target: string, mode: RefMode = 'strict'): RefDescriptor {\n if (target.includes('/')) {\n throw new RefScopeError(target)\n }\n if (!target || target.startsWith('_')) {\n throw new Error(\n `ref(): target collection name must be non-empty and cannot start with '_' (reserved for internal collections). Got \"${target}\".`,\n )\n }\n return { target, mode }\n}\n\n/**\n * Per-vault registry of reference declarations.\n *\n * The registry is populated by `Collection` constructors (which pass\n * their `refs` option through the Vault) and consulted by the\n * Vault on every `put` / `delete` and by `checkIntegrity`. A\n * single instance lives on the Vault for its lifetime; there's\n * no global state.\n *\n * The data structure is two parallel maps:\n *\n * - `outbound`: `collection → { field → RefDescriptor }` — what\n * refs does `collection` declare? Used on put to check\n * strict-target-exists and on checkIntegrity to walk each\n * collection's outbound refs.\n *\n * - `inbound`: `target → Array<{ collection, field, mode }>` —\n * which collections reference `target`? Used on delete to find\n * the records that might be affected by cascade / strict.\n *\n * The two views are kept in sync by `register()` and never mutated\n * otherwise — refs can't be unregistered at runtime in.\n */\nexport class RefRegistry {\n private readonly outbound = new Map<string, Record<string, RefDescriptor>>()\n private readonly inbound = new Map<\n string,\n Array<{ collection: string; field: string; mode: RefMode }>\n >()\n\n /**\n * Register the refs declared by a single collection. Idempotent in\n * the happy path — calling twice with the same data is a no-op.\n * Calling twice with DIFFERENT data throws, because silent\n * overrides would be confusing (\"I changed the ref and it doesn't\n * update\" vs \"I declared the same collection twice with different\n * refs and the second call won\").\n */\n register(collection: string, refs: Record<string, RefDescriptor>): void {\n const existing = this.outbound.get(collection)\n if (existing) {\n // Compare shallowly — if any field disagrees, reject.\n const existingKeys = Object.keys(existing).sort()\n const newKeys = Object.keys(refs).sort()\n if (existingKeys.join(',') !== newKeys.join(',')) {\n throw new Error(\n `RefRegistry: conflicting ref declarations for collection \"${collection}\"`,\n )\n }\n for (const k of existingKeys) {\n const a = existing[k]\n const b = refs[k]\n if (!a || !b || a.target !== b.target || a.mode !== b.mode) {\n throw new Error(\n `RefRegistry: conflicting ref declarations for collection \"${collection}\" field \"${k}\"`,\n )\n }\n }\n return\n }\n this.outbound.set(collection, { ...refs })\n for (const [field, desc] of Object.entries(refs)) {\n const list = this.inbound.get(desc.target) ?? []\n list.push({ collection, field, mode: desc.mode })\n this.inbound.set(desc.target, list)\n }\n }\n\n /** Get the outbound refs declared by a collection (or `{}` if none). */\n getOutbound(collection: string): Record<string, RefDescriptor> {\n return this.outbound.get(collection) ?? {}\n }\n\n /** Get the inbound refs that target a given collection (or `[]`). */\n getInbound(\n target: string,\n ): ReadonlyArray<{ collection: string; field: string; mode: RefMode }> {\n return this.inbound.get(target) ?? []\n }\n\n /**\n * Iterate every (collection → refs) pair that has at least one\n * declared reference. Used by `checkIntegrity` to walk the full\n * universe of outbound refs without needing to track collection\n * names elsewhere.\n */\n entries(): Array<[string, Record<string, RefDescriptor>]> {\n return [...this.outbound.entries()]\n }\n\n /** Clear the registry. Test-only escape hatch; never called from production code. */\n clear(): void {\n this.outbound.clear()\n this.inbound.clear()\n }\n}\n\n/**\n * Shape of a single violation reported by `vault.checkIntegrity()`.\n *\n * `refId` is the value we saw in the referencing field — it's the\n * ID we expected to find in `refTo`, but didn't. Left as `unknown`\n * because records are loosely typed at the integrity-check layer.\n */\nexport interface RefViolation {\n readonly collection: string\n readonly id: string\n readonly field: string\n readonly refTo: string\n readonly refId: unknown\n readonly mode: RefMode\n}\n","/**\n * Public `vault.user.*` API surface.\n *\n * Three families:\n * - Write-self: `me` / `updateMe` / `setMe` — always target the writer's\n * own keyringId. **Own-only write rule** is structural — no method\n * exists to write someone else's envelope.\n * - Read-anyone: `get` / `list` — read other principals' envelopes\n * (subject to `view-team-profiles` policy gate).\n * - Reactive: `subscribe` / `live` — in-process event emission on local\n * writes. Cross-instance updates land via the team/sync engine and\n * surface to subscribers when the sync diff replays through this API.\n *\n * @see docs/superpowers/specs/2026-05-05-user-envelope-design.md\n *\n * @module\n */\nimport type { NoydbStore } from '../../types.js'\nimport { PolicyDeniedError } from '../../policy/errors.js'\nimport type { FactorProof } from '../../policy/types.js'\nimport {\n loadUserEnvelope,\n saveUserEnvelope,\n listUserEnvelopeIds,\n} from './storage.js'\nimport type { UserEnvelope } from './types.js'\nimport {\n persistUserVisibility,\n readUserVisibility,\n} from '../../directory/visibility.js'\nimport type { UserVisibility } from '../../directory/types.js'\n\n/**\n * Recursive partial. Used for `updateMe(patch)` so callers can hand in\n * deeply-nested partial shapes and have them deep-merged onto the\n * current envelope.\n */\nexport type DeepPartial<T> = T extends object\n ? { [P in keyof T]?: DeepPartial<T[P]> }\n : T\n\n/**\n * Recursive partial with `null` allowed at every level — used by\n * `updateMe` to express deletion intent in addition to merge.\n *\n * Semantics inside `updateMe`:\n * - `undefined` (or absent key) — skip; source value preserved\n * - `null` — delete the key from the resulting envelope\n * - any other value — overwrite (deep-merge for plain objects,\n * replace for primitives / arrays)\n *\n * Matches lodash `_.merge` behavior on `null` and Firestore's\n * `FieldValue.delete()` semantics. Loosened from `DeepPartial<T>`.\n * Consumers wanting the original \"merge-only\" surface can keep\n * importing `DeepPartial` and avoid passing `null`.\n */\nexport type DeepPartialOrNull<T> = T extends object\n ? { [P in keyof T]?: DeepPartialOrNull<T[P]> | null }\n : T\n\n/** Cancel a previously-registered subscription. */\nexport type Unsubscribe = () => void\n\n/**\n * Optional factor-proof bundle threaded into gated user-envelope\n * operations. Same shape as `Noydb.checkGate(vault, gate, presented)`\n * accepts elsewhere — apps that have already presented a TOTP/email-OTP\n * for this session pass it here to satisfy tightened policies.\n */\nexport interface UserEnvelopePresented {\n readonly factors?: readonly FactorProof[]\n readonly sharedDevice?: boolean\n}\n\n/**\n * Callback used by `UserApi` to validate the active session against a\n * policy gate. Provided by the `Vault` constructor; in production this\n * delegates to `Noydb.checkGate(vault, gate, presented)`. In tests, a\n * no-op stub is fine.\n */\nexport type UserEnvelopeCheckGate = (\n gate: 'edit-own-profile' | 'view-team-profiles',\n presented?: UserEnvelopePresented,\n) => Promise<void>\n\n/**\n * Reactive handle returned by `live()`. `current` is the most recently\n * observed value; `subscribe(cb)` fires on subsequent local writes.\n * `stop()` releases the underlying subscription.\n */\nexport interface LiveUserEnvelope<T> {\n current(): UserEnvelope<T> | null\n subscribe(cb: (env: UserEnvelope<T> | null) => void): Unsubscribe\n stop(): void\n}\n\ninterface ChangeListener<T = unknown> {\n (env: UserEnvelope<T> | null): void\n}\n\n/**\n * Implementation behind `vault.user`. Constructed once per Vault, holds\n * the writer's keyringId in closure so `updateMe`/`setMe` cannot target\n * any other principal — the own-only rule is enforced at the type level\n * (no `set(otherKeyringId, …)` method) AND at runtime (the\n * keyringId argument simply doesn't exist on the write path).\n */\nexport class UserApi {\n /** keyringId → set of listeners. Wildcard '*' fires on every change. */\n private readonly listeners = new Map<string, Set<ChangeListener>>()\n\n constructor(\n private readonly adapter: NoydbStore,\n private readonly vaultName: string,\n /** The writer's own keyringId. Frozen at construction time. */\n private readonly writerKeyringId: string,\n private readonly getDek: () => Promise<CryptoKey>,\n /**\n * Policy-gate validator. When omitted, gates are skipped — useful\n * for low-level tests that exercise the storage layer directly.\n * Production paths always wire the Noydb-backed implementation.\n */\n private readonly checkGate?: UserEnvelopeCheckGate,\n ) {}\n\n // ─── Write-self ──────────────────────────────────────────────────────\n\n /** Read the writer's own envelope. Returns null if never written. */\n async me<T = unknown>(): Promise<UserEnvelope<T> | null> {\n const dek = await this.getDek()\n return loadUserEnvelope<T>(this.adapter, this.vaultName, this.writerKeyringId, dek)\n }\n\n /**\n * Deep-merge a partial patch into the writer's own envelope. Creates\n * the envelope on first call. Optimistic-concurrency safe — a stale\n * `_v` (parallel writer on another device) throws `ConflictError`.\n *\n * Patch semantics:\n * - `undefined` (or omitted key) — skip; existing value preserved\n * - `null` — delete the field from the merged result\n * - any other value — overwrite (deep-merge for plain objects,\n * replace for primitives / arrays)\n *\n * To clear a field, pass `null` rather than `undefined`. Callers\n * with shape `T = string | null` where `null` is a meaningful value\n * should use `setMe` for that specific field instead — `null` here\n * always means delete.\n *\n * Gated by the `edit-own-profile` policy gate (default `minTier: 3`).\n * Pass `presented` to satisfy tightened policies that require a\n * factor proof (e.g. STRICT_POLICY's TOTP requirement).\n */\n async updateMe<T extends object = Record<string, unknown>>(\n patch: DeepPartialOrNull<T>,\n presented?: UserEnvelopePresented,\n ): Promise<UserEnvelope<T>> {\n if (this.checkGate) await this.checkGate('edit-own-profile', presented)\n const dek = await this.getDek()\n const current = await loadUserEnvelope<T>(\n this.adapter,\n this.vaultName,\n this.writerKeyringId,\n dek,\n )\n const merged: T = current ? deepMerge(current.data, patch) : (patch as unknown as T)\n const written = await saveUserEnvelope<T>(\n this.adapter,\n this.vaultName,\n this.writerKeyringId,\n merged,\n dek,\n current?._v ?? 0,\n )\n this.fireChange(this.writerKeyringId, written)\n return written\n }\n\n /**\n * Replace the writer's own envelope with `payload`. Use sparingly —\n * `updateMe` is the canonical mutation. No `expectedVersion` check;\n * callers explicitly take last-write-wins semantics.\n *\n * Gated by `edit-own-profile`. See `updateMe` for `presented` usage.\n */\n async setMe<T = unknown>(\n payload: T,\n presented?: UserEnvelopePresented,\n ): Promise<UserEnvelope<T>> {\n if (this.checkGate) await this.checkGate('edit-own-profile', presented)\n const dek = await this.getDek()\n const written = await saveUserEnvelope<T>(\n this.adapter,\n this.vaultName,\n this.writerKeyringId,\n payload,\n dek,\n )\n this.fireChange(this.writerKeyringId, written)\n return written\n }\n\n // ─── Visibility ──────────────────────────────────────────────────────\n\n /**\n * Read the current user's visibility flag from\n * `_meta/visibility/<keyringId>`. Returns `{ hidden: false }` when no\n * document has been persisted (the default-visible case).\n */\n async getMyVisibility(): Promise<UserVisibility> {\n const persisted = await readUserVisibility(this.adapter, this.vaultName, this.writerKeyringId)\n return persisted ?? { hidden: false }\n }\n\n /**\n * Update the current user's visibility in the team directory.\n *\n * - `hidden: true` — opt out of the default `listUsersWithEnvelopes`\n * listing. `owner`/`admin` callers can still see the user by passing\n * `{ includeHidden: true }`.\n * - `hidden: false` — opt back in.\n *\n * Own-only by construction: the keyringId argument doesn't exist on\n * this method, so no caller can hide or unhide another principal.\n *\n * Honest caveat: this is a UX flag, not a privacy guarantee. The\n * envelope ciphertext at `_users/<keyringId>` and the keyring file at\n * `_keyring/<userId>` are both still observable to anyone with direct\n * store read access. See `docs/subsystems/user-envelope.md` →\n * \"Directory visibility\".\n */\n async setMyVisibility(visibility: UserVisibility): Promise<void> {\n await persistUserVisibility(\n this.adapter,\n this.vaultName,\n this.writerKeyringId,\n { hidden: visibility.hidden },\n )\n }\n\n // ─── Read-anyone ─────────────────────────────────────────────────────\n\n /**\n * Read another principal's envelope by their keyringId. Returns null\n * if the principal exists but has no envelope yet, or if the\n * keyringId does not exist at all.\n *\n * Gated by `view-team-profiles` (default `minTier: 2`) — but ONLY for\n * cross-principal reads. Reading your own envelope (`keyringId ===\n * self`) is never gated; that's just `me()` written long-form.\n */\n async get<T = unknown>(\n keyringId: string,\n presented?: UserEnvelopePresented,\n ): Promise<UserEnvelope<T> | null> {\n if (this.checkGate && keyringId !== this.writerKeyringId) {\n await this.checkGate('view-team-profiles', presented)\n }\n const dek = await this.getDek()\n return loadUserEnvelope<T>(this.adapter, this.vaultName, keyringId, dek)\n }\n\n /**\n * Read every persisted envelope in the vault. Order is store-defined.\n *\n * Gated by `view-team-profiles`. Default policy (`minTier: 2`) lets\n * any authenticated session read all envelopes. Two privacy-strict\n * opt-outs:\n *\n * - `view-team-profiles.enabled: false` → list() returns only the\n * caller's own envelope (silent self-fallback, no thrown error).\n * - `view-team-profiles.minTier: 1` + insufficient tier → throws\n * `PolicyDeniedError` with `reason: 'insufficient-tier'`. The\n * caller is expected to elevate, not silently degrade.\n *\n * The asymmetry is deliberate: `enabled: false` is a deliberate\n * design choice (\"nobody sees teammate profiles in this app\");\n * `insufficient-tier` is \"you need to authenticate further\". Different\n * UX prompts for different intents.\n */\n async list<T = unknown>(presented?: UserEnvelopePresented): Promise<UserEnvelope<T>[]> {\n if (this.checkGate) {\n try {\n await this.checkGate('view-team-profiles', presented)\n } catch (err) {\n if (err instanceof PolicyDeniedError && err.reason === 'disabled') {\n // Privacy-strict opt-out: quietly return only self.\n const me = await this.me<T>()\n return me ? [me] : []\n }\n throw err\n }\n }\n const dek = await this.getDek()\n const ids = await listUserEnvelopeIds(this.adapter, this.vaultName)\n const envelopes = await Promise.all(\n ids.map((id) => loadUserEnvelope<T>(this.adapter, this.vaultName, id, dek)),\n )\n return envelopes.filter((e): e is UserEnvelope<T> => e !== null)\n }\n\n // ─── Reactive ────────────────────────────────────────────────────────\n\n /**\n * Listen for changes to a specific keyringId's envelope. The callback\n * fires synchronously after every successful local `updateMe` /\n * `setMe` for that principal.\n *\n * Cross-instance changes (a teammate edits their profile on their\n * device, the sync engine pulls the diff onto this device) will fire\n * subscribers when the sync layer replays the write through this API.\n * In v1, subscribers do NOT fire on raw store changes — wire your sync\n * layer to call back through `vault.user.setMe` / `updateMe` if you\n * need that.\n *\n * Pass keyringId `'*'` to fire on every change in the vault.\n */\n subscribe<T = unknown>(\n keyringId: string,\n cb: (env: UserEnvelope<T> | null) => void,\n ): Unsubscribe {\n let listeners = this.listeners.get(keyringId)\n if (!listeners) {\n listeners = new Set()\n this.listeners.set(keyringId, listeners)\n }\n const wrapped: ChangeListener = cb as ChangeListener\n listeners.add(wrapped)\n return () => {\n listeners?.delete(wrapped)\n if (listeners && listeners.size === 0) {\n this.listeners.delete(keyringId)\n }\n }\n }\n\n /**\n * Reactive handle that caches the current value and re-reads on every\n * change for the given keyringId. Convenient for framework bindings:\n *\n * const live = vault.user.live<UserShape>(vault.userId)\n * live.subscribe(env => render(env?.data))\n *\n * Initial value is `null` until the first `current()` call materializes\n * it via `vault.user.get()`. Call `stop()` when done to release the\n * subscription.\n */\n live<T = unknown>(keyringId: string): LiveUserEnvelope<T> {\n let value: UserEnvelope<T> | null = null\n let primed = false\n const unsubscribe = this.subscribe<T>(keyringId, (env) => {\n value = env\n })\n\n return {\n current(): UserEnvelope<T> | null {\n if (!primed) {\n primed = true\n // First call: kick off a read but return synchronously. The\n // subscriber will be re-fired by the next write or the caller\n // can await `vault.user.get()` directly for an immediate read.\n }\n return value\n },\n subscribe: (cb) => this.subscribe<T>(keyringId, cb),\n stop: unsubscribe,\n }\n }\n\n // ─── Internal: change emission ───────────────────────────────────────\n\n private fireChange<T>(keyringId: string, env: UserEnvelope<T> | null): void {\n const targeted = this.listeners.get(keyringId)\n if (targeted) for (const l of targeted) l(env)\n const wildcard = this.listeners.get('*')\n if (wildcard) for (const l of wildcard) l(env)\n }\n}\n\n/**\n * Recursive plain-object deep merge with delete intent.\n *\n * Patch semantics:\n * - `undefined` — skip the key; source value preserved\n * - `null` — delete the key from output (lodash `_.merge` /\n * Firestore `FieldValue.delete()` semantics)\n * - plain object — recurse (deep merge)\n * - any other value — replace (arrays are replaced, not concatenated)\n *\n * Safe against the JS quirk where an own property explicitly set to\n * `undefined` is iterated by `Object.entries`. We dispatch on the value\n * BEFORE writing, so `{ k: undefined }` triggers the skip branch rather\n * than overwriting `out[k]` with undefined.\n */\nfunction deepMerge<T>(source: T, patch: DeepPartialOrNull<T>): T {\n if (!isPlainObject(source) || !isPlainObject(patch)) {\n // Top-level non-object replace. `null` patch at the leaf level\n // would have been caught by the parent recursion's branch table;\n // at the top level it means \"set the whole envelope to null,\"\n // which the type system already prevents (T extends object).\n return patch as unknown as T\n }\n const out: Record<string, unknown> = { ...(source as Record<string, unknown>) }\n for (const [key, patchVal] of Object.entries(patch as Record<string, unknown>)) {\n if (patchVal === undefined) {\n // Skip — preserve the source value at this key. Matches the\n // pre-existing behavior so callers who never used `null` see no diff.\n continue\n }\n if (patchVal === null) {\n // Delete intent. `delete` rather than `out[key] = undefined`\n // because JSON.stringify drops undefined fields silently and\n // we want the deletion to be visible to consumers iterating\n // the merged object (e.g. `Object.keys(merged.profile)`).\n delete out[key]\n continue\n }\n const sourceVal = (source as Record<string, unknown>)[key]\n if (isPlainObject(patchVal)) {\n // Recurse for any plain-object patch — including the \"source is\n // missing this key\" case. Without recursing through a synthetic\n // empty source, nested `null` deletions in the patch would land\n // as literal `null` values instead of triggering the delete\n // branch (e.g. `{ app: { signature: null } }` against a missing\n // `app` would emit `{ app: { signature: null } }` instead of\n // `{ app: {} }`).\n const recurseSource = isPlainObject(sourceVal) ? sourceVal : {}\n out[key] = deepMerge(recurseSource, patchVal as DeepPartialOrNull<typeof recurseSource>)\n } else {\n out[key] = patchVal\n }\n }\n return out as T\n}\n\nfunction isPlainObject(x: unknown): x is Record<string, unknown> {\n if (x === null || typeof x !== 'object') return false\n if (Array.isArray(x)) return false\n const proto = Object.getPrototypeOf(x) as object | null\n return proto === Object.prototype || proto === null\n}\n","/**\n * Deterministic JSON serializer: sorts object keys lexicographically at every\n * depth so structurally-equivalent objects produce identical strings. Array\n * order is preserved (arrays are semantically ordered).\n *\n * Used by {@link sha256Hex} to fingerprint a derived JSON Schema for\n * hash-based skip on persisted-schema writes.\n *\n * @module\n */\n\nexport function canonicalize(value: unknown): string {\n if (value === null || typeof value !== 'object') {\n return JSON.stringify(value)\n }\n if (Array.isArray(value)) {\n return '[' + value.map(canonicalize).join(',') + ']'\n }\n const obj = value as Record<string, unknown>\n const keys = Object.keys(obj).sort()\n const parts = keys.map((k) => JSON.stringify(k) + ':' + canonicalize(obj[k]))\n return '{' + parts.join(',') + '}'\n}\n","/**\n * Derive a {@link PersistedSchemaEnvelope} from a Standard Schema v1\n * validator. v0 supports Zod via `zod-to-json-schema` (optional peer-dep);\n * other families write a stub envelope flagging the kind.\n *\n * @see docs/superpowers/specs/2026-05-22-schema-dump-design.md\n *\n * @module\n */\n\nimport { canonicalize } from './canonicalize.js'\nimport { sha256Hex } from '../crypto.js'\nimport type { PersistedSchemaEnvelope, PersistedSchemaKind } from './types.js'\n\n/**\n * Heuristic Zod detection — Zod schemas carry a `_def.typeName` property\n * starting with `Zod` (e.g. `ZodObject`, `ZodString`). This survives Zod's\n * minor-version bumps because the typeName naming is stable across v3.\n */\nexport function isZodSchema(value: unknown): boolean {\n if (value === null || typeof value !== 'object') return false\n const def = (value as { _def?: { typeName?: unknown } })._def\n if (!def || typeof def !== 'object') return false\n return typeof def.typeName === 'string' && def.typeName.startsWith('Zod')\n}\n\nfunction detectKind(validator: unknown): PersistedSchemaKind {\n if (isZodSchema(validator)) return 'Zod'\n return 'Unknown'\n}\n\n/**\n * Lazy-require `zod-to-json-schema`. Returns the converter, or throws a\n * clear error if the peer-dep isn't installed.\n */\nasync function loadZodConverter(): Promise<(s: unknown) => object> {\n try {\n const mod = (await import('zod-to-json-schema')) as { zodToJsonSchema?: (s: unknown) => object }\n if (!mod.zodToJsonSchema) {\n throw new Error('zod-to-json-schema export missing')\n }\n return mod.zodToJsonSchema\n } catch (err) {\n throw new Error(\n 'persistJsonSchema requires the optional peer-dep `zod-to-json-schema`. '\n + 'Install it: `pnpm add zod-to-json-schema` (or npm/yarn equivalent). '\n + `Original error: ${err instanceof Error ? err.message : String(err)}`,\n )\n }\n}\n\nexport async function derivePersistedSchema(\n validator: unknown,\n): Promise<PersistedSchemaEnvelope> {\n const kind = detectKind(validator)\n const derivedAt = new Date().toISOString()\n\n if (kind === 'Zod') {\n const convert = await loadZodConverter()\n const jsonSchema = convert(validator)\n const canonical = canonicalize(jsonSchema)\n const hash = await sha256Hex(new TextEncoder().encode(canonical))\n return { _noydb_schema: 1, kind, jsonSchema, hash, derivedAt }\n }\n\n return {\n _noydb_schema: 1,\n kind,\n jsonSchema: null,\n hash: null,\n reason: `derivation not yet supported for kind=${kind} (v0 supports Zod only)`,\n derivedAt,\n }\n}\n","/**\n * Classify the difference between two derived JSON Schemas.\n *\n * v1 ruleset — top-level object properties + required-ness:\n * - additive ⇔ only new OPTIONAL properties (no removals, no changed\n * properties, no new required field, no required-ness flip)\n * - non-additive ⇔ any removal, any shape/type change, any required-ness\n * flip, or a new REQUIRED property\n * Deeper rules (nested objects, union widening, type narrowing) are\n * deferred (spec §8). Callers only invoke this with two object schemas.\n */\nimport { canonicalize } from '../persisted-schemas/canonicalize.js'\nimport type { SchemaDelta, FieldChange } from './types.js'\n\ninterface ObjectSchema {\n readonly properties?: Record<string, unknown>\n readonly required?: readonly string[]\n}\n\nexport function computeSchemaDelta(\n stored: object,\n fresh: object,\n collection: string,\n): SchemaDelta {\n const a = stored as ObjectSchema\n const b = fresh as ObjectSchema\n const aProps = a.properties ?? {}\n const bProps = b.properties ?? {}\n const aReq = new Set(a.required ?? [])\n const bReq = new Set(b.required ?? [])\n\n const aKeys = Object.keys(aProps)\n const bKeys = Object.keys(bProps)\n\n const added = bKeys.filter(k => !(k in aProps))\n const removed = aKeys.filter(k => !(k in bProps))\n\n const changed: FieldChange[] = []\n for (const k of bKeys) {\n if (!(k in aProps)) continue\n const shapeChanged = canonicalize(aProps[k]) !== canonicalize(bProps[k])\n const requiredChanged = aReq.has(k) !== bReq.has(k)\n if (shapeChanged || requiredChanged) {\n changed.push({ field: k, requiredChanged, shapeChanged })\n }\n }\n\n let kind: SchemaDelta['kind']\n if (added.length === 0 && removed.length === 0 && changed.length === 0) {\n kind = 'none'\n } else if (\n removed.length === 0 &&\n changed.length === 0 &&\n added.every(k => !bReq.has(k))\n ) {\n kind = 'additive'\n } else {\n kind = 'non-additive'\n }\n\n return { collection, kind, added, removed, changed }\n}\n","/** Ordered strategy evaluation: first non-`allow` decision wins. */\nimport type { SchemaDelta, SchemaUpdateStrategy, UpdateContext, UpdateDecision } from './types.js'\n\nexport async function evaluateStrategies(\n delta: SchemaDelta,\n strategies: readonly SchemaUpdateStrategy[],\n ctx: UpdateContext,\n): Promise<UpdateDecision> {\n for (const strategy of strategies) {\n const decision = await strategy.onSchemaDelta(delta, ctx)\n if (decision.action !== 'allow') return decision\n }\n return { action: 'allow' }\n}\n","/**\n * Orchestrate the derive → hash → skip-or-write cycle for a collection's\n * persisted JSON Schema. Called by the Vault at collection-registration\n * time when the developer opts in via `collection({ persistJsonSchema:\n * true })`.\n *\n * Skip semantics:\n *\n * - Zod validators: skip when the new hash equals the stored hash.\n * - Non-Zod (stub envelopes have hash=null): skip when the stored\n * envelope's `kind` matches the freshly-detected kind (since there's\n * no body to compare yet — a kind change is the only signal).\n *\n * @module\n */\n\nimport { derivePersistedSchema } from './derive.js'\nimport { loadPersistedSchema, savePersistedSchema } from './storage.js'\nimport { computeSchemaDelta } from '../schema-update/delta.js'\nimport { evaluateStrategies } from '../schema-update/dispatch.js'\nimport type { SchemaUpdateStrategy, UpdateDecision } from '../schema-update/types.js'\nimport type { NoydbStore } from '../types.js'\nimport type { PersistedSchemaEnvelope } from './types.js'\n\nexport interface PersistSchemaResult {\n /** True when a fresh envelope was written to storage. */\n readonly written: boolean\n /** True when an existing envelope matched and the write was skipped. */\n readonly skipped: boolean\n /** The envelope that was either written or matched. */\n readonly envelope: PersistedSchemaEnvelope\n /** The update-strategy decision, present when strategies ran. */\n readonly decision?: UpdateDecision\n}\n\nexport async function persistSchemaIfNeeded(opts: {\n readonly store: NoydbStore\n readonly vault: string\n readonly collectionName: string\n readonly validator: unknown\n readonly dek: CryptoKey\n readonly strategies?: readonly SchemaUpdateStrategy[]\n}): Promise<PersistSchemaResult> {\n const fresh = await derivePersistedSchema(opts.validator)\n const stored = await loadPersistedSchema(opts.store, opts.vault, opts.collectionName, opts.dek)\n\n if (stored && isEquivalent(stored, fresh)) {\n return { written: false, skipped: true, envelope: stored, decision: { action: 'allow' } }\n }\n\n // Changed (or first registration). Run update strategies only when we\n // have a comparable JSON-Schema baseline and strategies were registered.\n let decision: UpdateDecision = { action: 'allow' }\n const strategies = opts.strategies ?? []\n if (\n stored &&\n strategies.length > 0 &&\n stored.kind === fresh.kind &&\n isPlainObject(stored.jsonSchema) &&\n isPlainObject(fresh.jsonSchema)\n ) {\n const delta = computeSchemaDelta(stored.jsonSchema, fresh.jsonSchema, opts.collectionName)\n decision = await evaluateStrategies(delta, strategies, { collection: opts.collectionName })\n }\n\n if (decision.action !== 'allow') {\n // reject (or cutover): do NOT overwrite the baseline — the\n // old schema stays the source of truth until the change is resolved.\n return { written: false, skipped: false, envelope: stored ?? fresh, decision }\n }\n\n await savePersistedSchema(opts.store, opts.vault, opts.collectionName, opts.dek, fresh)\n return { written: true, skipped: false, envelope: fresh, decision }\n}\n\nfunction isPlainObject(v: unknown): v is object {\n return typeof v === 'object' && v !== null && !Array.isArray(v)\n}\n\nfunction isEquivalent(a: PersistedSchemaEnvelope, b: PersistedSchemaEnvelope): boolean {\n if (a.kind !== b.kind) return false\n // Zod path: real hashes — compare directly.\n if (a.hash && b.hash) return a.hash === b.hash\n // Stub path: both have hash=null. Kind equality is the only signal we have.\n if (a.hash === null && b.hash === null) return true\n // Mixed (one has a hash, the other doesn't) — treat as changed.\n return false\n}\n","/**\n * Per-collection write gate. Holds the (async) update decision\n * computed at registration; `Collection.put`/`delete` await it before\n * writing and throw the strategy's rejection error.\n *\n * Detection FAILURE (the promise rejecting) is deliberately NOT a write\n * block — schema detection is a fingerprint safety net, not a correctness\n * invariant (matches how persisted-schema write failures are swallowed).\n * Only an explicit `reject` decision blocks writes.\n */\nimport type { UpdateDecision } from './types.js'\n\nexport class SchemaUpdateGate {\n readonly #decision: Promise<UpdateDecision | null>\n\n constructor(decision: Promise<UpdateDecision>) {\n // Swallow detection failures into a non-blocking null.\n this.#decision = decision.catch(() => null)\n }\n\n async assertWritable(): Promise<void> {\n const decision = await this.#decision\n if (decision && decision.action === 'reject') {\n throw decision.error\n }\n // 'cutover' write-gating is handled by coordinatedCutover.\n }\n}\n","/**\n * Schema-fence document. Vault-level generation counter + drain\n * state, stored at `_meta/schema-fence` using the plaintext-envelope\n * pattern of `_meta/policy` (no PII — a counter + a state enum).\n */\nimport type { NoydbStore, EncryptedEnvelope } from '../types.js'\nimport { NOYDB_FORMAT_VERSION } from '../types.js'\n\nexport type FenceState = 'normal' | 'draining' | 'migrating' | 'complete'\n\nexport interface FenceDoc {\n readonly currentSchemaVersion: number\n readonly fenceState: FenceState\n}\n\nexport const FENCE_RECORD_ID = 'schema-fence'\nconst META_COLLECTION = '_meta'\n\nexport const DEFAULT_FENCE: FenceDoc = { currentSchemaVersion: 0, fenceState: 'normal' }\n\nexport async function loadFence(store: NoydbStore, vault: string): Promise<FenceDoc> {\n const envelope = await store.get(vault, META_COLLECTION, FENCE_RECORD_ID)\n if (!envelope) return DEFAULT_FENCE\n try {\n const parsed = JSON.parse(envelope._data) as unknown\n if (!isFenceDoc(parsed)) return DEFAULT_FENCE\n return parsed\n } catch {\n return DEFAULT_FENCE\n }\n}\n\nexport async function saveFence(store: NoydbStore, vault: string, fence: FenceDoc): Promise<void> {\n const envelope: EncryptedEnvelope = {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: 1,\n _ts: new Date().toISOString(),\n _iv: '',\n _data: JSON.stringify(fence),\n }\n await store.put(vault, META_COLLECTION, FENCE_RECORD_ID, envelope)\n}\n\nfunction isFenceDoc(x: unknown): x is FenceDoc {\n if (x === null || typeof x !== 'object') return false\n const o = x as Record<string, unknown>\n return typeof o['currentSchemaVersion'] === 'number'\n && (o['fenceState'] === 'normal' || o['fenceState'] === 'draining'\n || o['fenceState'] === 'migrating' || o['fenceState'] === 'complete')\n}\n","/**\n * Schema-cutover client registry. Each client keeps a\n * heartbeat doc at `_meta/schema-fence:client:<clientId>` carrying its\n * liveness (`lastSeen`) and the fence generation it has quiesced for\n * (`quiescedAtVersion`). Plaintext envelope, like the fence doc.\n */\nimport type { NoydbStore, EncryptedEnvelope } from '../types.js'\nimport { NOYDB_FORMAT_VERSION } from '../types.js'\n\nconst META_COLLECTION = '_meta'\nconst CLIENT_PREFIX = 'schema-fence:client:'\n\nexport interface ClientDoc {\n readonly clientId: string\n readonly lastSeen: number\n readonly quiescedAtVersion: number | null\n}\n\nexport async function writeClientDoc(\n store: NoydbStore,\n vault: string,\n clientId: string,\n doc: { lastSeen: number; quiescedAtVersion: number | null },\n): Promise<void> {\n const envelope: EncryptedEnvelope = {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: 1,\n _ts: new Date().toISOString(),\n _iv: '',\n _data: JSON.stringify({ clientId, ...doc }),\n }\n await store.put(vault, META_COLLECTION, `${CLIENT_PREFIX}${clientId}`, envelope)\n}\n\nexport async function listClientDocs(store: NoydbStore, vault: string): Promise<ClientDoc[]> {\n const ids = await store.list(vault, META_COLLECTION)\n const out: ClientDoc[] = []\n for (const id of ids) {\n if (!id.startsWith(CLIENT_PREFIX)) continue\n const env = await store.get(vault, META_COLLECTION, id)\n if (!env) continue\n try {\n const parsed = JSON.parse(env._data) as unknown\n if (isClientDoc(parsed)) out.push(parsed)\n } catch { /* skip corrupt */ }\n }\n return out\n}\n\n/**\n * True when every *active* client (lastSeen within staleMs of now) has\n * `quiescedAtVersion === generation`. Stale clients are ignored. An empty\n * active set is vacuously quiesced.\n */\nexport async function activeQuiesced(\n store: NoydbStore,\n vault: string,\n opts: { generation: number; now: number; staleMs: number; excludeClientId?: string },\n): Promise<boolean> {\n const docs = await listClientDocs(store, vault)\n const active = docs.filter(\n d => d.lastSeen >= opts.now - opts.staleMs && d.clientId !== opts.excludeClientId,\n )\n return active.every(d => d.quiescedAtVersion === opts.generation)\n}\n\nfunction isClientDoc(x: unknown): x is ClientDoc {\n if (x === null || typeof x !== 'object') return false\n const o = x as Record<string, unknown>\n return typeof o['clientId'] === 'string'\n && typeof o['lastSeen'] === 'number'\n && (o['quiescedAtVersion'] === null || typeof o['quiescedAtVersion'] === 'number')\n}\n","/**\n * Vault-level schema-fence controller.\n *\n * Owns the open-time generation snapshot, the pending-cutover registry,\n * and the cutover orchestration. 3a: single-client (the caller is the\n * migrator). 3b: a cooperative ack-barrier — after `draining`, the\n * migrator waits for the active client set (registry heartbeats) to ack\n * the draining generation before transforming. No leader election.\n */\nimport type { NoydbStore } from '../types.js'\nimport { loadFence, saveFence, type FenceState } from './fence.js'\nimport { SchemaFenceError, MigrationRequiredError, QuiesceTimeoutError } from '../errors.js'\nimport { activeQuiesced } from './client-registry.js'\nimport type { TransformFn } from './types.js'\n\n/** Runs one collection's transform; supplied by the Vault (binds to a Collection). */\nexport type RunTransform = (collection: string, transform: TransformFn) => Promise<void>\n\nexport class SchemaFenceController {\n readonly #store: NoydbStore\n readonly #vault: string\n readonly #onFlush: () => Promise<void>\n readonly #clientId: string\n readonly #now: () => number\n readonly #staleMs: number\n readonly #quiesceTimeoutMs: number\n readonly #emit: (e: { currentSchemaVersion: number; fenceState: FenceState }) => void\n #snapshot = 0\n readonly #pending = new Map<string, TransformFn>()\n\n constructor(opts: {\n store: NoydbStore\n vault: string\n onFlush: () => Promise<void>\n clientId?: string\n now?: () => number\n staleMs?: number\n quiesceTimeoutMs?: number\n emit?: (e: { currentSchemaVersion: number; fenceState: FenceState }) => void\n }) {\n this.#store = opts.store\n this.#vault = opts.vault\n this.#onFlush = opts.onFlush\n this.#clientId = opts.clientId ?? 'migrator'\n this.#now = opts.now ?? (() => Date.now())\n this.#staleMs = opts.staleMs ?? 30_000\n this.#quiesceTimeoutMs = opts.quiesceTimeoutMs ?? 60_000\n this.#emit = opts.emit ?? (() => {})\n }\n\n /** Capture the generation snapshot at vault-open. */\n async init(): Promise<void> {\n this.#snapshot = (await loadFence(this.#store, this.#vault)).currentSchemaVersion\n }\n\n /** Record a per-collection pending cutover (from a registration `cutover` decision). */\n registerPendingCutover(collection: string, transform: TransformFn): void {\n this.#pending.set(collection, transform)\n }\n\n /** Write-path gate. Throws when behind, fenced, or this collection is cutover-pending. */\n async assertWritable(collection: string): Promise<void> {\n const fence = await loadFence(this.#store, this.#vault)\n if (fence.currentSchemaVersion > this.#snapshot) {\n throw new MigrationRequiredError(\n `Vault \"${this.#vault}\" advanced to schema generation ${fence.currentSchemaVersion} ` +\n `(this client opened at ${this.#snapshot}). Reload to continue.`,\n )\n }\n if (fence.fenceState === 'draining' || fence.fenceState === 'migrating') {\n throw new SchemaFenceError(`Vault \"${this.#vault}\" is mid-cutover (${fence.fenceState}); writes are paused.`)\n }\n if (this.#pending.has(collection)) {\n throw new SchemaFenceError(\n `Collection \"${collection}\" has a pending schema cutover; run vault.runSchemaCutover() before writing.`,\n )\n }\n }\n\n /**\n * Admin trigger. Drain → wait for the active set to quiesce (or time out)\n * → migrate each pending transform → bump → complete → normal. The\n * migrator excludes itself from the barrier (it drained synchronously\n * here). `onPoll` (tests) advances other clients between barrier checks;\n * production falls back to a short real delay.\n */\n async runCutover(\n run: RunTransform,\n opts?: { onPoll?: () => Promise<void> },\n ): Promise<{ migrated: number }> {\n if (this.#pending.size === 0) return { migrated: 0 }\n const base = await loadFence(this.#store, this.#vault)\n const generation = base.currentSchemaVersion\n\n await this.#setState(generation, 'draining')\n await this.#onFlush() // drain THIS client first\n\n const deadline = this.#now() + this.#quiesceTimeoutMs\n while (!(await activeQuiesced(this.#store, this.#vault, {\n generation, now: this.#now(), staleMs: this.#staleMs, excludeClientId: this.#clientId,\n }))) {\n if (this.#now() >= deadline) {\n throw new QuiesceTimeoutError(\n `Cutover on \"${this.#vault}\" timed out waiting for clients to quiesce at generation ${generation}.`,\n )\n }\n await (opts?.onPoll ? opts.onPoll() : delay(50))\n }\n\n await this.#setState(generation, 'migrating')\n let migrated = 0\n for (const [collection, transform] of this.#pending) {\n await run(collection, transform)\n migrated++\n }\n\n const nextVersion = generation + 1\n await this.#setState(nextVersion, 'complete')\n this.#pending.clear()\n await this.#setState(nextVersion, 'normal')\n this.#snapshot = nextVersion\n return { migrated }\n }\n\n /** Recover a stuck drain: reset fenceState to normal at the current version (no bump). */\n async abort(): Promise<void> {\n const fence = await loadFence(this.#store, this.#vault)\n await this.#setState(fence.currentSchemaVersion, 'normal')\n }\n\n async #setState(currentSchemaVersion: number, fenceState: FenceState): Promise<void> {\n await saveFence(this.#store, this.#vault, { currentSchemaVersion, fenceState })\n this.#emit({ currentSchemaVersion, fenceState })\n }\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n","/**\n * Per-client schema-fence watcher. Polls the fence;\n * on `draining` it drains in-flight writes and acks; emits a same-instance\n * signal on every state transition (for UI). Driven by an interval\n * in production and by explicit `check()`/`beat()` in tests.\n */\nimport type { NoydbStore } from '../types.js'\nimport { loadFence, type FenceState } from './fence.js'\nimport { writeClientDoc } from './client-registry.js'\n\nexport interface FenceWatcherEvent {\n readonly currentSchemaVersion: number\n readonly fenceState: FenceState\n}\n\nexport class FenceWatcher {\n readonly #store: NoydbStore\n readonly #vault: string\n readonly #clientId: string\n readonly #onFlush: () => Promise<void>\n readonly #now: () => number\n readonly #emit: (e: FenceWatcherEvent) => void\n #lastState: FenceState | null = null\n #quiescedAtVersion: number | null = null\n #timer: ReturnType<typeof setInterval> | undefined\n\n constructor(opts: {\n store: NoydbStore\n vault: string\n clientId: string\n onFlush: () => Promise<void>\n now?: () => number\n emit?: (e: FenceWatcherEvent) => void\n }) {\n this.#store = opts.store\n this.#vault = opts.vault\n this.#clientId = opts.clientId\n this.#onFlush = opts.onFlush\n this.#now = opts.now ?? (() => Date.now())\n this.#emit = opts.emit ?? (() => {})\n }\n\n /** Publish liveness (and the current ack) without changing quiesce state. */\n async beat(): Promise<void> {\n await writeClientDoc(this.#store, this.#vault, this.#clientId, {\n lastSeen: this.#now(),\n quiescedAtVersion: this.#quiescedAtVersion,\n })\n }\n\n /** Poll the fence; quiesce on draining; emit on transitions. */\n async check(): Promise<void> {\n const fence = await loadFence(this.#store, this.#vault)\n if (fence.fenceState !== this.#lastState) {\n this.#lastState = fence.fenceState\n this.#emit({ currentSchemaVersion: fence.currentSchemaVersion, fenceState: fence.fenceState })\n }\n if (fence.fenceState === 'draining' && this.#quiescedAtVersion !== fence.currentSchemaVersion) {\n await this.#onFlush()\n this.#quiescedAtVersion = fence.currentSchemaVersion\n await this.beat()\n }\n if (fence.fenceState === 'normal') {\n this.#quiescedAtVersion = null\n }\n }\n\n start(intervalMs: number): void {\n if (this.#timer) return\n this.#timer = setInterval(() => { void this.beat(); void this.check() }, intervalMs)\n const timer = this.#timer as unknown as { unref?: () => void }\n if (typeof timer.unref === 'function') timer.unref() // don't keep the process alive\n }\n\n stop(): void {\n if (this.#timer) { clearInterval(this.#timer); this.#timer = undefined }\n }\n}\n","/**\n * Map a JSON Schema (Draft 2020-12 produced by `zod-to-json-schema`) into\n * the {@link FieldDescriptor} map consumed by {@link VaultSchemaSnapshot}.\n *\n * Used by both the persisted-schema path (decrypted envelope body) and the\n * live-validator path (in-process derivation).\n *\n * @module\n */\n\nimport type { FieldDescriptor, FieldSource } from './types.js'\n\ninterface JsonSchemaShape {\n type?: string | string[]\n properties?: Record<string, JsonSchemaShape>\n required?: string[]\n enum?: unknown[]\n const?: unknown\n minLength?: number\n maxLength?: number\n pattern?: string\n minimum?: number\n maximum?: number\n exclusiveMinimum?: number\n exclusiveMaximum?: number\n format?: string\n items?: JsonSchemaShape\n oneOf?: JsonSchemaShape[]\n anyOf?: JsonSchemaShape[]\n}\n\nfunction jsonSchemaType(node: JsonSchemaShape): string {\n if (Array.isArray(node.type)) {\n const non = node.type.filter((t) => t !== 'null')\n return non[0] ?? 'opaque'\n }\n if (node.enum && Array.isArray(node.enum)) return 'enum'\n // JSON Schema `const` is used by zod-to-json-schema for z.literal(...)\n if (node.const !== undefined) return 'enum'\n if (typeof node.type === 'string') return node.type\n return 'opaque'\n}\n\nfunction constraintsFor(node: JsonSchemaShape): Record<string, unknown> | undefined {\n const out: Record<string, unknown> = {}\n if (node.enum) out.values = node.enum\n // JSON Schema `const` (used by zod-to-json-schema for z.literal) — treat like a single-value enum\n if (node.const !== undefined) out.values = [node.const]\n if (node.minLength !== undefined) out.minLength = node.minLength\n if (node.maxLength !== undefined) out.maxLength = node.maxLength\n if (node.pattern !== undefined) out.pattern = node.pattern\n if (node.format !== undefined) out.format = node.format\n if (node.minimum !== undefined) out.minimum = node.minimum\n if (node.maximum !== undefined) out.maximum = node.maximum\n if (node.exclusiveMinimum !== undefined) out.gt = node.exclusiveMinimum\n if (node.exclusiveMaximum !== undefined) out.lt = node.exclusiveMaximum\n return Object.keys(out).length === 0 ? undefined : out\n}\n\n/**\n * Extract fields from a single JSON Schema object node (must have `properties`).\n * Used by both the plain-object path and the per-member extraction in the union path.\n */\nfunction extractObjectFields(\n obj: JsonSchemaShape,\n source: FieldSource,\n refs?: Record<string, { target: string; mode: string }>,\n): { fields: Record<string, FieldDescriptor>; required: Set<string> } {\n const required = new Set(Array.isArray(obj.required) ? obj.required : [])\n const fields: Record<string, FieldDescriptor> = {}\n if (!obj.properties || typeof obj.properties !== 'object') return { fields, required }\n\n for (const [name, node] of Object.entries(obj.properties)) {\n const descriptor: FieldDescriptor = {\n type: jsonSchemaType(node),\n source,\n ...(required.has(name) ? {} : { optional: true }),\n ...(refs?.[name] ? { references: `${refs[name].target}.id` } : {}),\n }\n const constraints = constraintsFor(node)\n if (constraints) (descriptor as { constraints?: Record<string, unknown> }).constraints = constraints\n fields[name] = descriptor\n }\n\n return { fields, required }\n}\n\n/**\n * Merge field descriptors from multiple union members.\n *\n * Merge rules:\n * - Emit the UNION of all field names so no member's fields are hidden.\n * - A field is required (optional=false/absent) only when it is required in\n * EVERY member; otherwise it is marked optional=true.\n * - For the discriminator field (appears in every member with a `const` value),\n * collect the const values from all members and surface them as constraints.values\n * so the caller can see the full literal set.\n * - For conflicting types across members, first-seen wins.\n */\nfunction mergeUnionMembers(\n members: JsonSchemaShape[],\n source: FieldSource,\n refs?: Record<string, { target: string; mode: string }>,\n): Record<string, FieldDescriptor> {\n if (members.length === 0) return {}\n\n // Extract per-member fields + required sets\n const extracted = members\n .filter((m) => m.properties && typeof m.properties === 'object')\n .map((m) => extractObjectFields(m, source, refs))\n\n if (extracted.length === 0) return {}\n\n // Collect all field names across all members\n const allNames = new Set<string>()\n for (const { fields } of extracted) {\n for (const name of Object.keys(fields)) allNames.add(name)\n }\n\n const memberCount = extracted.length\n const out: Record<string, FieldDescriptor> = {}\n\n for (const name of allNames) {\n // Which members contain this field?\n const presentIn = extracted.filter(({ fields }) => name in fields)\n const requiredInAll = presentIn.length === memberCount\n && presentIn.every(({ required }) => required.has(name))\n\n // Use first-seen descriptor as the base (presentIn is always non-empty here since\n // we iterate names that appeared in at least one member's fields)\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const base = presentIn[0]!.fields[name]!\n\n // For discriminator-like fields: collect const/enum values across all members\n // to surface the full literal set in constraints.values\n const allValues: unknown[] = []\n for (const { fields } of presentIn) {\n const fd = fields[name]\n if (fd?.constraints?.values && Array.isArray(fd.constraints.values)) {\n for (const v of fd.constraints.values) {\n if (!allValues.includes(v)) allValues.push(v)\n }\n }\n }\n\n const mergedConstraints: Record<string, unknown> | undefined =\n allValues.length > 0\n ? { ...(base.constraints ?? {}), values: allValues }\n : base.constraints\n\n const descriptor: FieldDescriptor = {\n type: base.type,\n source,\n ...(requiredInAll ? {} : { optional: true }),\n ...(base.references ? { references: base.references } : {}),\n }\n if (mergedConstraints) {\n (descriptor as { constraints?: Record<string, unknown> }).constraints = mergedConstraints\n }\n out[name] = descriptor\n }\n\n return out\n}\n\nexport function jsonSchemaToFields(\n jsonSchema: unknown,\n source: FieldSource,\n refs?: Record<string, { target: string; mode: string }>,\n): Record<string, FieldDescriptor> {\n if (!jsonSchema || typeof jsonSchema !== 'object') return {}\n const root = jsonSchema as JsonSchemaShape\n\n // Handle discriminated unions: zod-to-json-schema emits anyOf/oneOf for z.discriminatedUnion\n const unionMembers = root.anyOf ?? root.oneOf\n if (Array.isArray(unionMembers) && unionMembers.length > 0) {\n return mergeUnionMembers(unionMembers, source, refs)\n }\n\n if (!root.properties || typeof root.properties !== 'object') return {}\n\n const { fields } = extractObjectFields(root, source, refs)\n return fields\n}\n","/**\n * Orchestrate the structural walk of a Vault, producing a\n * {@link VaultSchemaSnapshot}. Called from `Vault.dumpSchema()`.\n *\n * @module\n */\n\nimport { derivePersistedSchema } from '../persisted-schemas/derive.js'\nimport { loadPersistedSchema } from '../persisted-schemas/storage.js'\nimport { jsonSchemaToFields } from './fields.js'\nimport type {\n CollectionDescriptor,\n CollectionStats,\n DumpSchemaOptions,\n FieldDescriptor,\n InternalCollectionStats,\n MaterializedViewDescriptor,\n OverlayViewDescriptor,\n DerivationDescriptor,\n VaultSchemaSnapshot,\n} from './types.js'\nimport type { Collection } from '../collection.js'\nimport type { NoydbStore } from '../types.js'\nimport type { RefRegistry } from '../refs.js'\n\n/**\n * The minimal slice of Vault internal state the walker needs.\n * Exposed via `vault._introspectState()` to keep the public Vault\n * surface narrow.\n *\n * @internal\n */\nexport interface VaultIntrospectState {\n readonly name: string\n readonly adapter: NoydbStore\n readonly collectionCache: Map<string, Collection<unknown>>\n readonly refRegistry: RefRegistry\n readonly getDEK: (collectionName: string) => Promise<CryptoKey>\n readonly subsystems: Record<string, boolean>\n // Typed loosely on purpose — these are private subsystem registries\n // accessed only for \"is anything registered\" enumeration.\n readonly mvRegistry: unknown\n readonly overlayRegistry: unknown\n readonly derivationRegistry: unknown\n}\n\nconst INTERNAL_PREFIX = '_'\n\n/** Reserved internal collections always present in any real vault. */\nconst KNOWN_INTERNAL_NAMES = ['_keyring', '_ledger', '_meta', '_schemas', '_deltas']\n\nexport async function dumpVaultSchema(\n vault: { _introspectState(): VaultIntrospectState },\n opts: DumpSchemaOptions,\n): Promise<VaultSchemaSnapshot> {\n const state = vault._introspectState()\n const sampleSize = opts.sampleSize ?? 50\n const withStats = opts.withStats === true\n\n // 1. User-facing collections — alphabetical for diff stability\n const cacheNames = [...state.collectionCache.keys()]\n const storageNames = (await safeListAllCollections(state.adapter, state.name))\n .filter((n) => !n.startsWith(INTERNAL_PREFIX))\n const allNames = Array.from(new Set([...cacheNames, ...storageNames])).sort()\n\n const collections: Record<string, CollectionDescriptor> = {}\n for (const name of allNames) {\n collections[name] = await describeCollection(state, name, sampleSize, withStats)\n }\n\n // 2. Materialized views (placeholder — real walk in MV slice 2 follow-up)\n const materializedViews = describeMVs(state.mvRegistry)\n // 3. Overlay views\n const overlayViews = describeOverlays(state.overlayRegistry)\n // 4. Derivations\n const derivations = describeDerivations(state.derivationRegistry)\n\n // 5. Internal collections — only with stats\n let internal: Record<string, InternalCollectionStats> | undefined\n if (withStats) {\n internal = {}\n for (const name of KNOWN_INTERNAL_NAMES) {\n const stats = await statsForCollection(state.adapter, state.name, name)\n if (stats.records > 0) {\n internal[name] = { records: stats.records, bytes: stats.bytes }\n }\n }\n }\n\n const snap: VaultSchemaSnapshot = {\n _noydb_snapshot: 1,\n vault: state.name,\n emittedAt: new Date().toISOString(),\n subsystems: state.subsystems,\n collections,\n materializedViews,\n overlayViews,\n derivations,\n ...(internal !== undefined ? { internal } : {}),\n }\n return snap\n}\n\nasync function safeListAllCollections(adapter: NoydbStore, vault: string): Promise<string[]> {\n try {\n const snap = await adapter.loadAll(vault)\n return Object.keys(snap)\n } catch {\n return []\n }\n}\n\nasync function describeCollection(\n state: VaultIntrospectState,\n collectionName: string,\n sampleSize: number,\n withStats: boolean,\n): Promise<CollectionDescriptor> {\n let fields: Record<string, FieldDescriptor> = {}\n let validator: CollectionDescriptor['validator']\n\n const refsRaw = state.refRegistry.getOutbound(collectionName)\n const refs: CollectionDescriptor['refs'] = {}\n for (const [name, desc] of Object.entries(refsRaw)) {\n refs[name] = { target: desc.target, mode: desc.mode }\n }\n\n // 1. Try the persisted Route B envelope first.\n try {\n const dek = await state.getDEK(collectionName)\n const persisted = await loadPersistedSchema(state.adapter, state.name, collectionName, dek)\n if (persisted) {\n validator = { kind: persisted.kind, source: 'persisted' }\n if (persisted.jsonSchema) {\n fields = jsonSchemaToFields(persisted.jsonSchema, 'persisted', refsRaw)\n }\n }\n } catch {\n // No DEK or decrypt failure — fall through to live-validator\n }\n\n // 2. Try the live in-process validator (when no persisted envelope).\n if (!validator) {\n const coll = state.collectionCache.get(collectionName)\n const schema = coll?.getSchema()\n if (schema) {\n try {\n const derived = await derivePersistedSchema(schema)\n validator = { kind: derived.kind, source: 'live-validator' }\n if (derived.jsonSchema) {\n fields = jsonSchemaToFields(derived.jsonSchema, 'live-validator', refsRaw)\n }\n } catch {\n // Derivation failed (e.g. missing peer-dep) — silently leave fields empty\n }\n }\n }\n\n // 3. Sampling fallback — deferred to a follow-up. For now: empty when no schema.\n if (Object.keys(fields).length === 0 && sampleSize > 0) {\n // Sampling path not implemented in baseline slice 2; reserved for follow-up.\n }\n\n const descriptor: CollectionDescriptor = {\n fields,\n indexes: [],\n refs,\n ...(validator ? { validator } : {}),\n }\n if (withStats) {\n const stats = await statsForCollection(state.adapter, state.name, collectionName)\n ;(descriptor as { stats?: CollectionStats }).stats = stats\n }\n return descriptor\n}\n\nasync function statsForCollection(\n adapter: NoydbStore,\n vault: string,\n collection: string,\n): Promise<CollectionStats> {\n const ids = await adapter.list(vault, collection)\n if (ids.length === 0) {\n return { records: 0, bytes: 0, bytesAvg: 0, bytesMin: 0, bytesMax: 0, oldest: '', newest: '' }\n }\n let total = 0\n let min = Number.POSITIVE_INFINITY\n let max = 0\n let oldest = ''\n let newest = ''\n for (const id of ids) {\n const env = await adapter.get(vault, collection, id)\n if (!env) continue\n const size = env._data.length\n total += size\n if (size < min) min = size\n if (size > max) max = size\n if (env._ts < oldest) oldest = env._ts\n if (env._ts > newest) newest = env._ts\n }\n return {\n records: ids.length,\n bytes: total,\n bytesAvg: Math.round(total / ids.length),\n bytesMin: min === Number.POSITIVE_INFINITY ? 0 : min,\n bytesMax: max,\n oldest: oldest === '' ? '' : oldest,\n newest,\n }\n}\n\nfunction describeMVs(registry: unknown): Record<string, MaterializedViewDescriptor> {\n if (!registry || typeof registry !== 'object') return {}\n const items = listFromRegistry(registry as Record<string, unknown>)\n const out: Record<string, MaterializedViewDescriptor> = {}\n // Each item is RegisteredMV { spec, dependencies, outputCollection, ... }\n for (const item of items) {\n const reg = item as {\n spec?: {\n name?: string\n unionSources?: ReadonlyArray<{ collection: string }>\n groupBy?: string | ReadonlyArray<string>\n aggregate?: Record<string, unknown>\n refresh?: string\n }\n dependencies?: ReadonlySet<string>\n }\n const spec = reg.spec\n if (!spec?.name) continue\n const sources = spec.unionSources\n ? spec.unionSources.map((u) => u.collection)\n : (reg.dependencies ? [...reg.dependencies].sort() : [])\n const groupBy = spec.groupBy\n ? Array.isArray(spec.groupBy) ? [...spec.groupBy] : [spec.groupBy]\n : undefined\n const aggregate = spec.aggregate ? Object.fromEntries(\n Object.entries(spec.aggregate).map(([k, v]) => [k, summariseAggregateOp(v)]),\n ) : undefined\n out[spec.name] = {\n sources,\n ...(groupBy ? { groupBy } : {}),\n ...(aggregate ? { aggregate } : {}),\n refresh: spec.refresh ?? 'eager',\n }\n }\n return out\n}\n\nfunction describeOverlays(registry: unknown): Record<string, OverlayViewDescriptor> {\n if (!registry || typeof registry !== 'object') return {}\n const specs = listFromRegistry(registry as Record<string, unknown>)\n const out: Record<string, OverlayViewDescriptor> = {}\n for (const spec of specs) {\n const s = spec as { name?: string; base?: string; overlay?: string }\n if (!s.name || !s.base || !s.overlay) continue\n out[s.name] = { base: s.base, overlay: s.overlay }\n }\n return out\n}\n\nfunction describeDerivations(registry: unknown): Record<string, DerivationDescriptor> {\n if (!registry || typeof registry !== 'object') return {}\n const items = listFromRegistry(registry as Record<string, unknown>)\n const out: Record<string, DerivationDescriptor> = {}\n for (const item of items) {\n // `all()` on DerivationRegistry returns RegisteredStrategy objects:\n // { spec: DerivationStrategy, strategyHash }. Read `spec` and fall\n // back to the item itself for forward-compat with other registries.\n const reg = item as { spec?: { source?: string; outputs?: Record<string, { collection: string }> }; source?: string; outputs?: Record<string, { collection: string }> }\n const s = reg.spec ?? reg\n if (!s.source) continue\n const outputCollections = s.outputs\n ? Object.values(s.outputs).map((o) => (o as { collection: string }).collection)\n : []\n // Key by sorted output-collection names so co-sourced derivations don't\n // collide. A single-output derivation keys as just that collection name\n // (e.g. 'billSummary'); multi-output keys as sorted join (e.g. 'a+b').\n // Falls back to source when no outputs are declared (defensive).\n const key = outputCollections.length > 0\n ? [...outputCollections].sort().join('+')\n : s.source\n out[key] = {\n source: s.source,\n outputs: outputCollections,\n }\n }\n return out\n}\n\nfunction listFromRegistry(reg: Record<string, unknown>): readonly unknown[] {\n // Registries expose different accessor methods; try the common ones.\n for (const method of ['all', 'list', 'specs', 'values']) {\n const fn = reg[method]\n if (typeof fn === 'function') {\n try {\n const out = (fn as () => unknown).call(reg)\n if (Array.isArray(out)) return out\n if (out && typeof (out as { values?: () => unknown }).values === 'function') {\n return [...(out as { values: () => Iterable<unknown> }).values()]\n }\n } catch {\n continue\n }\n }\n }\n return []\n}\n\nfunction summariseAggregateOp(value: unknown): string {\n if (value && typeof value === 'object') {\n const op = (value as { op?: string; kind?: string; field?: string }).op\n ?? (value as { kind?: string }).kind\n const field = (value as { field?: string }).field\n if (op && field) return `${op}(${field})`\n if (op) return op\n }\n return String(value)\n}\n","import type {\n NoydbStore,\n EncryptedEnvelope,\n VaultBackup,\n VaultSnapshot,\n HistoryConfig,\n ExportStreamOptions,\n ExportChunk,\n CollectionConflictResolver,\n CrossTierAccessEvent,\n TierMode,\n Role,\n} from './types.js'\nimport type { Noydb } from './noydb.js'\nimport type { IssueDelegationOptions, DelegationToken } from './team/delegation.js'\nimport { NOYDB_BACKUP_VERSION, NOYDB_FORMAT_VERSION } from './types.js'\nimport { Collection } from './collection.js'\nimport type { CacheOptions } from './collection.js'\nimport type { IndexDef } from './indexing/eager-indexes.js'\nimport type { JoinableSource } from './query/index.js'\nimport type { OnDirtyCallback } from './collection.js'\nimport type { UnlockedKeyring, BundleRecipient } from './team/keyring.js'\nimport type { MaterializedViewRegistry } from './materialized-views/registry.js'\nimport type { MaterializedViewStrategyHandle, MVQueryContext } from './materialized-views/types.js'\nimport type { OverlayedViewRegistry } from './overlay-views/registry.js'\nimport type { OverlayedViewStrategyHandle } from './overlay-views/types.js'\nimport { OverlayedCollection } from './overlay-views/virtual-collection.js'\nimport type { PublicEnvelope } from './meta/public-envelope/types.js'\nimport { buildRecipientKeyringFile } from './team/keyring.js'\nimport { ensureCollectionDEK, hasAccess, hasExportCapability, hasImportCapability } from './team/keyring.js'\nimport type { ExportFormat, KeyringFile } from './types.js'\nimport {\n ExportCapabilityError,\n ImportCapabilityError,\n ValidationError,\n AlreadyElevatedError,\n ElevationExpiredError,\n TierNotGrantedError,\n AttestationError,\n} from './errors.js'\nimport type { NoydbEventEmitter } from './events.js'\nimport { BackupLedgerError, BackupCorruptedError } from './errors.js'\nimport type { StandardSchemaV1 } from './schema.js'\nimport type { BlobStrategy } from './blobs/strategy.js'\nimport type { ArchiveStrategy } from './archive/index.js'\nimport type { ArchivePolicy, ArchiveContext, ArchiveResult, ArchiveRunOptions } from './archive/index.js'\nimport { runArchive, runRestore, runListArchived } from './archive/index.js'\nimport { SequenceStore, type SequenceHandle, type SequenceOptions, resolveSequenceKey, SEQUENCE_COLLECTION } from './sequence/index.js'\nimport { DeferredNumberingStore, type Assignment } from './numbering/index.js'\nimport type { DeferredNumberingConfig } from './numbering/descriptor.js'\nimport type { IndexStrategy } from './indexing/strategy.js'\nimport type { AggregateStrategy } from './aggregate/strategy.js'\nimport type { CrdtStrategy } from './crdt/strategy.js'\n// — import from leaf modules (NOT from ./history/ledger/index.js\n// or store.js) so the LedgerStore class never reaches the floor\n// bundle. The leaf files hold pure constants + a tiny hash helper;\n// the class lives behind the history strategy seam.\nimport type { LedgerStore } from './history/ledger/store.js'\nimport { LEDGER_COLLECTION, LEDGER_DELTAS_COLLECTION } from './history/ledger/constants.js'\nimport { sha256Hex } from './history/ledger/entry.js'\nimport type { VaultInstant } from './history/time-machine.js'\nimport { NO_HISTORY, type HistoryStrategy } from './history/strategy.js'\nimport { NO_FORGET, type ForgetStrategy, type ForgetResult } from './forget/strategy.js'\nimport {\n addSubjectRef,\n removeSubjectRef,\n lookupSubject,\n rebuildSubjectIndex as rebuildSubjectIndexImpl,\n type SubjectRef,\n} from './forget/subject-index.js'\nimport { ForgetStrategyNotConfiguredError } from './errors.js'\nimport type { VaultFrame } from './shadow/vault-frame.js'\nimport { NO_SHADOW, type ShadowStrategy } from './shadow/strategy.js'\nimport type { ConsentContext, ConsentAuditEntry, ConsentAuditFilter, ConsentOp } from './consent/consent.js'\nimport { NO_CONSENT, type ConsentStrategy } from './consent/strategy.js'\nimport { NO_PERIODS, type PeriodsStrategy } from './periods/strategy.js'\nimport {\n RefRegistry,\n RefIntegrityError,\n type RefDescriptor,\n type RefViolation,\n} from './refs.js'\nimport type { DictionaryHandle, DictionaryOptions, DictKeyDescriptor, StaticDictDescriptor } from './i18n/dictionary.js'\nimport { isDictCollectionName, isStaticDictDescriptor } from './i18n/dictionary.js'\nimport type { I18nTextDescriptor } from './i18n/core.js'\nimport { getAtPath } from './i18n/core.js'\nimport type { MoneyDescriptor } from './money/descriptor.js'\nimport type { ComputedFields } from './computed/index.js'\nimport { NO_I18N, type I18nStrategy } from './i18n/strategy.js'\nimport { NO_SYNC, type SyncStrategy } from './team/sync-strategy.js'\n// Type-only imports for the guard + derivation subsystems. The\n// runtime classes are loaded on demand via `await import(...)` inside\n// `_initGuards` / `_initDerivations` (and the read-only-facade\n// accessor below) so consumers that never register a guard or\n// derivation strategy don't pay the chunk cost. This seam prevents\n// the bundle regression that motivated the lazy-import pattern.\nimport type { GuardRegistry } from './guards/registry.js'\nimport type { GuardStrategyHandleAny } from './guards/types.js'\nimport type { ReadOnlyVaultFacade } from './guards/read-only-facade.js'\nimport type { DerivationRegistry } from './derivations/registry.js'\nimport type { DerivationStrategyHandle } from './derivations/types.js'\nimport type { LocaleReadOptions, ConflictPolicy } from './types.js'\nimport type { CrdtMode } from './crdt/crdt.js'\nimport { ReservedCollectionNameError, StaticDictReadonlyError, UnknownDictCodeError } from './errors.js'\nimport {\n PERIODS_COLLECTION,\n type PeriodRecord,\n type ClosePeriodOptions,\n type OpenPeriodOptions,\n} from './periods/index.js'\nimport { encrypt, decrypt } from './crypto.js'\nimport {\n sealRecordToHost as sealRecordToHostImpl,\n revokeSealedRecord as revokeSealedRecordImpl,\n rotateRecordCek as rotateRecordCekImpl,\n type SealingContext,\n} from './record-keys/index.js'\nimport type { RecipientSealer } from './team/managed-passphrase.js'\nimport {\n createExportBlobsHandle,\n EXPORT_AUDIT_COLLECTION,\n type ExportBlobsOptions,\n type ExportBlobsHandle,\n type ExportBlobsAuditEntry,\n} from './blobs/export-blobs.js'\nimport { runCompaction, type BlobFieldsConfig, type CompactRunOptions, type CompactionResult } from './blobs/blob-compaction.js'\nimport {\n writeMagicLinkGrant,\n type IssueMagicLinkGrantOptions,\n type MagicLinkGrantRecord,\n} from './team/magic-link-grant.js'\nimport { UserApi } from './meta/user-envelope/api.js'\nimport { persistSchemaIfNeeded } from './persisted-schemas/register.js'\nimport { SchemaUpdateGate } from './schema-update/gate.js'\nimport { SchemaFenceController } from './schema-update/fence-controller.js'\nimport { FenceWatcher } from './schema-update/fence-watcher.js'\nimport { loadFence, type FenceDoc } from './schema-update/fence.js'\nimport type { SchemaUpdateStrategy, UpdateDecision, TransformFn } from './schema-update/types.js'\nimport { SCHEMAS_COLLECTION } from './persisted-schemas/storage.js'\nimport type { AttestationFieldSchema, RevocationList } from '@noy-db/attestation'\nimport type { IssueContext } from './attestation/issue.js'\nimport type { RevokeContext } from './attestation/revoke.js'\nimport type { DumpSchemaOptions, VaultSchemaSnapshot, SchemaIntrospection } from './introspection/types.js'\nimport { dumpVaultSchema, type VaultIntrospectState } from './introspection/walk.js'\nimport { USER_ENVELOPE_COLLECTION } from './meta/user-envelope/types.js'\n\n/**\n * Resolve a label from an in-memory `{ locale → label }` map, walking the\n * same fallback chain semantics as `DictionaryHandle.resolveLabel` (#291).\n * Used by the staticDict read-path resolver, which has no `_dict_*` handle.\n */\nfunction resolveLabelFromMap(\n labels: Readonly<Record<string, string>>,\n locale: string,\n fallback?: string | readonly string[],\n): string | undefined {\n if (labels[locale] !== undefined) return labels[locale]\n const chain = Array.isArray(fallback)\n ? (fallback as readonly string[])\n : fallback\n ? [fallback as string]\n : []\n for (const fb of chain) {\n if (fb === 'any') {\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 return undefined\n}\n\n/** A vault (tenant namespace) containing collections. */\nexport class Vault {\n private readonly adapter: NoydbStore\n /** The vault's name as passed to `openVault()`. Stable for the instance lifetime. */\n public readonly name: string\n /**\n * Backreference to the parent `Noydb`. Lets vault-scoped subsystems\n * (e.g. `as-*` reader `apply()` paths gating on `withTransactions()`)\n * reach the strategy seam without threading `db` through every API.\n *\n * Type-only Noydb import keeps the module graph acyclic at runtime.\n */\n public readonly noydb: Noydb\n /**\n * The active in-memory keyring. NOT readonly because `load()`\n * needs to refresh it after restoring a different keyring file —\n * otherwise the in-memory DEKs (from the pre-load session) and\n * the on-disk wrapped DEKs (from the loaded backup) drift apart\n * and every subsequent decrypt fails with TamperedError.\n */\n private keyring: UnlockedKeyring\n private readonly encrypted: boolean\n private readonly emitter: NoydbEventEmitter\n private readonly onDirty: OnDirtyCallback | undefined\n private readonly onRegisterConflictResolver: ((name: string, resolver: CollectionConflictResolver) => void) | undefined\n private readonly syncAdapter: NoydbStore | undefined\n private readonly historyConfig: HistoryConfig\n /**\n * tree-shake seam for the optional blob subsystem. Undefined\n * means \"blobs are off for this vault\"; every `collection.blob(id)`\n * call throws with a pointer at `@noy-db/hub/blobs`.\n */\n private readonly blobStrategy: BlobStrategy | undefined\n\n /** Cold-storage archival strategy (the archive target store). */\n private readonly archiveStrategy: ArchiveStrategy | undefined\n\n /** Per-collection record archival policies. Indexed by collection name. */\n private readonly archiveRegistry = new Map<string, ArchivePolicy>()\n private readonly indexStrategy: IndexStrategy | undefined\n private readonly aggregateStrategy: AggregateStrategy | undefined\n private readonly crdtStrategy: CrdtStrategy | undefined\n private readonly consentStrategy: ConsentStrategy\n private readonly periodsStrategy: PeriodsStrategy\n private readonly shadowStrategy: ShadowStrategy\n private readonly historyStrategy: HistoryStrategy\n private readonly forgetStrategy: ForgetStrategy\n private readonly i18nStrategy: I18nStrategy\n private readonly syncStrategy: SyncStrategy\n /**\n * Per-vault guard registry. `null` until `_initGuards()` runs; stays\n * `null` for vaults that never register any guard strategy. The\n * runtime class is dynamic-imported on demand so consumers that\n * never use guards don't pull `GuardRegistry`/`GuardExecutor` into\n * their bundle.\n */\n private guardRegistry: GuardRegistry | null = null\n /**\n * Per-vault derivation registry. Same lazy-load contract as\n * `guardRegistry` — `null` until `_initDerivations()` runs with at\n * least one strategy handle.\n */\n private derivationRegistry: DerivationRegistry | null = null\n /**\n * Per-vault materialized-view registry. Same lazy-load\n * contract as `derivationRegistry` — `null` until\n * `_initMaterializedViews()` runs with at least one MV handle.\n */\n private materializedViewRegistry: MaterializedViewRegistry | null = null\n /**\n * Per-vault overlay registry. Same lazy-load contract as\n * `materializedViewRegistry` — `null` until `_initOverlayedViews()`\n * runs with at least one handle.\n */\n private overlayedViewRegistry: OverlayedViewRegistry | null = null\n /**\n * Cached read-only facade handed to guard callbacks via `ctx.vault`,\n * and to derivation callbacks via `derive(source, ctx)`. Allocated\n * eagerly inside `_initGuards()` and/or `_initDerivations()` so read\n * accessors stay synchronous (callers in `tx/transaction.ts` rely on\n * that). Stays `null` for vaults with neither subsystem configured.\n */\n private readOnlyFacade: ReadOnlyVaultFacade | null = null\n private getDEK: (collectionName: string) => Promise<CryptoKey>\n\n /**\n * Per-principal user envelope API.\n *\n * - Write-self: `me()`, `updateMe(patch)`, `setMe(payload)` — always\n * target this vault session's keyringId. There is no method to write\n * another principal's envelope (own-only write rule, structural).\n * - Read-anyone: `get(keyringId)`, `list()` — read other principals'\n * envelopes, subject to the `view-team-profiles` policy gate.\n * - Reactive: `subscribe(id, cb)`, `live(id)` — fire on local writes.\n *\n * @see docs/superpowers/specs/2026-05-05-user-envelope-design.md\n */\n public readonly user: UserApi\n\n /**\n * Optional callback that re-derives an UnlockedKeyring from the\n * adapter using the active user's passphrase. Called by `load()`\n * after the on-disk keyring file has been replaced — refreshes\n * `this.keyring` so the next DEK access uses the loaded wrapped\n * DEKs instead of the stale pre-load ones.\n *\n * Provided by Noydb at openVault() time. Tests that\n * construct Vault directly can pass `undefined`; load()\n * skips the refresh in that case (which is fine for plaintext\n * compartments — there's nothing to re-unwrap).\n */\n private readonly reloadKeyring: (() => Promise<UnlockedKeyring>) | undefined\n private readonly collectionCache = new Map<string, Collection<unknown>>()\n /** Vault-level schema cutover fence/controller. */\n readonly schemaFence: SchemaFenceController\n /** Per-client heartbeat/watcher; started lazily on cutover registration. */\n #fenceWatcher: FenceWatcher | undefined\n #fenceCoordinationStarted = false\n /** Per-collection registered schema-update strategy names. */\n readonly #schemaUpdateNames = new Map<string, string[]>()\n\n /**\n * per-collection `blobFields` retention/TTL config.\n * Populated on `collection({ blobFields })` and read by\n * `vault.compact()`. Indexed by collection name.\n */\n private readonly blobFieldsRegistry = new Map<string, BlobFieldsConfig<unknown>>()\n\n /**\n * Per-collection attestation field-schema (issue side). Populated on\n * `collection({ attestation })` and read by `issueAttestation()`.\n * Indexed by collection name.\n */\n private readonly attestationRegistry = new Map<string, AttestationFieldSchema>()\n\n /**\n * Per-vault ledger store. Lazy-initialized on first\n * `collection()` call (which passes it through to the Collection)\n * or on first `ledger()` call from user code.\n *\n * One LedgerStore is shared across all collections in a vault\n * because the hash chain is vault-scoped: the chain head is a\n * single \"what did this vault do last\" identifier, not a\n * per-collection one. Two collections appending concurrently is the\n * single-writer concurrency concern documented in the LedgerStore\n * docstring.\n */\n private ledgerStore: LedgerStore | null = null\n\n /** Lazily-built atomic-sequence store. See {@link sequence}. */\n private sequenceStore: SequenceStore | null = null\n /** Lazily-built deferred-numbering engine. See {@link runNumberingPass}. */\n private deferredNumbering: DeferredNumberingStore | null = null\n /** Registered deferred-numbering series, keyed by series name. */\n private readonly numberingConfigs: Map<string, DeferredNumberingConfig>\n\n /**\n * Background writes for persisted-schema envelopes (#schema-dump v0\n * slice 1). One promise per `collection({ persistJsonSchema: true })`\n * registration that actually fired a derive call. Fire-and-forget\n * from the collection factory; tests await\n * {@link _drainPendingSchemaWrites} before asserting on storage.\n * Production code does not need to drain — the writes are\n * idempotent fingerprints, not correctness invariants.\n */\n private _pendingSchemaWrites: Promise<void>[] = []\n\n /**\n * Per-vault foreign-key reference registry. Collections\n * register their `refs` option here on construction; the\n * vault uses the registry on every put/delete/checkIntegrity\n * call. One instance lives for the compartment's lifetime.\n */\n private readonly refRegistry = new RefRegistry()\n\n /**\n * Set of collection record-ids currently being deleted as part of\n * a cascade. Populated on entry to `enforceRefsOnDelete` and\n * drained on exit. Used to break mutual-cascade cycles: deleting\n * A → cascade to B → cascade back to A would otherwise recurse\n * forever, so we short-circuit when we see an already-in-progress\n * delete on the same (collection, id) pair.\n */\n private readonly cascadeInProgress = new Set<string>()\n\n /**\n * Vault-default locale. Set via\n * `openVault(name, { locale })`. Used as the fallback locale\n * when per-call `{ locale }` options are not specified on individual\n * `get()`/`list()` calls.\n */\n private locale: string | undefined\n\n /**\n * Current consent scope. Set by `withConsent()` and\n * restored in its finally block. When non-null, every collection\n * access inside the scope writes one entry to `_consent_audit`.\n *\n * Single-slot by design — two concurrent withConsent calls on the\n * same Vault stomp each other. Adopters needing per-flight scoping\n * should use separate Vault instances.\n */\n private consentContext: ConsentContext | null = null\n\n /**\n * Cache of closed/opened accounting periods.\n * Populated on first `closePeriod` / `openPeriod` / `listPeriods` /\n * per-collection write call. Kept in memory as an ordered list (by\n * `closedAt`) so period checks run fast when the gate bus fires.\n *\n * Sentinel `null` means \"not yet loaded\" — the first consumer\n * triggers a one-time `loadPeriods()` pass. Every subsequent\n * closure/opening pushes into the cache in-place so the next write\n * sees the updated chain without re-reading the adapter.\n */\n private periodCache: PeriodRecord[] | null = null\n\n /**\n * Registry of dictKey fields declared across all collections in this\n * vault. Keyed by collection name → field name → dictionary name.\n * Used by `DictionaryHandle.rename()` to find and update all records\n * referencing a renamed key.\n *\n * Populated by `collection()` when the `dictKeyFields` option is passed.\n */\n private readonly dictKeyFieldRegistry = new Map<\n string, // collection name\n Record<string, string> // field name → dictionary name\n >()\n\n /**\n * Names of dictionaries backed by a `staticDict()` descriptor (#291).\n * A static dict skips the `dictKeyFieldRegistry` rename machinery, but the\n * vault must still *know* a name is static so `vault.dictionary(name)` can\n * refuse mutation (`StaticDictReadonlyError`). Populated at `collection()`\n * config time whenever a `StaticDictDescriptor` is seen.\n */\n private readonly staticDictNames = new Set<string>()\n\n /**\n * Static-dict descriptors keyed by dictionary name (#291). Backs the\n * read-path label resolver (resolve from the in-memory table) and the\n * query-seam `resolveDictSource` snapshot. Last writer wins when the same\n * name is registered by multiple collections (identical-across-vaults by\n * construction, so the tables match).\n */\n private readonly staticByName = new Map<string, StaticDictDescriptor>()\n\n /**\n * Per-collection map of field name → StaticDictDescriptor (#291). Used by\n * `enforceStaticDictOnPut` to validate stored codes against `desc.keys`.\n */\n private readonly staticDescriptorByField = new Map<\n string, // collection name\n Record<string, StaticDictDescriptor>\n >()\n\n /**\n * Registry of i18nText fields declared across all collections. Keyed\n * by collection name → field name → I18nTextDescriptor. Used by\n * `applyI18nLocale` on reads and by `validateI18nTextValue` on puts.\n *\n * Populated by `collection()` when the `i18nFields` option is passed.\n */\n private readonly i18nFieldRegistry = new Map<\n string, // collection name\n Record<string, I18nTextDescriptor>\n >()\n\n /** Cache of DictionaryHandle instances, one per dictionary name. */\n private readonly dictionaryCache = new Map<string, DictionaryHandle>()\n\n /** — subscribers for cross-tier access events. */\n private readonly crossTierSubs = new Set<(event: CrossTierAccessEvent) => void>()\n\n /** — currently-active elevation, or null. One per vault. */\n private activeElevation: {\n readonly tier: number\n readonly expiresAt: number\n readonly reason: string\n readonly handle: ElevatedHandle\n } | null = null\n\n /**\n * Optional translator callback threaded from `Noydb.invokeTranslator`.\n * Present only when `plaintextTranslator` was configured on `createNoydb()`.\n */\n private readonly translateText:\n | ((text: string, from: string, to: string, field: string, collection: string) => Promise<string>)\n | undefined\n\n constructor(opts: {\n adapter: NoydbStore\n name: string\n noydb: Noydb\n keyring: UnlockedKeyring\n encrypted: boolean\n emitter: NoydbEventEmitter\n onDirty?: OnDirtyCallback | undefined\n historyConfig?: HistoryConfig | undefined\n reloadKeyring?: (() => Promise<UnlockedKeyring>) | undefined\n /** Vault-default locale. */\n locale?: string | undefined\n /** Translator callback from Noydb. */\n plaintextTranslator?:\n | ((text: string, from: string, to: string, field: string, collection: string) => Promise<string>)\n | undefined\n /**\n * callback to register a per-collection envelope-level\n * conflict resolver with the SyncEngine. Present when sync is configured.\n */\n onRegisterConflictResolver?: ((name: string, resolver: CollectionConflictResolver) => void) | undefined\n /** — optional remote/sync adapter for presence broadcasting. */\n syncAdapter?: NoydbStore | undefined\n /**\n * tree-shake seam — strategy for optional blob storage.\n * Passed through to every `Collection` built by `vault.collection()`.\n * `undefined` => every `collection.blob(id)` throws with a pointer\n * at `@noy-db/hub/blobs`.\n */\n blobStrategy?: BlobStrategy | undefined\n archiveStrategy?: ArchiveStrategy | undefined\n indexStrategy?: IndexStrategy | undefined\n aggregateStrategy?: AggregateStrategy | undefined\n crdtStrategy?: CrdtStrategy | undefined\n consentStrategy?: ConsentStrategy | undefined\n periodsStrategy?: PeriodsStrategy | undefined\n shadowStrategy?: ShadowStrategy | undefined\n historyStrategy?: HistoryStrategy | undefined\n i18nStrategy?: I18nStrategy | undefined\n syncStrategy?: SyncStrategy | undefined\n guardStrategies?: ReadonlyArray<GuardStrategyHandleAny> | undefined\n numberingConfigs?: ReadonlyArray<DeferredNumberingConfig> | undefined\n forgetStrategy?: ForgetStrategy | undefined\n }) {\n this.adapter = opts.adapter\n this.name = opts.name\n this.numberingConfigs = new Map((opts.numberingConfigs ?? []).map((c) => [c.series, c]))\n this.noydb = opts.noydb\n this.keyring = opts.keyring\n this.encrypted = opts.encrypted\n this.schemaFence = new SchemaFenceController({\n store: this.adapter,\n vault: this.name,\n onFlush: () => this.noydb._writeQueueTracker.onFlush(),\n clientId: this.noydb._clientId,\n emit: (e) => this.emitter.emit('schema:fence-changed', { vault: this.name, ...e }),\n })\n this.emitter = opts.emitter\n this.onDirty = opts.onDirty\n this.onRegisterConflictResolver = opts.onRegisterConflictResolver\n this.syncAdapter = opts.syncAdapter\n this.blobStrategy = opts.blobStrategy\n this.archiveStrategy = opts.archiveStrategy\n this.indexStrategy = opts.indexStrategy\n this.aggregateStrategy = opts.aggregateStrategy\n this.crdtStrategy = opts.crdtStrategy\n this.consentStrategy = opts.consentStrategy ?? NO_CONSENT\n this.periodsStrategy = opts.periodsStrategy ?? NO_PERIODS\n this.shadowStrategy = opts.shadowStrategy ?? NO_SHADOW\n this.historyStrategy = opts.historyStrategy ?? NO_HISTORY\n this.forgetStrategy = opts.forgetStrategy ?? NO_FORGET\n this.i18nStrategy = opts.i18nStrategy ?? NO_I18N\n this.syncStrategy = opts.syncStrategy ?? NO_SYNC\n // Guard + derivation registries are initialised lazily via\n // `_initGuards()` / `_initDerivations()` from `Noydb.openVault()`.\n // The classes are dynamic-imported there so vaults that never\n // register a strategy don't pull the subsystem code into the\n // floor bundle. The `opts.guardStrategies` argument is\n // intentionally accepted but unused on the constructor — the sync\n // `vault()` fallback path in `noydb.ts` does NOT call `_initGuards`,\n // matching the existing behaviour for `_initDerivations`.\n void opts.guardStrategies\n this.historyConfig = opts.historyConfig ?? { enabled: true }\n this.reloadKeyring = opts.reloadKeyring\n this.locale = opts.locale\n this.translateText = opts.plaintextTranslator\n\n // Build the lazy DEK resolver. Pulled out into a private method\n // so `load()` can rebuild it after a keyring refresh — the\n // closure captures `this.keyring` by reference, so changing the\n // field is enough, but resetting the cached `getDEKFn` ensures\n // ensureCollectionDEK runs again against the freshly-loaded\n // wrapped DEKs.\n this.getDEK = this.makeGetDEK()\n\n // User envelope API — frozen writerKeyringId, dynamic DEK resolver\n // (so a post-load() keyring refresh transparently rotates the DEK\n // through the rebuilt this.getDEK), and a checkGate callback that\n // delegates to Noydb's policy engine (wires edit-own-profile +\n // view-team-profiles).\n this.user = new UserApi(\n this.adapter,\n this.name,\n this.keyring.userId,\n () => this.getDEK(USER_ENVELOPE_COLLECTION),\n (gate, presented) => this.noydb.checkGate(this.name, gate, presented),\n )\n }\n\n /**\n * Construct (or reconstruct) the lazy DEK resolver. Captures the\n * CURRENT value of `this.keyring` and `this.adapter` in a closure,\n * memoizing the inner getDEKFn after first use so subsequent\n * lookups are O(1).\n *\n * `load()` calls this after refreshing `this.keyring` to discard\n * the prior session's cached DEKs.\n */\n private makeGetDEK(): (collectionName: string) => Promise<CryptoKey> {\n let getDEKFn: ((collectionName: string) => Promise<CryptoKey>) | null = null\n return async (collectionName: string): Promise<CryptoKey> => {\n if (!getDEKFn) {\n getDEKFn = await ensureCollectionDEK(this.adapter, this.name, this.keyring)\n }\n return getDEKFn(collectionName)\n }\n }\n\n /**\n * Open a typed collection within this vault.\n *\n * - `options.indexes` declares secondary indexes for the query DSL.\n * Indexes are computed in memory after decryption; adapters never\n * see plaintext index data.\n * - `options.prefetch` (default `true`) controls hydration. Eager mode\n * loads everything on first access; lazy mode (`prefetch: false`)\n * loads records on demand and bounds memory via the LRU cache.\n * - `options.cache` configures the LRU bounds. Required in lazy mode.\n * Accepts `{ maxRecords, maxBytes: '50MB' | 1024 }`.\n * - `options.schema` attaches a Standard Schema v1 validator (Zod,\n * Valibot, ArkType, Effect Schema, etc.). Every `put()` is validated\n * before encryption; every read is validated after decryption.\n * Failing records throw `SchemaValidationError`.\n * - `options.i18nFields` declares per-field `i18nText()` descriptors\n *. Validated on `put()` and locale-resolved on reads.\n * - `options.dictKeyFields` declares per-field `dictKey()` descriptors\n *. `put()` validates keys against the declared set; reads\n * with `{ locale }` add `<field>Label` virtual fields.\n *\n * Throws `ReservedCollectionNameError` for names starting with `_dict_` or\n * equal to `_sequences`. Use `vault.dictionary(name)` for dict collections\n * and `vault.sequence(name)` for sequence counters.\n *\n * Lazy mode + indexes is rejected at construction time — see the\n * Collection constructor for the rationale.\n */\n collection<T>(collectionName: string, options?: {\n indexes?: IndexDef[]\n /** — auto-reconcile policy for persisted-index drift. */\n reconcileOnOpen?: 'off' | 'dry-run' | 'auto'\n prefetch?: boolean\n cache?: CacheOptions\n schema?: StandardSchemaV1<unknown, T>\n refs?: Record<string, RefDescriptor>\n /** — declare i18nText fields for locale-aware reads. */\n i18nFields?: Record<string, I18nTextDescriptor>\n /** — declare dictKey / staticDict fields for label resolution on reads. */\n dictKeyFields?: Record<string, DictKeyDescriptor | StaticDictDescriptor>\n /** — declare money() fields for currency-safe decimal storage/formatting. */\n moneyFields?: Record<string, MoneyDescriptor>\n /** — declare computed scalar fields, evaluated on write (schema-owned). */\n computed?: ComputedFields<T>\n /** — per-collection conflict resolution policy. */\n conflictPolicy?: ConflictPolicy<T>\n /** — CRDT mode for collaborative editing without conflicts. */\n crdt?: CrdtMode\n /**\n * declare deterministic-encryption fields for blind\n * equality search. See `Collection` constructor docs for the full\n * trade-off. Requires `acknowledgeDeterministicRisk: true`.\n */\n deterministicFields?: readonly string[]\n /** — explicit ack that deterministic encryption leaks equality. */\n acknowledgeDeterministicRisk?: boolean\n /**\n * — per-record content-encryption keys. When `true`, every record\n * body is encrypted under a fresh per-record CEK wrapped under the\n * collection DEK (`_cek`), stable across versions. Foundation for\n * per-record erasure (#304) / record-scoped sealing (#306). Off by\n * default; non-adopting collections take the legacy path unchanged.\n */\n perRecordKeys?: boolean\n /**\n * declarative blob retention / TTL policy per slot\n * name. Values are `{ retainDays?, evictWhen? }`. Evaluated only\n * when `vault.compact()` runs.\n */\n blobFields?: BlobFieldsConfig<T>\n /** — declarative record archival policy: `{ archiveWhen, legalHold? }`. Evaluated when `vault.archive()` runs. */\n archive?: ArchivePolicy<T>\n /** — declared tiers for this collection. */\n tiers?: readonly number[]\n /** — how lower-tier reads see above-tier records. */\n tierMode?: TierMode\n /**\n * Opt-in persisted JSON Schema. When `true` AND a Zod `schema` is\n * provided, hub derives a JSON Schema via `zod-to-json-schema`\n * (optional peer-dep) and writes an encrypted snapshot to\n * `_schemas/<collectionName>`. Re-runs on every open; hash-skip\n * avoids write churn when the schema is unchanged.\n *\n * Default: `false`. Non-Zod Standard Schema validators receive a\n * stub envelope flagging the kind without a JSON Schema body.\n *\n * @see docs/superpowers/specs/2026-05-22-schema-dump-design.md\n */\n persistJsonSchema?: boolean\n /**\n * Ordered schema-update strategies. On a detected schema\n * change, evaluated in order; the first non-`allow` decision wins.\n * A `reject` is enforced at the write path (`put`/`delete` throw).\n * Requires `persistJsonSchema: true` (detection needs the baseline).\n */\n schemaUpdate?: readonly SchemaUpdateStrategy[]\n /** — declare the per-field schema for document attestation (issue side). */\n attestation?: AttestationFieldSchema\n }): Collection<T> {\n // Overlay intercept. When the requested collection name\n // matches a registered `withOverlayedView`, return the virtual\n // proxy that merges base + overlay on read and routes writes to\n // the overlay collection. The proxy implements the core\n // Collection<T> read/write surface (get, list, put, delete);\n // reactive APIs (live, subscribe) are out of scope.\n const overlayRegistry = this.overlayedViewRegistry\n if (overlayRegistry !== null && overlayRegistry.isOverlay(collectionName)) {\n const spec = overlayRegistry.byName(collectionName)\n if (spec) {\n // Recursive call into the same method — the base + overlay\n // are real collections, so they re-enter this method without\n // hitting the overlay intercept (their names won't match).\n const base = this.collection<T>(spec.base)\n const overlay = this.collection<T>(spec.overlay)\n const baseRowKey = overlayRegistry.resolveBaseRowKey(collectionName, this.materializedViewRegistry)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return new OverlayedCollection<any>(spec, base, overlay, baseRowKey) as unknown as Collection<T>\n }\n }\n // Guard: reject reserved _dict_* names\n if (isDictCollectionName(collectionName)) {\n throw new ReservedCollectionNameError(collectionName)\n }\n // Guard: reject the internal _sequences collection — use vault.sequence() instead.\n if (collectionName === SEQUENCE_COLLECTION) {\n throw new ReservedCollectionNameError(collectionName)\n }\n\n let coll = this.collectionCache.get(collectionName)\n if (coll && options?.moneyFields) {\n // The collection may have been auto-created (without options) by\n // materialized-view dependency analysis during openVault, before\n // this declaration. Reconcile money descriptors onto it so writes\n // quantize and money-aware aggregation applies. First-wins.\n coll._applyMoneyFields(options.moneyFields)\n }\n if (coll && options?.computed) {\n // Same MV-pre-creation reconcile as money: a collection used as an\n // MV source is auto-created (without options) before this\n // declaration; attach computed fields so writes materialize them.\n coll._applyComputed(options.computed as ComputedFields)\n }\n if (!coll) {\n // Register ref declarations (if any) with the vault-level\n // registry BEFORE constructing the Collection. This way the\n // first put() on the new collection already sees its refs via\n // vault.enforceRefsOnPut.\n if (options?.refs) {\n this.refRegistry.register(collectionName, options.refs)\n }\n\n // Register i18nText fields\n if (options?.i18nFields) {\n this.i18nFieldRegistry.set(collectionName, options.i18nFields)\n }\n\n // register blobFields retention/TTL policy\n if (options?.blobFields) {\n this.blobFieldsRegistry.set(collectionName, options.blobFields as BlobFieldsConfig<unknown>)\n }\n\n // register record archival policy\n if (options?.archive) {\n this.archiveRegistry.set(collectionName, options.archive as ArchivePolicy)\n }\n\n // register the per-collection attestation field-schema\n if (options?.attestation !== undefined) {\n this.attestationRegistry.set(collectionName, options.attestation)\n }\n\n // Register dictKey / staticDict fields. Plain dictKey fields go into\n // the rename-tracking registry; staticDict fields (#291) skip it (no\n // per-vault pointer rewrite) and instead populate the static\n // registries that back the read-path resolver, the readonly guard, and\n // put-time code validation.\n if (options?.dictKeyFields) {\n const dictFieldMap: Record<string, string> = {}\n const staticFieldMap: Record<string, StaticDictDescriptor> = {}\n for (const [field, desc] of Object.entries(options.dictKeyFields)) {\n if (isStaticDictDescriptor(desc)) {\n staticFieldMap[field] = desc\n this.staticDictNames.add(desc.name)\n this.staticByName.set(desc.name, desc)\n } else {\n dictFieldMap[field] = desc.name\n }\n }\n if (Object.keys(dictFieldMap).length > 0) {\n this.dictKeyFieldRegistry.set(collectionName, dictFieldMap)\n }\n if (Object.keys(staticFieldMap).length > 0) {\n this.staticDescriptorByField.set(collectionName, staticFieldMap)\n }\n }\n\n // Capture registered schema-update strategy names for introspection.\n if ((options?.schemaUpdate?.length ?? 0) > 0) {\n this.#schemaUpdateNames.set(collectionName, (options!.schemaUpdate ?? []).map((s) => s.name))\n }\n\n // Schema-update gate. Built only when persistence + strategies\n // are on. Detection runs in the same work pushed to the drain; the\n // gate caches the decision and the write path (put/delete) enforces it.\n let schemaUpdateGate: SchemaUpdateGate | undefined\n if (\n options?.persistJsonSchema === true &&\n options.schema !== undefined &&\n (options.schemaUpdate?.length ?? 0) > 0\n ) {\n const validator: unknown = options.schema\n const strategies = options.schemaUpdate ?? []\n const work = (async (): Promise<UpdateDecision> => {\n const dek = await this.getDEK(collectionName)\n const result = await persistSchemaIfNeeded({\n store: this.adapter, vault: this.name, collectionName, validator, dek, strategies,\n })\n const decision = result.decision ?? { action: 'allow' as const }\n if (decision.action === 'cutover') {\n this.schemaFence.registerPendingCutover(collectionName, decision.transform)\n this._ensureFenceCoordination()\n }\n return decision\n })()\n this._pendingSchemaWrites.push(work.then(() => {}, () => {}))\n schemaUpdateGate = new SchemaUpdateGate(work)\n }\n\n const collOpts: ConstructorParameters<typeof Collection<T>>[0] = {\n adapter: this.adapter,\n vault: this.name,\n name: collectionName,\n keyring: this.keyring,\n encrypted: this.encrypted,\n emitter: this.emitter,\n writeQueue: this.noydb._writeQueueTracker,\n writeHooks: this.noydb._writeHooks,\n subsystemBus: this.noydb._subsystemBus,\n activeTxId: () => this.noydb._activeTxContextOrNull?.txId ?? null,\n schemaUpdateGate,\n schemaFence: this.schemaFence,\n getDEK: this.getDEK,\n onDirty: this.onDirty,\n historyConfig: this.historyConfig,\n // thread the vault-wide blob strategy into every\n // collection. `undefined` is intentionally preserved so the\n // Collection constructor uses its NO_BLOBS default.\n ...(this.blobStrategy !== undefined ? { blobStrategy: this.blobStrategy } : {}),\n ...(this.indexStrategy !== undefined ? { indexStrategy: this.indexStrategy } : {}),\n ...(this.aggregateStrategy !== undefined ? { aggregateStrategy: this.aggregateStrategy } : {}),\n ...(this.crdtStrategy !== undefined ? { crdtStrategy: this.crdtStrategy } : {}),\n historyStrategy: this.historyStrategy,\n i18nStrategy: this.i18nStrategy,\n syncStrategy: this.syncStrategy,\n ledger: this.getLedgerOrNull() ?? undefined,\n refEnforcer: this,\n joinResolver: this,\n defaultLocale: this.locale,\n onRegisterConflictResolver: this.onRegisterConflictResolver,\n onAccess: (op, id) => this._logConsent(op, collectionName, id),\n // Derivation source is only wired when the corresponding registry\n // has been initialised. Guard source was removed in Track A slice 3b\n // — guards now run via the gate bus in Noydb.#registerGuardGate.\n // Vaults without derivations skip this so `Collection.put`'s\n // `if (this.derivationSource)` branch no-ops without touching the\n // derivation subsystem code.\n ...(this.derivationRegistry !== null\n ? {\n derivationSource: {\n registry: () => this.derivationRegistry as DerivationRegistry,\n getCollection: (name: string) =>\n this.collection(name) as unknown as Collection<Record<string, unknown>>,\n getReadOnlyFacade: () => this._ensureReadOnlyFacade(),\n getActiveTxContext: () => this.noydb._activeTxContextOrNull,\n createTxContext: () => this.noydb._createTxContext(),\n setActiveTxContext: (ctx) => this.noydb._setActiveTxContext(ctx),\n clearActiveTxContext: (ctx) => this.noydb._clearActiveTxContext(ctx),\n },\n }\n : {}),\n ...(this.materializedViewRegistry !== null\n ? {\n materializedViewSource: {\n \n registry: () => this.materializedViewRegistry!,\n getCollection: (name: string) => this.collection(name),\n getActiveTxContext: () => this.noydb._activeTxContextOrNull,\n getQueryContext: () => this as unknown as MVQueryContext,\n },\n }\n : {}),\n }\n if (options?.indexes !== undefined) collOpts.indexes = options.indexes\n if (options?.reconcileOnOpen !== undefined) collOpts.reconcileOnOpen = options.reconcileOnOpen\n if (options?.prefetch !== undefined) collOpts.prefetch = options.prefetch\n if (options?.cache !== undefined) collOpts.cache = options.cache\n if (options?.schema !== undefined) collOpts.schema = options.schema\n if (options?.conflictPolicy !== undefined) collOpts.conflictPolicy = options.conflictPolicy\n if (options?.crdt !== undefined) collOpts.crdt = options.crdt\n if (options?.deterministicFields !== undefined) {\n collOpts.deterministicFields = options.deterministicFields\n }\n if (options?.acknowledgeDeterministicRisk !== undefined) {\n collOpts.acknowledgeDeterministicRisk = options.acknowledgeDeterministicRisk\n }\n if (options?.perRecordKeys !== undefined) {\n collOpts.perRecordKeys = options.perRecordKeys\n }\n // #304 — a collection declared in `withForgetCascade({ subjects })` MUST\n // use per-record CEKs: crypto-shred can only guarantee erasure of a body\n // keyed off a per-record CEK. Force it on (and warn if the caller\n // explicitly set it false — that would silently defeat erasure).\n if (this.forgetStrategy.subjects[collectionName] !== undefined) {\n if (options?.perRecordKeys === false) {\n console.warn(\n `[noy-db] Collection \"${collectionName}\" is declared in withForgetCascade ` +\n `but opened with perRecordKeys: false. Forcing perRecordKeys: true — ` +\n `GDPR crypto-shred requires per-record CEKs.`,\n )\n }\n collOpts.perRecordKeys = true\n }\n if (options?.tiers !== undefined) collOpts.tiers = options.tiers\n if (options?.tierMode !== undefined) collOpts.tierMode = options.tierMode\n collOpts.onCrossTierAccess = (event) => this.emitCrossTier(event)\n if (this.syncAdapter !== undefined) collOpts.syncAdapter = this.syncAdapter\n if (options?.i18nFields !== undefined) collOpts.i18nFields = options.i18nFields\n if (options?.moneyFields !== undefined) collOpts.moneyFields = options.moneyFields\n if (options?.computed !== undefined) collOpts.computed = options.computed as ComputedFields\n if (options?.dictKeyFields !== undefined) {\n // Build the label resolver callback for this collection. A static\n // dict (#291) resolves from its in-memory table — no dictionary()\n // lookup, no _dict_* read — while a plain dictKey resolves through\n // the encrypted _dict_* handle as before.\n collOpts.dictLabelResolver = async (dictName, key, locale, fallback) => {\n const stat = this.staticByName.get(dictName)\n if (stat) {\n const labels = stat.table[key]\n return labels ? resolveLabelFromMap(labels, locale, fallback) : undefined\n }\n const handle = this.dictionary(dictName)\n return handle.resolveLabel(key, locale, fallback)\n }\n collOpts.dictKeyFields = options.dictKeyFields\n }\n // i18n / staticDict validation on put — enforced via the compartment's\n // put hook. staticDict adds put-time code validation (#291).\n if (\n options?.i18nFields !== undefined ||\n options?.dictKeyFields !== undefined\n ) {\n collOpts.i18nPutValidator = (record: unknown) => {\n this.enforceI18nOnPut(collectionName, record)\n this.enforceStaticDictOnPut(collectionName, record)\n }\n }\n // Wire the translator for autoTranslate: true fields\n if (options?.i18nFields !== undefined && this.translateText) {\n collOpts.autoTranslateHook = this.translateText\n }\n coll = new Collection<T>(collOpts)\n this.collectionCache.set(collectionName, coll)\n\n // Fire-and-forget persisted-schema write when opted in. Pushed\n // onto _pendingSchemaWrites so tests can drain before asserting;\n // production code ignores it (the writes are idempotent fingerprints).\n // When schemaUpdate strategies are present, persistence already ran\n // inside the gate's work above — skip the un-gated path here.\n if (\n options?.persistJsonSchema === true &&\n options.schema !== undefined &&\n (options.schemaUpdate?.length ?? 0) === 0\n ) {\n const validator: unknown = options.schema\n const work = (async () => {\n try {\n const dek = await this.getDEK(collectionName)\n await persistSchemaIfNeeded({\n store: this.adapter,\n vault: this.name,\n collectionName,\n validator,\n dek,\n })\n } catch (err) {\n // Schema persistence is a fingerprint, not a correctness\n // invariant — log and continue. Production callers can\n // still detect failures via _drainPendingSchemaWrites.\n \n console.warn(\n `[noy-db] persisted-schema write failed for \"${collectionName}\": `\n + (err instanceof Error ? err.message : String(err)),\n )\n }\n })()\n this._pendingSchemaWrites.push(work)\n }\n }\n return coll as Collection<T>\n }\n\n /**\n * Await all background persisted-schema writes triggered by\n * `collection({ persistJsonSchema: true })` calls on this vault.\n * Used in tests; production code does not need to call this.\n */\n async _drainPendingSchemaWrites(): Promise<void> {\n const pending = this._pendingSchemaWrites\n this._pendingSchemaWrites = []\n await Promise.allSettled(pending)\n }\n\n /**\n * Run a coordinated schema cutover. Drains pending writes, waits\n * for the active client set to quiesce (the ack-barrier), applies every\n * pending collection transform in bulk, bumps the vault schema generation,\n * and clears the fence. Returns the count of collections migrated.\n * `opts.onPoll` (tests) advances other clients between barrier checks.\n */\n async runSchemaCutover(opts?: { onPoll?: () => Promise<void> }): Promise<{ migrated: number }> {\n return this.schemaFence.runCutover(\n (collectionName, transform) => this.#runCutoverTransform(collectionName, transform),\n opts,\n )\n }\n\n async #runCutoverTransform(collectionName: string, transform: TransformFn): Promise<void> {\n const coll = this.collectionCache.get(collectionName)\n if (!coll) return\n await coll._applyCutoverTransform(transform)\n }\n\n /**\n * Refresh a loaded collection's view of one document from a peer\n * tab's broadcast. No-op when the collection isn't loaded in this tab\n * (it will read fresh on next open). Mirrors `#runCutoverTransform`'s guard.\n */\n async _applyRemoteWrite(collectionName: string, docId: string, action: 'put' | 'delete'): Promise<void> {\n const coll = this.collectionCache.get(collectionName)\n if (!coll) return\n await coll._applyRemoteChange(docId, action)\n }\n\n /**\n * For a detected conflict: capture this tab's clobbered record,\n * read the common ancestor from history, converge the cache to the store's\n * authoritative value (the re-read), and return all three for the\n * WriteConflict payload. Returns null when the collection isn't loaded.\n */\n async _captureAndConverge(\n collectionName: string,\n docId: string,\n action: 'put' | 'delete',\n baseV: number,\n ): Promise<{ local: unknown; remote: unknown; base: unknown } | null> {\n const coll = this.collectionCache.get(collectionName)\n if (!coll) return null\n // `local` is the pre-converge cached record (the clobbered write) — peek only, no store read.\n // Consumers must not mutate the returned records: in eager mode they alias live cache entries.\n const local = coll._peekCached(docId)\n let base: unknown = null\n try { base = await coll.getVersion(docId, baseV) } catch { base = null }\n await coll._applyRemoteChange(docId, action)\n // `remote` is the post-converge authoritative value via the universal read path\n // (cache in eager mode; a store read in lazy mode, where the LRU entry was just evicted).\n const remote = await coll.get(docId)\n return { local, remote, base }\n }\n\n /** Recover a stuck cutover fence — reset to normal without bumping. */\n async abortSchemaCutover(): Promise<void> {\n await this.schemaFence.abort()\n }\n\n /** Current schema-cutover fence state for this vault. Thin live read. */\n async schemaFenceState(): Promise<FenceDoc> {\n return loadFence(this.adapter, this.name)\n }\n\n /** @internal Start the per-client heartbeat + fence watcher once a cutover is registered. */\n _ensureFenceCoordination(): void {\n if (this.#fenceCoordinationStarted) return\n this.#fenceCoordinationStarted = true\n this.#fenceWatcher = new FenceWatcher({\n store: this.adapter,\n vault: this.name,\n clientId: this.noydb._clientId,\n onFlush: () => this.noydb._writeQueueTracker.onFlush(),\n emit: (e) => this.emitter.emit('schema:fence-changed', { vault: this.name, ...e }),\n })\n this.#fenceWatcher.start(2_000) // heartbeat + poll; unref'd so it never holds the process open\n }\n\n /** @internal Stop the heartbeat/watcher (vault lock/close). */\n _stopFenceCoordination(): void {\n this.#fenceWatcher?.stop()\n this.#fenceWatcher = undefined\n this.#fenceCoordinationStarted = false\n }\n\n /** @internal Drive one heartbeat + watch cycle deterministically (tests). */\n async _fenceTick(): Promise<void> {\n this._ensureFenceCoordination()\n await this.#fenceWatcher!.beat()\n await this.#fenceWatcher!.check()\n }\n\n /**\n * Validate i18nText fields on a `put()`. Called by Collection just\n * before the adapter write, after schema validation. Throws\n * `MissingTranslationError` when a required translation is absent.\n */\n enforceI18nOnPut(collectionName: string, record: unknown): void {\n const i18nFields = this.i18nFieldRegistry.get(collectionName)\n if (!i18nFields || Object.keys(i18nFields).length === 0) return\n if (!record || typeof record !== 'object') return\n\n const obj = record as Record<string, unknown>\n for (const [field, descriptor] of Object.entries(i18nFields)) {\n const values = getAtPath(obj, field)\n for (const value of values) {\n if (value === undefined || value === null) continue\n this.i18nStrategy.validateI18nTextValue(value, field, descriptor)\n }\n }\n }\n\n /**\n * Validate staticDict codes on a `put()` (#291). For each `staticDict()`\n * field, every stored code must be a declared key of the descriptor's\n * table, else `UnknownDictCodeError`. Opt out per descriptor with\n * `{ validateCodes: false }`. Supports scalar, dotted, and `[].`-wildcard\n * field paths via `getAtPath` (same path support as i18n validation).\n */\n enforceStaticDictOnPut(collectionName: string, record: unknown): void {\n const staticFields = this.staticDescriptorByField.get(collectionName)\n if (!staticFields || Object.keys(staticFields).length === 0) return\n if (!record || typeof record !== 'object') return\n\n const obj = record as Record<string, unknown>\n for (const [field, desc] of Object.entries(staticFields)) {\n if (desc.validateCodes === false) continue\n const known = new Set<string>(desc.keys)\n const values = getAtPath(obj, field)\n for (const value of values) {\n if (value === undefined || value === null) continue\n const codes = Array.isArray(value) ? value : [value]\n for (const code of codes) {\n if (typeof code !== 'string') continue\n if (!known.has(code)) {\n throw new UnknownDictCodeError(desc.name, field, code)\n }\n }\n }\n }\n }\n\n /**\n * Apply locale resolution to a record for the given collection.\n *\n * Called by Collection after decryption when locale options are present.\n * Returns a new object (never mutates the cached record).\n */\n async applyLocale(\n collectionName: string,\n record: Record<string, unknown>,\n localeOpts: LocaleReadOptions,\n ): Promise<Record<string, unknown>> {\n const locale = localeOpts.locale ?? this.locale\n const staticFields = this.staticDescriptorByField.get(collectionName)\n // A static dict with `displayLocale` resolves even under a locale-less\n // read (#291). The early-return relaxes only for that case; an i18nText-\n // only / plain-dictKey collection still returns the raw record when no\n // locale is active (today's invariant).\n const hasStaticDisplay =\n staticFields !== undefined &&\n Object.values(staticFields).some((d) => d.displayLocale !== undefined)\n if (!locale && !hasStaticDisplay) return record\n\n let result = record\n\n // 1. i18nText resolution — requires an active locale.\n if (locale) {\n const i18nFields = this.i18nFieldRegistry.get(collectionName)\n if (i18nFields && Object.keys(i18nFields).length > 0) {\n result = this.i18nStrategy.applyI18nLocale(result, i18nFields, locale, localeOpts.fallback)\n }\n }\n\n // 2. dictKey label resolution — add <field>Label virtual fields (encrypted\n // _dict_* handle). Skipped on `raw`. Static fields are NOT in this\n // registry (they skip rename tracking), so this never calls\n // this.dictionary(staticName).\n const dictFields = this.dictKeyFieldRegistry.get(collectionName)\n if (locale && dictFields && Object.keys(dictFields).length > 0 && locale !== 'raw') {\n const withLabels = { ...result }\n for (const [field, dictName] of Object.entries(dictFields)) {\n const key = result[field]\n if (typeof key !== 'string') continue\n const handle = this.dictionary(dictName)\n const label = await handle.resolveLabel(key, locale, localeOpts.fallback)\n if (label !== undefined) {\n withLabels[`${field}Label`] = label\n }\n }\n result = withLabels\n }\n\n // 3. staticDict label resolution — resolve from the in-memory table; uses\n // the field's displayLocale when no locale is active (#291). No\n // dictionary() lookup, so no StaticDictReadonlyError from this path.\n if (staticFields && Object.keys(staticFields).length > 0 && locale !== 'raw') {\n const withLabels = { ...result }\n for (const [field, desc] of Object.entries(staticFields)) {\n const effLocale = locale ?? desc.displayLocale\n if (!effLocale) continue\n const key = result[field]\n if (typeof key !== 'string') continue\n const labels = desc.table[key]\n if (!labels) continue\n const label = resolveLabelFromMap(labels, effLocale, localeOpts.fallback ?? desc.substitute)\n if (label !== undefined) {\n withLabels[`${field}Label`] = label\n }\n }\n result = withLabels\n }\n\n return result\n }\n\n /**\n * Open a dictionary by name. Returns a `DictionaryHandle` for CRUD\n * operations on the `_dict_<name>/` reserved collection.\n *\n * The handle is cached — multiple calls with the same name return the\n * same instance.\n *\n * @param name The dictionary name (e.g. `'status'` → `_dict_status/`).\n * @param options Optional ACL overrides (default `writableBy: 'admin'`).\n *\n * @example\n * ```ts\n * await company.dictionary('status').putAll({\n * draft: { en: 'Draft', th: 'ฉบับร่าง' },\n * paid: { en: 'Paid', th: 'ชำระแล้ว' },\n * })\n * ```\n */\n dictionary<Keys extends string = string>(\n name: string,\n options: DictionaryOptions = {},\n ): DictionaryHandle<Keys> {\n // A staticDict (#291) has no _dict_* collection and no mutation surface —\n // its labels are code constants. Refuse the handle so put/putAll/rename/\n // delete can never be attempted against a static name.\n if (this.staticDictNames.has(name)) {\n throw new StaticDictReadonlyError(name)\n }\n let handle = this.dictionaryCache.get(name)\n if (!handle) {\n handle = this.i18nStrategy.buildDictionaryHandle<Keys>({\n adapter: this.adapter,\n compartmentName: this.name,\n dictionaryName: name,\n keyring: this.keyring,\n getDEK: this.getDEK,\n encrypted: this.encrypted,\n ledger: this.getLedgerOrNull() ?? undefined,\n options,\n // findAndUpdateReferences: rewrite dictKey fields in all\n // registered collections when rename() is called\n findAndUpdateReferences: async (dictionaryName, oldKey, newKey) => {\n for (const [collectionName, dictFields] of this.dictKeyFieldRegistry) {\n // Find fields that point at this dictionary\n const fields = Object.entries(dictFields)\n .filter(([, dn]) => dn === dictionaryName)\n .map(([field]) => field)\n if (fields.length === 0) continue\n\n const coll = this.collection<Record<string, unknown>>(collectionName)\n const records = await coll.list()\n for (const record of records) {\n let changed = false\n const updated = { ...record }\n for (const field of fields) {\n if (updated[field] === oldKey) {\n updated[field] = newKey\n changed = true\n }\n }\n if (changed) {\n const id = (record['id'] as string | undefined)\n if (id !== undefined) {\n await coll.put(id, updated)\n }\n }\n }\n }\n },\n emitter: this.emitter,\n })\n this.dictionaryCache.set(name, handle)\n }\n return handle as DictionaryHandle<Keys>\n }\n\n /**\n * Build a `JoinableSource` for a dictKey field, for use in dict joins\n *. Returns a source whose snapshot contains `{ key, ...labels }`\n * records — one per dictionary entry — keyed by the stable key.\n *\n * Returns `null` when `field` is not a dictKey in `leftCollection`.\n *\n * The snapshot is built synchronously from whatever the dictionary\n * handle has in its cached state. For empty dictionaries this returns\n * an empty snapshot rather than `null`.\n */\n /**\n * Build a `JoinableSource` for a dictKey field, for use in dict joins\n *. Returns a source whose snapshot contains\n * `{ key, labels, ...labels }` records — one per dictionary entry —\n * keyed by the stable key.\n *\n * The snapshot is built synchronously from the DictionaryHandle's\n * write-through cache, which is populated on every `put()`, `rename()`,\n * `delete()`, and `list()` call. For pre-existing data not yet touched\n * this session, call `await vault.dictionary(name).list()` first\n * to warm the cache.\n *\n * Returns `null` when `field` is not a dictKey in `leftCollection`.\n */\n resolveDictSource(leftCollection: string, field: string): JoinableSource | null {\n // staticDict (#291): a code-table-backed source — snapshot() materialises\n // the in-memory table into [{ key, labels, ...labels }] rows, mirroring\n // DictionaryHandle.snapshotEntries(). Carries `displayLocale` so a\n // locale-less { by: 'label' } query has a default locale to resolve at.\n const staticFields = this.staticDescriptorByField.get(leftCollection)\n if (staticFields && field in staticFields) {\n const desc = staticFields[field]!\n const rows: readonly Record<string, unknown>[] = Object.entries(desc.table).map(\n ([key, labels]) => ({ key, labels, ...(labels as Record<string, string>) }),\n )\n const source: JoinableSource = {\n snapshot(): readonly unknown[] {\n return rows\n },\n lookupById(id: string): unknown {\n return rows.find((e) => e['key'] === id)\n },\n }\n if (desc.displayLocale !== undefined) {\n ;(source as { displayLocale?: string }).displayLocale = desc.displayLocale\n }\n return source\n }\n\n const dictFields = this.dictKeyFieldRegistry.get(leftCollection)\n if (!dictFields || !(field in dictFields)) return null\n const dictName = dictFields[field]\n if (!dictName) return null\n const handle = this.dictionary(dictName)\n return {\n snapshot(): readonly unknown[] {\n return handle.snapshotEntries()\n },\n lookupById(id: string): unknown {\n const entries = handle.snapshotEntries()\n return entries.find((e) => e['key'] === id)\n },\n }\n }\n\n /**\n * Set or update the vault-default locale at runtime.\n * Useful when the user switches their preferred language after opening\n * the vault.\n */\n setLocale(locale: string | undefined): void {\n this.locale = locale\n }\n\n /** Return the current vault-default locale. */\n getLocale(): string | undefined {\n return this.locale\n }\n\n /**\n * The user id of the keyring backing this vault session. Useful for\n * UI affordances (\"you are alice\"), audit trails, and orchestration\n * composables that need to stamp records with the current actor.\n */\n get userId(): string {\n return this.keyring.userId\n }\n\n /**\n * The role of the keyring backing this vault session — one of\n * `owner | admin | operator | viewer | client`. Useful for UI\n * affordance gates and approval workflows that need to confirm\n * the caller can perform a given action before attempting it.\n */\n get role(): Role {\n return this.keyring.role\n }\n\n /**\n * Build keyring files for bundle recipients without persisting them\n * to the source vault. Used by `writeNoydbBundle()` when the bundle\n * is re-keyed for distinct recipients.\n *\n * Each recipient becomes its own `KeyringFile` sealed with that\n * recipient's passphrase. The DEKs wrapped into each slot are\n * exactly those the recipient's role + permissions justify, and\n * never wider than the source keyring's own DEK set\n * (privilege-escalation check).\n *\n * Returns a `Record<userId, KeyringFile>` ready to substitute for\n * the `keyrings` field of a `vault.dump()` JSON. Adapter is never\n * touched; the produced files exist only in the bundle bytes.\n *\n * @public\n */\n async buildBundleRecipientKeyrings(\n recipients: readonly BundleRecipient[],\n ): Promise<Record<string, KeyringFile>> {\n const result: Record<string, KeyringFile> = {}\n for (const recipient of recipients) {\n if (recipient.id in result) {\n throw new Error(`buildBundleRecipientKeyrings: duplicate recipient id \"${recipient.id}\"`)\n }\n result[recipient.id] = await buildRecipientKeyringFile(this.keyring, recipient)\n }\n return result\n }\n\n /**\n * Authorize an `@noy-db/as-*` export against the current keyring's\n * `exportCapability`. Throws `ExportCapabilityError` if\n * the invoking keyring is not authorised.\n *\n * `as-*` packages MUST call this before invoking the underlying\n * export primitive (`exportStream()` / `writeNoydbBundle()` / …).\n *\n * - `assertCanExport('plaintext', 'xlsx')` — check plaintext tier\n * for a specific format. Defaults to empty for every role; owner\n * must positively grant.\n * - `assertCanExport('bundle')` — check encrypted-bundle tier.\n * Defaults to on for owner/admin, off for others.\n *\n * See `docs/patterns/as-exports.md` for the full policy.\n */\n assertCanExport(tier: 'plaintext', format: ExportFormat): void\n assertCanExport(tier: 'bundle'): void\n assertCanExport(tier: 'plaintext' | 'bundle', format?: ExportFormat): void {\n if (tier === 'plaintext') {\n if (format === undefined) {\n throw new Error('vault.assertCanExport: plaintext tier requires a format')\n }\n if (!hasExportCapability(this.keyring, 'plaintext', format)) {\n throw new ExportCapabilityError({\n tier: 'plaintext',\n userId: this.keyring.userId,\n format,\n })\n }\n return\n }\n if (!hasExportCapability(this.keyring, 'bundle')) {\n throw new ExportCapabilityError({\n tier: 'bundle',\n userId: this.keyring.userId,\n })\n }\n }\n\n /**\n * Authorize an `@noy-db/as-*` import against the current keyring's\n * `importCapability` (issue ). Throws `ImportCapabilityError` if\n * the invoking keyring is not authorised.\n *\n * `as-*` reader entry-points (`fromString` / `fromBytes`) MUST call\n * this before parsing or building an `ImportPlan`.\n *\n * - `assertCanImport('plaintext', 'csv')` — check plaintext-tier\n * import for a specific format. Default-closed for every role.\n * - `assertCanImport('bundle')` — check `.noydb` bundle-import gate.\n * Default-closed for every role, including owner — import is more\n * dangerous than export (corrupts vs leaks).\n *\n * Owner who wants to import re-grants own keyring with\n * `importCapability` set explicitly.\n */\n assertCanImport(tier: 'plaintext', format: ExportFormat): void\n assertCanImport(tier: 'bundle'): void\n assertCanImport(tier: 'plaintext' | 'bundle', format?: ExportFormat): void {\n if (tier === 'plaintext') {\n if (format === undefined) {\n throw new Error('vault.assertCanImport: plaintext tier requires a format')\n }\n if (!hasImportCapability(this.keyring, 'plaintext', format)) {\n throw new ImportCapabilityError({\n tier: 'plaintext',\n userId: this.keyring.userId,\n format,\n })\n }\n return\n }\n if (!hasImportCapability(this.keyring, 'bundle')) {\n throw new ImportCapabilityError({\n tier: 'bundle',\n userId: this.keyring.userId,\n })\n }\n }\n\n /**\n * Bulk blob extraction primitive.\n *\n * Returns an async-iterable handle over every blob attached to\n * records in the vault. Single capability check (`plaintext/blob`)\n * at handle creation; single audit entry to `_export_audit` before\n * the first yield. Per-blob decryption happens lazily as the\n * consumer pulls tuples.\n *\n * ```ts\n * const handle = vault.exportBlobs({\n * collections: ['invoiceScans'],\n * where: (rec) => (rec as { clientId?: string }).clientId === 'c-123',\n * })\n * for await (const { bytes, meta, recordRef } of handle) {\n * await uploadToColdStorage(bytes, recordRef)\n * }\n * ```\n *\n * @see `@noy-db/hub/store/export-blobs` for the full option surface.\n */\n /**\n * Evict blob slots per the per-collection `blobFields` retention\n * policy.\n *\n * Iterates every collection declared with `{ blobFields: {...} }`.\n * For each record, checks every configured slot against its\n * policy — `retainDays` (age-based TTL) and/or `evictWhen(record)`\n * (predicate) — and evicts matching slots. Every eviction writes\n * one entry to `_blob_eviction_audit` (actor + eTag + reason +\n * timestamp, no plaintext). Consumer-scheduled; noy-db never runs\n * this on its own.\n *\n * ```ts\n * await vault.compact() // run full pass\n * await vault.compact({ dryRun: true }) // preview counts\n * await vault.compact({ maxEvictions: 1000 }) // cap batch\n * ```\n */\n /**\n * Atomic, gap-free numbering. `vault.sequence('invoice-2026').next()`\n * returns 1, 2, 3, … with no gaps or duplicates under concurrency, via\n * an optimistic-CAS counter at `_sequences/<name>`. Each name is an\n * independent sequence.\n *\n * **Online-only:** `next()` throws `SequenceOfflineError` unless the\n * store advertises `capabilities.casAtomic` — gap-free numbering cannot\n * be serialized by an offline / non-CAS writer.\n *\n * ```ts\n * const n = await vault.sequence('invoice-2026').next() // 1, then 2, …\n * const cur = await vault.sequence('invoice-2026').peek() // current value, no allocation\n * ```\n */\n sequence(series: string, opts?: SequenceOptions): SequenceHandle {\n // A null byte is the structural partition separator in\n // resolveSequenceKey; a series name carrying one could forge a\n // partitioned key, so reject it (#345).\n if (series.includes('\\x00')) {\n throw new ValidationError(`sequence(\"${series}\"): series name must not contain a null byte (\\\\x00).`)\n }\n // Deferred-numbering series route to the pass-based engine; `next({ for })`\n // resolves at `runNumberingPass`. They are keyed by series only and have\n // no CAS counter, so seedTo (CAS-only) is unavailable. All other names\n // use the CAS counter.\n if (this.numberingConfigs.has(series)) {\n const eng = this.deferred()\n return {\n next: async (nextOpts) => {\n if (!nextOpts?.for) {\n throw new ValidationError(`sequence(\"${series}\") is a deferred-numbering series; call next({ for: recordId }).`)\n }\n return (await eng.enqueue(series, nextOpts.for)).assigned\n },\n peek: () => eng.peek(series),\n seedTo: () => {\n throw new ValidationError(`sequence(\"${series}\") is a deferred-numbering series; seedTo is CAS-only.`)\n },\n }\n }\n if (!this.sequenceStore) {\n this.sequenceStore = new SequenceStore({\n adapter: this.adapter,\n vault: this.name,\n encrypted: this.encrypted,\n getDEK: this.getDEK,\n actor: this.keyring.userId,\n })\n }\n return this.sequenceStore.handle(resolveSequenceKey(series, opts))\n }\n\n /** @internal — lazily build the deferred-numbering engine with a cache-coherent stamp. */\n private deferred(): DeferredNumberingStore {\n if (!this.deferredNumbering) {\n this.deferredNumbering = new DeferredNumberingStore({\n adapter: this.adapter,\n vault: this.name,\n encrypted: this.encrypted,\n getDEK: this.getDEK,\n actor: this.keyring.userId,\n configs: this.numberingConfigs,\n // Stamp THROUGH the Collection layer so cache/indexes/MVs stay coherent —\n // `this.collection(name)` returns the shared cached instance, so a\n // subsequent user `collection.get(id)` sees the assigned serial.\n stamp: async (collection, recordId, field, serial) => {\n const coll = this.collection<Record<string, unknown>>(collection)\n const rec = await coll.get(recordId)\n if (!rec) return false\n await coll.put(recordId, { ...rec, [field]: serial })\n return true\n },\n })\n }\n return this.deferredNumbering\n }\n\n /**\n * Run a deferred-numbering pass for `series`: assign gap-free serials to all\n * records whose store-commit-time interval has settled, in store-time order.\n * Returns the assignments made. See {@link sequence} / `withDeferredNumbering`.\n */\n async runNumberingPass(series: string): Promise<Assignment[]> {\n return this.deferred().runPass(series)\n }\n\n async compact(options: CompactRunOptions = {}): Promise<CompactionResult> {\n return runCompaction({\n adapter: this.adapter,\n vault: this.name,\n actor: this.keyring.userId,\n encrypted: this.encrypted,\n getDEK: this.getDEK,\n getBlobFields: <T>(name: string): BlobFieldsConfig<T> | null =>\n (this.blobFieldsRegistry.get(name) as BlobFieldsConfig<T> | undefined) ?? null,\n listCollections: () => this.collections(),\n listRecords: (name: string) => this.adapter.list(this.name, name),\n getRecord: async <T>(name: string, id: string) => {\n const coll = this.collection<T>(name)\n return coll.get(id)\n },\n listSlots: async (name: string, id: string) => {\n const coll = this.collection(name)\n return coll.blob(id).list()\n },\n deleteSlot: async (name: string, id: string, slotName: string) => {\n const coll = this.collection(name)\n await coll.blob(id).delete(slotName)\n },\n }, options)\n }\n\n /**\n * Sweep records eligible by their collection's `archive` policy into the\n * cold archive store. Relocation is envelope-level (no re-encryption) and\n * bypasses guards + materialized-view dispatch, so issued/immutable\n * records over a sealed period can be archived without recomputing\n * finalized aggregates. A `legalHold` predicate blocks archival.\n * Requires `archiveStrategy: withArchive({ store })` in `createNoydb`.\n */\n async archive(options: ArchiveRunOptions = {}): Promise<ArchiveResult> {\n return runArchive(this._archiveContext(), options)\n }\n\n /** Relocate one archived record back to the primary store. Returns false if it was not archived. */\n async restore(collection: string, id: string): Promise<boolean> {\n return runRestore(this._archiveContext(), collection, id)\n }\n\n /** List archived record ids for a collection (or all collections with an archive policy). */\n async listArchived(collection?: string): Promise<Array<{ collection: string; id: string }>> {\n return runListArchived(this._archiveContext(), collection)\n }\n\n private _archiveContext(): ArchiveContext {\n const strategy = this.archiveStrategy\n if (!strategy) {\n throw new Error(\n 'vault.archive/restore/listArchived require `archiveStrategy: withArchive({ store })` in createNoydb',\n )\n }\n const archiveStore = strategy.store\n return {\n vaultId: this.name,\n archiveStore,\n collectionsWithPolicy: () => [...this.archiveRegistry.keys()],\n getPolicy: (c) => this.archiveRegistry.get(c) ?? null,\n listRecordIds: (c) => this.adapter.list(this.name, c),\n getRecord: async (c, id) =>\n (await this.collection(c).get(id, { locale: 'raw' })) as Record<string, unknown> | null,\n getEnvelope: (c, id) => this.adapter.get(this.name, c, id),\n removeFromPrimary: (c, id) => this.collection(c)._internalDelete(id),\n restoreToPrimary: async (c, id, env) => {\n await this.adapter.put(this.name, c, id, env)\n await this.collection(c)._invalidateCacheEntry(id)\n },\n }\n }\n\n exportBlobs(options: ExportBlobsOptions = {}): ExportBlobsHandle {\n this.assertCanExport('plaintext', 'blob')\n return createExportBlobsHandle(\n this.keyring.userId,\n () => this.collections(),\n (name) => this.collection(name),\n (entry) => this.writeExportAudit(entry),\n options,\n )\n }\n\n async issueAttestation(collectionName: string, id: string): Promise<{ docId: string; qr: string; keyId: string; publicKeyB64: string }> {\n const fieldSchema = this.attestationRegistry.get(collectionName)\n if (!fieldSchema) {\n throw new AttestationError(`issueAttestation: collection '${collectionName}' has no attestation field-schema. Declare it via vault.collection('${collectionName}', { attestation: { fields: [...] } }).`)\n }\n const { issueAttestationCore } = await import('./attestation/issue.js')\n const out = await issueAttestationCore(this.makeIssueContext(), { collection: collectionName, id, fieldSchema })\n return { docId: out.docId, qr: out.qr, keyId: out.keyId, publicKeyB64: out.publicKeyB64 }\n }\n\n async getDocumentSigningPublicKey(): Promise<{ keyId: string; publicKeyB64: string }> {\n const { loadSigner, loadOrCreateSigner } = await import('./attestation/signer.js')\n // Reading an existing public key is open to any role that holds the\n // _attestations DEK — the public key is not secret. But MINTING the\n // signer is the firm's identity operation (same rule as issueAttestation):\n // a non-owner read must not silently create it.\n const existing = await loadSigner(this.adapter, this.name, this.getDEK)\n if (existing) return { keyId: existing.keyId, publicKeyB64: existing.publicKeyB64 }\n if (this.keyring.role !== 'owner') {\n throw new AttestationError(`getDocumentSigningPublicKey: no document-signing key exists yet; only the 'owner' may mint it. Caller is '${this.keyring.role}'. Have the owner issue an attestation (or call this) first.`)\n }\n const signer = await loadOrCreateSigner(this.adapter, this.name, this.getDEK)\n return { keyId: signer.keyId, publicKeyB64: signer.publicKeyB64 }\n }\n\n private makeIssueContext(): IssueContext {\n const adapter = this.adapter, vaultName = this.name, getDEK = this.getDEK\n return {\n store: adapter,\n vault: vaultName,\n role: this.keyring.role,\n getDEK: async () => getDEK('_attestations'),\n readRecord: async (collection: string, recId: string) => {\n const env = await adapter.get(vaultName, collection, recId)\n if (!env) return null\n const record = (await this.collection(collection).get(recId, { locale: 'raw' })) as Record<string, unknown> | null\n if (record === null) return null\n return { record, version: env._v }\n },\n }\n }\n\n async revokeAttestation(docId: string): Promise<void> {\n const { revokeDocCore } = await import('./attestation/revoke.js')\n await revokeDocCore(this.makeRevokeContext(), docId)\n }\n\n async unrevokeAttestation(docId: string): Promise<void> {\n const { unrevokeDocCore } = await import('./attestation/revoke.js')\n await unrevokeDocCore(this.makeRevokeContext(), docId)\n }\n\n async getRevokedDocIds(): Promise<string[]> {\n const { getRevokedDocIdsCore } = await import('./attestation/revoke.js')\n return getRevokedDocIdsCore(this.makeRevokeContext())\n }\n\n async publishRevocationList(): Promise<RevocationList> {\n const { publishRevocationListCore } = await import('./attestation/revoke.js')\n return publishRevocationListCore(this.makeRevokeContext())\n }\n\n private makeRevokeContext(): RevokeContext {\n const adapter = this.adapter, vaultName = this.name, getDEK = this.getDEK\n return {\n store: adapter,\n vault: vaultName,\n role: this.keyring.role,\n getDEK: async () => getDEK('_attestations'),\n }\n }\n\n private async writeExportAudit(entry: ExportBlobsAuditEntry): Promise<void> {\n const json = JSON.stringify(entry)\n const envelope: EncryptedEnvelope = this.encrypted\n ? await (async () => {\n const dek = await this.getDEK(EXPORT_AUDIT_COLLECTION)\n const { iv, data } = await encrypt(json, dek)\n return { _noydb: NOYDB_FORMAT_VERSION, _v: 1, _ts: entry.startedAt, _iv: iv, _data: data, _by: entry.actor }\n })()\n : { _noydb: NOYDB_FORMAT_VERSION, _v: 1, _ts: entry.startedAt, _iv: '', _data: json, _by: entry.actor }\n await this.adapter.put(this.name, EXPORT_AUDIT_COLLECTION, entry.id, envelope)\n }\n\n /**\n * Read-only accessor for the invoking keyring's export capability,\n * with role-based defaults resolved. Useful for UI affordances\n * (grey out the export button if no capability) without throwing.\n */\n canExport(tier: 'plaintext', format: ExportFormat): boolean\n canExport(tier: 'bundle'): boolean\n canExport(tier: 'plaintext' | 'bundle', format?: ExportFormat): boolean {\n if (tier === 'plaintext') {\n if (format === undefined) return false\n return hasExportCapability(this.keyring, 'plaintext', format)\n }\n return hasExportCapability(this.keyring, 'bundle')\n }\n\n /**\n * Decrypt a single envelope using the per-collection DEK, returning\n * the parsed plaintext record. Internal helper for bundle-pipeline\n * plaintext filters — keeps DEK access encapsulated\n * inside Vault so callers don't reach into private state.\n *\n * @internal\n */\n async _decryptEnvelopeForBundleFilter(\n env: EncryptedEnvelope,\n collectionName: string,\n ): Promise<unknown> {\n if (!this.encrypted) {\n return JSON.parse(env._data)\n }\n const dek = await this.getDEK(collectionName)\n const json = await decrypt(env._iv, env._data, dek)\n return JSON.parse(json)\n }\n\n /**\n * Read-only accessor for the invoking keyring's import capability\n * (issue ). UI affordance — returns false in every default-closed\n * case (every role with no explicit `importCapability` grant).\n */\n canImport(tier: 'plaintext', format: ExportFormat): boolean\n canImport(tier: 'bundle'): boolean\n canImport(tier: 'plaintext' | 'bundle', format?: ExportFormat): boolean {\n if (tier === 'plaintext') {\n if (format === undefined) return false\n return hasImportCapability(this.keyring, 'plaintext', format)\n }\n return hasImportCapability(this.keyring, 'bundle')\n }\n\n /**\n * Enforce strict outbound refs on a `put()`. Called by Collection\n * just before it writes to the adapter. For every strict ref\n * declared on the collection, check that the target id exists in\n * the target collection; throw `RefIntegrityError` if not.\n *\n * `warn` and `cascade` modes don't affect put semantics — they're\n * enforced at delete time or via `checkIntegrity()`.\n */\n async enforceRefsOnPut(collectionName: string, record: unknown): Promise<void> {\n const outbound = this.refRegistry.getOutbound(collectionName)\n if (Object.keys(outbound).length === 0) return\n if (!record || typeof record !== 'object') return\n const obj = record as Record<string, unknown>\n\n for (const [field, descriptor] of Object.entries(outbound)) {\n if (descriptor.mode !== 'strict') continue\n const rawId = obj[field]\n // Nullish ref values are allowed — treat them as \"no reference\".\n // Users who want \"always required\" should express it in their\n // Standard Schema validator via a non-optional field.\n if (rawId === null || rawId === undefined) continue\n // Refs must be strings or numbers — anything else (object,\n // array, boolean) is a programming error and should fail\n // loudly rather than serialize as \"[object Object]\".\n if (typeof rawId !== 'string' && typeof rawId !== 'number') {\n throw new RefIntegrityError({\n collection: collectionName,\n id: (obj['id'] as string | undefined) ?? '<unknown>',\n field,\n refTo: descriptor.target,\n refId: null,\n message:\n `Ref field \"${collectionName}.${field}\" must be a string or number, got ${typeof rawId}.`,\n })\n }\n const refId = String(rawId)\n const target = this.collection<Record<string, unknown>>(descriptor.target)\n const exists = await target.get(refId)\n if (!exists) {\n throw new RefIntegrityError({\n collection: collectionName,\n id: (obj['id'] as string | undefined) ?? '<unknown>',\n field,\n refTo: descriptor.target,\n refId,\n message:\n `Strict ref \"${collectionName}.${field}\" → \"${descriptor.target}\" ` +\n `cannot be satisfied: target id \"${refId}\" not found in \"${descriptor.target}\".`,\n })\n }\n }\n }\n\n /**\n * Enforce inbound ref modes on a `delete()`. Called by Collection\n * just before it deletes from the adapter. Walks every inbound\n * ref that targets this (collection, id) and:\n *\n * - `strict`: throws if any referencing records exist\n * - `cascade`: deletes every referencing record\n * - `warn`: no-op (checkIntegrity picks it up)\n *\n * Cascade cycles are broken via `cascadeInProgress` — re-entering\n * for the same (collection, id) returns immediately so two\n * mutually-cascading collections don't recurse forever.\n */\n async enforceRefsOnDelete(collectionName: string, id: string): Promise<void> {\n const key = `${collectionName}/${id}`\n if (this.cascadeInProgress.has(key)) return\n this.cascadeInProgress.add(key)\n\n try {\n const inbound = this.refRegistry.getInbound(collectionName)\n for (const rule of inbound) {\n const fromCollection = this.collection<Record<string, unknown>>(rule.collection)\n // Scan the referencing collection for records whose ref\n // field matches this id. For eager-mode collections this\n // is an in-memory filter; for lazy-mode it requires a scan.\n const allRecords = await fromCollection.list()\n const matches = allRecords.filter((rec) => {\n const raw = rec[rule.field]\n // Same string/number-only restriction as enforceRefsOnPut.\n // Anything else can't have been a valid ref to begin with,\n // so it can't match.\n if (typeof raw !== 'string' && typeof raw !== 'number') return false\n return String(raw) === id\n })\n if (matches.length === 0) continue\n\n if (rule.mode === 'strict') {\n const first = matches[0]\n throw new RefIntegrityError({\n collection: rule.collection,\n id: (first?.['id'] as string | undefined) ?? '<unknown>',\n field: rule.field,\n refTo: collectionName,\n refId: id,\n message:\n `Cannot delete \"${collectionName}\"/\"${id}\": ` +\n `${matches.length} record(s) in \"${rule.collection}\" still reference it via strict ref \"${rule.field}\".`,\n })\n }\n if (rule.mode === 'cascade') {\n // Atomicity (#346): if a transaction is active, register each\n // child's prior envelope on it BEFORE the delete so a later\n // mid-batch failure rolls the cascade back alongside the\n // parent. Mirrors how derivation outputs self-register on the\n // active ctx. Outside a tx the context is null and we skip it.\n const txCtx = this.noydb._activeTxContextOrNull\n for (const match of matches) {\n const matchId = (match['id'] as string | undefined) ?? null\n if (matchId === null) continue\n if (txCtx !== null) {\n const prior = await this.adapter.get(this.name, rule.collection, matchId)\n if (prior !== null) {\n txCtx._executed.push({\n op: {\n type: 'delete',\n vaultName: this.name,\n collectionName: rule.collection,\n id: matchId,\n },\n priorEnvelope: prior,\n })\n }\n }\n // Recursive delete — the cycle breaker above catches\n // infinite loops.\n await fromCollection.delete(matchId)\n }\n }\n // warn: no-op\n }\n } finally {\n this.cascadeInProgress.delete(key)\n }\n }\n\n // ─── Join resolver) ────────────────────\n\n /**\n * Look up the `RefDescriptor` the left collection declared for a\n * given field name. Returns `null` when the field has no ref\n * declaration — the Query builder turns that into an actionable\n * error at plan time (before any records are touched).\n *\n * Implements the `joinResolver.resolveRef` half of the structural\n * interface that `Collection.query()` consumes. See\n * `query/join.ts` for the full design.\n */\n resolveRef(leftCollection: string, field: string): RefDescriptor | null {\n const outbound = this.refRegistry.getOutbound(leftCollection)\n return outbound[field] ?? null\n }\n\n /**\n * Resolve a right-side join source by target collection name.\n * Returns `null` for unknown collections so the Query executor can\n * surface an actionable error naming the missing target.\n *\n * Implements the `joinResolver.resolveSource` half of the\n * structural interface. The returned JoinableSource is a thin\n * wrapper that reads the target collection's in-memory cache via\n * `list()` / `get()` synchronously — the cache is populated by an\n * earlier `ensureHydrated()` call through the target's query/list\n * path. If the target has not been opened yet in this session the\n * join will see an empty snapshot; consumers who hit this can\n * open the target collection explicitly before running the query.\n *\n * Only same-vault targets are resolvable — cross-vault\n * joins are explicitly forbidden by the architecture`).\n */\n resolveSource(collectionName: string): JoinableSource | null {\n // Reject internal / reserved collection names — joins against\n // `_ledger/`, `_keyring/`, `_deltas/`, etc. are never legitimate.\n if (collectionName.startsWith('_')) return null\n const coll = this.collectionCache.get(collectionName)\n if (!coll) return null\n // Collection exposes a structural `querySourceForJoin()` method\n // that returns a lightweight snapshot/lookupById view backed by\n // its in-memory cache. Typed as unknown here because\n // Collection<T> is covariant on T — the join executor only\n // reads fields by name and doesn't care about the concrete type.\n return (coll as unknown as {\n querySourceForJoin(): JoinableSource\n }).querySourceForJoin()\n }\n\n /**\n * Walk every collection that has declared refs, load its records,\n * and report any reference whose target id is missing. Modes are\n * reported alongside each violation so the caller can distinguish\n * \"this is a warning the user asked for\" from \"this should never\n * have happened\" (strict violations produced by out-of-band\n * writes).\n *\n * Returns `{ violations: [...] }` instead of throwing — the whole\n * point of `checkIntegrity()` is to surface a list for display\n * or repair, not to fail noisily.\n */\n async checkIntegrity(): Promise<{ violations: RefViolation[] }> {\n const violations: RefViolation[] = []\n for (const [collectionName, refs] of this.refRegistry.entries()) {\n const coll = this.collection<Record<string, unknown>>(collectionName)\n const records = await coll.list()\n for (const record of records) {\n const recId = (record['id'] as string | undefined) ?? '<unknown>'\n for (const [field, descriptor] of Object.entries(refs)) {\n const rawId = record[field]\n if (rawId === null || rawId === undefined) continue\n // Non-scalar ref values are flagged as a violation rather\n // than thrown — `checkIntegrity` is a \"report what's wrong\"\n // tool, not a \"block on first failure\" tool. The thrown\n // version lives in `enforceRefsOnPut`.\n if (typeof rawId !== 'string' && typeof rawId !== 'number') {\n violations.push({\n collection: collectionName,\n id: recId,\n field,\n refTo: descriptor.target,\n refId: rawId,\n mode: descriptor.mode,\n })\n continue\n }\n const refId = String(rawId)\n const target = this.collection<Record<string, unknown>>(descriptor.target)\n const exists = await target.get(refId)\n if (!exists) {\n violations.push({\n collection: collectionName,\n id: recId,\n field,\n refTo: descriptor.target,\n refId: rawId,\n mode: descriptor.mode,\n })\n }\n }\n }\n }\n return { violations }\n }\n\n /**\n * Return this compartment's hash-chained audit log.\n *\n * The ledger is lazy-initialized on first access and cached for the\n * lifetime of the Vault instance. Every LedgerStore instance\n * shares the same adapter and DEK resolver, so `vault.ledger()`\n * can be called repeatedly without performance cost.\n *\n * The LedgerStore itself is the public API: consumers call\n * `.append()` (via Collection internals), `.head()`, `.verify()`,\n * and `.entries({ from, to })`. See the LedgerStore docstring for\n * the full surface and the concurrency caveats.\n */\n ledger(): LedgerStore {\n const store = this.getLedgerOrNull()\n if (!store) {\n throw new Error(\n 'vault.ledger() requires the history strategy. Import ' +\n '`{ withHistory }` from \"@noy-db/hub/history\" and pass it to ' +\n '`createNoydb({ historyStrategy: withHistory() })`.',\n )\n }\n return store\n }\n\n /**\n * Internal accessor — returns the LedgerStore if the history\n * strategy is opted in, or `null` otherwise. Used by dump/restore/\n * verifyBackupIntegrity and by Collection write paths that already\n * gate on `if (this.ledger)`. The public `ledger()` accessor above\n * throws on null; this one stays silent so the off-path no-ops.\n */\n private getLedgerOrNull(): LedgerStore | null {\n if (!this.ledgerStore) {\n this.ledgerStore = this.historyStrategy.buildLedger({\n adapter: this.adapter,\n vault: this.name,\n encrypted: this.encrypted,\n getDEK: this.getDEK,\n actor: this.keyring.userId,\n })\n }\n return this.ledgerStore\n }\n\n // ─── GDPR right-to-erasure (#304) ────────────────────────────────\n\n /** @internal — add a subject→record ref to the encrypted subject index. */\n async _addSubjectRef(subjectId: string, ref: SubjectRef): Promise<void> {\n await addSubjectRef(this.adapter, this.name, this.getDEK, this.encrypted, subjectId, ref)\n }\n\n /** @internal — drop a subject→record ref from the encrypted subject index. */\n async _removeSubjectRef(subjectId: string, ref: SubjectRef): Promise<void> {\n await removeSubjectRef(this.adapter, this.name, this.getDEK, this.encrypted, subjectId, ref)\n }\n\n /**\n * Rebuild the encrypted subject index from canonical records. The recovery\n * path for the documented read-modify-write race (RISK #3). Returns the\n * number of distinct subjects re-indexed.\n */\n async rebuildSubjectIndex(): Promise<number> {\n if (Object.keys(this.forgetStrategy.subjects).length === 0) {\n throw new ForgetStrategyNotConfiguredError()\n }\n return rebuildSubjectIndexImpl(\n this.adapter,\n this.name,\n this.getDEK,\n this.encrypted,\n this.forgetStrategy.subjects,\n async (collectionName, id, env) => {\n const coll = this.collection<Record<string, unknown>>(collectionName)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (coll as any)._decodeEnvelope(env, id) as Promise<Record<string, unknown> | null>\n },\n )\n }\n\n /**\n * GDPR crypto-shred of a data subject (#304). Consults the encrypted subject\n * index and, per matching record:\n * - rewrites the LIVE envelope to a tombstone (drops `_iv`/`_data`/`_cek`/`_det`),\n * - tombstones every `_history` version of the record,\n * so the body and all prior versions become permanently undecryptable while\n * the collection DEK and every OTHER record stay intact. Then appends ONE\n * `op:'forget'` ledger entry whose `payloadHash` is `sha256Hex(subjectId)` —\n * the chain still `verify()`s, PROVING the subject existed and was erased\n * without retaining any plaintext.\n *\n * Reports — but does not silently swallow — two completeness gaps:\n * - `unmigratedRecords`: a record whose body was NOT yet migrated to a\n * per-record CEK (legacy body still under the shared collection DEK). It\n * is still tombstoned, but its pre-shred ciphertext (if leaked to a\n * backup before migration) stays decryptable. Migrate, then re-forget.\n * - `blobResidueCollections`: a shredded record still has blob attachments,\n * which are keyed off a separate `_blob` DEK and are out of scope here.\n *\n * @throws ForgetStrategyNotConfiguredError when no `withForgetCascade` was set.\n */\n async forget(subjectId: string): Promise<ForgetResult> {\n if (Object.keys(this.forgetStrategy.subjects).length === 0) {\n throw new ForgetStrategyNotConfiguredError()\n }\n\n const refs = await lookupSubject(this.adapter, this.name, this.getDEK, this.encrypted, subjectId)\n\n let recordsShredded = 0\n let historyVersionsShredded = 0\n const collections = new Set<string>()\n const unmigratedRecords: string[] = []\n const blobResidueCollections = new Set<string>()\n let blobsShredded = 0\n let blobsRetainedShared = 0\n const blobsEnabled = this.blobStrategy !== undefined\n const actor = this.keyring.userId\n\n for (const ref of refs) {\n const coll = this.collection<Record<string, unknown>>(ref.collection)\n const perRecordKeys = this.forgetStrategy.subjects[ref.collection] !== undefined\n\n // Detect an un-migrated record BEFORE shredding: a perRecordKeys\n // collection whose live envelope still carries a body but no `_cek`\n // means the body is keyed off the shared collection DEK (legacy /\n // not-yet-migrated), so a shred cannot guarantee erasure of pre-shred\n // ciphertext. We still tombstone it, but report the gap.\n const live = await this.adapter.get(this.name, ref.collection, ref.id)\n if (perRecordKeys && live && live._data && live._cek === undefined) {\n unmigratedRecords.push(`${ref.collection}:${ref.id}`)\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const shred = await (coll as any)._writeTombstone(ref.id, actor) as { previousVersion: number } | null\n if (shred !== null) {\n recordsShredded++\n collections.add(ref.collection)\n }\n\n // Tombstone every history version (idempotent — already-shredded skip).\n historyVersionsShredded += await this.historyStrategy.tombstoneHistory(\n this.adapter, this.name, ref.collection, ref.id, actor,\n )\n\n // Blob attachments (#365): crypto-shred the record's erasable blobs.\n // An erasable blob's chunks are under a per-blob content CEK whose only\n // copy is the BlobObject's wrapped `_cek`; deleting it at refCount 0\n // shreds the content. Legacy blobs (no `_cek`) or a session without the\n // blob subsystem cannot be shredded → reported as residue.\n if (blobsEnabled) {\n const r = await this.collection<Record<string, unknown>>(ref.collection)\n .blob(ref.id)\n .shredAllForRecord()\n blobsShredded += r.shredded.length\n blobsRetainedShared += r.retainedShared.length\n if (r.residue.length > 0) blobResidueCollections.add(ref.collection)\n } else {\n try {\n const slotIds = await this.adapter.list(this.name, `_blob_slots_${ref.collection}`)\n if (slotIds.includes(ref.id)) blobResidueCollections.add(ref.collection)\n } catch {\n // No blob-slots collection for this collection — nothing to report.\n }\n }\n\n // Drop the (now-shredded) ref from the subject index.\n await this._removeSubjectRef(subjectId, ref)\n }\n\n // ONE summary ledger entry for the whole subject. payloadHash =\n // sha256Hex(subjectId) so the ledger proves erasure without the subject.\n const subjectHash = await sha256Hex(subjectId)\n const ledger = this.getLedgerOrNull()\n if (!ledger) {\n throw new Error(\n 'vault.forget() requires the history strategy for the erasure-proof ' +\n 'ledger entry. Pass `historyStrategy: withHistory()` from ' +\n '\"@noy-db/hub/history\" to createNoydb().',\n )\n }\n const ledgerEntry = await ledger.append({\n op: 'forget',\n collection: '',\n id: '',\n version: 0,\n actor,\n payloadHash: subjectHash,\n reason: JSON.stringify({\n recordsShredded,\n historyVersionsShredded,\n collections: [...collections],\n unmigratedCount: unmigratedRecords.length,\n blobsShredded,\n blobsRetainedShared,\n blobResidueCollections: [...blobResidueCollections],\n }),\n })\n\n return {\n subject: subjectId,\n recordsShredded,\n historyVersionsShredded,\n collections: [...collections],\n unmigratedRecords,\n blobsShredded,\n blobsRetainedShared,\n blobResidueCollections: [...blobResidueCollections],\n ledgerEntry,\n }\n }\n\n // ─── Record-scoped CEK sealing (#306 slices 2-3) ──────────────────────\n\n /**\n * Seal ONE record's content-encryption key (CEK) to an `at-*` host so that\n * host — and only that host — can decrypt exactly that record, with no\n * access to the vault DEK and no ability to read any other record.\n *\n * The grantor (this caller, who holds the collection DEK) reads the record's\n * live `_cek`, unwraps it under the collection DEK, exports the raw CEK\n * bytes, builds a {@link SealedCekBinding} `{collection, id, cek, expiresAt}`,\n * seals that binding for the recipient host via the host's published hint,\n * and persists a thin {@link SealedCekDeliveryEnvelope} at\n * `_sealed_cek/<collection>/<id>/<pid>`. The binding (not the delivery\n * envelope) is the security boundary: the host re-verifies `{collection, id}`\n * and `expiresAt` from inside the sealed payload.\n *\n * Only works on a `perRecordKeys` record — a legacy record has no `_cek` to\n * seal (its body is under the shared collection DEK, which is never exposed\n * by sealing) → {@link RecordCekNotFoundError}.\n *\n * @param collection Collection holding the record.\n * @param id Record id.\n * @param hostSealer The recipient host's {@link RecipientSealer}.\n * @param opts.expiresAt REQUIRED authoritative expiry (ISO 8601), sealed into\n * the binding the host verifies.\n * @returns `{ pid, envelopeKey }` — the host provider id and the\n * `<collection>/<id>/<pid>` key the delivery envelope was written under.\n */\n async sealRecordToHost(\n collection: string,\n id: string,\n hostSealer: RecipientSealer,\n opts: { expiresAt: string },\n ): Promise<{ pid: string; envelopeKey: string }> {\n return sealRecordToHostImpl(this.sealingContext(), collection, id, hostSealer, opts)\n }\n\n /**\n * Revoke a single sealed-CEK delivery envelope by deleting it from the store.\n * A soft revocation: it removes the host's copy of the sealed CEK, but a host\n * that already fetched the envelope keeps whatever it cached. For a hard\n * revocation that makes the live record undecryptable to every prior grant,\n * use {@link rotateRecordCek}.\n */\n async revokeSealedRecord(collection: string, id: string, pid: string): Promise<void> {\n return revokeSealedRecordImpl(this.sealingContext(), collection, id, pid)\n }\n\n /**\n * HARD-rotate a record's CEK: decrypt the live body under the old CEK,\n * re-encrypt it under a freshly-minted CEK, write the new live envelope, evict\n * the in-memory caches, and delete EVERY sealed-CEK delivery envelope for the\n * record. After this, any host holding a previously-sealed CEK can still\n * decrypt PRE-rotation history versions (they keep their old `_cek`) but NOT\n * the rotated live record (its body is under the new CEK → the old CEK fails\n * the AES-GCM auth tag → `TamperedError`). That asymmetry IS the revocation:\n * old grants lose the live record.\n *\n * Administrative path — bypasses `Collection.put` deliberately (no guards, no\n * history snapshot, no materialized-view refresh): rotation is a key-rotation\n * operation, not a business write, and must not version-bump history (which\n * would re-encrypt the prior version under the NEW CEK and defeat the point).\n *\n * @throws {@link RecordCekNotFoundError} if the record is missing or has no `_cek`.\n */\n async rotateRecordCek(collection: string, id: string): Promise<void> {\n return rotateRecordCekImpl(this.sealingContext(), collection, id)\n }\n\n /**\n * Build the {@link SealingContext} the record-keys grantor functions need:\n * the vault-bound adapter, DEK resolver, actor, and the dual-cache eviction\n * `rotateRecordCek` performs (per-record CEK cache + decrypted-record cache).\n */\n private sealingContext(): SealingContext {\n return {\n adapter: this.adapter,\n vault: this.name,\n getDEK: (collection) => this.getDEK(collection),\n actor: this.keyring.userId,\n invalidateRecordCaches: async (collection, id) => {\n const coll = this.collection<Record<string, unknown>>(collection)\n coll._invalidateCekCacheEntry(id)\n await coll._invalidateCacheEntry(id)\n },\n }\n }\n\n /**\n * @internal — called by `Noydb.openVault` after construction.\n * Dynamic-imports `GuardRegistry` + `ReadOnlyVaultFacade` and seeds\n * the registry with the supplied strategy handles. No-op when the\n * handles array is empty — keeps the guard subsystem out of the\n * floor bundle for consumers that don't use guards.\n *\n * The read-only facade is eagerly instantiated here so the sync\n * accessor `_getReadOnlyFacade()` (called from the tx amendment\n * runner) stays synchronous.\n */\n async _initGuards(handles: ReadonlyArray<GuardStrategyHandleAny>): Promise<void> {\n if (handles.length === 0) return\n const [{ GuardRegistry }, { ReadOnlyVaultFacade }] = await Promise.all([\n import('./guards/registry.js'),\n import('./guards/read-only-facade.js'),\n ])\n const registry = new GuardRegistry()\n for (const h of handles) registry.register(h.spec)\n this.guardRegistry = registry\n this.readOnlyFacade = new ReadOnlyVaultFacade(this)\n }\n\n /**\n * @internal — The gate handler in Noydb.#registerGuardGate calls into\n * this. Returns `null` for vaults that never registered any guard\n * strategy. Callers MUST gate on null.\n */\n _getGuardRegistry(): GuardRegistry | null {\n return this.guardRegistry\n }\n\n /**\n * @internal — called by `Noydb.openVault` after construction.\n * Dynamic-imports `DerivationRegistry` and registers the supplied\n * derivation strategies (async because `strategyHash` computation\n * goes through `crypto.subtle.digest`). No-op when the handles\n * array is empty — keeps the derivation subsystem out of the floor\n * bundle for consumers that don't use derivations. Throws\n * `DerivationCycleError` if a cycle is detected after registration.\n */\n async _initDerivations(handles: ReadonlyArray<DerivationStrategyHandle>): Promise<void> {\n if (handles.length === 0) return\n const [{ DerivationRegistry }, { ReadOnlyVaultFacade }] = await Promise.all([\n import('./derivations/registry.js'),\n import('./guards/read-only-facade.js'),\n ])\n const registry = new DerivationRegistry()\n for (const h of handles) {\n await registry.register(h.spec)\n }\n registry.validate()\n this.derivationRegistry = registry\n // Share the facade with guards: if `_initGuards` ran first the slot\n // is already populated. Otherwise allocate so `derive(source, ctx)`\n // has a vault accessor without re-importing the class per call.\n if (this.readOnlyFacade === null) {\n this.readOnlyFacade = new ReadOnlyVaultFacade(this)\n }\n }\n\n /**\n * @internal — consumed by `Collection.put` at write-time. Returns\n * `null` for vaults that never registered any derivation strategy.\n */\n _getDerivationRegistry(): DerivationRegistry | null {\n return this.derivationRegistry\n }\n\n /**\n * @internal — called by `Noydb.openVault` after collections are\n * wired. Dynamic-imports `MaterializedViewRegistry`, registers each\n * MV spec (which invokes its `query()` once for dependency\n * analysis), then runs the unified cycle detection across the MV +\n * derivation graphs. No-op when the handles array is empty — keeps\n * the MV subsystem out of the floor bundle (mirrors the derivation lazy-import pattern).\n * Throws `MaterializedViewCycleError` if a cycle is detected.\n */\n async _initMaterializedViews(\n \n handles: ReadonlyArray<MaterializedViewStrategyHandle>,\n ): Promise<void> {\n if (handles.length === 0) return\n const { MaterializedViewRegistry } = await import('./materialized-views/registry.js')\n const registry = new MaterializedViewRegistry()\n // Phase 1: publish the (empty) registry on `this` BEFORE\n // registering any spec. The user's `query(db)` callback runs at\n // registration time and may construct source Collections via\n // `db.collection(name)` — those Collections are cached in the\n // vault and their `materializedViewSource` is populated from\n // `this.materializedViewRegistry` AT CONSTRUCTION TIME. If we\n // assigned `this.materializedViewRegistry` only after the\n // register() loop, the source Collections would cache with an\n // unset source and never dispatch MV refreshes on later writes.\n this.materializedViewRegistry = registry\n // Pass `this` Vault as the MVQueryContext — its `collection<T>()`\n // method is what the user's `query(db)` callback consumes.\n \n const db = this as unknown as MVQueryContext\n for (const h of handles) {\n await registry.register(h.spec, db)\n }\n // Phase 2: unified cycle detection across MV + derivation graphs.\n // Runs after all `register()` calls so the analyzer has every\n // dep-set; throws `MaterializedViewCycleError` on the first cycle.\n registry.validate(this.derivationRegistry)\n }\n\n /**\n * @internal — consumed by `Collection.put` at write-time. Returns\n * `null` for vaults that never registered any MV strategy.\n */\n _getMaterializedViewRegistry(): MaterializedViewRegistry | null {\n return this.materializedViewRegistry\n }\n\n /**\n * @internal — called by `Noydb.openVault` after MVs are wired.\n * Dynamic-imports `OverlayedViewRegistry`, registers each spec,\n * validates against the MV registry for name/base/overlay collisions.\n * Throws on validation failure.\n */\n async _initOverlayedViews(\n handles: ReadonlyArray<OverlayedViewStrategyHandle>,\n ): Promise<void> {\n if (handles.length === 0) return\n const { OverlayedViewRegistry } = await import('./overlay-views/registry.js')\n const registry = new OverlayedViewRegistry()\n const mvRegistry = this.materializedViewRegistry\n // Build the predicate set for registration validation:\n // - isOverlayName: an already-registered overlay's virtual name\n // - isMVOutput: a collection name owned by an MV\n const overlayNames = new Set<string>()\n for (const h of handles) overlayNames.add(h.spec.name)\n const isMVOutput = (name: string): boolean => {\n if (!mvRegistry) return false\n for (const reg of mvRegistry.all()) {\n if (reg.outputCollection === name) return true\n }\n return false\n }\n for (const h of handles) {\n registry.register(h.spec, {\n isOverlayName: (n) => overlayNames.has(n) && n !== h.spec.name,\n isMVOutput,\n })\n }\n this.overlayedViewRegistry = registry\n }\n\n /**\n * @internal — consumed by `Vault.collection()`. Returns `null` for\n * vaults with no overlays registered.\n */\n _getOverlayedViewRegistry(): OverlayedViewRegistry | null {\n return this.overlayedViewRegistry\n }\n\n /**\n * Manual re-materialize for a single registered MV. Useful\n * for `refresh: 'manual'` MVs (whose consumer drives refreshes\n * externally), for stale-bit recovery on vault re-open, and as the\n * explicit bulk-recompute escape hatch after a strategy change.\n *\n * Returns `{ written, deleted, failed }`. `deleted` is always 0\n * when tombstoning is not enabled.\n *\n * Throws if `name` is not a registered MV.\n */\n async refreshView(name: string): Promise<{ written: number; deleted: number; failed: number }> {\n const registry = this.materializedViewRegistry\n if (registry === null) {\n return { written: 0, deleted: 0, failed: 0 }\n }\n const reg = registry.byName(name)\n if (!reg) {\n throw new Error(`refreshView: no MV registered with name \"${name}\"`)\n }\n const { MaterializedViewExecutor } = await import('./materialized-views/executor.js')\n const result = await MaterializedViewExecutor.refresh(reg, {\n getCollection: (n) => this.collection(n),\n getActiveTxContext: () => this.noydb._activeTxContextOrNull,\n getQueryContext: () => this as unknown as MVQueryContext,\n })\n // Manual refresh clears any pending stale bit — the post-refresh\n // state matches the registered strategy.\n const { clearMVStale } = await import('./materialized-views/stale.js')\n clearMVStale(registry, name)\n return result\n }\n\n /**\n * Re-derive every record in the named source collection. Useful\n * after a strategy change to bring previously-derived records\n * up-to-date.\n *\n * Sequential in v1; parallelisation deferred to v2.\n */\n async deriveAll(sourceCollection: string): Promise<{ derived: number; failed: number }> {\n const registry = this._getDerivationRegistry()\n if (registry === null) return { derived: 0, failed: 0 }\n const strategies = registry.strategiesForSource(sourceCollection)\n if (strategies.length === 0) return { derived: 0, failed: 0 }\n\n const { DerivationExecutor } = await import('./derivations/executor.js')\n\n const sourceColl = this.collection<Record<string, unknown>>(sourceCollection)\n const records = await sourceColl.list()\n // `_initDerivations` populates `readOnlyFacade` — assert non-null\n // for the closure-captured ctx. Falls back to a fresh facade on the\n // sync-fallback path (Noydb.vault() without await) for the same\n // defensive reason `_ensureReadOnlyFacade` exists.\n const ctx = { vault: this.readOnlyFacade ?? new (await import('./guards/read-only-facade.js')).ReadOnlyVaultFacade(this) }\n let derived = 0\n let failed = 0\n for (const record of records) {\n if (typeof record !== 'object' || record === null) continue\n const id = (record as { id?: unknown }).id\n if (typeof id !== 'string') continue\n for (const { spec, strategyHash } of strategies) {\n const sourceWithId = { ...record, id }\n const result = await DerivationExecutor.run(spec, sourceWithId, 0, strategyHash, ctx)\n let anyFailed = false\n for (const key of Object.keys(spec.outputs)) {\n const out = result.outputs[key]\n if (!out) continue\n if (out.kind === 'failed') { anyFailed = true; continue }\n const outSpec = spec.outputs[key]\n if (!outSpec) continue\n const outputColl = this.collection(outSpec.collection)\n\n // Array-shape branch — diff against the fanout sidecar.\n if (out.kind === 'array') {\n const { loadFanoutSidecar, saveFanoutSidecar } =\n await import('./derivations/fanout-sidecar.js')\n const prior = await loadFanoutSidecar(this.adapter, this.name, spec.source, id, key)\n const prevKeys = new Set<string>(prior?.keys ?? [])\n const newKeysList = out.entries.map(e => e.key)\n const newKeysSet = new Set<string>(newKeysList)\n for (const k of prevKeys) {\n if (newKeysSet.has(k)) continue\n await outputColl._internalDelete(k)\n }\n for (const entry of out.entries) {\n await outputColl.put(entry.key, entry.value)\n }\n await saveFanoutSidecar(this.adapter, this.name, {\n source: spec.source,\n sourceId: id,\n outputKey: key,\n outputCollection: outSpec.collection,\n keys: newKeysList,\n })\n continue\n }\n\n if (out.skipped === true) {\n // Optional output skipped — delete any prior emission.\n // No txCtx hookup needed: `deriveAll` runs outside the\n // multi-record transaction window by design. Routed\n // through `_internalDelete` so the bulk recompute does not\n // trip user `onDelete` on the output collection.\n await outputColl._internalDelete(id)\n continue\n }\n await outputColl.put(id, out.value)\n }\n if (anyFailed) failed++\n else derived++\n }\n }\n return { derived, failed }\n }\n\n /**\n * @internal — exposed for `runTransaction({ amendment: true })` so\n * the amendment invariant runner can pass the SAME read-only vault\n * facade that the gate handler in Noydb.#registerGuardGate uses.\n * Eagerly instantiated by `_initGuards()` so this accessor stays\n * synchronous; returns `null` for vaults that never registered any\n * guard (amendments require at least one guard, so the caller should\n * never see null).\n */\n _getReadOnlyFacade(): ReadOnlyVaultFacade | null {\n return this.readOnlyFacade\n }\n\n /**\n * Internal lazy-allocator for the read-only facade. Used as a\n * defensive fallback; in practice `_initGuards()` eagerly\n * instantiates this, so the lazy path is a no-op.\n */\n private _ensureReadOnlyFacade(): ReadOnlyVaultFacade {\n if (this.readOnlyFacade !== null) return this.readOnlyFacade\n // Synchronous fall-back: dynamic import isn't available here,\n // but `_initGuards` always sets the facade before any\n // guard-hook can fire. Reaching this branch means a Vault was\n // constructed without `_initGuards` being awaited — e.g. via\n // the sync `Noydb.vault()` fallback path. Throw with a\n // pointer rather than silently building an invalid context.\n throw new Error(\n 'Vault: guard hook fired before _initGuards() completed. ' +\n 'This typically means the vault was opened via the sync ' +\n 'fallback path (Noydb.vault(name)) without first calling ' +\n 'await db.openVault(name). See issue #132.',\n )\n }\n\n /**\n * @internal — exposed for `runTransaction({ amendment: true })`\n * to append the structured `op: 'amendment'` audit entry without\n * dragging this private accessor onto the public surface or\n * forcing the tx executor to depend on the history-strategy\n * shape directly. Returns `null` when no history strategy is\n * configured, in which case the amendment commits silently\n * (the records still write through; only the multi-record\n * audit summary is skipped).\n */\n _getLedgerOrNull(): LedgerStore | null {\n return this.getLedgerOrNull()\n }\n\n /**\n * Return a read-only view of this vault as it existed at\n * `timestamp`. Time-machine queries are reconstructed from the\n * per-version history snapshots persisted by every `put()`, then\n * cross-checked against the ledger for deletes that happened\n * between the snapshot and the target timestamp.\n *\n * ```ts\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 * `timestamp` accepts an ISO-8601 string or a `Date`. Time-machine\n * views are read-only — writes throw {@link ReadOnlyAtInstantError}.\n * Accuracy bounded by history retention: if `historyConfig.maxVersions`\n * pruned earlier versions, queries before the oldest retained\n * snapshot return null even for records that existed.\n *\n *.\n */\n at(timestamp: string | Date): VaultInstant {\n const iso = timestamp instanceof Date ? timestamp.toISOString() : timestamp\n return this.historyStrategy.buildVaultInstant(\n {\n adapter: this.adapter,\n name: this.name,\n encrypted: this.encrypted,\n getDEK: this.getDEK,\n getLedger: () => (this.historyConfig.enabled === false ? null : this.getLedgerOrNull()),\n },\n iso,\n )\n }\n\n /**\n * Return a read-only \"shadow\" view of this vault. Every read method\n * on the returned {@link VaultFrame} delegates to the underlying\n * live collection; every write method throws\n * {@link ReadOnlyFrameError}.\n *\n * ```ts\n * const presentation = vault.frame()\n * const invoices = await presentation.collection<Invoice>('invoices').list()\n * ```\n *\n * Use for screen-sharing a live vault, demo mode, or compliance\n * review where the reviewer should not be able to edit. Writes are\n * blocked at the JavaScript layer — the keyring DEKs are unchanged,\n * so this is **not** a cryptographic security boundary against a\n * hostile caller in the same process. See {@link VaultFrame} for\n * the full caveat.\n *\n *.\n */\n frame(): VaultFrame {\n return this.shadowStrategy.buildFrame(this)\n }\n\n /**\n * Run `fn` under a consent scope. Every `get` / `put` / `delete`\n * that happens inside `fn` writes one entry to `_consent_audit`\n * with the supplied `purpose` and `consentHash`. Outside a scope,\n * no entries are written — consent logging is opt-in by design.\n *\n * ```ts\n * await vault.withConsent(\n * { purpose: 'quarterly-review', consentHash: '7f3a...' },\n * async () => {\n * const invoices = await vault.collection<Invoice>('invoices').list()\n * return invoices\n * },\n * )\n * ```\n *\n * The scope is a single slot on this Vault instance — two\n * concurrent `withConsent` calls stomp each other. Use separate\n * Vault instances (or an external `AsyncLocalStorage` shim) for\n * per-flight scoping.\n *\n *.\n */\n async withConsent<T>(ctx: ConsentContext, fn: () => Promise<T>): Promise<T> {\n const prior = this.consentContext\n this.consentContext = ctx\n try {\n return await fn()\n } finally {\n this.consentContext = prior\n }\n }\n\n /**\n * Query the consent-audit log. Returns every entry matching the\n * filter, newest-first isn't enforced — entries carry ULID ids so\n * sorting by id is insertion-order stable. Caller may sort further.\n *\n *.\n */\n async consentAudit(filter: ConsentAuditFilter = {}): Promise<ConsentAuditEntry[]> {\n return this.consentStrategy.read(this.adapter, this.name, this.encrypted, this.getDEK, filter)\n }\n\n /**\n * Called by Collection after every access when a consent scope is\n * active. Internal — not part of the public API.\n *\n * @internal\n */\n async _logConsent(op: ConsentOp, collection: string, recordId: string): Promise<void> {\n const ctx = this.consentContext\n if (!ctx) return\n await this.consentStrategy.write(\n this.adapter,\n this.name,\n this.encrypted,\n {\n actor: this.keyring.userId,\n purpose: ctx.purpose,\n consentHash: ctx.consentHash,\n op,\n collection,\n recordId,\n },\n this.getDEK,\n )\n }\n\n // ─── Hierarchical access ─────────────────────────\n\n /**\n * Subscribe to cross-tier access events. The callback fires every\n * time a record at a tier above the caller's inherent clearance is\n * read, written, elevated, or demoted successfully via this vault.\n * Returns an unsubscribe function.\n */\n onCrossTierAccess(\n listener: (event: CrossTierAccessEvent) => void,\n ): () => void {\n this.crossTierSubs.add(listener)\n return () => this.crossTierSubs.delete(listener)\n }\n\n private emitCrossTier(event: CrossTierAccessEvent): void {\n for (const sub of this.crossTierSubs) {\n try {\n sub(event)\n } catch {\n // subscriber failures are swallowed — audit sinks must be best-effort\n }\n }\n }\n\n /**\n * issue a time-boxed cross-tier delegation. Writes an\n * encrypted envelope to the reserved `_delegations` collection that\n * the target user's runtime will pick up next time they open the\n * vault.\n *\n * Caller must hold the tier DEK for the requested tier and\n * collection.\n */\n async delegate(opts: IssueDelegationOptions): Promise<DelegationToken> {\n const { issueDelegation, DELEGATIONS_COLLECTION } = await import('./team/delegation.js')\n // The target user's KEK is derived from THEIR keyring — we read\n // the keyring file to pick up the wrapped DEKs and their KEK salt,\n // but we cannot derive their KEK from our side (we don't have\n // their passphrase). For the delegation wraps against the\n // grantor's own KEK as a simpler first cut; swapping to a proper\n // per-target KEK exchange (via `on-magic-link` or OIDC) is a\n // follow-up tracked in the design doc.\n if (!this.keyring.kek) {\n throw new ValidationError(\n 'issueDelegation: keyring.kek is null — issuing a delegation requires ' +\n 'a tier-1 unlock. Re-authenticate at tier 1 (passphrase) first.',\n )\n }\n const targetKek = this.keyring.kek\n const delegationsDek = await this.getDEK(DELEGATIONS_COLLECTION)\n return issueDelegation(\n this.adapter,\n this.name,\n this.keyring,\n targetKek,\n delegationsDek,\n opts,\n )\n }\n\n /**\n * revoke an issued delegation by id. Safe to call even\n * if the id does not exist.\n */\n async revokeDelegation(id: string): Promise<void> {\n const { revokeDelegation, DELEGATIONS_COLLECTION } = await import('./team/delegation.js')\n await revokeDelegation(this.adapter, this.name, id)\n // Trigger store to note the delete.\n void DELEGATIONS_COLLECTION\n }\n\n // ─── Scoped tier elevation ───────────────────────────\n\n /**\n * Briefly elevate this vault to a higher tier and return a scoped\n * handle whose writes land at that tier. Reads on the original\n * vault continue at the caller's inherent tier; only the returned\n * handle is privileged. Auto-reverts when `release()` is called or\n * `ttlMs` elapses, whichever comes first.\n *\n * Capability semantics:\n * - The keyring must already carry a wrap for the target tier on\n * at least one collection (or be `owner` / `admin`, who can\n * auto-mint). Otherwise throws {@link TierNotGrantedError}.\n * - Per-collection capability gates (`canExportPlaintext`,\n * `canExportBundle`) are NOT bypassed — elevation is a tier\n * projection, not a privilege escalation path.\n * - Only one elevation can be active per vault at a time.\n * Calling `elevate(...)` while another is live throws\n * {@link AlreadyElevatedError}.\n *\n * Audit:\n * - One `_elevation_audit` envelope is written at start with\n * `{ id, actor, tier, reason, ttlMs, startedAt, expiresAt }`.\n * - Each write through the elevated handle additionally fires a\n * {@link CrossTierAccessEvent} with `authorization: 'elevation'`,\n * stamped with `reason` and `elevatedFrom`.\n */\n async elevate(\n tier: number,\n options: { ttlMs: number; reason: string },\n ): Promise<ElevatedHandle> {\n if (!Number.isInteger(tier) || tier <= 0) {\n throw new ValidationError(`elevate: tier must be a positive integer, got ${tier}`)\n }\n if (!options || typeof options.reason !== 'string' || options.reason.length === 0) {\n throw new ValidationError('elevate: reason is required (non-empty string)')\n }\n if (typeof options.ttlMs !== 'number' || options.ttlMs <= 0) {\n throw new ValidationError('elevate: ttlMs must be a positive number')\n }\n if (this.activeElevation) {\n throw new AlreadyElevatedError(this.activeElevation.tier)\n }\n // Construction-time tier-reach check: scan keyring for any\n // `*#${tier}` DEK. Owners and admins skip — they auto-mint at\n // write time per the existing `assertTierAccess` rules.\n if (this.keyring.role !== 'owner' && this.keyring.role !== 'admin') {\n const suffix = `#${tier}`\n let found = false\n for (const k of this.keyring.deks.keys()) {\n if (k.endsWith(suffix)) { found = true; break }\n }\n if (!found) {\n // Match the existing error class so adopters with one catch()\n // for tier-related failures don't need a second branch.\n throw new TierNotGrantedError('(any collection)', tier)\n }\n }\n\n const startedAt = new Date()\n const expiresAt = startedAt.getTime() + options.ttlMs\n const reason = options.reason\n\n const handle = new ElevatedHandle({\n vault: this,\n tier,\n reason,\n expiresAt,\n onRelease: () => {\n if (this.activeElevation && this.activeElevation.handle === handle) {\n this.activeElevation = null\n }\n },\n })\n\n this.activeElevation = { tier, expiresAt, reason, handle }\n await this.writeElevationAudit({\n actor: this.keyring.userId,\n tier,\n reason,\n ttlMs: options.ttlMs,\n startedAt: startedAt.toISOString(),\n expiresAt: new Date(expiresAt).toISOString(),\n })\n return handle\n }\n\n /**\n * Internal — invoked by an `ElevatedHandle.collection().put()` call.\n * Routes through the existing `Collection.putAtTier` code path with\n * the elevation context attached so the cross-tier event reflects\n * the right authorization class.\n */\n async _elevatedPut<T>(\n collectionName: string,\n id: string,\n record: T,\n tier: number,\n reason: string,\n ): Promise<void> {\n const coll = this.collection<T>(collectionName)\n await coll.putAtTier(id, record, tier, {\n elevation: { reason, fromTier: 0 },\n })\n }\n\n private async writeElevationAudit(entry: {\n actor: string\n tier: number\n reason: string\n ttlMs: number\n startedAt: string\n expiresAt: string\n }): Promise<void> {\n const id = `elev-${Date.now().toString(36)}-${Math.random().toString(16).slice(2, 10)}`\n const json = JSON.stringify({ id, ...entry })\n const envelope: EncryptedEnvelope = this.encrypted\n ? await (async () => {\n const dek = await this.getDEK(ELEVATION_AUDIT_COLLECTION)\n const { iv, data } = await encrypt(json, dek)\n return {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: 1,\n _ts: entry.startedAt,\n _iv: iv,\n _data: data,\n _by: entry.actor,\n }\n })()\n : {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: 1,\n _ts: entry.startedAt,\n _iv: '',\n _data: json,\n _by: entry.actor,\n }\n await this.adapter.put(this.name, ELEVATION_AUDIT_COLLECTION, id, envelope)\n }\n\n /**\n * low-level escape hatch used by `@noy-db/on-magic-link`\n * to persist a magic-link-bound grant after the auth package has\n * derived the content key + KEK from `(serverSecret, token, vault)`.\n *\n * Callers outside of `@noy-db/on-magic-link` should use\n * `issueMagicLinkDelegation()` from that package instead — it handles\n * the HKDF derivation, record-id composition, and batch logic so the\n * grantor doesn't touch this method directly.\n */\n async writeMagicLinkGrant(\n contentKey: CryptoKey,\n grantKek: CryptoKey,\n recordId: string,\n opts: IssueMagicLinkGrantOptions,\n ): Promise<MagicLinkGrantRecord> {\n return writeMagicLinkGrant(\n this.adapter,\n this.name,\n this.keyring,\n contentKey,\n grantKek,\n recordId,\n opts,\n )\n }\n\n // ─── Accounting periods ────────────────────────\n\n /**\n * Close an accounting period. After this call every record whose\n * envelope `_ts` is at or before `endDate` is write-locked: further\n * `put` or `delete` calls against such records throw\n * {@link PeriodClosedError}. New records (with fresh timestamps)\n * remain freely writable, and records last written AFTER `endDate`\n * are unaffected.\n *\n * Each closure writes a `PeriodRecord` to the reserved `_periods`\n * collection. The record carries the hash of the prior period's\n * record, so a tamper with any closure breaks the chain visible to\n * {@link listPeriods} + `vault.ledger().verify()`.\n *\n * Correctness is tied to the `_ts` field the hub assigns on every\n * write. Backdating records by editing the envelope directly is\n * outside the threat model — see SPEC § zero-knowledge envelopes.\n *\n *.\n */\n async closePeriod(options: ClosePeriodOptions): Promise<PeriodRecord> {\n const existing = await this._loadPeriodsCache()\n this.periodsStrategy.validatePeriodName(options.name, existing)\n if (typeof options.endDate !== 'string' || options.endDate.length === 0) {\n throw new ValidationError('closePeriod: endDate must be a non-empty ISO string.')\n }\n const anchor = await this.periodsStrategy.chainAnchor(existing)\n const record: PeriodRecord = {\n name: options.name,\n kind: 'closed',\n endDate: options.endDate,\n closedAt: new Date().toISOString(),\n closedBy: this.keyring.userId,\n priorPeriodHash: anchor.priorPeriodHash,\n ...(anchor.priorPeriodName !== undefined && { priorPeriodName: anchor.priorPeriodName }),\n ...(options.dateField !== undefined && { dateField: options.dateField }),\n }\n const envelope = await this._writePeriodRecord(record)\n await this.periodsStrategy.appendPeriodLedgerEntry(this.getLedgerOrNull(), this.keyring.userId, envelope, record.name)\n existing.push(record)\n this.periodCache = existing\n return record\n }\n\n /**\n * Open a new period that carries forward from a prior closed one\n *. The `carryForward` callback receives a read-only\n * {@link VaultInstant} view anchored at the prior period's\n * `endDate` — use it to compute opening balances, closing-trial\n * snapshots, or any aggregate the new period should inherit. The\n * returned `{ [collection]: { [id]: record } }` map is written\n * before the new `PeriodRecord` lands, so the opening entries\n * materialise with fresh `_ts` values that fall outside every\n * closed period (the guard lets them through).\n *\n * The new period is stored with `kind: 'opened'` and hash-chained\n * to the same chain the close calls build — `listPeriods()` sees\n * both closed and opened entries in `closedAt` order.\n */\n async openPeriod<TCollections extends Record<string, Record<string, unknown>>>(\n options: OpenPeriodOptions<TCollections>,\n ): Promise<PeriodRecord> {\n const existing = await this._loadPeriodsCache()\n this.periodsStrategy.validatePeriodName(options.name, existing)\n const prior = existing.find((p) => p.name === options.fromPeriod)\n if (!prior) {\n throw new ValidationError(\n `openPeriod: fromPeriod \"${options.fromPeriod}\" does not exist in this vault.`,\n )\n }\n if (prior.kind !== 'closed') {\n throw new ValidationError(\n `openPeriod: fromPeriod \"${options.fromPeriod}\" is of kind \"${prior.kind}\" — only closed periods can be carried forward.`,\n )\n }\n\n // Build a read-only facade over CURRENT state + the prior\n // period's endDate; after close, records dated <= endDate are\n // frozen so current state equals closing state. The caller\n // filters by business date via their own query against this\n // facade.\n const ctx = {\n priorEndDate: prior.endDate,\n collection: <T = unknown>(name: string) => {\n const c = this.collection<T>(name)\n return {\n get: (id: string) => c.get(id),\n list: () => c.list(),\n }\n },\n }\n const openings = await options.carryForward(ctx)\n\n // Write opening entries via the normal Collection path so they\n // get encryption, ledger entries, and change events. Each record\n // is timestamped NOW (outside every closed period) — that's why\n // the guard permits them.\n const openingCollections: string[] = []\n for (const [collName, records] of Object.entries(openings)) {\n if (!records || typeof records !== 'object') continue\n const recordEntries = Object.entries(records)\n if (recordEntries.length === 0) continue\n const coll = this.collection(collName)\n for (const [id, record] of recordEntries) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n await coll.put(id, record as any)\n }\n openingCollections.push(collName)\n }\n\n const anchor = await this.periodsStrategy.chainAnchor(existing)\n const record: PeriodRecord = {\n name: options.name,\n kind: 'opened',\n startDate: options.startDate,\n endDate: prior.endDate, // sealing boundary inherited from prior close\n closedAt: new Date().toISOString(),\n closedBy: this.keyring.userId,\n priorPeriodHash: anchor.priorPeriodHash,\n priorPeriodName: anchor.priorPeriodName ?? prior.name,\n ...(openingCollections.length > 0 && { openingCollections }),\n }\n const envelope = await this._writePeriodRecord(record)\n await this.periodsStrategy.appendPeriodLedgerEntry(this.getLedgerOrNull(), this.keyring.userId, envelope, record.name)\n existing.push(record)\n this.periodCache = existing\n return record\n }\n\n /** Return every closed / opened period in `closedAt` order. */\n async listPeriods(): Promise<readonly PeriodRecord[]> {\n return [...(await this._loadPeriodsCache())]\n }\n\n /** Look up a single period by name. Returns `null` if not found. */\n async getPeriod(name: string): Promise<PeriodRecord | null> {\n const all = await this._loadPeriodsCache()\n return all.find((p) => p.name === name) ?? null\n }\n\n /** @internal — called by the gate bus before put/delete. */\n async _assertTsWritable(\n existing: { ts: string | null; record: Record<string, unknown> | null } | null,\n incoming: Record<string, unknown> | null,\n ): Promise<void> {\n // Fast path: nothing to check, and no periods ever touched this\n // vault — avoid a full adapter scan for every put.\n if (existing === null && incoming === null) return\n if (this.periodCache === null) {\n this.periodCache = await this.periodsStrategy.loadPeriods(\n this.adapter,\n this.name,\n (env) => this._decryptPeriodRecord(env),\n )\n }\n if (this.periodCache.length === 0) return\n this.periodsStrategy.assertTsWritable(existing, incoming, this.periodCache)\n }\n\n private async _loadPeriodsCache(): Promise<PeriodRecord[]> {\n if (this.periodCache !== null) return this.periodCache\n const loaded = await this.periodsStrategy.loadPeriods(\n this.adapter,\n this.name,\n (env: EncryptedEnvelope) => this._decryptPeriodRecord(env),\n )\n this.periodCache = loaded\n return loaded\n }\n\n private async _writePeriodRecord(record: PeriodRecord): Promise<EncryptedEnvelope> {\n const json = JSON.stringify(record)\n let envelope: EncryptedEnvelope\n if (this.encrypted) {\n const dek = await this.getDEK(PERIODS_COLLECTION)\n const { iv, data } = await encrypt(json, dek)\n envelope = {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: 1,\n _ts: new Date().toISOString(),\n _iv: iv,\n _data: data,\n _by: this.keyring.userId,\n }\n } else {\n envelope = {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: 1,\n _ts: new Date().toISOString(),\n _iv: '',\n _data: json,\n _by: this.keyring.userId,\n }\n }\n await this.adapter.put(this.name, PERIODS_COLLECTION, record.name, envelope)\n return envelope\n }\n\n private async _decryptPeriodRecord(envelope: EncryptedEnvelope): Promise<PeriodRecord> {\n let json: string\n if (this.encrypted) {\n const dek = await this.getDEK(PERIODS_COLLECTION)\n json = await decrypt(envelope._iv, envelope._data, dek)\n } else {\n json = envelope._data\n }\n return JSON.parse(json) as PeriodRecord\n }\n\n /** List all collection names in this vault. */\n async collections(): Promise<string[]> {\n const snapshot = await this.adapter.loadAll(this.name)\n return Object.keys(snapshot)\n }\n\n /**\n * Emit a structured introspection snapshot of this vault — vault name,\n * subsystem opt-in matrix, collections + their fields, materialized\n * views, overlay views, derivations. With `withStats: true`, walks\n * every collection's envelopes to compute record counts, byte totals,\n * and oldest/newest timestamps.\n *\n * Consumed by the `noydb describe` CLI to produce human-readable\n * audit YAML/JSON from a `.noydb` bundle.\n *\n * Field provenance:\n * - `persisted`: read from `_schemas/<col>` envelope (Route B opt-in)\n * - `live-validator`: derived in-process from a Zod schema attached\n * to the live `Collection`\n * - `sampled`: inferred from decrypted records (deferred to a follow-up)\n * - `unknown`: no schema info available\n *\n * @see docs/superpowers/specs/2026-05-22-schema-dump-design.md\n */\n async dumpSchema(opts: DumpSchemaOptions = {}): Promise<VaultSchemaSnapshot> {\n return dumpVaultSchema(this, opts)\n }\n\n /**\n * Lightweight read of the vault's registered schema: collections\n * (+ doc counts), guards, materialized views, schema-update strategies,\n * and the unlocked user's grants. Cheap — one `adapter.list` per\n * collection, no decryption. For a full snapshot + stats use dumpSchema().\n * Post-unlock by construction (a Vault only exists with an unlocked keyring).\n */\n async introspect(): Promise<SchemaIntrospection> {\n const byCol = (a: { collection: string }, b: { collection: string }) =>\n a.collection.localeCompare(b.collection)\n\n // Union of collections registered this session (collectionCache) and\n // collections with persisted records (collections()), so registered-but-\n // empty collections are reported too.\n const names = [...new Set([...this.collectionCache.keys(), ...(await this.collections())])]\n .filter((n) => !n.startsWith('_'))\n .sort((a, b) => a.localeCompare(b))\n const collections: { name: string; docCount: number }[] = []\n for (const name of names) {\n const ids = await this.adapter.list(this.name, name)\n collections.push({ name, docCount: ids.length })\n }\n\n const guards = (this._getGuardRegistry()?.summary() ?? []).slice().sort(byCol)\n\n const materializedViews = (this._getMaterializedViewRegistry()?.all() ?? [])\n .map((mv) => ({ name: mv.spec.name, sourceCollections: [...mv.dependencies].sort() }))\n .sort((a, b) => a.name.localeCompare(b.name))\n\n const schemaUpdate = [...this.#schemaUpdateNames.entries()]\n .map(([collection, strategies]) => ({ collection, strategies }))\n .sort(byCol)\n\n // Grants reflect what the unlocked user can actually access: the\n // collections they hold a DEK for, with the level from `permissions`\n // (absent ⇒ implicit full access for owner/admin → 'rw').\n const grants = [...this.keyring.deks.keys()]\n .filter((collection) => !collection.startsWith('_'))\n .map((collection) => ({ collection, permission: this.keyring.permissions[collection] ?? 'rw' as const }))\n .sort(byCol)\n\n return { collections, guards, materializedViews, schemaUpdate, grants }\n }\n\n /**\n * Internal accessor for {@link dumpVaultSchema}. Exposes the structural\n * state the walker needs (collection cache, registries, ref registry,\n * adapter) without widening the public Vault surface.\n *\n * @internal\n */\n _introspectState(): VaultIntrospectState {\n return {\n name: this.name,\n adapter: this.adapter,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n collectionCache: this.collectionCache as Map<string, any>,\n refRegistry: this.refRegistry,\n getDEK: this.getDEK,\n subsystems: {\n guards: this.guardRegistry !== null,\n derivations: this.derivationRegistry !== null,\n materializedViews: this.materializedViewRegistry !== null,\n overlayViews: this.overlayedViewRegistry !== null,\n },\n mvRegistry: this.materializedViewRegistry,\n overlayRegistry: this.overlayedViewRegistry,\n derivationRegistry: this.derivationRegistry,\n }\n }\n\n /**\n * Return the stable opaque bundle handle for this vault,\n * generating and persisting a fresh ULID on first call.\n *\n * used by `writeNoydbBundle()` to identify the\n * vault in the unencrypted bundle header without\n * exposing the vault name. The handle is persisted in\n * the reserved `_meta` internal collection so subsequent\n * exports of the same vault produce the same handle —\n * bundle adapters (Drive, Dropbox, iCloud) will use it\n * as their primary key.\n *\n * **Storage path:** the handle is written via the adapter\n * directly with collection name `_meta` and id `handle`. The\n * envelope's `_data` field contains a plain JSON\n * `{ handle: '...' }` payload — the handle is opaque, doesn't\n * need encryption, and the bundle header exposes the same\n * value anyway. This mirrors the storage approach `_keyring`\n * uses for its plain-JSON wrapped-DEK envelopes (also bypasses\n * the AES-GCM layer; the `_iv` field is left empty).\n *\n * **Cross-process stability:** the handle survives process\n * restarts because it's persisted on the adapter, not just\n * cached in memory. A new Vault instance opened on the\n * same adapter sees the same `_meta/handle` envelope and\n * returns the same ULID.\n *\n * **Round-trip after restore:** the receiving vault of a\n * `load()` call generates its OWN handle on first export. The\n * dump body does not include `_meta`, because handle stability\n * is per-vault-instance, not per-vault-content. Two\n * separate restorations of the same backup produce two\n * distinct handles, which is the right behavior — they're\n * separate vault instances now.\n */\n async getBundleHandle(): Promise<string> {\n const existing = await this.adapter.get(this.name, '_meta', 'handle')\n if (existing) {\n try {\n const parsed = JSON.parse(existing._data) as unknown\n if (parsed !== null && typeof parsed === 'object' && 'handle' in parsed) {\n const handle = (parsed as { handle: unknown }).handle\n if (typeof handle === 'string' && /^[0-9A-HJKMNP-TV-Z]{26}$/.test(handle)) {\n return handle\n }\n }\n } catch {\n // Fall through to regenerate — corrupted handle envelope\n // is treated as missing, not as an error. The new handle\n // overwrites the bad one.\n }\n }\n // Lazy import to avoid a top-of-file circular dependency:\n // bundle/bundle.ts imports from vault.ts (the\n // Vault type), and vault.ts can't statically\n // import from bundle/* without forming a cycle. The dynamic\n // import is invoked once per fresh handle generation, which\n // is rare enough that the cost doesn't matter.\n const { generateULID } = await import('./bundle/ulid.js')\n const handle = generateULID()\n const envelope: EncryptedEnvelope = {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: 1,\n _ts: new Date().toISOString(),\n _iv: '',\n _data: JSON.stringify({ handle }),\n }\n await this.adapter.put(this.name, '_meta', 'handle', envelope)\n return handle\n }\n\n /**\n * Read the owner-curated public envelope for this vault (or\n * `undefined` if none is persisted). The envelope lives in\n * `_meta/public-envelope` as plaintext — readable without any KEK\n * — so `getBundleHandle`-style callers can label a vault before\n * unlock.\n *\n * Mirrors `Noydb.getPublicEnvelope(vault, opts)` but scoped to a\n * single, already-opened `Vault` instance so the\n * bundle writer can snapshot it without holding a `Noydb` reference.\n *\n * @see docs/subsystems/public-envelope.md\n */\n async getPublicEnvelope(\n opts: { readonly locale?: string } = {},\n ): Promise<PublicEnvelope | undefined> {\n const { readPublicEnvelope } = await import('./meta/public-envelope/index.js')\n return readPublicEnvelope(this.adapter, this.name, opts)\n }\n\n /**\n * Dump vault as a verifiable encrypted JSON backup string.\n *\n * backups embed the current ledger head and the full\n * `_ledger` + `_ledger_deltas` internal collections so the\n * receiver can run `verifyBackupIntegrity()` after `load()` and\n * detect any tampering between dump and restore. Backups produced\n * without a ledger (older formats or hub instances built without\n * the history strategy) skip the integrity check with a warning —\n * both modes round-trip cleanly.\n */\n async dump(): Promise<string> {\n const snapshot = await this.adapter.loadAll(this.name)\n\n // Load keyrings (separate path because loadAll filters them out\n // along with all other underscore-prefixed internal collections).\n const keyringIds = await this.adapter.list(this.name, '_keyring')\n const keyrings: Record<string, unknown> = {}\n for (const keyringId of keyringIds) {\n const envelope = await this.adapter.get(this.name, '_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 const internalSnapshot: VaultSnapshot = {}\n for (const internalName of [LEDGER_COLLECTION, LEDGER_DELTAS_COLLECTION, SCHEMAS_COLLECTION, SEQUENCE_COLLECTION]) {\n const ids = await this.adapter.list(this.name, internalName)\n if (ids.length === 0) continue\n const records: Record<string, EncryptedEnvelope> = {}\n for (const id of ids) {\n const envelope = await this.adapter.get(this.name, 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 = this.getLedgerOrNull()\n const head = ledgerForHead ? await ledgerForHead.head() : null\n const backup: VaultBackup = {\n _noydb_backup: NOYDB_BACKUP_VERSION,\n _compartment: this.name,\n _exported_at: new Date().toISOString(),\n _exported_by: this.keyring.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.\n *\n * After loading, runs `verifyBackupIntegrity()` to confirm:\n * 1. The hash chain is intact (no `prevHash` mismatches)\n * 2. The chain head matches the embedded `ledgerHead.hash`\n * from the backup\n * 3. Every data envelope's `payloadHash` matches the\n * corresponding ledger entry — i.e. nobody swapped\n * ciphertext between dump and restore\n *\n * On any failure, throws `BackupLedgerError` (chain or head\n * mismatch) or `BackupCorruptedError` (data envelope mismatch).\n * The vault state on the adapter has already been written\n * by the time we throw, so the caller is responsible for either\n * accepting the suspect state or wiping it and trying a different\n * backup.\n *\n * Legacy backups (no `ledgerHead` field, no `_internal`) load\n * with a console warning and skip the integrity check entirely\n * — there's no chain to verify against.\n */\n async load(backupJson: string): Promise<void> {\n const backup = JSON.parse(backupJson) as VaultBackup\n\n // 1. Restore data collections.\n await this.adapter.saveAll(this.name, 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 this.adapter.put(this.name, '_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 this.adapter.put(this.name, 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 if (this.reloadKeyring) {\n this.keyring = await this.reloadKeyring()\n // Rebuild the DEK resolver against the refreshed keyring so\n // the next ensureCollectionDEK call sees the loaded wrapped\n // DEKs, not the cached pre-load ones.\n this.getDEK = this.makeGetDEK()\n }\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 this.collectionCache.clear()\n this.ledgerStore = null\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 this.verifyBackupIntegrity()\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. Runs both:\n *\n * 1. `ledger.verify()` — walks the hash chain and confirms\n * every `prevHash` matches the recomputed hash of its\n * predecessor.\n *\n * 2. **Data envelope cross-check** — for every (collection, id)\n * that has a current value, find the most recent ledger\n * entry recording a `put` for that pair, recompute the\n * sha256 of the stored envelope's `_data`, and compare to\n * the entry's `payloadHash`. Any mismatch means an\n * out-of-band write modified the data without updating the\n * ledger.\n *\n * Returns a discriminated union so callers can handle the two\n * failure modes differently:\n * - `{ ok: true, head, length }` — chain verified and all\n * data matches; safe to use.\n * - `{ ok: false, kind: 'chain', divergedAt, message }` — the\n * chain itself is broken at the given index.\n * - `{ ok: false, kind: 'data', collection, id, message }` —\n * a specific data envelope doesn't match its ledger entry.\n *\n * This method is exposed so users can call it any time, not just\n * during `load()`. A scheduled background check is the simplest\n * way to detect tampering of an in-place vault.\n */\n async verifyBackupIntegrity(): Promise<\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 // 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 = this.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 this.adapter.get(this.name, 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 sha256Hex(envelope._data)\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 * Stream every collection in this vault as decrypted, ACL-scoped\n * chunks.\n *\n * ⚠ **This method decrypts your records.** noy-db's threat model assumes\n * that records on disk are encrypted; the values yielded here are\n * plaintext. The consumer is responsible for ensuring the yielded data\n * is handled in a way that matches the data's sensitivity. If your goal\n * is encrypted backup or transport between noy-db instances, use\n * `dump()` instead — it produces a tamper-evident encrypted envelope and\n * never exposes plaintext.\n *\n * ## Behavior\n *\n * - **ACL-scoped.** Collections the calling principal cannot read are\n * silently skipped (same rule as `Collection.list()`). An operator\n * with `{ invoices: 'rw', clients: 'ro' }` permissions on a\n * five-collection vault exports only `invoices` and `clients`,\n * with no error on the others.\n * - **Streaming.** Returns an `AsyncIterableIterator` so consumers can\n * process chunks as they arrive without holding the full export in\n * memory. Note: the underlying adapter call (`loadAll`) is still a\n * single bulk read — the streaming benefit is on the *output* side.\n * True per-record adapter streaming arrives with the query DSL.\n * - **Schema + refs surfaced** as metadata on every chunk so downstream\n * serializers (`@noy-db/as-csv`, `@noy-db/as-xlsx`, custom\n * exporters) can produce schema-aware output without reaching into\n * collection internals.\n * - **Internal collections filtered.** `_ledger`, `_keyring`, etc. are\n * never yielded — they're noy-db's own bookkeeping and have no value\n * in a plaintext export. Use `dump()` for full backup including\n * internal collections.\n *\n * ## Composition\n *\n * Once cross-vault queries land, fanning this out across\n * every vault the caller can unlock is `queryAcross(ids, c =>\n * c.exportStream())` — no new primitive needed. That's part of why this\n * method belongs in core: it's the single decrypt+ACL+metadata path\n * that every export-format package will build on, and pushing it into\n * a `@noy-db/as-*` package would force every format to re-solve\n * the same problems independently.\n *\n * @example\n * ```ts\n * for await (const chunk of company.exportStream()) {\n * // chunk.collection: 'invoices'\n * // chunk.schema: ZodObject | null\n * // chunk.refs: { clientId: { target: 'clients', mode: 'strict' } }\n * // chunk.records: Invoice[]\n * }\n * ```\n *\n * @example\n * ```ts\n * // Per-record streaming for arbitrarily large collections.\n * for await (const chunk of company.exportStream({ granularity: 'record' })) {\n * // chunk.records is always length 1\n * await writer.write(serialize(chunk.records[0]))\n * }\n * ```\n */\n async *exportStream(opts: ExportStreamOptions = {}): AsyncIterableIterator<ExportChunk> {\n const granularity = opts.granularity ?? 'collection'\n\n // One bulk read to enumerate collections. `loadAll` filters out\n // underscore-prefixed internal collections, which is exactly what we\n // want — internal bookkeeping has no place in a plaintext export.\n const snapshot = await this.adapter.loadAll(this.name)\n const collectionNames = Object.keys(snapshot).sort()\n\n // Resolve the ledger head once if requested. The head is identical\n // across every yielded chunk (one ledger per vault) — we copy\n // it onto each chunk so consumers doing per-record streaming don't\n // have to thread state across yields, and so the chunk shape stays\n // forward-compatible with future per-partition ledgers where the\n // head genuinely will differ per chunk.\n const ledgerHead = opts.withLedgerHead\n ? await (async () => {\n const ledger = this.getLedgerOrNull()\n if (!ledger) return undefined\n const head = await ledger.head()\n return head\n ? { hash: head.hash, index: head.entry.index, ts: head.entry.ts }\n : undefined\n })()\n : undefined\n\n // Capture ALL dictionary snapshots upfront before the first yield.\n // Building all snapshots eagerly before yielding anything ensures that\n // concurrent mutations during streaming do not affect the snapshot — any\n // dictionary.put() that happens after the first yield sees the pre-yield\n // state here. Keyed by collection name.\n const dictSnapshotCache = new Map<\n string, // collection name\n Record<string, Record<string, Record<string, string>>> // field → key → locale → label\n >()\n for (const collectionName of collectionNames) {\n const dictFields = this.dictKeyFieldRegistry.get(collectionName)\n if (dictFields && Object.keys(dictFields).length > 0) {\n const snap: Record<string, Record<string, Record<string, string>>> = {}\n for (const [fieldName, dictName] of Object.entries(dictFields)) {\n const entries = await this.dictionary(dictName).list()\n const keyMap: Record<string, Record<string, string>> = {}\n for (const entry of entries) {\n keyMap[entry.key] = entry.labels\n }\n snap[fieldName] = keyMap\n }\n dictSnapshotCache.set(collectionName, snap)\n }\n }\n\n for (const collectionName of collectionNames) {\n // ACL gate. The same `hasAccess` check that `Collection.list()`\n // honors — silent skip, no error, matches the \"operator can read\n // some but not all\" pattern.\n if (!hasAccess(this.keyring, collectionName)) continue\n\n const coll = this.collection(collectionName)\n const schema = coll.getSchema() ?? null\n const refs = this.refRegistry.getOutbound(collectionName)\n const ids = Object.keys(snapshot[collectionName] ?? {})\n\n const dictionaries = dictSnapshotCache.get(collectionName)\n\n if (granularity === 'collection') {\n // Decrypt every record in the collection, then yield once.\n // Using `coll.get(id)` rather than the loadAll envelope directly\n // because `get()` is the canonical decrypt+schema-validate path\n // and any future cache/index plumbing rides through it.\n const records: unknown[] = []\n for (const id of ids) {\n const record = await coll.get(id)\n if (record !== null) records.push(record)\n }\n const chunk: ExportChunk = {\n collection: collectionName,\n schema,\n refs,\n records,\n ...(dictionaries !== undefined ? { dictionaries } : {}),\n ...(ledgerHead ? { ledgerHead } : {}),\n }\n yield chunk\n } else {\n // Per-record yield. Memory profile: O(1 record) at a time.\n // The schema/refs metadata is repeated on every chunk so\n // consumers don't have to thread state across yields.\n for (const id of ids) {\n const record = await coll.get(id)\n if (record === null) continue\n const chunk: ExportChunk = {\n collection: collectionName,\n schema,\n refs,\n records: [record],\n ...(dictionaries !== undefined ? { dictionaries } : {}),\n ...(ledgerHead ? { ledgerHead } : {}),\n }\n yield chunk\n }\n }\n }\n }\n\n /**\n * Convenience wrapper that consumes `exportStream()` and serializes the\n * result to a single JSON string.\n *\n * ⚠ **`exportJSON()` decrypts your records and produces plaintext.**\n *\n * noy-db's threat model assumes that records on disk are encrypted.\n * This function deliberately violates that assumption: it produces a\n * JSON string in plaintext, which the consumer is then responsible for\n * protecting (filesystem permissions, full-disk encryption, secure\n * transfer, secure deletion).\n *\n * Use this function only when:\n * - You are the authorized owner of the data, **and**\n * - You have a legitimate downstream tool that requires plaintext\n * JSON, **and**\n * - You have a documented plan for how the resulting plaintext will be\n * protected and eventually destroyed.\n *\n * If your goal is encrypted backup or transport between noy-db\n * instances, use `dump()` instead — it produces a tamper-evident\n * encrypted envelope, never plaintext.\n *\n * ## Why `Promise<string>` instead of writing to a file path\n *\n * Core has zero `node:` imports — it runs unchanged in browsers, Node,\n * Bun, Deno, and edge runtimes. Accepting a file path would force a\n * `node:fs` import (breaks browsers) or a runtime dynamic import\n * (doesn't tree-shake, inflates bundles). Returning a string lets the\n * consumer choose any sink and forces the destination decision to be\n * explicit at the call site — which is also better for the security\n * warning.\n *\n * @example\n * ```ts\n * // Node: write to a file\n * import { writeFile } from 'node:fs/promises'\n * await writeFile('./backup.json', await company.exportJSON())\n * ```\n *\n * @example\n * ```ts\n * // Browser: download as a file\n * const json = await company.exportJSON()\n * const blob = new Blob([json], { type: 'application/json' })\n * const url = URL.createObjectURL(blob)\n * // ... attach to an <a download> and click\n * ```\n *\n * @example\n * ```ts\n * // Stream upload to a server\n * await fetch('/upload', {\n * method: 'POST',\n * body: await company.exportJSON(),\n * })\n * ```\n *\n * ## On-disk shape\n *\n * ```json\n * {\n * \"_noydb_export\": 1,\n * \"_compartment\": \"acme\",\n * \"_exported_at\": \"2026-04-07T12:00:00.000Z\",\n * \"_exported_by\": \"alice@acme.example\",\n * \"collections\": {\n * \"invoices\": {\n * \"schema\": null,\n * \"refs\": { \"clientId\": { \"target\": \"clients\", \"mode\": \"strict\" } },\n * \"records\": [ ... ]\n * }\n * },\n * \"ledgerHead\": { \"hash\": \"...\", \"index\": 42, \"ts\": \"...\" }\n * }\n * ```\n *\n * `schema` is included for forward compatibility but is currently\n * always `null` because Standard Schema validators are not JSON-\n * serializable. Format-package serializers that need the schema\n * should use `exportStream()` directly and read `chunk.schema` (which\n * is the live validator object, not a serialization of it).\n */\n async exportJSON(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 this.exportStream({\n granularity: 'collection',\n withLedgerHead: opts.withLedgerHead === true,\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: this.name,\n _exported_at: new Date().toISOString(),\n _exported_by: this.keyring.userId,\n collections,\n ...(hasDictionaries ? { _dictionaries: allDictionaries } : {}),\n ...(ledgerHead ? { ledgerHead } : {}),\n })\n }\n}\n\n// ─── Elevation handle ────────────────────────────────────\n\n/**\n * Reserved collection that holds the audit ledger of elevation\n * sessions. One envelope per `vault.elevate(...)` call.\n */\nexport const ELEVATION_AUDIT_COLLECTION = '_elevation_audit'\n\n/**\n * Scoped handle returned by `vault.elevate(...)`. Writes through this\n * handle land at the elevated tier with `authorization: 'elevation'`\n * stamped on the audit event; reads stay on the original `Vault`.\n *\n * The handle lazily checks its TTL on every operation, so a\n * forgotten `release()` cannot keep elevated writes alive past\n * `expiresAt` — the next call simply throws\n * {@link ElevationExpiredError}.\n *\n * Naming note: the issue's spec text used `elevated.session`\n * for this field; we name the field `handle` to avoid conflicting\n * with the codebase's existing `SessionToken` value type. The\n * semantics are unchanged.\n */\nexport class ElevatedHandle {\n /** Target tier this handle writes at. */\n readonly tier: number\n /** Audit string stamped on every cross-tier event. */\n readonly reason: string\n /** Absolute expiration in ms (Date.now()). */\n readonly expiresAt: number\n private released = false\n private readonly vault: Vault\n private readonly onRelease: () => void\n\n constructor(opts: {\n vault: Vault\n tier: number\n reason: string\n expiresAt: number\n onRelease: () => void\n }) {\n this.vault = opts.vault\n this.tier = opts.tier\n this.reason = opts.reason\n this.expiresAt = opts.expiresAt\n this.onRelease = opts.onRelease\n }\n\n /**\n * Scoped collection accessor. Returns a thin wrapper exposing the\n * single elevated operation (`put`). Reads, deletes, queries —\n * everything else — should go through the original `vault`'s\n * `collection(...)`, which keeps \"writes elevated, reads\n * unprivileged\" trivially true.\n */\n collection<T>(name: string): { put(id: string, record: T): Promise<void> } {\n // Don't gate the wrapper itself — just the operation. Adopters\n // commonly cache `const docs = elev.collection('docs')` and the\n // lazy-check still works correctly because assertActive runs at\n // every `put` call, against a fresh `Date.now()`.\n return {\n put: async (id: string, record: T): Promise<void> => {\n this.assertActive()\n await this.vault._elevatedPut<T>(name, id, record, this.tier, this.reason)\n },\n }\n }\n\n /**\n * Manually revert the elevation. Idempotent — calling twice (or\n * after the TTL expired) is a safe no-op. The vault's\n * active-elevation slot is cleared so a subsequent\n * `vault.elevate(...)` succeeds without throwing\n * {@link AlreadyElevatedError}.\n */\n async release(): Promise<void> {\n if (this.released) return\n this.released = true\n this.onRelease()\n }\n\n private assertActive(): void {\n if (this.released) {\n throw new ElevationExpiredError({ tier: this.tier, expiresAt: this.expiresAt })\n }\n if (Date.now() > this.expiresAt) {\n // Auto-release on first use past TTL so the vault's active\n // slot frees up without requiring the caller to think about\n // explicit release on expiry.\n this.released = true\n this.onRelease()\n throw new ElevationExpiredError({ tier: this.tier, expiresAt: this.expiresAt })\n }\n }\n}\n","import type { NoydbEventMap } from './types.js'\n\ntype EventHandler<T> = (data: T) => void\n\n/** Typed event emitter for NOYDB events. */\nexport class NoydbEventEmitter {\n private readonly listeners = new Map<string, Set<EventHandler<unknown>>>()\n\n on<K extends keyof NoydbEventMap>(\n event: K,\n handler: EventHandler<NoydbEventMap[K]>,\n ): void {\n let set = this.listeners.get(event as string)\n if (!set) {\n set = new Set()\n this.listeners.set(event as string, set)\n }\n set.add(handler as EventHandler<unknown>)\n }\n\n off<K extends keyof NoydbEventMap>(\n event: K,\n handler: EventHandler<NoydbEventMap[K]>,\n ): void {\n this.listeners.get(event as string)?.delete(handler as EventHandler<unknown>)\n }\n\n emit<K extends keyof NoydbEventMap>(event: K, data: NoydbEventMap[K]): void {\n const set = this.listeners.get(event as string)\n if (set) {\n for (const handler of set) {\n handler(data)\n }\n }\n }\n\n removeAllListeners(): void {\n this.listeners.clear()\n }\n}\n","/**\n * Observable write-queue.\n *\n * Tracks outstanding in-flight *logical* writes (a full Collection.put /\n * delete, including ledger + cache + derivation + MV dispatch — not just\n * the adapter call). The hub holds one tracker per instance; it is\n * framework-agnostic (no Vue/React dependency). UI layers subscribe via\n * onChange(); the migration drain (Slice 2) quiesces via onFlush().\n */\n\n/** Public, read-only view of the hub's write-queue. */\nexport interface WriteQueue {\n /** True while one or more writes are in flight (`depth > 0`). */\n readonly pending: boolean\n /** Count of outstanding write operations. */\n readonly depth: number\n /**\n * Subscribe to depth changes (fires on every begin and settle).\n * Returns an unsubscribe function. Intended for reactive wrappers\n * (e.g. `@noy-db/in-vue` turns this into a `ref`).\n */\n onChange(handler: () => void): () => void\n /**\n * Resolves once `depth` reaches 0. If a write settled with an error\n * while this flush was waiting, the returned promise REJECTS with that\n * error instead — so a drain caller surfaces the failure rather than\n * hanging. Resolves immediately when already idle and error-free.\n */\n onFlush(): Promise<void>\n}\n\ninterface FlushWaiter {\n resolve: () => void\n reject: (error: Error) => void\n}\n\nexport class WriteQueueTracker implements WriteQueue {\n #depth = 0\n #error: Error | null = null\n readonly #changeHandlers = new Set<() => void>()\n #flushWaiters: FlushWaiter[] = []\n\n get pending(): boolean {\n return this.#depth > 0\n }\n\n get depth(): number {\n return this.#depth\n }\n\n /** Mark one write as started. */\n begin(): void {\n this.#depth++\n this.#emitChange()\n }\n\n /** Mark one write as finished. Pass the error if it failed. */\n settle(error?: Error): void {\n this.#depth = Math.max(0, this.#depth - 1)\n if (error) this.#error = error\n this.#emitChange()\n if (this.#depth === 0) this.#drainFlush()\n }\n\n onChange(handler: () => void): () => void {\n this.#changeHandlers.add(handler)\n return () => {\n this.#changeHandlers.delete(handler)\n }\n }\n\n onFlush(): Promise<void> {\n if (this.#depth === 0) {\n const error = this.#error\n this.#error = null\n return error ? Promise.reject(error) : Promise.resolve()\n }\n return new Promise<void>((resolve, reject) => {\n this.#flushWaiters.push({ resolve, reject })\n })\n }\n\n /**\n * Run `fn` as a tracked write: depth++ on entry, depth-- on settle\n * (success or failure). The fn's resolved value is returned; a thrown\n * error is re-thrown after the queue is decremented.\n */\n async track<R>(fn: () => Promise<R>): Promise<R> {\n this.begin()\n try {\n const value = await fn()\n this.settle()\n return value\n } catch (error) {\n this.settle(error as Error)\n throw error\n }\n }\n\n #emitChange(): void {\n for (const handler of this.#changeHandlers) handler()\n }\n\n #drainFlush(): void {\n const waiters = this.#flushWaiters\n this.#flushWaiters = []\n const error = this.#error\n this.#error = null\n for (const waiter of waiters) {\n if (error) waiter.reject(error)\n else waiter.resolve()\n }\n }\n}\n","/**\n * Hub-level write lifecycle hooks. `onBeforeWrite` may abort (throw);\n * `onAfterWrite` is awaited and its errors are warned, not thrown. A\n * re-entrancy flag suppresses nested firing so a handler that writes can't\n * loop. Held on the Noydb instance, threaded into every Collection.\n */\nexport interface WriteEvent {\n readonly op: 'create' | 'update' | 'delete'\n readonly vault: string\n readonly collection: string\n readonly docId: string\n readonly before: unknown // decrypted prior record; null on 'create'\n readonly after: unknown // the record written; null on 'delete'\n readonly baseVersion: number // version the writer started from (0 on create)\n readonly version: number // version the writer wrote (baseVersion + 1)\n readonly userId: string\n readonly timestamp: number\n readonly txId: string\n}\n\nexport type WriteHook = (event: WriteEvent) => void | Promise<void>\nexport type Unsubscribe = () => void\n\nexport class WriteHookRegistry {\n readonly #before: WriteHook[] = []\n readonly #after: WriteHook[] = []\n #suppressed = false\n\n /** True while handlers are running — used by the write path to skip nested firing. */\n get suppressed(): boolean { return this.#suppressed }\n\n /** True when any hook is registered (cheap gate for the write path). */\n get hasHandlers(): boolean { return this.#before.length > 0 || this.#after.length > 0 }\n\n onBeforeWrite(handler: WriteHook): Unsubscribe {\n this.#before.push(handler)\n return () => { const i = this.#before.indexOf(handler); if (i >= 0) this.#before.splice(i, 1) }\n }\n\n onAfterWrite(handler: WriteHook): Unsubscribe {\n this.#after.push(handler)\n return () => { const i = this.#after.indexOf(handler); if (i >= 0) this.#after.splice(i, 1) }\n }\n\n /** Run before-hooks (awaited, in order). A throw propagates and aborts the write. */\n async runBefore(event: WriteEvent): Promise<void> {\n if (this.#before.length === 0) return\n this.#suppressed = true\n try {\n for (const h of this.#before.slice()) await h(event)\n } finally {\n this.#suppressed = false\n }\n }\n\n /** Run after-hooks (awaited, in order). Per-handler errors are warned, not thrown. */\n async runAfter(event: WriteEvent): Promise<void> {\n if (this.#after.length === 0) return\n this.#suppressed = true\n try {\n for (const h of this.#after.slice()) {\n try {\n await h(event)\n } catch (err) {\n console.warn(\n `[noy-db] onAfterWrite handler failed for ${event.collection}/${event.docId}: ` +\n (err instanceof Error ? err.message : String(err)),\n )\n }\n }\n } finally {\n this.#suppressed = false\n }\n }\n}\n","/**\n * Generic per-instance **observe** bus. Observe-class\n * subsystems (devtools inspector, audit, sync-dirty notification) register\n * handlers against named lifecycle points instead of the kernel naming each\n * subsystem. Mirrors the registry pattern of {@link WriteHookRegistry} but is\n * internal and keyed by lifecycle point.\n *\n * OBSERVE SEMANTICS: handlers react to a write that already happened. A\n * handler throw is warned, not propagated — it can never abort a write. Write-\n * *gating* subsystems (guards, periods) need a throw-propagating gate bus.\n * Add observe points by extending {@link LifecycleEventMap}. Write-*gating*\n * subsystems use the sibling gate API on this same class\n * (`registerGate`/`dispatchGate`, throw-propagating); see {@link GateEventMap}.\n *\n * @module\n */\nimport type { WriteEvent } from './write-hooks.js'\nimport type { Role } from './types.js'\n\n/** Typed map of OBSERVE lifecycle point → event payload. Extend by adding keys. */\nexport interface LifecycleEventMap {\n afterPut: WriteEvent\n afterDelete: WriteEvent\n}\n\nexport type LifecyclePoint = keyof LifecycleEventMap\nexport type BusHandler<P extends LifecyclePoint> = (event: LifecycleEventMap[P]) => void | Promise<void>\nexport type Unsubscribe = () => void\n\ntype AnyHandler = (event: unknown) => void | Promise<void>\n\n/** Payload for a `beforePut` gate — carries the data guards and periods need to validate or reject a write. */\nexport interface GatePutEvent {\n readonly op: 'create' | 'update'\n readonly vault: string\n readonly collection: string\n readonly docId: string\n /**\n * The record about to be written (pre schema-validation). Money fields\n * are presented in their canonical decoded form (#332) — equal on both\n * sides for an unchanged value, regardless of how the caller wrote them.\n */\n readonly incoming: unknown\n /**\n * Decrypted prior record, or null on create / when prior is unreadable.\n * Money fields are decoded to the canonical decimal `get()` shape, NOT\n * the stored scaled-int (#332) — `incoming[f] === existing[f]` holds\n * for an unchanged money field.\n */\n readonly existing: unknown\n /** Prior envelope version, or 0 when none. */\n readonly existingVersion: number\n /** Prior envelope timestamp (`_ts` ISO string), or undefined when none — periods compares against this. */\n readonly existingTs: string | undefined\n readonly userId: string\n readonly role: Role\n /**\n * Names of fields whose values are schema-owned computed fields for this\n * collection. Gate handlers (e.g. `frozenFields`) must skip these: the\n * incoming record is the raw user input (computed fields not yet evaluated),\n * so comparing `existing[computedField]` vs `incoming[computedField]`\n * would always see a change even when the computed result is unchanged.\n */\n readonly computedFieldNames?: ReadonlySet<string>\n}\n\n/** Payload for a `beforeDelete` gate. Like {@link GatePutEvent} without `incoming`. */\nexport interface GateDeleteEvent {\n readonly vault: string\n readonly collection: string\n readonly docId: string\n /** True for system-internal (housekeeping) deletes — handlers branch on this. */\n readonly internal: boolean\n /** Decrypted prior record; money fields decoded to the canonical `get()` shape (#332). */\n readonly existing: unknown\n readonly existingVersion: number\n readonly existingTs: string | undefined\n readonly userId: string\n readonly role: Role\n}\n\n/** Typed map of GATE lifecycle point → event payload. Extend by adding keys. */\nexport interface GateEventMap {\n beforePut: GatePutEvent\n beforeDelete: GateDeleteEvent\n}\n\nexport type GatePoint = keyof GateEventMap\nexport type GateHandler<P extends GatePoint> = (event: GateEventMap[P]) => void | Promise<void>\n\nexport class SubsystemBus {\n readonly #handlers = new Map<LifecyclePoint, AnyHandler[]>()\n readonly #gateHandlers = new Map<GatePoint, AnyHandler[]>()\n #depth = 0\n\n /** Register a handler for an observe point. Returns an unsubscribe fn. */\n register<P extends LifecyclePoint>(point: P, handler: BusHandler<P>): Unsubscribe {\n let arr = this.#handlers.get(point)\n if (!arr) { arr = []; this.#handlers.set(point, arr) }\n arr.push(handler as AnyHandler)\n return () => {\n const a = this.#handlers.get(point)\n if (!a) return\n const i = a.indexOf(handler as AnyHandler)\n if (i >= 0) a.splice(i, 1)\n }\n }\n\n /** Cheap gate for the write path — true when any handler is registered for the point. */\n hasHandlers(point: LifecyclePoint): boolean {\n const a = this.#handlers.get(point)\n return a !== undefined && a.length > 0\n }\n\n /**\n * True while one or more dispatches are in flight. Backed by a depth counter\n * so that two concurrent async dispatches (`Promise.all([put('a'), put('b')])`\n * each captured `busAfterPut=true` at their respective put() tops while depth\n * was 0) both proceed independently — the counter stays > 0 until BOTH finish,\n * so any nested write attempted by a handler still sees `dispatching === true`\n * and is suppressed by the write-path gate in `collection.ts`\n * (`busAfterPut = hasHandlers('afterPut') && !dispatching`). Re-entrancy\n * suppression lives exclusively on that write-path gate; concurrent independent\n * dispatches must not drop each other's events.\n */\n get dispatching(): boolean { return this.#depth > 0 }\n\n /**\n * Dispatch in registration order, awaited. Per-handler errors are warned, not\n * thrown — an observe handler must never abort a completed write. A\n * re-entrancy guard suppresses nested firing so a handler that itself writes\n * cannot loop (same rationale as WriteHookRegistry.#suppressed).\n */\n async dispatch<P extends LifecyclePoint>(point: P, event: LifecycleEventMap[P]): Promise<void> {\n const a = this.#handlers.get(point)\n if (!a || a.length === 0) return\n this.#depth++\n try {\n for (const h of a.slice()) {\n try {\n await h(event)\n } catch (err) {\n console.warn(\n `[noy-db] subsystem observe handler failed at ${point}: ` +\n (err instanceof Error ? err.message : String(err)),\n )\n }\n }\n } finally {\n this.#depth--\n }\n }\n\n /** Register a write-gating handler. A throw from the handler ABORTS the write. Returns an unsubscribe fn. */\n registerGate<P extends GatePoint>(point: P, handler: GateHandler<P>): Unsubscribe {\n let arr = this.#gateHandlers.get(point)\n if (!arr) { arr = []; this.#gateHandlers.set(point, arr) }\n arr.push(handler as AnyHandler)\n return () => {\n const a = this.#gateHandlers.get(point)\n if (!a) return\n const i = a.indexOf(handler as AnyHandler)\n if (i >= 0) a.splice(i, 1)\n }\n }\n\n /** Cheap gate for the write path — true when any gate handler is registered for the point. */\n hasGateHandlers(point: GatePoint): boolean {\n const a = this.#gateHandlers.get(point)\n return a !== undefined && a.length > 0\n }\n\n /**\n * Run gate handlers in registration order, awaited. Unlike `dispatch`\n * (observe), a handler throw is NOT swallowed — it PROPAGATES, aborting the\n * write before it reaches the store. The first throw stops the remaining\n * handlers (fail-fast). This is the seam guards/periods migrate onto.\n *\n * Note: gate handlers are validators that read, not write. A gate handler\n * that writes back into the same collection would re-enter the write path\n * and re-dispatch this point; loop-suppression for that case is deferred to\n * the migration slice (contract: gate handlers must not perform writes that\n * re-trigger their own point).\n */\n async dispatchGate<P extends GatePoint>(point: P, event: GateEventMap[P]): Promise<void> {\n const a = this.#gateHandlers.get(point)\n if (!a || a.length === 0) return\n for (const h of a.slice()) {\n await h(event) // throw propagates → aborts the write\n }\n }\n}\n","/**\n * Multi-tab coordination: primary/secondary election (Web Locks)\n * + presence heartbeat (BroadcastChannel). Browser-only; opt-in; no-op\n * when the APIs are absent. The lock/channel interfaces are hub-local\n * (structurally compatible with @noy-db/by-peer + @noy-db/by-tabs, but\n * not imported — those packages depend on hub).\n */\nexport type TabRole = 'primary' | 'secondary' | 'unknown'\nexport interface TabPresence { readonly tabId: string; readonly lastSeen: number; readonly role: TabRole }\nexport type Unsubscribe = () => void\n\n/** Structural subset of the Web Locks API / by-peer's MinimalLockManager. */\nexport interface TabLockManager {\n request<T>(name: string, options: { mode?: 'exclusive' | 'shared'; signal?: AbortSignal }, callback: (lock: unknown) => Promise<T>): Promise<T>\n}\n\n/** Structural subset of by-peer's PeerChannel / a BroadcastChannel wrapper. */\nexport interface TabChannel {\n send(payload: string): void\n on(event: 'message', listener: (payload: string) => void): Unsubscribe\n on(event: 'close', listener: () => void): Unsubscribe\n close(): void\n readonly isOpen: boolean\n}\n\nexport interface TabCoordinationOptions {\n readonly lockManager?: TabLockManager\n readonly channel?: TabChannel\n readonly tabId?: string\n readonly lockName?: string\n readonly heartbeatMs?: number\n readonly staleMs?: number\n readonly now?: () => number\n /**\n * Close the channel on `dispose()`. Set this only for a channel the\n * coordinator owns (e.g. the one `defaultChannel()` created); leave it\n * false for a caller-injected channel so the coordinator never closes a\n * channel it didn't create. Default: false.\n */\n readonly closeChannelOnDispose?: boolean\n /**\n * Also propagate committed writes to other tabs. Default true:\n * when tab coordination is enabled and a channel is available, a write in\n * one tab refreshes that document in every other tab. Set false to opt out.\n */\n readonly propagateWrites?: boolean\n /**\n * Channel for write propagation — distinct from the presence\n * channel. Default: an inline BroadcastChannel on `noydb:tab-writes`.\n */\n readonly writeChannel?: TabChannel\n}\n\ninterface PresenceMsg { readonly kind: 'tab-presence'; readonly tabId: string; readonly lastSeen: number; readonly role: TabRole }\n\nexport class TabCoordinator {\n readonly tabId: string\n role: TabRole = 'unknown'\n readonly #lockManager: TabLockManager | undefined\n readonly #channel: TabChannel | undefined\n readonly #lockName: string\n readonly #heartbeatMs: number\n readonly #staleMs: number\n readonly #now: () => number\n readonly #peers = new Map<string, TabPresence>()\n readonly #roleHandlers = new Set<(r: TabRole) => void>()\n readonly #tabsHandlers = new Set<(t: TabPresence[]) => void>()\n #ac: AbortController | undefined\n #releaseLock: (() => void) | undefined\n #unsub: Unsubscribe | undefined\n #closeUnsub: Unsubscribe | undefined\n #timer: ReturnType<typeof setInterval> | undefined\n readonly #ownsChannel: boolean\n #started = false\n #disposed = false\n #lastTabsSig = ''\n\n constructor(opts: TabCoordinationOptions = {}) {\n this.tabId = opts.tabId ?? `tab-${Math.trunc((opts.now ?? (() => 0))())}-${cheapRand()}`\n this.#lockManager = opts.lockManager\n this.#channel = opts.channel\n this.#lockName = opts.lockName ?? 'noydb:tab-primary'\n this.#heartbeatMs = opts.heartbeatMs ?? 2_000\n this.#staleMs = opts.staleMs ?? 6_000\n this.#now = opts.now ?? (() => Date.now())\n this.#ownsChannel = opts.closeChannelOnDispose ?? false\n }\n\n start(): void {\n if (this.#disposed || this.#started) return\n this.#started = true\n if (this.#channel) {\n this.#unsub = this.#channel.on('message', (p) => this.#onMessage(p))\n this.#closeUnsub = this.#channel.on('close', () => this.#onChannelClose())\n this.#beat()\n this.#timer = setInterval(() => this.#tick(), this.#heartbeatMs)\n const t = this.#timer as unknown as { unref?: () => void }\n if (typeof t.unref === 'function') t.unref()\n }\n if (this.#lockManager) {\n this.#ac = new AbortController()\n this.#setRole('secondary')\n void this.#lockManager\n .request(this.#lockName, { mode: 'exclusive', signal: this.#ac.signal }, () => {\n this.#setRole('primary')\n return new Promise<void>((resolve) => { this.#releaseLock = resolve })\n })\n .catch(() => { /* aborted on dispose */ })\n }\n }\n\n activeTabs(): TabPresence[] {\n if (!this.#channel) return []\n const cutoff = this.#now() - this.#staleMs\n const self: TabPresence = { tabId: this.tabId, lastSeen: this.#now(), role: this.role }\n const out = [self, ...[...this.#peers.values()].filter((p) => p.lastSeen >= cutoff)]\n return out.sort((a, b) => a.tabId.localeCompare(b.tabId))\n }\n\n onTabRoleChange(fn: (r: TabRole) => void): Unsubscribe { this.#roleHandlers.add(fn); return () => this.#roleHandlers.delete(fn) }\n onActiveTabsChange(fn: (t: TabPresence[]) => void): Unsubscribe { this.#tabsHandlers.add(fn); return () => this.#tabsHandlers.delete(fn) }\n\n dispose(): void {\n if (this.#disposed) return\n this.#disposed = true\n this.#releaseLock?.()\n this.#ac?.abort()\n if (this.#timer) { clearInterval(this.#timer); this.#timer = undefined }\n this.#unsub?.()\n this.#closeUnsub?.()\n if (this.#ownsChannel) this.#channel?.close()\n this.#setRole('unknown')\n }\n\n /** @internal test seam — broadcast one heartbeat now. */\n _beat(): void { this.#beat() }\n\n #tick(): void {\n this.#prune()\n this.#emitTabs()\n this.#beat()\n }\n\n #beat(): void {\n if (this.#disposed) return\n if (!this.#channel || !this.#channel.isOpen) return\n const msg: PresenceMsg = { kind: 'tab-presence', tabId: this.tabId, lastSeen: this.#now(), role: this.role }\n this.#channel.send(JSON.stringify(msg))\n }\n\n #onChannelClose(): void {\n if (this.#timer) { clearInterval(this.#timer); this.#timer = undefined }\n this.#setRole('unknown')\n }\n\n #onMessage(payload: string): void {\n let msg: unknown\n try { msg = JSON.parse(payload) } catch { return }\n if (!isPresenceMsg(msg) || msg.tabId === this.tabId) return\n this.#peers.set(msg.tabId, { tabId: msg.tabId, lastSeen: msg.lastSeen, role: msg.role })\n this.#prune()\n this.#emitTabs()\n }\n\n #prune(): void {\n const cutoff = this.#now() - this.#staleMs\n for (const [id, p] of this.#peers) if (p.lastSeen < cutoff) this.#peers.delete(id)\n }\n\n #setRole(role: TabRole): void {\n if (this.role === role) return\n this.role = role\n for (const h of this.#roleHandlers) h(role)\n this.#beat() // announce promptly\n this.#emitTabs()\n }\n\n #emitTabs(): void {\n const tabs = this.activeTabs()\n const sig = tabs.map((t) => `${t.tabId}:${t.role}`).join('|')\n if (sig === this.#lastTabsSig) return\n this.#lastTabsSig = sig\n for (const h of this.#tabsHandlers) h(tabs)\n }\n}\n\nfunction isPresenceMsg(x: unknown): x is PresenceMsg {\n if (x === null || typeof x !== 'object') return false\n const o = x as Record<string, unknown>\n return o['kind'] === 'tab-presence'\n && typeof o['tabId'] === 'string'\n && typeof o['lastSeen'] === 'number'\n && (o['role'] === 'primary' || o['role'] === 'secondary' || o['role'] === 'unknown')\n}\n\nfunction cheapRand(): string {\n // Non-crypto, non-Date id suffix for a default tabId; callers pass a stable tabId in tests.\n const g = globalThis as { crypto?: { randomUUID?: () => string } }\n return g.crypto?.randomUUID ? g.crypto.randomUUID().slice(0, 8) : 'anon'\n}\n\n/** Browser default lock manager (navigator.locks) or undefined. */\nexport function defaultLockManager(): TabLockManager | undefined {\n const nav = (globalThis as { navigator?: { locks?: TabLockManager } }).navigator\n return nav?.locks\n}\n\n/** Browser default channel: an inline BroadcastChannel wrapper, or undefined. */\nexport function defaultChannel(name = 'noydb:tabs'): TabChannel | undefined {\n // Gate on `window` — a real browser signal. Modern Node exposes a global\n // BroadcastChannel (worker_threads), so presence of the constructor alone is\n // NOT a browser signal; without this gate we'd start a heartbeat in Node.\n // Symmetric with defaultLockManager()'s navigator gate.\n if (typeof (globalThis as { window?: unknown }).window === 'undefined') return undefined\n const Bc = (globalThis as { BroadcastChannel?: typeof BroadcastChannel }).BroadcastChannel\n if (!Bc) return undefined\n const bc = new Bc(name)\n const msgListeners = new Set<(p: string) => void>()\n bc.onmessage = (e: MessageEvent) => { for (const l of msgListeners) l(String(e.data)) }\n return {\n isOpen: true,\n send(payload) { bc.postMessage(payload) },\n on(event, listener) {\n if (event === 'message') { const l = listener as (p: string) => void; msgListeners.add(l); return () => msgListeners.delete(l) }\n return () => {}\n },\n close() { msgListeners.clear(); bc.close() },\n }\n}\n","/**\n * Cross-tab write propagation. A role-agnostic relay: it broadcasts\n * a ciphertext-blind signal ({vault, collection, docId, action}) for every\n * locally-committed write (via onAfterWrite), and on receiving a peer\n * tab's signal it asks the host to refresh that document's in-memory view by\n * re-reading the shared encrypted store. Nothing decrypted crosses the wire.\n */\nimport type { TabChannel, Unsubscribe } from './tab-coordination.js'\nimport type { WriteEvent } from './write-hooks.js'\n\nexport interface TabWriteMsg {\n readonly kind: 'tab-write'\n readonly writerId: string\n readonly vault: string\n readonly collection: string\n readonly docId: string\n readonly action: 'put' | 'delete'\n readonly baseV: number\n readonly v: number\n}\n\nexport interface CrossTabWriteRelayOptions {\n /** The broadcast channel (its own — distinct from the presence channel). */\n readonly channel: TabChannel\n /** This tab's id — outgoing signals carry it; incoming self-signals are ignored. */\n readonly writerId: string\n /** Subscribe to committed writes (the host's onAfterWrite). */\n readonly subscribeAfterWrite: (handler: (e: WriteEvent) => void) => Unsubscribe\n /** Refresh a document's in-memory view from the shared store. */\n readonly applyRemoteWrite: (vault: string, collection: string, docId: string, action: 'put' | 'delete') => void | Promise<void>\n /** Report a detected conflict (host captures + converges + emits). */\n readonly reportConflict?: (vault: string, collection: string, docId: string, action: 'put' | 'delete', baseV: number, v: number, ownV: number) => void | Promise<void>\n /** Close the channel on dispose (only when the relay created it). Default false. */\n readonly closeChannelOnDispose?: boolean\n}\n\nexport class CrossTabWriteRelay {\n readonly #channel: TabChannel\n readonly #writerId: string\n readonly #subscribeAfterWrite: (handler: (e: WriteEvent) => void) => Unsubscribe\n readonly #applyRemoteWrite: (vault: string, collection: string, docId: string, action: 'put' | 'delete') => void | Promise<void>\n readonly #reportConflict: CrossTabWriteRelayOptions['reportConflict']\n readonly #ledger = new Map<string, number>()\n readonly #ownsChannel: boolean\n #unsubMsg: Unsubscribe | undefined\n #unsubWrite: Unsubscribe | undefined\n #started = false\n #disposed = false\n\n constructor(opts: CrossTabWriteRelayOptions) {\n this.#channel = opts.channel\n this.#writerId = opts.writerId\n this.#subscribeAfterWrite = opts.subscribeAfterWrite\n this.#applyRemoteWrite = opts.applyRemoteWrite\n this.#reportConflict = opts.reportConflict\n this.#ownsChannel = opts.closeChannelOnDispose ?? false\n }\n\n start(): void {\n if (this.#started || this.#disposed) return\n this.#started = true\n this.#unsubMsg = this.#channel.on('message', (p) => this.#onMessage(p))\n this.#unsubWrite = this.#subscribeAfterWrite((e) => this.#onLocalWrite(e))\n }\n\n dispose(): void {\n if (this.#disposed) return\n this.#disposed = true\n this.#unsubWrite?.()\n this.#unsubMsg?.()\n if (this.#ownsChannel) this.#channel.close()\n }\n\n #onLocalWrite(e: WriteEvent): void {\n if (this.#disposed || !this.#channel.isOpen) return\n this.#ledger.set(ledgerKey(e.vault, e.collection, e.docId), e.version)\n const action: 'put' | 'delete' = e.op === 'delete' ? 'delete' : 'put'\n const msg: TabWriteMsg = { kind: 'tab-write', writerId: this.#writerId, vault: e.vault, collection: e.collection, docId: e.docId, action, baseV: e.baseVersion, v: e.version }\n this.#channel.send(JSON.stringify(msg))\n }\n\n #onMessage(payload: string): void {\n if (this.#disposed) return\n let msg: unknown\n try { msg = JSON.parse(payload) } catch { return }\n if (!isTabWriteMsg(msg) || msg.writerId === this.#writerId) return\n const key = ledgerKey(msg.vault, msg.collection, msg.docId)\n const ownV = this.#ledger.get(key)\n if (ownV !== undefined && msg.baseV < ownV && this.#reportConflict) {\n void Promise.resolve(this.#reportConflict(msg.vault, msg.collection, msg.docId, msg.action, msg.baseV, msg.v, ownV)).catch((err) => {\n console.warn(`[noy-db] cross-tab conflict report failed for ${msg.collection}/${msg.docId}: ` + (err instanceof Error ? err.message : String(err)))\n })\n return\n }\n if (ownV !== undefined && msg.baseV >= ownV) this.#ledger.set(key, msg.v) // remote incorporated our write → advance\n void Promise.resolve(this.#applyRemoteWrite(msg.vault, msg.collection, msg.docId, msg.action)).catch((err) => {\n console.warn(`[noy-db] cross-tab apply failed for ${msg.collection}/${msg.docId}: ` + (err instanceof Error ? err.message : String(err)))\n })\n }\n}\n\nfunction ledgerKey(vault: string, collection: string, docId: string): string {\n // NUL separator: it cannot appear in a vault/collection/docId, so keys never collide.\n return `${vault}\\0${collection}\\0${docId}`\n}\n\nfunction isTabWriteMsg(x: unknown): x is TabWriteMsg {\n if (x === null || typeof x !== 'object') return false\n const o = x as Record<string, unknown>\n return o['kind'] === 'tab-write'\n && typeof o['writerId'] === 'string'\n && typeof o['vault'] === 'string'\n && typeof o['collection'] === 'string'\n && typeof o['docId'] === 'string'\n && (o['action'] === 'put' || o['action'] === 'delete')\n && typeof o['baseV'] === 'number'\n && typeof o['v'] === 'number'\n}\n","/**\n * Per-vault tier-3 (PIN / quick-resume) state.\n *\n * The hub holds a `PinResumeState`-shaped record in memory, keyed by\n * vault. `enrollUnlock` populates it; `unlockViaPin` consumes it via\n * `@noy-db/on-pin`'s `resumePin`. The cached state is wiped when the\n * idle timer fires or `db.close()` is called.\n *\n * Importantly, this module does NOT depend on `@noy-db/on-pin` — the\n * caller passes the already-built state in. That keeps the hub's\n * `peerDependencies` empty for tier-3 and lets developers swap the\n * primitive (e.g. an OS biometric in place of a PIN).\n *\n * @module\n */\n\n/**\n * Opaque `PinResumeState`-compatible record. Mirrored from\n * `@noy-db/on-pin/PinResumeState`. The hub treats the contents as\n * a black box.\n */\nexport interface QuickUnlockState {\n readonly _noydb_on_pin: 1\n readonly salt: string\n readonly iv: string\n readonly wrappedKeyring: string\n readonly expiresAt: string\n readonly maxAttempts: number\n attempts: number\n}\n\n/** In-memory store for tier-3 unlock state, keyed by vault. */\nexport class QuickUnlockStore {\n private readonly states = new Map<string, QuickUnlockState>()\n private readonly timers = new Map<string, ReturnType<typeof setTimeout>>()\n\n /**\n * Register a quick-unlock state for a vault. Replaces any existing\n * state. Schedules an automatic clear when the state's `expiresAt`\n * elapses.\n */\n set(vault: string, state: QuickUnlockState): void {\n this.clearTimer(vault)\n this.states.set(vault, state)\n const ttl = new Date(state.expiresAt).getTime() - Date.now()\n if (ttl > 0) {\n const timer = setTimeout(() => this.delete(vault), ttl)\n this.timers.set(vault, timer)\n }\n }\n\n /** Read the state for a vault. Returns undefined when none is registered. */\n get(vault: string): QuickUnlockState | undefined {\n return this.states.get(vault)\n }\n\n /** Drop the state for a vault. Cancels the auto-clear timer. */\n delete(vault: string): void {\n this.clearTimer(vault)\n this.states.delete(vault)\n }\n\n /** Drop every cached state. Called on `db.close()`. */\n clear(): void {\n for (const vault of this.states.keys()) {\n this.clearTimer(vault)\n }\n this.states.clear()\n }\n\n private clearTimer(vault: string): void {\n const t = this.timers.get(vault)\n if (t) clearTimeout(t)\n this.timers.delete(vault)\n }\n}\n","import type { SnapshotPolicy } from './policy.js'\n\nexport interface SnapshotMeta {\n readonly version: string\n readonly label?: string\n readonly note?: string\n readonly exportedAt: string\n readonly exportedBy: string\n readonly size: number\n /**\n * `'verified'` — bundle was produced by `writeNoydbBundle(vault, {})`, which embeds\n * ledgerHead metadata; `vault.load()` runs `verifyBackupIntegrity()` on restore.\n * `'legacy-unverifiable'` — reserved for v2 import paths that read pre-existing bundles\n * lacking a ledgerHead; not produced by the current engine.\n */\n readonly integrity: 'verified' | 'legacy-unverifiable'\n /** `true` for the rolling auto-snapshot; absent on on-demand checkpoints. */\n readonly auto?: true\n}\n\nexport interface RetentionPolicy {\n readonly keepLast?: number\n readonly maxAgeDays?: number\n readonly prune?: boolean\n}\n\n/** @internal */\nexport interface SnapshotIndex {\n snapshots: SnapshotMeta[]\n nextCounter: number\n /** Single rolling auto-snapshot slot, separate from the immutable `snapshots` pool. */\n auto?: SnapshotMeta\n}\n\n/** @internal */\nexport interface SnapshotStrategy {\n snapshot(vault: unknown, by: string, opts?: { label?: string; note?: string }): Promise<SnapshotMeta>\n listSnapshots(vaultId: string): Promise<SnapshotMeta[]>\n restoreSnapshot(vault: unknown, version: string): Promise<void>\n /** Rolling auto-snapshot to the fixed `<vault>__auto` key. */\n autoSnapshot(vault: unknown, by: string, opts?: { label?: string; note?: string }): Promise<SnapshotMeta>\n /** Configured cadence policy. Undefined or `mode:'manual'` ⇒ no scheduler is wired. */\n readonly policy?: SnapshotPolicy\n}\n\nconst NOT_ENABLED = new Error(\n 'Snapshots require the snapshot strategy. Import `{ withSnapshots }` from ' +\n '\"@noy-db/hub/snapshots\" and pass it to ' +\n '`createNoydb({ snapshotStrategy: withSnapshots({ store }) })`.',\n)\n\n/** No-op stub. @internal */\nexport const NO_SNAPSHOTS: SnapshotStrategy = {\n async snapshot() { throw NOT_ENABLED },\n async listSnapshots() { throw NOT_ENABLED },\n async restoreSnapshot() { throw NOT_ENABLED },\n async autoSnapshot() { throw NOT_ENABLED },\n}\n","/**\n * Owns timers + unload hooks for the automatic snapshot cadence. Distinct from\n * the sync `SyncScheduler` (whose push/pull/dirty-count shape doesn't map to\n * snapshots) — it borrows only the policy vocabulary. Delegates the actual\n * snapshot work to `callbacks.fire()`.\n */\nimport type { SnapshotPolicy } from './policy.js'\n\nexport interface SnapshotSchedulerCallbacks {\n /** Fire one auto-snapshot cycle (per dirty vault). Swallows its own per-vault errors. */\n fire(): Promise<void>\n /** Number of vaults with pending writes since the last fire. */\n pendingCount(): number\n}\n\nexport class SnapshotScheduler {\n private readonly policy: SnapshotPolicy\n private readonly callbacks: SnapshotSchedulerCallbacks\n\n private debounceTimer: ReturnType<typeof setTimeout> | null = null\n private intervalTimer: ReturnType<typeof setInterval> | null = null\n private lastFireTime = 0\n private firing = false\n private started = false\n\n private readonly boundVisibility: (() => void) | null = null\n private readonly boundUnload: (() => void) | null = null\n\n constructor(policy: SnapshotPolicy, callbacks: SnapshotSchedulerCallbacks) {\n this.policy = policy\n this.callbacks = callbacks\n if (this.shouldRegisterUnload()) {\n this.boundVisibility = this.handleVisibility.bind(this)\n this.boundUnload = this.handleUnload.bind(this)\n }\n }\n\n start(): void {\n if (this.started) return\n this.started = true\n\n if (this.policy.mode === 'interval') {\n const ms = this.policy.intervalMs ?? 300_000\n this.intervalTimer = setInterval(() => { void this.execFire() }, ms)\n }\n\n if (this.boundVisibility && this.boundUnload) {\n if (typeof document !== 'undefined') {\n document.addEventListener('visibilitychange', this.boundVisibility)\n }\n if (typeof globalThis.addEventListener === 'function') {\n globalThis.addEventListener('pagehide', this.boundUnload)\n }\n if (typeof process !== 'undefined' && typeof process.on === 'function') {\n process.on('beforeExit', this.boundUnload)\n }\n }\n }\n\n stop(): void {\n if (!this.started) return\n this.started = false\n if (this.debounceTimer) { clearTimeout(this.debounceTimer); this.debounceTimer = null }\n if (this.intervalTimer) { clearInterval(this.intervalTimer); this.intervalTimer = null }\n\n if (this.boundVisibility && this.boundUnload) {\n if (typeof document !== 'undefined') {\n document.removeEventListener('visibilitychange', this.boundVisibility)\n }\n if (typeof globalThis.removeEventListener === 'function') {\n globalThis.removeEventListener('pagehide', this.boundUnload)\n }\n if (typeof process !== 'undefined' && typeof process.removeListener === 'function') {\n process.removeListener('beforeExit', this.boundUnload)\n }\n }\n }\n\n notifyChange(): void {\n if (!this.started) return\n if (this.policy.mode === 'debounce') this.resetDebounce()\n }\n\n private resetDebounce(): void {\n if (this.debounceTimer) clearTimeout(this.debounceTimer)\n const ms = this.policy.debounceMs ?? 30_000\n this.debounceTimer = setTimeout(() => {\n this.debounceTimer = null\n void this.execFire()\n }, ms)\n }\n\n private async execFire(): Promise<void> {\n if (this.firing) return\n\n const minInterval = this.policy.minIntervalMs ?? 0\n if (minInterval > 0 && Date.now() - this.lastFireTime < minInterval) {\n if (this.policy.mode === 'debounce') this.resetDebounce()\n return\n }\n if (this.callbacks.pendingCount() === 0) return\n\n this.firing = true\n try {\n await this.callbacks.fire()\n this.lastFireTime = Date.now()\n } catch {\n // fire() swallows per-vault errors; this guards the contract regardless.\n } finally {\n this.firing = false\n }\n }\n\n private handleVisibility(): void {\n if (typeof document !== 'undefined' && document.visibilityState === 'hidden') {\n this.flush()\n }\n }\n\n private handleUnload(): void {\n this.flush()\n }\n\n private flush(): void {\n if (this.callbacks.pendingCount() === 0) return\n void this.callbacks.fire().catch(() => {})\n }\n\n private shouldRegisterUnload(): boolean {\n return this.policy.onUnload ?? (this.policy.mode !== 'manual')\n }\n}\n","/**\n * Strategy seam for the optional multi-record transaction subsystem.\n * `runTransaction` is only reachable through `withTransactions()`\n * exported from `@noy-db/hub/tx`. Consumers who don't use\n * `db.transaction(fn)` ship none of the ~288 LOC.\n *\n * @internal\n */\n\nimport type { Noydb } from '../noydb.js'\nimport type { TxContext, AmendmentTxOptions } from './transaction.js'\nimport type { DryRunResult } from './dry-run.js'\nimport type { TransactionInvariant } from './invariants.js'\n\n/**\n * @internal\n */\nexport interface TxStrategy {\n runTransaction<T>(\n db: Noydb,\n fn: (tx: TxContext) => Promise<T> | T,\n options?: AmendmentTxOptions,\n txInvariants?: ReadonlyArray<TransactionInvariant>,\n ): Promise<T>\n runDryRun(db: Noydb, fn: (tx: TxContext) => unknown): Promise<DryRunResult>\n}\n\nconst NOT_ENABLED = new Error(\n 'Multi-record transactions require the tx strategy. Import ' +\n '`{ withTransactions }` from \"@noy-db/hub/tx\" and pass it to ' +\n '`createNoydb({ txStrategy: withTransactions() })`.',\n)\n\n/**\n * @internal\n */\nexport const NO_TX: TxStrategy = {\n async runTransaction(\n _db: Noydb,\n _fn: unknown,\n _options?: AmendmentTxOptions,\n _txInvariants?: ReadonlyArray<TransactionInvariant>,\n ): Promise<never> { throw NOT_ENABLED },\n async runDryRun() { throw NOT_ENABLED },\n}\n","/**\n * Strategy seam for the optional session-policy subsystem. Core\n * imports `SessionStrategy` type-only + `NO_SESSION` stub; real\n * `validateSessionPolicy`, `createEnforcer`, and `revokeAllSessions`\n * are only reachable via `withSession()` in `./active.ts`.\n *\n * Solo apps that never set `sessionPolicy` and never issue a session\n * token ship none of the ~495 LOC of policy + token machinery\n * (session-policy.ts + session.ts). Dev-unlock (~299 LOC) is a\n * separate import already tree-shake-friendly via direct named\n * imports.\n *\n * Behavior under NO_SESSION:\n *\n * - **validateSessionPolicy** — throws when called. Only fires if\n * `createNoydb({ sessionPolicy })` was passed; if you set a policy\n * you must opt into the strategy.\n * - **createEnforcer** — throws. Same gate.\n * - **revokeAllSessions** — silent no-op. Called unconditionally on\n * `db.close()`; without the strategy the global session registry\n * never recorded anything, so the no-op is correct.\n *\n * @internal\n */\n\nimport type { SessionPolicy } from '../types.js'\nimport type { PolicyEnforcer, PolicyEnforcerOptions } from './session-policy.js'\n\n/**\n * @internal\n */\nexport interface SessionStrategy {\n validateSessionPolicy(policy: SessionPolicy): void\n createEnforcer(opts: PolicyEnforcerOptions): PolicyEnforcer\n revokeAllSessions(): void\n}\n\nfunction notEnabled(op: string): Error {\n return new Error(\n `${op} requires the session strategy. Import ` +\n '`{ withSession }` from \"@noy-db/hub/session\" and pass it to ' +\n '`createNoydb({ sessionStrategy: withSession() })`.',\n )\n}\n\n/**\n * No-session stub. Policy validation + enforcer construction throw\n * with an actionable pointer; global session revocation is a silent\n * no-op (the registry was never populated).\n *\n * @internal\n */\nexport const NO_SESSION: SessionStrategy = {\n validateSessionPolicy() { throw notEnabled('sessionPolicy') },\n createEnforcer() { throw notEnabled('session policy enforcement') },\n revokeAllSessions() {},\n}\n","import type { VaultPolicy } from './types.js'\n\n/**\n * Default policy for personal vaults and SMB deployments — the gates\n * that need an off-device factor get one (TOTP / email-OTP / paper\n * recovery), the rest take a tier-1 unlock alone. Tier-3 (PIN) is the\n * floor only for `rotate-unlock` because that's the\n * \"change my PIN\" flow.\n *\n * The unspecified gates (e.g. `view-user-auth`) inherit the engine\n * default of `{ enabled: false, minTier: 1 }` — they fail closed.\n *\n * @see docs/subsystems/session-tiers.md → Built-in gates\n */\nexport const PERSONAL_POLICY: VaultPolicy = Object.freeze({\n passphrase: {\n minWords: 6,\n minWordLength: 3,\n rejectRepeatedAdjacent: true,\n },\n gates: {\n 'rotate-passphrase': {\n minTier: 1,\n // Any second factor satisfies the gate — off-device kinds (TOTP,\n // email-OTP, paper recovery, roaming WebAuthn) are the strongest;\n // platform-bound kinds (platform WebAuthn, password, PIN) are\n // accepted because requiring \"something off-device\" is overkill\n // for personal/SMB threat models. Consumers needing the off-device\n // guarantee should use STRICT_POLICY or override this gate.\n factors: [{\n anyOf: [\n 'totp', 'email-otp', 'recovery',\n 'webauthn-roaming', 'webauthn-platform',\n 'password', 'pin',\n ],\n }],\n },\n 'recover-passphrase': {\n minTier: 1,\n enabled: true,\n },\n // rotate-recovery: deliberate paper-sheet regeneration\n // when the user remembers their passphrase. PERSONAL allows tier-1 —\n // knowing the passphrase is enough.\n 'rotate-recovery': { minTier: 1 },\n 'enroll-authenticator': { minTier: 1 },\n 'remove-authenticator': { minTier: 1 },\n // update-authenticator: meta-only mutation (slot rename, label\n // changes). Symmetric with enroll/remove under PERSONAL — tier-1\n // unlock alone. The structural anti-slot-swap guard inside the\n // implementation enforces wrap-material/id/method immutability\n // regardless of this gate's settings.\n 'update-authenticator': { minTier: 1 },\n 'rotate-unlock': { minTier: 2 },\n 'enroll-user': { minTier: 1 },\n 'revoke-user': { minTier: 1 },\n // Peer-recovery is a high-trust intentional op — co-owners\n // recovering each other should not need an off-device factor in\n // the personal/SMB threat model (the partner is already vetted by\n // virtue of being a co-owner). Tier-1 unlock is the floor; the\n // STRICT preset adds a recovery/email-OTP requirement.\n 'peer-recover-user': { minTier: 1 },\n // update-user: post-grant identity mutation (role/displayName/\n // permissions). PERSONAL_POLICY treats this on par with enroll-user\n // / revoke-user — tier-1 unlock alone. The role-elevation guard\n // inside the implementation is the structural backstop that this\n // gate's settings cannot weaken.\n 'update-user': { minTier: 1 },\n 'export-bundle': { minTier: 1 },\n 'export-plaintext': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp'] }],\n },\n 'view-user-auth': {\n minTier: 1,\n enabled: false,\n },\n // ─── User envelope gates ──────────────────────────────────────────\n // edit-own-profile: tier 3 floor — any active session can edit their\n // own profile/preferences. Tightening to require a TOTP for\n // profile changes is a one-line override.\n // view-team-profiles: tier 2 floor — an authenticated session can\n // read teammates' profiles (display names, avatars, locales).\n // Setting `enabled: false` makes vault.user.list() return only\n // self (privacy-strict opt-out).\n 'edit-own-profile': { minTier: 3 },\n 'view-team-profiles': { minTier: 2 },\n },\n}) as VaultPolicy\n\n/**\n * Strict policy for regulated deployments and shared workstations —\n * raises the phrase floor to 8 words, demands two distinct factors for\n * exports, and blocks export-on-shared-device. Use as a base for\n * `policy: { ...STRICT_POLICY, gates: { ...STRICT_POLICY.gates, ... } }`\n * tweaks.\n */\nexport const STRICT_POLICY: VaultPolicy = Object.freeze({\n passphrase: {\n minWords: 8,\n minWordLength: 3,\n rejectRepeatedAdjacent: true,\n },\n gates: {\n 'rotate-passphrase': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp', 'recovery'], count: 2 }],\n },\n 'recover-passphrase': {\n minTier: 1,\n enabled: true,\n },\n // rotate-recovery: STRICT requires an off-device factor —\n // rotating recovery is an off-site-trust event; a stolen unlocked\n // laptop must not be able to silently mint a new sheet for the\n // attacker. Matches the `peer-recover-user` STRICT default.\n 'rotate-recovery': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp', 'webauthn-roaming'] }],\n },\n 'enroll-authenticator': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp'] }],\n },\n 'remove-authenticator': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp'] }],\n },\n // STRICT update-authenticator: same factor floor as enroll/remove.\n // Even though meta changes don't touch wrap material, a malicious\n // rename could mislead the user about which device a slot\n // corresponds to (\"MacBook Touch ID\" → \"iPhone Touch ID\" on a\n // shared workstation). STRICT requires a fresh factor proof.\n 'update-authenticator': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp'] }],\n },\n 'rotate-unlock': { minTier: 1 },\n 'enroll-user': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp'] }],\n },\n 'revoke-user': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp'] }],\n },\n // STRICT peer-recovery: the issuer must present a recovery code\n // OR a fresh off-device second factor at the moment of recovery.\n // This binds the high-trust operation to a verifiable proof\n // (recovery sheet photographed by an attacker won't suffice —\n // they'd also need tier-1 unlock first; this gate is the freshness\n // binding on top). Roaming WebAuthn (YubiKey-class hardware key)\n // accepted; platform-bound kinds (Touch ID, password, PIN)\n // intentionally excluded under STRICT because they don't survive\n // device theft — the off-device requirement is the whole point.\n 'peer-recover-user': {\n minTier: 1,\n factors: [{ anyOf: ['recovery', 'totp', 'email-otp', 'webauthn-roaming'] }],\n },\n // STRICT update-user: matches the enroll-user / revoke-user shape\n // (off-device factor required). Update-user is admin-shaped — it\n // mutates someone else's role/permissions; STRICT requires a fresh\n // off-device factor proof so the operator affirmatively re-asserts\n // identity at the moment of mutation. Platform-bound factors\n // (Touch ID / password / PIN) intentionally excluded: same logic as\n // peer-recover-user — the off-device requirement is the whole\n // point under STRICT.\n 'update-user': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp'] }],\n },\n 'export-bundle': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp'] }],\n warn: { sharedDevice: 'block' },\n },\n 'export-plaintext': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp'], count: 2 }],\n warn: { sharedDevice: 'block' },\n },\n 'view-user-auth': {\n minTier: 1,\n enabled: false,\n },\n // ─── User envelope gates ──────────────────────────────────────────\n // STRICT: profile edits require a TOTP/email-OTP factor (typical\n // shared-workstation hardening — your name/avatar shouldn't change\n // without a fresh second-factor proof).\n 'edit-own-profile': {\n minTier: 2,\n factors: [{ anyOf: ['totp', 'email-otp'] }],\n },\n 'view-team-profiles': { minTier: 2 },\n },\n}) as VaultPolicy\n\n/**\n * Merge a developer override onto a preset. Unspecified gates inherit;\n * specified gates fully replace the preset's entry for that gate.\n *\n * Example:\n *\n * ```ts\n * mergePolicy(PERSONAL_POLICY, {\n * gates: {\n * 'app:approve-large-payment': { minTier: 2, factors: [{ anyOf: ['totp'] }] },\n * },\n * })\n * // → PERSONAL_POLICY plus the new app gate; existing gates intact.\n * ```\n */\nexport function mergePolicy(\n base: VaultPolicy,\n override?: Partial<VaultPolicy>,\n): VaultPolicy {\n if (!override) return base\n const passphrase = override.passphrase ?? base.passphrase\n return {\n ...(passphrase !== undefined ? { passphrase } : {}),\n gates: {\n ...base.gates,\n ...(override.gates ?? {}),\n },\n }\n}\n","/**\n * Policy gate engine — the {@link checkGate} entry point.\n *\n * Given a configured {@link VaultPolicy}, an active session tier, and\n * the factor proofs an actor is presenting, decide whether the gate\n * permits the action. On denial, throws {@link PolicyDeniedError} with\n * a stable {@link PolicyDenyReason} so consumers can branch in error\n * UIs.\n *\n * @see docs/subsystems/session-tiers.md → checkGate() API\n *\n * @module\n */\nimport { PolicyDeniedError, type PolicyDenyReason } from './errors.js'\nimport type {\n ActiveTier,\n FactorProof,\n GateName,\n GatePolicy,\n VaultPolicy,\n FactorRequirement,\n} from './types.js'\n\n/** Default freshness window — 5 minutes. */\nexport const DEFAULT_FRESHNESS_MS = 5 * 60 * 1000\n\n/** Caller-supplied context for one `checkGate` invocation. */\nexport interface CheckGateContext {\n /** Tier the active session currently holds. */\n readonly activeTier: ActiveTier\n /** Proofs the actor is presenting for this gate. */\n readonly factors?: ReadonlyArray<FactorProof>\n /**\n * If the host knows the actor is on a shared device, set this to\n * `true` so the engine can apply `warn.sharedDevice` rules. Defaults\n * to `false`.\n */\n readonly sharedDevice?: boolean\n /**\n * Override `now()` for tests. Defaults to `Date.now()`.\n * @internal\n */\n readonly now?: number\n}\n\n/**\n * Decide whether `gate` permits the action under `context`. Throws\n * {@link PolicyDeniedError} on denial; resolves with `void` on success.\n *\n * Lookup rules:\n * - **Built-in gates** without a configured policy fail closed\n * (`enabled: false`).\n * - **App-defined gates** (`app:*`) without a configured policy are\n * treated as no-op (allow). The developer registered the policy if\n * they wanted enforcement; absence means the gate is informational.\n */\nexport async function checkGate(\n policy: VaultPolicy,\n gate: GateName,\n context: CheckGateContext,\n): Promise<void> {\n const configured = policy.gates[gate]\n if (!configured) {\n if (gate.startsWith('app:')) {\n // Custom app gate without a policy — the developer hasn't\n // registered one; engine treats it as an unenforced label.\n return\n }\n // Built-in gate without a policy — fail closed.\n throw deny(gate, 'disabled', { minTier: 1, enabled: false })\n }\n\n if (configured.enabled === false) {\n throw deny(gate, 'disabled', configured)\n }\n\n // Tier check first — cheap and a hard prerequisite.\n if (context.activeTier > configured.minTier) {\n // Higher number is a LOWER tier in this model (1 is most privileged).\n throw deny(gate, 'insufficient-tier', configured)\n }\n\n // Factor checks — every requirement entry must be satisfied.\n if (configured.factors && configured.factors.length > 0) {\n const presented = context.factors ?? []\n const now = context.now ?? Date.now()\n for (const requirement of configured.factors) {\n const matches = countMatchingFactors(presented, requirement, now)\n const need = requirement.count ?? 1\n if (matches.fresh < need) {\n if (matches.totalKindMatches < need) {\n throw deny(gate, 'missing-factor', configured)\n }\n // Some matched the kind list but not the freshness window.\n throw deny(gate, 'stale-proof', configured)\n }\n }\n }\n\n // Soft signals — only `'block'` raises here.\n if (configured.warn?.sharedDevice === 'block' && context.sharedDevice === true) {\n throw deny(gate, 'shared-device-blocked', configured)\n }\n}\n\n/**\n * Same as {@link checkGate} but returns a structured verdict instead\n * of throwing. Useful when an error UI wants to show the user\n * \"you'll need TOTP plus a recovery code to do that\" without first\n * triggering the action.\n */\nexport async function describeGate(\n policy: VaultPolicy,\n gate: GateName,\n context: CheckGateContext,\n): Promise<{ ok: true } | { ok: false; reason: PolicyDenyReason; required: GatePolicy }> {\n try {\n await checkGate(policy, gate, context)\n return { ok: true }\n } catch (err) {\n if (err instanceof PolicyDeniedError) {\n return { ok: false, reason: err.reason, required: err.required }\n }\n throw err\n }\n}\n\nfunction countMatchingFactors(\n presented: ReadonlyArray<FactorProof>,\n requirement: FactorRequirement,\n now: number,\n): { totalKindMatches: number; fresh: number } {\n const freshnessMs = requirement.freshnessMs ?? DEFAULT_FRESHNESS_MS\n let totalKindMatches = 0\n let fresh = 0\n for (const proof of presented) {\n if (!requirement.anyOf.includes(proof.kind)) continue\n totalKindMatches += 1\n const minted = proof.mintedAt ? Date.parse(proof.mintedAt) : now\n if (Number.isFinite(minted) && now - minted <= freshnessMs) {\n fresh += 1\n }\n }\n return { totalKindMatches, fresh }\n}\n\nfunction deny(gate: GateName, reason: PolicyDenyReason, required: GatePolicy): PolicyDeniedError {\n return new PolicyDeniedError(gate, reason, required)\n}\n","import type {\n NoydbOptions,\n NoydbEventMap,\n GrantOptions,\n RevokeOptions,\n UpdateUserOptions,\n UserInfo,\n PushResult,\n PullResult,\n PushOptions,\n PullOptions,\n SyncStatus,\n SyncTarget,\n NoydbStore,\n Role,\n AccessibleVault,\n ListAccessibleVaultsOptions,\n QueryAcrossOptions,\n QueryAcrossResult,\n ReAuthOperation,\n TranslatorAuditEntry,\n WriteConflict,\n} from './types.js'\nimport { ValidationError, NoAccessError, InvalidKeyError, KeyringCorruptError, StoreCapabilityError, PermissionDeniedError, VaultTemplateNotFoundError, ReservedVaultNameError } from './errors.js'\nimport { STATE_VAULT_NAME } from './federation/constants.js'\nimport type { StateManagementVault } from './federation/state-vault.js'\nimport {\n readDirectoryConfig,\n persistDirectoryConfig,\n} from './directory/storage.js'\nimport type { PassphrasePolicy } from './validation.js'\nimport {\n rotatePassphrase as keyringRotatePassphrase,\n recoverPassphrase as keyringRecoverPassphrase,\n type RotatePassphraseInput,\n type RecoverPassphraseInput,\n type RecoverPassphraseResult,\n type RotateRecoveryOptions,\n type RotateRecoveryResult,\n type EnrollRecoveryResult,\n type RecoveryEnrollmentInput,\n type RecoveryProof,\n} from './team/rotate-recover.js'\nimport {\n recoverUser as keyringRecoverUser,\n type RecoverUserOptions,\n} from './team/peer-recover.js'\nimport {\n loadPaperRecoveryEntries,\n savePaperRecoveryEntries,\n hasRecoveryEnrolled,\n hasStrongRecoveryEnrolled,\n mintPaperRecoveryEntry,\n type PaperRecoveryEntry,\n loadShamirRecoveryEntries,\n saveShamirRecoveryEntries,\n mintShamirRecoveryEntry,\n type ShamirRecoveryEntry,\n} from './team/recovery.js'\nimport { resolveManagedSecret, saveSealedPassphrase } from './team/managed-passphrase.js'\nimport type { ShamirRecoveryProvider } from './team/shamir-recovery-provider.js'\nimport { generateULID } from './bundle/ulid.js'\nimport { RecoveryNotEnrolledError, RecoveryProfileNotImplementedError, ManagedRecoveryNotEnrolledError, PolicyDeniedError } from './policy/errors.js'\nimport {\n describeAuthConfig as fnDescribeAuthConfig,\n diagramAuthConfig as fnDiagramAuthConfig,\n describeUserAuth as fnDescribeUserAuth,\n describeAllUsersAuth as fnDescribeAllUsersAuth,\n} from './auth-introspection/index.js'\nimport {\n loadPublicEnvelope,\n savePublicEnvelope,\n readPublicEnvelope as fnReadPublicEnvelope,\n resolveSchema as resolvePublicEnvelopeSchema,\n validatePublicEnvelopeInput,\n type PublicEnvelope,\n type SetPublicEnvelopeInput,\n type ResolvedPublicEnvelopeSchema,\n} from './meta/public-envelope/index.js'\nimport { Vault } from './vault.js'\nimport { NoydbEventEmitter } from './events.js'\nimport { WriteQueueTracker, type WriteQueue } from './write-queue.js'\nimport { WriteHookRegistry, type WriteHook, type Unsubscribe } from './write-hooks.js'\nimport { SubsystemBus } from './subsystem-bus.js'\nimport { TabCoordinator, defaultLockManager, defaultChannel, type TabCoordinationOptions, type TabRole, type TabPresence } from './tab-coordination.js'\nimport { CrossTabWriteRelay } from './tab-write-relay.js'\nimport {\n loadKeyring,\n createOwnerKeyring,\n assertKeyringOpenAllowed,\n grant as keyringGrant,\n revoke as keyringRevoke,\n rotateKeys as keyringRotate,\n changeSecret as keyringChangeSecret,\n listUsers as keyringListUsers,\n updateKeyringIdentity,\n} from './team/keyring.js'\nimport type { UnlockedKeyring } from './team/keyring.js'\nimport {\n enrollAuthenticator as keyringEnrollAuthenticator,\n removeAuthenticator as keyringRemoveAuthenticator,\n updateAuthenticator as keyringUpdateAuthenticator,\n findAuthenticator,\n type EnrollAuthenticatorOptions,\n type UpdateAuthenticatorOptions,\n} from './team/authenticators.js'\nimport { QuickUnlockStore, type QuickUnlockState } from './session/unlock-state.js'\nimport type { KeyringAuthenticator } from './types.js'\nimport type { SyncEngine } from './team/sync.js'\nimport type { SyncTransaction } from './team/sync-transaction.js'\nimport { NO_SYNC, type SyncStrategy } from './team/sync-strategy.js'\nimport { NO_SNAPSHOTS, type SnapshotStrategy, type SnapshotMeta } from './snapshots/strategy.js'\nimport { SnapshotScheduler } from './snapshots/scheduler.js'\nimport type { AmendmentTxOptions } from './tx/transaction.js'\nimport { TxContext } from './tx/transaction.js'\nimport type { DryRunResult } from './tx/dry-run.js'\nimport { NO_TX, type TxStrategy } from './tx/strategy.js'\nimport { NO_FORGET, type ForgetStrategy } from './forget/strategy.js'\nimport { readDottedPath, coerceSubjectId } from './forget/subject-index.js'\nimport { INDEXED_STORE_POLICY } from './store/sync-policy.js'\nimport type { PolicyEnforcer } from './session/session-policy.js'\nimport { NO_SESSION, type SessionStrategy } from './session/strategy.js'\nimport {\n checkGate as policyCheckGate,\n loadVaultPolicy,\n saveVaultPolicy,\n PERSONAL_POLICY,\n mergePolicy,\n type ActiveTier,\n type FactorProofBundle,\n type GateName,\n type VaultPolicy,\n} from './policy/index.js'\nimport type { VaultGroup } from './federation/vault-group.js'\nimport type { VaultTemplate, VaultGroupOptions } from './federation/types.js'\n\n/**\n * Privilege rank used by `listAccessibleVaults({ minRole })` to\n * filter the result. Higher number = more privileged. Owner is at the\n * top; client is at the bottom. Viewer outranks client because viewer\n * has read-all access while client has only explicit-collection read\n * — the ordering reflects \"how much can this principal see,\" not\n * \"how much can this principal modify.\"\n */\nconst ROLE_RANK: Record<Role, number> = {\n client: 1,\n viewer: 2,\n operator: 3,\n admin: 4,\n owner: 5,\n}\n\n/** Dummy keyring for unencrypted mode. */\nfunction createPlaintextKeyring(userId: string): UnlockedKeyring {\n return {\n userId,\n displayName: userId,\n role: 'owner',\n permissions: {},\n deks: new Map(),\n kek: null,\n salt: new Uint8Array(0),\n authenticators: [],\n }\n}\n\n/** The top-level NOYDB instance. */\nexport class Noydb {\n private readonly options: NoydbOptions\n private readonly emitter = new NoydbEventEmitter()\n private readonly writeQueueTracker = new WriteQueueTracker()\n private readonly writeHooks = new WriteHookRegistry()\n private readonly subsystemBus = new SubsystemBus()\n private readonly clientId = generateULID()\n private readonly vaultCache = new Map<string, Vault>()\n private readonly keyringCache = new Map<string, UnlockedKeyring>()\n private readonly syncEngines = new Map<string, SyncEngine>()\n /**\n * Per-vault active session tier — defaults to `1` after a passphrase\n * unlock; tier-2 / tier-3 unlocks downgrade it. Used by\n * {@link checkGate} to evaluate `gate.minTier`.\n */\n private readonly activeTier = new Map<string, ActiveTier>()\n /**\n * Per-vault loaded policy. Cached after the first\n * `_meta/policy` load; replaced by `db.updatePolicy()`.\n */\n private readonly policyCache = new Map<string, VaultPolicy>()\n /**\n * One-shot bypass for the managed-mode strong-recovery check.\n * Set true by {@link openVaultAndEnrollRecovery} for the duration of\n * the bootstrap window so the keyring can be created before the\n * strong recovery is enrolled. Always cleared (try/finally).\n * @internal\n */\n private _skipNextManagedRecoveryCheck = false\n /** Per-vault tier-3 (PIN / quick-resume) state. */\n private readonly quickUnlock = new QuickUnlockStore()\n /**\n * Resolved public-envelope schema. Lazily computed once from\n * `NoydbOptions.publicEnvelope`; `undefined` when the developer\n * didn't opt in.\n */\n private readonly publicEnvelopeSchema: ResolvedPublicEnvelopeSchema | undefined\n private closed = false\n private sessionTimer: ReturnType<typeof setTimeout> | null = null\n /** Same-device multi-tab coordinator; created on `enableTabCoordination()`. */\n private tabCoordinator: TabCoordinator | undefined\n /** Cross-tab write relay; created on `enableTabCoordination()`. */\n private writeRelay: CrossTabWriteRelay | undefined\n /** Per-vault policy enforcers. */\n private readonly policyEnforcers = new Map<string, PolicyEnforcer>()\n private readonly vaultTemplates = new Map<string, VaultTemplate>()\n private readonly txStrategy: TxStrategy\n private readonly forgetStrategy: ForgetStrategy\n private readonly sessionStrategy: SessionStrategy\n private readonly syncStrategy: SyncStrategy\n private readonly snapshotStrategy: SnapshotStrategy\n private snapshotScheduler: SnapshotScheduler | null = null\n private readonly dirtySnapshotVaults = new Set<string>()\n /**\n * Currently-running multi-record transaction, set by\n * `runTransaction` at the start of Phase 2 (commit) and cleared in\n * the same function's `finally` block. Side-effect writes triggered\n * during a staged op's `Collection.put` (today: eager derivation\n * outputs) register their pre-write envelope on `_executed` here so\n * a mid-batch failure rolls them back alongside the main staged ops.\n * `null` outside of Phase 2.\n * @internal\n */\n private _activeTxContext: TxContext | null = null\n\n // ─── plaintextTranslator state ─────────────────────────\n /**\n * In-process translation cache. Key is `\"${field}\\x00${collection}\\x00${from}\\x00${to}\\x00${text}\"`.\n * Cleared on `close()` alongside the KEK and DEKs.\n */\n private readonly translatorCache = new Map<string, string>()\n /** Audit log for all translator invocations in this session. Cleared on `close()`. */\n private readonly _translatorAuditLog: TranslatorAuditEntry[] = []\n\n constructor(options: NoydbOptions) {\n this.options = options\n this.txStrategy = options.txStrategy ?? NO_TX\n this.forgetStrategy = options.forgetStrategy ?? NO_FORGET\n this.sessionStrategy = options.sessionStrategy ?? NO_SESSION\n this.syncStrategy = options.syncStrategy ?? NO_SYNC\n this.snapshotStrategy = options.snapshotStrategy ?? NO_SNAPSHOTS\n this.initSnapshotCadence()\n this.publicEnvelopeSchema = resolvePublicEnvelopeSchema(options.publicEnvelope)\n // Validate sessionPolicy at construction time (developer error if invalid).\n // The strategy's stub throws with a pointer at the subpath if the\n // consumer set a policy without opting in.\n if (options.sessionPolicy) {\n this.sessionStrategy.validateSessionPolicy(options.sessionPolicy)\n }\n this.#registerGuardGate()\n this.#registerPeriodGate()\n this.#registerForgetHooks()\n this.resetSessionTimer()\n }\n\n /** @internal — resolved forget strategy (NO_FORGET when not configured). */\n get _forgetStrategy(): ForgetStrategy {\n return this.forgetStrategy\n }\n\n // #304 — GDPR subject-index maintenance. When `withForgetCascade` declares\n // any subject fields, keep the encrypted `_subject_index` in lock-step with\n // writes so `vault.forget(subjectId)` can find every record for a subject.\n //\n // Two consumers are required because they cover disjoint events:\n // - onAfterWrite fires on create/update (NOT delete) — add the new ref;\n // on an update that changed the subject value, drop the stale ref.\n // - the subsystemBus `afterDelete` observer fires on delete (onAfterWrite\n // does NOT) — drop the ref so a deleted record never lingers in the\n // index (RISK #2). Without it, forget() would try to shred a ghost.\n #registerForgetHooks(): void {\n const subjects = this.forgetStrategy.subjects\n if (Object.keys(subjects).length === 0) return\n\n const subjectFieldFor = (collection: string): string | undefined => subjects[collection]\n\n this.writeHooks.onAfterWrite(async (event) => {\n const field = subjectFieldFor(event.collection)\n if (field === undefined) return\n const vault = this.vaultCache.get(event.vault)\n if (!vault) return\n // Add the ref for the new subject value.\n if (event.after !== null && typeof event.after === 'object') {\n const subjectValue = readDottedPath(event.after as Record<string, unknown>, field)\n if (subjectValue !== undefined && subjectValue !== null) {\n await vault._addSubjectRef(coerceSubjectId(subjectValue), { collection: event.collection, id: event.docId })\n }\n }\n // On update, if the subject value changed, drop the stale ref.\n if (event.op === 'update' && event.before !== null && typeof event.before === 'object') {\n const beforeValue = readDottedPath(event.before as Record<string, unknown>, field)\n const afterValue =\n event.after !== null && typeof event.after === 'object'\n ? readDottedPath(event.after as Record<string, unknown>, field)\n : undefined\n const beforeId = beforeValue === undefined || beforeValue === null ? undefined : coerceSubjectId(beforeValue)\n const afterId = afterValue === undefined || afterValue === null ? undefined : coerceSubjectId(afterValue)\n if (beforeId !== undefined && beforeId !== afterId) {\n await vault._removeSubjectRef(beforeId, { collection: event.collection, id: event.docId })\n }\n }\n })\n\n this.subsystemBus.register('afterDelete', async (event) => {\n const field = subjectFieldFor(event.collection)\n if (field === undefined) return\n const vault = this.vaultCache.get(event.vault)\n if (!vault) return\n if (event.before !== null && typeof event.before === 'object') {\n const subjectValue = readDottedPath(event.before as Record<string, unknown>, field)\n if (subjectValue !== undefined && subjectValue !== null) {\n await vault._removeSubjectRef(coerceSubjectId(subjectValue), { collection: event.collection, id: event.docId })\n }\n }\n })\n }\n\n // Track A — guards migration. Registers record-lock / field-freeze / onDelete\n // / amendment-collect as gate-bus handlers (only when guards are opted in, so\n // the write path is zero-cost otherwise). Resolves the live vault's\n // GuardRegistry per dispatch. Registered BEFORE the period gate so guard\n // checks run first. The amendment branch is a side-effect (collectChange),\n // NOT a throw — and runs even for internal deletes (an amendment invariant\n // must see system housekeeping tombstones); onDelete/checks run only for\n // user (non-internal) operations.\n #registerGuardGate(): void {\n if (this.options.guardStrategies === undefined) return\n this.subsystemBus.registerGate('beforePut', async (e) => {\n const v = this.vaultCache.get(e.vault)\n if (!v) return\n const registry = v._getGuardRegistry()\n if (!registry) return\n const guards = registry.guardsFor(e.collection)\n if (guards.length === 0) return\n const existing = (e.existing ?? null) as Record<string, unknown> | null\n const incoming = e.incoming as Record<string, unknown>\n if (registry.isAmendmentActive()) {\n registry.collectChange(e.collection, e.docId, existing, incoming, e.existingVersion, e.existingVersion + 1)\n return\n }\n const facade = v._getReadOnlyFacade()\n if (!facade) return\n const ctx = { existing, vault: facade, userId: e.userId, role: e.role }\n await registry.runChecks(e.collection, incoming, ctx)\n const { GuardExecutor } = await import('./guards/executor.js')\n for (const g of guards) {\n await GuardExecutor.checkFrozenFields(g, e.docId, existing, incoming, e.computedFieldNames)\n }\n })\n this.subsystemBus.registerGate('beforeDelete', async (e) => {\n const v = this.vaultCache.get(e.vault)\n if (!v) return\n const registry = v._getGuardRegistry()\n if (!registry) return\n const guards = registry.guardsFor(e.collection)\n if (guards.length === 0) return\n const existing = (e.existing ?? null) as Record<string, unknown> | null\n if (registry.isAmendmentActive()) {\n registry.collectChange(e.collection, e.docId, existing, null as unknown as Record<string, unknown>, e.existingVersion, e.existingVersion)\n return\n }\n if (e.internal) return\n const facade = v._getReadOnlyFacade()\n if (!facade) return\n const ctx = { existing, vault: facade, userId: e.userId, role: e.role }\n await registry.runOnDelete(e.collection, existing ?? {}, ctx)\n })\n }\n\n /**\n * Register closed-period write guards on the subsystem bus when a\n * periodsStrategy is configured. Handlers resolve the live Vault from\n * vaultCache so they always use the up-to-date period cache.\n */\n // Track A — periods migration. Registers the closed-period write guard as a\n // gate-bus handler (only when periods is opted in, so the write path is\n // zero-cost otherwise). Each handler resolves the LIVE vault from the cache\n // per dispatch and delegates to its `_assertTsWritable`, which owns all\n // period logic. Resolving the live vault makes eviction/re-creation\n // transparent. Semantics note: if a write reaches the gate through a retained\n // collection handle whose vault has been evicted from `vaultCache` (e.g. a\n // post-revocation write on a stale handle), the period check is skipped — the\n // guard binds to the live vault, not a captured instance. Periods is a\n // write-integrity guard, not a security boundary, and a re-open reloads the\n // period cache; the trade-off is intentional.\n #registerPeriodGate(): void {\n if (this.options.periodsStrategy === undefined) return\n this.subsystemBus.registerGate('beforePut', async (e) => {\n const v = this.vaultCache.get(e.vault)\n if (!v) return\n const existing = e.op === 'create'\n ? null\n : { ts: e.existingTs ?? null, record: (e.existing ?? null) as Record<string, unknown> | null }\n await v._assertTsWritable(existing, e.incoming as Record<string, unknown>)\n })\n this.subsystemBus.registerGate('beforeDelete', async (e) => {\n if (e.internal) return\n const v = this.vaultCache.get(e.vault)\n if (!v) return\n await v._assertTsWritable(\n { ts: e.existingTs ?? null, record: (e.existing ?? null) as Record<string, unknown> | null },\n null,\n )\n })\n }\n\n private resetSessionTimer(): void {\n if (this.sessionTimer) clearTimeout(this.sessionTimer)\n // Honor the new sessionPolicy.idleTimeoutMs if present, fall back to\n // the legacy sessionTimeout for backwards compatibility.\n const idleMs = this.options.sessionPolicy?.idleTimeoutMs ?? this.options.sessionTimeout\n if (idleMs && idleMs > 0) {\n this.sessionTimer = setTimeout(() => {\n this.close()\n }, idleMs)\n }\n }\n\n /**\n * Attach a policy enforcer for a vault.\n * Called internally when a session is started for a vault; the\n * enforcer handles idle/absolute timeouts and background-lock behavior.\n */\n private attachPolicyEnforcer(vault: string, sessionId: string): void {\n const policy = this.options.sessionPolicy\n if (!policy) return\n\n // Tear down any previous enforcer for this vault\n this.policyEnforcers.get(vault)?.destroy()\n\n const enforcer = this.sessionStrategy.createEnforcer({\n policy,\n sessionId,\n onRevoke: (_reason) => {\n this.keyringCache.delete(vault)\n this.vaultCache.delete(vault)\n this.policyEnforcers.delete(vault)\n },\n })\n this.policyEnforcers.set(vault, enforcer)\n }\n\n /**\n * Touch the policy enforcer for a vault (records activity, resets\n * idle timer). Also touches the legacy session timer. No-op if no enforcer.\n */\n private touchPolicy(vault?: string): void {\n this.resetSessionTimer()\n if (vault) {\n this.policyEnforcers.get(vault)?.touch()\n }\n }\n\n /**\n * Check that a policy-guarded operation is permitted.\n * Throws `SessionPolicyError` if re-auth is required.\n */\n private checkPolicyOperation(vault: string, op: ReAuthOperation): void {\n this.policyEnforcers.get(vault)?.checkOperation(op)\n }\n\n /**\n * Open a vault by name.\n *\n * @param name Vault identifier.\n * @param opts Optional settings for this session.\n * @param opts.locale Default locale for i18n/dictKey field resolution\n *. Set here to avoid passing `{ locale }`\n * on every individual `get()`/`list()` call.\n */\n async openVault(\n name: string,\n opts?: { locale?: string; create?: boolean },\n ): Promise<Vault> {\n if (this.closed) throw new ValidationError('Instance is closed')\n this.touchPolicy(name)\n\n let comp = this.vaultCache.get(name)\n if (comp) {\n // Update locale on existing cached vault if specified\n if (opts?.locale !== undefined) {\n comp.setLocale(opts.locale)\n }\n return comp\n }\n\n const keyring = await this.getKeyringInternal(name, { create: opts?.create !== false })\n // Tier-1 unlock — passphrase / getKeyring callbacks both yield the\n // most-privileged tier. Tier-2 / tier-3 unlocks install\n // a lower tier here when they land.\n if (!this.activeTier.has(name)) {\n this.activeTier.set(name, 1)\n }\n // Load + persist the policy document. First call: persist the\n // developer-supplied policy (or default preset). Later calls: read\n // whatever's on disk and merge any developer override on top.\n if (this.options.encrypt !== false && !this.policyCache.has(name)) {\n await this.bootstrapPolicy(name)\n }\n\n // Set up sync engine(s) — handles bare NoydbStore, SyncTarget, or SyncTarget[]\n let syncEngine: SyncEngine | undefined\n const targets = normalizeSyncTargets(this.options.sync)\n if (targets.length > 0) {\n // Primary sync engine is the first sync-peer (or first target if none)\n const primary = targets.find(t => t.role === 'sync-peer') ?? targets[0]!\n const effectivePolicy = this.options.syncPolicy ?? primary.policy ?? INDEXED_STORE_POLICY\n syncEngine = this.syncStrategy.buildSyncEngine({\n local: this.options.store,\n remote: primary.store,\n vault: name,\n strategy: this.options.conflict ?? 'version',\n emitter: this.emitter,\n syncPolicy: effectivePolicy,\n role: primary.role,\n ...(primary.label !== undefined ? { label: primary.label } : {}),\n })\n this.syncEngines.set(name, syncEngine)\n\n // Additional targets get their own engines (backup/archive are push-only)\n for (const target of targets) {\n if (target === primary) continue\n const targetPolicy = target.policy ?? this.options.syncPolicy ?? INDEXED_STORE_POLICY\n const engine = this.syncStrategy.buildSyncEngine({\n local: this.options.store,\n remote: target.store,\n vault: name,\n strategy: this.options.conflict ?? 'version',\n emitter: this.emitter,\n syncPolicy: targetPolicy,\n role: target.role,\n ...(target.label !== undefined ? { label: target.label } : {}),\n })\n const key = `${name}::${target.label ?? target.role}`\n this.syncEngines.set(key, engine)\n }\n }\n\n comp = new Vault({\n adapter: this.options.store,\n name,\n noydb: this,\n keyring,\n encrypted: this.options.encrypt !== false,\n emitter: this.emitter,\n onDirty: targets.length > 0\n ? async (coll, id, action, version) => {\n // Fan out dirty tracking to all sync engines for this vault\n for (const [key, engine] of this.syncEngines) {\n if (key === name || key.startsWith(`${name}::`)) {\n void engine.trackChange(coll, id, action, version)\n }\n }\n }\n : undefined,\n onRegisterConflictResolver: syncEngine\n ? (resolverName, resolver) => syncEngine.registerConflictResolver(resolverName, resolver)\n : undefined,\n syncAdapter: targets.length > 0 ? targets[0]!.store : undefined,\n historyConfig: this.options.history,\n ...(this.options.blobStrategy !== undefined ? { blobStrategy: this.options.blobStrategy } : {}),\n ...(this.options.archiveStrategy !== undefined ? { archiveStrategy: this.options.archiveStrategy } : {}),\n ...(this.options.indexStrategy !== undefined ? { indexStrategy: this.options.indexStrategy } : {}),\n ...(this.options.aggregateStrategy !== undefined ? { aggregateStrategy: this.options.aggregateStrategy } : {}),\n ...(this.options.crdtStrategy !== undefined ? { crdtStrategy: this.options.crdtStrategy } : {}),\n ...(this.options.consentStrategy !== undefined ? { consentStrategy: this.options.consentStrategy } : {}),\n ...(this.options.periodsStrategy !== undefined ? { periodsStrategy: this.options.periodsStrategy } : {}),\n ...(this.options.shadowStrategy !== undefined ? { shadowStrategy: this.options.shadowStrategy } : {}),\n ...(this.options.historyStrategy !== undefined ? { historyStrategy: this.options.historyStrategy } : {}),\n ...(this.options.i18nStrategy !== undefined ? { i18nStrategy: this.options.i18nStrategy } : {}),\n ...(this.options.syncStrategy !== undefined ? { syncStrategy: this.options.syncStrategy } : {}),\n ...(this.options.guardStrategies !== undefined ? { guardStrategies: this.options.guardStrategies } : {}),\n ...(this.options.numbering !== undefined ? { numberingConfigs: this.options.numbering } : {}),\n forgetStrategy: this.forgetStrategy,\n locale: opts?.locale,\n // Thread the translator hook so Collection.put() can invoke it\n plaintextTranslator: this.options.plaintextTranslator\n ? (text, from, to, field, collection) =>\n this.invokeTranslator(text, from, to, field, collection)\n : undefined,\n // Refresh callback used by Vault.load() to re-derive\n // the in-memory keyring from a freshly-loaded keyring file.\n // Encrypted compartments need this so post-load decrypts work\n // against the loaded session's wrapped DEKs; plaintext\n // compartments leave it null and load() skips the refresh.\n reloadKeyring:\n this.options.encrypt !== false && this.options.secret\n ? async () => {\n // Drop the cached keyring so the next loadKeyring\n // call reads fresh from the adapter, then update the\n // cache so subsequent openVault calls see the\n // refreshed keyring too.\n this.keyringCache.delete(name)\n const refreshed = await loadKeyring(\n this.options.store,\n name,\n this.options.user,\n this.options.secret as string,\n )\n this.keyringCache.set(name, refreshed)\n return refreshed\n }\n : undefined,\n })\n // Initialise the optional guard + derivation registries via\n // dynamic-import. Both calls are no-ops when the corresponding\n // strategies array is empty / unset, leaving the subsystem code\n // out of the floor bundle for consumers that don't use it.\n await comp._initGuards(this.options.guardStrategies ?? [])\n await comp._initDerivations(this.options.derivationStrategies ?? [])\n await comp._initMaterializedViews(this.options.materializedViewStrategies ?? [])\n await comp._initOverlayedViews(this.options.overlayedViewStrategies ?? [])\n // Snapshot the schema-fence generation once per opened vault.\n await comp.schemaFence.init()\n this.vaultCache.set(name, comp)\n return comp\n }\n\n /** Synchronous vault access (must call openVault first, or auto-opens). */\n vault(name: string): Vault {\n const cached = this.vaultCache.get(name)\n if (cached) return cached\n\n // For backwards compat: if not opened yet, create with cached keyring or plaintext\n if (this.options.encrypt === false) {\n const keyring = createPlaintextKeyring(this.options.user)\n const comp = new Vault({\n adapter: this.options.store,\n name,\n noydb: this,\n keyring,\n encrypted: false,\n emitter: this.emitter,\n historyConfig: this.options.history,\n ...(this.options.blobStrategy !== undefined ? { blobStrategy: this.options.blobStrategy } : {}),\n ...(this.options.archiveStrategy !== undefined ? { archiveStrategy: this.options.archiveStrategy } : {}),\n ...(this.options.indexStrategy !== undefined ? { indexStrategy: this.options.indexStrategy } : {}),\n ...(this.options.aggregateStrategy !== undefined ? { aggregateStrategy: this.options.aggregateStrategy } : {}),\n ...(this.options.crdtStrategy !== undefined ? { crdtStrategy: this.options.crdtStrategy } : {}),\n ...(this.options.consentStrategy !== undefined ? { consentStrategy: this.options.consentStrategy } : {}),\n ...(this.options.periodsStrategy !== undefined ? { periodsStrategy: this.options.periodsStrategy } : {}),\n ...(this.options.shadowStrategy !== undefined ? { shadowStrategy: this.options.shadowStrategy } : {}),\n ...(this.options.historyStrategy !== undefined ? { historyStrategy: this.options.historyStrategy } : {}),\n ...(this.options.i18nStrategy !== undefined ? { i18nStrategy: this.options.i18nStrategy } : {}),\n ...(this.options.syncStrategy !== undefined ? { syncStrategy: this.options.syncStrategy } : {}),\n ...(this.options.guardStrategies !== undefined ? { guardStrategies: this.options.guardStrategies } : {}),\n ...(this.options.numbering !== undefined ? { numberingConfigs: this.options.numbering } : {}),\n forgetStrategy: this.forgetStrategy,\n })\n this.vaultCache.set(name, comp)\n return comp\n }\n\n const keyring = this.keyringCache.get(name)\n if (!keyring) {\n throw new ValidationError(\n `Vault \"${name}\" not opened. Use await db.openVault(\"${name}\") first.`,\n )\n }\n\n const comp = new Vault({\n adapter: this.options.store,\n name,\n noydb: this,\n keyring,\n encrypted: true,\n historyConfig: this.options.history,\n ...(this.options.blobStrategy !== undefined ? { blobStrategy: this.options.blobStrategy } : {}),\n ...(this.options.archiveStrategy !== undefined ? { archiveStrategy: this.options.archiveStrategy } : {}),\n ...(this.options.indexStrategy !== undefined ? { indexStrategy: this.options.indexStrategy } : {}),\n ...(this.options.aggregateStrategy !== undefined ? { aggregateStrategy: this.options.aggregateStrategy } : {}),\n ...(this.options.crdtStrategy !== undefined ? { crdtStrategy: this.options.crdtStrategy } : {}),\n ...(this.options.consentStrategy !== undefined ? { consentStrategy: this.options.consentStrategy } : {}),\n ...(this.options.periodsStrategy !== undefined ? { periodsStrategy: this.options.periodsStrategy } : {}),\n ...(this.options.shadowStrategy !== undefined ? { shadowStrategy: this.options.shadowStrategy } : {}),\n ...(this.options.historyStrategy !== undefined ? { historyStrategy: this.options.historyStrategy } : {}),\n ...(this.options.i18nStrategy !== undefined ? { i18nStrategy: this.options.i18nStrategy } : {}),\n ...(this.options.syncStrategy !== undefined ? { syncStrategy: this.options.syncStrategy } : {}),\n ...(this.options.guardStrategies !== undefined ? { guardStrategies: this.options.guardStrategies } : {}),\n ...(this.options.numbering !== undefined ? { numberingConfigs: this.options.numbering } : {}),\n emitter: this.emitter,\n })\n this.vaultCache.set(name, comp)\n return comp\n }\n\n /**\n * Grant access to a user for a vault.\n *\n * Gated by `enroll-user`. `STRICT_POLICY` requires a TOTP / email-OTP\n * factor proof so the operator affirmatively re-asserts identity at\n * the moment of grant; `PERSONAL_POLICY` accepts a tier-1 unlock alone.\n *\n * The legacy `requireReAuthFor: ['grant']` session-policy check still\n * fires on top — both are independent opt-ins.\n */\n async grant(\n vault: string,\n options: GrantOptions,\n factors?: FactorProofBundle,\n ): Promise<void> {\n this.checkPolicyOperation(vault, 'grant')\n await this.checkGate(vault, 'enroll-user', factors)\n const keyring = await this.getKeyringInternal(vault)\n await keyringGrant(this.options.store, vault, keyring, options)\n }\n\n /**\n * Revoke a user's access to a vault.\n *\n * Gated by `revoke-user`. `STRICT_POLICY` requires a TOTP / email-OTP\n * factor proof; `PERSONAL_POLICY` accepts a tier-1 unlock alone.\n *\n * The legacy `requireReAuthFor: ['revoke']` session-policy check still\n * fires on top — both are independent opt-ins.\n */\n async revoke(\n vault: string,\n options: RevokeOptions,\n factors?: FactorProofBundle,\n ): Promise<void> {\n this.checkPolicyOperation(vault, 'revoke')\n await this.checkGate(vault, 'revoke-user', factors)\n const keyring = await this.getKeyringInternal(vault)\n await keyringRevoke(this.options.store, vault, keyring, options)\n }\n\n /**\n * Mutate post-grant identity fields on an existing keyring — `role`,\n * `displayName`, and/or `permissions`. Pure plaintext-header rewrite:\n * no DEK rewrap, no KEK required, no authenticator slots touched.\n * Tier-2 enrollments and recovery codes survive.\n *\n * Different from `db.revoke + db.grant`:\n *\n * - Same `userId`, same DEK wrappings, same `granted_by`, same\n * `_users/<keyringId>` envelope. Only the specified header\n * fields move. Last-write-wins via the standard keyring put.\n * - No cascade on role demotion (admins demoted to operator keep\n * the keyrings they previously granted; the cascade rules are\n * a `db.revoke` concern, not `db.updateUser`).\n * - Tier-2 slots NOT dropped — the wrapping is unaffected.\n *\n * Role-elevation guard: BOTH the old and new role must satisfy\n * `db.grant`'s hierarchy. Owner can do anything; admin manages\n * admin/operator/viewer/client laterally; admin cannot promote to\n * owner OR demote from owner. The guard runs regardless of the\n * `update-user` policy gate's settings — gates can only be more\n * permissive than the structural floor, never less.\n *\n * Gated by `update-user`. `STRICT_POLICY` requires a TOTP/email-OTP\n * factor proof so the operator affirmatively re-asserts identity at\n * the moment of mutation; `PERSONAL_POLICY` accepts a tier-1 unlock\n * alone.\n *\n * ```ts\n * await db.updateUser('acme', {\n * userId: 'bob',\n * role: 'operator', // promote\n * permissions: { invoices: 'rw' },\n * }, { factors: [{ kind: 'totp' }] })\n * ```\n *\n * @throws `NoAccessError` when no keyring exists for the target.\n * @throws `PermissionDeniedError` when the role hierarchy rejects.\n * @throws `ValidationError` when no field is provided.\n */\n async updateUser(\n vault: string,\n options: UpdateUserOptions,\n factors?: FactorProofBundle,\n ): Promise<void> {\n await this.checkGate(vault, 'update-user', factors)\n const keyring = await this.getKeyringInternal(vault)\n await updateKeyringIdentity(this.options.store, vault, keyring, options)\n // If the caller updated their own role / permissions, the cached\n // unlocked keyring is stale — drop it so the next access reloads\n // with the new header fields. (DEKs unchanged, so the cached\n // unlock still works; only the role-gated checks would diverge.)\n if (options.userId === this.options.user) {\n this.keyringCache.delete(vault)\n }\n }\n\n /**\n * Rotate the DEKs for the given collections in a vault.\n *\n * Generates fresh DEKs, re-encrypts every record in each collection,\n * and re-wraps the new DEKs into every remaining user's keyring. The\n * old DEKs become unreachable — useful as a defense-in-depth measure\n * after a suspected key leak, or as the scheduled half of a\n * key-rotation policy.\n *\n * Unlike `revoke({ rotateKeys: true })`, this call does NOT remove\n * any users — every current member keeps access, but with fresh\n * keys. This is the \"just rotate\" path; the \"revoke and rotate\"\n * path still lives in `revoke()`.\n *\n * Exposed on Noydb (rather than only on the lower-level keyring\n * module) so CLI and admin tooling can trigger rotation without\n * reaching into internals. See `noy-db rotate` for the CLI wrapper.\n */\n async rotate(vault: string, collections: string[]): Promise<void> {\n this.checkPolicyOperation(vault, 'rotate')\n const keyring = await this.getKeyringInternal(vault)\n await keyringRotate(this.options.store, vault, keyring, collections)\n // Refresh the cached keyring so subsequent operations see the\n // freshly-rotated DEKs. Without this, `ensureCollectionDEK` on\n // the next Collection access would still hold the old ones.\n this.keyringCache.set(vault, keyring)\n }\n\n /** List all users with access to a vault. */\n async listUsers(vault: string): Promise<UserInfo[]> {\n return keyringListUsers(this.options.store, vault)\n }\n\n // ─── Cross-vault queries ──────────────────────\n\n /**\n * Enumerate every vault the calling principal can unwrap,\n * optionally filtered by minimum role.\n *\n * The walk is a two-step pipeline: first ask the adapter for the\n * universe of compartments it stores, then for each one attempt to\n * load the calling user's keyring with the in-memory passphrase.\n * Compartments where the user has no keyring file (`NoAccessError`)\n * or where the passphrase doesn't unwrap (`InvalidKeyError`) are\n * silently dropped from the result — the existence of those\n * compartments is **not** confirmed in the return value.\n *\n * Requires the optional `NoydbStore.listVaults()` capability.\n * Throws `StoreCapabilityError` against stores that don't\n * implement it (today: store-aws-dynamo, store-aws-s3, store-browser-local, store-browser-idb). For those backends the\n * consumer should either pass an explicit candidate list to\n * `queryAcross()` directly, or maintain a vault index out of\n * band.\n *\n * **Privacy note.** This method's return value never reveals the\n * existence of a vault the caller cannot unwrap. The adapter\n * sees the enumeration call (it has to — it owns the storage), but\n * downstream consumers of `listAccessibleVaults()` only see\n * the filtered list. That's the boundary the existence-leak\n * guarantee draws.\n *\n * **Known edge case.** A vault whose keyring file\n * happens to have an empty wrapped-DEKs map (because the owner\n * granted access before any collection was created) will pass the\n * `loadKeyring` probe with *any* passphrase — there are no DEKs to\n * unwrap, so the integrity-checked unwrap that normally rejects\n * wrong passphrases never runs. The result is that an unrelated\n * principal who happens to know the user-id and the vault\n * name can show up in `listAccessibleVaults()` as having\n * access to that empty vault. They cannot read any actual\n * data (their DEK set is empty), so this is a metadata leak\n * (vault name + user-id), not a content leak. Hardening this\n * via a passphrase canary in the keyring file is a deferred\n * follow-up.\n *\n * **Cost.** O(compartments × keyring-load) — one `loadKeyring`\n * attempt per vault in the universe. Each attempt does one\n * adapter `get` + one PBKDF2 derivation + N AES-KW unwraps. For\n * dozens of compartments this is fine; for thousands the consumer\n * should cache the result and refresh on grant/revoke events. A\n * future optimization could batch the keyring reads via\n * `loadAll('_keyring')` if such a thing existed at the adapter\n * layer, but the contract doesn't expose that.\n *\n * @example\n * ```ts\n * // All compartments I can unwrap\n * const all = await db.listAccessibleVaults()\n *\n * // Only compartments where I'm at least admin\n * const admin = await db.listAccessibleVaults({ minRole: 'admin' })\n *\n * // Only compartments I own\n * const owned = await db.listAccessibleVaults({ minRole: 'owner' })\n * ```\n */\n async listAccessibleVaults(\n options: ListAccessibleVaultsOptions = {},\n ): Promise<AccessibleVault[]> {\n if (this.closed) throw new ValidationError('Instance is closed')\n this.resetSessionTimer()\n\n const adapter = this.options.store\n if (typeof adapter.listVaults !== 'function') {\n throw new StoreCapabilityError(\n 'listVaults',\n 'Noydb.listAccessibleVaults()',\n adapter.name,\n )\n }\n\n if (this.options.encrypt === false) {\n // Plaintext mode: no keyrings exist; every vault the\n // adapter knows about is \"accessible\" trivially as owner.\n const all = await adapter.listVaults()\n return all.map((id) => ({ id, role: 'owner' as Role }))\n }\n\n if (!this.options.secret) {\n throw new ValidationError(\n 'Noydb.listAccessibleVaults(): a secret (passphrase) is required ' +\n 'when encryption is enabled.',\n )\n }\n\n const minRank = ROLE_RANK[options.minRole ?? 'client']\n const universe = await adapter.listVaults()\n const accessible: AccessibleVault[] = []\n\n for (const vault of universe) {\n // Probe with loadKeyring directly (NOT getKeyring, which would\n // auto-create a fresh owner keyring on miss — that would\n // silently grant access to every empty vault in the\n // universe and is exactly the wrong shape for an enumeration\n // API). The two expected failure modes — no keyring file, or\n // wrong passphrase — are caught and silently dropped so the\n // return value never leaks existence.\n let keyring: UnlockedKeyring\n try {\n keyring = await loadKeyring(\n adapter,\n vault,\n this.options.user,\n this.options.secret,\n )\n } catch (err) {\n if (\n err instanceof NoAccessError ||\n err instanceof InvalidKeyError ||\n err instanceof KeyringCorruptError\n ) {\n // No accessible key material for this vault. KeyringCorruptError\n // is included so a single partially-corrupted vault does NOT\n // poison the enumeration of every other healthy vault — the\n // caller can probe a corrupted vault directly via openVault()\n // / loadKeyring() if they want to act on it.\n continue\n }\n throw err // unexpected error — surface it\n }\n\n if (ROLE_RANK[keyring.role] < minRank) continue\n accessible.push({ id: vault, role: keyring.role })\n\n // Opportunistically prime the keyring cache so a subsequent\n // openVault() doesn't have to re-derive the KEK. The cost\n // is one Map.set per vault we already paid to unwrap.\n this.keyringCache.set(vault, keyring)\n }\n\n return accessible\n }\n\n /**\n * Run a per-vault callback against a list of compartments and\n * collect the results.\n *\n * Pure orchestration — there is no new crypto, no new sync, no new\n * authorization layer. Each vault is opened via the existing\n * `openVault()` path (which honors the cache primed by\n * `listAccessibleVaults`), the callback runs against the\n * resulting `Vault` instance, and the result (or thrown\n * error) is captured into the per-vault slot.\n *\n * **Per-vault errors do not abort the fan-out.** If one\n * vault's callback throws, that vault's slot carries\n * the error and the remaining compartments still run. The caller\n * decides how to handle the partition between success and failure.\n * This is the right shape for cross-tenant reports where one\n * tenant's outage shouldn't hide the other tenants' data.\n *\n * **Concurrency** is opt-in via `options.concurrency`. The default\n * is `1` (sequential) — conservative because per-vault\n * callbacks typically do their own I/O and an unbounded fan-out\n * can exhaust adapter connections (DynamoDB throughput, S3 socket\n * limits, browser fetch concurrency). Bump to 4-8 for cloud-backed\n * adapters where parallelism is the whole point.\n *\n * @example\n * ```ts\n * // Cross-tenant invoice totals as a flat list\n * const accessible = await db.listAccessibleVaults({ minRole: 'admin' })\n * const results = await db.queryAcross(\n * accessible.map((c) => c.id),\n * async (comp) => {\n * return comp.collection<Invoice>('invoices').query()\n * .where('month', '==', '2026-03')\n * .toArray()\n * },\n * { concurrency: 4 },\n * )\n * // results: Array<{ vault, result?: Invoice[], error?: Error }>\n *\n * // Compose with exportStream() — cross-vault plaintext export\n * const exports = await db.queryAcross(accessible.map((c) => c.id), async (comp) => {\n * const out: unknown[] = []\n * for await (const chunk of comp.exportStream()) out.push(chunk)\n * return out\n * })\n * ```\n */\n async queryAcross<T>(\n vaultIds: string[],\n fn: (vault: Vault) => Promise<T>,\n options: QueryAcrossOptions = {},\n ): Promise<QueryAcrossResult<T>[]> {\n if (this.closed) throw new ValidationError('Instance is closed')\n this.resetSessionTimer()\n\n const concurrency = Math.max(1, options.concurrency ?? 1)\n const results: QueryAcrossResult<T>[] = new Array(vaultIds.length)\n\n // Tiny inline p-limit. Maintains a sliding window of `concurrency`\n // in-flight promises and schedules the next vault as each\n // one settles. No external dep. Index-keyed result array so the\n // output preserves caller-supplied order even when concurrency\n // > 1 lets later compartments finish before earlier ones.\n let nextIndex = 0\n const inFlight: Set<Promise<void>> = new Set()\n\n const launch = (): Promise<void> | null => {\n if (nextIndex >= vaultIds.length) return null\n const idx = nextIndex++\n const vaultId = vaultIds[idx]!\n const task = (async () => {\n try {\n const comp = await this.openVault(vaultId, { create: options.create !== false })\n const result = await fn(comp)\n results[idx] = { vault: vaultId, result }\n } catch (err) {\n results[idx] = {\n vault: vaultId,\n error: err instanceof Error ? err : new Error(String(err)),\n }\n }\n })()\n inFlight.add(task)\n // Fire-and-forget cleanup. The task itself never rejects (the\n // try/catch above swallows everything into the result slot), so\n // there's no rejection to handle here — `void` tells the linter\n // we know what we're doing.\n void task.finally(() => inFlight.delete(task))\n return task\n }\n\n // Prime the window.\n for (let i = 0; i < concurrency; i++) {\n if (launch() === null) break\n }\n\n // Drain. As each task settles, kick off the next one until the\n // input is exhausted. `Promise.race` against the live set is the\n // simplest way to \"wake up on whichever finishes first\" without\n // pulling in p-limit / async-pool / etc.\n while (inFlight.size > 0) {\n await Promise.race(inFlight)\n while (inFlight.size < concurrency && nextIndex < vaultIds.length) {\n if (launch() === null) break\n }\n }\n\n return results\n }\n\n /**\n * Register a shard schema blueprint. `createShard` / `openVaultGroup`\n * stamp shards from the named template. See the MVF design spec.\n */\n withVaultTemplate(name: string, template: VaultTemplate): void {\n this.vaultTemplates.set(name, template)\n }\n\n /**\n * Open a VaultGroup — transparent routing over per-partition shard\n * vaults, with shard discovery backed by the supplied `vault-registry`\n * collection.\n */\n async openVaultGroup<T>(name: string, opts: VaultGroupOptions<T>): Promise<VaultGroup<T>> {\n if (this.closed) throw new ValidationError('Instance is closed')\n if (name === STATE_VAULT_NAME) throw new ReservedVaultNameError(name)\n const template = this.vaultTemplates.get(opts.sharding.vaultTemplate)\n if (!template) throw new VaultTemplateNotFoundError(opts.sharding.vaultTemplate)\n // Lazy-load so the federation module stays a separate chunk, not part\n // of the always-loaded core graph (keeps the core bundle ceiling). Both\n // imports below MUST remain dynamic for the same reason.\n const { VaultGroup } = await import('./federation/vault-group.js')\n const { StateManagementVault } = await import('./federation/state-vault.js')\n // Managed control plane when no explicit registry is supplied.\n const stateVault = opts.registry ? undefined : await StateManagementVault.open(this)\n const registry = opts.registry ?? stateVault!.registry\n const group = new VaultGroup<T>(this, name, registry, opts.sharding, template)\n if (stateVault) {\n group._attachStateVault(stateVault)\n // recordManifest persists control-plane state → hard-fail on error.\n await stateVault.recordManifest(opts.sharding.vaultTemplate, template)\n // manifest-recorded + group-opened are incidental audit events →\n // best-effort, never fail the open.\n try {\n await stateVault.appendEvent({\n type: 'manifest-recorded',\n group: name,\n templateName: opts.sharding.vaultTemplate,\n version: template.version,\n })\n await stateVault.appendEvent({ type: 'group-opened', group: name })\n } catch {\n /* best-effort: event logging never fails openVaultGroup */\n }\n }\n return group\n }\n\n /**\n * Open the reserved StateManagement control-plane vault (registry +\n * schema-manifest + deployment-events). Lazy-loaded so the federation\n * chunk stays out of the core graph until used.\n */\n async openStateManagementVault(): Promise<StateManagementVault> {\n if (this.closed) throw new ValidationError('Instance is closed')\n const { StateManagementVault } = await import('./federation/state-vault.js')\n return StateManagementVault.open(this)\n }\n\n /**\n * @internal — true when an encrypted shard vault is provisioned\n * (its keyring exists in the store).\n */\n async _shardVaultProvisioned(vaultId: string): Promise<boolean> {\n return (await this.options.store.list(vaultId, '_keyring')).length > 0\n }\n\n /**\n * Change the current user's passphrase for a vault.\n *\n * Validates the new passphrase against the strength rules. Pass\n * `{ allowWeakPassphrase: true }` to skip — typically only useful for\n * fixtures and migrations. Pass a `PassphrasePolicy` to override the\n * default rules (e.g. consumer-tunable `pattern` / `customValidator`).\n */\n async changeSecret(\n vault: string,\n newPassphrase: string,\n options?: PassphrasePolicy & { allowWeakPassphrase?: boolean },\n ): Promise<void> {\n this.checkPolicyOperation(vault, 'changeSecret')\n const keyring = await this.getKeyringInternal(vault)\n const updated = await keyringChangeSecret(\n this.options.store,\n vault,\n keyring,\n newPassphrase,\n options,\n )\n this.keyringCache.set(vault, updated)\n }\n\n // ─── Sync ──────────────────────────────────────────────────────\n\n /** Push local changes to remote for a vault. */\n async push(vault: string, options?: PushOptions): Promise<PushResult> {\n const engine = this.getSyncEngine(vault)\n return engine.push(options)\n }\n\n /** Pull remote changes to local for a vault. */\n async pull(vault: string, options?: PullOptions): Promise<PullResult> {\n const engine = this.getSyncEngine(vault)\n return engine.pull(options)\n }\n\n /**\n * Bidirectional sync: pull then push for all targets.\n * `sync-peer` targets do pull+push; `backup`/`archive` targets do push-only.\n */\n async sync(vault: string, options?: { push?: PushOptions; pull?: PullOptions }): Promise<{ pull: PullResult; push: PushResult }> {\n const primary = this.getSyncEngine(vault)\n const result = await primary.sync(options)\n\n // Fan out push to backup/archive targets (fire-and-mark-dirty)\n for (const [key, engine] of this.syncEngines) {\n if (key === vault) continue\n if (!key.startsWith(`${vault}::`)) continue\n if (engine.role === 'sync-peer') {\n await engine.sync(options).catch((err: Error) => {\n this.emitter.emit('sync:backup-error', {\n vault,\n target: engine.label ?? engine.role,\n error: err,\n })\n })\n } else {\n // backup/archive: push-only\n await engine.push(options?.push).catch((err: Error) => {\n this.emitter.emit('sync:backup-error', {\n vault,\n target: engine.label ?? engine.role,\n error: err,\n })\n })\n }\n }\n\n return result\n }\n\n /**\n * Multi-record atomic transaction.\n *\n * The callback stages writes across any number of vaults /\n * collections; on return the hub pre-flights version checks, then\n * commits every staged op. If the body throws, nothing is\n * persisted. If any staged op fails its `expectedVersion` check,\n * the batch throws `ConflictError` with zero writes performed. If a\n * mid-commit failure occurs after one or more ops have already\n * written, each executed op is reverted best-effort (see\n * `runTransaction` for the crash-window caveat).\n *\n * Distinct from `transaction(vault: string) → SyncTransaction`\n * which batches push/pull across sync peers.\n */\n transaction<T>(fn: (tx: TxContext) => Promise<T> | T): Promise<T>\n /**\n * Open an amendment-mode transaction. Requires `admin` or `owner`\n * role on every vault touched by the body; throws\n * `AmendmentForbiddenError` on first non-privileged `tx.vault(name)`\n * call. Guard `check` callbacks are SKIPPED inside an amendment —\n * the staged change-set is fed to each guard's `amendment.invariant`\n * after the body returns, and the multi-record summary is appended\n * to the vault's ledger as `op: 'amendment'`.\n */\n transaction<T>(\n options: AmendmentTxOptions,\n fn: (tx: TxContext) => Promise<T> | T,\n ): Promise<T>\n /**\n * Dry-run a transaction: run the body to stage ops, then return\n * the directly-affected diff + collected guard violations WITHOUT\n * committing (no adapter writes, no write hooks). MV/derivation cascade\n * is not simulated. Requires `withTransactions()`.\n */\n transaction(\n options: { readonly dryRun: true },\n fn: (tx: TxContext) => unknown,\n ): Promise<DryRunResult>\n /**\n * Create a sync transaction for the given vault.\n * The vault must already be open via `openVault()`.\n * Call `tx.put()` / `tx.delete()` to stage changes, then `tx.commit()`\n * to write all locally and push atomically to remote.\n */\n transaction(vault: string): SyncTransaction\n transaction<T>(\n arg: string | AmendmentTxOptions | { readonly dryRun: true } | ((tx: TxContext) => Promise<T> | T),\n maybeFn?: (tx: TxContext) => Promise<T> | T,\n ): SyncTransaction | Promise<T> | Promise<DryRunResult> {\n if (typeof arg === 'function') {\n return this.txStrategy.runTransaction(this, arg)\n }\n if (typeof arg === 'object' && arg !== null && (arg as { dryRun?: boolean }).dryRun === true) {\n // Dry-run form: stage + diff, no commit.\n if (typeof maybeFn !== 'function') {\n throw new ValidationError(\n 'db.transaction({ dryRun: true }, fn) requires the callback as the second argument.',\n )\n }\n return this.txStrategy.runDryRun(this, maybeFn)\n }\n if (typeof arg === 'object' && arg !== null && (arg as { amendment?: boolean }).amendment === true) {\n // Two-arg amendment form. We forward `arg` as the options bag —\n // the executor handles reason validation + per-vault role check.\n if (typeof maybeFn !== 'function') {\n throw new ValidationError(\n 'db.transaction({ amendment: true }, fn) requires the callback as the second argument.',\n )\n }\n return this.txStrategy.runTransaction(this, maybeFn, arg as AmendmentTxOptions)\n }\n const vault = arg as string\n const comp = this.vaultCache.get(vault)\n if (!comp) {\n throw new ValidationError(\n `Vault \"${vault}\" is not open. Call openVault() first.`,\n )\n }\n const engine = this.getSyncEngine(vault)\n return this.syncStrategy.buildSyncTransaction(comp, engine)\n }\n\n /**\n * Internal accessor for the primary store — used by the tx\n * executor to perform raw adapter reads for pre-flight CAS and\n * raw writes for rollback. Not part of the public API.\n *\n * @internal\n */\n get _store(): NoydbStore {\n return this.options.store\n }\n\n /**\n * Currently-running multi-record transaction, or `null` outside\n * Phase 2. `Collection.dispatchDerivations` consults this so a\n * recursive derived-output write inside `Collection.put` can register\n * its envelope onto `ctx._executed` and roll back with the main\n * staged ops on mid-batch failure.\n *\n * @internal\n */\n get _activeTxContextOrNull(): TxContext | null {\n return this._activeTxContext\n }\n\n /**\n * Called by `runTransaction` at Phase 2 start, and by\n * `Collection.putManyAtomic` (via `derivationSource.setActiveTxContext`)\n * for its own Phase 2 loop. Nested or concurrent (non-nested)\n * transactions on the same Noydb instance are NOT supported —\n * overwriting an active context means another transaction is still\n * running and its `_executed` list would be cross-contaminated by\n * the nested writes. We tolerate the overwrite (best-effort, no\n * throw) to keep the rare interleaving from breaking consumers who\n * currently get lucky with timing, but applications should ensure\n * their multi-record commits are serialised on a single Noydb.\n *\n * @internal\n */\n _setActiveTxContext(ctx: TxContext): void {\n this._activeTxContext = ctx\n }\n\n /**\n * Factory for a transient `TxContext` bound to this Noydb. Used by\n * `Collection.putManyAtomic` (via `derivationSource.createTxContext`)\n * to publish an active context for the duration of its bulk-atomic\n * Phase 2 loop, so recursive derivation-output writes register on\n * `ctx._executed` and roll back together with the source ops.\n *\n * @internal\n */\n _createTxContext(): TxContext {\n return new TxContext(this)\n }\n\n /**\n * Called by `runTransaction` in its `finally`. Only clears when the\n * passed ctx matches the active one — a defensive no-op if some\n * other code path already cleared it.\n *\n * @internal\n */\n _clearActiveTxContext(ctx: TxContext): void {\n if (this._activeTxContext === ctx) {\n this._activeTxContext = null\n }\n }\n\n /** Get sync status for a vault. */\n syncStatus(vault: string): SyncStatus {\n const engine = this.syncEngines.get(vault)\n if (!engine) {\n return { dirty: 0, lastPush: null, lastPull: null, online: true }\n }\n return engine.status()\n }\n\n private requireShamirProvider(): ShamirRecoveryProvider {\n const p = this.options.shamirRecovery\n if (!p) {\n throw new Error(\n \"shamir recovery requires a ShamirRecoveryProvider — pass \"\n + \"shamirRecovery: shamirRecoveryProvider() from '@noy-db/on-shamir' to createNoydb()\",\n )\n }\n return p\n }\n\n private getSyncEngine(vault: string): SyncEngine {\n const engine = this.syncEngines.get(vault)\n if (!engine) {\n throw new ValidationError('No sync adapter configured. Pass a `sync` adapter to createNoydb().')\n }\n return engine\n }\n\n // ─── Events ────────────────────────────────────────────────────\n\n on<K extends keyof NoydbEventMap>(event: K, handler: (data: NoydbEventMap[K]) => void): void {\n this.emitter.on(event, handler)\n }\n\n off<K extends keyof NoydbEventMap>(event: K, handler: (data: NoydbEventMap[K]) => void): void {\n this.emitter.off(event, handler)\n }\n\n /**\n * Observable write-queue for this hub instance. Reflects outstanding\n * in-flight writes across all collections. See {@link WriteQueue}.\n *\n * @example\n * window.addEventListener('beforeunload', (e) => {\n * if (db.writeQueue.pending) { e.preventDefault(); e.returnValue = '' }\n * })\n */\n get writeQueue(): WriteQueue {\n return this.writeQueueTracker\n }\n\n /**\n * @internal Mutable tracker behind {@link writeQueue}. Threaded into\n * each Collection (via Vault) so `put`/`delete` can `track()` writes.\n * Not part of the public surface — consumers use `writeQueue`.\n */\n get _writeQueueTracker(): WriteQueueTracker {\n return this.writeQueueTracker\n }\n\n /**\n * Register a hook that runs before each write. Awaited; a throw\n * aborts the write. Returns an unsubscribe function.\n */\n onBeforeWrite(handler: WriteHook): Unsubscribe {\n return this.writeHooks.onBeforeWrite(handler)\n }\n\n /**\n * Register a hook that runs after each committed write. Awaited;\n * a handler error is warned, never rolled back. Returns an unsubscribe fn.\n */\n onAfterWrite(handler: WriteHook): Unsubscribe {\n return this.writeHooks.onAfterWrite(handler)\n }\n\n /** Subscribe to cross-tab write conflicts. Returns an unsubscribe. */\n onWriteConflict(fn: (c: WriteConflict) => void): Unsubscribe {\n this.on('write:conflict', fn)\n return () => this.off('write:conflict', fn)\n }\n\n /**\n * Enable same-device multi-tab coordination: primary/secondary\n * election + presence. Browser-only — a graceful no-op (role 'unknown')\n * when Web Locks / BroadcastChannel are unavailable and nothing is\n * injected. Idempotent; returns a disposer.\n */\n enableTabCoordination(opts: TabCoordinationOptions = {}): { dispose: () => void } {\n if (this.tabCoordinator) return { dispose: () => this.disableTabCoordination() }\n const lockManager = opts.lockManager ?? defaultLockManager()\n const channel = opts.channel ?? defaultChannel()\n const c = new TabCoordinator({\n ...opts,\n ...(lockManager ? { lockManager } : {}),\n ...(channel ? { channel } : {}),\n // We own the channel only when we created the default; never close a caller-injected one.\n closeChannelOnDispose: opts.channel === undefined && channel !== undefined,\n })\n this.tabCoordinator = c\n c.start()\n if (opts.propagateWrites !== false) {\n const writeChannel = opts.writeChannel ?? defaultChannel('noydb:tab-writes')\n if (writeChannel) {\n const relay = new CrossTabWriteRelay({\n channel: writeChannel,\n writerId: c.tabId,\n subscribeAfterWrite: (h) => this.onAfterWrite(h),\n applyRemoteWrite: (vault, collection, docId, action) => this.#applyRemoteWrite(vault, collection, docId, action),\n reportConflict: (vault, collection, docId, action, baseV, v, ownV) => this.#reportWriteConflict(vault, collection, docId, action, baseV, v, ownV),\n // Own the channel only when we created the default (mirrors the presence channel).\n closeChannelOnDispose: opts.writeChannel === undefined && writeChannel !== undefined,\n })\n this.writeRelay = relay\n relay.start()\n }\n }\n return { dispose: () => this.disableTabCoordination() }\n }\n\n #applyRemoteWrite(vaultName: string, collectionName: string, docId: string, action: 'put' | 'delete'): Promise<void> {\n const v = this.vaultCache.get(vaultName)\n if (!v) return Promise.resolve()\n return v._applyRemoteWrite(collectionName, docId, action)\n }\n\n async #reportWriteConflict(vaultName: string, collectionName: string, docId: string, action: 'put' | 'delete', baseV: number, v: number, ownV: number): Promise<void> {\n const vault = this.vaultCache.get(vaultName)\n if (!vault) return\n const cap = await vault._captureAndConverge(collectionName, docId, action, baseV)\n if (!cap) return\n const conflict: WriteConflict = {\n vault: vaultName, collection: collectionName, docId,\n local: cap.local, remote: cap.remote, base: cap.base,\n localVersion: ownV, remoteVersion: v, baseVersion: baseV,\n }\n this.emitter.emit('write:conflict', conflict)\n }\n\n private disableTabCoordination(): void {\n this.tabCoordinator?.dispose()\n this.tabCoordinator = undefined\n this.writeRelay?.dispose()\n this.writeRelay = undefined\n }\n\n get tabRole(): TabRole { return this.tabCoordinator?.role ?? 'unknown' }\n activeTabs(): TabPresence[] { return this.tabCoordinator?.activeTabs() ?? [] }\n onTabRoleChange(fn: (r: TabRole) => void): Unsubscribe { return this.tabCoordinator?.onTabRoleChange(fn) ?? (() => {}) }\n onActiveTabsChange(fn: (t: TabPresence[]) => void): Unsubscribe { return this.tabCoordinator?.onActiveTabsChange(fn) ?? (() => {}) }\n\n /** @internal The write-hook registry, threaded into each Collection. */\n get _writeHooks(): WriteHookRegistry {\n return this.writeHooks\n }\n\n /** @internal The observe bus, threaded into every Collection. */\n get _subsystemBus(): SubsystemBus {\n return this.subsystemBus\n }\n\n /** @internal Stable per-instance id for schema-cutover coordination. */\n get _clientId(): string {\n return this.clientId\n }\n\n /**\n * Soft-lock a single vault: clear its in-memory keyring, DEKs, vault\n * instance, sync engine, policy enforcer, and active-tier entry —\n * WITHOUT destroying the `Noydb` instance.\n *\n * Designed for \"lock screen\" UX: the user taps **Lock** and DEKs are\n * scrubbed from memory immediately, but the same `Noydb` instance can\n * be re-unlocked via {@link unlockViaAuthenticator} (tier 2) or\n * {@link unlockViaPin} (tier 3) without re-running `createNoydb`.\n *\n * **QuickUnlock state is preserved.** That's the whole point — the\n * user can still resume via PIN without a full credential re-prompt.\n * The on-disk `_meta/policy` document is also kept in cache (it\n * survives lock; nothing about it changes when DEKs are scrubbed).\n *\n * No-op when `vault` is not currently in cache (idempotent).\n */\n lockVault(vault: string): void {\n // Sync engine: stop autosync + drop the engine so the next openVault\n // builds a fresh one against the freshly-loaded keyring.\n this.syncEngines.get(vault)?.stopAutoSync()\n this.syncEngines.delete(vault)\n // Policy enforcer: cancels its idle timer and any visibility listener.\n this.policyEnforcers.get(vault)?.destroy()\n this.policyEnforcers.delete(vault)\n // Live caches: scrub DEKs, vault instance, active tier.\n this.vaultCache.get(vault)?._stopFenceCoordination() // stop heartbeat/watcher timers\n this.keyringCache.delete(vault)\n this.vaultCache.delete(vault)\n this.activeTier.delete(vault)\n // Intentionally NOT cleared:\n // - this.quickUnlock — preserves PIN resume.\n // - this.policyCache — vault policy is on-disk data, survives lock.\n // - this.sessionStrategy — no per-vault revoke; close() handles bulk.\n }\n\n close(): void {\n this.closed = true\n this.snapshotScheduler?.stop()\n this.snapshotScheduler = null\n if (this.sessionTimer) {\n clearTimeout(this.sessionTimer)\n this.sessionTimer = null\n }\n // Destroy all policy enforcers (cancels timers + visibility listeners)\n for (const enforcer of this.policyEnforcers.values()) {\n enforcer.destroy()\n }\n this.policyEnforcers.clear()\n // Revoke all in-memory session keys\n this.sessionStrategy.revokeAllSessions()\n // Stop all sync engines\n for (const engine of this.syncEngines.values()) {\n engine.stopAutoSync()\n }\n this.syncEngines.clear()\n for (const v of this.vaultCache.values()) v._stopFenceCoordination() // stop heartbeat/watcher timers\n this.disableTabCoordination() // stop tab lock/heartbeat timers\n this.keyringCache.clear()\n this.vaultCache.clear()\n this.activeTier.clear()\n this.policyCache.clear()\n this.quickUnlock.clear()\n this.emitter.removeAllListeners()\n // Clear translator state — same lifetime as KEK/DEKs\n this.translatorCache.clear()\n this._translatorAuditLog.length = 0\n }\n\n /**\n * Returns a snapshot of all translator invocations since the last\n * `close()`. Useful for testing and compliance auditing. The log is\n * in-memory only — it is cleared when `db.close()` is called.\n *\n * Entries deliberately omit content hashes. See `TranslatorAuditEntry`\n * and issue for the rationale.\n */\n translatorAuditLog(): readonly TranslatorAuditEntry[] {\n return [...this._translatorAuditLog]\n }\n\n /**\n * Invoke the configured `plaintextTranslator` (or serve from cache).\n * Records one `TranslatorAuditEntry` per call regardless of cache hit.\n * Called by `Vault` during `put()` for `autoTranslate: true` fields.\n *\n * @internal — not part of the public API surface\n */\n async invokeTranslator(\n text: string,\n from: string,\n to: string,\n field: string,\n collection: string,\n ): Promise<string> {\n const cacheKey = `${field}\\x00${collection}\\x00${from}\\x00${to}\\x00${text}`\n const translatorName = this.options.plaintextTranslatorName ?? 'anonymous'\n\n const cached = this.translatorCache.get(cacheKey)\n if (cached !== undefined) {\n this._translatorAuditLog.push({\n type: 'translator-invocation',\n field,\n collection,\n fromLocale: from,\n toLocale: to,\n translatorName,\n timestamp: new Date().toISOString(),\n cached: true,\n })\n return cached\n }\n\n const result = await this.options.plaintextTranslator!({ text, from, to, field, collection })\n this.translatorCache.set(cacheKey, result)\n this._translatorAuditLog.push({\n type: 'translator-invocation',\n field,\n collection,\n fromLocale: from,\n toLocale: to,\n translatorName,\n timestamp: new Date().toISOString(),\n })\n return result\n }\n\n // ─── Policy gates (issue #9) ──────────────────────────────────\n /**\n * Read the active policy for a vault. Loads from `_meta/policy` on\n * first call; subsequent calls hit the in-memory cache. Throws\n * `ValidationError` if the vault has not been opened.\n */\n async getPolicy(vault: string): Promise<VaultPolicy> {\n if (this.closed) throw new ValidationError('Instance is closed')\n const cached = this.policyCache.get(vault)\n if (cached) return cached\n await this.bootstrapPolicy(vault)\n return this.policyCache.get(vault) ?? PERSONAL_POLICY\n }\n\n /**\n * Replace the policy document at `_meta/policy` and update the\n * in-memory cache. Gated by the `enroll-user` policy (a policy\n * change is fundamentally a privilege-management action).\n */\n async updatePolicy(vault: string, override: Partial<VaultPolicy>): Promise<VaultPolicy> {\n if (this.closed) throw new ValidationError('Instance is closed')\n const current = await this.getPolicy(vault)\n const merged = mergePolicy(current, override)\n if (this.options.encrypt !== false) {\n await saveVaultPolicy(this.options.store, vault, merged)\n }\n this.policyCache.set(vault, merged)\n return merged\n }\n\n /**\n * Read the current vault-level user-directory toggle. Returns\n * the default-on shape (`{ enabled: true }`) when no `_meta/directory`\n * document has been persisted yet.\n *\n * No role gate — anyone who can open the vault can read the toggle.\n */\n async getDirectoryEnabled(vault: string): Promise<boolean> {\n if (this.closed) throw new ValidationError('Instance is closed')\n const persisted = await readDirectoryConfig(this.options.store, vault)\n return persisted?.enabled ?? true\n }\n\n /**\n * Toggle the vault's user-directory listing on or off.\n * Owner-only. When disabled, `listUsersWithEnvelopes()` throws\n * {@link import('./errors.js').DirectoryDisabledError} for callers\n * whose role is neither `owner` nor `admin`.\n *\n * Honest caveat: this is a UX flag, not a privacy guarantee. The\n * keyring file at `_keyring/<userId>` and the envelope ciphertext at\n * `_users/<keyringId>` remain observable to anyone with direct store\n * read access — only the hub-level enumeration is gated. See\n * `docs/subsystems/user-envelope.md` → \"Directory visibility\".\n */\n async setDirectoryEnabled(vault: string, enabled: boolean): Promise<void> {\n if (this.closed) throw new ValidationError('Instance is closed')\n const keyring = await this.getKeyringInternal(vault)\n if (keyring.role !== 'owner') {\n throw new PermissionDeniedError(\n `setDirectoryEnabled requires owner role; caller has role \"${keyring.role}\"`,\n )\n }\n await persistDirectoryConfig(this.options.store, vault, { enabled })\n }\n\n /**\n * Evaluate a policy gate against the active session tier and the\n * presented factor proofs. Throws {@link PolicyDeniedError} on\n * denial; resolves with `void` on success.\n *\n * @param vault The vault whose policy applies.\n * @param gate Gate name — built-in (e.g. `'rotate-passphrase'`)\n * or app-defined (`app:*`).\n * @param presented Caller-supplied factor proofs.\n */\n async checkGate(\n vault: string,\n gate: GateName,\n factors?: FactorProofBundle,\n ): Promise<void> {\n const policy = await this.getPolicy(vault)\n const tier = this.activeTier.get(vault) ?? 1\n await policyCheckGate(policy, gate, {\n activeTier: tier,\n ...(factors?.factors !== undefined ? { factors: factors.factors } : {}),\n ...(factors?.sharedDevice !== undefined\n ? { sharedDevice: factors.sharedDevice }\n : {}),\n })\n }\n\n /** Read or persist the vault policy at `_meta/policy` on first open. */\n private async bootstrapPolicy(\n vault: string,\n opts?: { skipManagedCheck?: boolean },\n ): Promise<void> {\n const onDisk = await loadVaultPolicy(this.options.store, vault)\n if (onDisk) {\n // Honour the on-disk document; developer overrides cannot\n // weaken what the vault committed to at creation time.\n this.policyCache.set(vault, onDisk)\n await this.assertRecoveryEnrolled(vault, onDisk, opts)\n return\n }\n // First time — persist the developer's policy (or default preset).\n const initial = this.options.policy\n ? mergePolicy(PERSONAL_POLICY, this.options.policy)\n : PERSONAL_POLICY\n await saveVaultPolicy(this.options.store, vault, initial)\n this.policyCache.set(vault, initial)\n await this.assertRecoveryEnrolled(vault, initial, opts)\n }\n\n /**\n * Throw {@link RecoveryNotEnrolledError} or\n * {@link ManagedRecoveryNotEnrolledError} when recovery enrollment\n * is missing.\n *\n * Two enforcement modes:\n *\n * 1. **Managed-mode mandatory strong-recovery.** When\n * `passphraseMode === 'managed'`, the vault MUST have at least\n * one **strong** recovery profile (Shamir today). Paper alone is\n * rejected because under managed mode the user has no memorized\n * passphrase, so losing the paper sheet = losing every record.\n * This check is unconditional — independent of `requireRecovery`\n * and the `recover-passphrase` gate.\n *\n * 2. **Opt-in strict mandatory-recovery.** When\n * `requireRecovery: true` is set on createNoydb (and the gate is\n * not explicitly disabled), require ANY recovery profile (paper\n * or shamir). This is the v0.x default-off behavior; v1.0 may\n * flip it default-on.\n *\n * The managed-mode check fires from {@link bootstrapPolicy} unless\n * the `skipManagedCheck` flag is set (used by\n * {@link openVaultAndEnrollRecovery} to allow atomic create-and-enroll).\n */\n private async assertRecoveryEnrolled(\n vault: string,\n policy: VaultPolicy,\n opts?: { skipManagedCheck?: boolean },\n ): Promise<void> {\n const skipManaged = (opts?.skipManagedCheck ?? false) || this._skipNextManagedRecoveryCheck\n if (this.options.passphraseMode === 'managed' && !skipManaged) {\n const enrolled = await hasStrongRecoveryEnrolled(this.options.store, vault)\n if (!enrolled) {\n throw new ManagedRecoveryNotEnrolledError(vault)\n }\n }\n if (this.options.requireRecovery !== true) return\n const gate = policy.gates['recover-passphrase']\n if (gate?.enabled === false) return\n const enrolled = await hasRecoveryEnrolled(this.options.store, vault)\n if (enrolled) return\n throw new RecoveryNotEnrolledError()\n }\n\n /**\n * Internal accessor used by tier-2/tier-3 unlock paths\n * to mark the active session tier.\n * @internal\n */\n _setActiveTier(vault: string, tier: ActiveTier): void {\n this.activeTier.set(vault, tier)\n }\n\n // ─── Tier-2 enroll / remove ─────────────────────────────────────\n /**\n * Add a tier-2 authenticator slot to the calling user's keyring.\n * Each slot independently wraps the SAME KEK under a method-specific\n * key — adding a slot is a constant-time keyring write.\n *\n * The wrapping ciphertext is produced by the corresponding\n * `@noy-db/on-*` package (e.g. `enrollPasswordAuthenticator` from\n * `@noy-db/on-password`); the hub persists the result.\n *\n * Gated by `enroll-authenticator`; `presented` carries any factor\n * proofs the active policy demands.\n */\n async enrollAuthenticator(\n vault: string,\n options: EnrollAuthenticatorOptions,\n factors?: FactorProofBundle,\n ): Promise<void> {\n await this.checkGate(vault, 'enroll-authenticator', factors)\n const keyring = await this.getKeyringInternal(vault)\n const next = await keyringEnrollAuthenticator(this.options.store, vault, keyring, options)\n this.keyringCache.set(vault, next)\n }\n\n /**\n * Remove a tier-2 authenticator slot. Idempotent — removing a\n * non-existent slot is a successful no-op. Gated by\n * `remove-authenticator`.\n */\n async removeAuthenticator(\n vault: string,\n slotId: string,\n factors?: FactorProofBundle,\n ): Promise<void> {\n await this.checkGate(vault, 'remove-authenticator', factors)\n const keyring = await this.getKeyringInternal(vault)\n const next = await keyringRemoveAuthenticator(this.options.store, vault, keyring, slotId)\n this.keyringCache.set(vault, next)\n }\n\n /** Read the slot list for a vault. Internal — `describeAuthConfig` consumes this. */\n async listAuthenticators(vault: string): Promise<ReadonlyArray<KeyringAuthenticator>> {\n const keyring = await this.getKeyringInternal(vault)\n return keyring.authenticators\n }\n\n /**\n * Mutate the `meta` blob on an existing authenticator slot — slot\n * rename, label change, attachment of UI hints. The slot's `id`,\n * `method`, and wrap material (`wrapped_kek` / `wrapped_deks` + `iv`)\n * are immutable through this method. Anti-slot-swap is structural,\n * not gate-driven.\n *\n * `meta` patch semantics (top-level merge):\n * - Top-level merge — absent keys preserved\n * - `null` value — delete that meta key\n * - Other values — replace verbatim\n *\n * Use case: per-slot nickname for \"iPhone Touch ID\" vs \"MacBook\n * Touch ID\" disambiguation in admin UIs. The slot id (auto-derived\n * from credentialId prefix) is not human-friendly; `meta.nickname`\n * is.\n *\n * Gated by `update-authenticator`. PERSONAL_POLICY: tier-1 unlock\n * alone (matches enroll/remove). STRICT_POLICY: tier-1 +\n * TOTP/email-OTP factor proof — a malicious rename on a shared\n * workstation could mislead the user about which device a slot\n * corresponds to, so STRICT requires fresh factor binding.\n *\n * @throws `NoAccessError` when no slot with the given id exists.\n * @throws `ValidationError` when no patch field is provided.\n */\n async updateAuthenticator(\n vault: string,\n slotId: string,\n options: UpdateAuthenticatorOptions,\n factors?: FactorProofBundle,\n ): Promise<void> {\n await this.checkGate(vault, 'update-authenticator', factors)\n const keyring = await this.getKeyringInternal(vault)\n const next = await keyringUpdateAuthenticator(this.options.store, vault, keyring, slotId, options)\n this.keyringCache.set(vault, next)\n }\n\n /**\n * Native WebAuthn enrollment using the **real** internal keyring.\n *\n * Why this exists: when a consumer is using `createNoydb({ secret })`,\n * they cannot reach the live `UnlockedKeyring` to feed it to\n * `enrollWebAuthn(keyring, vault, opts)` from `@noy-db/on-webauthn`.\n * Constructing a synthetic keyring (the previous workaround) produces\n * a slot whose `wrapped_kek` references the synthetic payload, not\n * the live session — so `unlockViaAuthenticator()` later replaces the\n * live DEK map with stale wrapped DEKs and every decrypt fails.\n *\n * This method runs `ceremony` with the REAL keyring (still in\n * `keyringCache`). The ceremony performs the WebAuthn enrollment and\n * returns the slot options that hub then persists via the standard\n * tier-2 enrollAuthenticator path.\n *\n * Layering note: hub does not import `@noy-db/on-webauthn` (that\n * would invert the dep graph). The consumer wires it in:\n *\n * ```ts\n * import { enrollWebAuthn } from '@noy-db/on-webauthn'\n *\n * await db.enrollWebAuthn('demo', async (keyring) => {\n * const e = await enrollWebAuthn(keyring, 'demo', { rp: {...} })\n * return {\n * id: `webauthn-${e.credentialId.slice(0, 8)}`,\n * method: 'webauthn',\n * wrapped_kek: e.wrappedPayload,\n * meta: {\n * credentialId: e.credentialId,\n * wrapIv: e.wrapIv,\n * prfUsed: e.prfUsed,\n * beFlag: e.beFlag,\n * requireSingleDevice: e.requireSingleDevice,\n * },\n * }\n * })\n * ```\n *\n * Returns the WebAuthn `credentialId` (extracted from `meta.credentialId`)\n * for the caller's lookup index (a bootstrap vault, a PublicEnvelope,\n * a server-side allowlist).\n *\n * Gated by `enroll-authenticator` like `enrollAuthenticator()` itself.\n */\n async enrollWebAuthn(\n vault: string,\n ceremony: (keyring: UnlockedKeyring) => Promise<EnrollAuthenticatorOptions>,\n factors?: FactorProofBundle,\n ): Promise<{ credentialId: string }> {\n await this.checkGate(vault, 'enroll-authenticator', factors)\n const keyring = await this.getKeyringInternal(vault)\n const slotOptions = await ceremony(keyring)\n if (slotOptions.method !== 'webauthn') {\n throw new ValidationError(\n `enrollWebAuthn: ceremony returned method \"${slotOptions.method}\"; expected \"webauthn\". ` +\n 'Use db.enrollAuthenticator() for non-webauthn methods.',\n )\n }\n const credentialId = (slotOptions.meta as { credentialId?: unknown }).credentialId\n if (typeof credentialId !== 'string' || credentialId.length === 0) {\n throw new ValidationError(\n 'enrollWebAuthn: ceremony result must include `meta.credentialId` (base64 string). ' +\n 'See @noy-db/on-webauthn enrollWebAuthn() return shape.',\n )\n }\n const next = await keyringEnrollAuthenticator(this.options.store, vault, keyring, slotOptions)\n this.keyringCache.set(vault, next)\n return { credentialId }\n }\n\n /**\n * Filter the slot list to webauthn-method slots only. Useful for\n * \"you have N WebAuthn credentials enrolled\" UI surfaces and for\n * deciding when a new device prompt should appear. Identity is\n * `id` + `enrolled_at`; the `meta.credentialId` (base64) is used by\n * `allowCredentials` at unlock time.\n */\n async listWebAuthnSlots(vault: string): Promise<ReadonlyArray<{\n id: string\n enrolledAt: string\n credentialId: string\n }>> {\n const keyring = await this.getKeyringInternal(vault)\n return keyring.authenticators\n .filter((a) => a.method === 'webauthn')\n .map((a) => {\n const credentialId = (a.meta as { credentialId?: unknown }).credentialId\n return {\n id: a.id,\n enrolledAt: a.enrolled_at,\n credentialId: typeof credentialId === 'string' ? credentialId : '',\n }\n })\n }\n\n /**\n * Resolve a slot by id, then hand the wrapped-KEK ciphertext + meta\n * to the caller-supplied verifier. The verifier is the\n * `unlockWith*` function from the corresponding `@noy-db/on-*`\n * package, e.g. `unlockWithPassword(slot, password)`.\n *\n * On success, mark the active session tier as 2 — subsequent\n * `checkGate` calls see a tier-2 unlock.\n */\n async unlockViaAuthenticator(\n vault: string,\n slotId: string,\n verify: (slot: KeyringAuthenticator) => Promise<UnlockedKeyring>,\n ): Promise<UnlockedKeyring> {\n const keyring = await this.getKeyringInternal(vault)\n const slot = findAuthenticator(keyring, slotId)\n if (!slot) {\n throw new ValidationError(\n `unlockViaAuthenticator: no slot with id \"${slotId}\" in vault \"${vault}\".`,\n )\n }\n const unlocked = await verify(slot)\n this.keyringCache.set(vault, unlocked)\n this.activeTier.set(vault, 2)\n return unlocked\n }\n\n // ─── Public envelope (docs/subsystems/public-envelope.md) ──────\n /**\n * Set the owner-curated public envelope for a vault. Throws\n * `ValidationError` if the developer did not opt the hub into\n * `publicEnvelope` via `NoydbOptions`, or if the input violates\n * the resolved schema (oversized icon, disallowed MIME, oversized\n * string, unknown field).\n *\n * `createdAt` is set on the first write and preserved on every\n * subsequent write. `updatedAt` is refreshed on every write.\n * `version` is monotonic — increments on every successful write.\n */\n async setPublicEnvelope(\n vault: string,\n input: SetPublicEnvelopeInput,\n ): Promise<PublicEnvelope> {\n if (!this.publicEnvelopeSchema) {\n throw new ValidationError(\n 'setPublicEnvelope: the public-envelope feature is not enabled. ' +\n 'Pass `publicEnvelope: true` (or a schema object) to `createNoydb`.',\n )\n }\n validatePublicEnvelopeInput(input, this.publicEnvelopeSchema)\n\n const now = new Date().toISOString()\n const existing = await loadPublicEnvelope(this.options.store, vault)\n const next: PublicEnvelope = {\n _noydb_public: 1,\n version: (existing?.version ?? 0) + 1,\n ...(existing?.createdAt !== undefined ? { createdAt: existing.createdAt } : { createdAt: now }),\n updatedAt: now,\n ...(input.name !== undefined ? { name: input.name } : (existing?.name !== undefined ? { name: existing.name } : {})),\n ...(input.description !== undefined ? { description: input.description } : (existing?.description !== undefined ? { description: existing.description } : {})),\n ...(input.icon !== undefined ? { icon: input.icon } : (existing?.icon !== undefined ? { icon: existing.icon } : {})),\n ...(input.defaultLocale !== undefined ? { defaultLocale: input.defaultLocale } : (existing?.defaultLocale !== undefined ? { defaultLocale: existing.defaultLocale } : {})),\n }\n await savePublicEnvelope(this.options.store, vault, next)\n return next\n }\n\n /**\n * Read the public envelope for a vault. Returns `undefined` when\n * none has been written. Pass `locale` to resolve any locale-map\n * fields to plain strings; omitting `locale` returns the raw map.\n *\n * Works even when the developer didn't enable\n * `publicEnvelope` — reads are passive and never throw on a\n * missing schema (the envelope is plaintext and exists on disk\n * regardless).\n */\n async getPublicEnvelope(\n vault: string,\n opts: { readonly locale?: string } = {},\n ): Promise<PublicEnvelope | undefined> {\n return fnReadPublicEnvelope(this.options.store, vault, opts)\n }\n\n // ─── Auth introspection ─────────────────────────────────────────\n /** English summary of the configured auth model. */\n async describeAuthConfig(vault: string): Promise<string> {\n return fnDescribeAuthConfig(this.options.store, vault)\n }\n\n /** Mermaid `flowchart TB` source for the auth graph. */\n async diagramAuthConfig(vault: string): Promise<string> {\n return fnDiagramAuthConfig(this.options.store, vault)\n }\n\n /**\n * Per-user enrollment summary. Gated by `view-user-auth` (default:\n * disabled). Sanitization is allowlist-based — never renders cred\n * ids, password hashes, secrets, or any field outside the allowlist.\n */\n async describeUserAuth(\n vault: string,\n userId: string,\n factors?: FactorProofBundle,\n ): Promise<string> {\n await this.checkGate(vault, 'view-user-auth', factors)\n return fnDescribeUserAuth(this.options.store, vault, userId)\n }\n\n /** Bulk variant for owner dashboards. Gated by `view-user-auth`. */\n async describeAllUsersAuth(\n vault: string,\n factors?: FactorProofBundle,\n ): Promise<Array<{ userId: string; description: string }>> {\n await this.checkGate(vault, 'view-user-auth', factors)\n return fnDescribeAllUsersAuth(this.options.store, vault)\n }\n\n // ─── Tier-1 change flows ────────────────────────────────────────\n /**\n * Rotate the user's passphrase (user remembers old). Validates the\n * new phrase against the configured `passphrase` policy, runs the\n * `rotate-passphrase` gate, then re-derives + re-wraps every DEK.\n *\n * Tier-2 authenticator slots are dropped — each slot wraps the old\n * KEK and would need its derivation key to be re-presented. Re-enrol\n * via `db.enrollAuthenticator` after rotation.\n *\n * @throws `WeakPassphraseError` on a weak new phrase.\n * @throws `PolicyDeniedError` when the gate denies (missing factor, …).\n * @throws `InvalidKeyError` when `oldPassphrase` is wrong.\n */\n async rotatePassphrase(\n vault: string,\n input: RotatePassphraseInput,\n factors?: FactorProofBundle,\n ): Promise<void> {\n // Managed-passphrase mode: the user does NOT know the\n // current passphrase (hub generated it and sealed it under the\n // provider). Manual rotation via this method is impossible by\n // construction — surface a clear error rather than fail mid-way\n // with InvalidKeyError once `oldPassphrase` doesn't match the\n // hub-generated one. Recovery-under-managed (which mints a fresh\n // sealed passphrase via the provider) is the supported path; it\n // lands in a follow-up.\n if (this.options.passphraseMode === 'managed') {\n throw new PolicyDeniedError(\n 'rotate-passphrase',\n 'disabled',\n { minTier: 1, enabled: false },\n 'Managed-passphrase mode (#14): the passphrase is hub-generated '\n + 'and sealed under the SealingKeyProvider — there is no '\n + 'plaintext to rotate. Use the recovery flow (follow-up issue) '\n + 'to mint a fresh sealed passphrase.',\n )\n }\n await this.checkGate(vault, 'rotate-passphrase', factors)\n const userId = this.options.user\n const next = await keyringRotatePassphrase(this.options.store, vault, userId, input)\n this.keyringCache.set(vault, next)\n }\n\n /**\n * Reset the passphrase using a recovery proof (user forgot the old).\n * Currently supports the `'paper'` profile end-to-end; the\n * other profiles throw {@link RecoveryProfileNotImplementedError}.\n *\n * Burns the used recovery entry on success.\n */\n async recoverPassphrase(\n vault: string,\n input: RecoverPassphraseInput,\n factors?: FactorProofBundle,\n ): Promise<RecoverPassphraseResult> {\n await this.checkGate(vault, 'recover-passphrase', factors)\n const userId = this.options.user\n\n // Snapshot the entries BEFORE recovery — the team function burns\n // exactly one entry, so post-recovery `_meta/recovery-paper`\n // contains `entriesBeforeRecovery.length - 1` entries (the ones\n // the user did NOT just consume). Those are what we replace\n // under the auto-rotation logic.\n const entriesBeforeRecovery = await loadPaperRecoveryEntries(this.options.store, vault)\n\n const next = await keyringRecoverPassphrase(this.options.shamirRecovery, this.options.store, vault, userId, input)\n this.keyringCache.set(vault, next)\n\n const rotateRemaining = input.rotateRemainingCodes ?? true\n const remainingAfterBurn = Math.max(0, entriesBeforeRecovery.length - 1)\n if (!rotateRemaining || remainingAfterBurn === 0) {\n return { newCodes: [] }\n }\n\n // Auto-rotate: replace the remaining entries with a fresh set\n // minted under the new keyring's DEKs. Wraps the same DEK set the\n // recovered keyring just got, so the new codes round-trip through\n // a future `db.recoverPassphrase` cleanly.\n //\n // If this step fails (store error mid-mint), we leave the existing\n // post-burn entries in place — the user falls back to the\n // fall back to prior behavior (remaining N-1 codes still valid). Strictly\n // safer than wiping then failing.\n const codeGen = input.codeGenerator ?? generateULID\n const newCodeCount = input.newCodeCount ?? remainingAfterBurn\n const codes: string[] = []\n const newEntries: PaperRecoveryEntry[] = []\n for (let i = 0; i < newCodeCount; i++) {\n const rawCode = codeGen()\n const entry = await mintPaperRecoveryEntry(next.deks, rawCode, generateULID())\n codes.push(rawCode)\n newEntries.push(entry)\n }\n // Single replace-all write — `savePaperRecoveryEntries` overwrites\n // `_meta/recovery-paper` atomically (one envelope `put`).\n await savePaperRecoveryEntries(this.options.store, vault, newEntries)\n\n return { newCodes: codes }\n }\n\n /**\n * Deliberate paper-recovery-code regeneration. User knows their\n * passphrase but wants a fresh sheet — they lost the printout or\n * suspect compromise of the off-site copy.\n *\n * Symmetric to {@link rotatePassphrase} for the recovery profile:\n * gated, audit-trackable, ergonomic. Replaces (not appends) the\n * paper sheet under `_meta/recovery-paper` in a single envelope `put`.\n *\n * Gated by the `rotate-recovery` policy gate:\n * - PERSONAL_POLICY: `{ minTier: 1 }` — knowing the passphrase\n * suffices, matching the lower-level flow's bar.\n * - STRICT_POLICY: `{ minTier: 1, factors: [{ anyOf: ['totp',\n * 'email-otp', 'webauthn-roaming'] }] }` — rotation is an\n * off-site-trust event; require an off-device factor so a\n * stolen unlocked laptop cannot silently mint a sheet for the\n * attacker.\n *\n * Defaults `count` to the existing sheet size so consumers aren't\n * surprised by a different code count. Explicit `count` overrides.\n *\n * @throws {@link RecoveryProfileNotImplementedError} when `profile`\n * is anything other than `'paper'` (v1 dispatch limit).\n * @throws {@link PolicyDeniedError} when the gate denies (missing\n * factor, tier mismatch, ...).\n * @throws on missing paper sheet — \"nothing to rotate\" surfaces as\n * an error rather than silently minting an entire new sheet.\n *\n * @example Default count + show-once UI\n * ```ts\n * const { newCodes } = await db.rotateRecovery('acme', { profile: 'paper' })\n * showCodesToUser(newCodes)\n * ```\n *\n * @example STRICT-policy site with TOTP factor proof\n * ```ts\n * await db.rotateRecovery(\n * 'acme',\n * { profile: 'paper', count: 10 },\n * { factors: [{ kind: 'totp', proof: '123456' }] },\n * )\n * ```\n */\n async rotateRecovery(\n vault: string,\n options: RotateRecoveryOptions,\n factors?: FactorProofBundle,\n ): Promise<RotateRecoveryResult> {\n if (options.profile === 'paper') {\n return this.rotateRecoveryPaper(vault, options, factors)\n }\n if (options.profile === 'shamir') {\n return this.rotateRecoveryShamir(vault, options, factors)\n }\n // Defense-in-depth for `as unknown as ...` bypass.\n throw new RecoveryProfileNotImplementedError(\n (options as { profile: string }).profile,\n '#196',\n )\n }\n\n private async rotateRecoveryPaper(\n vault: string,\n options: Extract<RotateRecoveryOptions, { profile: 'paper' }>,\n factors?: FactorProofBundle,\n ): Promise<RotateRecoveryResult> {\n await this.checkGate(vault, 'rotate-recovery', factors)\n\n const existing = await loadPaperRecoveryEntries(this.options.store, vault)\n if (existing.length === 0) {\n throw new Error(\n `db.rotateRecovery: no recovery codes are enrolled for vault \"${vault}\". ` +\n `Call db.enrollRecovery({ profile: 'paper', entries }) first; ` +\n `rotateRecovery replaces an existing sheet rather than minting one from scratch.`,\n )\n }\n\n const keyring = await this.getKeyring(vault)\n const codeGen = options.codeGenerator ?? generateULID\n const count = options.count ?? existing.length\n\n const codes: string[] = []\n const newEntries: PaperRecoveryEntry[] = []\n for (let i = 0; i < count; i++) {\n const rawCode = codeGen()\n const entry = await mintPaperRecoveryEntry(keyring.deks, rawCode, generateULID())\n codes.push(rawCode)\n newEntries.push(entry)\n }\n // Atomic replace — `savePaperRecoveryEntries` overwrites\n // `_meta/recovery-paper` in a single envelope `put`.\n await savePaperRecoveryEntries(this.options.store, vault, newEntries)\n\n return { newCodes: codes, entryId: 'paper-batch' }\n }\n\n private async rotateRecoveryShamir(\n vault: string,\n options: Extract<RotateRecoveryOptions, { profile: 'shamir' }>,\n factors?: FactorProofBundle,\n ): Promise<RotateRecoveryResult> {\n await this.checkGate(vault, 'rotate-recovery', factors)\n\n const existing = await loadShamirRecoveryEntries(this.options.store, vault)\n if (existing.length === 0) {\n throw new Error(\n `db.rotateRecovery: no Shamir recovery entry is enrolled for vault \"${vault}\". ` +\n `Call db.enrollRecovery({ profile: 'shamir', k, n }) first; ` +\n `rotateRecovery replaces an existing entry rather than minting one from scratch.`,\n )\n }\n\n // Pick which entry to rotate.\n let targetEntryId: string\n if (options.entryId !== undefined) {\n const found = existing.find(e => e.entryId === options.entryId)\n if (!found) {\n throw new Error(\n `db.rotateRecovery: no Shamir entry with entryId=\"${options.entryId}\" found `\n + `in vault \"${vault}\". Available: ${existing.map(e => `\"${e.entryId}\"`).join(', ')}.`,\n )\n }\n targetEntryId = options.entryId\n } else {\n if (existing.length > 1) {\n throw new Error(\n `db.rotateRecovery: vault \"${vault}\" has ${existing.length} Shamir entries `\n + `enrolled (${existing.map(e => `\"${e.entryId}\"`).join(', ')}). `\n + `Pass \\`entryId\\` to disambiguate which one to rotate; ambiguous rotation `\n + `would risk replacing the wrong entry.`,\n )\n }\n targetEntryId = existing[0]!.entryId\n }\n\n const keyring = await this.getKeyring(vault)\n const { entry, shareStrings } = await mintShamirRecoveryEntry(\n this.requireShamirProvider(),\n keyring.deks,\n targetEntryId,\n options.k,\n options.n,\n options.label,\n )\n\n // Atomic single-doc replace: drop the old entry, insert the new one.\n const next: ShamirRecoveryEntry[] = existing\n .filter(e => e.entryId !== targetEntryId)\n .concat(entry)\n await saveShamirRecoveryEntries(this.options.store, vault, next)\n\n return { newShares: shareStrings, entryId: targetEntryId }\n }\n\n /**\n * **Atomic create-and-enroll for managed-mode vaults.**\n *\n * Bootstraps a managed-mode vault and enrolls strong recovery in\n * a single ceremony. Under `passphraseMode: 'managed'`, every\n * `openVault` call requires a strong recovery profile (Shamir\n * today) to be enrolled — otherwise it throws\n * {@link ManagedRecoveryNotEnrolledError}. This method bypasses\n * the check temporarily so the keyring can be created, enrolls\n * the supplied recovery profile(s), then returns the vault.\n *\n * For Shamir enrollments, the show-once share strings come back\n * in `recoveryEnrollments[i].shares`. The hub never retains them\n * — the caller MUST display them to the user (once) before any\n * subsequent operation.\n *\n * Paper alone is NOT a strong profile under managed mode; passing\n * `{ profile: 'paper', ... }` without an accompanying shamir entry\n * is rejected at validation time.\n *\n * ```ts\n * const db = await createNoydb({\n * store, user: 'alice',\n * passphraseMode: 'managed',\n * sealingKey: macosKeychainSealingProvider({ ... }),\n * })\n *\n * const { vault, recoveryEnrollments } = await db.openVaultAndEnrollRecovery('acme', {\n * recovery: [{ profile: 'shamir', k: 2, n: 3 }],\n * })\n * for (const r of recoveryEnrollments) {\n * if (r.shares) showSharesToUser(r.shares) // ONCE\n * }\n * ```\n *\n * @throws ValidationError if recovery is empty, or contains no\n * strong profile under managed mode.\n */\n async openVaultAndEnrollRecovery(\n vault: string,\n opts: {\n readonly recovery: ReadonlyArray<RecoveryEnrollmentInput>\n readonly locale?: string\n },\n ): Promise<{\n readonly vault: Vault\n readonly recoveryEnrollments: ReadonlyArray<EnrollRecoveryResult>\n }> {\n if (opts.recovery.length === 0) {\n throw new ValidationError(\n 'openVaultAndEnrollRecovery: at least one recovery enrollment is required.',\n )\n }\n\n // Validate \"at least one strong\" when managed mode is on.\n if (this.options.passphraseMode === 'managed') {\n const hasStrong = opts.recovery.some(r => r.profile === 'shamir')\n if (!hasStrong) {\n throw new ValidationError(\n 'openVaultAndEnrollRecovery: managed-mode vaults require at least one strong '\n + 'recovery profile in the `recovery` array. Paper alone is not strong under '\n + 'managed mode (no user passphrase to fall back on). Include '\n + '{ profile: \"shamir\", k, n } in `recovery`.',\n )\n }\n }\n\n // Temporarily bypass the managed-mode strong-recovery check so\n // openVault can create the keyring. Recovery enrollment happens\n // inside this window; the check is restored at the end.\n this._skipNextManagedRecoveryCheck = true\n let vaultHandle: Vault\n try {\n vaultHandle = await this.openVault(vault, opts.locale !== undefined ? { locale: opts.locale } : undefined)\n } finally {\n this._skipNextManagedRecoveryCheck = false\n }\n\n // Enroll each recovery profile.\n const recoveryEnrollments: EnrollRecoveryResult[] = []\n for (const enrollment of opts.recovery) {\n recoveryEnrollments.push(await this.enrollRecovery(vault, enrollment))\n }\n\n // Belt-and-braces final check — by now, strong recovery must be on disk.\n if (this.options.passphraseMode === 'managed') {\n const policy = this.policyCache.get(vault)\n if (policy) {\n await this.assertRecoveryEnrolled(vault, policy)\n }\n }\n\n return { vault: vaultHandle, recoveryEnrollments }\n }\n\n /**\n * **Recovery flow under managed-passphrase mode.**\n *\n * Replaces the sealed passphrase of a managed-mode vault with a\n * fresh 256-bit random, sealed under the configured\n * `SealingKeyProvider`. The user never sees the new passphrase.\n *\n * Internally:\n * 1. Verify the recovery proof (Shamir today) and unwrap the\n * DEK set.\n * 2. Mint a fresh 256-bit random as the new effective passphrase.\n * 3. Rewrap the DEK set under a fresh KEK derived from the new\n * passphrase (via the existing `recoverPassphrase` path).\n * 4. Seal the random bytes under the provider and overwrite\n * `_meta/sealed-passphrase`.\n * 5. Drop the keyring cache so the next operation re-derives.\n *\n * The vault's strong-recovery enrollment is preserved across\n * recovery (Shamir entries are not burned on use).\n *\n * @throws ValidationError if the Noydb instance is not in managed mode.\n */\n async recoverManagedPassphrase(\n vault: string,\n options: {\n readonly recoveryProof: RecoveryProof\n readonly passphrasePolicy?: PassphrasePolicy\n },\n ): Promise<void> {\n if (this.options.passphraseMode !== 'managed') {\n throw new ValidationError(\n 'recoverManagedPassphrase: this method only applies to vaults opened '\n + 'in managed-passphrase mode. For standard mode, use db.recoverPassphrase.',\n )\n }\n const provider = this.options.sealingKey\n if (!provider) {\n throw new ValidationError(\n 'recoverManagedPassphrase: createNoydb({ passphraseMode: \"managed\" }) requires '\n + '`sealingKey` to be supplied; without it the new sealed passphrase cannot '\n + 'be persisted.',\n )\n }\n\n // Mint fresh 256-bit random; base64 it for use as the new\n // effective passphrase. AES-GCM auth-tag failures in the\n // managed-mode envelope catch tampering.\n const randomBytes = new Uint8Array(32)\n globalThis.crypto.getRandomValues(randomBytes)\n let binary = ''\n for (let i = 0; i < randomBytes.length; i++) binary += String.fromCharCode(randomBytes[i]!)\n const newPassphrase = btoa(binary)\n\n try {\n // Seal first; if the provider fails (KMS down, keychain locked),\n // we don't touch the keyring. Then run recoverPassphrase which\n // rewraps DEKs under the new KEK derived from the random bytes.\n const sealed = await provider.seal(randomBytes)\n await keyringRecoverPassphrase(\n this.options.shamirRecovery,\n this.options.store,\n vault,\n this.options.user,\n {\n newPassphrase,\n recoveryProof: options.recoveryProof,\n // The new passphrase IS 256 bits of random; policy gates on\n // length/entropy don't apply.\n allowWeakPassphrase: true,\n ...(options.passphrasePolicy !== undefined\n ? { passphrasePolicy: options.passphrasePolicy }\n : {}),\n },\n )\n // Update _meta/sealed-passphrase with the freshly sealed random.\n // The previous envelope is overwritten by saveSealedPassphrase.\n await saveSealedPassphrase(this.options.store, vault, {\n providerId: provider.id,\n sealed,\n })\n } finally {\n // Best-effort zero of the in-memory random buffer.\n randomBytes.fill(0)\n }\n\n // Drop the keyring cache so the next openVault re-derives from\n // the new sealed envelope.\n this.keyringCache.delete(vault)\n }\n\n /**\n * Atomic peer-recovery — re-wraps an EXISTING user's keyring under\n * a fresh temp passphrase in a single store write. Closes the\n * partial-failure window (the previous compose-from-primitives\n * pattern was `db.revoke + db.grant`, two writes — if the issuer\n * cancelled between them the target was locked out entirely).\n *\n * Different from `db.revoke + db.grant`:\n *\n * - Same `userId`, role, permissions, capabilities preserved.\n * - DEKs unchanged → every other principal in the vault keeps\n * access. No key rotation.\n * - Allows owner→owner natively. The existing\n * `db.revoke` retains its block — peer-recovery is a separate,\n * intentionally-named operation.\n * - Tier-2 slots dropped (they wrap the old KEK).\n *\n * Gated by `peer-recover-user`; `STRICT_POLICY` requires a\n * recovery / TOTP / email-OTP factor proof at the moment of\n * recovery, so the issuer affirmatively re-asserts identity.\n *\n * The recipient should call `db.rotatePassphrase` on first session\n * to choose their own phrase — the temp acts as a single-use\n * bridge.\n *\n * ```ts\n * await db.recoverUser('acme', {\n * userId: 'bob',\n * passphrase: 'temporary-correct-horse-battery-staple-printer',\n * }, { factors: [{ kind: 'recovery' }] })\n * // Bob opens createNoydb({ user: 'bob', secret: tempPhrase })\n * // and immediately calls db.rotatePassphrase to set his own.\n * ```\n *\n * @throws `NoAccessError` when no keyring exists for the target.\n * @throws `PermissionDeniedError` when the caller's role can't\n * recover the target's role (admin→owner is blocked even\n * under recovery).\n * @throws `PrivilegeEscalationError` when the caller lacks a DEK\n * the target previously had access to.\n *\n */\n async recoverUser(\n vault: string,\n options: RecoverUserOptions,\n factors?: FactorProofBundle,\n ): Promise<void> {\n await this.checkGate(vault, 'peer-recover-user', factors)\n const callerKeyring = await this.getKeyringInternal(vault)\n await keyringRecoverUser(this.options.store, vault, callerKeyring, options)\n // If the caller is recovering THEIR OWN keyring (rare but\n // possible — e.g. a self-recovery flow that bypasses the password\n // ceremony), the keyringCache entry is now stale. Drop it so the\n // next access reloads with the fresh wrapping.\n if (options.userId === this.options.user) {\n this.keyringCache.delete(vault)\n }\n }\n\n /**\n * Persist a recovery enrollment. Accepts the `'paper'`\n * profile.\n *\n * The hub wraps the user's DEK set (not the KEK) under a code-derived\n * AES-GCM key — see `team/recovery.ts` for the rationale. The mint\n * helper {@link mintPaperRecoveryEntry} is the canonical primitive;\n * pair it with `db.getKeyring(vault)` to obtain the live DEK set:\n *\n * ```ts\n * import { mintPaperRecoveryEntry } from '@noy-db/hub'\n *\n * const keyring = await db.getKeyring('acme')\n * const codes: string[] = ['CORRECT-HORSE-1', 'BATTERY-STAPLE-2', ...]\n * const entries = await Promise.all(\n * codes.map((code, i) => mintPaperRecoveryEntry(keyring.deks, code, `code-${i}`)),\n * )\n * await db.enrollRecovery('acme', { profile: 'paper', entries })\n * showCodesToUser(codes)\n * ```\n *\n * `@noy-db/on-recovery`'s `generateRecoveryCodeSet`\n * delegates to `mintPaperRecoveryEntry` internally — its output is\n * fed directly to this API. Pick whichever fits your code-gen layer:\n *\n * ```ts\n * import { generateRecoveryCodeSet } from '@noy-db/on-recovery'\n * const { codes, entries } = await generateRecoveryCodeSet({ deks: keyring.deks, count: 8 })\n * await db.enrollRecovery('acme', { profile: 'paper', entries })\n * ```\n */\n async enrollRecovery(\n vault: string,\n enrollment: RecoveryEnrollmentInput,\n ): Promise<EnrollRecoveryResult> {\n if (enrollment.profile === 'paper') {\n const existing = await loadPaperRecoveryEntries(this.options.store, vault)\n await savePaperRecoveryEntries(this.options.store, vault, [\n ...existing,\n ...enrollment.entries,\n ])\n // Paper enrollments don't have a single entryId — callers\n // pre-mint with their own ids. Return a stable sentinel so the\n // result type is consistent for both profiles.\n return { entryId: 'paper-batch' }\n }\n if (enrollment.profile === 'shamir') {\n const keyring = await this.getKeyring(vault)\n const entryId = enrollment.entryId ?? generateULID()\n const { entry, shareStrings } = await mintShamirRecoveryEntry(\n this.requireShamirProvider(),\n keyring.deks,\n entryId,\n enrollment.k,\n enrollment.n,\n enrollment.label,\n )\n const existing = await loadShamirRecoveryEntries(this.options.store, vault)\n // If a Shamir entry with this id already exists, replace it\n // (allows callers to be idempotent on `entryId`); otherwise append.\n const next: ShamirRecoveryEntry[] = existing.filter(e => e.entryId !== entryId).concat(entry)\n await saveShamirRecoveryEntries(this.options.store, vault, next)\n return { entryId, shares: shareStrings }\n }\n // Defense-in-depth for `as unknown as ...` bypass at the call site.\n throw new RecoveryProfileNotImplementedError(\n (enrollment as { profile: string }).profile,\n '#196',\n )\n }\n\n /** Read the persisted recovery entries (paper + Shamir). Used by `describeAuthConfig`. */\n async listRecoveryEntries(\n vault: string,\n ): Promise<{\n paper: ReadonlyArray<PaperRecoveryEntry>\n shamir: ReadonlyArray<ShamirRecoveryEntry>\n }> {\n const paper = await loadPaperRecoveryEntries(this.options.store, vault)\n const shamir = await loadShamirRecoveryEntries(this.options.store, vault)\n return { paper, shamir }\n }\n\n // ─── Tier-3 enroll / unlock ─────────────────────────────────────\n /**\n * Register a tier-3 quick-unlock state for the vault. The state is\n * an opaque blob produced by `@noy-db/on-pin/enrollPin` (or any\n * compatible primitive). It is held in memory only — never persisted\n * — and auto-clears when its `expiresAt` elapses.\n *\n * Gated by `rotate-unlock` (the same gate covers \"set\" and \"rotate\"\n * because tier-3 is a single-slot rolling secret).\n */\n async enrollUnlock(\n vault: string,\n state: QuickUnlockState,\n factors?: FactorProofBundle,\n ): Promise<void> {\n await this.checkGate(vault, 'rotate-unlock', factors)\n this.quickUnlock.set(vault, state)\n }\n\n /**\n * Resume a session via the registered tier-3 state. The verifier is\n * `@noy-db/on-pin/resumePin` (or compatible). On success, mark the\n * active session tier as 3 — every operation must re-authenticate at\n * tier 2 to elevate.\n *\n * Returns `undefined` (caller should fall back to tier 2) when no\n * tier-3 state is registered.\n */\n async unlockViaPin(\n vault: string,\n resume: (state: QuickUnlockState) => Promise<UnlockedKeyring>,\n ): Promise<UnlockedKeyring | undefined> {\n const state = this.quickUnlock.get(vault)\n if (!state) return undefined\n const keyring = await resume(state)\n this.keyringCache.set(vault, keyring)\n this.activeTier.set(vault, 3)\n return keyring\n }\n\n /** Drop the tier-3 state for a vault — explicit logout. */\n clearQuickUnlock(vault: string): void {\n this.quickUnlock.delete(vault)\n }\n\n /**\n * Public accessor for the unlocked keyring of a vault.\n *\n * Returns a **defensive shallow copy** so consumers can read the DEK\n * map and authenticator list without the risk of mutating the hub's\n * internal cache. Internal hub code paths use a live reference\n * via `getKeyringInternal`; ceremonies and external consumers always\n * get a snapshot.\n *\n * The CryptoKey values inside `deks` are not cloned — Web Crypto\n * keys are opaque handles, and a shared handle is intentional\n * (encrypt / decrypt go through the same key the cache holds).\n * Only the container Map / authenticator array is fresh.\n *\n * Used by `@noy-db/on-*` ceremonies that need the live DEK set\n * (paper recovery via {@link mintPaperRecoveryEntry}, tier-3 PIN\n * enrolment via on-pin's `enrollPin`, custom on-* ceremonies that\n * don't have a hub-side wrapper).\n *\n * No new permission gate — this is an accessor over already-unlocked\n * state. The keyring is materialized only after the calling session\n * has unlocked the vault at tier 1, 2, or 3, so exposing it does not\n * widen access. Throws `ValidationError` when encryption is enabled\n * and no `secret` / `getKeyring` is configured.\n *\n * ```ts\n * const keyring = await db.getKeyring('acme')\n * // keyring.deks: Map<collection, CryptoKey>\n * // keyring.kek: CryptoKey | null (null for tier-3 / wrap-DEKs sessions)\n * // keyring.role / .permissions / .authenticators\n * ```\n */\n async getKeyring(vault: string): Promise<UnlockedKeyring> {\n const live = await this.getKeyringInternal(vault)\n // Deep-ish defensive copy. Each container the consumer might\n // reasonably mutate is freshly cloned. CryptoKey handles inside\n // `deks` are intentionally shared — they're opaque references that\n // both encrypt and decrypt go through. `salt` (Uint8Array) is left\n // as-is: no realistic mutation path.\n return {\n ...live,\n deks: new Map(live.deks),\n permissions: { ...live.permissions },\n authenticators: live.authenticators.map((a) => ({\n ...a,\n meta: { ...a.meta },\n })),\n ...(live.policy !== undefined ? { policy: { ...live.policy } } : {}),\n ...(live.exportCapability !== undefined\n ? { exportCapability: { ...live.exportCapability } }\n : {}),\n ...(live.importCapability !== undefined\n ? { importCapability: { ...live.importCapability } }\n : {}),\n }\n }\n\n /**\n * Live-reference variant used by the hub's own code paths. Internal\n * mutations on `deks` (e.g. {@link ensureCollectionDEK} adding a\n * collection key) need to land on the cached keyring so subsequent\n * accesses see them. Not exposed publicly — callers outside hub\n * should use {@link getKeyring}, which returns a defensive copy.\n */\n private async getKeyringInternal(\n vault: string,\n opts: { create: boolean } = { create: true },\n ): Promise<UnlockedKeyring> {\n if (this.options.encrypt === false) {\n return createPlaintextKeyring(this.options.user)\n }\n\n const cached = this.keyringCache.get(vault)\n if (cached) return cached\n\n // Custom unlock path (e.g. WebAuthn / OIDC / Shamir): caller-supplied\n // callback owns \"open existing vs create new\" — no automatic NoAccessError\n // fallback because the callback owner has the UI context for that choice.\n if (this.options.getKeyring) {\n const keyring = await this.options.getKeyring(vault)\n this.keyringCache.set(vault, keyring)\n return keyring\n }\n\n // Pre-gate (#313): refuse to self-provision into a vault held by other\n // principals; create-on-open only for a genuinely-new vault. Runs BEFORE\n // resolveManagedSecret (which persists on first open) so a fail-closed open\n // writes nothing. encrypt:false returned a plaintext keyring above, so we're\n // always on the encrypted path here. Logic lives in team/keyring.ts.\n await assertKeyringOpenAllowed(this.options.store, vault, this.options.user, opts.create)\n\n // Managed-passphrase mode — resolve the effective secret\n // before falling into the normal load/create path. The first call\n // mints + seals + persists; subsequent calls unseal what's there.\n // The returned string takes the place of `options.secret` for the\n // rest of this method (and is NOT persisted on `this.options`).\n let effectiveSecret: string | undefined\n if (this.options.passphraseMode === 'managed') {\n // sealingKey presence was validated at createNoydb time.\n \n effectiveSecret = await resolveManagedSecret(\n this.options.store,\n vault,\n this.options.sealingKey!,\n )\n } else {\n effectiveSecret = this.options.secret\n }\n\n if (!effectiveSecret) {\n throw new ValidationError('A secret (passphrase) or getKeyring callback is required when encryption is enabled')\n }\n\n let keyring: UnlockedKeyring\n try {\n keyring = await loadKeyring(this.options.store, vault, this.options.user, effectiveSecret)\n } catch (err) {\n if (err instanceof NoAccessError) {\n // No keyring on disk — first boot or cleared store.\n keyring = await createOwnerKeyring(\n this.options.store,\n vault,\n this.options.user,\n effectiveSecret,\n {\n // Managed mode generates 256-bit base64 strings that don't satisfy\n // the human-passphrase strength rules (no spaces, no \"words\").\n // Skip validation in managed mode — the entropy floor is already\n // 256 bits by construction.\n validate: this.options.passphraseMode === 'managed'\n ? false\n : this.options.validatePassphrase === true,\n },\n )\n } else if (err instanceof InvalidKeyError && this.options.onInvalidKey === 'reset') {\n // Stale keyring: exists in the store but the current credentials can't\n // decrypt it (e.g. the data records were cleared while the _keyring row\n // survived, or a WebAuthn credential was rotated between sessions).\n // The caller opted into reset — delete the stale row and start fresh.\n await this.options.store.delete(vault, '_keyring', this.options.user)\n keyring = await createOwnerKeyring(\n this.options.store,\n vault,\n this.options.user,\n effectiveSecret,\n {\n validate: this.options.passphraseMode === 'managed'\n ? false\n : this.options.validatePassphrase === true,\n },\n )\n } else {\n throw err\n }\n }\n\n this.keyringCache.set(vault, keyring)\n return keyring\n }\n\n /**\n * Take an on-demand checkpoint of the given vault.\n * Requires `snapshotStrategy: withSnapshots({ store })` in `createNoydb`.\n * @throws ValidationError when the vault is not open\n */\n async snapshot(vault: string, opts?: { label?: string; note?: string }): Promise<SnapshotMeta> {\n if (this.closed) throw new ValidationError('Instance is closed')\n const v = this.vaultCache.get(vault)\n if (!v) {\n throw new ValidationError(\n `Vault \"${vault}\" is not open. Call openVault() first.`,\n )\n }\n return this.snapshotStrategy.snapshot(v, this.options.user, opts)\n }\n\n /**\n * Wire the automatic-snapshot cadence when a non-manual `snapshotPolicy` is\n * configured. Subscribes to `onAfterWrite` to mark the written vault dirty and\n * nudge the scheduler; the scheduler fires `autoSnapshot()` per dirty vault.\n * No-op for `mode:'manual'` or no policy.\n */\n private initSnapshotCadence(): void {\n const policy = this.snapshotStrategy.policy\n if (!policy || !policy.mode || policy.mode === 'manual') return\n\n const scheduler = new SnapshotScheduler(policy, {\n fire: async () => {\n const names = [...this.dirtySnapshotVaults]\n this.dirtySnapshotVaults.clear()\n for (const name of names) {\n const v = this.vaultCache.get(name)\n if (!v) continue\n try {\n await this.snapshotStrategy.autoSnapshot(v, this.options.user)\n } catch (err) {\n // Keep the vault pending so a later cadence tick (interval) or the\n // next write (debounce) retries; a failed auto-snapshot is logged,\n // never thrown (it runs inside the after-write hook contract).\n this.dirtySnapshotVaults.add(name)\n console.warn(\n `[noy-db] auto-snapshot failed for vault \"${name}\": ` +\n (err instanceof Error ? err.message : String(err)),\n )\n }\n }\n },\n pendingCount: () => this.dirtySnapshotVaults.size,\n })\n\n this.onAfterWrite((event) => {\n this.dirtySnapshotVaults.add(event.vault)\n scheduler.notifyChange()\n })\n scheduler.start()\n this.snapshotScheduler = scheduler\n }\n\n /**\n * List all snapshots for the given vault, newest first.\n * Reads only the sidecar index — does not download snapshot bytes.\n */\n async listSnapshots(vault: string): Promise<SnapshotMeta[]> {\n if (this.closed) throw new ValidationError('Instance is closed')\n return this.snapshotStrategy.listSnapshots(vault)\n }\n\n /**\n * Restore the vault to a previously snapshotted state.\n * Runs `verifyBackupIntegrity()` automatically on restore.\n * @throws SnapshotNotFoundError when `version` doesn't exist in the store\n * @throws ValidationError when the vault is not open\n */\n async restoreSnapshot(vault: string, version: string): Promise<void> {\n if (this.closed) throw new ValidationError('Instance is closed')\n const v = this.vaultCache.get(vault)\n if (!v) {\n throw new ValidationError(\n `Vault \"${vault}\" is not open. Call openVault() first.`,\n )\n }\n return this.snapshotStrategy.restoreSnapshot(v, version)\n }\n}\n\n/** Create a new NOYDB instance. */\nexport async function createNoydb(options: NoydbOptions): Promise<Noydb> {\n const encrypted = options.encrypt !== false\n const managed = options.passphraseMode === 'managed'\n\n if (options.secret && options.getKeyring) {\n throw new ValidationError('Provide either `secret` or `getKeyring`, not both')\n }\n\n // Managed-passphrase mode — mutually exclusive with both\n // `secret` (the whole point is hub generates and seals; the user\n // doesn't supply one) and `getKeyring` (a custom unlock path that\n // bypasses the sealing flow entirely). Requires a SealingKeyProvider.\n if (managed) {\n if (options.secret) {\n throw new ValidationError(\n '`passphraseMode: \"managed\"` is mutually exclusive with `secret` — '\n + 'managed mode generates the passphrase itself. Drop `secret`.',\n )\n }\n if (options.getKeyring) {\n throw new ValidationError(\n '`passphraseMode: \"managed\"` is mutually exclusive with `getKeyring` — '\n + 'a custom unlock callback would bypass the sealing flow. Drop `getKeyring`.',\n )\n }\n if (!options.sealingKey) {\n throw new ValidationError(\n '`passphraseMode: \"managed\"` requires `sealingKey: SealingKeyProvider` '\n + '(see @noy-db/seal-macos-keychain / @noy-db/seal-aws-kms / etc.).',\n )\n }\n }\n\n if (encrypted && !managed && !options.secret && !options.getKeyring) {\n throw new ValidationError('A secret (passphrase) or getKeyring callback is required when encryption is enabled')\n }\n\n return new Noydb(options)\n}\n\n// ─── Internal helpers ─────────────────────────────────────────────────\n\n/**\n * Normalize `NoydbOptions.sync` to a `SyncTarget[]`.\n * Accepts a bare NoydbStore, a SyncTarget, or an array.\n */\nfunction normalizeSyncTargets(\n sync: NoydbOptions['sync'],\n): SyncTarget[] {\n if (!sync) return []\n if (Array.isArray(sync)) return sync\n // SyncTarget has a `role` property; bare NoydbStore does not\n if ('role' in sync && typeof sync.role === 'string') {\n return [sync]\n }\n // Bare NoydbStore — wrap as sync-peer\n return [{ store: sync as NoydbStore, role: 'sync-peer' }]\n}\n"],"mappings":"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","names":["notEnabled","notEnabled","cached","version","cek","envelope","previousEnvelope","iv","data","NOT_ENABLED","NOT_ENABLED","checkGate","isPlainObject","META_COLLECTION","META_COLLECTION","ref","sha256Hex","record","handle","generateULID","readPublicEnvelope","NOT_ENABLED","NOT_ENABLED","notEnabled","keyring","comp","enrolled"]}
|