@noy-db/hub 0.7.1-pre.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +147 -14
- package/LICENSE +202 -21
- package/NOTICE +1 -0
- package/README.md +5 -5
- package/codemods/0.8.0-pre.json +61 -0
- package/dist/api-OS747DS4.js +18 -0
- package/dist/as/index.js +11 -12
- package/dist/as/index.js.map +1 -1
- package/dist/at/index.js +9 -10
- package/dist/attestation/index.js +37 -26
- package/dist/attestation/index.js.map +1 -1
- package/dist/{backup-XKCXVKV3.js → backup-YE2VQ26S.js} +15 -16
- package/dist/backup-YE2VQ26S.js.map +1 -0
- package/dist/blobs/index.js +13 -14
- package/dist/blobs/index.js.map +1 -1
- package/dist/broker/index.js +12 -13
- package/dist/broker/index.js.map +1 -1
- package/dist/by/index.js +2 -2
- package/dist/capsule/contract.d.ts +159 -0
- package/dist/capsule/contract.js +95 -0
- package/dist/capsule/enclave-aes/bound.d.ts +52 -0
- package/dist/capsule/enclave-aes/capabilities.d.ts +2 -0
- package/dist/capsule/enclave-aes/classify/compare.d.ts +20 -0
- package/dist/{kernel/enclave → capsule/enclave-aes}/classify/find.d.ts +1 -1
- package/dist/{kernel/enclave → capsule/enclave-aes}/classify/reveal.d.ts +1 -1
- package/dist/{kernel/enclave → capsule/enclave-aes}/classify/verify.d.ts +2 -2
- package/dist/{kernel/enclave → capsule/enclave-aes}/classify/write.d.ts +1 -1
- package/dist/{kernel/enclave → capsule/enclave-aes}/crypto.d.ts +33 -129
- package/dist/capsule/enclave-aes/index.d.ts +113 -0
- package/dist/capsule/enclave-aes/index.js +335 -0
- package/dist/capsule/enclave-aes/index.js.map +1 -0
- package/dist/capsule/enclave-aes/primitives.d.ts +29 -0
- package/dist/capsule/index.d.ts +27 -0
- package/dist/capsule/plumbing/ct-equal.d.ts +11 -0
- package/dist/{kernel/enclave/record-keys → capsule/plumbing}/deterministic.d.ts +8 -21
- package/dist/capsule/plumbing/digest.d.ts +122 -0
- package/dist/{kernel/enclave/record-keys → capsule/plumbing}/envelope-body.d.ts +44 -48
- package/dist/capsule/plumbing/index.d.ts +100 -0
- package/dist/capsule/plumbing/lifecycle.d.ts +50 -0
- package/dist/{kernel/enclave/record-keys → capsule/plumbing}/record-codec.d.ts +80 -20
- package/dist/{kernel/enclave → capsule/plumbing}/record-envelope.d.ts +1 -1
- package/dist/capsule/plumbing/rekey-blob.d.ts +33 -0
- package/dist/capsule/plumbing/rekey.d.ts +44 -0
- package/dist/capsule/plumbing/sealed-slot.d.ts +22 -0
- package/dist/capsule/plumbing/sealed-slots.d.ts +37 -0
- package/dist/capsule/plumbing/sealing.d.ts +29 -0
- package/dist/capsule/plumbing/sign.d.ts +9 -0
- package/dist/{kernel/enclave/record-keys → capsule/plumbing}/tombstone.d.ts +2 -2
- package/dist/capsule-VOLX3QRQ.js +209 -0
- package/dist/cargo/index.js +39 -36
- package/dist/{chunk-Q2MPFCQ7.js → chunk-23D6M6VM.js} +5 -5
- package/dist/chunk-23D6M6VM.js.map +1 -0
- package/dist/{chunk-R7BX2NB3.js → chunk-244QBK7Z.js} +4 -4
- package/dist/chunk-244QBK7Z.js.map +1 -0
- package/dist/chunk-2AFX33YA.js +936 -0
- package/dist/chunk-2AFX33YA.js.map +1 -0
- package/dist/{chunk-MVMXZYXT.js → chunk-2GHDLTPE.js} +2 -2
- package/dist/{chunk-GYGLAVCX.js → chunk-2MG3SW7Q.js} +6 -2
- package/dist/chunk-2MG3SW7Q.js.map +1 -0
- package/dist/{chunk-XLMEZIAJ.js → chunk-2ODVB6LZ.js} +2 -2
- package/dist/{chunk-HJUWN7JN.js → chunk-2PVXF5CS.js} +33 -8
- package/dist/chunk-2PVXF5CS.js.map +1 -0
- package/dist/{chunk-YJRT5UQM.js → chunk-2RH777HH.js} +21 -20
- package/dist/{chunk-YJRT5UQM.js.map → chunk-2RH777HH.js.map} +1 -1
- package/dist/{chunk-7O3Y4PPD.js → chunk-37EPTBBR.js} +153 -16
- package/dist/chunk-37EPTBBR.js.map +1 -0
- package/dist/{chunk-2ENE6445.js → chunk-3A5DUZ56.js} +102 -16
- package/dist/chunk-3A5DUZ56.js.map +1 -0
- package/dist/chunk-3EWS67C7.js +461 -0
- package/dist/chunk-3EWS67C7.js.map +1 -0
- package/dist/{chunk-SGZAIJCV.js → chunk-3L2NBKDR.js} +4 -8
- package/dist/chunk-3L2NBKDR.js.map +1 -0
- package/dist/{chunk-YMUFFJCO.js → chunk-3TDUWVWB.js} +5 -2
- package/dist/chunk-3TDUWVWB.js.map +1 -0
- package/dist/{chunk-4GVM6QZA.js → chunk-3XJQBBZD.js} +26 -28
- package/dist/chunk-3XJQBBZD.js.map +1 -0
- package/dist/{chunk-4ZS56W5S.js → chunk-42ALPZ2B.js} +672 -664
- package/dist/chunk-42ALPZ2B.js.map +1 -0
- package/dist/chunk-4CIQDWRB.js +524 -0
- package/dist/chunk-4CIQDWRB.js.map +1 -0
- package/dist/{chunk-RMS3NEA3.js → chunk-4JPMZTJY.js} +2 -2
- package/dist/{chunk-P3MG6QCN.js → chunk-4T3SE27M.js} +5 -9
- package/dist/chunk-4T3SE27M.js.map +1 -0
- package/dist/chunk-4V3Q35WG.js +204 -0
- package/dist/chunk-4V3Q35WG.js.map +1 -0
- package/dist/{chunk-NQKIUNW5.js → chunk-52MGURXO.js} +2 -2
- package/dist/{chunk-EQEYOJBM.js → chunk-5A4345TG.js} +4 -4
- package/dist/chunk-5A4345TG.js.map +1 -0
- package/dist/{chunk-334WSVOW.js → chunk-5FE75J4S.js} +6 -6
- package/dist/chunk-5FE75J4S.js.map +1 -0
- package/dist/chunk-5KC7QYEC.js +565 -0
- package/dist/chunk-5KC7QYEC.js.map +1 -0
- package/dist/{chunk-RSGLUIO6.js → chunk-5UMK7GRI.js} +13 -12
- package/dist/chunk-5UMK7GRI.js.map +1 -0
- package/dist/chunk-5WWDGFOS.js +275 -0
- package/dist/chunk-5WWDGFOS.js.map +1 -0
- package/dist/{chunk-QPQUVOZ2.js → chunk-6QVKPHBF.js} +3 -5
- package/dist/chunk-6QVKPHBF.js.map +1 -0
- package/dist/{chunk-ACAQ2DSG.js → chunk-747G6CT3.js} +2 -2
- package/dist/chunk-747G6CT3.js.map +1 -0
- package/dist/{chunk-QTQUH4DS.js → chunk-7R2Q7CPL.js} +16 -16
- package/dist/chunk-7R2Q7CPL.js.map +1 -0
- package/dist/{chunk-UGTBXF5U.js → chunk-7XMHMVTS.js} +3 -3
- package/dist/{chunk-YJX7EOJD.js → chunk-A4XMIZT3.js} +6 -6
- package/dist/{chunk-YJX7EOJD.js.map → chunk-A4XMIZT3.js.map} +1 -1
- package/dist/{chunk-A66I4JOA.js → chunk-AEQGFRU4.js} +4 -4
- package/dist/chunk-AEQGFRU4.js.map +1 -0
- package/dist/chunk-AL6ML4LA.js +1558 -0
- package/dist/chunk-AL6ML4LA.js.map +1 -0
- package/dist/{chunk-BZ3534YM.js → chunk-AUKKUPVB.js} +2 -2
- package/dist/{chunk-CUZLNGD5.js → chunk-B2YY6WDD.js} +1 -1
- package/dist/chunk-B2YY6WDD.js.map +1 -0
- package/dist/chunk-BKT776R5.js +1 -0
- package/dist/chunk-BNWA3WG5.js +22 -0
- package/dist/chunk-BNWA3WG5.js.map +1 -0
- package/dist/{chunk-VXANTWBJ.js → chunk-BPWYQ25R.js} +92 -6
- package/dist/{chunk-VXANTWBJ.js.map → chunk-BPWYQ25R.js.map} +1 -1
- package/dist/{chunk-6LKOJBV6.js → chunk-BVCUTXE3.js} +2 -2
- package/dist/chunk-CY2CYVWZ.js +41 -0
- package/dist/chunk-CY2CYVWZ.js.map +1 -0
- package/dist/{chunk-M4YPHYEH.js → chunk-DHHGL42E.js} +70 -25
- package/dist/chunk-DHHGL42E.js.map +1 -0
- package/dist/{chunk-VTFVLCUH.js → chunk-DIZLQVAA.js} +2 -2
- package/dist/{chunk-G73UVHCA.js → chunk-DLD5LGDS.js} +11 -12
- package/dist/chunk-DLD5LGDS.js.map +1 -0
- package/dist/{chunk-WQBG4SZS.js → chunk-DQESF6RP.js} +60 -49
- package/dist/chunk-DQESF6RP.js.map +1 -0
- package/dist/{chunk-LWBCUYZW.js → chunk-E2N2T5ZO.js} +2 -2
- package/dist/{chunk-3PGS7TYR.js → chunk-EGVJ7TM4.js} +29 -32
- package/dist/chunk-EGVJ7TM4.js.map +1 -0
- package/dist/{chunk-JVIBCBC7.js → chunk-EJLV62NI.js} +2 -2
- package/dist/{chunk-KKEESNPE.js → chunk-EYG2CY2X.js} +126 -19
- package/dist/chunk-EYG2CY2X.js.map +1 -0
- package/dist/{enclave-55PAM4YO.js → chunk-EZGV6F47.js} +83 -56
- package/dist/chunk-EZGV6F47.js.map +1 -0
- package/dist/{chunk-CHQCZZWC.js → chunk-EZOAKKTB.js} +36 -27
- package/dist/chunk-EZOAKKTB.js.map +1 -0
- package/dist/chunk-F6NCB7KT.js +13 -0
- package/dist/chunk-F6NCB7KT.js.map +1 -0
- package/dist/chunk-FFJFE4T7.js +100 -0
- package/dist/chunk-FFJFE4T7.js.map +1 -0
- package/dist/{chunk-JMGDHKQF.js → chunk-FLPCETP6.js} +2 -2
- package/dist/chunk-FOEDQATO.js +53 -0
- package/dist/chunk-FOEDQATO.js.map +1 -0
- package/dist/{chunk-DGOZ4UZD.js → chunk-FVH5QYY2.js} +2 -2
- package/dist/{chunk-HIWCKBEY.js → chunk-G2MVBDFP.js} +54 -28
- package/dist/chunk-G2MVBDFP.js.map +1 -0
- package/dist/chunk-GMKGGY7V.js +234 -0
- package/dist/chunk-GMKGGY7V.js.map +1 -0
- package/dist/{chunk-EIPVYUEP.js → chunk-GQ4MF3CM.js} +3 -3
- package/dist/chunk-GQ4MF3CM.js.map +1 -0
- package/dist/{chunk-PEOZ34EM.js → chunk-GSAK56VF.js} +1 -1
- package/dist/chunk-GSAK56VF.js.map +1 -0
- package/dist/{chunk-5VCRVKOZ.js → chunk-GUZET4SG.js} +12 -4
- package/dist/chunk-GUZET4SG.js.map +1 -0
- package/dist/{chunk-JBDFMYKQ.js → chunk-GZT3NQRA.js} +2 -2
- package/dist/{chunk-K23VKTN4.js → chunk-H23XHRTT.js} +19 -34
- package/dist/chunk-H23XHRTT.js.map +1 -0
- package/dist/{chunk-TFR7DSOV.js → chunk-H427H63K.js} +2 -2
- package/dist/{chunk-DFMWUOU5.js → chunk-H7JBY4P7.js} +23 -32
- package/dist/chunk-H7JBY4P7.js.map +1 -0
- package/dist/{chunk-SKGMN35F.js → chunk-HS554XAF.js} +3 -3
- package/dist/chunk-HS554XAF.js.map +1 -0
- package/dist/{chunk-HK67PX4J.js → chunk-HW7CMKUG.js} +1 -1
- package/dist/chunk-HW7CMKUG.js.map +1 -0
- package/dist/{chunk-3BVH633C.js → chunk-IMQKWR46.js} +5 -7
- package/dist/chunk-IMQKWR46.js.map +1 -0
- package/dist/{chunk-R42NSZI6.js → chunk-IUBMZPHM.js} +7 -7
- package/dist/chunk-IUBMZPHM.js.map +1 -0
- package/dist/{chunk-CUQPWYRX.js → chunk-IUT3GWP3.js} +75 -386
- package/dist/chunk-IUT3GWP3.js.map +1 -0
- package/dist/{chunk-RF6D3Y5E.js → chunk-JDEYF3PJ.js} +4 -8
- package/dist/{chunk-RF6D3Y5E.js.map → chunk-JDEYF3PJ.js.map} +1 -1
- package/dist/{chunk-PPTHY5QO.js → chunk-JIBUPZHA.js} +99 -8
- package/dist/chunk-JIBUPZHA.js.map +1 -0
- package/dist/{chunk-SMH6SRX7.js → chunk-JOSPH3E5.js} +2 -2
- package/dist/chunk-JQYKPKG6.js +193 -0
- package/dist/chunk-JQYKPKG6.js.map +1 -0
- package/dist/{chunk-7APJ6CO6.js → chunk-JSMTXZR3.js} +45 -13
- package/dist/chunk-JSMTXZR3.js.map +1 -0
- package/dist/chunk-JWWYRR4Q.js +12 -0
- package/dist/chunk-JWWYRR4Q.js.map +1 -0
- package/dist/{chunk-BVN6KXL2.js → chunk-KZXDLBY6.js} +14 -9
- package/dist/chunk-KZXDLBY6.js.map +1 -0
- package/dist/chunk-LGNDFRYC.js +23 -0
- package/dist/chunk-LGNDFRYC.js.map +1 -0
- package/dist/{chunk-XKWGNJ26.js → chunk-LIOVX5TJ.js} +7 -11
- package/dist/chunk-LIOVX5TJ.js.map +1 -0
- package/dist/{chunk-AYX7AINO.js → chunk-LNSVGRHO.js} +5 -7
- package/dist/chunk-LNSVGRHO.js.map +1 -0
- package/dist/chunk-M5B2W6YY.js +293 -0
- package/dist/chunk-M5B2W6YY.js.map +1 -0
- package/dist/chunk-MBMTND6D.js +456 -0
- package/dist/chunk-MBMTND6D.js.map +1 -0
- package/dist/{chunk-3BZZJJMQ.js → chunk-MILI22XQ.js} +3 -3
- package/dist/{chunk-A2HKRLPV.js → chunk-MXKI4ABF.js} +18 -59
- package/dist/chunk-MXKI4ABF.js.map +1 -0
- package/dist/{chunk-ZYIYHJ5R.js → chunk-MXOQ5JCG.js} +869 -238
- package/dist/chunk-MXOQ5JCG.js.map +1 -0
- package/dist/{chunk-V7ZRRCRJ.js → chunk-N7EVQD5S.js} +9 -13
- package/dist/chunk-N7EVQD5S.js.map +1 -0
- package/dist/chunk-N7UDP5VU.js +757 -0
- package/dist/chunk-N7UDP5VU.js.map +1 -0
- package/dist/chunk-NBQ3KK6X.js +270 -0
- package/dist/chunk-NBQ3KK6X.js.map +1 -0
- package/dist/{chunk-ZORTV6NH.js → chunk-NCO25JZO.js} +88 -4
- package/dist/chunk-NCO25JZO.js.map +1 -0
- package/dist/chunk-NH2UOV3B.js +18 -0
- package/dist/chunk-NH2UOV3B.js.map +1 -0
- package/dist/chunk-NYMLINRP.js +28 -0
- package/dist/chunk-NYMLINRP.js.map +1 -0
- package/dist/{chunk-YYP7WSEB.js → chunk-O2IMQSNA.js} +2 -2
- package/dist/chunk-O46CHQT7.js +215 -0
- package/dist/chunk-O46CHQT7.js.map +1 -0
- package/dist/chunk-OIEO4WDL.js +27 -0
- package/dist/chunk-OIEO4WDL.js.map +1 -0
- package/dist/{chunk-TRGTKX5E.js → chunk-OKSTSITU.js} +27 -4
- package/dist/chunk-OKSTSITU.js.map +1 -0
- package/dist/chunk-OYW3I5M4.js +31 -0
- package/dist/chunk-OYW3I5M4.js.map +1 -0
- package/dist/{chunk-Q7HZX3IF.js → chunk-PD64727P.js} +2 -2
- package/dist/chunk-PD64727P.js.map +1 -0
- package/dist/{chunk-FET5XCAT.js → chunk-PP3K67AJ.js} +34 -6
- package/dist/chunk-PP3K67AJ.js.map +1 -0
- package/dist/chunk-Q2XRFWOI.js +40 -0
- package/dist/chunk-Q2XRFWOI.js.map +1 -0
- package/dist/{chunk-QIZPZMUI.js → chunk-Q4UHJ5SN.js} +2 -2
- package/dist/{chunk-FAHMLERK.js → chunk-QBLT6POL.js} +2 -2
- package/dist/chunk-QMWY2FDS.js +157 -0
- package/dist/chunk-QMWY2FDS.js.map +1 -0
- package/dist/{chunk-LH5A3ZPG.js → chunk-RB4DOPGZ.js} +150 -22
- package/dist/chunk-RB4DOPGZ.js.map +1 -0
- package/dist/chunk-RHVMZSUU.js +7 -0
- package/dist/chunk-RHVMZSUU.js.map +1 -0
- package/dist/{chunk-BUE2D7PX.js → chunk-SMV2HRDU.js} +2 -2
- package/dist/chunk-SUZKW6UR.js +25 -0
- package/dist/chunk-SUZKW6UR.js.map +1 -0
- package/dist/{chunk-7MG7SJT7.js → chunk-SV2PM2OY.js} +1 -1
- package/dist/chunk-SV2PM2OY.js.map +1 -0
- package/dist/{chunk-UXVWEX5L.js → chunk-SYNY3VB5.js} +6 -2
- package/dist/chunk-SYNY3VB5.js.map +1 -0
- package/dist/{chunk-4GFX6MPA.js → chunk-TEHHROZL.js} +6 -8
- package/dist/chunk-TEHHROZL.js.map +1 -0
- package/dist/chunk-TKVUE4JF.js +1289 -0
- package/dist/chunk-TKVUE4JF.js.map +1 -0
- package/dist/{chunk-SFAWCTEM.js → chunk-TZZBXPZK.js} +2 -2
- package/dist/{chunk-F3W6YMDC.js → chunk-U2FZNEWJ.js} +4 -4
- package/dist/chunk-U2FZNEWJ.js.map +1 -0
- package/dist/{chunk-BLN54W3L.js → chunk-UA372JHH.js} +56 -3
- package/dist/chunk-UA372JHH.js.map +1 -0
- package/dist/{chunk-6YXCPL4T.js → chunk-UEFOQH74.js} +2 -2
- package/dist/chunk-UEFOQH74.js.map +1 -0
- package/dist/{chunk-2N5ML6HT.js → chunk-UIYESRD6.js} +9 -11
- package/dist/chunk-UIYESRD6.js.map +1 -0
- package/dist/{chunk-UHHPLO3I.js → chunk-V3RWOOSO.js} +4 -4
- package/dist/{chunk-KTFRCC5C.js → chunk-V7ADQF5O.js} +82 -8
- package/dist/chunk-V7ADQF5O.js.map +1 -0
- package/dist/{chunk-453F654R.js → chunk-VAORSCSU.js} +3 -3
- package/dist/chunk-VAORSCSU.js.map +1 -0
- package/dist/{chunk-GPNTB4Y7.js → chunk-VFHCKG5M.js} +6 -10
- package/dist/chunk-VFHCKG5M.js.map +1 -0
- package/dist/{chunk-2577DKXB.js → chunk-VHBKYN2J.js} +3 -3
- package/dist/chunk-VHBKYN2J.js.map +1 -0
- package/dist/chunk-VHM7HCKB.js +220 -0
- package/dist/chunk-VHM7HCKB.js.map +1 -0
- package/dist/{chunk-ZHKOPKE3.js → chunk-VKI2EB3N.js} +3 -3
- package/dist/chunk-VKI2EB3N.js.map +1 -0
- package/dist/{chunk-UDHWDSRL.js → chunk-VMV5SBE4.js} +16 -17
- package/dist/chunk-VMV5SBE4.js.map +1 -0
- package/dist/{chunk-SPYWXKJN.js → chunk-VQDZYB2B.js} +3 -3
- package/dist/chunk-VQDZYB2B.js.map +1 -0
- package/dist/{chunk-Q2PU57HC.js → chunk-VVOLDVIR.js} +2 -2
- package/dist/{chunk-3VF3WQ4F.js → chunk-WPOYWFSE.js} +7 -7
- package/dist/{chunk-3VF3WQ4F.js.map → chunk-WPOYWFSE.js.map} +1 -1
- package/dist/{chunk-OTQZ7ZWU.js → chunk-WXE4W2U6.js} +7 -11
- package/dist/chunk-WXE4W2U6.js.map +1 -0
- package/dist/chunk-XBKH4FOC.js +195 -0
- package/dist/chunk-XBKH4FOC.js.map +1 -0
- package/dist/{chunk-TUFM4UZP.js → chunk-XQRFSKYM.js} +2 -2
- package/dist/{chunk-3V4KWFX7.js → chunk-XSPFDUDG.js} +58 -53
- package/dist/chunk-XSPFDUDG.js.map +1 -0
- package/dist/{chunk-GY4WYNNG.js → chunk-Y2RKVFKR.js} +2 -2
- package/dist/{chunk-UP4BECPY.js → chunk-Y3LPTBG7.js} +89 -27
- package/dist/chunk-Y3LPTBG7.js.map +1 -0
- package/dist/{chunk-4OZNXTO4.js → chunk-YRXFFWG4.js} +2 -2
- package/dist/classified/index.js +5 -5
- package/dist/{classified-marker-BWOFVYAC.js → classified-marker-SIYKUU5L.js} +3 -3
- package/dist/classified-marker-SIYKUU5L.js.map +1 -0
- package/dist/collection-facade-CS7CA2XO.js +47 -0
- package/dist/{computed-VPOKQK4N.js → computed-FAD7SED4.js} +3 -3
- package/dist/consent/index.js +10 -11
- package/dist/consent/index.js.map +1 -1
- package/dist/cover/index.js +10 -11
- package/dist/coverage/index.js +306 -0
- package/dist/coverage/index.js.map +1 -0
- package/dist/custody/index.js +12 -13
- package/dist/{dead-filter-PKQDLOT4.js → dead-filter-4F3LWYKH.js} +11 -3
- package/dist/dead-filter-4F3LWYKH.js.map +1 -0
- package/dist/debug/index.js +11 -2
- package/dist/debug/index.js.map +1 -1
- package/dist/{delegation-DS5NRILW.js → delegation-NANZDG4N.js} +13 -16
- package/dist/delegation-NANZDG4N.js.map +1 -0
- package/dist/derivations/index.js +25 -23
- package/dist/derive-XLOJVXPU.js +20 -0
- package/dist/directory/index.js +10 -11
- package/dist/{dispatch-IEPAVQUM.js → dispatch-H4HV32AM.js} +5 -5
- package/dist/{dispatch-Q6MWLOJY.js → dispatch-JDZNGEB3.js} +20 -21
- package/dist/dispatch-JDZNGEB3.js.map +1 -0
- package/dist/executor-FMPVN6DT.js +35 -0
- package/dist/executor-LBBBRTN5.js +8 -0
- package/dist/executor-OSRZST2U.js +8 -0
- package/dist/export-accessible-RAOJAAU5.js +22 -0
- package/dist/extract-partition-JD5CUSTG.js +37 -0
- package/dist/{fanout-sidecar-S3QL53YX.js → fanout-sidecar-L7NHPIOC.js} +13 -15
- package/dist/fanout-sidecar-L7NHPIOC.js.map +1 -0
- package/dist/find-JRN4RNQ5.js +10 -0
- package/dist/forget/index.js +9 -10
- package/dist/forget/index.js.map +1 -1
- package/dist/guards/index.js +4 -4
- package/dist/history/index.js +13 -14
- package/dist/history/index.js.map +1 -1
- package/dist/i18n/index.js +14 -15
- package/dist/i18n/index.js.map +1 -1
- package/dist/index.d.ts +36 -14
- package/dist/index.js +970 -163
- package/dist/index.js.map +1 -1
- package/dist/indexing/index.js +13 -5
- package/dist/indexing/index.js.map +1 -1
- package/dist/introspection/index.js +11 -12
- package/dist/issue-YIVBZUTH.js +19 -0
- package/dist/ivf-flat-UZ6DQDLS.js +314 -0
- package/dist/ivf-flat-UZ6DQDLS.js.map +1 -0
- package/dist/{json-schema-V3M5MUCM.js → json-schema-3SHX72CC.js} +2 -1
- package/dist/json-schema-3SHX72CC.js.map +1 -0
- package/dist/kernel/attestation-types.d.ts +62 -0
- package/dist/kernel/collection-config.d.ts +5 -68
- package/dist/kernel/collection.d.ts +30 -9
- package/dist/kernel/cutover-transform.d.ts +1 -1
- package/dist/kernel/errors.d.ts +257 -38
- package/dist/kernel/generation-map.d.ts +48 -0
- package/dist/kernel/merge-authority.d.ts +1 -1
- package/dist/kernel/noydb.d.ts +6 -1
- package/dist/kernel/paths.d.ts +29 -5
- package/dist/kernel/prepared-write.d.ts +1 -1
- package/dist/kernel/present-cache.d.ts +58 -0
- package/dist/kernel/query/all.d.ts +7 -0
- package/dist/kernel/query/builder.d.ts +601 -270
- package/dist/kernel/query/civil-date.d.ts +64 -0
- package/dist/kernel/query/cursor.d.ts +40 -0
- package/dist/kernel/query/distinct-key.d.ts +98 -0
- package/dist/kernel/query/hydration.d.ts +76 -0
- package/dist/kernel/query/index.d.ts +31 -15
- package/dist/kernel/query/internal/core.d.ts +30 -0
- package/dist/kernel/query/internal/hooks.d.ts +22 -0
- package/dist/kernel/query/internal/maintenance.d.ts +43 -0
- package/dist/kernel/query/live/incremental.d.ts +314 -0
- package/dist/kernel/query/live/index.d.ts +22 -0
- package/dist/kernel/query/live/install.d.ts +2 -0
- package/dist/kernel/query/{live.d.ts → live/live.d.ts} +39 -9
- package/dist/kernel/query/live/methods.d.ts +107 -0
- package/dist/kernel/query/predicate.d.ts +119 -1
- package/dist/kernel/query/reduce/date-trunc.d.ts +75 -0
- package/dist/kernel/query/reduce/index.d.ts +36 -0
- package/dist/kernel/query/reduce/install.d.ts +2 -0
- package/dist/kernel/query/reduce/methods.d.ts +259 -0
- package/dist/kernel/query/reduce/scan-methods.d.ts +121 -0
- package/dist/kernel/query/relate/explain.d.ts +199 -0
- package/dist/kernel/query/relate/index.d.ts +48 -0
- package/dist/kernel/query/relate/install.d.ts +2 -0
- package/dist/kernel/query/relate/join-on.d.ts +126 -0
- package/dist/kernel/query/relate/join-reduce.d.ts +16 -0
- package/dist/kernel/query/relate/join.d.ts +452 -0
- package/dist/kernel/query/relate/methods.d.ts +426 -0
- package/dist/kernel/query/relate/partition.d.ts +87 -0
- package/dist/kernel/query/relate/scan-methods.d.ts +163 -0
- package/dist/kernel/query/relate/traverse.d.ts +109 -0
- package/dist/kernel/query/scan-builder.d.ts +79 -176
- package/dist/kernel/query/sort-key.d.ts +52 -0
- package/dist/kernel/secret-mode.d.ts +1 -1
- package/dist/kernel/tx-write-gate.d.ts +77 -0
- package/dist/kernel/types.d.ts +113 -8
- package/dist/kernel/validation.d.ts +27 -10
- package/dist/kernel/vault.d.ts +11 -6
- package/dist/kernel/via/compose.d.ts +3 -0
- package/dist/kernel/via/index.d.ts +56 -0
- package/dist/kernel/via/pipeline.d.ts +48 -0
- package/dist/kernel/write-queue.d.ts +17 -0
- package/dist/{ledger-EDXFFZQL.js → ledger-5ZMGE44K.js} +11 -12
- package/dist/liberate-WZSZM2W6.js +24 -0
- package/dist/link-set-MFXC24VK.js +29 -0
- package/dist/{managed-secret-NCWEMPUQ.js → managed-secret-MFTFT22X.js} +10 -11
- package/dist/materialized-views/index.js +30 -24
- package/dist/{migrate-cek-5ENH64AA.js → migrate-cek-DZRFFOHW.js} +2 -2
- package/dist/money/index.js +5 -5
- package/dist/noydb-ITIGNKUF.js +96 -0
- package/dist/overlay-views/index.js +4 -4
- package/dist/periods/index.js +12 -13
- package/dist/pod/index.js +74 -67
- package/dist/{pod-handle-ECVCDIXW.js → pod-handle-A3LET7NO.js} +10 -11
- package/dist/pod-handle-A3LET7NO.js.map +1 -0
- package/dist/policy/index.js +10 -11
- package/dist/port/on/index.d.ts +1 -1
- package/dist/port/to/index.d.ts +1 -1
- package/dist/port/with/blob-strategy.d.ts +10 -1
- package/dist/port/with/classified-strategy.d.ts +1 -1
- package/dist/port/with/collection-options.d.ts +6 -1
- package/dist/port/with/collection-registries.d.ts +1 -1
- package/dist/port/with/coverage-strategy.d.ts +83 -0
- package/dist/port/with/lookup-strategy.d.ts +2 -2
- package/dist/port/with/service-bus.d.ts +46 -0
- package/dist/port/with/strategies.d.ts +2 -0
- package/dist/portability/index.js +8 -8
- package/dist/{post-register-3IPCSG6Q.js → post-register-7ND27CF2.js} +6 -6
- package/dist/post-register-7ND27CF2.js.map +1 -0
- package/dist/query/all/index.js +31 -0
- package/dist/query/index.js +20 -32
- package/dist/query/live/index.js +21 -0
- package/dist/query/live/index.js.map +1 -0
- package/dist/query/reduce/index.js +33 -0
- package/dist/query/reduce/index.js.map +1 -0
- package/dist/query/relate/index.js +56 -0
- package/dist/query/relate/index.js.map +1 -0
- package/dist/reduce/index.js +72 -18
- package/dist/reduce/index.js.map +1 -1
- package/dist/register-DT5HZ2LZ.js +30 -0
- package/dist/registry-BHRZGZHF.js +8 -0
- package/dist/registry-ET6ZFFWA.js +34 -0
- package/dist/registry-HXFGLGTG.js +8 -0
- package/dist/registry-THCPDEOD.js +23 -0
- package/dist/request-withdrawal-AV2MJJKY.js +30 -0
- package/dist/{reveal-QZDHSGD4.js → reveal-B2TLP4JQ.js} +10 -9
- package/dist/reveal-B2TLP4JQ.js.map +1 -0
- package/dist/revoke-6DWIEOCV.js +24 -0
- package/dist/satellites/index.js +1 -1
- package/dist/schema-update/index.js +2 -2
- package/dist/sealed-record/index.js +16 -18
- package/dist/sealed-record/index.js.map +1 -1
- package/dist/search/index.js +11 -5
- package/dist/{seed-X5CC22CQ.js → seed-XNSE4U3S.js} +15 -18
- package/dist/seed-XNSE4U3S.js.map +1 -0
- package/dist/sequence/index.js +9 -10
- package/dist/session/index.js +9 -10
- package/dist/session/index.js.map +1 -1
- package/dist/shadow/index.js +2 -2
- package/dist/signer-MHGW3OIL.js +23 -0
- package/dist/snapshots/index.js +11 -11
- package/dist/stale-6GCFMOOR.js +28 -0
- package/dist/storage-BYN5LO6Z.js +21 -0
- package/dist/storage-BYN5LO6Z.js.map +1 -0
- package/dist/store/index.js +1 -1
- package/dist/{store-coordination-provider-4WZAIRHC.js → store-coordination-provider-C4BPT5XF.js} +11 -12
- package/dist/store-coordination-provider-C4BPT5XF.js.map +1 -0
- package/dist/sync/index.js +10 -11
- package/dist/sync/index.js.map +1 -1
- package/dist/team/index.js +17 -16
- package/dist/tiers/index.js +13 -12
- package/dist/to/index.js +2 -2
- package/dist/transactions/index.js +3 -3
- package/dist/util/index.js +1 -1
- package/dist/vault-head/index.js +11 -14
- package/dist/vault-head/index.js.map +1 -1
- package/dist/{verify-6MDTIUEV.js → verify-UKALW7C2.js} +14 -12
- package/dist/verify-UKALW7C2.js.map +1 -0
- package/dist/via/blob/index.d.ts +1 -0
- package/dist/via/classified/binding.d.ts +2 -2
- package/dist/via/classified/config-drift.d.ts +2 -2
- package/dist/via/classified/errors.d.ts +1 -1
- package/dist/via/geo/binding.d.ts +31 -0
- package/dist/via/geo/descriptor.d.ts +54 -0
- package/dist/via/geo/geohash.d.ts +95 -0
- package/dist/via/geo/index.d.ts +13 -0
- package/dist/via/geo/where.d.ts +50 -0
- package/dist/via/i18n/core.d.ts +1 -1
- package/dist/via/lookup/handle.d.ts +4 -4
- package/dist/via/lookup/registry.d.ts +1 -1
- package/dist/via/lookup/snapshot.d.ts +3 -3
- package/dist/walk-4VPK7AS4.js +20 -0
- package/dist/walk-4VPK7AS4.js.map +1 -0
- package/dist/with-audit/attestation/index.d.ts +2 -1
- package/dist/with-audit/attestation/issue.d.ts +2 -2
- package/dist/with-audit/attestation/revoke.d.ts +2 -2
- package/dist/with-audit/attestation/scheme.d.ts +7 -0
- package/dist/with-audit/attestation/signer.d.ts +1 -1
- package/dist/with-audit/attestation/strategy.d.ts +2 -2
- package/dist/with-audit/attestation/types.d.ts +10 -0
- package/dist/with-audit/attestation/vault-facade.d.ts +2 -2
- package/dist/with-audit/attestation/verifier.d.ts +6 -0
- package/dist/with-audit/consent/consent.d.ts +1 -1
- package/dist/with-audit/consent/strategy.d.ts +1 -1
- package/dist/with-audit/coverage/accounting.d.ts +112 -0
- package/dist/with-audit/coverage/active.d.ts +29 -0
- package/dist/with-audit/coverage/index.d.ts +61 -0
- package/dist/with-audit/coverage/sketch.d.ts +75 -0
- package/dist/with-audit/forget/subject-index.d.ts +1 -1
- package/dist/with-audit/periods/periods.d.ts +55 -7
- package/dist/with-audit/periods/reserved-collections.d.ts +3 -0
- package/dist/with-audit/periods/vault-facade.d.ts +18 -1
- package/dist/with-audit/sealed-record/index.d.ts +2 -2
- package/dist/with-audit/sealed-record/strategy.d.ts +1 -1
- package/dist/with-audit/tiers/index.d.ts +53 -2
- package/dist/with-audit/tiers/strategy.d.ts +8 -0
- package/dist/with-cargo/adopt-partition.d.ts +1 -1
- package/dist/with-cargo/extract-partition.d.ts +1 -1
- package/dist/with-cargo/floor.d.ts +3 -3
- package/dist/with-commit/history/history.d.ts +2 -2
- package/dist/with-commit/history/index.d.ts +1 -1
- package/dist/with-commit/history/ledger/store.d.ts +1 -1
- package/dist/with-commit/history/strategy.d.ts +1 -1
- package/dist/with-commit/history/time-machine.d.ts +1 -1
- package/dist/with-commit/numbering/index.d.ts +1 -1
- package/dist/with-commit/sequence/index.d.ts +1 -1
- package/dist/with-commit/tx/invariants.d.ts +1 -1
- package/dist/with-commit/tx/transaction.d.ts +13 -3
- package/dist/with-commit/vault-head/head.d.ts +1 -1
- package/dist/with-commit/vault-head/index.d.ts +1 -1
- package/dist/with-commit/vault-head/strategy.d.ts +1 -1
- package/dist/with-commit/vault-head/verify.d.ts +1 -1
- package/dist/with-formula/derivations/dispatch.d.ts +1 -1
- package/dist/with-formula/derivations/fanout-sidecar.d.ts +1 -1
- package/dist/with-formula/materialized-views/dependency-analyzer.d.ts +4 -3
- package/dist/with-formula/materialized-views/emit-memo.d.ts +40 -0
- package/dist/with-formula/materialized-views/executor.d.ts +8 -0
- package/dist/with-formula/materialized-views/index.d.ts +1 -1
- package/dist/with-formula/materialized-views/registry.d.ts +15 -0
- package/dist/with-formula/materialized-views/types.d.ts +106 -14
- package/dist/with-formula/materialized-views/window-stage.d.ts +11 -0
- package/dist/with-formula/overlay-views/types.d.ts +1 -1
- package/dist/with-formula/overlay-views/virtual-collection.d.ts +13 -4
- package/dist/with-lookup/embeddings/chunks.d.ts +79 -0
- package/dist/with-lookup/embeddings/descriptor.d.ts +21 -0
- package/dist/with-lookup/embeddings/index.d.ts +3 -0
- package/dist/with-lookup/embeddings/ivf-flat.d.ts +93 -0
- package/dist/with-lookup/embeddings/vector-index.d.ts +73 -0
- package/dist/with-lookup/embeddings/vector-set.d.ts +94 -1
- package/dist/with-lookup/embeddings/with-vector-index.d.ts +67 -0
- package/dist/with-lookup/indexing/collection-facade.d.ts +86 -3
- package/dist/with-lookup/indexing/compound-indexes.d.ts +129 -0
- package/dist/with-lookup/indexing/eager-indexes.d.ts +170 -1
- package/dist/with-lookup/indexing/index-snapshot.d.ts +62 -0
- package/dist/with-lookup/indexing/lazy-builder.d.ts +33 -0
- package/dist/with-lookup/indexing/persisted-field-indexes.d.ts +104 -0
- package/dist/with-lookup/indexing/persisted-indexes.d.ts +12 -0
- package/dist/with-lookup/indexing/sorted-indexes.d.ts +117 -0
- package/dist/with-lookup/indexing/unique-constraints.d.ts +106 -23
- package/dist/with-lookup/reduce/active.d.ts +2 -24
- package/dist/with-lookup/reduce/group-core.d.ts +43 -0
- package/dist/with-lookup/reduce/groupby.d.ts +195 -36
- package/dist/with-lookup/reduce/incremental-group.d.ts +153 -0
- package/dist/with-lookup/reduce/index.d.ts +26 -5
- package/dist/with-lookup/reduce/reducers.d.ts +255 -1
- package/dist/with-lookup/reduce/reduction.d.ts +44 -13
- package/dist/with-lookup/reduce/strategy.d.ts +43 -3
- package/dist/with-lookup/reduce/window.d.ts +262 -0
- package/dist/with-lookup/search/collection-facade.d.ts +45 -9
- package/dist/with-lookup/search/index-store.d.ts +5 -3
- package/dist/with-lookup/search/index.d.ts +4 -2
- package/dist/with-lookup/search/inverted-index.d.ts +38 -2
- package/dist/with-lookup/search/persisted-index-store.d.ts +5 -2
- package/dist/with-lookup/search/phrase.d.ts +28 -0
- package/dist/with-lookup/search/retrieve-types.d.ts +57 -1
- package/dist/with-lookup/search/serialize.d.ts +29 -3
- package/dist/with-lookup/search/strategy.d.ts +2 -6
- package/dist/with-party/broker/index.d.ts +3 -3
- package/dist/with-party/directory/cover/index.d.ts +1 -1
- package/dist/with-party/directory/cover/storage.d.ts +1 -1
- package/dist/with-party/directory/cover/types.d.ts +1 -1
- package/dist/with-party/directory/index.d.ts +1 -1
- package/dist/with-party/directory/types.d.ts +1 -1
- package/dist/with-party/directory/user-envelope/api.d.ts +1 -1
- package/dist/with-party/directory/user-envelope/storage.d.ts +1 -1
- package/dist/with-party/policy/engine.d.ts +1 -1
- package/dist/with-party/policy/index.d.ts +1 -1
- package/dist/with-party/policy/presets.d.ts +1 -1
- package/dist/with-party/team/authenticators.d.ts +91 -1
- package/dist/with-party/team/delegation.d.ts +1 -1
- package/dist/with-party/team/echo-secret.d.ts +2 -2
- package/dist/with-party/team/index.d.ts +4 -3
- package/dist/with-party/team/keyring.d.ts +2 -2
- package/dist/with-party/team/magic-link-grant.d.ts +1 -1
- package/dist/with-party/team/managed-secret.d.ts +1 -1
- package/dist/with-party/team/noydb-facade.d.ts +12 -3
- package/dist/with-party/team/recovery.d.ts +1 -1
- package/dist/with-party/team/roster-tag.d.ts +1 -1
- package/dist/with-party/team/rotate-recover.d.ts +1 -1
- package/dist/with-party/team/wrapped-deks.d.ts +1 -1
- package/dist/with-pod/format.d.ts +1 -1
- package/dist/with-pod/index.d.ts +1 -1
- package/dist/with-pod/pod.d.ts +1 -1
- package/dist/with-shape/blobs/blob-compaction.d.ts +17 -1
- package/dist/with-shape/blobs/blob-intent.d.ts +1 -1
- package/dist/with-shape/blobs/blob-set.d.ts +23 -4
- package/dist/with-shape/blobs/legacy-sweep.d.ts +35 -0
- package/dist/with-shape/introspection/describe.d.ts +7 -1
- package/dist/with-shape/introspection/field-meta.d.ts +18 -0
- package/dist/with-shape/introspection/types.d.ts +57 -1
- package/dist/with-shape/introspection/walk.d.ts +1 -1
- package/dist/with-shape/links/lazy-handle.d.ts +1 -1
- package/dist/with-shape/links/link-set.d.ts +1 -1
- package/dist/with-shape/links/vault-facade.d.ts +1 -1
- package/dist/with-shape/manifest/derive.d.ts +1 -1
- package/dist/with-shape/manifest/storage.d.ts +1 -1
- package/dist/with-shape/persisted-schemas/register.d.ts +1 -1
- package/dist/with-shape/persisted-schemas/storage.d.ts +1 -1
- package/dist/with-shape/satellites/dead-filter.d.ts +1 -1
- package/dist/with-shape/satellites/declare.d.ts +1 -1
- package/dist/with-shape/satellites/marker.d.ts +1 -1
- package/dist/with-shape/satellites/post-register.d.ts +1 -1
- package/dist/with-store/partitioned/index.d.ts +337 -0
- package/dist/with-sync/change-broadcast.d.ts +153 -0
- package/dist/with-sync/presence.d.ts +5 -10
- package/dist/withdraw-accessible-HL7GACUE.js +27 -0
- package/dist/withdraw-accessible-HL7GACUE.js.map +1 -0
- package/package.json +48 -12
- package/dist/api-WYW4YEQG.js +0 -19
- package/dist/backup-XKCXVKV3.js.map +0 -1
- package/dist/chunk-2577DKXB.js.map +0 -1
- package/dist/chunk-2ENE6445.js.map +0 -1
- package/dist/chunk-2N5ML6HT.js.map +0 -1
- package/dist/chunk-334WSVOW.js.map +0 -1
- package/dist/chunk-3BVH633C.js.map +0 -1
- package/dist/chunk-3PGS7TYR.js.map +0 -1
- package/dist/chunk-3V4KWFX7.js.map +0 -1
- package/dist/chunk-453F654R.js.map +0 -1
- package/dist/chunk-4GFX6MPA.js.map +0 -1
- package/dist/chunk-4GVM6QZA.js.map +0 -1
- package/dist/chunk-4ZS56W5S.js.map +0 -1
- package/dist/chunk-5VCRVKOZ.js.map +0 -1
- package/dist/chunk-6YXCPL4T.js.map +0 -1
- package/dist/chunk-7APJ6CO6.js.map +0 -1
- package/dist/chunk-7MG2LHO5.js +0 -1616
- package/dist/chunk-7MG2LHO5.js.map +0 -1
- package/dist/chunk-7MG7SJT7.js.map +0 -1
- package/dist/chunk-7O3Y4PPD.js.map +0 -1
- package/dist/chunk-A2HKRLPV.js.map +0 -1
- package/dist/chunk-A66I4JOA.js.map +0 -1
- package/dist/chunk-ACAQ2DSG.js.map +0 -1
- package/dist/chunk-ATL3ZVXT.js +0 -151
- package/dist/chunk-ATL3ZVXT.js.map +0 -1
- package/dist/chunk-AYX7AINO.js.map +0 -1
- package/dist/chunk-BLN54W3L.js.map +0 -1
- package/dist/chunk-BRLKZUBT.js +0 -95
- package/dist/chunk-BRLKZUBT.js.map +0 -1
- package/dist/chunk-BTDR2PXY.js +0 -29
- package/dist/chunk-BTDR2PXY.js.map +0 -1
- package/dist/chunk-BVN6KXL2.js.map +0 -1
- package/dist/chunk-CHQCZZWC.js.map +0 -1
- package/dist/chunk-CUQPWYRX.js.map +0 -1
- package/dist/chunk-CUZLNGD5.js.map +0 -1
- package/dist/chunk-DFMWUOU5.js.map +0 -1
- package/dist/chunk-EIPVYUEP.js.map +0 -1
- package/dist/chunk-EQEYOJBM.js.map +0 -1
- package/dist/chunk-F3W6YMDC.js.map +0 -1
- package/dist/chunk-FET5XCAT.js.map +0 -1
- package/dist/chunk-G73UVHCA.js.map +0 -1
- package/dist/chunk-GPNTB4Y7.js.map +0 -1
- package/dist/chunk-GYGLAVCX.js.map +0 -1
- package/dist/chunk-HIWCKBEY.js.map +0 -1
- package/dist/chunk-HJUWN7JN.js.map +0 -1
- package/dist/chunk-HK67PX4J.js.map +0 -1
- package/dist/chunk-HPVZCW43.js +0 -479
- package/dist/chunk-HPVZCW43.js.map +0 -1
- package/dist/chunk-I3ISCYT7.js +0 -159
- package/dist/chunk-I3ISCYT7.js.map +0 -1
- package/dist/chunk-K23VKTN4.js.map +0 -1
- package/dist/chunk-KKEESNPE.js.map +0 -1
- package/dist/chunk-KTFRCC5C.js.map +0 -1
- package/dist/chunk-LH5A3ZPG.js.map +0 -1
- package/dist/chunk-LP7BEXCT.js +0 -32
- package/dist/chunk-LP7BEXCT.js.map +0 -1
- package/dist/chunk-M4YPHYEH.js.map +0 -1
- package/dist/chunk-NSITFOCJ.js +0 -99
- package/dist/chunk-NSITFOCJ.js.map +0 -1
- package/dist/chunk-OTQZ7ZWU.js.map +0 -1
- package/dist/chunk-P3MG6QCN.js.map +0 -1
- package/dist/chunk-PEOZ34EM.js.map +0 -1
- package/dist/chunk-PPTHY5QO.js.map +0 -1
- package/dist/chunk-Q2MPFCQ7.js.map +0 -1
- package/dist/chunk-Q7HZX3IF.js.map +0 -1
- package/dist/chunk-QPQUVOZ2.js.map +0 -1
- package/dist/chunk-QTQUH4DS.js.map +0 -1
- package/dist/chunk-R42NSZI6.js.map +0 -1
- package/dist/chunk-R7BX2NB3.js.map +0 -1
- package/dist/chunk-RSGLUIO6.js.map +0 -1
- package/dist/chunk-RTBJ5IOO.js +0 -87
- package/dist/chunk-RTBJ5IOO.js.map +0 -1
- package/dist/chunk-SGZAIJCV.js.map +0 -1
- package/dist/chunk-SKGMN35F.js.map +0 -1
- package/dist/chunk-SPYWXKJN.js.map +0 -1
- package/dist/chunk-SZJ3DLZA.js +0 -66
- package/dist/chunk-SZJ3DLZA.js.map +0 -1
- package/dist/chunk-TRGTKX5E.js.map +0 -1
- package/dist/chunk-UDHWDSRL.js.map +0 -1
- package/dist/chunk-UP4BECPY.js.map +0 -1
- package/dist/chunk-UXVWEX5L.js.map +0 -1
- package/dist/chunk-V7ZRRCRJ.js.map +0 -1
- package/dist/chunk-WQBG4SZS.js.map +0 -1
- package/dist/chunk-XKWGNJ26.js.map +0 -1
- package/dist/chunk-YMUFFJCO.js.map +0 -1
- package/dist/chunk-ZHKOPKE3.js.map +0 -1
- package/dist/chunk-ZN4FD4PE.js +0 -364
- package/dist/chunk-ZN4FD4PE.js.map +0 -1
- package/dist/chunk-ZORTV6NH.js.map +0 -1
- package/dist/chunk-ZYIYHJ5R.js.map +0 -1
- package/dist/classified-marker-BWOFVYAC.js.map +0 -1
- package/dist/collection-facade-JSJYIKS4.js +0 -45
- package/dist/dead-filter-PKQDLOT4.js.map +0 -1
- package/dist/delegation-DS5NRILW.js.map +0 -1
- package/dist/derive-E642AOUB.js +0 -21
- package/dist/dispatch-Q6MWLOJY.js.map +0 -1
- package/dist/executor-5NIMLSKZ.js +0 -8
- package/dist/executor-7UQ3BZ4F.js +0 -29
- package/dist/executor-AQVXV5GZ.js +0 -8
- package/dist/export-accessible-ORMKLA3E.js +0 -22
- package/dist/extract-partition-NKYO3WNG.js +0 -37
- package/dist/fanout-sidecar-S3QL53YX.js.map +0 -1
- package/dist/find-NOGJ25VX.js +0 -10
- package/dist/issue-3DTQ7VJJ.js +0 -18
- package/dist/json-schema-V3M5MUCM.js.map +0 -1
- package/dist/kernel/enclave/classify/compare.d.ts +0 -10
- package/dist/kernel/enclave/index.d.ts +0 -87
- package/dist/kernel/enclave/record-keys/lifecycle.d.ts +0 -124
- package/dist/kernel/enclave/record-keys/rekey-blob.d.ts +0 -88
- package/dist/kernel/enclave/record-keys/rekey.d.ts +0 -91
- package/dist/kernel/enclave/record-keys/sealed-slot.d.ts +0 -14
- package/dist/kernel/enclave/record-keys/sealed-slots.d.ts +0 -123
- package/dist/kernel/enclave/record-keys/sealing.d.ts +0 -70
- package/dist/kernel/query/join.d.ts +0 -232
- package/dist/liberate-V35QUHJP.js +0 -24
- package/dist/link-set-2TTM3IZC.js +0 -30
- package/dist/noydb-62MX4QUG.js +0 -90
- package/dist/pod-handle-ECVCDIXW.js.map +0 -1
- package/dist/post-register-3IPCSG6Q.js.map +0 -1
- package/dist/register-HHLXEQDN.js +0 -31
- package/dist/registry-23WF3TGH.js +0 -8
- package/dist/registry-4AYVUNXK.js +0 -8
- package/dist/registry-JS3YFQQM.js +0 -18
- package/dist/registry-XX2Z7B46.js +0 -32
- package/dist/request-withdrawal-CHPATE4G.js +0 -30
- package/dist/reveal-QZDHSGD4.js.map +0 -1
- package/dist/revoke-7M2VW4ON.js +0 -23
- package/dist/seed-X5CC22CQ.js.map +0 -1
- package/dist/signer-SJQJVSM6.js +0 -24
- package/dist/stale-BZS6H2RY.js +0 -29
- package/dist/storage-RW4QBS23.js +0 -22
- package/dist/store-coordination-provider-4WZAIRHC.js.map +0 -1
- package/dist/verify-6MDTIUEV.js.map +0 -1
- package/dist/walk-ZURCH6RZ.js +0 -21
- package/dist/withdraw-accessible-PXR4IXDX.js +0 -27
- /package/dist/{api-WYW4YEQG.js.map → api-OS747DS4.js.map} +0 -0
- /package/dist/{computed-VPOKQK4N.js.map → capsule/contract.js.map} +0 -0
- /package/dist/{kernel/enclave → capsule/enclave-aes}/broker/proof.d.ts +0 -0
- /package/dist/{kernel/enclave → capsule/enclave-aes}/classify/bidx.d.ts +0 -0
- /package/dist/{kernel/enclave → capsule/enclave-aes}/classify/digest.d.ts +0 -0
- /package/dist/{kernel/enclave → capsule/enclave-aes}/classify/vdig.d.ts +0 -0
- /package/dist/{kernel/enclave/classify → capsule/plumbing}/kofn.d.ts +0 -0
- /package/dist/{kernel/enclave/classify → capsule/plumbing}/normalize.d.ts +0 -0
- /package/dist/{kernel/enclave → capsule/plumbing}/record-aad.d.ts +0 -0
- /package/dist/{collection-facade-JSJYIKS4.js.map → capsule-VOLX3QRQ.js.map} +0 -0
- /package/dist/{chunk-MVMXZYXT.js.map → chunk-2GHDLTPE.js.map} +0 -0
- /package/dist/{chunk-XLMEZIAJ.js.map → chunk-2ODVB6LZ.js.map} +0 -0
- /package/dist/{chunk-RMS3NEA3.js.map → chunk-4JPMZTJY.js.map} +0 -0
- /package/dist/{chunk-NQKIUNW5.js.map → chunk-52MGURXO.js.map} +0 -0
- /package/dist/{chunk-UGTBXF5U.js.map → chunk-7XMHMVTS.js.map} +0 -0
- /package/dist/{chunk-BZ3534YM.js.map → chunk-AUKKUPVB.js.map} +0 -0
- /package/dist/{derive-E642AOUB.js.map → chunk-BKT776R5.js.map} +0 -0
- /package/dist/{chunk-6LKOJBV6.js.map → chunk-BVCUTXE3.js.map} +0 -0
- /package/dist/{chunk-VTFVLCUH.js.map → chunk-DIZLQVAA.js.map} +0 -0
- /package/dist/{chunk-LWBCUYZW.js.map → chunk-E2N2T5ZO.js.map} +0 -0
- /package/dist/{chunk-JVIBCBC7.js.map → chunk-EJLV62NI.js.map} +0 -0
- /package/dist/{chunk-JMGDHKQF.js.map → chunk-FLPCETP6.js.map} +0 -0
- /package/dist/{chunk-DGOZ4UZD.js.map → chunk-FVH5QYY2.js.map} +0 -0
- /package/dist/{chunk-JBDFMYKQ.js.map → chunk-GZT3NQRA.js.map} +0 -0
- /package/dist/{chunk-TFR7DSOV.js.map → chunk-H427H63K.js.map} +0 -0
- /package/dist/{chunk-SMH6SRX7.js.map → chunk-JOSPH3E5.js.map} +0 -0
- /package/dist/{chunk-3BZZJJMQ.js.map → chunk-MILI22XQ.js.map} +0 -0
- /package/dist/{chunk-YYP7WSEB.js.map → chunk-O2IMQSNA.js.map} +0 -0
- /package/dist/{chunk-QIZPZMUI.js.map → chunk-Q4UHJ5SN.js.map} +0 -0
- /package/dist/{chunk-FAHMLERK.js.map → chunk-QBLT6POL.js.map} +0 -0
- /package/dist/{chunk-BUE2D7PX.js.map → chunk-SMV2HRDU.js.map} +0 -0
- /package/dist/{chunk-SFAWCTEM.js.map → chunk-TZZBXPZK.js.map} +0 -0
- /package/dist/{chunk-UHHPLO3I.js.map → chunk-V3RWOOSO.js.map} +0 -0
- /package/dist/{chunk-Q2PU57HC.js.map → chunk-VVOLDVIR.js.map} +0 -0
- /package/dist/{chunk-TUFM4UZP.js.map → chunk-XQRFSKYM.js.map} +0 -0
- /package/dist/{chunk-GY4WYNNG.js.map → chunk-Y2RKVFKR.js.map} +0 -0
- /package/dist/{chunk-4OZNXTO4.js.map → chunk-YRXFFWG4.js.map} +0 -0
- /package/dist/{enclave-55PAM4YO.js.map → collection-facade-CS7CA2XO.js.map} +0 -0
- /package/dist/{executor-5NIMLSKZ.js.map → computed-FAD7SED4.js.map} +0 -0
- /package/dist/{executor-7UQ3BZ4F.js.map → derive-XLOJVXPU.js.map} +0 -0
- /package/dist/{dispatch-IEPAVQUM.js.map → dispatch-H4HV32AM.js.map} +0 -0
- /package/dist/{executor-AQVXV5GZ.js.map → executor-FMPVN6DT.js.map} +0 -0
- /package/dist/{export-accessible-ORMKLA3E.js.map → executor-LBBBRTN5.js.map} +0 -0
- /package/dist/{extract-partition-NKYO3WNG.js.map → executor-OSRZST2U.js.map} +0 -0
- /package/dist/{find-NOGJ25VX.js.map → export-accessible-RAOJAAU5.js.map} +0 -0
- /package/dist/{issue-3DTQ7VJJ.js.map → extract-partition-JD5CUSTG.js.map} +0 -0
- /package/dist/{ledger-EDXFFZQL.js.map → find-JRN4RNQ5.js.map} +0 -0
- /package/dist/{liberate-V35QUHJP.js.map → issue-YIVBZUTH.js.map} +0 -0
- /package/dist/{link-set-2TTM3IZC.js.map → ledger-5ZMGE44K.js.map} +0 -0
- /package/dist/{managed-secret-NCWEMPUQ.js.map → liberate-WZSZM2W6.js.map} +0 -0
- /package/dist/{noydb-62MX4QUG.js.map → link-set-MFXC24VK.js.map} +0 -0
- /package/dist/{register-HHLXEQDN.js.map → managed-secret-MFTFT22X.js.map} +0 -0
- /package/dist/{migrate-cek-5ENH64AA.js.map → migrate-cek-DZRFFOHW.js.map} +0 -0
- /package/dist/{registry-23WF3TGH.js.map → noydb-ITIGNKUF.js.map} +0 -0
- /package/dist/{registry-4AYVUNXK.js.map → query/all/index.js.map} +0 -0
- /package/dist/{registry-JS3YFQQM.js.map → register-DT5HZ2LZ.js.map} +0 -0
- /package/dist/{registry-XX2Z7B46.js.map → registry-BHRZGZHF.js.map} +0 -0
- /package/dist/{request-withdrawal-CHPATE4G.js.map → registry-ET6ZFFWA.js.map} +0 -0
- /package/dist/{revoke-7M2VW4ON.js.map → registry-HXFGLGTG.js.map} +0 -0
- /package/dist/{signer-SJQJVSM6.js.map → registry-THCPDEOD.js.map} +0 -0
- /package/dist/{stale-BZS6H2RY.js.map → request-withdrawal-AV2MJJKY.js.map} +0 -0
- /package/dist/{storage-RW4QBS23.js.map → revoke-6DWIEOCV.js.map} +0 -0
- /package/dist/{walk-ZURCH6RZ.js.map → signer-MHGW3OIL.js.map} +0 -0
- /package/dist/{withdraw-accessible-PXR4IXDX.js.map → stale-6GCFMOOR.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/with-cargo/active.ts","../src/with-cargo/describe-extraction.ts","../src/with-cargo/adopt-partition.ts","../src/with-cargo/decrypt-partition.ts"],"sourcesContent":["/**\n * Enable the cargo (partition extraction) capability.\n * Pass to `createNoydb({ cargoStrategy: withCargo() })` to make the source-side\n * `extractPartition(vault, ...)` free function live. The extraction crypto\n * engine is dynamically imported here, so it stays out of the floor bundle\n * until opted in. The recipient-side `adoptPartition` /\n * `decryptExtractedPartition` free functions — and `diffVault` (shared\n * import/merge infra) — are ungated and unaffected.\n */\nimport type { CargoStrategy } from './strategy.js'\n\nexport function withCargo(): CargoStrategy {\n return {\n async extractPartition(vault, opts) {\n const { extractPartitionCore } = await import('./extract-partition.js')\n return extractPartitionCore(vault, opts)\n },\n }\n}\n","/**\n * Partition-extraction dry-run. Read-only preview of what an\n * `extractPartition` would move: record counts, byte totals, and the\n * timestamp span per collection — computed from raw encrypted\n * envelopes WITHOUT decrypting them. Writes nothing, mutates nothing.\n *\n * @module\n */\nimport type { Vault } from '../kernel/vault.js'\nimport { walkClosure, type WalkClosureOptions, type DanglingRefNotice } from './walk-closure.js'\n\nexport interface ExtractionPreview {\n readonly totalRecords: number\n /** Sum of serialized encrypted-envelope sizes (bytes). */\n readonly totalBytes: number\n readonly byCollection: ReadonlyArray<{\n readonly name: string\n readonly recordCount: number\n readonly bytes: number\n /** Earliest envelope `_ts` in this collection (lexicographic). */\n readonly oldestTs?: string\n readonly newestTs?: string\n }>\n readonly graph: { readonly depth: number; readonly cyclesDetected: boolean }\n /** Records the walk reached but whose envelope couldn't be read. */\n readonly inaccessible: ReadonlyArray<{ readonly collection: string; readonly id: string }>\n /**\n * #772: outbound FK edges whose referenced parent was excluded from the\n * closure (missing, or tier-elevated and therefore invisible) — mirrors\n * `ExtractPartitionResult.danglingRefs` (#759) so a preview/extract pair\n * gives the SAME signal. A parent excluded this way never appears in\n * `byCollection` at all; this is the only preview-time indicator.\n */\n readonly danglingRefs: ReadonlyArray<DanglingRefNotice>\n}\n\nexport async function describeExtraction(\n vault: Vault,\n opts: WalkClosureOptions,\n): Promise<ExtractionPreview> {\n const { closure, graph, danglingRefs } = await walkClosure(vault, opts)\n\n const { name: vaultName, adapter } = vault._introspectState()\n const encoder = new TextEncoder()\n\n const byCollection: Array<{\n name: string; recordCount: number; bytes: number; oldestTs?: string; newestTs?: string\n }> = []\n const inaccessible: Array<{ collection: string; id: string }> = []\n let totalBytes = 0\n let totalRecords = 0\n\n for (const [collectionName, ids] of closure) {\n let bytes = 0\n let oldestTs: string | undefined\n let newestTs: string | undefined\n let recordCount = 0\n\n for (const id of ids) {\n const env = await adapter.get(vaultName, collectionName, id)\n if (!env) {\n // Walk reached it (via decrypted list) but the raw store read\n // returned nothing — surface rather than miscount.\n inaccessible.push({ collection: collectionName, id })\n continue\n }\n recordCount++\n bytes += encoder.encode(JSON.stringify(env)).length\n const ts = env._ts\n if (oldestTs === undefined || ts < oldestTs) oldestTs = ts\n if (newestTs === undefined || ts > newestTs) newestTs = ts\n }\n\n byCollection.push({\n name: collectionName,\n recordCount,\n bytes,\n // Spread conditionally — exactOptionalPropertyTypes forbids an\n // explicit `undefined` on an optional property.\n ...(oldestTs !== undefined ? { oldestTs } : {}),\n ...(newestTs !== undefined ? { newestTs } : {}),\n })\n totalBytes += bytes\n totalRecords += recordCount\n }\n\n byCollection.sort((a, b) => a.name.localeCompare(b.name))\n\n return Object.freeze({\n totalRecords,\n totalBytes,\n byCollection,\n graph,\n inaccessible,\n danglingRefs,\n })\n}\n","/**\n * Partition adoption. Recipient side: verify an extracted bundle,\n * validate the transfer key, import the re-keyed collections into a\n * destination store, and record an `_meta/adoption` marker. The bundle\n * stays UNOWNED after adoption — `createOwnerOnAdoptedPartition`\n * mints the owner; the transfer seal is then destroyed.\n *\n * @module\n */\nimport { base64ToBuffer, wrapKey, type EnclaveKey } from '../kernel/enclave/index.js'\nimport { TransferSealError, AdoptionStateError, ValidationError } from '../kernel/errors.js'\nimport type { NoydbStore, VaultSnapshot, KeyringFile } from '../kernel/types.js'\nimport { createOwnerKeyring, requireRosterKey } from '../with-party/team/keyring.js'\nimport { mintRosterTag } from '../with-party/team/roster-tag.js' // #1115\nimport { nextRosterEpoch } from '../with-party/team/roster-epoch.js' // #1097\nimport { resolveManagedSecret } from '../with-party/team/managed-secret.js'\nimport type { NoydbSealer } from '../with-party/team/managed-secret.js'\nimport type { NoydbShamir } from '../with-party/team/noydb-shamir.js'\nimport type { RecoveryEnrollmentInput } from '../with-party/team/rotate-recover.js'\nimport { LedgerStore } from '../with-commit/history/ledger/store.js'\nimport { LEDGER_COLLECTION } from '../with-commit/history/ledger/constants.js'\nimport type { TransferSealPayload } from '../with-pod/pod.js'\nimport { readPodHeader, readPod, parseExtractedPartitionBody } from '../with-pod/pod.js'\nimport { buildRecordEnvelope } from '../kernel/enclave/index.js'\n\n/**\n * Reverse of `sealDeks`. Imports the transfer key, decrypts the\n * sealed `{ collection: base64(rawDEK) }` map (layout iv(12)‖ct‖tag), and\n * re-imports each DEK as an AES-GCM key. Throws `TransferSealError` on a\n * wrong key (AES-GCM auth-tag failure) or malformed payload.\n */\nexport async function unsealDeks(\n seal: TransferSealPayload,\n transferKey: Uint8Array,\n): Promise<Map<string, EnclaveKey>> {\n if (transferKey.byteLength !== 32) {\n throw new TransferSealError(\n `transfer key must be 32 bytes, got ${transferKey.byteLength}.`,\n )\n }\n const key = await crypto.subtle.importKey('raw', transferKey as BufferSource, 'AES-GCM', false, ['decrypt'])\n const raw = base64ToBuffer(seal.payload)\n let plaintext: ArrayBuffer\n try {\n plaintext = await crypto.subtle.decrypt(\n { name: 'AES-GCM', iv: raw.slice(0, 12) as BufferSource },\n key,\n raw.slice(12) as BufferSource,\n )\n } catch {\n throw new TransferSealError(\n 'transfer seal could not be opened — wrong transfer key (AES-GCM authentication failed).',\n )\n }\n let dekMap: Record<string, string>\n try {\n dekMap = JSON.parse(new TextDecoder().decode(plaintext)) as Record<string, string>\n } catch {\n throw new TransferSealError('transfer seal payload is not valid JSON after decryption.')\n }\n const deks = new Map<string, EnclaveKey>()\n for (const [collection, b64] of Object.entries(dekMap)) {\n // Extractable: the recipient must be able to re-wrap these under their\n // own KEK (AES-KW) at owner-creation. Matches generateDEK.\n const dek = await crypto.subtle.importKey('raw', base64ToBuffer(b64) as BufferSource, 'AES-GCM', true, ['encrypt', 'decrypt'])\n deks.set(collection, dek)\n }\n return deks\n}\n\nexport interface AdoptPartitionOptions {\n readonly transferKey: Uint8Array\n readonly destinationStore: NoydbStore\n readonly vaultName: string\n}\n\nexport interface AdoptPartitionResult {\n readonly vaultName: string\n readonly needsOwner: true\n readonly sealId: string\n}\n\nexport async function adoptPartition(\n bundleBytes: Uint8Array,\n opts: AdoptPartitionOptions,\n): Promise<AdoptPartitionResult> {\n const { transferKey, destinationStore, vaultName } = opts\n\n const header = readPodHeader(bundleBytes)\n if (header.bundleKind !== 'extracted-partition' || header.transferSeal === undefined) {\n throw new ValidationError(\n 'adoptPartition requires an extracted-partition bundle with a transfer seal. '\n + 'For ordinary backups use readPod + vault.load.',\n )\n }\n\n const { dumpJson } = await readPod(bundleBytes)\n const { dump, seal } = parseExtractedPartitionBody(dumpJson)\n\n // Validate the transfer key by unsealing in memory; throws\n // TransferSealError on mismatch. DEKs are discarded here — they stay\n // sealed at rest (in _meta/adoption) until owner-creation wraps them under the\n // recipient's KEK.\n await unsealDeks(seal, transferKey)\n\n // Single-occupancy per vaultName: an `_meta/adoption` marker already present\n // means this slot holds a partition (adopted-and-unowned, or already owned).\n // saveAll below would overwrite its data and replace the marker, stranding the\n // prior adoption's transfer seal. Refuse regardless of sealId — re-adopting the\n // SAME bundle is a redundant call, and adopting a DIFFERENT bundle here would\n // clobber the existing partition. Either way, pick a fresh vaultName.\n const existing = await destinationStore.get(vaultName, '_meta', 'adoption')\n if (existing) {\n const prior = JSON.parse(existing._data) as { sealId?: string }\n if (prior.sealId === seal.sealId) {\n throw new AdoptionStateError(\n `partition (sealId ${seal.sealId}) is already adopted into vault \"${vaultName}\".`,\n )\n }\n throw new AdoptionStateError(\n `vault \"${vaultName}\" already holds an adopted partition (sealId ${prior.sealId}); `\n + `adopting a different partition (sealId ${seal.sealId}) here would overwrite it. `\n + `Adopt into a fresh vaultName instead.`,\n )\n }\n\n // The marker-only check above misses a worse case: a vaultName already in use\n // by an ORDINARY vault (createNoydb + openVault) carries no `_meta/adoption`,\n // yet `saveAll` below is destructive on SQL adapters (`DELETE FROM ... WHERE\n // vault = ?` followed by upsert) and would wipe the legitimate keyring +\n // data. Refuse adoption into ANY occupied slot — a fresh vaultName is the\n // documented precondition.\n const existingKeyring = await destinationStore.list(vaultName, '_keyring')\n if (existingKeyring.length > 0) {\n throw new AdoptionStateError(\n `vault \"${vaultName}\" already holds a keyring (an unrelated owner exists at this slot); `\n + `adoptPartition requires a fresh vaultName to avoid destructive saveAll on SQL adapters.`,\n )\n }\n\n const backup = JSON.parse(dump) as { collections: VaultSnapshot; _internal?: VaultSnapshot }\n await destinationStore.saveAll(vaultName, backup.collections)\n\n // Import carried internal collections (e.g. _schemas from carrySchemas).\n // saveAll only writes data collections; _internal is written per-record.\n if (backup._internal) {\n for (const [collection, records] of Object.entries(backup._internal)) {\n for (const [id, envelope] of Object.entries(records)) {\n await destinationStore.put(vaultName, collection, id, envelope)\n }\n }\n }\n\n const adoptedAt = new Date().toISOString()\n const adoption = { sealId: seal.sealId, adoptedAt, needsOwner: true as const, transferSeal: seal }\n await destinationStore.put(vaultName, '_meta', 'adoption',\n buildRecordEnvelope({ collection: '_meta', id: 'adoption', version: 1 },\n { ts: adoptedAt, iv: '', data: JSON.stringify(adoption) }))\n\n return { vaultName, needsOwner: true, sealId: seal.sealId }\n}\n\nexport interface CreateOwnerResult {\n readonly vaultName: string\n readonly userId: string\n}\n\n/** Standard-mode owner: recipient supplies the secret. */\nexport interface CreateOwnerStandardOptions {\n readonly userId: string\n readonly secret: string\n readonly transferKey: Uint8Array\n}\n\n/**\n * Managed-mode owner: the secret is minted + sealed under\n * a `NoydbSealer` (e.g. an `at-*` OS keychain) so the partition\n * auto-unlocks on the recipient's device. Managed mode mandates a strong\n * (Shamir) recovery profile at creation, which needs the\n * `shamirRecovery` provider injected.\n */\nexport interface CreateOwnerManagedOptions {\n readonly userId: string\n readonly secretMode: 'managed'\n readonly sealingKey: NoydbSealer\n readonly recovery: ReadonlyArray<RecoveryEnrollmentInput>\n readonly shamirRecovery: NoydbShamir\n readonly transferKey: Uint8Array\n}\n\nexport type CreateOwnerOptions = CreateOwnerStandardOptions | CreateOwnerManagedOptions\n\nfunction isManaged(o: CreateOwnerOptions): o is CreateOwnerManagedOptions {\n return 'secretMode' in o && o.secretMode === 'managed'\n}\n\n/**\n * Mint the first owner keyring on an adopted-but-unowned partition,\n * then destroy the transfer seal.\n *\n * Standard mode: the recipient supplies a secret. Managed mode: the\n * secret is minted + sealed under a `NoydbSealer` and a strong\n * (Shamir) recovery profile is enrolled — orchestrated via the existing\n * `openVaultAndEnrollRecovery` ceremony.\n *\n * Either way, reuses `createOwnerKeyring` to derive the KEK + write the base\n * keyring, then wraps the partition's DEKs (recovered from the seal) under that\n * KEK and re-persists the merged keyring file.\n *\n * Idempotent under retry: the seal is destroyed LAST (Stage D), after the\n * keyring (Stage A), the ledger transition (Stage B), and — in managed mode —\n * strong-recovery enrollment (Stage C). A failure in the fallible enrollment\n * step leaves the seal intact, and re-running with the same `userId` +\n * `transferKey` resumes from the first incomplete stage. (Multi-profile recovery\n * arrays may re-enroll an already-enrolled profile on retry; managed mode's\n * mandated single Shamir profile does not.)\n */\nexport async function createOwnerOnAdoptedPartition(\n store: NoydbStore,\n vaultName: string,\n opts: CreateOwnerOptions,\n): Promise<CreateOwnerResult> {\n const { userId, transferKey } = opts\n\n // Managed mode requires a strong (Shamir) recovery profile, validated BEFORE\n // any disk write — same gate as createNoydb.\n if (isManaged(opts) && !opts.recovery.some((r) => r.profile === 'shamir')) {\n throw new AdoptionStateError(\n 'managed-mode adoption requires at least one strong (shamir) recovery profile in '\n + '`recovery` — paper alone is not strong when there is no user secret to fall back on.',\n )\n }\n\n // 1. Verify adopted-unowned state.\n const adoptionEnv = await store.get(vaultName, '_meta', 'adoption')\n if (!adoptionEnv) {\n throw new AdoptionStateError(\n `vault \"${vaultName}\" is not an adopted partition (no _meta/adoption). `\n + `createOwnerOnAdoptedPartition only applies to vaults created via adoptPartition.`,\n )\n }\n const adoption = JSON.parse(adoptionEnv._data) as {\n sealId: string; adoptedAt: string; needsOwner?: boolean\n consumedAt?: string; transferSeal?: TransferSealPayload\n }\n if (adoption.consumedAt !== undefined || adoption.transferSeal === undefined) {\n throw new AdoptionStateError(\n `vault \"${vaultName}\" already has an owner (transfer seal consumed at ${adoption.consumedAt}).`,\n )\n }\n\n // 2. Recover the partition DEKs from the seal (throws on wrong key) BEFORE\n // writing any keyring, so a bad transfer key leaves no trace. Always\n // validated, including when resuming a partial prior call.\n const partitionDeks = await unsealDeks(adoption.transferSeal, transferKey)\n\n // The ceremony below is split into stages so a failure in the fallible\n // managed-enrollment step (network/provider outage) leaves the call RETRYABLE\n // — the seal is destroyed only once everything durable is in place. Each stage\n // detects its own prior completion rather than relying on a single resume bit.\n\n // A keyring present for a DIFFERENT user (with the seal still unconsumed) is a\n // genuine second-owner attempt — refuse it. A same-user keyring is a resumed\n // partial call and is handled by the stage checks below.\n const existingKeyring = await store.get(vaultName, '_keyring', userId)\n const otherOwners = (await store.list(vaultName, '_keyring')).filter((u) => u !== userId)\n if (otherOwners.length > 0) {\n throw new AdoptionStateError(\n `vault \"${vaultName}\" already has a keyring for a different owner; cannot create owner \"${userId}\".`,\n )\n }\n\n // Stage A — mint the owner keyring + merge the partition DEKs. Considered done\n // only when the keyring already holds every partition DEK. createOwnerKeyring\n // overwrites (fresh KEK + fresh _users DEK), so re-running is safe ONLY while\n // no recovery has been enrolled yet — guaranteed here because enrollment\n // (Stage C) runs strictly after Stage A completes.\n const partitionCollections = [...partitionDeks.keys()]\n const priorDeks = existingKeyring ? (JSON.parse(existingKeyring._data) as KeyringFile).deks : {}\n const ownerMinted = existingKeyring !== null && partitionCollections.every((c) => c in priorDeks)\n if (!ownerMinted) {\n // Resolve the owner secret. Managed mode mints a random secret, seals\n // it under the provider, and persists _meta/sealed-secret (so the\n // partition auto-unlocks on the recipient's device); standard mode uses the\n // caller's secret. Idempotent under retry — resolveManagedSecret's reopen\n // arm reuses an already-sealed secret.\n const secret = isManaged(opts)\n ? await resolveManagedSecret(store, vaultName, opts.sealingKey)\n : opts.secret\n\n // Mint the owner keyring (KEK + _users DEK + canary, written to disk).\n const unlocked = await createOwnerKeyring(store, vaultName, { userId: userId, secret: secret })\n\n // Merge the partition DEKs (wrapped under the new KEK) into the keyring.\n const env = await store.get(vaultName, '_keyring', userId)\n if (!env) throw new AdoptionStateError(`keyring write for \"${userId}\" did not persist`)\n const keyringFile = JSON.parse(env._data) as KeyringFile\n const kek = unlocked.kek\n if (!kek) throw new AdoptionStateError(`owner keyring for \"${userId}\" has no KEK to wrap partition DEKs under`)\n const mergedDeks: Record<string, string> = { ...keyringFile.deks }\n for (const [collection, dek] of partitionDeks) {\n mergedDeks[collection] = await wrapKey(dek, kek)\n }\n // #1115 — RESTAMP. The roster tag now covers the DEK key SET, and this merge\n // is precisely a change to that set: adoption joins the partition's\n // collections to a keyring `createOwnerKeyring` stamped moments earlier\n // without them. Writing the merged file under the old tag would leave every\n // adopted vault failing `roster-tag-mismatch` on its first open.\n //\n // The roster key is the one just minted for this NEW vault — unlike\n // `liberateVault`, which joins an EXISTING vault and must keep the\n // incumbent key so co-members can still verify each other.\n const merged: KeyringFile = { ...keyringFile, deks: mergedDeks }\n // #1097 — stamped BEFORE the tag is minted, so it lands inside the\n // authenticated canonical and a store can neither edit nor strip it.\n const withEpoch = { ...merged, roster_epoch: nextRosterEpoch(keyringFile.roster_epoch) }\n const rosterKey = requireRosterKey(unlocked, 'adoptPartition')\n const mergedFile: KeyringFile = { ...withEpoch, roster_tag: await mintRosterTag(withEpoch, rosterKey) }\n await store.put(vaultName, '_keyring', userId, { ...env, _data: JSON.stringify(mergedFile) })\n }\n\n // Stage B — record the ownership transition on the carried\n // audit chain (carryLedger sealed the _ledger DEK). No-op without that DEK.\n // Idempotent: appended only if the closing `transfer-seal-consumed` entry is\n // absent, so a retry does not duplicate the pair.\n const ledgerDek = partitionDeks.get(LEDGER_COLLECTION)\n if (ledgerDek) {\n const ledger = new LedgerStore({\n adapter: store,\n vault: vaultName,\n encrypted: true,\n getDEK: async () => ledgerDek,\n actor: userId,\n })\n const creationReason = `creation-of-new-owner:${userId}`\n const consumedReason = `transfer-seal-consumed:${adoption.sealId}`\n // Gate each append on its own presence — a crash or store error strictly\n // between the two adjacent puts would otherwise re-append the first one\n // on retry. The pair is the audit record, not a single transaction.\n const recordedReasons = new Set((await ledger.loadAllEntries()).map((e) => e.reason))\n if (!recordedReasons.has(creationReason)) {\n await ledger.append({ op: 'lifecycle', collection: '', id: '', version: 0, actor: '', payloadHash: '', reason: creationReason })\n }\n if (!recordedReasons.has(consumedReason)) {\n await ledger.append({ op: 'lifecycle', collection: '', id: '', version: 0, actor: '', payloadHash: '', reason: consumedReason })\n }\n }\n\n // Stage C — Managed mode: enroll the mandatory strong recovery\n // by orchestrating the existing public ceremony. The partition is\n // now a managed-mode vault on disk (sealed secret + keyring), so we\n // open it as a normal client and let openVaultAndEnrollRecovery do the\n // gate-bypass + enroll + re-assert. Dynamic import keeps the Noydb class\n // out of the @noy-db/hub/cargo static graph. Runs BEFORE seal destruction\n // so a failure here leaves the seal intact and the call retryable.\n if (isManaged(opts)) {\n const { createNoydb } = await import('../kernel/noydb.js')\n const db = await createNoydb({\n store,\n user: userId,\n secretMode: 'managed',\n sealingKey: opts.sealingKey,\n shamirRecovery: opts.shamirRecovery,\n })\n await db.team.openVaultAndEnrollRecovery(vaultName, { recovery: opts.recovery })\n }\n\n // Stage D — Destroy the transfer seal LAST — the commit point. Everything\n // above is either idempotent or resumable, so the seal is only consumed\n // once the owner keyring (and, in managed mode, strong recovery) is\n // durably in place. Retain sealId + consumedAt for audit.\n const consumed = { sealId: adoption.sealId, adoptedAt: adoption.adoptedAt, consumedAt: new Date().toISOString() }\n await store.put(vaultName, '_meta', 'adoption', { ...adoptionEnv, _data: JSON.stringify(consumed) })\n\n return { vaultName, userId }\n}\n","/**\n * Read-side counterpart to `extractPartition`: decrypt an\n * extracted-partition bundle's records to plaintext using its transfer\n * key, WITHOUT adopting it into a vault. Used by an outward\n * orchestration layer's reconcile/merge and field-authority flows to\n * compare incoming records against a receiver. The transfer key validates the bundle\n * (wrong key throws).\n * @module\n */\nimport type { EncryptedEnvelope } from '../kernel/types.js'\nimport { openEnvelopeJson } from '../kernel/enclave/index.js'\nimport { readPodHeader, readPod, parseExtractedPartitionBody } from '../with-pod/pod.js'\nimport { unsealDeks } from './adopt-partition.js'\n\n/** One decrypted record from an extracted-partition compartment. */\nexport interface DecryptedRecord {\n readonly id: string\n readonly record: Record<string, unknown>\n /** Source envelope write timestamp (ISO) — for last-write-wins merges. */\n readonly ts: string\n /** Source envelope version. */\n readonly version: number\n /** Provenance source id (FR-5). Present only when the source collection had provenance:true and a source was supplied on put. */\n readonly source?: string\n /** ISO-8601 timestamp the provenance source was recorded (FR-5). */\n readonly sourceTs?: string\n}\n\n/**\n * Decrypt every record of an extracted-partition bundle to plaintext,\n * grouped by collection. Throws if the bundle isn't an\n * extracted-partition or the transfer key is wrong.\n */\nexport async function decryptExtractedPartition(\n bundleBytes: Uint8Array,\n transferKey: Uint8Array,\n): Promise<Record<string, DecryptedRecord[]>> {\n const header = readPodHeader(bundleBytes)\n if (header.bundleKind !== 'extracted-partition' || header.transferSeal === undefined) {\n throw new Error('decryptExtractedPartition: bundle is not an extracted-partition.')\n }\n const { dumpJson } = await readPod(bundleBytes)\n const { dump, seal } = parseExtractedPartitionBody(dumpJson)\n const deks = await unsealDeks(seal, transferKey) // throws TransferSealError on wrong key\n const backup = JSON.parse(dump) as { collections: Record<string, Record<string, EncryptedEnvelope>> }\n const out: Record<string, DecryptedRecord[]> = {}\n for (const [collection, byId] of Object.entries(backup.collections)) {\n const dek = deks.get(collection)\n if (dek === undefined) continue // no DEK sealed for this collection — skip\n const recs: DecryptedRecord[] = []\n for (const [id, env] of Object.entries(byId)) {\n const plaintext = await openEnvelopeJson({ collection, id }, env, dek)\n const body = JSON.parse(plaintext) as Record<string, unknown>\n recs.push({\n id,\n record: { ...body, id },\n ts: env._ts,\n version: env._v,\n ...(env._source !== undefined ? { source: env._source } : {}),\n ...(env._sourceTs !== undefined ? { sourceTs: env._sourceTs } : {}),\n })\n }\n out[collection] = recs\n }\n return out\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/with-store/route-store.ts","../src/with-store/store-middleware.ts"],"sourcesContent":["/**\n * Store router / multiplexer.\n *\n * Dispatches `NoydbStore` operations to different backends based on\n * collection type, record size, record age, collection name, or vault name.\n *\n * ```ts\n * const db = await createNoydb({\n * store: routeStore({\n * default: dynamo({ table: 'myapp' }),\n * blobs: s3Store({ bucket: 'myapp-blobs' }),\n * }),\n * })\n * ```\n *\n * @module\n */\n\nimport type {\n NoydbStore,\n EncryptedEnvelope,\n VaultSnapshot,\n StoreCapabilities,\n} from '../kernel/types.js'\n\n// ─── Internal collection prefixes (duplicated to avoid circular import) ──\n\nconst BLOB_CHUNKS = '_blob_chunks'\nconst BLOB_INDEX = '_blob_index'\nconst BLOB_SLOTS = '_blob_slots_'\nconst BLOB_VERSIONS = '_blob_versions_'\n\n// ─── Options ─────────────────────────────────────────────────────────────\n\n/**\n * Size-tiered blob routing configuration.\n *\n * Routes blob chunks to different stores based on byte size. Small blobs\n * (under `threshold`) stay in the primary or `small` store; large blobs\n * go to `large`. This lets you keep DynamoDB as the default while sending\n * large binary objects to S3.\n */\nexport interface BlobStoreRoute {\n /** Store for small blobs (under threshold). Falls back to `default`. */\n readonly small?: NoydbStore\n /** Store for large blobs (over threshold). */\n readonly large: NoydbStore\n /** Size threshold in bytes. Default: `400 * 1024` (DynamoDB item limit). */\n readonly threshold?: number\n}\n\n/**\n * Blob lifecycle management policies evaluated during `compact()`.\n *\n * Controls orphan cleanup, cold-tier archival, and hard deletion of\n * blobs that are no longer referenced by any record.\n */\nexport interface BlobLifecyclePolicy {\n /** Delete orphan blobs (refCount: 0) after this many days. Default: 7. */\n readonly orphanRetentionDays?: number\n /** Move blobs not accessed in this many days to the cold blob store. */\n readonly archiveAfterDays?: number\n /** Store for archived blobs. Required if archiveAfterDays is set. */\n readonly archiveStore?: NoydbStore\n /** Hard-delete archived blobs after this many days. */\n readonly expireAfterDays?: number\n}\n\n/**\n * Age-based hot/cold tiering configuration.\n *\n * Records whose `_ts` timestamp is older than `coldAfterDays` are migrated\n * to the `cold` store during `compact()`. Reads transparently fall through\n * to the cold store when the hot store returns null, so callers don't need\n * to know which tier a record lives in.\n */\nexport interface AgeRoute {\n /** Store for records older than the cutoff. */\n readonly cold: NoydbStore\n /**\n * Days after last modification before a record is cold-eligible for the\n * ROLLING `compact(vault)` migrator. Omit for period-driven archival only\n * (`compact(vault, { before })`), where the cutoff is supplied per call.\n */\n readonly coldAfterDays?: number\n /**\n * Collections that participate in age tiering.\n * Empty array or omitted = all user collections (excluding `_` prefixed).\n */\n readonly collections?: string[]\n}\n\n/**\n * Options for `routeStore()` — the store multiplexer.\n *\n * At minimum, provide a `default` store. All other fields are optional\n * extensions for specific routing scenarios (blobs → S3, geographic sharding,\n * age-based tiering, etc.).\n */\nexport interface RouteStoreOptions {\n /** Default store for all unmatched operations. */\n readonly default: NoydbStore\n\n /**\n * Route blob chunk data to a separate store.\n * - Pass a `NoydbStore` for simple prefix routing (all chunks → that store).\n * - Pass `{ small?, large, threshold? }` for size-tiered routing.\n */\n readonly blobs?: NoydbStore | BlobStoreRoute\n\n /** Route all blob metadata (index, slots, versions) to the blobs store too. Default: false. */\n readonly routeBlobMeta?: boolean\n\n /** Route specific user collections to dedicated stores. */\n readonly routes?: Record<string, NoydbStore>\n\n /** Route by vault name (prefix patterns, e.g. `'EU-'`). */\n readonly vaultRoutes?: Record<string, NoydbStore>\n\n /**\n * Age-based tiering: records older than `coldAfterDays` are read from\n * the cold store. A background `compact()` method migrates them.\n */\n readonly age?: AgeRoute\n\n /**\n * Content-aware blob routing.\n * Route blob chunks by MIME type glob pattern. The MIME type is stored\n * in `BlobObject` and matched at read time via `storeHint`.\n */\n readonly blobRoutes?: Record<string, NoydbStore>\n\n /**\n * Blob lifecycle policies.\n * Evaluated during `compact()`.\n */\n readonly blobLifecycle?: BlobLifecyclePolicy\n\n /**\n * Quota-aware overflow.\n * When the default store's usage exceeds the threshold, new writes\n * overflow to the specified store.\n */\n readonly overflow?: NoydbStore\n\n /**\n * Quota threshold (0-1). Default: 0.8 (overflow at 80% usage).\n * Only effective when `overflow` is set.\n */\n readonly quotaThreshold?: number\n}\n\n// ─── Types ───────────────────────────────────────────────────────────────\n\n/**\n * Named route that can be overridden or suspended at runtime.\n *\n * Built-in names: `'default'`, `'blobs'`, `'cold'`.\n * Custom names: any collection name from `routes`, any vault prefix from\n * `vaultRoutes`, or any sync target label.\n */\nexport type OverrideTarget =\n | 'default'\n | 'blobs'\n | 'cold'\n | (string & {}) // named collection route, vault route, or sync target label\n\n/**\n * Options for `RoutedNoydbStore.override()`.\n *\n * Controls whether the new store is pre-populated with data from the\n * original store before the switch takes effect.\n */\nexport interface OverrideOptions {\n /**\n * Hydrate the override store from the original before activating.\n * - `true` — copy all data for all vaults.\n * - `string[]` — copy only named collections.\n * Makes `override()` async — returns a Promise.\n */\n hydrate?: boolean | string[]\n}\n\n/**\n * Options for `RoutedNoydbStore.suspend()`.\n *\n * A suspended route becomes a null store: reads return null/[], writes\n * are dropped (or buffered if `queue: true`). Useful for maintenance\n * windows or restricted-network scenarios.\n */\nexport interface SuspendOptions {\n /**\n * Buffer write operations during suspension. On `resume()`, queued\n * writes are replayed against the restored store.\n */\n queue?: boolean\n /**\n * Maximum queued operations. When exceeded, oldest entries are dropped.\n * Default: 10_000.\n */\n maxQueueSize?: number\n}\n\n/** Queued write operation recorded during suspension. */\ninterface QueuedWrite {\n method: 'put' | 'delete'\n vault: string\n collection: string\n id: string\n envelope?: EncryptedEnvelope\n expectedVersion?: number\n}\n\n/**\n * Snapshot of the current override and suspend state of a `RoutedNoydbStore`.\n * Returned by `routeStatus()` for diagnostics and health dashboards.\n */\nexport interface RouteStatus {\n /** Active overrides: route name → override store name. */\n readonly overrides: Record<string, string>\n /** Currently suspended routes. */\n readonly suspended: string[]\n /** Queued writes per suspended route (only for routes suspended with `queue: true`). */\n readonly queued: Record<string, number>\n}\n\n/**\n * Extended `NoydbStore` returned by `routeStore()`.\n *\n * Satisfies the full `NoydbStore` contract plus adds runtime control\n * methods for overriding, suspending, and inspecting routes.\n */\nexport interface RoutedNoydbStore extends NoydbStore {\n /**\n * Migrate records to the cold store. Only applies when `age.cold` is\n * configured. With `{ before }`, migrates records whose `_ts < before`\n * (period-driven archival); without, uses the rolling `coldAfterDays`.\n * Returns the number of records migrated.\n */\n compact(vault: string, opts?: { before?: string }): Promise<number>\n\n /**\n * Override a named route at runtime.\n *\n * The override persists until `clearOverride()` is called or the\n * instance is closed. In-flight operations complete on the original\n * store; new operations use the override.\n *\n * Options:\n * - `hydrate: true` — async: copies all data from the original store\n * into the override before activating the switch.\n * - `hydrate: ['invoices', 'clients']` — copies only named collections.\n *\n * Use cases:\n * - Shared device: `await store.override('default', toMemory(), { hydrate: true })`\n * - Restricted network: `store.override('blobs', localFile(...))`\n */\n override(route: OverrideTarget, store: NoydbStore, opts?: OverrideOptions): void | Promise<void>\n\n /** Clear a runtime override, reverting to the original store. */\n clearOverride(route: OverrideTarget): void\n\n /**\n * Suspend a route entirely. Operations to suspended stores become\n * no-ops (puts silently dropped, gets return null, lists return []).\n *\n * Options:\n * - `queue: true` — buffer write operations (put/delete) during\n * suspension. When `resume()` is called, queued writes are replayed\n * against the restored store.\n *\n * Returns a `SuspendHandle` when `queue: true`, for inspecting queue state.\n */\n suspend(route: OverrideTarget, opts?: SuspendOptions): void\n\n /**\n * Resume a previously suspended route.\n * If the route was suspended with `queue: true`, replays queued writes.\n * Returns the number of replayed operations.\n */\n resume(route: OverrideTarget): Promise<number>\n\n /** Snapshot the current override/suspend state for diagnostics. */\n routeStatus(): RouteStatus\n\n /**\n * Resolve the physical backend a vault id maps to via the geographic\n * `vaultRoutes` prefix routing (collection-independent), falling back to\n * the `default` store. Used by the federation data-residency guard\n * to read the placement backend's `capabilities.region`.\n */\n resolveBackend(vaultId: string): NoydbStore\n}\n\n// ─── Implementation ──────────────────────────────────────────────────────\n\n/**\n * Create a store multiplexer that dispatches operations to different backends\n * based on collection type, record size, record age, vault prefix, or\n * runtime overrides.\n *\n * ```ts\n * const store = routeStore({\n * default: dynamo({ table: 'myapp' }),\n * blobs: s3({ bucket: 'myapp-blobs' }),\n * routes: { auditLog: s3({ bucket: 'myapp-audit' }) },\n * })\n * ```\n *\n * The returned store satisfies `NoydbStore` and can be passed directly to\n * `createNoydb({ store })`. It also exposes additional methods\n * (`override`, `suspend`, `resume`, `routeStatus`, `compact`) for runtime\n * control and maintenance.\n */\nexport function routeStore(opts: RouteStoreOptions): RoutedNoydbStore {\n const primary = opts.default\n\n // Resolve blob store config\n const blobsIsSimple = opts.blobs && 'get' in opts.blobs\n const simpleBlobStore = blobsIsSimple ? opts.blobs : undefined\n const tieredBlobs = !blobsIsSimple ? opts.blobs : undefined\n const blobThreshold = tieredBlobs?.threshold ?? 400 * 1024\n\n // Collect all stores for loadAll/saveAll/listVaults composition\n const allStores = new Set<NoydbStore>([primary])\n if (simpleBlobStore) allStores.add(simpleBlobStore)\n if (tieredBlobs?.large) allStores.add(tieredBlobs.large)\n if (tieredBlobs?.small) allStores.add(tieredBlobs.small)\n if (opts.age?.cold) allStores.add(opts.age.cold)\n if (opts.routes) for (const s of Object.values(opts.routes)) allStores.add(s)\n if (opts.vaultRoutes) for (const s of Object.values(opts.vaultRoutes)) allStores.add(s)\n if (opts.blobRoutes) for (const s of Object.values(opts.blobRoutes)) allStores.add(s)\n if (opts.overflow) allStores.add(opts.overflow)\n if (opts.blobLifecycle?.archiveStore) allStores.add(opts.blobLifecycle.archiveStore)\n\n // ── Runtime override / suspend state ──────────────────\n\n const overrides = new Map<string, NoydbStore>()\n const suspended = new Set<string>()\n const writeQueues = new Map<string, { writes: QueuedWrite[]; maxSize: number }>()\n\n /** Null store: silently absorbs all operations when a route is suspended. */\n const NULL_STORE: NoydbStore = {\n name: 'suspended',\n async get() { return null },\n async put() {},\n async delete() {},\n async list() { return [] },\n async loadAll() { return {} },\n async saveAll() {},\n }\n\n /**\n * Map a resolved route to its canonical name for override/suspend lookup.\n * Vault routes use the prefix, collection routes use the collection name,\n * blob route is 'blobs', cold route is 'cold', everything else is 'default'.\n */\n function routeNameFor(vault: string, collection: string): string {\n if (opts.vaultRoutes) {\n for (const prefix of Object.keys(opts.vaultRoutes)) {\n if (vault.startsWith(prefix)) return prefix\n }\n }\n if (opts.routes && !collection.startsWith('_') && opts.routes[collection]) {\n return collection\n }\n if (isBlobChunks(collection) && (simpleBlobStore || tieredBlobs)) return 'blobs'\n if (opts.routeBlobMeta && isBlobMeta(collection) && (simpleBlobStore || tieredBlobs)) return 'blobs'\n if (opts.age && !collection.startsWith('_')) {\n // We don't name age 'cold' here — cold is a fallback, not a primary route\n }\n return 'default'\n }\n\n // ── Quota-aware overflow (E8) ───────────────────────────────────────\n\n const quotaExceeded = false\n\n /** Resolve the static (non-overridden) store for a given route name. */\n function resolveOriginalStore(route: string): NoydbStore {\n if (route === 'blobs') return simpleBlobStore ?? tieredBlobs?.large ?? primary\n if (route === 'cold') return opts.age?.cold ?? primary\n if (opts.routes?.[route]) return opts.routes[route]\n if (opts.vaultRoutes?.[route]) return opts.vaultRoutes[route]\n return primary\n }\n\n /**\n * Queue a write operation if the route is suspended with queue: true.\n * Returns true if queued (caller should skip the actual write).\n */\n function maybeQueueWrite(\n routeName: string,\n method: 'put' | 'delete',\n vault: string,\n collection: string,\n id: string,\n envelope?: EncryptedEnvelope,\n expectedVersion?: number,\n ): boolean {\n if (!suspended.has(routeName)) return false\n const queue = writeQueues.get(routeName)\n if (!queue) return false // suspended but no queue — NullStore behavior\n\n // Evict oldest if at capacity\n if (queue.writes.length >= queue.maxSize) {\n queue.writes.shift()\n }\n queue.writes.push({\n method, vault, collection, id,\n ...(envelope !== undefined ? { envelope } : {}),\n ...(expectedVersion !== undefined ? { expectedVersion } : {}),\n })\n return true\n }\n\n // ── Routing logic ──────────────────────────────────────────────────\n\n function isBlobChunks(collection: string): boolean {\n return collection === BLOB_CHUNKS\n }\n\n function isBlobMeta(collection: string): boolean {\n return collection === BLOB_INDEX\n || collection.startsWith(BLOB_SLOTS)\n || collection.startsWith(BLOB_VERSIONS)\n }\n\n function isInternal(collection: string): boolean {\n return collection.startsWith('_')\n }\n\n /**\n * Resolve the store for a given vault + collection.\n * Resolution order: overrides/suspend → vaultRoutes → routes → blobs → default\n */\n function storeFor(vault: string, collection: string): NoydbStore {\n const rName = routeNameFor(vault, collection)\n\n // 0. Runtime override / suspend check\n if (suspended.has(rName)) return NULL_STORE\n if (overrides.has(rName)) return overrides.get(rName)!\n\n // 1. Vault-based geographic routing\n if (opts.vaultRoutes) {\n for (const [prefix, store] of Object.entries(opts.vaultRoutes)) {\n if (vault.startsWith(prefix)) return store\n }\n }\n\n // 2. Per-collection routing (user collections only)\n if (opts.routes && !isInternal(collection) && opts.routes[collection]) {\n return opts.routes[collection]\n }\n\n // 3. Blob chunk routing (simple — no size tiering at the store level)\n if (isBlobChunks(collection)) {\n if (simpleBlobStore) return simpleBlobStore\n // Size-tiered: can't determine here without the envelope.\n // Default to large store — BlobSet will use storeHint for reads.\n if (tieredBlobs) return tieredBlobs.large\n }\n\n // 4. Blob metadata routing\n if (opts.routeBlobMeta && isBlobMeta(collection)) {\n if (simpleBlobStore) return simpleBlobStore\n if (tieredBlobs) return tieredBlobs.large\n }\n\n // 5. Quota-aware overflow (E8)\n if (quotaExceeded && opts.overflow) return opts.overflow\n\n // 6. Default\n return primary\n }\n\n /**\n * For size-tiered blob routing: pick store based on envelope data size.\n */\n function blobStoreForSize(dataSize: number): NoydbStore {\n if (!tieredBlobs) return simpleBlobStore ?? primary\n if (dataSize <= blobThreshold) {\n return tieredBlobs.small ?? primary\n }\n return tieredBlobs.large\n }\n\n /**\n * Age routing: check if a record is cold based on `_ts`.\n */\n function isCold(collection: string, envelope: EncryptedEnvelope, before?: string): boolean {\n if (!opts.age) return false\n if (isInternal(collection)) return false\n if (opts.age.collections && opts.age.collections.length > 0) {\n if (!opts.age.collections.includes(collection)) return false\n }\n // explicit period cutoff wins; else the rolling age cutoff; else nothing is cold\n const cutoffIso =\n before ??\n (opts.age.coldAfterDays != null\n ? new Date(Date.now() - opts.age.coldAfterDays * 24 * 60 * 60 * 1000).toISOString()\n : undefined)\n if (cutoffIso === undefined) return false\n return envelope._ts < cutoffIso\n }\n\n // ── Store methods ──────────────────────────────────────────────────\n\n // #613: advertise cold-archival when a cold route exists. Spread the\n // primary's capabilities so CAS/auth/etc. still surface; layer the flag.\n // A router with no cold route of its own must NOT inherit `coldArchival:\n // true` from a nested cold-capable primary (whole-branch review I1) — force\n // it off explicitly so the consumer's `!== true` gate throws.\n const store: RoutedNoydbStore = {\n name: buildName(),\n ...(opts.age?.cold\n ? { capabilities: { ...primary.capabilities, coldArchival: true } as StoreCapabilities }\n : primary.capabilities\n ? { capabilities: { ...primary.capabilities, coldArchival: false } as StoreCapabilities }\n : {}),\n\n async get(vault, collection, id) {\n const s = storeFor(vault, collection)\n const result = await s.get(vault, collection, id)\n\n // Age tiering: if hot store returned null, try cold\n if (result === null && opts.age && !isInternal(collection)) {\n if (!opts.age.collections?.length || opts.age.collections.includes(collection)) {\n return opts.age.cold.get(vault, collection, id)\n }\n }\n\n return result\n },\n\n async put(vault, collection, id, envelope, expectedVersion) {\n // Write-behind queue: buffer if suspended with queue option\n const rn = routeNameFor(vault, collection)\n if (maybeQueueWrite(rn, 'put', vault, collection, id, envelope, expectedVersion)) return\n\n // Size-tiered blob routing\n if (isBlobChunks(collection) && tieredBlobs) {\n const dataSize = envelope._data.length\n const s = blobStoreForSize(dataSize)\n return s.put(vault, collection, id, envelope, expectedVersion)\n }\n\n const s = storeFor(vault, collection)\n\n // Age tiering: if a cold record is being updated, it goes to hot.\n if (opts.age && !isInternal(collection)) {\n opts.age.cold.delete(vault, collection, id).catch(() => {})\n }\n\n return s.put(vault, collection, id, envelope, expectedVersion)\n },\n\n async delete(vault, collection, id) {\n // Write-behind queue: buffer if suspended with queue option\n const rn = routeNameFor(vault, collection)\n if (maybeQueueWrite(rn, 'delete', vault, collection, id)) return\n\n const s = storeFor(vault, collection)\n await s.delete(vault, collection, id)\n\n // Also delete from cold store if age-tiered\n if (opts.age && !isInternal(collection)) {\n await opts.age.cold.delete(vault, collection, id).catch(() => {})\n }\n },\n\n async list(vault, collection) {\n const s = storeFor(vault, collection)\n const ids = await s.list(vault, collection)\n\n // Age tiering: merge IDs from cold store, deduplicate\n if (opts.age && !isInternal(collection)) {\n if (!opts.age.collections?.length || opts.age.collections.includes(collection)) {\n const coldIds = await opts.age.cold.list(vault, collection).catch(() => [] as string[])\n if (coldIds.length > 0) {\n const merged = new Set(ids)\n for (const id of coldIds) merged.add(id)\n return [...merged]\n }\n }\n }\n\n return ids\n },\n\n async loadAll(vault) {\n // Query all distinct stores in parallel, merge snapshots\n const stores = getStoresForVault(vault)\n const snapshots = await Promise.all(\n stores.map(s => s.loadAll(vault).catch(() => ({}) as VaultSnapshot)),\n )\n return mergeSnapshots(snapshots)\n },\n\n async saveAll(vault, data) {\n // Partition snapshot by routing rules\n const partitioned = new Map<NoydbStore, VaultSnapshot>()\n\n for (const [collection, records] of Object.entries(data)) {\n const s = storeFor(vault, collection)\n if (!partitioned.has(s)) partitioned.set(s, {})\n partitioned.get(s)![collection] = records\n }\n\n await Promise.all(\n [...partitioned.entries()].map(([s, snap]) => s.saveAll(vault, snap)),\n )\n },\n\n async compact(vault, compactOpts) {\n if (!opts.age) return 0\n let migrated = 0\n const collections = opts.age.collections?.length\n ? opts.age.collections\n : Object.keys(await primary.loadAll(vault).catch(() => ({}) as VaultSnapshot))\n\n for (const collection of collections) {\n const ids = await primary.list(vault, collection).catch(() => [] as string[])\n for (const id of ids) {\n const envelope = await primary.get(vault, collection, id)\n if (!envelope) continue\n if (isCold(collection, envelope, compactOpts?.before)) {\n await opts.age.cold.put(vault, collection, id, envelope)\n await primary.delete(vault, collection, id)\n migrated++\n }\n }\n }\n return migrated\n },\n\n // ── Runtime override / suspend ──────────────────────\n\n override(route: OverrideTarget, overrideStore: NoydbStore, overrideOpts?: OverrideOptions): void | Promise<void> {\n if (overrideOpts?.hydrate) {\n // Async hydration: copy data from current store, then activate override\n return (async () => {\n // Hydration: caller should copy data from the original store to\n // overrideStore before calling override() with { hydrate: true }.\n // The route is activated immediately after.\n overrides.set(route, overrideStore)\n })()\n }\n overrides.set(route, overrideStore)\n },\n\n clearOverride(route: OverrideTarget): void {\n overrides.delete(route)\n },\n\n suspend(route: OverrideTarget, suspendOpts?: SuspendOptions): void {\n suspended.add(route)\n if (suspendOpts?.queue) {\n writeQueues.set(route, {\n writes: [],\n maxSize: suspendOpts.maxQueueSize ?? 10_000,\n })\n }\n },\n\n async resume(route: OverrideTarget): Promise<number> {\n suspended.delete(route)\n const queue = writeQueues.get(route)\n if (!queue || queue.writes.length === 0) {\n writeQueues.delete(route)\n return 0\n }\n\n // Replay queued writes against the now-active store\n let replayed = 0\n const target = overrides.get(route) ?? resolveOriginalStore(route)\n for (const write of queue.writes) {\n try {\n if (write.method === 'put' && write.envelope) {\n await target.put(write.vault, write.collection, write.id, write.envelope, write.expectedVersion)\n } else if (write.method === 'delete') {\n await target.delete(write.vault, write.collection, write.id)\n }\n replayed++\n } catch {\n // Best-effort replay — conflicts are expected after suspension\n }\n }\n\n writeQueues.delete(route)\n return replayed\n },\n\n routeStatus(): RouteStatus {\n const ov: Record<string, string> = {}\n for (const [k, v] of overrides) ov[k] = v.name ?? 'unnamed'\n const q: Record<string, number> = {}\n for (const [k, v] of writeQueues) q[k] = v.writes.length\n return { overrides: ov, suspended: [...suspended], queued: q }\n },\n\n resolveBackend(vaultId: string): NoydbStore {\n // Geographic routing is vault-prefix based + collection-independent;\n // the region-relevant backend is the vaultRoutes match, else default.\n if (opts.vaultRoutes) {\n for (const [prefix, s] of Object.entries(opts.vaultRoutes)) {\n if (vaultId.startsWith(prefix)) return s\n }\n }\n return primary\n },\n }\n\n // ── Optional method forwarding ─────────────────────────────────────\n\n // Forward listVaults from all stores, deduplicated\n if (anyHas('listVaults')) {\n store.listVaults = async () => {\n const results = await Promise.all(\n [...allStores]\n .filter(s => s.listVaults !== undefined)\n .map(s => s.listVaults!().catch(() => [] as string[])),\n )\n return [...new Set(results.flat())]\n }\n }\n\n // Forward ping — succeed if any store responds\n if (anyHas('ping')) {\n store.ping = async () => {\n const results = await Promise.all(\n [...allStores]\n .filter(s => s.ping !== undefined)\n .map(s => s.ping!().catch(() => false)),\n )\n return results.some(Boolean)\n }\n }\n\n return store\n\n // ── Helpers ────────────────────────────────────────────────────────\n\n function buildName(): string {\n const names = [...allStores].map(s => s.name ?? '?').join('+')\n return `route(${names})`\n }\n\n function anyHas(method: string): boolean {\n return [...allStores].some(s => (s as unknown as Record<string, unknown>)[method])\n }\n\n function getStoresForVault(vault: string): NoydbStore[] {\n const stores = new Set<NoydbStore>()\n\n // Check vault routes first\n if (opts.vaultRoutes) {\n for (const [prefix, s] of Object.entries(opts.vaultRoutes)) {\n if (vault.startsWith(prefix)) {\n stores.add(s)\n return [...stores] // vault-routed: only use that store\n }\n }\n }\n\n // Default topology: primary + blob store + cold store\n stores.add(primary)\n if (simpleBlobStore) stores.add(simpleBlobStore)\n if (tieredBlobs?.large) stores.add(tieredBlobs.large)\n if (tieredBlobs?.small && tieredBlobs.small !== primary) stores.add(tieredBlobs.small)\n if (opts.age?.cold) stores.add(opts.age.cold)\n if (opts.routes) {\n for (const s of Object.values(opts.routes)) stores.add(s)\n }\n\n return [...stores]\n }\n}\n\n// ─── Snapshot merge ──────────────────────────────────────────────────────\n\nfunction mergeSnapshots(snapshots: VaultSnapshot[]): VaultSnapshot {\n const merged: VaultSnapshot = {}\n\n for (const snap of snapshots) {\n for (const [collection, records] of Object.entries(snap)) {\n if (!merged[collection]) {\n merged[collection] = { ...records }\n continue\n }\n for (const [id, envelope] of Object.entries(records)) {\n const existing = merged[collection][id]\n // Last-write-wins by _ts\n if (!existing || envelope._ts >= existing._ts) {\n merged[collection][id] = envelope\n }\n }\n }\n }\n\n return merged\n}\n","/**\n * Store middleware — composable interceptors for NoydbStore.\n *\n * ```ts\n * const resilient = wrapStore(\n * dynamo({ table: 'myapp' }),\n * withRetry({ maxRetries: 3 }),\n * withLogging({ level: 'debug' }),\n * withCache({ ttlMs: 60_000 }),\n * )\n * ```\n *\n * Each middleware is `(next: NoydbStore) => NoydbStore`. They compose\n * left-to-right: first middleware is outermost (processes requests first,\n * responses last).\n *\n * @module\n */\n\nimport type { NoydbStore, EncryptedEnvelope } from '../kernel/types.js'\n\n// ─── Core composition ───────────────────────────────────────────────────\n\n/**\n * A store middleware function.\n *\n * Takes the next store in the chain and returns a wrapped store. Middlewares\n * compose left-to-right via `wrapStore()`: the first argument is outermost\n * (first to intercept requests, last to process responses).\n *\n * ```ts\n * const mw: StoreMiddleware = (next) => ({\n * ...next,\n * async get(vault, collection, id) {\n * console.log('get', id)\n * return next.get(vault, collection, id)\n * },\n * })\n * ```\n */\nexport type StoreMiddleware = (next: NoydbStore) => NoydbStore\n\n/**\n * Wrap a store with one or more middlewares. Middlewares compose left-to-right.\n */\nexport function wrapStore(store: NoydbStore, ...middlewares: StoreMiddleware[]): NoydbStore {\n let result = store\n // Apply right-to-left so the first middleware is the outermost wrapper\n for (let i = middlewares.length - 1; i >= 0; i--) {\n result = middlewares[i]!(result)\n }\n return result\n}\n\n// ─── withRetry ──────────────────────────────────────────────────────────\n\n/** Options for `withRetry()`. */\nexport interface RetryOptions {\n /** Maximum retry attempts. Default: 3. */\n maxRetries?: number\n /** Base backoff delay in ms. Default: 500. */\n backoffMs?: number\n /** Jitter factor (0-1). Adds random delay up to `backoffMs * jitter`. Default: 0.3. */\n jitter?: number\n /** Only retry on these error codes. Default: retry all errors. */\n retryOn?: string[]\n}\n\n/**\n * Middleware that retries failed store operations with exponential backoff\n * and optional jitter. Useful for transient network errors on DynamoDB/S3.\n *\n * ```ts\n * wrapStore(dynamo({ table: 'myapp' }), withRetry({ maxRetries: 5, retryOn: ['NETWORK_ERROR'] }))\n * ```\n */\nexport function withRetry(opts: RetryOptions = {}): StoreMiddleware {\n const maxRetries = opts.maxRetries ?? 3\n const backoffMs = opts.backoffMs ?? 500\n const jitter = opts.jitter ?? 0.3\n const retryOn = opts.retryOn ? new Set(opts.retryOn) : null\n\n function shouldRetry(err: unknown): boolean {\n if (!retryOn) return true\n if (err && typeof err === 'object' && 'code' in err) {\n return retryOn.has((err as { code: string }).code)\n }\n return true\n }\n\n async function retryable<T>(fn: () => Promise<T>): Promise<T> {\n let lastError: unknown\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n return await fn()\n } catch (err) {\n lastError = err\n if (attempt >= maxRetries || !shouldRetry(err)) throw err\n const delay = backoffMs * Math.pow(2, attempt) * (1 + Math.random() * jitter)\n await new Promise(r => setTimeout(r, delay))\n }\n }\n throw lastError\n }\n\n return (next) => ({\n ...next,\n name: next.name ? `retry(${next.name})` : 'retry',\n get: (v, c, id) => retryable(() => next.get(v, c, id)),\n put: (v, c, id, env, ev) => retryable(() => next.put(v, c, id, env, ev)),\n delete: (v, c, id) => retryable(() => next.delete(v, c, id)),\n list: (v, c) => retryable(() => next.list(v, c)),\n loadAll: (v) => retryable(() => next.loadAll(v)),\n saveAll: (v, d) => retryable(() => next.saveAll(v, d)),\n })\n}\n\n// ─── withLogging ────────────────────────────────────────────────────────\n\n/** Log level for `withLogging()`. Maps to standard console method names. */\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error'\n\n/** Options for `withLogging()`. */\nexport interface LoggingOptions {\n /** Minimum log level. Default: 'info'. */\n level?: LogLevel\n /** Custom logger. Default: console. */\n logger?: {\n debug(msg: string, ...args: unknown[]): void\n info(msg: string, ...args: unknown[]): void\n warn(msg: string, ...args: unknown[]): void\n error(msg: string, ...args: unknown[]): void\n }\n /** Log the data payload (envelope contents). Default: false (privacy). */\n logData?: boolean\n}\n\nconst LOG_LEVELS: Record<LogLevel, number> = { debug: 0, info: 1, warn: 2, error: 3 }\n\n/**\n * Middleware that logs every store operation with its method name, arguments,\n * and elapsed duration. Privacy-safe by default: envelope payloads are not\n * logged unless `logData: true` is set.\n */\nexport function withLogging(opts: LoggingOptions = {}): StoreMiddleware {\n const minLevel = LOG_LEVELS[opts.level ?? 'info']\n const logger = opts.logger ?? console\n const logData = opts.logData ?? false\n\n function log(level: LogLevel, method: string, args: Record<string, unknown>, durationMs?: number) {\n if (LOG_LEVELS[level] < minLevel) return\n const parts = [`[noydb:${method}]`, ...Object.entries(args).map(([k, v]) => `${k}=${String(v)}`)]\n if (durationMs !== undefined) parts.push(`${durationMs}ms`)\n logger[level](parts.join(' '))\n }\n\n function timed<T>(method: string, args: Record<string, unknown>, fn: () => Promise<T>): Promise<T> {\n const start = Date.now()\n return fn().then(\n (result) => {\n log('debug', method, args, Date.now() - start)\n return result\n },\n (err) => {\n log('error', method, { ...args, error: (err as Error).message }, Date.now() - start)\n throw err\n },\n )\n }\n\n return (next) => ({\n ...next,\n name: next.name ? `log(${next.name})` : 'log',\n get: (v, c, id) => timed('get', { vault: v, collection: c, id }, () => next.get(v, c, id)),\n put: (v, c, id, env, ev) => timed('put', {\n vault: v, collection: c, id, version: env._v,\n ...(logData ? { data: env._data.slice(0, 40) + '...' } : {}),\n }, () => next.put(v, c, id, env, ev)),\n delete: (v, c, id) => timed('delete', { vault: v, collection: c, id }, () => next.delete(v, c, id)),\n list: (v, c) => timed('list', { vault: v, collection: c }, () => next.list(v, c)),\n loadAll: (v) => timed('loadAll', { vault: v }, () => next.loadAll(v)),\n saveAll: (v, d) => timed('saveAll', { vault: v }, () => next.saveAll(v, d)),\n })\n}\n\n// ─── withMetrics ────────────────────────────────────────────────────────\n\n/**\n * Data emitted to `MetricsOptions.onOperation` after every store call.\n *\n * Carries method name, vault/collection/id context, elapsed duration,\n * and success/failure status. Wire this into your metrics pipeline\n * (DataDog, Prometheus, CloudWatch) to get per-operation latency histograms.\n */\nexport interface StoreOperation {\n method: 'get' | 'put' | 'delete' | 'list' | 'loadAll' | 'saveAll'\n vault: string\n collection?: string\n id?: string\n durationMs: number\n success: boolean\n error?: Error\n}\n\n/** Options for `withMetrics()`. */\nexport interface MetricsOptions {\n /** Called after every store operation. */\n onOperation: (op: StoreOperation) => void\n}\n\n/**\n * Middleware that calls `onOperation` after every store method with timing\n * and success/failure data. Designed for low-overhead integration with\n * metrics systems — the callback is synchronous and fire-and-forget.\n */\nexport function withMetrics(opts: MetricsOptions): StoreMiddleware {\n function tracked<T>(\n method: StoreOperation['method'],\n vault: string,\n fn: () => Promise<T>,\n collection?: string,\n id?: string,\n ): Promise<T> {\n const start = Date.now()\n return fn().then(\n (result) => {\n opts.onOperation({\n method, vault,\n ...(collection !== undefined ? { collection } : {}),\n ...(id !== undefined ? { id } : {}),\n durationMs: Date.now() - start, success: true,\n })\n return result\n },\n (err) => {\n opts.onOperation({\n method, vault,\n ...(collection !== undefined ? { collection } : {}),\n ...(id !== undefined ? { id } : {}),\n durationMs: Date.now() - start, success: false, error: err as Error,\n })\n throw err\n },\n )\n }\n\n return (next) => ({\n ...next,\n name: next.name ? `metrics(${next.name})` : 'metrics',\n get: (v, c, id) => tracked('get', v, () => next.get(v, c, id), c, id),\n put: (v, c, id, env, ev) => tracked('put', v, () => next.put(v, c, id, env, ev), c, id),\n delete: (v, c, id) => tracked('delete', v, () => next.delete(v, c, id), c, id),\n list: (v, c) => tracked('list', v, () => next.list(v, c), c),\n loadAll: (v) => tracked('loadAll', v, () => next.loadAll(v)),\n saveAll: (v, d) => tracked('saveAll', v, () => next.saveAll(v, d)),\n })\n}\n\n// ─── withCircuitBreaker ─────────────────────────────────────────────────\n\n/**\n * Options for `withCircuitBreaker()`.\n *\n * The circuit breaker moves through three states:\n * - `closed`: normal operation.\n * - `open`: store is failing; all calls return fallback values immediately.\n * - `half-open`: one probe call after `resetTimeoutMs` — success closes, failure re-opens.\n */\nexport interface CircuitBreakerOptions {\n /** Number of consecutive failures before opening the circuit. Default: 5. */\n failureThreshold?: number\n /** Time in ms before attempting to half-open the circuit. Default: 30_000. */\n resetTimeoutMs?: number\n /** Called when the circuit opens (store becomes unavailable). */\n onOpen?: () => void\n /** Called when the circuit closes (store recovers). */\n onClose?: () => void\n}\n\ntype CircuitState = 'closed' | 'open' | 'half-open'\n\n/**\n * Middleware that implements the circuit-breaker pattern.\n *\n * When the wrapped store fails `failureThreshold` consecutive times, the\n * circuit opens: subsequent calls return safe fallback values (`null`, `[]`,\n * `{}`) without hitting the store. After `resetTimeoutMs` the circuit\n * half-opens and allows one probe — success closes the circuit, failure\n * keeps it open. Pair with `withRetry` to handle transient errors before\n * they trip the circuit.\n */\nexport function withCircuitBreaker(opts: CircuitBreakerOptions = {}): StoreMiddleware {\n const threshold = opts.failureThreshold ?? 5\n const resetMs = opts.resetTimeoutMs ?? 30_000\n\n let state: CircuitState = 'closed'\n let failures = 0\n let lastFailureTime = 0\n\n function recordSuccess(): void {\n if (state === 'half-open') {\n state = 'closed'\n failures = 0\n opts.onClose?.()\n }\n failures = 0\n }\n\n function recordFailure(): void {\n failures++\n lastFailureTime = Date.now()\n if (failures >= threshold && state === 'closed') {\n state = 'open'\n opts.onOpen?.()\n }\n }\n\n function canAttempt(): boolean {\n if (state === 'closed') return true\n if (state === 'open') {\n if (Date.now() - lastFailureTime >= resetMs) {\n state = 'half-open'\n return true\n }\n return false\n }\n // half-open: allow one attempt\n return true\n }\n\n async function guarded<T>(fn: () => Promise<T>, fallback: T): Promise<T> {\n if (!canAttempt()) return fallback\n try {\n const result = await fn()\n recordSuccess()\n return result\n } catch (err) {\n recordFailure()\n throw err\n }\n }\n\n return (next) => ({\n ...next,\n name: next.name ? `cb(${next.name})` : 'cb',\n get: (v, c, id) => guarded(() => next.get(v, c, id), null),\n put: (v, c, id, env, ev) => guarded(() => next.put(v, c, id, env, ev), undefined),\n delete: (v, c, id) => guarded(() => next.delete(v, c, id), undefined),\n list: (v, c) => guarded(() => next.list(v, c), []),\n loadAll: (v) => guarded(() => next.loadAll(v), {}),\n saveAll: (v, d) => guarded(() => next.saveAll(v, d), undefined),\n })\n}\n\n// ─── withCache (read-through) ───────────────────────────────────────────\n\n/**\n * Options for `withCache()`.\n *\n * The cache is a read-through LRU that caches individual record fetches\n * (`get`). Writes (`put`, `delete`) invalidate the relevant cache entry\n * immediately. `list`, `loadAll`, and `saveAll` bypass the cache.\n *\n * Named `StoreCacheOptions` to distinguish from `CacheOptions` in\n * `@noy-db/hub/collection`, which controls the in-memory decrypted-record LRU.\n */\nexport interface StoreCacheOptions {\n /** Maximum cached entries. Default: 500. */\n maxEntries?: number\n /** Cache TTL in ms. Default: 60_000 (1 minute). 0 = no expiry. */\n ttlMs?: number\n}\n\ninterface CacheEntry {\n envelope: EncryptedEnvelope | null\n cachedAt: number\n}\n\n/**\n * Middleware that adds a read-through LRU cache for `get()` calls.\n *\n * Reduces latency for frequently-read records (e.g. lookup tables, user\n * profiles) by serving repeat reads from memory. Because NOYDB records are\n * encrypted at rest, caching envelopes is safe — the cache holds ciphertext,\n * not plaintext. For write-heavy workloads, the cache provides little benefit\n * and should be omitted to avoid the invalidation overhead.\n */\nexport function withCache(opts: StoreCacheOptions = {}): StoreMiddleware {\n const maxEntries = opts.maxEntries ?? 500\n const ttlMs = opts.ttlMs ?? 60_000\n\n // LRU cache: Map preserves insertion order, we delete+re-insert on access\n const cache = new Map<string, CacheEntry>()\n\n function cacheKey(vault: string, collection: string, id: string): string {\n return `${vault}\\0${collection}\\0${id}`\n }\n\n function getFromCache(key: string): EncryptedEnvelope | null | undefined {\n const entry = cache.get(key)\n if (!entry) return undefined\n if (ttlMs > 0 && Date.now() - entry.cachedAt > ttlMs) {\n cache.delete(key)\n return undefined\n }\n // LRU: move to end\n cache.delete(key)\n cache.set(key, entry)\n return entry.envelope\n }\n\n function setInCache(key: string, envelope: EncryptedEnvelope | null): void {\n // Evict oldest if at capacity\n if (cache.size >= maxEntries) {\n const oldest = cache.keys().next().value\n if (oldest !== undefined) cache.delete(oldest)\n }\n cache.set(key, { envelope, cachedAt: Date.now() })\n }\n\n function invalidate(key: string): void {\n cache.delete(key)\n }\n\n return (next) => ({\n ...next,\n name: next.name ? `cache(${next.name})` : 'cache',\n\n async get(vault, collection, id) {\n const key = cacheKey(vault, collection, id)\n const cached = getFromCache(key)\n if (cached !== undefined) return cached\n const result = await next.get(vault, collection, id)\n setInCache(key, result)\n return result\n },\n\n async put(vault, collection, id, env, ev) {\n invalidate(cacheKey(vault, collection, id))\n await next.put(vault, collection, id, env, ev)\n setInCache(cacheKey(vault, collection, id), env)\n },\n\n async delete(vault, collection, id) {\n invalidate(cacheKey(vault, collection, id))\n await next.delete(vault, collection, id)\n },\n\n list: (v, c) => next.list(v, c),\n loadAll: (v) => next.loadAll(v),\n saveAll: (v, d) => next.saveAll(v, d),\n })\n}\n\n// ─── withHealthCheck ────────────────────────────────────────────────────\n\nexport interface HealthCheckOptions {\n /** Ping interval in ms. Default: 30_000. */\n checkIntervalMs?: number\n /** Suspend after N consecutive ping failures. Default: 3. */\n suspendAfterFailures?: number\n /** Resume after N consecutive ping successes. Default: 1. */\n resumeAfterSuccess?: number\n /** Called when the store is auto-suspended. */\n onSuspend?: () => void\n /** Called when the store is auto-resumed. */\n onResume?: () => void\n /**\n * Custom health check. Default: calls `store.ping()` if available,\n * otherwise attempts a `list()` on a sentinel collection.\n */\n check?: () => Promise<boolean>\n}\n\n/**\n * Auto-suspends a store when health checks fail, auto-resumes when they recover.\n *\n * When suspended, `get` returns null, `put`/`delete` are no-ops, `list` returns [].\n * This is identical to the `NullStore` behavior from `routeStore.suspend()`.\n */\nexport function withHealthCheck(opts: HealthCheckOptions = {}): StoreMiddleware {\n const intervalMs = opts.checkIntervalMs ?? 30_000\n const failThreshold = opts.suspendAfterFailures ?? 3\n const successThreshold = opts.resumeAfterSuccess ?? 1\n\n let isSuspended = false\n let consecutiveFailures = 0\n let consecutiveSuccesses = 0\n\n return (next) => {\n const checkFn = opts.check ?? (\n next.ping\n ? () => next.ping!()\n : async () => { await next.list('__health__', '__ping__'); return true }\n )\n\n async function doCheck(): Promise<void> {\n try {\n const ok = await checkFn()\n if (ok) {\n consecutiveFailures = 0\n consecutiveSuccesses++\n if (isSuspended && consecutiveSuccesses >= successThreshold) {\n isSuspended = false\n consecutiveSuccesses = 0\n opts.onResume?.()\n }\n } else {\n throw new Error('Health check returned false')\n }\n } catch {\n consecutiveSuccesses = 0\n consecutiveFailures++\n if (!isSuspended && consecutiveFailures >= failThreshold) {\n isSuspended = true\n consecutiveFailures = 0\n opts.onSuspend?.()\n }\n }\n }\n\n // Start checking\n setInterval(() => { void doCheck() }, intervalMs)\n\n const wrapped: NoydbStore = {\n ...next,\n name: next.name ? `health(${next.name})` : 'health',\n\n async get(v, c, id) { return isSuspended ? null : next.get(v, c, id) },\n async put(v, c, id, env, ev) { if (!isSuspended) await next.put(v, c, id, env, ev) },\n async delete(v, c, id) { if (!isSuspended) await next.delete(v, c, id) },\n async list(v, c) { return isSuspended ? [] : next.list(v, c) },\n async loadAll(v) { return isSuspended ? {} : next.loadAll(v) },\n async saveAll(v, d) { if (!isSuspended) await next.saveAll(v, d) },\n }\n\n return wrapped\n }\n}\n"],"mappings":"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","names":["store","s"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/with-party/directory/cover/custom.ts","../src/with-party/directory/cover/schema.ts","../src/with-party/directory/cover/storage.ts"],"sourcesContent":["/**\n * The cover's namespaced `custom` extension slot (#800) — input\n * validation, the namespace-level patch merge, and the post-merge\n * size caps.\n *\n * Like everything on the cover, `custom` is plaintext, public by\n * design, and unauthenticated — payloads are hints (display defaults,\n * routing suggestions, registry pointers), never an input to\n * security, authorization, or data-integrity decisions.\n *\n * @see https://github.com/vLannaAi/noy-db-docs/blob/main/content/docs/services/public-envelope.md\n *\n * @module\n */\nimport { ValidationError } from '../../../kernel/errors.js'\nimport type { Cover, JsonValue, ResolvedCoverSchema } from './types.js'\n\n/**\n * Namespace keys must be reverse-DNS or package-style identifiers —\n * at least one dot/dash-separated segment (`noydb.viewer`,\n * `com.acme.registry` pass; a bare `config` fails), so two frameworks\n * can't collide on a bare word.\n */\nconst CUSTOM_KEY_PATTERN = /^[a-z0-9]+([.-][a-z0-9]+)+$/i\n\n/** Maximum nesting depth of a namespace payload (containers, not leaves). */\nconst MAX_CUSTOM_DEPTH = 8\n\n/**\n * Validate the owner-supplied `custom` input: the field must be a\n * plain object, every key must match {@link CUSTOM_KEY_PATTERN}, and\n * every value must be JSON-serializable (no functions, `undefined`,\n * symbols, bigints, or cycles) within the depth cap. `null` is\n * accepted — it is the delete-this-namespace directive and never\n * persists. Throws `ValidationError` on the first violation.\n */\nexport function validateCustomInput(custom: Record<string, JsonValue>): void {\n if (custom === null || typeof custom !== 'object' || Array.isArray(custom)) {\n throw new ValidationError(\n `setCover: custom must be a { [namespace]: value } object, got ${\n Array.isArray(custom) ? 'array' : typeof custom\n }.`,\n )\n }\n for (const [ns, value] of Object.entries(custom)) {\n if (!CUSTOM_KEY_PATTERN.test(ns)) {\n throw new ValidationError(\n `setCover: custom namespace \"${ns}\" is invalid. Keys must be ` +\n 'reverse-DNS or package-style identifiers with at least one ' +\n 'dot/dash-separated segment (e.g. \"noydb.viewer\", \"com.acme.registry\").',\n )\n }\n assertJsonValue(value, ns, 1, new Set())\n }\n}\n\nfunction assertJsonValue(\n value: unknown,\n ns: string,\n depth: number,\n seen: Set<object>,\n): void {\n if (value === null) return\n const t = typeof value\n if (t === 'string' || t === 'number' || t === 'boolean') return\n if (t !== 'object') {\n throw new ValidationError(\n `setCover: custom[\"${ns}\"] contains a non-JSON value (${t}). ` +\n 'Only strings, numbers, booleans, null, arrays, and plain objects are allowed.',\n )\n }\n const container = value as object\n if (seen.has(container)) {\n throw new ValidationError(\n `setCover: custom[\"${ns}\"] contains a circular reference.`,\n )\n }\n if (depth > MAX_CUSTOM_DEPTH) {\n throw new ValidationError(\n `setCover: custom[\"${ns}\"] nests deeper than the ${MAX_CUSTOM_DEPTH}-level cap.`,\n )\n }\n seen.add(container)\n const children = Array.isArray(container) ? container : Object.values(container)\n for (const child of children) {\n assertJsonValue(child, ns, depth + 1, seen)\n }\n seen.delete(container)\n}\n\n/**\n * Namespace-level patch merge for `setCover`: provided namespaces\n * replace their previous value, absent namespaces are preserved, and\n * an explicit `null` deletes that namespace (so `null` never persists\n * as a namespace value). A whole-`custom`-absent patch preserves the\n * previous custom, consistent with the other cover fields. Rationale:\n * framework A must never need read-modify-write of framework B's data.\n *\n * Returns a spreadable fragment — `{ custom }` when the merge leaves\n * at least one namespace, `{}` when it leaves none (the field is\n * dropped from the persisted document rather than stored empty).\n */\nexport function mergeCustom(\n existing: Record<string, JsonValue> | undefined,\n patch: Record<string, JsonValue> | undefined,\n): { custom: Record<string, JsonValue> } | Record<string, never> {\n if (patch === undefined) {\n return existing !== undefined ? { custom: existing } : {}\n }\n const merged: Record<string, JsonValue> = { ...existing }\n for (const [ns, value] of Object.entries(patch)) {\n if (value === null) {\n delete merged[ns]\n } else {\n merged[ns] = value\n }\n }\n return Object.keys(merged).length > 0 ? { custom: merged } : {}\n}\n\n/**\n * Post-merge size caps — validates the WOULD-BE-PERSISTED document\n * (after the namespace merge), so a small patch can't tip the stored\n * cover over a cap unnoticed. `maxCoverBytes` bounds the entire\n * serialized document, which also closes the unbounded locale-map\n * key-count hole for `name` / `description`. Sizes are measured as\n * `JSON.stringify` length. Throws `ValidationError` on violation.\n */\nexport function validateCoverSize(\n cover: Cover,\n schema: ResolvedCoverSchema,\n): void {\n if (cover.custom !== undefined) {\n const customSize = JSON.stringify(cover.custom).length\n if (customSize > schema.maxCustomBytes) {\n throw new ValidationError(\n `setCover: custom exceeds the ${schema.maxCustomBytes}-byte cap ` +\n `(got ${customSize} bytes serialized, after merging with the stored namespaces).`,\n )\n }\n }\n const totalSize = JSON.stringify(cover).length\n if (totalSize > schema.maxCoverBytes) {\n throw new ValidationError(\n `setCover: the cover document exceeds the ${schema.maxCoverBytes}-byte cap ` +\n `(got ${totalSize} bytes serialized).`,\n )\n }\n}\n","/**\n * Validate-on-write for the cover. Runs at every `setCover` call;\n * the developer's schema decides which fields are allowed and the\n * size caps that apply.\n *\n * @module\n */\nimport { ValidationError } from '../../../kernel/errors.js'\nimport { validateCustomInput } from './custom.js'\nimport type {\n Cover,\n CoverText,\n JsonValue,\n ResolvedCoverSchema,\n CoverField,\n} from './types.js'\n\n/** Owner-supplied input — the subset of {@link Cover} the owner can set. */\nexport interface SetCoverInput {\n readonly name?: CoverText\n readonly description?: CoverText\n readonly icon?: string\n readonly defaultLocale?: string\n /**\n * Namespace-level patch for the cover's `custom` slot (#800):\n * provided namespaces replace their previous value, absent\n * namespaces are preserved, an explicit `null` deletes that\n * namespace. Requires `'custom'` in the schema's `fields` list —\n * the `cover: true` shorthand does NOT enable it.\n */\n readonly custom?: Record<string, JsonValue>\n}\n\nconst DATA_URL_PREFIX = /^data:([a-zA-Z0-9.+-]+\\/[a-zA-Z0-9.+-]+);base64,/\n\n/**\n * Validate an owner-supplied cover input against the developer's\n * resolved schema. Throws `ValidationError` on the first violation;\n * returns void on success.\n *\n * The validator is deliberately strict: every fail mode is a hard\n * error rather than a silent drop, so the owner finds out immediately\n * which field they oversized rather than discovering a truncated\n * label months later.\n */\nexport function validateCoverInput(\n input: SetCoverInput,\n schema: ResolvedCoverSchema,\n): void {\n const allowed = new Set<CoverField>(schema.fields)\n\n // Reject any key not in the schema's allowed-field list.\n for (const key of Object.keys(input)) {\n const known: CoverField | undefined =\n key === 'name' || key === 'description' || key === 'icon' || key === 'defaultLocale' || key === 'custom'\n ? key\n : undefined\n if (!known) {\n throw new ValidationError(\n `setCover: unknown field \"${key}\". ` +\n `Allowed fields: ${[...allowed].join(', ')}.`,\n )\n }\n if (!allowed.has(known)) {\n throw new ValidationError(\n `setCover: field \"${known}\" is not enabled in this vault's schema. ` +\n `Allowed fields: ${[...allowed].join(', ')}.`,\n )\n }\n }\n\n if (input.name !== undefined) {\n validateText(input.name, 'name', schema.maxStringChars)\n }\n if (input.description !== undefined) {\n validateText(input.description, 'description', schema.maxStringChars)\n }\n if (input.icon !== undefined) {\n validateIcon(input.icon, schema)\n }\n if (input.defaultLocale !== undefined && typeof input.defaultLocale !== 'string') {\n throw new ValidationError(\n `setCover: defaultLocale must be a string (BCP-47), got ${typeof input.defaultLocale}.`,\n )\n }\n if (input.custom !== undefined) {\n validateCustomInput(input.custom)\n }\n}\n\nfunction validateText(\n value: CoverText,\n field: string,\n maxChars: number,\n): void {\n if (typeof value === 'string') {\n if (value.length > maxChars) {\n throw new ValidationError(\n `setCover: ${field} exceeds the ${maxChars}-character cap (got ${value.length}).`,\n )\n }\n return\n }\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n throw new ValidationError(\n `setCover: ${field} must be a string or { [locale]: string } map, got ${typeof value}.`,\n )\n }\n // Locale map. Each value must be a non-empty string within the cap.\n for (const [locale, str] of Object.entries(value)) {\n if (typeof str !== 'string') {\n throw new ValidationError(\n `setCover: ${field}[${locale}] must be a string, got ${typeof str}.`,\n )\n }\n if (str.length > maxChars) {\n throw new ValidationError(\n `setCover: ${field}[${locale}] exceeds the ${maxChars}-character cap (got ${str.length}).`,\n )\n }\n }\n}\n\nfunction validateIcon(icon: string, schema: ResolvedCoverSchema): void {\n if (typeof icon !== 'string') {\n throw new ValidationError(\n `setCover: icon must be a data: URL string, got ${typeof icon}.`,\n )\n }\n if (icon.length > schema.maxIconBytes) {\n throw new ValidationError(\n `setCover: icon exceeds the ${schema.maxIconBytes}-byte cap (got ${icon.length}).`,\n )\n }\n const m = DATA_URL_PREFIX.exec(icon)\n if (!m) {\n throw new ValidationError(\n 'setCover: icon must be a base64 data URL ' +\n '(`data:image/png;base64,…` or `data:image/svg+xml;base64,…`). ' +\n 'External URLs are not supported in v1.',\n )\n }\n const mime = m[1]!\n if (!schema.iconMimeTypes.includes(mime)) {\n throw new ValidationError(\n `setCover: icon MIME type \"${mime}\" is not allowed. ` +\n `Permitted types: ${schema.iconMimeTypes.join(', ')}.`,\n )\n }\n}\n\n/**\n * Lightweight runtime predicate — used by the bundle header\n * validator to recognise a cover without requiring it. (The wire\n * discriminator keeps its frozen name: `_noydb_public: 1`.)\n */\nexport function isCover(x: unknown): x is Cover {\n if (x === null || typeof x !== 'object' || Array.isArray(x)) return false\n const obj = x as Record<string, unknown>\n return obj['_noydb_public'] === 1 && typeof obj['version'] === 'number'\n}\n","/**\n * Persistence helpers for `_meta/public-envelope` — the cover's\n * frozen wire location. Mirrors the bypass-AES pattern used by\n * `_meta/handle` and `_meta/policy` — the document is plaintext\n * JSON, the envelope's `_iv` field is left empty.\n *\n * @module\n */\nimport { buildRecordEnvelope } from '../../../kernel/enclave/index.js'\nimport type { NoydbStore } from '../../../kernel/types.js'\nimport type { Cover } from './types.js'\nimport { isCover } from './schema.js'\n\n/**\n * Reserved id for the vault-level cover record. The VALUE is frozen\n * wire format — the record predates the #799 rename and stays at\n * `_meta/public-envelope` so existing vaults need no migration.\n */\nexport const COVER_RECORD_ID = 'public-envelope'\n\n/**\n * Read the cover from `_meta/public-envelope`. Returns `undefined`\n * when no cover has been persisted (fresh vault, or a vault written\n * before the feature was enabled). Tolerates corrupted documents —\n * a JSON parse failure surfaces as `undefined`, not a thrown error,\n * mirroring `_meta/handle`'s contract.\n */\nexport async function loadCover(\n store: NoydbStore,\n vault: string,\n): Promise<Cover | undefined> {\n const envelope = await store.get(vault, '_meta', COVER_RECORD_ID)\n if (!envelope) return undefined\n try {\n const parsed = JSON.parse(envelope._data) as unknown\n if (!isCover(parsed)) return undefined\n return parsed\n } catch {\n return undefined\n }\n}\n\n/** Persist the cover. Idempotent — overwrites any prior write. */\nexport async function saveCover(\n store: NoydbStore,\n vault: string,\n cover: Cover,\n): Promise<void> {\n const wireEnvelope = buildRecordEnvelope(\n { collection: '_meta', id: COVER_RECORD_ID, version: 1 },\n { iv: '', data: JSON.stringify(cover) },\n )\n await store.put(vault, '_meta', COVER_RECORD_ID, wireEnvelope)\n}\n\n/**\n * Public, no-key reader. Plain function, not a method on `Noydb` —\n * the whole point is it works without an authenticated session, so\n * a UI can show \"Acme 2026 Tax Records\" before unlocking.\n *\n * Resolves any `name` / `description` locale map through the supplied\n * `locale` (when provided). Omitting `locale` returns the raw\n * cover, which a multilingual picker can render as it pleases.\n */\nexport async function readCover(\n store: NoydbStore,\n vault: string,\n opts: { readonly locale?: string } = {},\n): Promise<Cover | undefined> {\n const raw = await loadCover(store, vault)\n if (!raw) return undefined\n if (opts.locale === undefined) return raw\n return resolveLocale(raw, opts.locale)\n}\n\n/**\n * Resolve the locale-map fields (`name`, `description`) of a cover\n * to plain strings for the requested locale, falling back through\n * `defaultLocale` and then any available translation.\n *\n * @internal\n */\nexport function resolveLocale(\n cover: Cover,\n locale: string,\n): Cover {\n return {\n ...cover,\n ...(cover.name !== undefined ? { name: pickLocale(cover.name, locale, cover.defaultLocale) } : {}),\n ...(cover.description !== undefined ? { description: pickLocale(cover.description, locale, cover.defaultLocale) } : {}),\n }\n}\n\n/**\n * Resolve a `string | { [locale]: string }` value to a string for a\n * given locale. Exported so the bundle reader can reuse it without\n * duplicating the fallback chain.\n *\n * **Looser than `resolveI18nText`** — the hub's record-field resolver\n * throws `LocaleNotSpecifiedError` when no translation matches, but\n * label semantics deliberately prefer \"show *something*\" over\n * throwing. The fallback chain is:\n * 1. Exact `locale` match.\n * 2. `defaultLocale` (when supplied on the cover).\n * 3. First non-empty value in the map.\n * 4. Empty string (only if every translation is empty — pathological).\n *\n * This deviation is documented in `https://github.com/vLannaAi/noy-db-docs/blob/main/content/docs/services/public-envelope.md`.\n */\nexport function pickLocale(\n value: string | Record<string, string>,\n locale: string,\n defaultLocale: string | undefined,\n): string {\n if (typeof value === 'string') return value\n if (value[locale] !== undefined && value[locale] !== '') return value[locale]\n if (defaultLocale && value[defaultLocale] !== undefined && value[defaultLocale] !== '') {\n return value[defaultLocale]\n }\n for (const v of Object.values(value)) {\n if (v !== '') return v\n }\n return ''\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/with-formula/derivations/strategy-hash.ts","../src/with-formula/derivations/registry.ts"],"sourcesContent":["/**\n * Deterministic hash of a derivation strategy's \"shape\": source\n * collection, declared sibling sources, output keys, derive function\n * source. Used to detect\n * strategy drift: a record whose `_derivedFrom.strategyHash` doesn't\n * match the current strategy is considered stale.\n *\n * Web Crypto SHA-256 — no extra deps.\n */\nimport { sha256Hex } from '../../kernel/enclave/index.js'\n\nexport async function computeStrategyHash(\n source: string,\n outputKeys: readonly string[],\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n derive: (...args: any[]) => any,\n sources?: ReadonlyArray<string>,\n): Promise<string> {\n const canonical = JSON.stringify({\n source,\n outputs: [...outputKeys].sort(),\n derive: derive.toString(),\n // Declared sibling sources — adding/removing a trigger\n // collection invalidates cached derived records. Omitted when empty\n // so strategies without siblings keep their existing hash.\n ...(sources?.length ? { sources: [...sources].sort() } : {}),\n })\n const bytes = new TextEncoder().encode(canonical)\n return sha256Hex(bytes)\n}\n","import { matchTargetFieldNames } from '../../kernel/collection-config.js'\nimport { DerivationCycleError, DuplicateBehaviorNameError, ValidationError } from '../../kernel/errors.js'\nimport { ViaGraph, type FieldRef, type EdgeKind, type Grain } from '../../kernel/via/graph.js'\nimport { schemaFieldKeys } from '../../with-shape/introspection/describe.js'\nimport { computeStrategyHash } from './strategy-hash.js'\nimport { hopCollections, normalizeTriggerBy, type NormalizedTrigger } from './trigger-match.js'\nimport type { DerivationSpec } from './types.js'\n\n/**\n * Whole-record artifact-grain field marker (#638 Task 2). A derivation's\n * `derive()`/a rollup's `compute()` reads the WHOLE source record — there is\n * no single declared field to point at — so a trigger/output collection is\n * modelled as one artifact node per collection (`kernel/via/graph.ts`'s\n * \"Artifact-grain targets... modelled as a field node whose field is the\n * artifact key\" convention). MUST match `materialized-views/registry.ts`'s\n * and `vault.ts`'s overlay-edge marker so cross-registry edges (a derivation\n * feeding into / out of an MV or overlay collection) resolve to the SAME\n * graph node.\n */\nconst WHOLE_RECORD = '*'\n\n/** Strip this registry's `.${WHOLE_RECORD}` artifact suffix off a graph cycle\n * path entry, recovering the bare collection name — preserves the exact\n * pre-#638 `DerivationCycleError` message shape (behavior lock) for a pure\n * record-shape derivation cycle. A rollup's real-field target (not suffixed\n * `.${WHOLE_RECORD}`) is left untouched. */\nfunction stripArtifactSuffix(displayId: string): string {\n const suffix = `.${WHOLE_RECORD}`\n return displayId.endsWith(suffix) ? displayId.slice(0, -suffix.length) : displayId\n}\n\ninterface RegisteredStrategy {\n // Type-erased to allow the registry to hold heterogeneous strategies.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n spec: DerivationSpec<any, any>\n strategyHash: string\n readonly triggers: ReadonlyArray<NormalizedTrigger>\n}\n\n/**\n * Vault-internal registry of derivation strategies. Owned by `Vault`;\n * not exported.\n *\n * @internal\n */\nexport class DerivationRegistry {\n private readonly _bySource = new Map<string, RegisteredStrategy[]>()\n private readonly _byOutput = new Map<string, RegisteredStrategy[]>()\n private readonly _byName = new Map<string, RegisteredStrategy>()\n\n /**\n * Register a derivation strategy. If `spec.name` is given and already\n * registered by another derivation in this vault, throws\n * {@link DuplicateBehaviorNameError} before indexing.\n */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n async register(spec: DerivationSpec<any, any>): Promise<void> {\n if (spec.name !== undefined && this._byName.has(spec.name)) {\n throw new DuplicateBehaviorNameError(spec.name, 'derivation')\n }\n\n const outputKeys = Object.keys(spec.outputs)\n const strategyHash = await computeStrategyHash(spec.source, outputKeys, spec.derive, spec.sources)\n const triggers = normalizeTriggerBy(spec.triggerBy)\n const reg: RegisteredStrategy = { spec, strategyHash, triggers }\n\n if (spec.name !== undefined) this._byName.set(spec.name, reg)\n\n const fromSource = this._bySource.get(spec.source)\n if (fromSource) fromSource.push(reg)\n else this._bySource.set(spec.source, [reg])\n\n // Declared sibling sources index the SAME `reg` under each\n // extra collection so `strategiesForSource(extra)` returns it and a\n // sibling write re-fires the derivation. Sibling keys also enter\n // `_bySource`, so `validate()`'s cycle DFS walks them automatically.\n for (const extra of spec.sources ?? []) {\n const fromExtra = this._bySource.get(extra)\n if (fromExtra) fromExtra.push(reg)\n else this._bySource.set(extra, [reg])\n }\n\n // FK triggers index the SAME `reg` under each parent collection so\n // a parent write re-fires the derivation (fanned out to matching source\n // records in `dispatchDerivations`). Like sources[], these keys enter\n // `_bySource` so the cycle DFS walks the trigger→output edge.\n // #1277 — the INTERMEDIATE of a declared hop is indexed too, so a write\n // that re-points it re-fires the derivation. Without this the hop's whole\n // correctness argument fails: nothing is written to the trigger or source\n // collection when an intermediate moves, so no other path can notice, and\n // every source it used to address is stranded silently. Entering `_bySource`\n // also puts the hop edge into `validate()`'s cycle DFS, which would\n // otherwise be blind to it.\n for (const t of triggers) {\n for (const hop of hopCollections(t.match)) {\n const fromHop = this._bySource.get(hop)\n if (fromHop) { if (!fromHop.includes(reg)) fromHop.push(reg) }\n else this._bySource.set(hop, [reg])\n }\n }\n for (const t of triggers) {\n const fromTrigger = this._bySource.get(t.collection)\n if (fromTrigger) fromTrigger.push(reg)\n else this._bySource.set(t.collection, [reg])\n }\n\n // Rollup: a write to the child `from` collection recomputes\n // the parent (= spec.source = into) at id child[key]. Index under `from`\n // so a child write fires it; spec.source (into) is already indexed above,\n // so a parent write also recomputes its own aggregate (covers the\n // parent-created-after-children case). The from→into edge enters the cycle\n // DFS automatically.\n if (spec.rollup) {\n const fromRollup = this._bySource.get(spec.rollup.from)\n if (fromRollup) fromRollup.push(reg)\n else this._bySource.set(spec.rollup.from, [reg])\n }\n\n for (const key of outputKeys) {\n const output = spec.outputs[key]\n if (!output) continue\n const outputCollection = output.collection\n const arr = this._byOutput.get(outputCollection)\n if (arr) arr.push(reg)\n else this._byOutput.set(outputCollection, [reg])\n }\n }\n\n strategiesForSource(source: string): ReadonlyArray<RegisteredStrategy> {\n return this._bySource.get(source) ?? []\n }\n\n strategiesProducingOutput(collection: string): ReadonlyArray<RegisteredStrategy> {\n return this._byOutput.get(collection) ?? []\n }\n\n /**\n * The #1253-pattern typo guard for match fields (#1249): a misspelt\n * `to`/`from` silently matches nothing forever, so validate against the\n * collection's enumerable field set at the earliest point it exists.\n * `schemaFieldKeys(schema) === undefined` (TS-generic collection,\n * unreadable validator) is DELIBERATELY silent — those fields are real\n * and unenumerable. `configKeys` folds in the collection's other\n * non-schema field declarations (fieldMeta/moneyFields/dictKeyFields/\n * refs/computed); `denormExempt` is derived here from this registry's\n * own strategies rather than taken as a parameter — a field this\n * collection's own derivations write via `denorm` is never a typo.\n */\n validateFieldsFor(\n collectionName: string,\n schema: unknown,\n configKeys: ReadonlyArray<string>,\n viaSources: {\n readonly computed?: Readonly<Record<string, unknown>> | undefined\n readonly viaFields?: Readonly<Record<string, unknown>> | undefined\n } | undefined = undefined,\n ): void {\n const targets = matchTargetFieldNames(viaSources ?? {})\n const virtual = new Set(targets.virtual)\n const shapeKeys = schemaFieldKeys(schema)\n // The two checks have DIFFERENT preconditions, which is why one loop runs\n // both rather than an early return covering both. The typo check needs a\n // readable field list and must stay silent without one — a false \"unknown\n // field\" on a TS-generic collection would be worse than no check. The\n // virtual check needs nothing but the declaration in hand: \"declared, and\n // never stored\" is provable from the declaration alone (#1266).\n if (shapeKeys === undefined && virtual.size === 0) return\n const keys = shapeKeys === undefined ? undefined\n : new Set([...shapeKeys, ...configKeys, ...targets.declared])\n const denormExempt = new Set<string>()\n const regs = new Set([...this._bySource.values()].flat())\n for (const reg of regs) {\n if (reg.spec.source !== collectionName) continue\n for (const out of Object.values(reg.spec.outputs) as Array<{ collection?: string; denorm?: readonly string[] }>) {\n if (out.collection === collectionName) for (const d of out.denorm ?? []) denormExempt.add(d)\n }\n }\n const unknown = (f: string): boolean =>\n keys !== undefined && !keys.has(f) && !denormExempt.has(f)\n for (const reg of regs) {\n const name = reg.spec.name ?? reg.spec.source\n for (const t of reg.triggers) {\n for (const p of t.match) {\n // `to` reads the SOURCE record; `from` reads the WRITTEN record.\n // Both are the stored shape, so both refuse a virtual target.\n if (reg.spec.source === collectionName) {\n if (virtual.has(p.to)) throw new ValidationError(this._virtualMatchMessage(name, collectionName, p.to, 'to'))\n if (unknown(p.to)) {\n throw new ValidationError(\n `derivation \"${name}\": triggerBy match names source field \"${p.to}\", which \"${collectionName}\" does not declare — a typo here silently matches nothing forever`)\n }\n }\n if (t.collection === collectionName && p.from !== 'id') {\n if (virtual.has(p.from)) throw new ValidationError(this._virtualMatchMessage(name, collectionName, p.from, 'from'))\n if (unknown(p.from)) {\n throw new ValidationError(\n `derivation \"${name}\": triggerBy match reads \"${p.from}\" from written \"${collectionName}\" records, which that collection does not declare — a typo here silently matches nothing forever`)\n }\n }\n }\n }\n }\n }\n\n /** #1266 — one message shape for both match sides; see {@link matchTargetFieldNames}. */\n private _virtualMatchMessage(name: string, collectionName: string, field: string, side: 'to' | 'from'): string {\n const where = side === 'to'\n ? `names source field \"${field}\", which \"${collectionName}\"`\n : `reads \"${field}\" from written \"${collectionName}\" records, which that collection`\n return `derivation \"${name}\": triggerBy match ${where} declares as a VIRTUAL computed field — virtual fields are evaluated on read and never stored, so the matcher would read every candidate record and match nothing, forever. Declare it as \\`mode: 'materialized'\\` (stored, indexable) or match on a stored field.`\n }\n\n /**\n * All registered strategies as a flat, deduplicated array.\n * Each strategy is indexed once per source (not once per output key),\n * so iterating `_bySource.values()` naturally yields each strategy\n * exactly once per source — deduplication is handled by flattening\n * the per-source arrays and collecting into a Set by identity.\n *\n * Used by `dumpSchema()` / `describeDerivations()` in the introspection\n * walker to populate the derivations map.\n */\n all(): ReadonlyArray<RegisteredStrategy> {\n const seen = new Set<RegisteredStrategy>()\n for (const strategies of this._bySource.values()) {\n for (const s of strategies) seen.add(s)\n }\n return [...seen]\n }\n\n /**\n * Graph edges for #638 Task 2: one `'derivation'`/`'record'` edge per\n * (non-self-write) output key — target = the output collection (a\n * `WHOLE_RECORD` artifact node), sources = every collection that can\n * trigger this strategy (`source`, `sources[]`, `triggerBy[].collection`,\n * and — for a rollup — `rollup.from`), mirroring EXACTLY the trigger keys\n * `register()` indexes under `_bySource`. The self-write reverse-denorm\n * output (`output.collection === source` with `denorm` declared) is\n * skipped — the SAME condition the old local DFS used; it is not a cycle\n * (see the comment `validate()` used to carry, now on this skip).\n * Rollups ADDITIONALLY get a dedicated `'rollup'`/`'aggregate'` edge\n * targeting the real `rollup.field` on the parent (`source`) — the\n * self-write output above only covers the cycle-DFS skip, not\n * dispatch/taint (Tasks 3/4/6), which need the real field.\n */\n edges(): ReadonlyArray<{ readonly target: FieldRef; readonly sources: readonly FieldRef[]; readonly kind: EdgeKind; readonly grain: Grain }> {\n const out: Array<{ target: FieldRef; sources: FieldRef[]; kind: EdgeKind; grain: Grain }> = []\n for (const reg of this.all()) {\n const spec = reg.spec\n const triggerCollections = [\n spec.source,\n ...(spec.sources ?? []),\n ...(spec.triggerBy ?? []).map((t) => t.collection),\n ...(spec.rollup ? [spec.rollup.from] : []),\n ]\n const sources: FieldRef[] = triggerCollections.map((c) => ({ collection: c, field: WHOLE_RECORD }))\n for (const key of Object.keys(spec.outputs)) {\n const output = spec.outputs[key]\n if (!output) continue\n if (output.shape === 'record' && output.collection === spec.source && output.denorm !== undefined) continue\n out.push({ target: { collection: output.collection, field: WHOLE_RECORD }, sources, kind: 'derivation', grain: 'record' })\n }\n if (spec.rollup) {\n out.push({\n target: { collection: spec.source, field: spec.rollup.field },\n sources: [{ collection: spec.rollup.from, field: WHOLE_RECORD }],\n kind: 'rollup',\n grain: 'aggregate',\n })\n }\n }\n return out\n }\n\n /**\n * Cycle detection, delegated to `ViaGraph.assertAcyclic()` (#638 Task 2 —\n * retires the local DFS). Call after all `register()` calls complete (i.e.\n * at vault open). Throws `DerivationCycleError` on the first cycle found —\n * SAME class/timing as before; the message/path is byte-identical to the\n * pre-#638 shape for a pure record-shape derivation cycle (the\n * `WHOLE_RECORD` artifact suffix is stripped back to a bare collection\n * name before re-throwing).\n *\n * `graph` is the caller's shared per-vault graph, ALREADY carrying this\n * registry's `edges()` (the caller registers them — see `Vault._initDerivations`)\n * — omit it (e.g. this registry's own unit tests) to validate this\n * registry's edges in isolation against a throwaway graph.\n */\n validate(graph?: ViaGraph): void {\n const g = graph ?? new ViaGraph()\n if (!graph) {\n for (const edge of this.edges()) g.registerDerived(edge.target, edge.sources, edge.kind, edge.grain)\n }\n try {\n g.assertAcyclic()\n } catch (e) {\n if (e instanceof DerivationCycleError) throw new DerivationCycleError(e.path.map(stripArtifactSuffix))\n throw e\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/with-shape/introspection/walk.ts"],"sourcesContent":["/**\n * Orchestrate the structural walk of a Vault, producing a\n * {@link VaultSchemaSnapshot}. Called from `Vault.dumpSchema()`.\n *\n * @module\n */\n\nimport { derivePersistedSchema } from '../persisted-schemas/derive.js'\nimport { loadPersistedSchema } from '../persisted-schemas/storage.js'\nimport { fallbackDerivationName } from './derivation-key.js'\nimport { jsonSchemaToFields } from './fields.js'\nimport type {\n CollectionConfig,\n CollectionDescriptor,\n CollectionStats,\n DumpSchemaOptions,\n FieldDescriptor,\n InternalCollectionStats,\n MaterializedViewDescriptor,\n OverlayViewDescriptor,\n DerivationDescriptor,\n VaultSchemaSnapshot,\n} from './types.js'\nimport type { Collection } from '../../kernel/collection.js'\nimport type { NoydbStore } from '../../kernel/types.js'\nimport type { UnlockedKeyring } from '../../with-party/team/keyring.js'\nimport type { RefRegistry } from '../../kernel/refs.js'\nimport type { VaultMeta } from './meta.js'\nimport type { EnclaveKey } from '../../kernel/enclave/index.js'\n\n/**\n * The minimal slice of Vault internal state the walker needs.\n * Exposed via `vault._introspectState()` to keep the public Vault\n * surface narrow.\n *\n * @internal\n */\nexport interface VaultIntrospectState {\n readonly name: string\n readonly adapter: NoydbStore\n readonly collectionCache: Map<string, Collection<unknown>>\n readonly refRegistry: RefRegistry\n readonly getDEK: (collectionName: string) => Promise<EnclaveKey>\n /** The active unlocked keyring — role/permissions/userId for access-scoped ops. */\n readonly keyring: UnlockedKeyring\n readonly subsystems: Record<string, boolean>\n /** Vault-level descriptive metadata, when set via `openVault({meta})`. */\n readonly vaultMeta?: VaultMeta\n // Typed loosely on purpose — these are private service registries\n // accessed only for \"is anything registered\" enumeration.\n readonly mvRegistry: unknown\n readonly overlayRegistry: unknown\n readonly derivationRegistry: unknown\n /**\n * Returns the registered schema-update strategy names for a collection,\n * or `undefined` when none are registered. Populated from\n * `vault.#schemaUpdateNames` in `_introspectState()`.\n */\n readonly getCollectionSchemaUpdateNames?: (col: string) => readonly string[] | undefined\n /**\n * Returns `true` when the collection has an archive policy registered\n * in `vault.archiveRegistry`, `false` otherwise. Populated from\n * `vault.archiveRegistry` in `_introspectState()`.\n */\n readonly hasCollectionArchive?: (col: string) => boolean\n}\n\nconst INTERNAL_PREFIX = '_'\n\n/** Reserved internal collections always present in any real vault. */\nconst KNOWN_INTERNAL_NAMES = ['_keyring', '_ledger', '_meta', '_schemas', '_deltas']\n\nexport async function dumpVaultSchema(\n vault: { _introspectState(): VaultIntrospectState },\n opts: DumpSchemaOptions,\n): Promise<VaultSchemaSnapshot> {\n const state = vault._introspectState()\n const sampleSize = opts.sampleSize ?? 50\n const withStats = opts.withStats === true\n\n // 1. User-facing collections — alphabetical for diff stability\n const cacheNames = [...state.collectionCache.keys()]\n const storageNames = (await safeListAllCollections(state.adapter, state.name))\n .filter((n) => !n.startsWith(INTERNAL_PREFIX))\n const allNames = Array.from(new Set([...cacheNames, ...storageNames])).sort()\n\n const collections: Record<string, CollectionDescriptor> = {}\n for (const name of allNames) {\n collections[name] = await describeCollection(state, name, sampleSize, withStats)\n }\n\n // 2. Materialized views (placeholder — real walk in MV slice 2 follow-up)\n const materializedViews = describeMVs(state.mvRegistry)\n // 3. Overlay views\n const overlayViews = describeOverlays(state.overlayRegistry)\n // 4. Derivations\n const derivations = describeDerivations(state.derivationRegistry)\n\n // 5. Internal collections — only with stats\n let internal: Record<string, InternalCollectionStats> | undefined\n if (withStats) {\n internal = {}\n for (const name of KNOWN_INTERNAL_NAMES) {\n const stats = await statsForCollection(state.adapter, state.name, name)\n if (stats.records > 0) {\n internal[name] = { records: stats.records, bytes: stats.bytes }\n }\n }\n }\n\n const snap: VaultSchemaSnapshot = {\n _noydb_snapshot: 1,\n vault: state.name,\n emittedAt: new Date().toISOString(),\n subsystems: state.subsystems,\n ...(state.vaultMeta !== undefined ? { meta: state.vaultMeta } : {}),\n collections,\n materializedViews,\n overlayViews,\n derivations,\n ...(internal !== undefined ? { internal } : {}),\n }\n return snap\n}\n\nasync function safeListAllCollections(adapter: NoydbStore, vault: string): Promise<string[]> {\n try {\n const snap = await adapter.loadAll(vault)\n return Object.keys(snap)\n } catch {\n return []\n }\n}\n\nasync function describeCollection(\n state: VaultIntrospectState,\n collectionName: string,\n sampleSize: number,\n withStats: boolean,\n): Promise<CollectionDescriptor> {\n let fields: Record<string, FieldDescriptor> = {}\n let validator: CollectionDescriptor['validator']\n\n const refsRaw = state.refRegistry.getOutbound(collectionName)\n const refs: CollectionDescriptor['refs'] = {}\n for (const [name, desc] of Object.entries(refsRaw)) {\n refs[name] = { target: desc.target, mode: desc.mode, ...(desc.isArray ? { isArray: true } : {}) }\n }\n\n // 1. Try the persisted Route B envelope first.\n try {\n const dek = await state.getDEK(collectionName)\n const persisted = await loadPersistedSchema(state.adapter, state.name, collectionName, dek)\n if (persisted) {\n validator = { kind: persisted.kind, source: 'persisted' }\n if (persisted.jsonSchema) {\n fields = jsonSchemaToFields(persisted.jsonSchema, 'persisted', refsRaw)\n }\n }\n } catch {\n // No DEK or decrypt failure — fall through to live-validator\n }\n\n const liveColl = state.collectionCache.get(collectionName)\n\n // 2. Try the live in-process validator (when no persisted envelope).\n if (!validator) {\n const schema = liveColl?.getSchema()\n if (schema) {\n try {\n const derived = await derivePersistedSchema(schema)\n validator = { kind: derived.kind, source: 'live-validator' }\n if (derived.jsonSchema) {\n fields = jsonSchemaToFields(derived.jsonSchema, 'live-validator', refsRaw)\n }\n } catch {\n // Derivation failed (e.g. missing peer-dep) — silently leave fields empty\n }\n }\n }\n\n // 3. Sampling fallback — deferred to a follow-up. For now: empty when no schema.\n if (Object.keys(fields).length === 0 && sampleSize > 0) {\n // Sampling path not implemented in baseline slice 2; reserved for follow-up.\n }\n\n // Populate collection-level meta and config from the live collection when available.\n const collMeta = liveColl?.getMeta()\n const collConfig = liveColl?.getConfig()\n\n // Thread vault-level config (archive + schemaUpdate) that the Collection cannot see.\n const archivePresent = state.hasCollectionArchive?.(collectionName) === true\n const schemaUpdateNames = state.getCollectionSchemaUpdateNames?.(collectionName)\n const hasSchemaUpdate = schemaUpdateNames !== undefined && schemaUpdateNames.length > 0\n\n // Merge Collection-level config with vault-level fields. Omit config entirely\n // when all sources are empty.\n let mergedConfig: CollectionConfig | undefined\n if (collConfig !== undefined || archivePresent || hasSchemaUpdate) {\n mergedConfig = {\n ...(collConfig ?? {}),\n ...(archivePresent ? { archive: true as const } : {}),\n ...(hasSchemaUpdate ? { schemaUpdate: schemaUpdateNames } : {}),\n }\n }\n\n const descriptor: CollectionDescriptor = {\n fields,\n indexes: liveColl?.getDeclaredIndexes() ?? [],\n refs,\n ...(validator ? { validator } : {}),\n ...(collMeta !== undefined ? { meta: collMeta } : {}),\n ...(mergedConfig !== undefined ? { config: mergedConfig } : {}),\n }\n if (withStats) {\n const stats = await statsForCollection(state.adapter, state.name, collectionName)\n ;(descriptor as { stats?: CollectionStats }).stats = stats\n }\n return descriptor\n}\n\nasync function statsForCollection(\n adapter: NoydbStore,\n vault: string,\n collection: string,\n): Promise<CollectionStats> {\n const ids = await adapter.list(vault, collection)\n if (ids.length === 0) {\n return { records: 0, bytes: 0, bytesAvg: 0, bytesMin: 0, bytesMax: 0, oldest: '', newest: '' }\n }\n let total = 0\n let min = Number.POSITIVE_INFINITY\n let max = 0\n let oldest = ''\n let newest = ''\n for (const id of ids) {\n const env = await adapter.get(vault, collection, id)\n if (!env) continue\n const size = env._data.length\n total += size\n if (size < min) min = size\n if (size > max) max = size\n if (env._ts < oldest) oldest = env._ts\n if (env._ts > newest) newest = env._ts\n }\n return {\n records: ids.length,\n bytes: total,\n bytesAvg: Math.round(total / ids.length),\n bytesMin: min === Number.POSITIVE_INFINITY ? 0 : min,\n bytesMax: max,\n oldest: oldest === '' ? '' : oldest,\n newest,\n }\n}\n\nfunction describeMVs(registry: unknown): Record<string, MaterializedViewDescriptor> {\n if (!registry || typeof registry !== 'object') return {}\n const items = listFromRegistry(registry as Record<string, unknown>)\n const out: Record<string, MaterializedViewDescriptor> = {}\n // Each item is RegisteredMV { spec, dependencies, outputCollection, ... }\n for (const item of items) {\n const reg = item as {\n spec?: {\n name?: string\n unionSources?: ReadonlyArray<{ collection: string }>\n groupBy?: string | ReadonlyArray<string>\n aggregate?: Record<string, unknown>\n refresh?: string\n }\n dependencies?: ReadonlySet<string>\n }\n const spec = reg.spec\n if (!spec?.name) continue\n const sources = spec.unionSources\n ? spec.unionSources.map((u) => u.collection)\n : (reg.dependencies ? [...reg.dependencies].sort() : [])\n const groupBy = spec.groupBy\n ? Array.isArray(spec.groupBy) ? [...spec.groupBy] : [spec.groupBy]\n : undefined\n const aggregate = spec.aggregate ? Object.fromEntries(\n Object.entries(spec.aggregate).map(([k, v]) => [k, summariseAggregateOp(v)]),\n ) : undefined\n out[spec.name] = {\n sources,\n ...(groupBy ? { groupBy } : {}),\n ...(aggregate ? { aggregate } : {}),\n refresh: spec.refresh ?? 'eager',\n }\n }\n return out\n}\n\nfunction describeOverlays(registry: unknown): Record<string, OverlayViewDescriptor> {\n if (!registry || typeof registry !== 'object') return {}\n const specs = listFromRegistry(registry as Record<string, unknown>)\n const out: Record<string, OverlayViewDescriptor> = {}\n for (const spec of specs) {\n const s = spec as { name?: string; base?: string; overlay?: string }\n if (!s.name || !s.base || !s.overlay) continue\n out[s.name] = { base: s.base, overlay: s.overlay }\n }\n return out\n}\n\nfunction describeDerivations(registry: unknown): Record<string, DerivationDescriptor> {\n if (!registry || typeof registry !== 'object') return {}\n const items = listFromRegistry(registry as Record<string, unknown>)\n const out: Record<string, DerivationDescriptor> = {}\n const used = new Set<string>()\n // Pre-seed with every explicit name BEFORE keying any derivation, so an\n // unnamed derivation's fallback key never collides with (and clobbers) a\n // named one, regardless of registration order (#973).\n for (const item of items) {\n const reg = item as { spec?: { name?: string }; name?: string }\n const explicitName = (reg.spec ?? reg).name\n if (explicitName !== undefined) used.add(explicitName)\n }\n for (const item of items) {\n // `all()` on DerivationRegistry returns RegisteredStrategy objects:\n // { spec: DerivationSpec, strategyHash }. Read `spec` and fall\n // back to the item itself for forward-compat with other registries.\n const reg = item as { spec?: { name?: string; source?: string; outputs?: Record<string, { collection: string }> }; name?: string; source?: string; outputs?: Record<string, { collection: string }> }\n const s = reg.spec ?? reg\n if (!s.source) continue\n const outputCollections = s.outputs\n ? Object.values(s.outputs).map((o) => (o as { collection: string }).collection)\n : []\n // Named derivations key by their (vault-unique) `name`. Unnamed ones key\n // by the shared collision-safe fallback (sorted output collections, else\n // source, with a `#occurrence` suffix on collision) — the SAME algorithm\n // `listBehaviors` uses (`./derivation-key.ts`) so both surfaces key an\n // unnamed derivation identically.\n const key = s.name ?? fallbackDerivationName(outputCollections, s.source, used)\n if (s.name === undefined) used.add(key)\n out[key] = {\n source: s.source,\n outputs: outputCollections,\n ...(s.name !== undefined ? { name: s.name } : {}),\n }\n }\n return out\n}\n\nfunction listFromRegistry(reg: Record<string, unknown>): readonly unknown[] {\n // Registries expose different accessor methods; try the common ones.\n for (const method of ['all', 'list', 'specs', 'values']) {\n const fn = reg[method]\n if (typeof fn === 'function') {\n try {\n const out = (fn as () => unknown).call(reg)\n if (Array.isArray(out)) return out\n if (out && typeof (out as { values?: () => unknown }).values === 'function') {\n return [...(out as { values: () => Iterable<unknown> }).values()]\n }\n } catch {\n continue\n }\n }\n }\n return []\n}\n\nfunction summariseAggregateOp(value: unknown): string {\n if (value && typeof value === 'object') {\n const op = (value as { op?: string; kind?: string; field?: string }).op\n ?? (value as { kind?: string }).kind\n const field = (value as { field?: string }).field\n if (op && field) return `${op}(${field})`\n if (op) return op\n }\n return String(value)\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/with-audit/attestation/signer.ts"],"sourcesContent":["import type { NoydbStore } from '../../kernel/types.js'\nimport { buildRecordAad, buildRecordEnvelope, encrypt, openEnvelopeJson, type EnclaveKey } from '../../kernel/enclave/index.js'\nimport { ConflictError } from '../../kernel/errors.js'\nimport { generateDocSigningKeyPair } from '@noy-db/attestation'\n\nexport const ATTESTATIONS_COLLECTION = '_attestations'\nexport const SIGNER_RECORD_ID = '_signer'\nexport const REVOKED_RECORD_ID = '_revoked'\n\nexport interface DocSigner {\n readonly keyId: string\n readonly publicKeyB64: string\n readonly privateKeyPkcs8B64: string\n}\n\n/**\n * Pure read: return the firm's persisted document-signing keypair, or `null`\n * if none has been minted yet. Never writes — callers that must NOT mint\n * (e.g. an ungated public-key getter) use this instead of `loadOrCreateSigner`.\n *\n * Stored as an encrypted record `_attestations/_signer` under the\n * `_attestations` collection DEK (resolved via `getDEK`, which is\n * AES-KW-wrapped under the owner KEK + persisted by the keyring). The KEK\n * itself is AES-KW-only and cannot AES-GCM-encrypt these bytes — hence\n * storage under a normal collection DEK.\n */\nexport async function loadSigner(\n store: NoydbStore,\n vault: string,\n getDEK: (collection: string) => Promise<EnclaveKey>,\n): Promise<DocSigner | null> {\n const existing = await store.get(vault, ATTESTATIONS_COLLECTION, SIGNER_RECORD_ID)\n if (!existing) return null\n const dek = await getDEK(ATTESTATIONS_COLLECTION)\n const json = await openEnvelopeJson({ collection: ATTESTATIONS_COLLECTION, id: SIGNER_RECORD_ID }, existing, dek)\n return JSON.parse(json) as DocSigner\n}\n\n/**\n * Lazily mint (or load) the firm's Ed25519 document-signing keypair.\n *\n * On a concurrent first-mint, two callers can both read `null` and both mint\n * distinct keypairs. The `put(…, expectedVersion: 0)` (\"must not already\n * exist\") lets exactly one win; the loser catches `ConflictError`, re-reads,\n * and returns the winner's signer — converging on a single keypair rather than\n * clobbering it or surfacing a raw conflict. (All real stores treat a missing\n * record + `ev: 0` as a no-conflict write, so the catch fires on lost-race only.)\n */\nexport async function loadOrCreateSigner(\n store: NoydbStore,\n vault: string,\n getDEK: (collection: string) => Promise<EnclaveKey>,\n): Promise<DocSigner> {\n const existing = await loadSigner(store, vault, getDEK)\n if (existing) return existing\n\n const dek = await getDEK(ATTESTATIONS_COLLECTION)\n const signer = await generateDocSigningKeyPair()\n const identity = { collection: ATTESTATIONS_COLLECTION, id: SIGNER_RECORD_ID, version: 1 }\n const { iv, data } = await encrypt(JSON.stringify(signer), dek, buildRecordAad(identity))\n const env = buildRecordEnvelope(\n identity,\n { iv, data },\n )\n try {\n await store.put(vault, ATTESTATIONS_COLLECTION, SIGNER_RECORD_ID, env, 0)\n return signer\n } catch (e) {\n if (!(e instanceof ConflictError)) throw e\n // Lost the race — another writer minted first. Adopt the winner.\n const winner = await loadSigner(store, vault, getDEK)\n if (!winner) {\n throw new ConflictError(0, 'loadOrCreateSigner: signer mint lost a concurrent race but the winning record could not be re-read.')\n }\n return winner\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;AAGA,SAAS,iCAAiC;AAEnC,IAAM,0BAA0B;AAChC,IAAM,mBAAmB;AACzB,IAAM,oBAAoB;AAmBjC,eAAsB,WACpB,OACA,OACA,QAC2B;AAC3B,QAAM,WAAW,MAAM,MAAM,IAAI,OAAO,yBAAyB,gBAAgB;AACjF,MAAI,CAAC,SAAU,QAAO;AACtB,QAAM,MAAM,MAAM,OAAO,uBAAuB;AAChD,QAAM,OAAO,MAAM,iBAAiB,EAAE,YAAY,yBAAyB,IAAI,iBAAiB,GAAG,UAAU,GAAG;AAChH,SAAO,KAAK,MAAM,IAAI;AACxB;AAYA,eAAsB,mBACpB,OACA,OACA,QACoB;AACpB,QAAM,WAAW,MAAM,WAAW,OAAO,OAAO,MAAM;AACtD,MAAI,SAAU,QAAO;AAErB,QAAM,MAAM,MAAM,OAAO,uBAAuB;AAChD,QAAM,SAAS,MAAM,0BAA0B;AAC/C,QAAM,WAAW,EAAE,YAAY,yBAAyB,IAAI,kBAAkB,SAAS,EAAE;AACzF,QAAM,EAAE,IAAI,KAAK,IAAI,MAAM,QAAQ,KAAK,UAAU,MAAM,GAAG,KAAK,eAAe,QAAQ,CAAC;AACxF,QAAM,MAAM;AAAA,IACV;AAAA,IACA,EAAE,IAAI,KAAK;AAAA,EACb;AACA,MAAI;AACF,UAAM,MAAM,IAAI,OAAO,yBAAyB,kBAAkB,KAAK,CAAC;AACxE,WAAO;AAAA,EACT,SAAS,GAAG;AACV,QAAI,EAAE,aAAa,eAAgB,OAAM;AAEzC,UAAM,SAAS,MAAM,WAAW,OAAO,OAAO,MAAM;AACpD,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,cAAc,GAAG,qGAAqG;AAAA,IAClI;AACA,WAAO;AAAA,EACT;AACF;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/with-commit/sequence/active.ts","../src/with-commit/sequence/strategy.ts","../src/with-commit/sequence/index.ts"],"sourcesContent":["/**\n * Enable the atomic-sequence capability.\n * Pass to `createNoydb({ sequenceStrategy: withSequence() })` to make\n * `vault.sequence('name').next()` / `.peek()` / `.seedTo()` live. The\n * {@link SequenceStore} CAS engine is statically imported here, so it is pulled\n * into the bundle only when `withSequence()` is referenced (the floor never\n * imports it).\n */\nimport type { SequenceStrategy } from './strategy.js'\nimport { SequenceStore } from './index.js'\n\nexport function withSequence(): SequenceStrategy {\n return {\n createStore(opts) {\n return new SequenceStore(opts)\n },\n }\n}\n","/**\n * Sequence capability strategy — the single on-demand factory the vault routes\n * `vault.sequence()` through to build its atomic-CAS {@link SequenceStore}. The\n * active engine ({@link withSequence}) constructs the real store (kept out of\n * the floor bundle — the store class is reached only via the opt-in\n * `active.ts` chunk); {@link NO_SEQUENCE} throws. The vault always assembles the\n * per-call {@link SequenceStoreOptions} and delegates here, so an un-opted-in\n * caller hits `NO_SEQUENCE`'s throw at `vault.sequence()`.\n *\n * Note: `vault.sequence()` is synchronous, so the factory is a plain (sync)\n * constructor — the engine is tree-shaken by reachability (only `withSequence()`\n * pulls `active.ts`, which statically imports the store), not by a dynamic\n * import. Deferred-numbering series (`withDeferredNumbering`) are a distinct\n * capability and are NOT routed through this strategy.\n * @internal\n */\nimport type { SequenceStore, SequenceStoreOptions } from './index.js'\nimport { SequenceNotEnabledError } from '../../kernel/errors.js'\n\nexport interface SequenceStrategy {\n createStore(opts: SequenceStoreOptions): SequenceStore\n}\n\n/**\n * No-op stub — the floor default. The capability factory throws\n * {@link SequenceNotEnabledError}; opt in with `sequenceStrategy: withSequence()`\n * in createNoydb. @internal\n */\nexport const NO_SEQUENCE: SequenceStrategy = {\n createStore(): SequenceStore {\n throw new SequenceNotEnabledError()\n },\n}\n","/**\n * Atomic sequence primitive — online-coordinated gap-free numbering.\n *\n * `vault.sequence('invoice-2026').next()` returns 1, 2, 3, … with no\n * gaps and no duplicates, even under concurrent callers. Each named\n * sequence is an independent counter record at `_sequences/<name>`,\n * incremented with an optimistic compare-and-swap retry loop — the same\n * proven pattern as the ledger head (`history/ledger/store.ts`).\n *\n * **Explicitly online-only.** Gap-free numbering requires single-authority\n * serialization, which an offline / non-CAS store cannot provide. `next()`\n * throws {@link SequenceOfflineError} unless the backing store advertises\n * `capabilities.casAtomic`. This is a deliberate, honest wall — an offline\n * writer cannot safely allocate a global sequence number.\n *\n * Note on \"gap-free\": the *sequence* is gap-free (each `next()` yields a\n * unique, +1 value). If a caller discards a value without using it, that\n * is a gap in *usage*, not in the sequence — assign each `next()` result\n * to its record in the same operation.\n */\n\nimport { buildRecordAad, buildRecordEnvelope } from '../../kernel/enclave/index.js'\nimport type { NoydbStore, EncryptedEnvelope } from '../../kernel/types.js'\nimport { encrypt, openEnvelopeJson, type EnclaveKey } from '../../kernel/enclave/index.js'\nimport type { ConflictError} from '../../kernel/errors.js';\nimport { isConflictError, SequenceContentionError, SequenceOfflineError, ValidationError } from '../../kernel/errors.js'\n\n// Capability opt-in seam (S4): `vault.sequence()` builds its CAS store through\n// the sequenceStrategy, so it throws SequenceNotEnabledError unless opted in.\nexport { withSequence } from './active.js'\nexport { NO_SEQUENCE, type SequenceStrategy } from './strategy.js'\nexport { SequenceNotEnabledError } from '../../kernel/errors.js'\n\nexport const SEQUENCE_COLLECTION = '_sequences'\n// A sequence is a single hot CAS row — higher contention than a ledger\n// append. A larger budget + jittered backoff absorbs moderate concurrency;\n// a genuine burst beyond this surfaces SequenceContentionError so the\n// caller can retry / queue (the honest online-only contract).\nconst MAX_NEXT_ATTEMPTS = 16\n\ninterface SequenceState {\n value: number\n}\n\n/** Options for `SequenceHandle.next`. Deferred-numbering series use `for`; the CAS counter ignores all of these. */\nexport interface NextOptions {\n /** Deferred mode: the record id to number. Ignored by the CAS counter. */\n readonly for?: string\n /** Deferred mode: reject after this many ms if still unsealed (reserved; not yet enforced in this slice). */\n readonly timeoutMs?: number\n}\n\n/**\n * Partitioning for a CAS sequence. A partitioned sequence is an\n * independent counter scoped to one tuple of values — e.g.\n * `sequence('invoice', { partition: [2026, 'EU'] })` numbers EU-2026 invoices\n * separately from `[2026, 'US']` and from the bare `invoice` series.\n *\n * Partition components are URI-encoded (so `/`, null bytes and other\n * separators in a value can never collide with the structural separators) and\n * `'/'`-joined, then appended to the series with a null-byte (`\\x00`)\n * separator. The null byte is illegal in a plain series name, which guarantees\n * a partitioned key is always disjoint from any unpartitioned series.\n */\nexport interface SequenceOptions {\n /** Partition tuple. Each component is URI-encoded and `'/'`-joined. */\n readonly partition?: readonly (string | number)[]\n /**\n * Render template for the serial string. When set, `vault.sequence`\n * returns a {@link FormattedSequenceHandle} whose `next()` resolves to\n * `{ serial, formatted }`. Tokens:\n * - `{seq}` — the allocated integer\n * - `{seq:0N}` — zero-padded to width N (e.g. `{seq:04}` → `0001`)\n * - `{partition.i}` — the i-th `partition` component (original value)\n *\n * Any other token, or a `{partition.i}` index beyond the supplied\n * `partition`, throws `ValidationError` at `vault.sequence()` construction.\n * Per-partition reset is inherent: a new partition tuple starts at 1.\n */\n readonly format?: string\n}\n\n/**\n * A formatted sequence handle. Identical to {@link SequenceHandle}\n * except `next()` also returns the rendered `formatted` string. `peek()` /\n * `seedTo()` operate on the underlying integer counter, unchanged.\n */\nexport interface FormattedSequenceHandle {\n /** Allocate the next value and return it with its rendered serial string. */\n next(opts?: NextOptions): Promise<{ serial: number; formatted: string }>\n /** Read the current integer value without allocating. Returns 0 if never used. */\n peek(): Promise<number>\n /** Set-if-greater on the underlying integer counter. See {@link SequenceHandle.seedTo}. */\n seedTo(n: number): Promise<void>\n}\n\n// Matches a single `{...}` token with no nested braces.\nconst SEQ_FORMAT_TOKEN = /\\{([^{}]*)\\}/g\nconst SEQ_PAD_TOKEN = /^seq:0(\\d+)$/\nconst SEQ_PARTITION_TOKEN = /^partition\\.(\\d+)$/\n\n/**\n * Validate a sequence `format` against the supplied partition and return a\n * pure `(serial) => string` renderer. Eager validation: every token is\n * checked now, so a bad pattern throws `ValidationError` at construction —\n * never at `next()` time.\n */\nexport function compileSequenceFormat(\n format: string,\n series: string,\n partition: readonly (string | number)[] | undefined,\n): (serial: number) => string {\n const parts = partition ?? []\n for (const m of format.matchAll(SEQ_FORMAT_TOKEN)) {\n const token = m[1] ?? ''\n if (token === 'seq') continue\n if (SEQ_PAD_TOKEN.test(token)) continue\n const partMatch = SEQ_PARTITION_TOKEN.exec(token)\n if (partMatch) {\n const idx = Number(partMatch[1])\n if (idx >= parts.length) {\n throw new ValidationError(\n `sequence(\"${series}\"): format token \"{${token}}\" references partition index ${idx}, ` +\n `but only ${parts.length} partition component(s) were supplied.`,\n )\n }\n continue\n }\n throw new ValidationError(\n `sequence(\"${series}\"): format contains unknown token \"{${token}}\". ` +\n `Accepted tokens: {seq}, {seq:0N}, {partition.i}.`,\n )\n }\n return (serial: number): string =>\n format.replace(SEQ_FORMAT_TOKEN, (full, token: string) => {\n if (token === 'seq') return String(serial)\n const padMatch = SEQ_PAD_TOKEN.exec(token)\n if (padMatch) return String(serial).padStart(Number(padMatch[1]), '0')\n const partMatch = SEQ_PARTITION_TOKEN.exec(token)\n if (partMatch) return String(parts[Number(partMatch[1])])\n return full // unreachable — validated above\n })\n}\n\n/**\n * Resolve the CAS storage key for a (series, partition) pair.\n *\n * With no partition the key is `series` verbatim. With a partition the key is\n * `${series}\\x00${parts}` where `parts` is each component passed through\n * `encodeURIComponent(String(part))` and `'/'`-joined. The null-byte separator\n * is illegal in a plain series name, so partitioned keys never collide with\n * unpartitioned ones; URI-encoding keeps any component containing `/` distinct\n * from a multi-component partition.\n *\n * @throws {ValidationError} if any partition component is empty after `String()`\n * or is a non-finite number (`NaN`, `±Infinity`).\n */\nexport function resolveSequenceKey(series: string, opts?: SequenceOptions): string {\n const partition = opts?.partition\n if (!partition || partition.length === 0) return series\n const parts = partition.map((p) => {\n if (typeof p === 'number' && !Number.isFinite(p)) {\n throw new ValidationError(`sequence partition component must be a finite number, got ${p}`)\n }\n const s = String(p)\n if (s === '') {\n throw new ValidationError('sequence partition component must not be empty')\n }\n return encodeURIComponent(s)\n })\n return `${series}\\x00${parts.join('/')}`\n}\n\nexport interface SequenceHandle {\n /** Atomically allocate and return the next value (1, 2, 3, …). Deferred series resolve at the next pass. */\n next(opts?: NextOptions): Promise<number>\n /** Read the current value without allocating. Returns 0 if never used. */\n peek(): Promise<number>\n /**\n * Set-if-greater: advance the counter to at least `n`. A no-op if the\n * current value is already `>= n` (so it never rewinds), and `seedTo(0)` is\n * a no-op. Idempotent and CAS-safe under concurrent `next()` / `seedTo()`.\n *\n * Use after a bundle / CSV import to fast-forward the counter past the\n * highest imported serial, so subsequent `next()` calls cannot re-use a\n * number that is already on a record.\n *\n * Online-only: throws {@link SequenceOfflineError} on a non-CAS store.\n */\n seedTo(n: number): Promise<void>\n}\n\nasync function sleepBackoff(attempt: number): Promise<void> {\n // Exponential backoff with full jitter to break the thundering herd\n // when many writers contend on the same counter row.\n const ceil = Math.min(2 ** attempt, 32)\n const ms = Math.floor(Math.random() * ceil)\n await new Promise((r) => setTimeout(r, ms))\n}\n\n/** Per-call context the vault assembles to build a {@link SequenceStore}. */\nexport interface SequenceStoreOptions {\n adapter: NoydbStore\n vault: string\n encrypted: boolean\n getDEK: (collectionName: string) => Promise<EnclaveKey>\n actor: string\n}\n\nexport class SequenceStore {\n private readonly adapter: NoydbStore\n private readonly vault: string\n private readonly encrypted: boolean\n private readonly getDEK: (collectionName: string) => Promise<EnclaveKey>\n private readonly actor: string\n /**\n * Memoized DEK promise. The `_sequences` collection DEK is created on\n * first access; without sharing one promise, a burst of concurrent\n * `next()` calls would each trigger DEK creation and diverge (one\n * writer's ciphertext unreadable by another). One shared promise → one\n * DEK.\n */\n private dekPromise: Promise<EnclaveKey> | null = null\n\n constructor(opts: SequenceStoreOptions) {\n this.adapter = opts.adapter\n this.vault = opts.vault\n this.encrypted = opts.encrypted\n this.getDEK = opts.getDEK\n this.actor = opts.actor\n }\n\n /** A handle bound to one sequence name. */\n handle(name: string): SequenceHandle {\n return {\n next: () => this.next(name),\n peek: () => this.peek(name),\n seedTo: (n) => this.seedTo(name, n),\n }\n }\n\n private assertOnline(): void {\n if (this.adapter.capabilities?.casAtomic !== true) {\n throw new SequenceOfflineError()\n }\n }\n\n private dek(): Promise<EnclaveKey> {\n if (!this.dekPromise) this.dekPromise = this.getDEK(SEQUENCE_COLLECTION)\n return this.dekPromise\n }\n\n private async read(name: string): Promise<{ env: EncryptedEnvelope | null; value: number }> {\n const env = await this.adapter.get(this.vault, SEQUENCE_COLLECTION, name)\n if (!env) return { env: null, value: 0 }\n const json = this.encrypted ? await openEnvelopeJson({ collection: SEQUENCE_COLLECTION, id: name }, env, await this.dek()) : env._data\n const state = JSON.parse(json) as SequenceState\n return { env, value: state.value }\n }\n\n private async encryptState(name: string, state: SequenceState, version: number): Promise<EncryptedEnvelope> {\n const json = JSON.stringify(state)\n if (!this.encrypted) {\n return buildRecordEnvelope({ collection: SEQUENCE_COLLECTION, id: name, version }, { iv: '', data: json})\n }\n const identity = { collection: SEQUENCE_COLLECTION, id: name, version }\n const { iv, data } = await encrypt(json, await this.dek(), buildRecordAad(identity))\n return buildRecordEnvelope(identity, { iv, data})\n }\n\n async peek(name: string): Promise<number> {\n return (await this.read(name)).value\n }\n\n async next(name: string): Promise<number> {\n this.assertOnline()\n let lastConflict: ConflictError | undefined\n for (let attempt = 0; attempt < MAX_NEXT_ATTEMPTS; attempt++) {\n const { env, value } = await this.read(name)\n const nextValue = value + 1\n const expectedVersion = env?._v ?? 0 // 0 ≡ \"must not yet exist\" (create)\n const envelope = await this.encryptState(name, { value: nextValue }, expectedVersion + 1)\n try {\n await this.adapter.put(this.vault, SEQUENCE_COLLECTION, name, envelope, expectedVersion)\n return nextValue\n } catch (err) {\n if (isConflictError(err)) {\n lastConflict = err\n if (attempt < MAX_NEXT_ATTEMPTS - 1) await sleepBackoff(attempt)\n continue\n }\n throw err\n }\n }\n void lastConflict\n throw new SequenceContentionError(name, MAX_NEXT_ATTEMPTS)\n }\n\n async seedTo(name: string, n: number): Promise<void> {\n this.assertOnline()\n if (n <= 0) return // set-if-greater: 0 (and any non-positive seed) is a no-op\n let lastConflict: ConflictError | undefined\n for (let attempt = 0; attempt < MAX_NEXT_ATTEMPTS; attempt++) {\n const { env, value } = await this.read(name)\n if (value >= n) return // already at or past the floor — no write, idempotent\n const expectedVersion = env?._v ?? 0 // 0 ≡ \"must not yet exist\" (create)\n const envelope = await this.encryptState(name, { value: n }, expectedVersion + 1)\n try {\n await this.adapter.put(this.vault, SEQUENCE_COLLECTION, name, envelope, expectedVersion)\n return\n } catch (err) {\n if (isConflictError(err)) {\n lastConflict = err\n if (attempt < MAX_NEXT_ATTEMPTS - 1) await sleepBackoff(attempt)\n continue\n }\n throw err\n }\n }\n void lastConflict\n throw new SequenceContentionError(name, MAX_NEXT_ATTEMPTS)\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/with-shape/satellites/existence.ts"],"sourcesContent":["import type { NoydbStore, EncryptedEnvelope } from '../../kernel/types.js'\n\n/**\n * Existence authority (spec § Convergence & existence authority, rule 1): the\n * base row is the sole authority on record existence. `null` (absent) and the\n * tombstone shape (`_iv === '' && _data === ''`, per `buildTombstone()`) both\n * read as \"not live\" — undecrypted, envelope-level checks only.\n */\nfunction isEnvelopeLive(env: EncryptedEnvelope | null): boolean {\n return env !== null && !(env._iv === '' && env._data === '')\n}\n\n/** One undecrypted adapter `get` on the base — the store-shape the spec pins (zero extra crypto). */\nexport async function isBaseLive(adapter: NoydbStore, vault: string, base: string, id: string): Promise<boolean> {\n return isEnvelopeLive(await adapter.get(vault, base, id))\n}\n\n/** The set of base ids that are currently live — used to id-filter satellite `list()` results. */\nexport async function liveBaseIdSet(adapter: NoydbStore, vault: string, base: string): Promise<Set<string>> {\n const ids = await adapter.list(vault, base)\n const out = new Set<string>()\n for (const id of ids) if (await isBaseLive(adapter, vault, base, id)) out.add(id)\n return out\n}\n"],"mappings":";AAQA,SAAS,eAAe,KAAwC;AAC9D,SAAO,QAAQ,QAAQ,EAAE,IAAI,QAAQ,MAAM,IAAI,UAAU;AAC3D;AAGA,eAAsB,WAAW,SAAqB,OAAe,MAAc,IAA8B;AAC/G,SAAO,eAAe,MAAM,QAAQ,IAAI,OAAO,MAAM,EAAE,CAAC;AAC1D;AAGA,eAAsB,cAAc,SAAqB,OAAe,MAAoC;AAC1G,QAAM,MAAM,MAAM,QAAQ,KAAK,OAAO,IAAI;AAC1C,QAAM,MAAM,oBAAI,IAAY;AAC5B,aAAW,MAAM,IAAK,KAAI,MAAM,WAAW,SAAS,OAAO,MAAM,EAAE,EAAG,KAAI,IAAI,EAAE;AAChF,SAAO;AACT;","names":[]}
|