@noy-db/hub 0.3.0-pre.2 → 0.3.0-pre.3
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/adapter/index.d.ts +2 -2
- package/dist/adapter/index.js +1 -1
- package/dist/aggregate/index.d.ts +3 -3
- package/dist/aggregate/index.js +4 -4
- package/dist/api-LORZ2EZU.js +17 -0
- package/dist/as/index.d.ts +4 -4
- package/dist/as/index.js +9 -6
- package/dist/at/index.d.ts +2 -2
- package/dist/attestation/index.d.ts +3 -3
- package/dist/attestation/index.js +18 -15
- package/dist/attestation/index.js.map +1 -1
- package/dist/{backup-KMJQ66MF.js → backup-NGRJ46SH.js} +9 -6
- package/dist/{backup-KMJQ66MF.js.map → backup-NGRJ46SH.js.map} +1 -1
- package/dist/blobs/index.d.ts +4 -4
- package/dist/blobs/index.js +8 -5
- package/dist/blobs/index.js.map +1 -1
- package/dist/bundle/index.d.ts +5 -5
- package/dist/bundle/index.js +18 -15
- package/dist/bundle/index.js.map +1 -1
- package/dist/{bundle-PwBGkhpe.d.ts → bundle-B-P3_Jvb.d.ts} +1 -1
- package/dist/by/index.js +2 -2
- package/dist/cargo/index.d.ts +4 -4
- package/dist/cargo/index.js +20 -17
- package/dist/{chunk-Y22T3KQE.js → chunk-2KSPDSWI.js} +3 -3
- package/dist/{chunk-ITNUCOXM.js → chunk-2N4MUSF3.js} +7 -5
- package/dist/{chunk-ITNUCOXM.js.map → chunk-2N4MUSF3.js.map} +1 -1
- package/dist/{chunk-5N6CZTCY.js → chunk-2ZORB5RW.js} +3 -3
- package/dist/{chunk-FISN7WE4.js → chunk-3UDPDRUC.js} +4 -4
- package/dist/{chunk-TA66UMI4.js → chunk-46YGCU6Z.js} +2 -2
- package/dist/{chunk-IPB7FTQX.js → chunk-4DZGZ7II.js} +8 -6
- package/dist/{chunk-IPB7FTQX.js.map → chunk-4DZGZ7II.js.map} +1 -1
- package/dist/{chunk-SKF73JOP.js → chunk-4NMFWOS2.js} +3 -3
- package/dist/{chunk-IAGBDSCS.js → chunk-4NZCZUGL.js} +2 -2
- package/dist/{chunk-DFEMTNPJ.js → chunk-55HDKLI3.js} +8 -6
- package/dist/{chunk-DFEMTNPJ.js.map → chunk-55HDKLI3.js.map} +1 -1
- package/dist/{chunk-WWGT2MDV.js → chunk-5A6TC3RQ.js} +5 -5
- package/dist/{chunk-5O3AOPDT.js → chunk-5EZAJEES.js} +151 -432
- package/dist/chunk-5EZAJEES.js.map +1 -0
- package/dist/{chunk-62QYRORB.js → chunk-5Z3RNFJC.js} +3 -3
- package/dist/{chunk-M6OST55S.js → chunk-5ZPWVNL3.js} +2 -2
- package/dist/{chunk-PSMV73A5.js → chunk-6CNLU4TO.js} +5 -5
- package/dist/{chunk-QZISFCVG.js → chunk-6DP5HBQD.js} +11 -9
- package/dist/{chunk-QZISFCVG.js.map → chunk-6DP5HBQD.js.map} +1 -1
- package/dist/{chunk-AIWULCUO.js → chunk-6EVZXETK.js} +5 -3
- package/dist/{chunk-AIWULCUO.js.map → chunk-6EVZXETK.js.map} +1 -1
- package/dist/{chunk-GYGWYIOZ.js → chunk-6I2YPLAG.js} +7 -5
- package/dist/{chunk-GYGWYIOZ.js.map → chunk-6I2YPLAG.js.map} +1 -1
- package/dist/{chunk-SRB2XEWB.js → chunk-6OQ7NKMZ.js} +6 -4
- package/dist/{chunk-SRB2XEWB.js.map → chunk-6OQ7NKMZ.js.map} +1 -1
- package/dist/chunk-6RASM2J4.js +25 -0
- package/dist/chunk-6RASM2J4.js.map +1 -0
- package/dist/{chunk-5LUY7UTV.js → chunk-7IP75FP2.js} +2 -2
- package/dist/{chunk-HCIPRAGS.js → chunk-7MHVHGQZ.js} +2 -2
- package/dist/{chunk-PSHOXR6C.js → chunk-ADBMJDBW.js} +370 -83
- package/dist/chunk-ADBMJDBW.js.map +1 -0
- package/dist/{chunk-ZCGAHGUS.js → chunk-AY4P6PHN.js} +2 -2
- package/dist/{chunk-ZYUC53LT.js → chunk-BLZRNHMG.js} +51 -2
- package/dist/{chunk-ZYUC53LT.js.map → chunk-BLZRNHMG.js.map} +1 -1
- package/dist/{chunk-KXGNJJXB.js → chunk-BV7KNFJY.js} +7 -7
- package/dist/{chunk-BG3SPSR4.js → chunk-BYW7EU5L.js} +2 -2
- package/dist/{chunk-NF5JWERG.js → chunk-BZIWKN74.js} +2 -2
- package/dist/chunk-CPAROOKP.js +124 -0
- package/dist/chunk-CPAROOKP.js.map +1 -0
- package/dist/{chunk-AQTBSL7R.js → chunk-CVXLJIAV.js} +5 -5
- package/dist/{chunk-CWPPNPOH.js → chunk-DA34OEZU.js} +2 -2
- package/dist/{chunk-RUEKROOS.js → chunk-DGUR3CC4.js} +2 -2
- package/dist/{chunk-LXQT4WMP.js → chunk-DHIN36UC.js} +8 -6
- package/dist/{chunk-LXQT4WMP.js.map → chunk-DHIN36UC.js.map} +1 -1
- package/dist/{chunk-JNUWZ6D3.js → chunk-E4YJUNPU.js} +7 -5
- package/dist/{chunk-JNUWZ6D3.js.map → chunk-E4YJUNPU.js.map} +1 -1
- package/dist/{chunk-UV5MFVO3.js → chunk-FELHYKIO.js} +2 -2
- package/dist/{chunk-KVOXU4T5.js → chunk-HGQG3VIP.js} +2 -2
- package/dist/{chunk-XXYIOFUB.js → chunk-IIK7W3AN.js} +5 -5
- package/dist/{chunk-IGUYVGGI.js → chunk-IJW6K6UX.js} +3 -3
- package/dist/{chunk-76722EBH.js → chunk-IWVWB7BZ.js} +11 -9
- package/dist/{chunk-76722EBH.js.map → chunk-IWVWB7BZ.js.map} +1 -1
- package/dist/{chunk-QHJW5EXU.js → chunk-JFYIHLU3.js} +2 -2
- package/dist/chunk-L4IRFTIF.js +424 -0
- package/dist/chunk-L4IRFTIF.js.map +1 -0
- package/dist/{chunk-SM3AVUHC.js → chunk-LES2Z7B4.js} +2 -2
- package/dist/{chunk-IUEN57TV.js → chunk-LHYQE3BP.js} +4 -4
- package/dist/{chunk-V7RWQRG7.js → chunk-LKBLAUOB.js} +3 -3
- package/dist/{chunk-UDRIWL7A.js → chunk-MCJAUQGE.js} +3 -3
- package/dist/chunk-MIOLJG2R.js +105 -0
- package/dist/chunk-MIOLJG2R.js.map +1 -0
- package/dist/{chunk-UIU2THRG.js → chunk-N2FP26NH.js} +5 -5
- package/dist/{chunk-DGDI2D4M.js → chunk-NIA5VQ7G.js} +8 -6
- package/dist/{chunk-DGDI2D4M.js.map → chunk-NIA5VQ7G.js.map} +1 -1
- package/dist/{chunk-CMGR4ZEW.js → chunk-NMRKAGHE.js} +2 -2
- package/dist/{chunk-LV7M27WM.js → chunk-NPVICKZE.js} +4 -4
- package/dist/chunk-NTHKOFVL.js +195 -0
- package/dist/chunk-NTHKOFVL.js.map +1 -0
- package/dist/{chunk-IO6GRPT6.js → chunk-O5DNEXQC.js} +2 -2
- package/dist/{chunk-5TDJ56JE.js → chunk-OCDUQUAP.js} +1 -1
- package/dist/chunk-OCDUQUAP.js.map +1 -0
- package/dist/{chunk-UPJNJGGA.js → chunk-OVIVYAQL.js} +10 -8
- package/dist/{chunk-UPJNJGGA.js.map → chunk-OVIVYAQL.js.map} +1 -1
- package/dist/{chunk-I2NOIW44.js → chunk-P6DN5QU7.js} +8 -6
- package/dist/{chunk-I2NOIW44.js.map → chunk-P6DN5QU7.js.map} +1 -1
- package/dist/{chunk-Q7SS3IME.js → chunk-P6UXDALK.js} +3 -3
- package/dist/{chunk-UAG5KWVA.js → chunk-PJDK2PPQ.js} +3 -3
- package/dist/{chunk-AXRXJTE2.js → chunk-PUNJAEY6.js} +5 -5
- package/dist/{chunk-LFLXAY2W.js → chunk-PYWW4KLO.js} +9 -7
- package/dist/{chunk-LFLXAY2W.js.map → chunk-PYWW4KLO.js.map} +1 -1
- package/dist/{chunk-M2YKN37S.js → chunk-QLQS5A7X.js} +2 -2
- package/dist/{chunk-I3TIKTJO.js → chunk-TICO2I2O.js} +2 -2
- package/dist/{chunk-3YFXJ3ZP.js → chunk-U5DWHU3S.js} +2 -2
- package/dist/{chunk-26LGBE4T.js → chunk-U6OM4E67.js} +6 -4
- package/dist/{chunk-26LGBE4T.js.map → chunk-U6OM4E67.js.map} +1 -1
- package/dist/{chunk-TEILUWOI.js → chunk-UP6EMMDI.js} +10 -10
- package/dist/{chunk-SMXWYP24.js → chunk-VBYVKOMJ.js} +3 -3
- package/dist/{chunk-AZAOEIKW.js → chunk-VHEEU4ZO.js} +2 -2
- package/dist/{chunk-MD3Y6J3L.js → chunk-WVIIJPTJ.js} +7 -5
- package/dist/{chunk-MD3Y6J3L.js.map → chunk-WVIIJPTJ.js.map} +1 -1
- package/dist/{chunk-EIZUR2XW.js → chunk-XRE4JOEO.js} +2 -2
- package/dist/{chunk-VFQGRQIH.js → chunk-YDP2SA5K.js} +7 -5
- package/dist/{chunk-VFQGRQIH.js.map → chunk-YDP2SA5K.js.map} +1 -1
- package/dist/{chunk-5R3ERCDH.js → chunk-YN66UOXT.js} +3 -3
- package/dist/{chunk-IELYAOGG.js → chunk-YTIAXSUE.js} +4 -4
- package/dist/{chunk-TJYQIGAP.js → chunk-Z44OY24N.js} +3 -3
- package/dist/{chunk-VCTFO5CO.js → chunk-ZAWD6O46.js} +2 -2
- package/dist/{chunk-PKHL44ER.js → chunk-ZD4D7UM6.js} +2 -2
- package/dist/{chunk-MTMJVJ5W.js → chunk-ZFME46HJ.js} +5 -3
- package/dist/chunk-ZFME46HJ.js.map +1 -0
- package/dist/{chunk-LMTH2RM6.js → chunk-ZNI3RTFV.js} +2 -2
- package/dist/{chunk-WYSO2NIH.js → chunk-ZRDYQZYH.js} +2 -2
- package/dist/classified/index.d.ts +17 -0
- package/dist/classified/index.js +38 -0
- package/dist/collection-facade-XPVRHBGU.js +36 -0
- package/dist/consent/index.d.ts +3 -3
- package/dist/consent/index.js +7 -4
- package/dist/consent/index.js.map +1 -1
- package/dist/crdt/index.d.ts +3 -3
- package/dist/delegation-4HUHUE6T.js +22 -0
- package/dist/derivations/index.d.ts +4 -4
- package/dist/derivations/index.js +9 -6
- package/dist/describe/index.d.ts +1 -1
- package/dist/{describe-Ccd1hS7a.d.ts → describe-0tiXAjoO.d.ts} +10 -0
- package/dist/{dev-unlock-h0K-UZTk.d.ts → dev-unlock-B_s9DUWa.d.ts} +1 -1
- package/dist/{enclave-UL5LW66V.js → enclave-IS7HZSQ7.js} +34 -18
- package/dist/executor-ANFBCOYA.js +9 -0
- package/dist/executor-IKT47SH2.js +9 -0
- package/dist/executor-OIECZXTV.js +18 -0
- package/dist/export-accessible-NZWCFZHL.js +20 -0
- package/dist/extract-partition-52LX6RQH.js +33 -0
- package/dist/{fanout-sidecar-GF3DJ6KR.js → fanout-sidecar-DDKRG2MX.js} +14 -14
- package/dist/fanout-sidecar-DDKRG2MX.js.map +1 -0
- package/dist/forget/index.js +7 -4
- package/dist/forget/index.js.map +1 -1
- package/dist/guards/index.d.ts +4 -4
- package/dist/guards/index.js +3 -3
- package/dist/{hash-CdSr06sm.d.ts → hash-CWxn7sf6.d.ts} +7 -2
- package/dist/history/index.d.ts +4 -4
- package/dist/history/index.js +9 -6
- package/dist/history/index.js.map +1 -1
- package/dist/i18n/index.d.ts +3 -3
- package/dist/i18n/index.js +11 -8
- package/dist/i18n/index.js.map +1 -1
- package/dist/in/index.d.ts +2 -2
- package/dist/{index-_6At2_9_.d.ts → index-D05bV0_g.d.ts} +245 -5
- package/dist/{index-CGLLRtFc.d.ts → index-DTMUUwwW.d.ts} +3 -3
- package/dist/index.d.ts +30 -14
- package/dist/index.js +136 -75
- package/dist/index.js.map +1 -1
- package/dist/indexing/index.d.ts +3 -3
- package/dist/indexing/index.js +4 -4
- package/dist/issue-F4SYPJGJ.js +16 -0
- package/dist/kernel/index.d.ts +3 -3
- package/dist/kernel/index.js +10 -7
- package/dist/{ledger-RYI35CDS.js → ledger-YUAJUNFP.js} +9 -6
- package/dist/liberate-6LDETRIW.js +21 -0
- package/dist/materialized-views/index.d.ts +4 -4
- package/dist/materialized-views/index.js +13 -10
- package/dist/{mime-magic-B4RoFj3B.d.ts → mime-magic-Qr_4HjP6.d.ts} +1 -1
- package/dist/noydb-WQNBVJIG.js +54 -0
- package/dist/on/index.d.ts +2 -2
- package/dist/on/index.js +7 -4
- package/dist/overlay-views/index.d.ts +4 -4
- package/dist/overlay-views/index.js +4 -4
- package/dist/periods/index.d.ts +3 -3
- package/dist/periods/index.js +10 -7
- package/dist/pod/index.d.ts +3 -3
- package/dist/pod/index.js +9 -6
- package/dist/{policy-IXK4FVXP.js → policy-LRE6HTO5.js} +5 -5
- package/dist/portability/index.d.ts +3 -3
- package/dist/portability/index.js +8 -8
- package/dist/{public-envelope-JHDQCPSX.js → public-envelope-WVRRUVAJ.js} +4 -4
- package/dist/query/index.d.ts +2 -2
- package/dist/query/index.js +6 -6
- package/dist/registry-6HZ2JSQ7.js +14 -0
- package/dist/registry-GPXZQ7DT.js +9 -0
- package/dist/registry-USYD2ECC.js +16 -0
- package/dist/request-withdrawal-54V4L6CR.js +28 -0
- package/dist/reveal-WSUHXCSS.js +37 -0
- package/dist/reveal-WSUHXCSS.js.map +1 -0
- package/dist/revoke-JV26NTQD.js +21 -0
- package/dist/sealed-record/index.d.ts +3 -3
- package/dist/sealed-record/index.js +10 -7
- package/dist/sealed-record/index.js.map +1 -1
- package/dist/session/index.d.ts +4 -4
- package/dist/session/index.js +7 -4
- package/dist/session/index.js.map +1 -1
- package/dist/shadow/index.d.ts +3 -3
- package/dist/shadow/index.js +2 -2
- package/dist/{signer-PNKTBVF7.js → signer-AE56T5HE.js} +8 -5
- package/dist/snapshots/index.d.ts +3 -3
- package/dist/snapshots/index.js +8 -5
- package/dist/snapshots/index.js.map +1 -1
- package/dist/{stale-3JWHNDIY.js → stale-LX4BR43V.js} +2 -2
- package/dist/{store-coordination-provider-3I7XWZZK.js → store-coordination-provider-KTRIC6PR.js} +3 -3
- package/dist/sync/index.d.ts +2 -2
- package/dist/sync/index.js +7 -4
- package/dist/sync/index.js.map +1 -1
- package/dist/team/index.d.ts +3 -3
- package/dist/team/index.js +13 -10
- package/dist/tiers/index.d.ts +2 -2
- package/dist/tiers/index.js +8 -5
- package/dist/to/index.d.ts +2 -2
- package/dist/to/index.js +1 -1
- package/dist/{transition-guard-DqodPNKw.d.ts → transition-guard-C1Pyz8nH.d.ts} +1 -1
- package/dist/tx/index.d.ts +3 -3
- package/dist/tx/index.js +3 -3
- package/dist/ui/index.d.ts +1 -1
- package/dist/util/index.js +1 -1
- package/dist/validators-Dzn7T-3x.d.ts +62 -0
- package/dist/{vault-diff-BtpiBvic.d.ts → vault-diff-Fn0WeY2w.d.ts} +1 -1
- package/dist/verify-SW6J63Q2.js +135 -0
- package/dist/verify-SW6J63Q2.js.map +1 -0
- package/dist/with/index.d.ts +3 -3
- package/dist/with/index.js +9 -6
- package/dist/{with-materialized-view-DMmWtYfJ.d.ts → with-materialized-view-NKxs6iK5.d.ts} +1 -1
- package/dist/{with-overlayed-view-D_IB2nkM.d.ts → with-overlayed-view-B4fPYHwV.d.ts} +1 -1
- package/dist/{with-rollup-em2wxoHP.d.ts → with-rollup-Bl0sRFEt.d.ts} +1 -1
- package/dist/withdraw-accessible-DGA4V2TP.js +25 -0
- package/dist/withdraw-accessible-DGA4V2TP.js.map +1 -0
- package/package.json +7 -3
- package/dist/api-RW3KP7WU.js +0 -14
- package/dist/chunk-5O3AOPDT.js.map +0 -1
- package/dist/chunk-5TDJ56JE.js.map +0 -1
- package/dist/chunk-MTMJVJ5W.js.map +0 -1
- package/dist/chunk-PSHOXR6C.js.map +0 -1
- package/dist/collection-facade-GQAOGJP2.js +0 -33
- package/dist/delegation-UL5HKLER.js +0 -19
- package/dist/executor-2FWQRLMG.js +0 -15
- package/dist/executor-QZ7BXICW.js +0 -9
- package/dist/executor-Z5ZLJVTV.js +0 -9
- package/dist/export-accessible-KRV5W4GH.js +0 -17
- package/dist/extract-partition-GLKBOXFQ.js +0 -30
- package/dist/fanout-sidecar-GF3DJ6KR.js.map +0 -1
- package/dist/issue-Y6UVIR43.js +0 -13
- package/dist/liberate-CRPZEV7O.js +0 -18
- package/dist/noydb-LDEBLNHY.js +0 -50
- package/dist/registry-45RJNWGU.js +0 -9
- package/dist/registry-5GRV5VXI.js +0 -13
- package/dist/registry-WEUCHBO4.js +0 -11
- package/dist/request-withdrawal-GBPH2FDY.js +0 -25
- package/dist/revoke-TUFRGI6S.js +0 -18
- package/dist/withdraw-accessible-FFS46EOD.js +0 -22
- /package/dist/{api-RW3KP7WU.js.map → api-LORZ2EZU.js.map} +0 -0
- /package/dist/{chunk-Y22T3KQE.js.map → chunk-2KSPDSWI.js.map} +0 -0
- /package/dist/{chunk-5N6CZTCY.js.map → chunk-2ZORB5RW.js.map} +0 -0
- /package/dist/{chunk-FISN7WE4.js.map → chunk-3UDPDRUC.js.map} +0 -0
- /package/dist/{chunk-TA66UMI4.js.map → chunk-46YGCU6Z.js.map} +0 -0
- /package/dist/{chunk-SKF73JOP.js.map → chunk-4NMFWOS2.js.map} +0 -0
- /package/dist/{chunk-IAGBDSCS.js.map → chunk-4NZCZUGL.js.map} +0 -0
- /package/dist/{chunk-WWGT2MDV.js.map → chunk-5A6TC3RQ.js.map} +0 -0
- /package/dist/{chunk-62QYRORB.js.map → chunk-5Z3RNFJC.js.map} +0 -0
- /package/dist/{chunk-M6OST55S.js.map → chunk-5ZPWVNL3.js.map} +0 -0
- /package/dist/{chunk-PSMV73A5.js.map → chunk-6CNLU4TO.js.map} +0 -0
- /package/dist/{chunk-5LUY7UTV.js.map → chunk-7IP75FP2.js.map} +0 -0
- /package/dist/{chunk-HCIPRAGS.js.map → chunk-7MHVHGQZ.js.map} +0 -0
- /package/dist/{chunk-ZCGAHGUS.js.map → chunk-AY4P6PHN.js.map} +0 -0
- /package/dist/{chunk-KXGNJJXB.js.map → chunk-BV7KNFJY.js.map} +0 -0
- /package/dist/{chunk-BG3SPSR4.js.map → chunk-BYW7EU5L.js.map} +0 -0
- /package/dist/{chunk-NF5JWERG.js.map → chunk-BZIWKN74.js.map} +0 -0
- /package/dist/{chunk-AQTBSL7R.js.map → chunk-CVXLJIAV.js.map} +0 -0
- /package/dist/{chunk-CWPPNPOH.js.map → chunk-DA34OEZU.js.map} +0 -0
- /package/dist/{chunk-RUEKROOS.js.map → chunk-DGUR3CC4.js.map} +0 -0
- /package/dist/{chunk-UV5MFVO3.js.map → chunk-FELHYKIO.js.map} +0 -0
- /package/dist/{chunk-KVOXU4T5.js.map → chunk-HGQG3VIP.js.map} +0 -0
- /package/dist/{chunk-XXYIOFUB.js.map → chunk-IIK7W3AN.js.map} +0 -0
- /package/dist/{chunk-IGUYVGGI.js.map → chunk-IJW6K6UX.js.map} +0 -0
- /package/dist/{chunk-QHJW5EXU.js.map → chunk-JFYIHLU3.js.map} +0 -0
- /package/dist/{chunk-SM3AVUHC.js.map → chunk-LES2Z7B4.js.map} +0 -0
- /package/dist/{chunk-IUEN57TV.js.map → chunk-LHYQE3BP.js.map} +0 -0
- /package/dist/{chunk-V7RWQRG7.js.map → chunk-LKBLAUOB.js.map} +0 -0
- /package/dist/{chunk-UDRIWL7A.js.map → chunk-MCJAUQGE.js.map} +0 -0
- /package/dist/{chunk-UIU2THRG.js.map → chunk-N2FP26NH.js.map} +0 -0
- /package/dist/{chunk-CMGR4ZEW.js.map → chunk-NMRKAGHE.js.map} +0 -0
- /package/dist/{chunk-LV7M27WM.js.map → chunk-NPVICKZE.js.map} +0 -0
- /package/dist/{chunk-IO6GRPT6.js.map → chunk-O5DNEXQC.js.map} +0 -0
- /package/dist/{chunk-Q7SS3IME.js.map → chunk-P6UXDALK.js.map} +0 -0
- /package/dist/{chunk-UAG5KWVA.js.map → chunk-PJDK2PPQ.js.map} +0 -0
- /package/dist/{chunk-AXRXJTE2.js.map → chunk-PUNJAEY6.js.map} +0 -0
- /package/dist/{chunk-M2YKN37S.js.map → chunk-QLQS5A7X.js.map} +0 -0
- /package/dist/{chunk-I3TIKTJO.js.map → chunk-TICO2I2O.js.map} +0 -0
- /package/dist/{chunk-3YFXJ3ZP.js.map → chunk-U5DWHU3S.js.map} +0 -0
- /package/dist/{chunk-TEILUWOI.js.map → chunk-UP6EMMDI.js.map} +0 -0
- /package/dist/{chunk-SMXWYP24.js.map → chunk-VBYVKOMJ.js.map} +0 -0
- /package/dist/{chunk-AZAOEIKW.js.map → chunk-VHEEU4ZO.js.map} +0 -0
- /package/dist/{chunk-EIZUR2XW.js.map → chunk-XRE4JOEO.js.map} +0 -0
- /package/dist/{chunk-5R3ERCDH.js.map → chunk-YN66UOXT.js.map} +0 -0
- /package/dist/{chunk-IELYAOGG.js.map → chunk-YTIAXSUE.js.map} +0 -0
- /package/dist/{chunk-TJYQIGAP.js.map → chunk-Z44OY24N.js.map} +0 -0
- /package/dist/{chunk-VCTFO5CO.js.map → chunk-ZAWD6O46.js.map} +0 -0
- /package/dist/{chunk-PKHL44ER.js.map → chunk-ZD4D7UM6.js.map} +0 -0
- /package/dist/{chunk-LMTH2RM6.js.map → chunk-ZNI3RTFV.js.map} +0 -0
- /package/dist/{chunk-WYSO2NIH.js.map → chunk-ZRDYQZYH.js.map} +0 -0
- /package/dist/{collection-facade-GQAOGJP2.js.map → classified/index.js.map} +0 -0
- /package/dist/{delegation-UL5HKLER.js.map → collection-facade-XPVRHBGU.js.map} +0 -0
- /package/dist/{enclave-UL5LW66V.js.map → delegation-4HUHUE6T.js.map} +0 -0
- /package/dist/{executor-2FWQRLMG.js.map → enclave-IS7HZSQ7.js.map} +0 -0
- /package/dist/{executor-QZ7BXICW.js.map → executor-ANFBCOYA.js.map} +0 -0
- /package/dist/{executor-Z5ZLJVTV.js.map → executor-IKT47SH2.js.map} +0 -0
- /package/dist/{export-accessible-KRV5W4GH.js.map → executor-OIECZXTV.js.map} +0 -0
- /package/dist/{extract-partition-GLKBOXFQ.js.map → export-accessible-NZWCFZHL.js.map} +0 -0
- /package/dist/{issue-Y6UVIR43.js.map → extract-partition-52LX6RQH.js.map} +0 -0
- /package/dist/{ledger-RYI35CDS.js.map → issue-F4SYPJGJ.js.map} +0 -0
- /package/dist/{liberate-CRPZEV7O.js.map → ledger-YUAJUNFP.js.map} +0 -0
- /package/dist/{noydb-LDEBLNHY.js.map → liberate-6LDETRIW.js.map} +0 -0
- /package/dist/{policy-IXK4FVXP.js.map → noydb-WQNBVJIG.js.map} +0 -0
- /package/dist/{public-envelope-JHDQCPSX.js.map → policy-LRE6HTO5.js.map} +0 -0
- /package/dist/{registry-45RJNWGU.js.map → public-envelope-WVRRUVAJ.js.map} +0 -0
- /package/dist/{registry-5GRV5VXI.js.map → registry-6HZ2JSQ7.js.map} +0 -0
- /package/dist/{registry-WEUCHBO4.js.map → registry-GPXZQ7DT.js.map} +0 -0
- /package/dist/{request-withdrawal-GBPH2FDY.js.map → registry-USYD2ECC.js.map} +0 -0
- /package/dist/{revoke-TUFRGI6S.js.map → request-withdrawal-54V4L6CR.js.map} +0 -0
- /package/dist/{signer-PNKTBVF7.js.map → revoke-JV26NTQD.js.map} +0 -0
- /package/dist/{stale-3JWHNDIY.js.map → signer-AE56T5HE.js.map} +0 -0
- /package/dist/{withdraw-accessible-FFS46EOD.js.map → stale-LX4BR43V.js.map} +0 -0
- /package/dist/{store-coordination-provider-3I7XWZZK.js.map → store-coordination-provider-KTRIC6PR.js.map} +0 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import {
|
|
2
|
+
VDIG_ITERATIONS,
|
|
3
|
+
blindedEqual,
|
|
4
|
+
evaluateKofN,
|
|
5
|
+
normalizeForVerify,
|
|
6
|
+
openVdigPayload,
|
|
7
|
+
pbkdf2VerifyDigest
|
|
8
|
+
} from "./chunk-CPAROOKP.js";
|
|
9
|
+
import {
|
|
10
|
+
base64ToBuffer,
|
|
11
|
+
dualReadSealedSlot,
|
|
12
|
+
generateSalt
|
|
13
|
+
} from "./chunk-L4IRFTIF.js";
|
|
14
|
+
import {
|
|
15
|
+
ClassifiedConfigError,
|
|
16
|
+
ClassifiedVerifyError
|
|
17
|
+
} from "./chunk-BLZRNHMG.js";
|
|
18
|
+
import "./chunk-PZ5AY32C.js";
|
|
19
|
+
|
|
20
|
+
// src/kernel/enclave/classify/verify.ts
|
|
21
|
+
async function padOnce(iter = VDIG_ITERATIONS) {
|
|
22
|
+
const dummy = await pbkdf2VerifyDigest("noydb-classify-c4-pad", generateSalt(), iter);
|
|
23
|
+
await blindedEqual(dummy, dummy);
|
|
24
|
+
}
|
|
25
|
+
async function padFalse() {
|
|
26
|
+
await padOnce();
|
|
27
|
+
return { ok: false };
|
|
28
|
+
}
|
|
29
|
+
function refuseSealedResidue(collection, field) {
|
|
30
|
+
throw new ClassifiedConfigError(
|
|
31
|
+
collection,
|
|
32
|
+
`field "${field}" carries a recoverable _sealed slot but no _vdig \u2014 storage-form transition detected (R6); refused fail-loud, never an ok:false masquerading as wrong-password`
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
async function verifyDigestField(ctx, id, field, candidate, policy) {
|
|
36
|
+
const env = await ctx.getEnvelope(id);
|
|
37
|
+
if (env === null) return padFalse();
|
|
38
|
+
const blob = env._vdig?.[field];
|
|
39
|
+
if (blob === void 0) {
|
|
40
|
+
if (env._sealed?.[field] !== void 0) refuseSealedResidue(ctx.collection, field);
|
|
41
|
+
return padFalse();
|
|
42
|
+
}
|
|
43
|
+
const cek = await ctx.resolveCek(env);
|
|
44
|
+
if (cek === void 0) return padFalse();
|
|
45
|
+
let payload;
|
|
46
|
+
try {
|
|
47
|
+
payload = await openVdigPayload(blob, cek, ctx.collection, id, field);
|
|
48
|
+
} catch {
|
|
49
|
+
return padFalse();
|
|
50
|
+
}
|
|
51
|
+
const normalized = normalizeForVerify(policy.normalize, candidate);
|
|
52
|
+
const digest = await pbkdf2VerifyDigest(normalized, base64ToBuffer(payload.cur.salt), payload.iter);
|
|
53
|
+
const ok = await blindedEqual(digest, base64ToBuffer(payload.cur.hash));
|
|
54
|
+
if (!ok) return { ok: false };
|
|
55
|
+
if (policy.rotateDays !== void 0 && ctx.now() > Date.parse(payload.cur.at) + policy.rotateDays * 864e5) {
|
|
56
|
+
return { ok: true, mustRotate: true };
|
|
57
|
+
}
|
|
58
|
+
return { ok: true };
|
|
59
|
+
}
|
|
60
|
+
async function verifyTextField(ctx, id, field, candidate, normalize) {
|
|
61
|
+
const env = await ctx.getEnvelope(id);
|
|
62
|
+
const blob = env?._sealed?.[field];
|
|
63
|
+
let stored;
|
|
64
|
+
if (env !== null && blob !== void 0) {
|
|
65
|
+
const cek = await ctx.resolveCek(env);
|
|
66
|
+
const dek = await ctx.getDEK();
|
|
67
|
+
try {
|
|
68
|
+
stored = String(JSON.parse(await dualReadSealedSlot(blob, field, ctx.collection, cek, dek)));
|
|
69
|
+
} catch {
|
|
70
|
+
stored = void 0;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
await padOnce();
|
|
74
|
+
const a = new TextEncoder().encode(normalizeForVerify(normalize, candidate));
|
|
75
|
+
const b = stored !== void 0 ? new TextEncoder().encode(normalizeForVerify(normalize, stored)) : a;
|
|
76
|
+
const eq = await blindedEqual(a, b);
|
|
77
|
+
return { ok: stored !== void 0 && eq };
|
|
78
|
+
}
|
|
79
|
+
async function matchGroupFields(ctx, id, answers, members, opts) {
|
|
80
|
+
if (!Number.isInteger(opts.min) || opts.min < 1 || opts.min > members.length) {
|
|
81
|
+
throw new ClassifiedVerifyError(
|
|
82
|
+
ctx.collection,
|
|
83
|
+
"*",
|
|
84
|
+
`matchGroup min ${opts.min} out of range 1..${members.length}`
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
const normalized = /* @__PURE__ */ new Map();
|
|
88
|
+
for (const m of members) {
|
|
89
|
+
const answer = answers[m.field];
|
|
90
|
+
if (answer === void 0) continue;
|
|
91
|
+
if (typeof answer !== "string") {
|
|
92
|
+
throw new ClassifiedVerifyError(ctx.collection, m.field, "candidate must be a string");
|
|
93
|
+
}
|
|
94
|
+
normalized.set(m.field, normalizeForVerify(m.policy.normalize, answer));
|
|
95
|
+
}
|
|
96
|
+
const env = await ctx.getEnvelope(id);
|
|
97
|
+
if (env !== null) {
|
|
98
|
+
for (const m of members) {
|
|
99
|
+
if (env._sealed?.[m.field] !== void 0 && env._vdig?.[m.field] === void 0) {
|
|
100
|
+
refuseSealedResidue(ctx.collection, m.field);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
const cek = env !== null ? await ctx.resolveCek(env) : void 0;
|
|
105
|
+
const results = [];
|
|
106
|
+
for (const m of members) {
|
|
107
|
+
const candidate = normalized.get(m.field);
|
|
108
|
+
const blob = env?._vdig?.[m.field];
|
|
109
|
+
if (env === null || cek === void 0 || blob === void 0) {
|
|
110
|
+
await padOnce();
|
|
111
|
+
results.push(false);
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
try {
|
|
115
|
+
const payload = await openVdigPayload(blob, cek, ctx.collection, id, m.field);
|
|
116
|
+
if (candidate === void 0) {
|
|
117
|
+
await padOnce(payload.iter);
|
|
118
|
+
results.push(false);
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
const digest = await pbkdf2VerifyDigest(candidate, base64ToBuffer(payload.cur.salt), payload.iter);
|
|
122
|
+
results.push(await blindedEqual(digest, base64ToBuffer(payload.cur.hash)));
|
|
123
|
+
} catch {
|
|
124
|
+
await padOnce();
|
|
125
|
+
results.push(false);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return { passed: evaluateKofN(results, opts.min) };
|
|
129
|
+
}
|
|
130
|
+
export {
|
|
131
|
+
matchGroupFields,
|
|
132
|
+
verifyDigestField,
|
|
133
|
+
verifyTextField
|
|
134
|
+
};
|
|
135
|
+
//# sourceMappingURL=verify-SW6J63Q2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/kernel/enclave/classify/verify.ts"],"sourcesContent":["/**\n * The enclave verify oracle (spec §3). Verdict-only egress: no path\n * distinguishes \"record missing\" / \"no digest\" / \"AAD-tamper\" / \"mismatch\"\n * beyond { ok: false } — existence oracles are oracles too. Every path that\n * cannot run a real comparison runs ONE dummy PBKDF2 + ONE dummy tag-compare\n * first (C4), so wall-clock cannot enumerate records/fields/answers. The\n * text door (verifyTextField) has no real PBKDF2 of its own, so it pays the\n * pad UNCONDITIONALLY — every outcome, including a real compare, costs the\n * same one PBKDF2 unit (no inverted exists-vs-absent oracle).\n * Throws are reserved for caller/config bugs (ClassifiedVerifyError /\n * ClassifiedConfigError) and are exempt from the pad by design (R6 note).\n * @module\n */\nimport { generateSalt, base64ToBuffer, type EnclaveKey } from '../crypto.js'\nimport { pbkdf2VerifyDigest, VDIG_ITERATIONS } from './digest.js'\nimport { normalizeForVerify, type VerifyNormalizeMode } from './normalize.js'\nimport { blindedEqual } from './compare.js'\nimport { evaluateKofN } from './kofn.js'\nimport { openVdigPayload, type VdigPayload } from './vdig.js'\nimport { dualReadSealedSlot } from '../record-keys/sealed-slot.js'\nimport { ClassifiedConfigError, ClassifiedVerifyError } from '../../errors.js'\nimport type { EncryptedEnvelope, VdigFieldPolicy, ClassifiedVerdict } from '../../types.js'\n\nexport interface VerifyEngineCtx {\n readonly collection: string\n getEnvelope(id: string): Promise<EncryptedEnvelope | null>\n resolveCek(env: EncryptedEnvelope): Promise<EnclaveKey | undefined>\n getDEK(): Promise<EnclaveKey>\n readonly now: () => number\n}\n\n/**\n * C4 pad: one full-cost dummy digest + one dummy compare; result discarded.\n * Pad at `iter` when the caller holds an AUTHENTICATED payload.iter, so pad\n * cost tracks the real compare cost across future iteration bumps; the\n * fully-absent paths (no payload to read an iter from) use VDIG_ITERATIONS.\n */\nasync function padOnce(iter: number = VDIG_ITERATIONS): Promise<void> {\n const dummy = await pbkdf2VerifyDigest('noydb-classify-c4-pad', generateSalt(), iter)\n await blindedEqual(dummy, dummy)\n}\n\nasync function padFalse(): Promise<ClassifiedVerdict> {\n await padOnce()\n return { ok: false }\n}\n\n/** R6 verify-side transition evidence — config bug, fail-loud, pad-exempt. */\nfunction refuseSealedResidue(collection: string, field: string): never {\n throw new ClassifiedConfigError(collection,\n `field \"${field}\" carries a recoverable _sealed slot but no _vdig — storage-form ` +\n `transition detected (R6); refused fail-loud, never an ok:false masquerading as wrong-password`)\n}\n\nexport async function verifyDigestField(\n ctx: VerifyEngineCtx,\n id: string,\n field: string,\n candidate: string,\n policy: VdigFieldPolicy,\n): Promise<ClassifiedVerdict> {\n const env = await ctx.getEnvelope(id)\n if (env === null) return padFalse()\n const blob = env._vdig?.[field]\n if (blob === undefined) {\n if (env._sealed?.[field] !== undefined) refuseSealedResidue(ctx.collection, field)\n return padFalse()\n }\n const cek = await ctx.resolveCek(env)\n if (cek === undefined) return padFalse()\n\n let payload: VdigPayload\n try {\n payload = await openVdigPayload(blob, cek, ctx.collection, id, field)\n } catch {\n return padFalse() // AAD/tamper (C1) → padded false; no tamper oracle to the caller\n }\n\n const normalized = normalizeForVerify(policy.normalize, candidate)\n const digest = await pbkdf2VerifyDigest(normalized, base64ToBuffer(payload.cur.salt), payload.iter)\n const ok = await blindedEqual(digest, base64ToBuffer(payload.cur.hash))\n if (!ok) return { ok: false } // I1: bare false — mustRotate never computed here\n\n if (policy.rotateDays !== undefined\n && ctx.now() > Date.parse(payload.cur.at) + policy.rotateDays * 86_400_000) {\n // Disclosing write-age-vs-policy to a SUCCESSFUL verifier is intended (audit F6).\n return { ok: true, mustRotate: true }\n }\n return { ok: true }\n}\n\nexport async function verifyTextField(\n ctx: VerifyEngineCtx,\n id: string,\n field: string,\n candidate: string,\n normalize: VerifyNormalizeMode,\n): Promise<ClassifiedVerdict> {\n // C4, single code path: (a) attempt the unseal where a slot exists, then\n // for EVERY outcome — present-correct, present-wrong, missing record,\n // missing slot, tampered — (b) run the one constant-cost pad, (c) run one\n // blindedEqual, (d) return the boolean. Unlike the digest door there is no\n // real PBKDF2 here (unseal is sub-ms AES-GCM), so skipping the pad on the\n // real compare would make exists-but-wrong ~100x FASTER than absent — an\n // inverted existence oracle. No branch below skips the dominant cost.\n const env = await ctx.getEnvelope(id)\n const blob = env?._sealed?.[field]\n let stored: string | undefined\n if (env !== null && blob !== undefined) {\n const cek = await ctx.resolveCek(env)\n const dek = await ctx.getDEK()\n try {\n // Plaintext exists microseconds inside this function; only the boolean leaves.\n stored = String(JSON.parse(await dualReadSealedSlot(blob, field, ctx.collection, cek, dek)))\n } catch {\n stored = undefined // AAD/tamper (C1) → same padded compare tail as absent\n }\n }\n await padOnce()\n const a = new TextEncoder().encode(normalizeForVerify(normalize, candidate))\n const b = stored !== undefined\n ? new TextEncoder().encode(normalizeForVerify(normalize, stored))\n : a // no-compare dummy comparand — the verdict is forced false below\n const eq = await blindedEqual(a, b)\n return { ok: stored !== undefined && eq }\n}\n\nexport async function matchGroupFields(\n ctx: VerifyEngineCtx,\n id: string,\n answers: Record<string, string>,\n members: ReadonlyArray<{ readonly field: string; readonly policy: VdigFieldPolicy }>,\n opts: { readonly min: number },\n): Promise<{ readonly passed: boolean }> {\n // I2 step 1 — validate EVERYTHING up front, before any PBKDF2, throwing\n // uniformly at ~0 elapsed (no member-position leak via timing/throw type).\n if (!Number.isInteger(opts.min) || opts.min < 1 || opts.min > members.length) {\n throw new ClassifiedVerifyError(ctx.collection, '*',\n `matchGroup min ${opts.min} out of range 1..${members.length}`)\n }\n const normalized = new Map<string, string>()\n for (const m of members) {\n const answer = answers[m.field] // non-member answer keys: silently ignored\n if (answer === undefined) continue\n if (typeof answer !== 'string') {\n throw new ClassifiedVerifyError(ctx.collection, m.field, 'candidate must be a string')\n }\n normalized.set(m.field, normalizeForVerify(m.policy.normalize, answer))\n }\n\n const env = await ctx.getEnvelope(id)\n if (env !== null) {\n for (const m of members) { // R6 evidence — uniform, before any PBKDF2\n if (env._sealed?.[m.field] !== undefined && env._vdig?.[m.field] === undefined) {\n refuseSealedResidue(ctx.collection, m.field)\n }\n }\n }\n const cek = env !== null ? await ctx.resolveCek(env) : undefined\n\n // I2 step 2+3 — iterate RESOLVED GROUP MEMBERS (denominator = |members|),\n // evaluate EVERY member (collect, never break), pad every no-compare slot.\n const results: boolean[] = []\n for (const m of members) {\n const candidate = normalized.get(m.field)\n const blob = env?._vdig?.[m.field]\n if (env === null || cek === undefined || blob === undefined) {\n await padOnce()\n results.push(false)\n continue\n }\n try {\n const payload = await openVdigPayload(blob, cek, ctx.collection, id, m.field)\n if (candidate === undefined) {\n // Slot present, answer absent: the payload's authenticated iter is in\n // hand — pad at IT (not the constant) so a future iteration bump\n // cannot desync this pad's cost from the real compare's cost.\n await padOnce(payload.iter)\n results.push(false)\n continue\n }\n const digest = await pbkdf2VerifyDigest(candidate, base64ToBuffer(payload.cur.salt), payload.iter)\n results.push(await blindedEqual(digest, base64ToBuffer(payload.cur.hash)))\n } catch {\n await padOnce()\n results.push(false)\n }\n }\n // Per-member results never appear in any return, error, or audit payload.\n return { passed: evaluateKofN(results, opts.min) }\n}\n"],"mappings":"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","names":[]}
|
package/dist/with/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export { U as Unsubscribe, W as WriteEvent, a as WriteHook, b as WriteHookRegistry } from '../index-B9QdHytu.js';
|
|
2
|
-
import { cF as UnlockedKeyring, cG as ExportFormat } from '../index-
|
|
3
|
-
export { cH as BusHandler, cI as GateDeleteEvent, cJ as GateEventMap, cK as GateHandler, cL as GatePoint, cM as GatePutEvent, cN as LifecycleEventMap, cO as LifecyclePoint, cP as ServiceBus, cQ as SubsystemBus } from '../index-
|
|
2
|
+
import { cF as UnlockedKeyring, cG as ExportFormat } from '../index-D05bV0_g.js';
|
|
3
|
+
export { cH as BusHandler, cI as GateDeleteEvent, cJ as GateEventMap, cK as GateHandler, cL as GatePoint, cM as GatePutEvent, cN as LifecycleEventMap, cO as LifecyclePoint, cP as ServiceBus, cQ as SubsystemBus } from '../index-D05bV0_g.js';
|
|
4
4
|
import '../subject-index-O75wKshW.js';
|
|
5
|
-
import '../describe-
|
|
5
|
+
import '../describe-0tiXAjoO.js';
|
|
6
6
|
import '@noy-db/attestation';
|
|
7
7
|
|
|
8
8
|
/**
|
package/dist/with/index.js
CHANGED
|
@@ -6,12 +6,15 @@ import {
|
|
|
6
6
|
assertCanImport,
|
|
7
7
|
canExport,
|
|
8
8
|
canImport
|
|
9
|
-
} from "../chunk-
|
|
10
|
-
import "../chunk-
|
|
11
|
-
import "../chunk-
|
|
12
|
-
import "../chunk-
|
|
13
|
-
import "../chunk-
|
|
14
|
-
import "../chunk-
|
|
9
|
+
} from "../chunk-YN66UOXT.js";
|
|
10
|
+
import "../chunk-5A6TC3RQ.js";
|
|
11
|
+
import "../chunk-2N4MUSF3.js";
|
|
12
|
+
import "../chunk-5EZAJEES.js";
|
|
13
|
+
import "../chunk-6RASM2J4.js";
|
|
14
|
+
import "../chunk-CPAROOKP.js";
|
|
15
|
+
import "../chunk-L4IRFTIF.js";
|
|
16
|
+
import "../chunk-OCDUQUAP.js";
|
|
17
|
+
import "../chunk-BLZRNHMG.js";
|
|
15
18
|
import "../chunk-PZ5AY32C.js";
|
|
16
19
|
export {
|
|
17
20
|
ServiceBus,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { cf as MaterializedViewStrategy, cg as MaterializedViewStrategyHandle } from './index-
|
|
1
|
+
import { cf as MaterializedViewStrategy, cg as MaterializedViewStrategyHandle } from './index-D05bV0_g.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Register a materialized view: a declared query whose result is
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ch as OverlayedViewStrategy, cq as OverlayedViewStrategyHandle } from './index-
|
|
1
|
+
import { ch as OverlayedViewStrategy, cq as OverlayedViewStrategyHandle } from './index-D05bV0_g.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Register a read-shadow overlay: bind an MV-owned base collection to
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c2 as DerivationStrategy, cb as DerivationStrategyHandle } from './index-
|
|
1
|
+
import { c2 as DerivationStrategy, cb as DerivationStrategyHandle } from './index-D05bV0_g.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Register a deterministic derivation: one source collection → one or
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FROZEN_SNAPSHOTS_COLLECTION,
|
|
3
|
+
freezeAndDeleteClosure,
|
|
4
|
+
freezeSnapshotOnly,
|
|
5
|
+
randomId,
|
|
6
|
+
withdrawAccessibleData
|
|
7
|
+
} from "./chunk-6CNLU4TO.js";
|
|
8
|
+
import "./chunk-7MHVHGQZ.js";
|
|
9
|
+
import "./chunk-3UDPDRUC.js";
|
|
10
|
+
import "./chunk-VBYVKOMJ.js";
|
|
11
|
+
import "./chunk-5EZAJEES.js";
|
|
12
|
+
import "./chunk-6RASM2J4.js";
|
|
13
|
+
import "./chunk-CPAROOKP.js";
|
|
14
|
+
import "./chunk-L4IRFTIF.js";
|
|
15
|
+
import "./chunk-OCDUQUAP.js";
|
|
16
|
+
import "./chunk-BLZRNHMG.js";
|
|
17
|
+
import "./chunk-PZ5AY32C.js";
|
|
18
|
+
export {
|
|
19
|
+
FROZEN_SNAPSHOTS_COLLECTION,
|
|
20
|
+
freezeAndDeleteClosure,
|
|
21
|
+
freezeSnapshotOnly,
|
|
22
|
+
randomId,
|
|
23
|
+
withdrawAccessibleData
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=withdraw-accessible-DGA4V2TP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@noy-db/hub",
|
|
3
|
-
"version": "0.3.0-pre.
|
|
3
|
+
"version": "0.3.0-pre.3",
|
|
4
4
|
"description": "Zero-knowledge, offline-first, encrypted document store — core library with AES-256-GCM, PBKDF2, multi-user keyring, and sync engine",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "vLannaAi <vicio@lanna.ai>",
|
|
@@ -116,6 +116,10 @@
|
|
|
116
116
|
"types": "./dist/attestation/index.d.ts",
|
|
117
117
|
"default": "./dist/attestation/index.js"
|
|
118
118
|
},
|
|
119
|
+
"./classified": {
|
|
120
|
+
"types": "./dist/classified/index.d.ts",
|
|
121
|
+
"default": "./dist/classified/index.js"
|
|
122
|
+
},
|
|
119
123
|
"./tiers": {
|
|
120
124
|
"types": "./dist/tiers/index.d.ts",
|
|
121
125
|
"default": "./dist/tiers/index.js"
|
|
@@ -188,14 +192,14 @@
|
|
|
188
192
|
"node": ">=22.0.0"
|
|
189
193
|
},
|
|
190
194
|
"dependencies": {
|
|
191
|
-
"@noy-db/attestation": "0.3.0-pre.
|
|
195
|
+
"@noy-db/attestation": "0.3.0-pre.3"
|
|
192
196
|
},
|
|
193
197
|
"devDependencies": {
|
|
194
198
|
"@types/node": "^22.0.0",
|
|
195
199
|
"esbuild": "^0.25.0",
|
|
196
200
|
"zod": "^4.0.0",
|
|
197
201
|
"zod-to-json-schema": "^3.25.2",
|
|
198
|
-
"@noy-db/on-shamir": "0.3.0-pre.
|
|
202
|
+
"@noy-db/on-shamir": "0.3.0-pre.3"
|
|
199
203
|
},
|
|
200
204
|
"peerDependencies": {
|
|
201
205
|
"zod-to-json-schema": "^3.25.0"
|
package/dist/api-RW3KP7WU.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
UserApi,
|
|
3
|
-
createUserApi
|
|
4
|
-
} from "./chunk-UDRIWL7A.js";
|
|
5
|
-
import "./chunk-ITNUCOXM.js";
|
|
6
|
-
import "./chunk-5O3AOPDT.js";
|
|
7
|
-
import "./chunk-5TDJ56JE.js";
|
|
8
|
-
import "./chunk-ZYUC53LT.js";
|
|
9
|
-
import "./chunk-PZ5AY32C.js";
|
|
10
|
-
export {
|
|
11
|
-
UserApi,
|
|
12
|
-
createUserApi
|
|
13
|
-
};
|
|
14
|
-
//# sourceMappingURL=api-RW3KP7WU.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/kernel/enclave/crypto.ts","../src/kernel/enclave/record-keys/lifecycle.ts","../src/kernel/enclave/record-keys/tombstone.ts","../src/kernel/enclave/record-keys/sealed-slot.ts","../src/kernel/schema.ts","../src/kernel/enclave/record-keys/record-codec.ts","../src/kernel/enclave/record-keys/sealing.ts","../src/kernel/enclave/record-keys/deterministic.ts","../src/kernel/enclave/record-keys/envelope-body.ts"],"sourcesContent":["/**\n * Cryptographic primitives — thin wrappers around the Web Crypto API.\n *\n * ## Design principle\n *\n * **Zero npm crypto dependencies.** Every operation uses `globalThis.crypto.subtle`,\n * which is available natively in Node.js ≥ 18, all modern browsers, and\n * Deno/Bun. This avoids supply-chain risk from third-party crypto packages and\n * ensures the library stays auditable.\n *\n * ## Algorithms\n *\n * | Use case | Algorithm | Parameters |\n * |----------|-----------|------------|\n * | Key derivation | PBKDF2-SHA256 | 600,000 iterations, 32-byte salt |\n * | Record encryption | AES-256-GCM | 12-byte random IV per operation |\n * | DEK wrapping | AES-KW (RFC 3394) | 256-bit KEK |\n * | Binary encrypt | AES-256-GCM | same as record encryption |\n * | Integrity | HMAC-SHA256 | for presence channels |\n * | Content hash | SHA-256 | for ledger and bundle integrity |\n *\n * ## Key lifecycle\n *\n * ```\n * passphrase + salt\n * └─► deriveKey() → KEK (CryptoKey, extractable: false)\n * └─► wrapKey() → wrapped DEK bytes [stored in keyring]\n * └─► unwrapKey() → DEK (CryptoKey) [memory only during session]\n * └─► encrypt() / decrypt() → ciphertext / plaintext\n * ```\n *\n * IVs are generated fresh by {@link generateIV} on every encrypt call.\n * Reusing an IV with the same key would break GCM's authentication guarantee —\n * this function should be the only place IVs are produced.\n *\n * @module\n */\n\nimport { DecryptionError, InvalidKeyError, TamperedError } from '../errors.js'\n\n/**\n * **EnclaveKey** — the opaque key type at the enclave seam.\n *\n * In noy-db's reference enclave this is `CryptoKey` (the Web Crypto API's\n * key handle). A fork's enclave redefines this alias to its own key\n * representation (e.g. `type EnclaveKey = null` for a keyless HSM-backed\n * fork) — outside `kernel/enclave/**`, every consumer must treat it as\n * opaque: never construct, inspect, or serialize it directly, only pass it\n * between barrel functions (`encrypt`/`decrypt`/`wrapKey`/`unwrapKey`/…).\n */\nexport type EnclaveKey = CryptoKey\n\nconst PBKDF2_ITERATIONS = 600_000\nconst SALT_BYTES = 32\nconst IV_BYTES = 12\nconst KEY_BITS = 256\n\nconst subtle = globalThis.crypto.subtle\n\n// ─── Key Derivation ────────────────────────────────────────────────────\n\n/** Derive a KEK from a passphrase and salt using PBKDF2-SHA256. */\nexport async function deriveKey(\n passphrase: string,\n salt: Uint8Array,\n): Promise<CryptoKey> {\n const keyMaterial = await subtle.importKey(\n 'raw',\n new TextEncoder().encode(passphrase),\n 'PBKDF2',\n false,\n ['deriveKey'],\n )\n\n return subtle.deriveKey(\n {\n name: 'PBKDF2',\n salt: salt as BufferSource,\n iterations: PBKDF2_ITERATIONS,\n hash: 'SHA-256',\n },\n keyMaterial,\n { name: 'AES-KW', length: KEY_BITS },\n false,\n ['wrapKey', 'unwrapKey'],\n )\n}\n\n/**\n * Which AES algorithm/usage a {@link derivePassphraseKey} result is for:\n * `'aes-kw'` mints a key-wrapping key (`wrapKey`/`unwrapKey`, e.g. for\n * KEK derivation); `'aes-gcm'` mints a direct encrypt/decrypt key (e.g.\n * for the wrap-DEKs primitive in `with-party/team/wrapped-deks.ts`).\n */\nexport type PassphraseKeyUsage = 'aes-kw' | 'aes-gcm'\n\n/**\n * Derive a non-extractable AES key from a passphrase/credential and salt\n * via PBKDF2-SHA256, generalizing {@link deriveKey}'s AES-KW derivation to\n * also cover AES-GCM-usage keys. Callers pin their own `iterations` and\n * `keyUsage` so an existing call site's exact parameters (and thus its\n * derived-key bytes) are preserved verbatim when migrated onto this\n * shared primitive — this is call-site consolidation, not a KDF change.\n */\nexport async function derivePassphraseKey(\n passphrase: string,\n salt: Uint8Array,\n params: { iterations: number; keyUsage: PassphraseKeyUsage },\n): Promise<CryptoKey> {\n const keyMaterial = await subtle.importKey(\n 'raw',\n new TextEncoder().encode(passphrase),\n 'PBKDF2',\n false,\n ['deriveKey'],\n )\n\n return params.keyUsage === 'aes-gcm'\n ? subtle.deriveKey(\n {\n name: 'PBKDF2',\n salt: salt as BufferSource,\n iterations: params.iterations,\n hash: 'SHA-256',\n },\n keyMaterial,\n { name: 'AES-GCM', length: KEY_BITS },\n false,\n ['encrypt', 'decrypt'],\n )\n : subtle.deriveKey(\n {\n name: 'PBKDF2',\n salt: salt as BufferSource,\n iterations: params.iterations,\n hash: 'SHA-256',\n },\n keyMaterial,\n { name: 'AES-KW', length: KEY_BITS },\n false,\n ['wrapKey', 'unwrapKey'],\n )\n}\n\n// ─── DEK Generation ────────────────────────────────────────────────────\n\n/** Generate a random AES-256-GCM data encryption key. */\nexport async function generateDEK(): Promise<CryptoKey> {\n return subtle.generateKey(\n { name: 'AES-GCM', length: KEY_BITS },\n true, // extractable — needed for AES-KW wrapping\n ['encrypt', 'decrypt'],\n )\n}\n\n// ─── Key Wrapping ──────────────────────────────────────────────────────\n\n/** Wrap (encrypt) a DEK with a KEK using AES-KW. Returns base64 string. */\nexport async function wrapKey(dek: CryptoKey, kek: CryptoKey): Promise<string> {\n const wrapped = await subtle.wrapKey('raw', dek, kek, 'AES-KW')\n return bufferToBase64(wrapped)\n}\n\n/** Unwrap (decrypt) a DEK from base64 string using a KEK. */\nexport async function unwrapKey(\n wrappedBase64: string,\n kek: CryptoKey,\n): Promise<CryptoKey> {\n try {\n return await subtle.unwrapKey(\n 'raw',\n base64ToBuffer(wrappedBase64) as BufferSource,\n kek,\n 'AES-KW',\n { name: 'AES-GCM', length: KEY_BITS },\n true,\n ['encrypt', 'decrypt'],\n )\n } catch {\n throw new InvalidKeyError()\n }\n}\n\n// ─── Per-record CEK wrapping ───────────────────────────────────────────\n\n/**\n * Derive a **dedicated** AES-KW wrapping key from a collection/tier DEK via\n * HKDF-SHA256, used to wrap/unwrap a per-record CEK.\n *\n * The collection/tier DEKs are AES-256-**GCM** keys (usages\n * `encrypt`/`decrypt`) and cannot themselves act as an AES-KW KEK. We do NOT\n * re-import the raw DEK bytes directly as an AES-KW key — that would reuse one\n * key across two primitives (AES-GCM for `_det`/presence, AES-KW for CEK\n * wrapping), violating key separation. Instead we HKDF-derive a domain-\n * separated KW key (salt `noydb-cek-wrap`), exactly as `derivePresenceKey`\n * derives a separate presence key. The derivation is deterministic, so\n * wrapping the same CEK under the same DEK always yields identical ciphertext\n * — which is what lets an update reuse a record's stable CEK and produce a\n * byte-identical `_cek`. The KW key is independent of the DEK's GCM key.\n *\n * The DEK must be extractable (it is — `generateDEK`/`unwrapKey` mint\n * extractable keys).\n */\nasync function asKwKey(dek: CryptoKey): Promise<CryptoKey> {\n const rawDek = await subtle.exportKey('raw', dek)\n const hkdfKey = await subtle.importKey('raw', rawDek, 'HKDF', false, ['deriveBits'])\n const salt = new TextEncoder().encode('noydb-cek-wrap')\n const info = new TextEncoder().encode('v1')\n const bits = await subtle.deriveBits(\n { name: 'HKDF', hash: 'SHA-256', salt, info },\n hkdfKey,\n KEY_BITS,\n )\n return subtle.importKey('raw', bits, 'AES-KW', false, ['wrapKey', 'unwrapKey'])\n}\n\n/**\n * AES-KW-wrap a per-record CEK under a collection/tier DEK. Returns base64.\n * Deterministic over `(cek, dek)`.\n */\nexport async function wrapCek(cek: CryptoKey, dek: CryptoKey): Promise<string> {\n const kw = await asKwKey(dek)\n const wrapped = await subtle.wrapKey('raw', cek, kw, 'AES-KW')\n return bufferToBase64(wrapped)\n}\n\n/**\n * Unwrap a per-record CEK from base64 under a collection/tier DEK. Throws\n * `InvalidKeyError` if the wrapped bytes do not authenticate under the DEK.\n */\nexport async function unwrapCek(wrappedBase64: string, dek: CryptoKey): Promise<CryptoKey> {\n const kw = await asKwKey(dek)\n try {\n return await subtle.unwrapKey(\n 'raw',\n base64ToBuffer(wrappedBase64) as BufferSource,\n kw,\n 'AES-KW',\n { name: 'AES-GCM', length: KEY_BITS },\n true,\n ['encrypt', 'decrypt'],\n )\n } catch {\n throw new InvalidKeyError()\n }\n}\n\n/**\n * Import a raw 32-byte AES-256-GCM record CEK (e.g. from a sealed-CEK\n * delivery binding). Non-extractable, decrypt-only — the imported key is\n * used solely to open the record's `_iv`/`_data` body under `decrypt()`.\n */\nexport async function importCek(rawKey: Uint8Array): Promise<CryptoKey> {\n return subtle.importKey('raw', rawKey as BufferSource, { name: 'AES-GCM', length: KEY_BITS }, false, ['decrypt'])\n}\n\n// ─── Encrypt / Decrypt ─────────────────────────────────────────────────\n\nexport interface EncryptResult {\n iv: string // base64\n data: string // base64\n}\n\n/** Encrypt plaintext JSON string with AES-256-GCM. Fresh IV per call. */\nexport async function encrypt(\n plaintext: string,\n dek: CryptoKey,\n): Promise<EncryptResult> {\n const iv = generateIV()\n const encoded = new TextEncoder().encode(plaintext)\n\n const ciphertext = await subtle.encrypt(\n { name: 'AES-GCM', iv: iv as BufferSource },\n dek,\n encoded,\n )\n\n return {\n iv: bufferToBase64(iv),\n data: bufferToBase64(ciphertext),\n }\n}\n\n/** Decrypt AES-256-GCM ciphertext. Throws on wrong key or tampered data. */\nexport async function decrypt(\n ivBase64: string,\n dataBase64: string,\n dek: CryptoKey,\n): Promise<string> {\n const iv = base64ToBuffer(ivBase64)\n const ciphertext = base64ToBuffer(dataBase64)\n\n try {\n const plaintext = await subtle.decrypt(\n { name: 'AES-GCM', iv: iv as BufferSource },\n dek,\n ciphertext as BufferSource,\n )\n return new TextDecoder().decode(plaintext)\n } catch (err) {\n if (err instanceof Error && err.name === 'OperationError') {\n throw new TamperedError()\n }\n throw new DecryptionError(\n err instanceof Error ? err.message : 'Decryption failed',\n )\n }\n}\n\n// ─── Binary Encrypt / Decrypt ────────\n\n/**\n * Encrypt raw bytes with AES-256-GCM using a fresh random IV.\n * Used by the attachment store so binary blobs avoid double base64 encoding\n * (the existing `encrypt()` function calls `TextEncoder` on a string — here\n * we pass the `Uint8Array` directly to `subtle.encrypt`).\n */\nexport async function encryptBytes(\n data: Uint8Array,\n dek: CryptoKey,\n): Promise<EncryptResult> {\n const iv = generateIV()\n const ciphertext = await subtle.encrypt(\n { name: 'AES-GCM', iv: iv as BufferSource },\n dek,\n data as unknown as BufferSource,\n )\n return {\n iv: bufferToBase64(iv),\n data: bufferToBase64(ciphertext),\n }\n}\n\n/**\n * Decrypt AES-256-GCM ciphertext back to raw bytes.\n * Counterpart to `encryptBytes`. Throws `TamperedError` on auth-tag failure.\n */\nexport async function decryptBytes(\n ivBase64: string,\n dataBase64: string,\n dek: CryptoKey,\n): Promise<Uint8Array> {\n const iv = base64ToBuffer(ivBase64)\n const ciphertext = base64ToBuffer(dataBase64)\n try {\n const plaintext = await subtle.decrypt(\n { name: 'AES-GCM', iv: iv as BufferSource },\n dek,\n ciphertext as BufferSource,\n )\n return new Uint8Array(plaintext)\n } catch (err) {\n if (err instanceof Error && err.name === 'OperationError') {\n throw new TamperedError()\n }\n throw new DecryptionError(\n err instanceof Error ? err.message : 'Decryption failed',\n )\n }\n}\n\n/**\n * SHA-256 hex digest of raw bytes. Used to derive content-addressed\n * eTags for blob deduplication. Computed on plaintext bytes\n * before compression and encryption so the eTag identifies content, not\n * ciphertext, and survives re-encryption (key rotation, re-upload).\n */\nexport async function sha256Hex(data: Uint8Array): Promise<string> {\n const hash = await subtle.digest('SHA-256', data as unknown as BufferSource)\n return Array.from(new Uint8Array(hash))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('')\n}\n\n// ─── HMAC-SHA-256 ─────────────────────────────\n\n/**\n * Compute HMAC-SHA-256(key, data) and return hex string.\n *\n * Used to derive content-addressed eTags that are opaque to the store:\n * ```\n * eTag = hmacSha256Hex(blobDEK, plaintext)\n * ```\n *\n * Unlike a plain SHA-256, the HMAC is keyed by the vault-shared `_blob` DEK,\n * so an attacker with store access cannot pre-compute eTags for known files.\n * Deduplication still works within a vault (same key + same content = same eTag).\n */\nexport async function hmacSha256Hex(key: CryptoKey, data: Uint8Array): Promise<string> {\n // Export AES-GCM DEK raw bytes → import as HMAC key\n const rawKey = await subtle.exportKey('raw', key)\n const hmacKey = await subtle.importKey(\n 'raw',\n rawKey,\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign'],\n )\n const sig = await subtle.sign('HMAC', hmacKey, data as unknown as BufferSource)\n return Array.from(new Uint8Array(sig))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('')\n}\n\n// ─── AAD-aware Binary Encrypt / Decrypt ──\n\n/**\n * Encrypt raw bytes with AES-256-GCM using Additional Authenticated Data.\n *\n * The AAD binds each chunk to its parent blob and position, preventing\n * chunk reorder, substitution, and truncation attacks:\n * ```\n * AAD = UTF-8(\"{eTag}:{chunkIndex}:{chunkCount}\")\n * ```\n *\n * The AAD is NOT stored — the reader reconstructs it from `BlobObject`\n * metadata and passes it to `decryptBytesWithAAD`.\n */\nexport async function encryptBytesWithAAD(\n data: Uint8Array,\n dek: CryptoKey,\n aad: Uint8Array,\n): Promise<EncryptResult> {\n const iv = generateIV()\n const ciphertext = await subtle.encrypt(\n {\n name: 'AES-GCM',\n iv: iv as BufferSource,\n additionalData: aad as BufferSource,\n },\n dek,\n data as unknown as BufferSource,\n )\n return {\n iv: bufferToBase64(iv),\n data: bufferToBase64(ciphertext),\n }\n}\n\n/**\n * Decrypt AES-256-GCM ciphertext with AAD verification.\n *\n * If the AAD does not match the one used at encryption time (e.g. because\n * a chunk was reordered or substituted from another blob), the GCM auth\n * tag fails and this throws `TamperedError`.\n */\nexport async function decryptBytesWithAAD(\n ivBase64: string,\n dataBase64: string,\n dek: CryptoKey,\n aad: Uint8Array,\n): Promise<Uint8Array> {\n const iv = base64ToBuffer(ivBase64)\n const ciphertext = base64ToBuffer(dataBase64)\n try {\n const plaintext = await subtle.decrypt(\n {\n name: 'AES-GCM',\n iv: iv as BufferSource,\n additionalData: aad as BufferSource,\n },\n dek,\n ciphertext as BufferSource,\n )\n return new Uint8Array(plaintext)\n } catch (err) {\n if (err instanceof Error && err.name === 'OperationError') {\n throw new TamperedError()\n }\n throw new DecryptionError(\n err instanceof Error ? err.message : 'Decryption failed',\n )\n }\n}\n\n// ─── Presence Key Derivation ──────────────────────────────\n\n/**\n * Derive an AES-256-GCM presence key from a collection DEK using HKDF-SHA256.\n *\n * The presence key is domain-separated from the data DEK by the fixed salt\n * `'noydb-presence'` and the `info` = collection name. This means:\n * - The adapter never sees the presence key.\n * - Presence payloads rotate automatically when the collection DEK is rotated.\n * - Revoked users cannot derive the new presence key after a DEK rotation.\n *\n * @param dek The collection's AES-256-GCM DEK (extractable).\n * @param collectionName Used as the HKDF `info` parameter for domain separation.\n * @returns A non-extractable AES-256-GCM key suitable for presence payload encryption.\n */\nexport async function derivePresenceKey(dek: CryptoKey, collectionName: string): Promise<CryptoKey> {\n // Step 1: export DEK raw bytes\n const rawDek = await subtle.exportKey('raw', dek)\n\n // Step 2: import as HKDF key material\n const hkdfKey = await subtle.importKey(\n 'raw',\n rawDek,\n 'HKDF',\n false,\n ['deriveBits'],\n )\n\n // Step 3: derive 256 bits with salt='noydb-presence' and info=collectionName\n const salt = new TextEncoder().encode('noydb-presence')\n const info = new TextEncoder().encode(collectionName)\n const bits = await subtle.deriveBits(\n { name: 'HKDF', hash: 'SHA-256', salt, info },\n hkdfKey,\n KEY_BITS,\n )\n\n // Step 4: import derived bits as AES-GCM key\n return subtle.importKey(\n 'raw',\n bits,\n { name: 'AES-GCM', length: KEY_BITS },\n false,\n ['encrypt', 'decrypt'],\n )\n}\n\n// ─── Sealed Field Key Derivation ──────────────────────────\n\n/**\n * Derive a **per-field** AES-256-GCM key from a collection DEK using\n * HKDF-SHA256, used to encrypt a single sensitive field into its own\n * `_sealed[field]` envelope slot (structural group-encryption).\n *\n * Domain-separated from the data DEK (and from the presence/deterministic\n * channels) by the fixed salt `'noydb-sealed'` and an `info` of\n * `JSON.stringify(['noydb-sealed', collectionName, field])`. The JSON-array\n * encoding is injective — each element is separately quoted/escaped — so\n * collection `a/sealed/b` + field `c` cannot collide with collection `a` +\n * field `b/sealed/c`. Each sensitive field gets a **distinct** key, so a\n * `_sealed[a]` ciphertext does not authenticate under field `b`'s key —\n * sealed fields are cryptographically isolated from one another. The\n * collection name keeps the same field name in two collections from sharing a\n * key, mirroring how `derivePresenceKey` / `encryptDeterministic` domain-separate.\n *\n * @param dek The collection's AES-256-GCM DEK (extractable).\n * @param collectionName Part of the HKDF `info` for domain separation.\n * @param field Sensitive field name — the rest of the `info`.\n * @returns A non-extractable AES-256-GCM key for that field's sealed slot.\n */\nexport async function deriveSealedFieldKey(\n dek: CryptoKey,\n collectionName: string,\n field: string,\n): Promise<CryptoKey> {\n const rawDek = await subtle.exportKey('raw', dek)\n const hkdfKey = await subtle.importKey('raw', rawDek, 'HKDF', false, ['deriveBits'])\n const salt = new TextEncoder().encode('noydb-sealed')\n // JSON-array encoding is injective: each element is separately quoted/\n // escaped, so collection `a/sealed/b` + field `c` cannot collide with\n // collection `a` + field `b/sealed/c`.\n const info = new TextEncoder().encode(JSON.stringify(['noydb-sealed', collectionName, field]))\n const bits = await subtle.deriveBits(\n { name: 'HKDF', hash: 'SHA-256', salt, info },\n hkdfKey,\n KEY_BITS,\n )\n return subtle.importKey(\n 'raw',\n bits,\n { name: 'AES-GCM', length: KEY_BITS },\n false,\n ['encrypt', 'decrypt'],\n )\n}\n\n/**\n * Derive a per-record sealed-field key from the record's **per-record CEK**\n * rather than the collection DEK. Same HKDF construction as\n * {@link deriveSealedFieldKey} but with salt `'noydb-sealed-cek'` (distinct\n * from `'noydb-sealed'`), so a CEK-derived key can never collide with a\n * DEK-derived one for the same `{collection, field}`.\n *\n * The point: the sealed ciphertext's only key now flows from the record's CEK.\n * Dropping the record's wrapped `_cek` (crypto-shred / `forget`) makes the key\n * — and thus `_sealed[field]` — unrecoverable, giving sealed fields the same\n * erasure guarantee `_data` already has. The CEK must be extractable (it is —\n * `unwrapCek`/`generateDEK` mint extractable keys).\n *\n * @param cek The record's AES-256-GCM CEK (extractable).\n * @param collectionName Part of the HKDF `info` for domain separation.\n * @param field Sensitive field name — the rest of the `info`.\n * @returns A non-extractable AES-256-GCM key for that field's sealed slot.\n */\nexport async function deriveSealedFieldKeyFromCek(\n cek: CryptoKey,\n collectionName: string,\n field: string,\n): Promise<CryptoKey> {\n const rawCek = await subtle.exportKey('raw', cek)\n const hkdfKey = await subtle.importKey('raw', rawCek, 'HKDF', false, ['deriveBits'])\n const salt = new TextEncoder().encode('noydb-sealed-cek')\n const info = new TextEncoder().encode(JSON.stringify(['noydb-sealed-cek', collectionName, field]))\n const bits = await subtle.deriveBits(\n { name: 'HKDF', hash: 'SHA-256', salt, info },\n hkdfKey,\n KEY_BITS,\n )\n return subtle.importKey(\n 'raw',\n bits,\n { name: 'AES-GCM', length: KEY_BITS },\n false,\n ['encrypt', 'decrypt'],\n )\n}\n\n// ─── Deterministic Encryption ────────────────────────────\n\n/**\n * Derive a deterministic 12-byte IV from `{ DEK, context, plaintext }`\n * via HKDF-SHA256. Given the same three inputs, the IV is identical, so\n * `encryptDeterministic` produces the same ciphertext on every call —\n * which is precisely what enables blind equality search on encrypted\n * fields.\n *\n * **The side channel this opens.** Two records whose field value is the\n * same produce the same ciphertext. An observer with store access can\n * therefore tell which records share a value — not *what* the value is,\n * but the equivalence class. This is the well-known trade-off of\n * deterministic encryption and is why the feature is strictly opt-in\n * per field, guarded by `acknowledgeDeterministicRisk: true` at\n * collection creation.\n *\n * The context string MUST include the collection name and field name,\n * so:\n * - The same plaintext in two different fields encrypts differently\n * (no cross-field equality leak).\n * - The same plaintext in two different collections (different DEKs)\n * encrypts differently by virtue of the key, even before HKDF\n * domain separation kicks in.\n */\nasync function deriveDeterministicIV(\n dek: CryptoKey,\n context: string,\n plaintext: string,\n): Promise<Uint8Array> {\n const rawDek = await subtle.exportKey('raw', dek)\n const hkdfKey = await subtle.importKey('raw', rawDek, 'HKDF', false, ['deriveBits'])\n const salt = new TextEncoder().encode('noydb-deterministic-v1')\n const info = new TextEncoder().encode(`${context}\\x00${plaintext}`)\n const bits = await subtle.deriveBits(\n { name: 'HKDF', hash: 'SHA-256', salt, info },\n hkdfKey,\n IV_BYTES * 8,\n )\n return new Uint8Array(bits)\n}\n\n/**\n * Encrypt a plaintext string with AES-256-GCM and a deterministic,\n * HKDF-derived IV.\n *\n * The same `{ dek, context, plaintext }` triple always produces the\n * same `{ iv, data }` — call this twice and you can string-compare the\n * ciphertexts to check equality of the inputs without decrypting them.\n *\n * @param context Domain-separation string — by convention\n * `'<collection>/<field>'`. Different contexts encrypt\n * the same plaintext to different ciphertexts, so\n * `email` in collection `users` does not collide with\n * `email` in collection `customers`.\n */\nexport async function encryptDeterministic(\n plaintext: string,\n dek: CryptoKey,\n context: string,\n): Promise<EncryptResult> {\n const iv = await deriveDeterministicIV(dek, context, plaintext)\n const encoded = new TextEncoder().encode(plaintext)\n const ciphertext = await subtle.encrypt(\n { name: 'AES-GCM', iv: iv as BufferSource },\n dek,\n encoded,\n )\n return {\n iv: bufferToBase64(iv),\n data: bufferToBase64(ciphertext),\n }\n}\n\n/**\n * Counterpart to {@link encryptDeterministic}. The IV is stored\n * alongside the ciphertext (exactly like the randomized path), so\n * decrypt uses the stored IV and verifies the GCM auth tag — a tampered\n * ciphertext throws `TamperedError` just like randomized AES-GCM.\n */\nexport async function decryptDeterministic(\n ivBase64: string,\n dataBase64: string,\n dek: CryptoKey,\n): Promise<string> {\n return decrypt(ivBase64, dataBase64, dek)\n}\n\n// ─── Random Generation ─────────────────────────────────────────────────\n\n/** Generate a random 12-byte IV for AES-GCM. */\nexport function generateIV(): Uint8Array {\n return globalThis.crypto.getRandomValues(new Uint8Array(IV_BYTES))\n}\n\n/** Generate a random 32-byte salt for PBKDF2. */\nexport function generateSalt(): Uint8Array {\n return globalThis.crypto.getRandomValues(new Uint8Array(SALT_BYTES))\n}\n\n// ─── Base64 Helpers ────────────────────────────────────────────────────\n\nexport function bufferToBase64(buffer: ArrayBuffer | Uint8Array): string {\n const bytes = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer)\n let binary = ''\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]!)\n }\n return btoa(binary)\n}\n\nexport function base64ToBuffer(base64: string): Uint8Array<ArrayBuffer> {\n const binary = atob(base64)\n const bytes = new Uint8Array(binary.length)\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i)\n }\n return bytes\n}\n","/**\n * Per-record CEK lifecycle helpers for the WRITE path.\n *\n * These are the collection-coupled CEK operations, lifted off `Collection`\n * behind narrow deps so the kernel file delegates instead of carrying the\n * crypto inline:\n *\n * - {@link resolveStableCek} — the stable-CEK rule: an update or history\n * snapshot reuses the record's existing CEK so a single CEK delete kills\n * the whole version chain; a genuine insert (or legacy record being\n * migrated) mints a fresh one.\n * - {@link rewrapBodyToDek} — move a record body's wrapping from one DEK to\n * another (tier elevate/demote, bundle re-key) WITHOUT changing the body\n * key: unwrap the CEK under the source DEK, re-encrypt the body under the\n * same CEK, re-wrap the CEK under the destination DEK. History-chain\n * identity is preserved because the body key never changes.\n *\n * Both are pure functions over their deps — the `cekCache` ownership stays on\n * the collection (its lifetime is tied to `load()`), so callers cache the\n * returned key themselves.\n */\nimport { encrypt, decrypt, generateDEK, wrapCek, unwrapCek, type EnclaveKey } from '../crypto.js'\nimport type { EncryptedEnvelope } from '../../types.js'\nimport type { Lru } from '../../cache/index.js'\n\n/** Dependencies {@link resolveStableCek} needs from its collection. */\nexport interface StableCekDeps {\n /** The collection's per-record CEK cache (`null` → no caching). */\n readonly cache: Lru<string, EnclaveKey> | null\n /** Read the record's live envelope (to recover an existing `_cek`). */\n getLive(id: string): Promise<EncryptedEnvelope | null>\n /** The DEK the CEK is wrapped under (the collection DEK on the normal path). */\n getDEK(): Promise<EnclaveKey>\n}\n\n/**\n * Resolve the stable CEK for a record on the write path. Caches the resolved\n * key under `id` so an update + its history snapshot share one CEK.\n */\nexport async function resolveStableCek(deps: StableCekDeps, id: string): Promise<EnclaveKey> {\n const cached = deps.cache?.get(id)\n if (cached) return cached\n\n const live = await deps.getLive(id)\n if (live?._cek !== undefined) {\n const cek = await unwrapCek(live._cek, await deps.getDEK())\n deps.cache?.set(id, cek, 1)\n return cek\n }\n\n const fresh = await generateDEK()\n deps.cache?.set(id, fresh, 1)\n return fresh\n}\n\n/** Re-wrapped body bytes + the (optional) CEK to cache. */\nexport interface RewrappedBody {\n readonly _iv: string\n readonly _data: string\n /** Present iff the source envelope carried a CEK (per-record-key record). */\n readonly _cek?: string\n /** The body key when one exists, so the caller can cache it; `null` for a legacy record. */\n readonly cek: EnclaveKey | null\n}\n\n/**\n * Move a record body from `fromDek` to `toDek`.\n *\n * - Per-record-key record (`_cek` present): unwrap the CEK under `fromDek`,\n * re-encrypt the body under the SAME CEK, re-wrap the CEK under `toDek`. The\n * body key is unchanged → history-chain identity preserved.\n * - Legacy record (no `_cek`): decrypt under `fromDek`, re-encrypt under `toDek`\n * directly — byte-for-byte the pre-CEK behaviour.\n */\nexport async function rewrapBodyToDek(\n envelope: Pick<EncryptedEnvelope, '_iv' | '_data' | '_cek'>,\n fromDek: EnclaveKey,\n toDek: EnclaveKey,\n): Promise<RewrappedBody> {\n if (envelope._cek !== undefined) {\n const cek = await unwrapCek(envelope._cek, fromDek)\n const plaintext = await decrypt(envelope._iv, envelope._data, cek)\n const { iv, data } = await encrypt(plaintext, cek)\n return { _iv: iv, _data: data, _cek: await wrapCek(cek, toDek), cek }\n }\n const plaintext = await decrypt(envelope._iv, envelope._data, fromDek)\n const { iv, data } = await encrypt(plaintext, toDek)\n return { _iv: iv, _data: data, cek: null }\n}\n","/**\n * Tombstone shape + predicate for the per-record-key (CEK) layer.\n *\n * A *tombstone* is the residue a GDPR crypto-shred (`vault.forget()`)\n * leaves on disk: the live envelope rewritten to `{ _noydb, _v, _ts, _by,\n * _iv:'', _data:'' }`, dropping `_iv`/`_data`/`_cek`/`_det`. With the wrapped\n * per-record CEK gone, the body — and every history version under the same\n * CEK — is permanently undecryptable, while the record KEY survives so the\n * version counter and \"record existed and was erased\" persist for the audit\n * ledger.\n *\n * These two helpers are the pure, collection-independent core of that\n * contract: {@link buildTombstone} mints the shape, {@link isTombstone}\n * recognises it on the read path. The orchestration that *writes* a tombstone\n * (`_writeTombstone`) and drives `vault.forget()` lives with the collection /\n * vault; it calls into these.\n */\nimport { NOYDB_FORMAT_VERSION, type EncryptedEnvelope } from '../../types.js'\n\n/**\n * Is this envelope a crypto-shred tombstone?\n *\n * A tombstone carries no body (`_data` empty) and no wrapped CEK (`_cek`\n * absent) — decrypting it would call `decrypt('', '', dek)` → an AES-GCM\n * throw, so every read choke point must short-circuit to `null` instead.\n *\n * `encrypted` is the collection's encryption flag: on an unencrypted\n * collection there are no envelopes to shred, so nothing is ever a tombstone.\n * (Legacy migration envelopes carry non-empty `_iv`/`_data`, so they are not\n * tombstones and stay readable.)\n */\nexport function isTombstone(envelope: EncryptedEnvelope, encrypted: boolean): boolean {\n if (!encrypted) return false\n return !envelope._data && envelope._cek === undefined\n}\n\n/**\n * Mint a tombstone envelope from a record's live version + actor.\n *\n * Keeps `_v` (the displaced version) so the counter is monotonic across the\n * shred, stamps a fresh `_ts`, and records `_by` when an actor is supplied.\n * Deliberately omits `_iv`/`_data`/`_cek`/`_det` — that omission *is* the\n * erasure.\n */\nexport function buildTombstone(version: number, actor: string): EncryptedEnvelope {\n return {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: version,\n _ts: new Date().toISOString(),\n _iv: '',\n _data: '',\n ...(actor ? { _by: actor } : {}),\n }\n}\n","/**\n * Sealed-slot (`iv:data`) parsing + the CEK/DEK dual-read, factored out so the\n * three callers that decrypt a `_sealed[field]` slot share ONE implementation\n * with no coupling between them:\n *\n * - {@link RecordCodec.unsealField} / `classifySealedShred` (read + classify),\n * - `record-keys/sealing.ts:rotateRecordCek` (re-seal under a new CEK).\n *\n * These are pure helpers over an explicit `(cek, dek)` pair — NOT a context\n * object — so `sealing.ts` (which holds only the DEK) can import them without\n * pulling in the whole codec, avoiding a codec↔sealing dependency cycle.\n */\nimport { decrypt, deriveSealedFieldKey, deriveSealedFieldKeyFromCek } from '../crypto.js'\n\n/** Parse an `iv:data` sealed slot (split on the FIRST `:`). */\nexport function parseSealedSlot(blob: string): { iv: string; data: string } {\n const sep = blob.indexOf(':')\n return { iv: blob.slice(0, sep), data: blob.slice(sep + 1) }\n}\n\n/**\n * Dual-read: decrypt a sealed slot trying the CEK-derived field key first,\n * falling back to the collection-DEK field key. Legacy records\n * (even ones whose body is CEK-encrypted) are sealed under the collection-DEK\n * key; current writes seal under the per-record CEK. Try the CEK key first; on\n * its AES-GCM auth failure, fall back to the DEK key. Throws only if BOTH fail.\n * Returns the plaintext string (callers `JSON.parse` as needed).\n */\nexport async function dualReadSealedSlot(\n blob: string,\n field: string,\n collection: string,\n cek: CryptoKey | undefined,\n dek: CryptoKey,\n): Promise<string> {\n const { iv, data } = parseSealedSlot(blob)\n if (cek !== undefined) {\n try {\n const fieldKey = await deriveSealedFieldKeyFromCek(cek, collection, field)\n return await decrypt(iv, data, fieldKey)\n } catch {\n // fall through to the legacy collection-DEK derivation\n }\n }\n const fieldKey = await deriveSealedFieldKey(dek, collection, field)\n return decrypt(iv, data, fieldKey)\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 * RecordCodec — the per-record envelope build + encrypt/decrypt + per-record-CEK\n * + sealed-field crypto.\n *\n * `Collection` holds one `RecordCodec` instance and delegates the crypto write\n * path (`encryptRecord` / `encryptJsonString` / `buildDebugEnvelope`), the read\n * path (`decryptRecord` / `decryptJsonString` / `resolveEnvelopeCek`), and the\n * sealed-field helpers (`unsealField` / `makeSealedHandle` / `toCacheRecord` /\n * `classifySealedShred`) to it. The codec receives every `this.*` dependency\n * it needs via {@link RecordCodecContext}.\n *\n * The crux is `cekCache`: it is the SAME `Lru` reference `Collection` owns (not\n * a copy). `resolveEnvelopeCek` reads/writes it, and tier methods +\n * `vault.invalidateRecordCaches` keep mutating that same object — a copy would\n * silently break the \"single CEK delete kills the version chain\" invariant.\n *\n * Internal service — not exported as a `@noy-db/hub/*` subpath.\n */\nimport { encrypt, decrypt, encryptDeterministic, wrapCek, unwrapCek, deriveSealedFieldKey, deriveSealedFieldKeyFromCek, type EnclaveKey } from '../crypto.js'\nimport { NOYDB_FORMAT_VERSION, SealedHandle, type EncryptedEnvelope, type CrdtMode, type CrdtState, type CrdtStrategy } from '../../types.js'\nimport { isTombstone } from './tombstone.js'\nimport { parseSealedSlot, dualReadSealedSlot } from './sealed-slot.js'\nimport { DebugReservedFieldError } from '../../errors.js'\nimport { validateSchemaOutput, type StandardSchemaV1 } from '../../schema.js'\nimport type { Lru } from '../../cache/index.js'\n\n/** Everything the moving crypto methods touched on `this.*`, as a flat context. */\nexport interface RecordCodecContext<T> {\n /** Collection name — the crypto AAD scope and schema-error context. */\n readonly name: string\n /** Actor id stamped on `_by` (the collection's keyring.userId). */\n readonly actor: string\n /** False on plaintext collections — selects the no-ciphertext envelope branch. */\n readonly storeCiphertext: boolean\n /** keyring.debugPlaintext — debug-inline envelope on user collections. */\n readonly debugPlaintext: boolean\n /** Emit `_source`/`_sourceTs` provenance fields when a source is supplied. */\n readonly provenance: boolean\n /** Declared `sensitive` fields → sealed into `_sealed[field]`. */\n readonly sensitiveFields: ReadonlySet<string>\n /** Declared deterministic-index fields, or null. */\n readonly deterministicFields: ReadonlySet<string> | null\n /** CRDT mode (decrypt resolves CrdtState→snapshot when set). */\n readonly crdtMode: CrdtMode | undefined\n /** CRDT strategy seam (resolveCrdtSnapshot). */\n readonly crdtStrategy: CrdtStrategy\n /** Output-schema validator, or undefined. */\n readonly schema: StandardSchemaV1<unknown, T> | undefined\n /** The collection DEK (codec only ever needs this.name's DEK). */\n getDEK(): Promise<EnclaveKey>\n /**\n * The collection's per-record CEK cache (SHARED reference, not a copy).\n * Ownership/lifetime stays on Collection; codec reads+writes it in\n * resolveEnvelopeCek exactly as the inline code did. `null` → no caching.\n */\n readonly cekCache: Lru<string, EnclaveKey> | null\n}\n\nexport class RecordCodec<T> {\n constructor(private readonly ctx: RecordCodecContext<T>) {}\n\n // ──────────────────────────────────────────────────────────────────────\n // Low-level literal builders\n // ──────────────────────────────────────────────────────────────────────\n\n /**\n * Assemble a canonical ciphertext body envelope literal from already-computed\n * parts. Pure, no crypto. Each call stamps its own `_ts` — provenance carries\n * a SEPARATE timestamp (computed by the caller), so the two never share one.\n */\n static buildEnvelope(p: {\n version: number\n iv: string\n data: string\n by?: string\n cek?: string\n provenance?: { source: string; sourceTs: string } | undefined\n extra?: Partial<Pick<EncryptedEnvelope, '_tier' | '_det' | '_sealed'>>\n }): EncryptedEnvelope {\n return {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: p.version,\n _ts: new Date().toISOString(),\n _iv: p.iv,\n _data: p.data,\n ...(p.by !== undefined ? { _by: p.by } : {}),\n ...(p.cek !== undefined ? { _cek: p.cek } : {}),\n ...(p.provenance !== undefined ? { _source: p.provenance.source, _sourceTs: p.provenance.sourceTs } : {}),\n ...(p.extra ?? {}),\n }\n }\n\n /** Plaintext (`_iv:''`) body envelope — the `!storeCiphertext` shape. */\n static buildPlaintextEnvelope(p: {\n version: number\n data: string\n by?: string\n provenance?: { source: string; sourceTs: string } | undefined\n }): EncryptedEnvelope {\n return {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: p.version,\n _ts: new Date().toISOString(),\n _iv: '',\n _data: p.data,\n ...(p.by !== undefined ? { _by: p.by } : {}),\n ...(p.provenance !== undefined ? { _source: p.provenance.source, _sourceTs: p.provenance.sourceTs } : {}),\n }\n }\n\n // ──────────────────────────────────────────────────────────────────────\n // Write path\n // ──────────────────────────────────────────────────────────────────────\n\n /**\n * Build a debug-plaintext envelope: the record's own fields inlined as\n * top-level keys beside the reserved `_`-metadata, with `_debug: 1` and an\n * empty `_data`. Lets native store tooling read the record without\n * unwrapping. Only reached for user collections under `debugPlaintext`\n * (see {@link encryptRecord}). Rejects `_`-prefixed record fields, which\n * would collide with the reserved metadata namespace.\n */\n buildDebugEnvelope(record: T, version: number, source?: string, sourceTs?: string): EncryptedEnvelope {\n const rec = record as unknown as Record<string, unknown>\n for (const key of Object.keys(rec)) {\n if (key.startsWith('_')) throw new DebugReservedFieldError(this.ctx.name, key)\n }\n return {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: version,\n _ts: new Date().toISOString(),\n _iv: '',\n _data: '',\n _by: this.ctx.actor,\n _debug: NOYDB_FORMAT_VERSION,\n ...(this.ctx.provenance && source !== undefined ? { _source: source, _sourceTs: sourceTs ?? new Date().toISOString() } : {}),\n ...rec,\n } as unknown as EncryptedEnvelope\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 async encryptJsonString(\n json: string,\n version: number,\n cek?: EnclaveKey,\n source?: string,\n sourceTs?: string,\n ): Promise<EncryptedEnvelope> {\n const by = this.ctx.actor\n const provenance = this.ctx.provenance && source !== undefined\n ? { source, sourceTs: sourceTs ?? new Date().toISOString() }\n : undefined\n\n if (!this.ctx.storeCiphertext) {\n return RecordCodec.buildPlaintextEnvelope({ version, data: json, by, provenance })\n }\n\n const dek = await this.ctx.getDEK()\n\n if (cek !== undefined) {\n const { iv, data } = await encrypt(json, cek)\n const wrapped = await wrapCek(cek, dek)\n return RecordCodec.buildEnvelope({ version, iv, data, by, cek: wrapped, provenance })\n }\n\n const { iv, data } = await encrypt(json, dek)\n return RecordCodec.buildEnvelope({ version, iv, data, by, provenance })\n }\n\n async encryptRecord(\n record: T,\n version: number,\n cek?: EnclaveKey,\n source?: string,\n sourceTs?: string,\n ): Promise<EncryptedEnvelope> {\n // Debug-plaintext: write user-collection records with their fields inlined\n // beside the envelope metadata so native store tools read them directly.\n // Internal (`_`-prefixed) collections keep the classic shape — some store\n // `_`-prefixed fields that the inline layout would collide with.\n if (!this.ctx.storeCiphertext && this.ctx.debugPlaintext && !this.ctx.name.startsWith('_')) {\n return this.buildDebugEnvelope(record, version, source, sourceTs)\n }\n\n // Structural group-encryption: peel declared sensitive fields out\n // of the record BEFORE building `_data`, sealing each into its own\n // `_sealed[field]` slot under a per-field key. Default-off — with no\n // sensitive fields the open record is unchanged and no `_sealed` is\n // emitted, so the envelope stays byte-identical to legacy output.\n let openRecord = record\n let sealed: Record<string, string> | undefined\n if (this.ctx.storeCiphertext && this.ctx.sensitiveFields.size > 0) {\n const src = record as unknown as Record<string, unknown>\n const dek = await this.ctx.getDEK()\n const open: Record<string, unknown> = { ...src }\n const slots: Record<string, string> = {}\n for (const field of this.ctx.sensitiveFields) {\n if (!(field in src)) continue\n const value = src[field]\n if (value === undefined) continue\n const fieldKey = cek !== undefined\n ? await deriveSealedFieldKeyFromCek(cek, this.ctx.name, field)\n : await deriveSealedFieldKey(dek, this.ctx.name, field)\n const { iv, data } = await encrypt(JSON.stringify(value), fieldKey)\n slots[field] = `${iv}:${data}`\n delete open[field]\n }\n if (Object.keys(slots).length > 0) {\n sealed = slots\n openRecord = open as unknown as T\n }\n }\n\n const base = await this.encryptJsonString(JSON.stringify(openRecord), version, cek, source, sourceTs)\n const withSealed = sealed ? { ...base, _sealed: sealed } : base\n if (!this.ctx.deterministicFields || !this.ctx.storeCiphertext) return withSealed\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. Sealed fields are\n // excluded — they live only in `_sealed`, never the `_det` index.\n const dek = await this.ctx.getDEK()\n const rec = record as unknown as Record<string, unknown>\n const det: Record<string, string> = {}\n for (const field of this.ctx.deterministicFields) {\n if (this.ctx.sensitiveFields.has(field)) continue\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.ctx.name}/${field}`)\n det[field] = `${iv}:${data}`\n }\n if (Object.keys(det).length === 0) return withSealed\n return { ...withSealed, _det: det }\n }\n\n // ──────────────────────────────────────────────────────────────────────\n // Read path\n // ──────────────────────────────────────────────────────────────────────\n\n /**\n * Resolve the per-record CEK for a stored envelope, or `undefined` for a\n * legacy (`_cek`-absent) envelope. Unwraps `_cek` under the collection DEK and\n * memoises it in the CEK cache under `id` (when supplied) so repeated reads of\n * the same record skip the unwrap. Shared by the body-decrypt path\n * ({@link decryptJsonString}) and the sealed-field path ({@link decryptRecord}\n * / {@link toCacheRecord}) so both agree on the record's key.\n */\n async resolveEnvelopeCek(envelope: EncryptedEnvelope, id?: string): Promise<EnclaveKey | undefined> {\n if (envelope._cek === undefined) return undefined\n const cached = id !== undefined ? this.ctx.cekCache?.get(id) : undefined\n if (cached !== undefined) return cached\n const dek = await this.ctx.getDEK()\n const cek = await unwrapCek(envelope._cek, dek)\n if (id !== undefined) this.ctx.cekCache?.set(id, cek, 1)\n return cek\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 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.storeCiphertext`) legitimately\n // have empty `_iv`/`_data`, so `isTombstone` is false for them — preserved.\n if (isTombstone(envelope, this.ctx.storeCiphertext)) return null\n if (!this.ctx.storeCiphertext) {\n // Debug-plaintext layout: record fields were inlined as top-level keys\n // (see buildDebugEnvelope). Reconstruct the record from the non-`_`\n // keys. Self-describing via `_debug`, so a classic plaintext reader\n // handles debug-written envelopes too.\n if (envelope._debug !== undefined) {\n const rec: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(envelope)) {\n if (!key.startsWith('_')) rec[key] = value\n }\n return JSON.stringify(rec)\n }\n return envelope._data\n }\n const cek = await this.resolveEnvelopeCek(envelope, id)\n if (cek !== undefined) return decrypt(envelope._iv, envelope._data, cek)\n const dek = await this.ctx.getDEK()\n return decrypt(envelope._iv, envelope._data, dek)\n }\n\n /**\n * Unseal a single `_sealed[field]` slot to its plaintext value: derive the\n * per-field key off the collection DEK, AES-GCM-decrypt the `iv:data` blob,\n * and JSON-parse the result. Shared by both the inline-decrypt path and a\n * {@link Sealed} handle's `reveal()` — so the on-demand reveal and the eager\n * materialisation always agree byte-for-byte.\n */\n async unsealField(field: string, blob: string, cek?: EnclaveKey): Promise<unknown> {\n // Dual-read. Current writes seal under a key derived from the record's\n // per-record CEK; legacy records (even ones whose body is\n // CEK-encrypted) are sealed under the collection-DEK key. Try the CEK key\n // first; on its AES-GCM auth failure, fall back to the DEK key. Without this\n // fallback every legacy `_sealed` record would throw TamperedError (data loss).\n const dek = await this.ctx.getDEK()\n return JSON.parse(await dualReadSealedSlot(blob, field, this.ctx.name, cek, dek))\n }\n\n /**\n * Classify a live envelope's `_sealed` slots for crypto-shred completeness.\n * `forget()` drops `_cek`/`_sealed` but\n * RETAINS the collection DEK, so only a slot keyed off the per-record CEK is\n * genuinely shredded by the tombstone; a legacy slot keyed off the\n * collection DEK survives in any synced/backup copy.\n *\n * Mirrors {@link unsealField}'s dual-read split: try the CEK-derived key per\n * slot — success → `shreddable`, AES-GCM auth failure → `dekResidue`. With no\n * `_cek` (pure legacy collection-DEK sealing) ALL slots are residue.\n */\n async classifySealedShred(\n live: EncryptedEnvelope,\n ): Promise<{ shreddable: string[]; dekResidue: string[] }> {\n const shreddable: string[] = []\n const dekResidue: string[] = []\n const sealed = live._sealed\n if (sealed === undefined) return { shreddable, dekResidue }\n const cek = await this.resolveEnvelopeCek(live)\n for (const [field, blob] of Object.entries(sealed)) {\n if (cek === undefined) { dekResidue.push(field); continue }\n const { iv, data } = parseSealedSlot(blob)\n try {\n await decrypt(iv, data, await deriveSealedFieldKeyFromCek(cek, this.ctx.name, field))\n shreddable.push(field)\n } catch {\n dekResidue.push(field)\n }\n }\n return { shreddable, dekResidue }\n }\n\n /**\n * Build a non-leaking {@link Sealed} handle over a sealed field's ciphertext.\n * The handle captures only the ciphertext `blob` and a closure to\n * {@link unsealField}; the plaintext is never stored on it — so the handle\n * may sit in the working-set cache (or be logged/serialised) without\n * exposing the value, which decrypts only on `reveal()`.\n */\n makeSealedHandle(field: string, blob: string, cek?: EnclaveKey): SealedHandle<unknown> {\n return new SealedHandle(() => this.unsealField(field, blob, cek))\n }\n\n /**\n * Replace a record's declared sensitive fields with {@link Sealed} handles\n * built from the just-written envelope's `_sealed` slots, leaving every\n * other field as its plaintext value. Used to populate the cache on the\n * write path without ever materialising sealed plaintext into it. Returns\n * `record` untouched when the collection seals nothing.\n */\n async toCacheRecord(record: T, envelope: EncryptedEnvelope, id?: string): Promise<T> {\n const sealed = envelope._sealed\n if (sealed === undefined || !this.ctx.storeCiphertext || this.ctx.sensitiveFields.size === 0) {\n return record\n }\n const cek = await this.resolveEnvelopeCek(envelope, id)\n const clone = { ...(record as unknown as Record<string, unknown>) }\n for (const [field, blob] of Object.entries(sealed)) {\n clone[field] = this.makeSealedHandle(field, blob, cek)\n }\n return clone as unknown as T\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 async decryptRecord(\n envelope: EncryptedEnvelope,\n opts: { skipValidation?: boolean; id?: string; sealedAsHandles?: boolean } = {},\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.ctx.crdtMode && parsed !== null && typeof parsed === 'object' && '_crdt' in parsed) {\n parsed = this.ctx.crdtStrategy.resolveCrdtSnapshot(parsed as CrdtState)\n }\n\n let record = parsed as T\n\n // Structural group-encryption + sealed access gate.\n // Each `_sealed[field]` slot is restored under its own per-field key.\n // `sealedAsHandles: false` (default — internal callers that compute on\n // real values) inline-decrypts to the plaintext value; `true` (the\n // public / cache path) yields an opaque {@link Sealed} handle so the\n // plaintext is never materialised into the working-set cache.\n if (envelope._sealed !== undefined && this.ctx.storeCiphertext) {\n const sealedCek = await this.resolveEnvelopeCek(envelope, opts.id)\n const target = record as unknown as Record<string, unknown>\n for (const [field, blob] of Object.entries(envelope._sealed)) {\n target[field] = opts.sealedAsHandles\n ? this.makeSealedHandle(field, blob, sealedCek)\n : await this.unsealField(field, blob, sealedCek)\n }\n }\n\n // Skip output validation when sealed fields are returned as handles:\n // the record carries opaque `Sealed` handles in place of the declared\n // values, so a whole-record schema check would false-positive on them.\n // (The values were validated on input/write; the open fields are\n // unchanged from the validated body.) The inline-value path below still\n // validates fully.\n const sealedAsHandles = opts.sealedAsHandles === true && envelope._sealed !== undefined\n if (this.ctx.schema !== undefined && !opts.skipValidation && !sealedAsHandles) {\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.ctx.schema,\n record,\n `${this.ctx.name}@v${envelope._v}`,\n )\n }\n\n return record\n }\n}\n","/**\n * Record-scoped CEK sealing — grantor side.\n *\n * The **grantor** holds the collection DEK and seals ONE record's CEK to an\n * `at-*` host so that host — and only that host — can decrypt exactly that\n * record, with no access to the vault DEK and no ability to read any other\n * record. This is the counterpart to the host-side `openSealedRecord`\n * (`@noy-db/hub/sealed-record`), which holds no DEK.\n *\n * These functions are the orchestration behind `vault.sealRecordToHost` /\n * `vault.revokeSealedRecord` / `vault.rotateRecordCek`, lifted off `Vault`\n * behind a narrow {@link SealingContext} so the kernel file delegates. They\n * live in `record-keys/` (the vault-side CEK policy layer), NOT in\n * `sealed-record/`, so the host-side subpath stays DEK-free — the wire\n * *types* they share are spine-owned (`kernel/types.ts`), not imported from\n * `sealed-record/` directly.\n */\nimport { encrypt, decrypt, generateDEK, wrapCek, unwrapCek, bufferToBase64, deriveSealedFieldKeyFromCek, type EnclaveKey } from '../crypto.js'\nimport {\n NOYDB_FORMAT_VERSION,\n type EncryptedEnvelope,\n type NoydbStore,\n type RecipientSealer,\n type SealedCekBinding,\n type SealedCekDeliveryEnvelope,\n} from '../../types.js'\nimport { dualReadSealedSlot } from './sealed-slot.js'\nimport { RecordCekNotFoundError, ValidationError } from '../../errors.js'\n\nconst subtle = globalThis.crypto.subtle\n\n/** The `_sealed_cek` delivery namespace (one envelope per `collection/id/pid`). */\nexport const SEALED_CEK_NS = '_sealed_cek'\n\n/** What the grantor functions need from their `Vault`. */\nexport interface SealingContext {\n readonly adapter: NoydbStore\n /** Vault id (the adapter's first coordinate). */\n readonly vault: string\n /** Resolve the DEK a record's CEK is wrapped under. */\n getDEK(collection: string): Promise<EnclaveKey>\n /** Actor id stamped on `_by` (empty string → omit). */\n readonly actor: string\n /** Evict the per-record CEK cache + decrypted-record cache after a rotation. */\n invalidateRecordCaches(collection: string, id: string): Promise<void>\n}\n\n/**\n * Seal a record's CEK to a host. See `vault.sealRecordToHost` for the contract.\n * Returns `{ pid, envelopeKey }`.\n */\nexport async function sealRecordToHost(\n ctx: SealingContext,\n collection: string,\n id: string,\n hostSealer: RecipientSealer,\n opts: { expiresAt: string },\n): Promise<{ pid: string; envelopeKey: string }> {\n // Guard separators: the `_sealed_cek` id is `collection/id/pid`, so a `/` in\n // any component would make the prefix-delete in rotateRecordCek() (which\n // matches `${collection}/${id}/`) ambiguous and could over- or under-match.\n if (collection.includes('/')) throw new ValidationError(`sealRecordToHost: collection \"${collection}\" must not contain \"/\"`)\n if (id.includes('/')) throw new ValidationError(`sealRecordToHost: id \"${id}\" must not contain \"/\"`)\n // M-4: reject a malformed/empty expiry at seal time. `Date.parse('')` (and any\n // non-ISO string) is NaN, and the open-time check `NaN <= now` is `false` — so\n // a malformed expiry would silently mint an ETERNAL grant. A *past* (but valid)\n // timestamp is still allowed: it seals, then fails closed at open time.\n if (Number.isNaN(Date.parse(opts.expiresAt))) {\n throw new ValidationError(`sealRecordToHost: expiresAt \"${opts.expiresAt}\" is not a valid ISO 8601 timestamp`)\n }\n\n const live = await ctx.adapter.get(ctx.vault, collection, id)\n if (!live || live._cek === undefined) {\n throw new RecordCekNotFoundError(collection, id)\n }\n\n const dek = await ctx.getDEK(collection)\n const cek = await unwrapCek(live._cek, dek)\n const rawCek = await subtle.exportKey('raw', cek)\n const cekB64 = bufferToBase64(rawCek)\n\n const hint = await hostSealer.publishRecipientHint()\n if (hint.pid.includes('/')) throw new ValidationError(`sealRecordToHost: recipient pid \"${hint.pid}\" must not contain \"/\"`)\n\n const binding: SealedCekBinding = {\n collection,\n id,\n cek: cekB64,\n expiresAt: opts.expiresAt,\n }\n const sealed = await hostSealer.sealForRecipient(\n new TextEncoder().encode(JSON.stringify(binding)),\n hint,\n )\n\n const delivery: SealedCekDeliveryEnvelope = {\n v: 1,\n _noydb_sealed_cek: 1,\n pid: hint.pid,\n payload: bufferToBase64(sealed),\n expiresAt: opts.expiresAt,\n }\n\n const envelopeKey = `${collection}/${id}/${hint.pid}`\n const prior = await ctx.adapter.get(ctx.vault, SEALED_CEK_NS, envelopeKey)\n const env: EncryptedEnvelope = {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: (prior?._v ?? 0) + 1,\n _ts: new Date().toISOString(),\n // AES-GCM bypassed — the sealing layer is the security boundary, exactly\n // like the managed-passphrase `_meta/sealed-passphrase` envelope.\n _iv: '',\n _data: JSON.stringify(delivery),\n ...(ctx.actor ? { _by: ctx.actor } : {}),\n }\n await ctx.adapter.put(ctx.vault, SEALED_CEK_NS, envelopeKey, env)\n\n return { pid: hint.pid, envelopeKey }\n}\n\n/**\n * Revoke one sealed-CEK grant.\n *\n * **Default (`{ hard: false }`) is SOFT** — it only deletes the delivery\n * envelope from the store. A host that already fetched (or cached the unsealed\n * CEK from) that envelope KEEPS decrypt capability for the record; soft revoke\n * is a \"stop new fetches\" control, not a cryptographic cutoff.\n *\n * **`{ hard: true }`** additionally rotates the record's CEK (via\n * {@link rotateRecordCek}): the live body is re-encrypted under a fresh CEK and\n * EVERY sealed-CEK delivery envelope for the record (all pids) is deleted, so\n * any previously-sealed CEK fails the AES-GCM auth tag on the rotated body —\n * future opens are cryptographically denied. (PRE-rotation history versions,\n * which keep their old `_cek`, remain openable — same semantics as\n * `rotateRecordCek`.)\n */\nexport async function revokeSealedRecord(\n ctx: SealingContext,\n collection: string,\n id: string,\n pid: string,\n opts?: { hard?: boolean },\n): Promise<void> {\n if (opts?.hard === true) {\n // Hard revocation supersedes the single-pid soft delete: rotateRecordCek\n // re-keys the record and drops every delivery envelope for it.\n await rotateRecordCek(ctx, collection, id)\n return\n }\n await ctx.adapter.delete(ctx.vault, SEALED_CEK_NS, `${collection}/${id}/${pid}`)\n}\n\n/**\n * HARD-rotate a record's CEK: re-encrypt the live body under a fresh CEK, evict\n * caches, and delete EVERY sealed-CEK delivery envelope for the record. See\n * `vault.rotateRecordCek` for why this bypasses `Collection.put` (no guards, no\n * history bump — a key rotation must not re-encrypt prior history under the new\n * CEK).\n */\nexport async function rotateRecordCek(\n ctx: SealingContext,\n collection: string,\n id: string,\n): Promise<void> {\n const live = await ctx.adapter.get(ctx.vault, collection, id)\n if (!live || live._cek === undefined) {\n throw new RecordCekNotFoundError(collection, id)\n }\n\n const dek = await ctx.getDEK(collection)\n const oldCek = await unwrapCek(live._cek, dek)\n const json = await decrypt(live._iv, live._data, oldCek)\n\n const newCek = await generateDEK()\n const { iv, data } = await encrypt(json, newCek)\n\n // Sealed fields are keyed off the per-record CEK, so a rotation\n // must RE-ENCRYPT each `_sealed[field]` under the new CEK (carrying the old\n // slots forward would orphan them — the old CEK is gone after this rotate).\n // Dual-read the old slot: try the old-CEK-derived key, fall\n // back to the collection-DEK key (legacy), then re-seal under newCek.\n let sealedOut: Record<string, string> | undefined\n if (live._sealed !== undefined) {\n const out: Record<string, string> = {}\n for (const [field, slot] of Object.entries(live._sealed)) {\n const plaintext = await dualReadSealedSlot(slot, field, collection, oldCek, dek)\n const resealed = await encrypt(plaintext, await deriveSealedFieldKeyFromCek(newCek, collection, field))\n out[field] = `${resealed.iv}:${resealed.data}`\n }\n sealedOut = out\n }\n\n const env: EncryptedEnvelope = {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: live._v + 1,\n _ts: new Date().toISOString(),\n _iv: iv,\n _data: data,\n _cek: await wrapCek(newCek, dek),\n ...(ctx.actor ? { _by: ctx.actor } : {}),\n ...(live._tier !== undefined ? { _tier: live._tier } : {}),\n ...(live._det !== undefined ? { _det: live._det } : {}),\n // Re-encrypt sealed (`sensitive`) fields under the new CEK. Sealed\n // keys derive off the per-record CEK, so the rotated record's old CEK is\n // destroyed here — carrying the old `_sealed` slots forward verbatim would\n // orphan them (unreadable under the new CEK). `sealedOut` holds the slots\n // dual-read from the old CEK (or the legacy DEK) and re-sealed under newCek.\n ...(sealedOut !== undefined ? { _sealed: sealedOut } : {}),\n }\n await ctx.adapter.put(ctx.vault, collection, id, env)\n\n // Evict BOTH caches synchronously so no read returns the stale old-CEK record.\n await ctx.invalidateRecordCaches(collection, id)\n\n // Delete every sealed-CEK delivery envelope for this record — all pids.\n const prefix = `${collection}/${id}/`\n const keys = await ctx.adapter.list(ctx.vault, SEALED_CEK_NS)\n for (const key of keys) {\n if (key.startsWith(prefix)) {\n await ctx.adapter.delete(ctx.vault, SEALED_CEK_NS, key)\n }\n }\n}\n","/**\n * Deterministic-index lookups (`findByDet` / `queryByDet`).\n *\n * A collection that declares `deterministicFields` stamps a deterministic\n * AES-GCM ciphertext for each such field on the envelope's `_det` slot at write\n * time (the encrypt side lives in {@link RecordCodec.encryptRecord}). These\n * helpers are the READ side: recompute the deterministic ciphertext for a query\n * value and scan the adapter for envelopes whose `_det[field]` matches — no\n * record bodies are decrypted during the scan, which is the whole point of a\n * deterministic index.\n *\n * Both functions take a small {@link DeterministicContext} (the exact `this.*`\n * the moving methods touched) instead of `this`, mirroring the `record-keys/`\n * siblings. Behaviour is byte-identical to the inline code they replaced.\n *\n * Internal service — not exported as a `@noy-db/hub/*` subpath.\n */\nimport { encryptDeterministic, type EnclaveKey } from '../crypto.js'\nimport type { NoydbStore } from '../../types.js'\nimport type { RecordCodec } from './record-codec.js'\n\n/** Everything the moving deterministic-index methods touched on `this.*`. */\nexport interface DeterministicContext<T> {\n /** Collection name — the deterministic-encryption AAD scope. */\n readonly name: string\n /** Vault namespace the records live under. */\n readonly vault: string\n /** The ciphertext store (scanned envelope-by-envelope). */\n readonly adapter: NoydbStore\n /** Declared deterministic-index fields, or null when the feature is off. */\n readonly deterministicFields: ReadonlySet<string> | null\n /** False on plaintext collections — det lookups are encrypted-only. */\n readonly storeCiphertext: boolean\n /** The collection DEK resolver. */\n getDEK(): Promise<EnclaveKey>\n /** The record codec — decrypts a matched envelope to T. */\n readonly codec: RecordCodec<T>\n}\n\n/** Recompute the deterministic ciphertext target for a query value. */\nasync function detTarget<T>(ctx: DeterministicContext<T>, field: string, value: unknown): Promise<string> {\n const dek = await ctx.getDEK()\n const plaintext = typeof value === 'string' ? value : JSON.stringify(value)\n const { iv, data } = await encryptDeterministic(plaintext, dek, `${ctx.name}/${field}`)\n return `${iv}:${data}`\n}\n\nfunction assertDetField<T>(ctx: DeterministicContext<T>, field: string, method: string): void {\n if (!ctx.deterministicFields || !ctx.deterministicFields.has(field)) {\n throw new Error(\n `Collection \"${ctx.name}\": field \"${field}\" is not declared in deterministicFields`,\n )\n }\n if (!ctx.storeCiphertext) {\n throw new Error(\n `Collection \"${ctx.name}\": ${method} is only meaningful on encrypted collections`,\n )\n }\n}\n\n/**\n * Find the first record whose deterministic field matches the given plaintext.\n * Returns `null` when no match exists.\n *\n * Reads every envelope via the adapter and compares the stored `_det[field]` to\n * a freshly computed deterministic ciphertext — no record bodies are decrypted\n * during the search.\n *\n * Throws when the field is not declared in `deterministicFields`, so a typo\n * fails loudly at the call site rather than silently returning null forever.\n */\nexport async function findByDet<T>(ctx: DeterministicContext<T>, field: string, value: unknown): Promise<T | null> {\n assertDetField(ctx, field, 'findByDet')\n const target = await detTarget(ctx, field, value)\n\n const ids = await ctx.adapter.list(ctx.vault, ctx.name)\n for (const id of ids) {\n const env = await ctx.adapter.get(ctx.vault, ctx.name, id)\n if (!env || !env._det) continue\n if (env._det[field] === target) {\n return ctx.codec.decryptRecord(env)\n }\n }\n return null\n}\n\n/**\n * Return every record whose deterministic field matches. Same semantics as\n * {@link findByDet} but without the short-circuit.\n */\nexport async function queryByDet<T>(ctx: DeterministicContext<T>, field: string, value: unknown): Promise<T[]> {\n assertDetField(ctx, field, 'queryByDet')\n const target = await detTarget(ctx, field, value)\n\n const ids = await ctx.adapter.list(ctx.vault, ctx.name)\n const matches: T[] = []\n for (const id of ids) {\n const env = await ctx.adapter.get(ctx.vault, ctx.name, id)\n if (!env || !env._det) continue\n if (env._det[field] === target) {\n const rec = await ctx.codec.decryptRecord(env)\n if (rec !== null) matches.push(rec) // skip tombstone (defensive)\n }\n }\n return matches\n}\n","/**\n * Enclave body helpers — the C1 protected-body access contract.\n *\n * `EncryptedEnvelope` splits into a protocol header (family-owned; `_noydb`,\n * `_v`, `_ts`, `_by`, `_source`, `_sourceTs`, `_tier`, `_elevatedBy`) and a\n * protected body (enclave-owned; `_iv`, `_data`, `_cek`, `_det`, `_sealed`,\n * `_debug`). The four helpers below are the ONLY sanctioned way for code\n * outside `kernel/enclave/**` to read or construct the protected body —\n * later migration batches move the ~121 direct `_iv`/`_data`/`_cek`/`_sealed`\n * access sites in `with-*` services onto these.\n *\n * Each helper reproduces an EXISTING behavior byte-for-byte (see the\n * per-function doc for its oracle call site) — this file introduces no new\n * crypto or semantics, only a narrower door onto what already runs.\n */\nimport { encrypt, decrypt, generateDEK, wrapCek, unwrapCek, type EnclaveKey } from '../crypto.js'\nimport type { EncryptedEnvelope } from '../../types.js'\n\n/**\n * Open an envelope's protected body to its JSON text.\n *\n * Mirrors the dominant direct-decrypt call-site shape (e.g.\n * `with-audit/consent/consent.ts`'s `decryptEntry`):\n * - `opts.encrypted === false` (default `true`) → plaintext collection;\n * returns `env._data` as-is, `key` untouched.\n * - `env._cek` present → per-record-key envelope (mirrors\n * `record-codec.ts`'s `resolveEnvelopeCek`): unwrap the CEK under `key`\n * (the collection DEK), decrypt the body under the unwrapped CEK.\n * - `env._cek` absent → legacy path, decrypt the body directly under `key`.\n */\nexport async function openEnvelopeJson(\n env: EncryptedEnvelope,\n key: EnclaveKey,\n opts?: { encrypted?: boolean },\n): Promise<string> {\n if (opts?.encrypted === false) return env._data\n if (env._cek !== undefined) {\n const cek = await unwrapCek(env._cek, key)\n return decrypt(env._iv, env._data, cek)\n }\n return decrypt(env._iv, env._data, key)\n}\n\n/**\n * Produce the protected-body fields (`_iv`/`_data`/`_cek`) for an envelope a\n * caller is assembling.\n *\n * - `opts.encrypted === false` (default `true`) → plaintext collection;\n * emits `{ _iv: '', _data: json }` (today's `buildPlaintextEnvelope`\n * shape), `key` untouched.\n * - `opts.perRecordKey === true` → mints a fresh per-record CEK, encrypts\n * the body under it, and AES-KW-wraps the CEK under `key` (mirrors\n * `encryptJsonString`'s `cek !== undefined` branch, except the CEK is\n * generated here rather than supplied by the caller).\n * - otherwise → legacy path, body encrypted directly under `key`.\n */\nexport async function writeEnvelopeBody(\n json: string,\n key: EnclaveKey,\n opts?: { encrypted?: boolean; perRecordKey?: boolean },\n): Promise<Pick<EncryptedEnvelope, '_iv' | '_data' | '_cek'>> {\n if (opts?.encrypted === false) return { _iv: '', _data: json }\n\n if (opts?.perRecordKey === true) {\n const cek = await generateDEK()\n const { iv, data } = await encrypt(json, cek)\n const wrapped = await wrapCek(cek, key)\n return { _iv: iv, _data: data, _cek: wrapped }\n }\n\n const { iv, data } = await encrypt(json, key)\n return { _iv: iv, _data: data }\n}\n\n/**\n * Discriminant: does this envelope carry a per-record key?\n *\n * Replaces raw `envelope._cek !== undefined` checks scattered across\n * services — `_cek` presence is the format discriminant (see\n * `record-codec.ts`'s `resolveEnvelopeCek` doc).\n */\nexport function hasPerRecordKey(env: EncryptedEnvelope): boolean {\n return env._cek !== undefined\n}\n\n/**\n * Canonical body string for the ledger hash chain — the exact bytes\n * `with-commit/history/ledger/hash.ts`'s `envelopePayloadHash` derives from\n * `_data` + `_sealed` before hashing:\n * - no `_sealed` → `_data` alone (back-compat: every pre-existing ledger\n * entry and non-sealed backup hashes byte-identically).\n * - `_sealed` present → canonical JSON of `{ _data, _sealed }` with sorted\n * keys at every level, so the result is independent of `_sealed`'s\n * field-insertion / store-serialization order.\n *\n * Deliberately reimplements the two-key-object canonicalization inline\n * rather than importing `with-commit/history/ledger/entry.ts`'s general\n * `canonicalJson` — `kernel/enclave/**` may import only spine types (C3),\n * never a `with-*` service. For this fixed `{ _data: string; _sealed:\n * Record<string, string> }` shape the two produce byte-identical output\n * (verified against that exact call site's oracle expression in\n * `envelope-body.test.ts`).\n */\nexport function envelopeBodyForHash(env: EncryptedEnvelope): string {\n if (env._sealed === undefined) return env._data\n const sealedKeys = Object.keys(env._sealed).sort()\n const sealedParts = sealedKeys.map(\n (k) => `${JSON.stringify(k)}:${JSON.stringify(env._sealed![k])}`,\n )\n return `{\"_data\":${JSON.stringify(env._data)},\"_sealed\":{${sealedParts.join(',')}}}`\n}\n"],"mappings":"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","names":["plaintext","iv","data","fieldKey","iv","data","dek","subtle","iv","data"]}
|