@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
package/dist/chunk-RTBJ5IOO.js
DELETED
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
getAtPath
|
|
3
|
-
} from "./chunk-TRGTKX5E.js";
|
|
4
|
-
import {
|
|
5
|
-
EmbeddingModelMismatchError
|
|
6
|
-
} from "./chunk-7O3Y4PPD.js";
|
|
7
|
-
|
|
8
|
-
// src/with-lookup/embeddings/descriptor.ts
|
|
9
|
-
function embeddingSourceText(record, source) {
|
|
10
|
-
const fields = typeof source === "string" ? [source] : source;
|
|
11
|
-
const parts = [];
|
|
12
|
-
for (const f of fields) {
|
|
13
|
-
for (const leaf of getAtPath(record, f)) {
|
|
14
|
-
if (typeof leaf === "string" && leaf !== "") parts.push(leaf);
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
return parts.join(" ");
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// src/with-lookup/embeddings/vec-id.ts
|
|
21
|
-
function encodeVecId(collection, recordId) {
|
|
22
|
-
if (collection.includes("/")) {
|
|
23
|
-
throw new Error(
|
|
24
|
-
`encodeVecId: collection name "${collection}" must not contain "/" \u2014 it would make the "${collection}/${recordId}" _vec id ambiguous against another collection's rows.`
|
|
25
|
-
);
|
|
26
|
-
}
|
|
27
|
-
return `${collection}/${recordId}`;
|
|
28
|
-
}
|
|
29
|
-
function decodeVecId(collection, vecId) {
|
|
30
|
-
const prefix = `${collection}/`;
|
|
31
|
-
if (!vecId.startsWith(prefix)) return null;
|
|
32
|
-
return vecId.slice(prefix.length);
|
|
33
|
-
}
|
|
34
|
-
function isVecIdFor(collection, vecId) {
|
|
35
|
-
return vecId.startsWith(`${collection}/`);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// src/with-lookup/embeddings/cosine.ts
|
|
39
|
-
function cosine(a, b) {
|
|
40
|
-
if (a.length !== b.length) return 0;
|
|
41
|
-
let dot = 0, na = 0, nb = 0;
|
|
42
|
-
for (let i = 0; i < a.length; i++) {
|
|
43
|
-
const x = a[i], y = b[i];
|
|
44
|
-
dot += x * y;
|
|
45
|
-
na += x * x;
|
|
46
|
-
nb += y * y;
|
|
47
|
-
}
|
|
48
|
-
if (na === 0 || nb === 0) return 0;
|
|
49
|
-
return dot / (Math.sqrt(na) * Math.sqrt(nb));
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// src/with-lookup/embeddings/vector-set.ts
|
|
53
|
-
var VectorSet = class {
|
|
54
|
-
vectors;
|
|
55
|
-
get loaded() {
|
|
56
|
-
return this.vectors !== void 0;
|
|
57
|
-
}
|
|
58
|
-
async ensureLoaded(load) {
|
|
59
|
-
if (this.vectors === void 0) this.vectors = await load();
|
|
60
|
-
}
|
|
61
|
-
markDirty() {
|
|
62
|
-
this.vectors = void 0;
|
|
63
|
-
}
|
|
64
|
-
cosineTopK(query, k, opts = {}) {
|
|
65
|
-
const all = this.vectors ?? [];
|
|
66
|
-
const minScore = opts.minScore ?? -Infinity;
|
|
67
|
-
const hits = [];
|
|
68
|
-
for (const v of all) {
|
|
69
|
-
if (opts.expectModel !== void 0 && v.model !== opts.expectModel) {
|
|
70
|
-
throw new EmbeddingModelMismatchError(opts.expectModel, v.model);
|
|
71
|
-
}
|
|
72
|
-
const score = cosine(query, v.vec);
|
|
73
|
-
if (score >= minScore) hits.push({ id: v.id, score });
|
|
74
|
-
}
|
|
75
|
-
hits.sort((a, b) => b.score - a.score);
|
|
76
|
-
return hits.slice(0, k);
|
|
77
|
-
}
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
export {
|
|
81
|
-
embeddingSourceText,
|
|
82
|
-
VectorSet,
|
|
83
|
-
encodeVecId,
|
|
84
|
-
decodeVecId,
|
|
85
|
-
isVecIdFor
|
|
86
|
-
};
|
|
87
|
-
//# sourceMappingURL=chunk-RTBJ5IOO.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/with-lookup/embeddings/descriptor.ts","../src/with-lookup/embeddings/vec-id.ts","../src/with-lookup/embeddings/cosine.ts","../src/with-lookup/embeddings/vector-set.ts"],"sourcesContent":["/** Per-collection embedding config (L2). The encode hook is host/remote — no bundled model. */\nimport { getAtPath } from '../../via/i18n/core.js'\n\nexport interface EmbeddingDescriptor {\n readonly source: string | readonly string[]\n readonly encode: (text: string) => Promise<Float32Array>\n readonly dim: number\n readonly model: string\n}\n\n/** Concatenate the record's source-field text (skips empties; supports nested/[]-wildcard paths). */\nexport function embeddingSourceText(record: Record<string, unknown>, source: string | readonly string[]): string {\n const fields = typeof source === 'string' ? [source] : source\n const parts: string[] = []\n for (const f of fields) {\n for (const leaf of getAtPath(record, f)) {\n if (typeof leaf === 'string' && leaf !== '') parts.push(leaf)\n }\n }\n return parts.join(' ')\n}\n","/**\n * Collection-namespaced `_vec` side-car ids (#726).\n *\n * `_vec` embedding side-cars used to be keyed by the bare record id,\n * vault-wide — two collections sharing a record id shared one `_vec` row.\n * This was verified to be a clobber/crash bug, NOT a confidentiality leak:\n * every collection has its own DEK, and AES-GCM auth-tag verification means\n * decrypting a foreign collection's `_vec` row under the wrong DEK throws\n * `TamperedError` rather than returning wrong plaintext — no disclosure\n * mechanism exists. The real bug was id collision: a same-id write/forget in\n * one collection could clobber or delete the other collection's row, and a\n * collection whose `similarTo()` / cold semantic `retrieve()` encountered a\n * foreign same-id row crashed with an uncaught `TamperedError` (a DoS). The\n * store-collection bucket stays the literal `'_vec'`; the id becomes\n * composite: `${collection}/${recordId}`. Mirrors `encodeIdxId`\n * (`../indexing/persisted-indexes.js`).\n *\n * Decode is deliberately NOT split-on-`/`: the collection is always known\n * at the decode site (`ctx.name`), so `decodeVecId` strips that known\n * prefix — correct even when `recordId` itself contains `/`.\n *\n * Precondition: `collection` itself must not contain `/` — otherwise\n * `${collection}/${recordId}` is ambiguous (e.g. collection `'a'` would\n * misattribute collection `'a/b'`'s rows via prefix match in `isVecIdFor`).\n * Collection names are NOT currently restricted to a `/`-free charset by\n * `vault.collection()`, so `encodeVecId` enforces the precondition itself,\n * failing loud at the write boundary rather than silently misencoding.\n */\n\n/**\n * Encode the `_vec` side-car id for a (collection, recordId) pair.\n * Format: `<collection>/<recordId>` — no escaping; `recordId` may contain `/`.\n *\n * Throws if `collection` contains `/`: that would make the composite id\n * ambiguous against `isVecIdFor`'s prefix match (collection `'a'` would\n * appear to own collection `'a/b'`'s rows), reintroducing the clobber/crash\n * risk the namespacing fix exists to close.\n */\nexport function encodeVecId(collection: string, recordId: string): string {\n if (collection.includes('/')) {\n throw new Error(\n `encodeVecId: collection name \"${collection}\" must not contain \"/\" — ` +\n `it would make the \"${collection}/${recordId}\" _vec id ambiguous against another collection's rows.`,\n )\n }\n return `${collection}/${recordId}`\n}\n\n/**\n * Decode a `_vec` id back to the bare record id, given the KNOWN owning\n * collection — strips the `<collection>/` prefix rather than splitting on\n * `/`, so a `recordId` containing `/` round-trips correctly. Returns `null`\n * if `vecId` does not belong to `collection`.\n */\nexport function decodeVecId(collection: string, vecId: string): string | null {\n const prefix = `${collection}/`\n if (!vecId.startsWith(prefix)) return null\n return vecId.slice(prefix.length)\n}\n\n/** Predicate form of {@link decodeVecId} — used to filter `list()` results. */\nexport function isVecIdFor(collection: string, vecId: string): boolean {\n return vecId.startsWith(`${collection}/`)\n}\n","/** Cosine similarity in [-1,1]; 0 on zero-norm or length mismatch (no NaN). (L2) */\nexport function cosine(a: Float32Array | number[], b: Float32Array | number[]): number {\n if (a.length !== b.length) return 0\n let dot = 0, na = 0, nb = 0\n for (let i = 0; i < a.length; i++) {\n const x = a[i]!, y = b[i]!\n dot += x * y; na += x * x; nb += y * y\n }\n if (na === 0 || nb === 0) return 0\n return dot / (Math.sqrt(na) * Math.sqrt(nb))\n}\n","/** In-memory vector set for L2 semantic retrieval. Loaded once per session from\n * decrypted _vec sidecars (injected loader), brute-force cosine kNN, model-guarded. */\nimport { cosine } from './cosine.js'\nimport { EmbeddingModelMismatchError } from '../../kernel/errors.js'\n\nexport interface StoredVector { readonly id: string; readonly vec: Float32Array; readonly model: string }\nexport interface VectorHit { readonly id: string; readonly score: number }\n\nexport class VectorSet {\n private vectors: StoredVector[] | undefined\n get loaded(): boolean { return this.vectors !== undefined }\n\n async ensureLoaded(load: () => Promise<StoredVector[]>): Promise<void> {\n if (this.vectors === undefined) this.vectors = await load()\n }\n\n markDirty(): void { this.vectors = undefined }\n\n cosineTopK(query: Float32Array, k: number, opts: { minScore?: number; expectModel?: string } = {}): VectorHit[] {\n const all = this.vectors ?? []\n const minScore = opts.minScore ?? -Infinity\n const hits: VectorHit[] = []\n for (const v of all) {\n if (opts.expectModel !== undefined && v.model !== opts.expectModel) {\n throw new EmbeddingModelMismatchError(opts.expectModel, v.model)\n }\n const score = cosine(query, v.vec)\n if (score >= minScore) hits.push({ id: v.id, score })\n }\n hits.sort((a, b) => b.score - a.score)\n return hits.slice(0, k)\n }\n}\n"],"mappings":";;;;;;;;AAWO,SAAS,oBAAoB,QAAiC,QAA4C;AAC/G,QAAM,SAAS,OAAO,WAAW,WAAW,CAAC,MAAM,IAAI;AACvD,QAAM,QAAkB,CAAC;AACzB,aAAW,KAAK,QAAQ;AACtB,eAAW,QAAQ,UAAU,QAAQ,CAAC,GAAG;AACvC,UAAI,OAAO,SAAS,YAAY,SAAS,GAAI,OAAM,KAAK,IAAI;AAAA,IAC9D;AAAA,EACF;AACA,SAAO,MAAM,KAAK,GAAG;AACvB;;;ACkBO,SAAS,YAAY,YAAoB,UAA0B;AACxE,MAAI,WAAW,SAAS,GAAG,GAAG;AAC5B,UAAM,IAAI;AAAA,MACR,iCAAiC,UAAU,oDACnB,UAAU,IAAI,QAAQ;AAAA,IAChD;AAAA,EACF;AACA,SAAO,GAAG,UAAU,IAAI,QAAQ;AAClC;AAQO,SAAS,YAAY,YAAoB,OAA8B;AAC5E,QAAM,SAAS,GAAG,UAAU;AAC5B,MAAI,CAAC,MAAM,WAAW,MAAM,EAAG,QAAO;AACtC,SAAO,MAAM,MAAM,OAAO,MAAM;AAClC;AAGO,SAAS,WAAW,YAAoB,OAAwB;AACrE,SAAO,MAAM,WAAW,GAAG,UAAU,GAAG;AAC1C;;;AC9DO,SAAS,OAAO,GAA4B,GAAoC;AACrF,MAAI,EAAE,WAAW,EAAE,OAAQ,QAAO;AAClC,MAAI,MAAM,GAAG,KAAK,GAAG,KAAK;AAC1B,WAAS,IAAI,GAAG,IAAI,EAAE,QAAQ,KAAK;AACjC,UAAM,IAAI,EAAE,CAAC,GAAI,IAAI,EAAE,CAAC;AACxB,WAAO,IAAI;AAAG,UAAM,IAAI;AAAG,UAAM,IAAI;AAAA,EACvC;AACA,MAAI,OAAO,KAAK,OAAO,EAAG,QAAO;AACjC,SAAO,OAAO,KAAK,KAAK,EAAE,IAAI,KAAK,KAAK,EAAE;AAC5C;;;ACFO,IAAM,YAAN,MAAgB;AAAA,EACb;AAAA,EACR,IAAI,SAAkB;AAAE,WAAO,KAAK,YAAY;AAAA,EAAU;AAAA,EAE1D,MAAM,aAAa,MAAoD;AACrE,QAAI,KAAK,YAAY,OAAW,MAAK,UAAU,MAAM,KAAK;AAAA,EAC5D;AAAA,EAEA,YAAkB;AAAE,SAAK,UAAU;AAAA,EAAU;AAAA,EAE7C,WAAW,OAAqB,GAAW,OAAoD,CAAC,GAAgB;AAC9G,UAAM,MAAM,KAAK,WAAW,CAAC;AAC7B,UAAM,WAAW,KAAK,YAAY;AAClC,UAAM,OAAoB,CAAC;AAC3B,eAAW,KAAK,KAAK;AACnB,UAAI,KAAK,gBAAgB,UAAa,EAAE,UAAU,KAAK,aAAa;AAClE,cAAM,IAAI,4BAA4B,KAAK,aAAa,EAAE,KAAK;AAAA,MACjE;AACA,YAAM,QAAQ,OAAO,OAAO,EAAE,GAAG;AACjC,UAAI,SAAS,SAAU,MAAK,KAAK,EAAE,IAAI,EAAE,IAAI,MAAM,CAAC;AAAA,IACtD;AACA,SAAK,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;AACrC,WAAO,KAAK,MAAM,GAAG,CAAC;AAAA,EACxB;AACF;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/with-shape/persisted-schemas/storage.ts"],"sourcesContent":["/**\n * Read / write the per-collection persisted-schema envelope. Mirrors the\n * standard noy-db record envelope shape and is **AES-GCM encrypted with\n * the collection's DEK** — the schema body (field names, enum values,\n * constraints) is sensitive metadata, so it gets the same encryption\n * envelope as the records it describes.\n *\n * Storage layout:\n *\n * <vault>/_schemas/<collection> → EncryptedEnvelope\n *\n * The DEK passed to {@link savePersistedSchema} / {@link loadPersistedSchema}\n * is the same key the collection uses for its records.\n *\n * @module\n */\n\nimport { buildRecordAad, buildRecordEnvelope, encrypt, openEnvelopeJson, type EnclaveKey } from '../../kernel/enclave/index.js'\nimport type { NoydbStore } from '../../kernel/types.js'\nimport type { PersistedSchemaEnvelope } from './types.js'\n\n/** Reserved collection name where persisted schemas live. */\nexport const SCHEMAS_COLLECTION = '_schemas' as const\n\n/**\n * A decrypted persisted-schema read paired with the wrapping envelope's\n * `_v`. The version is the optimistic-concurrency token: pass it back to\n * {@link savePersistedSchema} as `expectedVersion` to make the write a CAS\n * that rejects a stale put (see #583 — the `_schemas` record is shared by\n * the JSON-Schema writer and the classified-marker writer).\n */\nexport interface PersistedSchemaEntry {\n /** Wrapping envelope `_v` (0 when no record exists yet). */\n readonly version: number\n /** Decrypted payload, or `undefined` when absent/corrupt/wrong-DEK. */\n readonly payload: PersistedSchemaEnvelope | undefined\n}\n\n/**\n * Read the persisted-schema envelope for one collection together with its\n * wrapping `_v`. The version reflects the raw stored envelope even when the\n * payload cannot be decrypted/parsed (so a CAS still guards a corrupt record\n * rather than silently clobbering it).\n */\nexport async function loadPersistedSchemaEntry(\n store: NoydbStore,\n vault: string,\n collection: string,\n dek: EnclaveKey,\n): Promise<PersistedSchemaEntry> {\n const envelope = await store.get(vault, SCHEMAS_COLLECTION, collection)\n if (!envelope) return { version: 0, payload: undefined }\n const version = envelope._v\n try {\n const plaintext = await openEnvelopeJson({ collection: SCHEMAS_COLLECTION, id: collection }, envelope, dek)\n const parsed = JSON.parse(plaintext) as PersistedSchemaEnvelope\n if (parsed._noydb_schema !== 1) return { version, payload: undefined }\n return { version, payload: parsed }\n } catch {\n return { version, payload: undefined }\n }\n}\n\n/**\n * Read and decrypt the persisted-schema envelope for one collection.\n * Returns `undefined` when no envelope has been written or when decryption\n * fails (e.g. wrong DEK passed). Tolerates corrupted records — JSON parse\n * failures surface as `undefined`, mirroring `_meta/handle`'s contract.\n */\nexport async function loadPersistedSchema(\n store: NoydbStore,\n vault: string,\n collection: string,\n dek: EnclaveKey,\n): Promise<PersistedSchemaEnvelope | undefined> {\n return (await loadPersistedSchemaEntry(store, vault, collection, dek)).payload\n}\n\n/**\n * Encrypt and persist a schema envelope for one collection. Always\n * overwrites any prior write (callers gate on hash equality before calling\n * to avoid no-op writes).\n *\n * Pass `expectedVersion` — the `version` from {@link loadPersistedSchemaEntry}\n * captured at load time — to make the write an optimistic CAS: on a store with\n * `casAtomic`, `store.put` throws {@link ConflictError} when the record was\n * bumped concurrently, so a lost update on the shared `_schemas` record is\n * rejected instead of silently clobbering the other writer's field (#583).\n * When omitted, keeps the legacy unconditional last-writer-wins behaviour.\n */\nexport async function savePersistedSchema(\n store: NoydbStore,\n vault: string,\n collection: string,\n dek: EnclaveKey,\n payload: PersistedSchemaEnvelope,\n expectedVersion?: number,\n): Promise<void> {\n const json = JSON.stringify(payload)\n const baseVersion = expectedVersion ?? (await store.get(vault, SCHEMAS_COLLECTION, collection))?._v ?? 0\n const identity = { collection: SCHEMAS_COLLECTION, id: collection, version: baseVersion + 1 }\n const { iv, data } = await encrypt(json, dek, buildRecordAad(identity))\n const env = buildRecordEnvelope(\n identity,\n { iv, data },\n )\n await store.put(vault, SCHEMAS_COLLECTION, collection, env, expectedVersion)\n}\n"],"mappings":";;;;;;;;;;;;AAsBO,IAAM,qBAAqB;AAsBlC,eAAsB,yBACpB,OACA,OACA,YACA,KAC+B;AAC/B,QAAM,WAAW,MAAM,MAAM,IAAI,OAAO,oBAAoB,UAAU;AACtE,MAAI,CAAC,SAAU,QAAO,EAAE,SAAS,GAAG,SAAS,OAAU;AACvD,QAAM,UAAU,SAAS;AACzB,MAAI;AACF,UAAM,YAAY,MAAM,iBAAiB,EAAE,YAAY,oBAAoB,IAAI,WAAW,GAAG,UAAU,GAAG;AAC1G,UAAM,SAAS,KAAK,MAAM,SAAS;AACnC,QAAI,OAAO,kBAAkB,EAAG,QAAO,EAAE,SAAS,SAAS,OAAU;AACrE,WAAO,EAAE,SAAS,SAAS,OAAO;AAAA,EACpC,QAAQ;AACN,WAAO,EAAE,SAAS,SAAS,OAAU;AAAA,EACvC;AACF;AAQA,eAAsB,oBACpB,OACA,OACA,YACA,KAC8C;AAC9C,UAAQ,MAAM,yBAAyB,OAAO,OAAO,YAAY,GAAG,GAAG;AACzE;AAcA,eAAsB,oBACpB,OACA,OACA,YACA,KACA,SACA,iBACe;AACf,QAAM,OAAO,KAAK,UAAU,OAAO;AACnC,QAAM,cAAc,oBAAoB,MAAM,MAAM,IAAI,OAAO,oBAAoB,UAAU,IAAI,MAAM;AACvG,QAAM,WAAW,EAAE,YAAY,oBAAoB,IAAI,YAAY,SAAS,cAAc,EAAE;AAC5F,QAAM,EAAE,IAAI,KAAK,IAAI,MAAM,QAAQ,MAAM,KAAK,eAAe,QAAQ,CAAC;AACtE,QAAM,MAAM;AAAA,IACV;AAAA,IACA,EAAE,IAAI,KAAK;AAAA,EACb;AACA,QAAM,MAAM,IAAI,OAAO,oBAAoB,YAAY,KAAK,eAAe;AAC7E;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/with-formula/overlay-views/virtual-collection.ts"],"sourcesContent":["import { OverlayIdMismatchError } from '../../kernel/errors.js'\nimport type { Collection } from '../../kernel/collection.js'\nimport type { OverlayedViewSpec } from './types.js'\n\n/**\n * Virtual-collection proxy returned by `vault.collection(overlayName)`\n * when `overlayName` is a registered `withOverlayedView`.\n *\n * Implements the core `Collection<T>`-shaped read/write surface with\n * merge-on-read semantics:\n * - `get(id)`: overlay row wins iff `overlay[shadowField] === shadowValue`;\n * when `spec.mergeMode` is set, an intermediate status may instead pull\n * a declared subset of fields from the overlay over the base\n * - `list()` / `.query()`: union of ids, per-id merge applied\n * - `put(record)` / `put(id, record)`: routes to overlay; id derived\n * via the base MV's `rowKey` (validated on the two-arg form)\n * - `delete(id)`: removes the overlay row only; base stays\n *\n * Reactive APIs (`live`, `subscribe`, `query().live()`) are out of\n * scope for this release and surface as \"not yet implemented\" — wired in a\n * future sub-issue.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport class OverlayedCollection<T extends Record<string, unknown> = any> {\n constructor(\n private readonly spec: OverlayedViewSpec,\n private readonly baseCollection: Collection<T>,\n private readonly overlayCollection: Collection<T>,\n private readonly baseRowKey: ((row: Record<string, unknown>) => string) | undefined,\n ) {}\n\n /**\n * Convenience accessors for advanced callers that need to bypass the\n * virtual layer (bulk imports, direct overlay queries). Mirrors the\n * spec's \"direct writes to the underlying overlay collection skip\n * the validation\" escape hatch.\n */\n readonly overlay = {\n rowKey: (row: Record<string, unknown>): string => {\n if (!this.baseRowKey) {\n throw new Error(\n `Overlay \"${this.spec.name}\": base \"${this.spec.base}\" is not an MV — ` +\n `cannot auto-derive id from the row. Use \\`put(id, record)\\` instead.`,\n )\n }\n return this.baseRowKey(row)\n },\n }\n\n /** Get the merged row by id. */\n async get(id: string): Promise<T | null> {\n const overlayRow = await this.overlayCollection.get(id)\n const baseRow = await this.baseCollection.get(id)\n return this.mergeRows(overlayRow, baseRow)\n }\n\n /** List union of base + overlay ids, applying the merge per row. */\n async list(): Promise<T[]> {\n const baseRows = await this.baseCollection.list()\n const overlayRows = await this.overlayCollection.list()\n const idOf = (row: T): string => {\n // Best-effort: use baseRowKey if available, else assume the row\n // has a `.id` field (common pattern). The spec requires every\n // base MV to declare `rowKey`, so the first branch is the\n // canonical path.\n if (this.baseRowKey) return this.baseRowKey(row as Record<string, unknown>)\n const idField = (row as Record<string, unknown>).id\n return typeof idField === 'string' ? idField : ''\n }\n // Key base + overlay rows by id, then union the id sets and run the\n // same per-id merge `get()` uses. Nulls (overlay-only rows that\n // don't qualify and have no base) are filtered out.\n const baseById = new Map<string, T>()\n const overlayById = new Map<string, T>()\n for (const row of baseRows) {\n const id = idOf(row)\n if (id) baseById.set(id, row)\n }\n for (const row of overlayRows) {\n const id = idOf(row)\n if (id) overlayById.set(id, row)\n }\n const out: T[] = []\n for (const id of new Set([...baseById.keys(), ...overlayById.keys()])) {\n const merged = this.mergeRows(overlayById.get(id) ?? null, baseById.get(id) ?? null)\n if (merged !== null) out.push(merged)\n }\n return out\n }\n\n /**\n * Write to the overlay. Two forms:\n * - `put(record)`: id is derived via the base MV's `rowKey(record)`.\n * Throws if the base isn't an MV.\n * - `put(id, record)`: validates `id === rowKey(record)`; throws\n * `OverlayIdMismatchError` on mismatch.\n */\n async put(idOrRecord: string | T, maybeRecord?: T): Promise<void> {\n let id: string\n let record: T\n if (maybeRecord === undefined) {\n // Single-arg form: put(record). Derive id via base rowKey.\n record = idOrRecord as T\n if (!this.baseRowKey) {\n throw new Error(\n `Overlay \"${this.spec.name}\".put(record): base \"${this.spec.base}\" is not an MV. ` +\n `Use put(id, record) explicitly.`,\n )\n }\n id = this.baseRowKey(record as Record<string, unknown>)\n } else {\n // Two-arg form: put(id, record). Validate against rowKey.\n id = idOrRecord as string\n record = maybeRecord\n if (this.baseRowKey) {\n const expected = this.baseRowKey(record as Record<string, unknown>)\n if (id !== expected) {\n throw new OverlayIdMismatchError(id, expected)\n }\n }\n }\n await this.overlayCollection.put(id, record)\n }\n\n /**\n * Remove the overlay row only. Idempotent (no-op on absent).\n * The base row is untouched — if a base row exists for `id`,\n * subsequent reads return it.\n */\n async delete(id: string): Promise<void> {\n await this.overlayCollection.delete(id)\n }\n\n /**\n * Merge a single id's overlay + base rows into the visible row.\n *\n * Priority (first match wins):\n * 1. Binary shadow win — overlay present AND\n * `overlay[shadowField] === shadowValue` → return the overlay row\n * entirely. This stays FIRST so the original binary behaviour is\n * unchanged whether or not `mergeMode` is configured.\n * 2. Field-level merge — overlay present, `mergeMode` configured,\n * and a rule whose `whenStatus` equals `overlay[shadowField]`.\n * The matched rule pulls its `overlayFields` (those present on\n * the overlay row) on top of the base row. With no base row, the\n * overlay row is returned as-is.\n * 3. Fallback — return the base row (possibly `null`). An\n * overlay-only row that qualifies under neither (1) nor (2) and\n * has no base is therefore NOT surfaced.\n */\n private mergeRows(overlayRow: T | null, baseRow: T | null): T | null {\n const shadowField = this.spec.shadowField\n if (\n overlayRow !== null &&\n (overlayRow as Record<string, unknown>)[shadowField] === this.spec.shadowValue\n ) {\n return overlayRow\n }\n if (overlayRow !== null && this.spec.mergeMode) {\n const status = (overlayRow as Record<string, unknown>)[shadowField]\n const rule = this.spec.mergeMode.rules.find((r) => r.whenStatus === status)\n if (rule) {\n if (baseRow === null) return overlayRow\n const overlaySrc = overlayRow as Record<string, unknown>\n const picked: Record<string, unknown> = {}\n for (const field of rule.overlayFields) {\n if (field in overlaySrc) picked[field] = overlaySrc[field]\n }\n return { ...(baseRow as Record<string, unknown>), ...picked } as T\n }\n }\n return baseRow\n }\n\n // ─── Throw-stubs for the unimplemented Collection<T> surface ───────\n //\n // `Vault.collection(name)` widens the return type to `Collection<T>`\n // for the overlay intercept, but `OverlayedCollection` doesn't\n // implement the full surface. These stubs catch the common\n // reactive / chainable APIs with a clear \"not yet implemented\"\n // error pointing at the relevant issue — so consumers don't hit a\n // cryptic `undefined is not a function` runtime crash.\n //\n // Throw-stubs so consumers get actionable errors rather than cryptic crashes.\n\n /** @throws — chainable Query<T> over a virtual collection is deferred. */\n query(): never {\n throw new Error(\n `OverlayedCollection \"${this.spec.name}\".query() is not yet implemented for overlay views (#154). ` +\n `Use \\`list()\\` + filter for now, or read from the underlying \\`${this.spec.base}\\` / \\`${this.spec.overlay}\\` collections directly. ` +\n `Reactive APIs land in a future MV sub-issue.`,\n )\n }\n\n /** @throws — change-stream subscription over a virtual collection is deferred. */\n subscribe(): never {\n throw new Error(\n `OverlayedCollection \"${this.spec.name}\".subscribe() is not yet implemented for overlay views (#154). ` +\n `Subscribe to the underlying \\`${this.spec.base}\\` / \\`${this.spec.overlay}\\` collections individually for now. ` +\n `Merged change-stream lands in a future MV sub-issue.`,\n )\n }\n\n /** @throws — live query over a virtual collection is deferred. */\n live(): never {\n throw new Error(\n `OverlayedCollection \"${this.spec.name}\".live() is not yet implemented for overlay views (#154). ` +\n `Reactive APIs land in a future MV sub-issue.`,\n )\n }\n\n /** @throws — async iteration over a virtual collection is deferred. */\n scan(): never {\n throw new Error(\n `OverlayedCollection \"${this.spec.name}\".scan() is not yet implemented for overlay views (#154). ` +\n `Use \\`list()\\` for now (no row-count ceiling at niwat scale), or scan the underlying collections directly.`,\n )\n }\n\n /** @throws — lazy-mode query is not applicable to virtual collections. */\n lazyQuery(): never {\n throw new Error(\n `OverlayedCollection \"${this.spec.name}\".lazyQuery() is not supported. ` +\n `Virtual collections always materialize through base + overlay reads — lazy-mode indexed lookups don't apply.`,\n )\n }\n\n /** @throws — bulk-atomic put is deferred to a future MV sub-issue. */\n putManyAtomic(): never {\n throw new Error(\n `OverlayedCollection \"${this.spec.name}\".putManyAtomic() is not yet implemented for overlay views (#154). ` +\n `Use sequential \\`.put(record)\\` calls for now, or write to \\`${this.spec.overlay}\\` directly.`,\n )\n }\n\n /** @throws — bulk delete is deferred to a future MV sub-issue. */\n deleteMany(): never {\n throw new Error(\n `OverlayedCollection \"${this.spec.name}\".deleteMany() is not yet implemented for overlay views (#154). ` +\n `Use sequential \\`.delete(id)\\` calls for now, or operate on \\`${this.spec.overlay}\\` directly.`,\n )\n }\n\n /** @throws — `.first()` over a virtual collection is deferred. */\n first(): never {\n throw new Error(\n `OverlayedCollection \"${this.spec.name}\".first() is not yet implemented for overlay views (#154). ` +\n `Use \\`(await list())[0]\\` for now.`,\n )\n }\n\n /** @throws — `.count()` over a virtual collection is deferred. */\n count(): never {\n throw new Error(\n `OverlayedCollection \"${this.spec.name}\".count() is not yet implemented for overlay views (#154). ` +\n `Use \\`(await list()).length\\` for now.`,\n )\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/with-party/policy/presets.ts","../src/with-party/policy/engine.ts","../src/with-party/policy/noydb-facade.ts"],"sourcesContent":["import type { VaultPolicy } from '../../kernel/types.js'\n\n/**\n * Default policy for personal vaults and SMB deployments — the gates\n * that need an off-device factor get one (TOTP / email-OTP / paper\n * recovery), the rest take a tier-1 unlock alone. Tier-3 (PIN) is the\n * floor only for `rotate-unlock` because that's the\n * \"change my PIN\" flow.\n *\n * The unspecified gates (e.g. `view-user-auth`) inherit the engine\n * default of `{ enabled: false, minTier: 1 }` — they fail closed.\n *\n * @see https://github.com/vLannaAi/noy-db-docs/blob/main/content/docs/services/session-tiers.md → Built-in gates\n */\nexport const PERSONAL_POLICY: VaultPolicy = Object.freeze({\n secret: {\n minWords: 6,\n minWordLength: 3,\n rejectRepeatedAdjacent: true,\n },\n gates: {\n 'rotate-secret': {\n minTier: 1,\n // Any second factor satisfies the gate — off-device kinds (TOTP,\n // email-OTP, paper recovery, roaming WebAuthn) are the strongest;\n // platform-bound kinds (platform WebAuthn, password, PIN) are\n // accepted because requiring \"something off-device\" is overkill\n // for personal/SMB threat models. Consumers needing the off-device\n // guarantee should use STRICT_POLICY or override this gate.\n factors: [{\n anyOf: [\n 'totp', 'email-otp', 'recovery',\n 'webauthn-roaming', 'webauthn-platform',\n 'password', 'pin',\n ],\n }],\n },\n 'recover-secret': {\n minTier: 1,\n enabled: true,\n },\n // rotate-recovery: deliberate paper-sheet regeneration\n // when the user remembers their secret. PERSONAL allows tier-1 —\n // knowing the secret is enough.\n 'rotate-recovery': { minTier: 1 },\n 'enroll-authenticator': { minTier: 1 },\n 'remove-authenticator': { minTier: 1 },\n // update-authenticator: meta-only mutation (slot rename, label\n // changes). Symmetric with enroll/remove under PERSONAL — tier-1\n // unlock alone. The structural anti-slot-swap guard inside the\n // implementation enforces wrap-material/id/method immutability\n // regardless of this gate's settings.\n 'update-authenticator': { minTier: 1 },\n 'rotate-unlock': { minTier: 2 },\n 'enroll-user': { minTier: 1 },\n 'revoke-user': { minTier: 1 },\n // Peer-recovery is a high-trust intentional op — co-owners\n // recovering each other should not need an off-device factor in\n // the personal/SMB threat model (the partner is already vetted by\n // virtue of being a co-owner). Tier-1 unlock is the floor; the\n // STRICT preset adds a recovery/email-OTP requirement.\n 'peer-recover-user': { minTier: 1 },\n // update-user: post-grant identity mutation (role/displayName/\n // permissions). PERSONAL_POLICY treats this on par with enroll-user\n // / revoke-user — tier-1 unlock alone. The role-elevation guard\n // inside the implementation is the structural backstop that this\n // gate's settings cannot weaken.\n 'update-user': { minTier: 1 },\n 'export-bundle': { minTier: 1 },\n 'export-plaintext': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp'] }],\n },\n 'view-user-auth': {\n minTier: 1,\n enabled: false,\n },\n // ─── User envelope gates ──────────────────────────────────────────\n // edit-own-profile: tier 3 floor — any active session can edit their\n // own profile/preferences. Tightening to require a TOTP for\n // profile changes is a one-line override.\n // view-team-profiles: tier 2 floor — an authenticated session can\n // read teammates' profiles (display names, avatars, locales).\n // Setting `enabled: false` makes vault.user.list() return only\n // self (privacy-strict opt-out).\n 'edit-own-profile': { minTier: 3 },\n 'view-team-profiles': { minTier: 2 },\n // client-unilateral-withdraw: a non-owner's self-service DESTRUCTIVE\n // withdrawal (export-and-delete/freeze). Fail-closed by default —\n // the firm opts in per jurisdiction/contract (e.g. GDPR Art. 17).\n // Listed explicitly (not just relying on the built-in default) so it is\n // discoverable in describeGate / policy dumps.\n 'client-unilateral-withdraw': { minTier: 1, enabled: false },\n // Two-party withdrawal: filing a request is non-destructive\n // (tier-1, enabled so a read-only client can ask); deciding it is the\n // destructive step (tier-2 floor + owner/admin role, enforced in code).\n 'user-request-withdrawal': { minTier: 1 },\n 'approve-user-withdrawal': { minTier: 2 },\n },\n}) as VaultPolicy\n\n/**\n * Strict policy for regulated deployments and shared workstations —\n * raises the phrase floor to 8 words, demands two distinct factors for\n * exports, and blocks export-on-shared-device. Use as a base for\n * `policy: { ...STRICT_POLICY, gates: { ...STRICT_POLICY.gates, ... } }`\n * tweaks.\n */\nexport const STRICT_POLICY: VaultPolicy = Object.freeze({\n secret: {\n minWords: 8,\n minWordLength: 3,\n rejectRepeatedAdjacent: true,\n },\n gates: {\n 'rotate-secret': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp', 'recovery'], count: 2 }],\n },\n 'recover-secret': {\n minTier: 1,\n enabled: true,\n },\n // rotate-recovery: STRICT requires an off-device factor —\n // rotating recovery is an off-site-trust event; a stolen unlocked\n // laptop must not be able to silently mint a new sheet for the\n // attacker. Matches the `peer-recover-user` STRICT default.\n 'rotate-recovery': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp', 'webauthn-roaming'] }],\n },\n 'enroll-authenticator': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp'] }],\n },\n 'remove-authenticator': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp'] }],\n },\n // STRICT update-authenticator: same factor floor as enroll/remove.\n // Even though meta changes don't touch wrap material, a malicious\n // rename could mislead the user about which device a slot\n // corresponds to (\"MacBook Touch ID\" → \"iPhone Touch ID\" on a\n // shared workstation). STRICT requires a fresh factor proof.\n 'update-authenticator': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp'] }],\n },\n 'rotate-unlock': { minTier: 1 },\n 'enroll-user': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp'] }],\n },\n 'revoke-user': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp'] }],\n },\n // STRICT peer-recovery: the issuer must present a recovery code\n // OR a fresh off-device second factor at the moment of recovery.\n // This binds the high-trust operation to a verifiable proof\n // (recovery sheet photographed by an attacker won't suffice —\n // they'd also need tier-1 unlock first; this gate is the freshness\n // binding on top). Roaming WebAuthn (YubiKey-class hardware key)\n // accepted; platform-bound kinds (Touch ID, password, PIN)\n // intentionally excluded under STRICT because they don't survive\n // device theft — the off-device requirement is the whole point.\n 'peer-recover-user': {\n minTier: 1,\n factors: [{ anyOf: ['recovery', 'totp', 'email-otp', 'webauthn-roaming'] }],\n },\n // STRICT update-user: matches the enroll-user / revoke-user shape\n // (off-device factor required). Update-user is admin-shaped — it\n // mutates someone else's role/permissions; STRICT requires a fresh\n // off-device factor proof so the operator affirmatively re-asserts\n // identity at the moment of mutation. Platform-bound factors\n // (Touch ID / password / PIN) intentionally excluded: same logic as\n // peer-recover-user — the off-device requirement is the whole\n // point under STRICT.\n 'update-user': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp'] }],\n },\n 'export-bundle': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp'] }],\n warn: { sharedDevice: 'block' },\n },\n 'export-plaintext': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp'], count: 2 }],\n warn: { sharedDevice: 'block' },\n },\n 'view-user-auth': {\n minTier: 1,\n enabled: false,\n },\n // ─── User envelope gates ──────────────────────────────────────────\n // STRICT: profile edits require a TOTP/email-OTP factor (typical\n // shared-workstation hardening — your name/avatar shouldn't change\n // without a fresh second-factor proof).\n 'edit-own-profile': {\n minTier: 2,\n factors: [{ anyOf: ['totp', 'email-otp'] }],\n },\n 'view-team-profiles': { minTier: 2 },\n // STRICT: still fail-closed, but if a regulated firm flips enabled:true\n // they inherit a two-factor proof + shared-device block for the\n // destructive withdrawal (mirrors export-plaintext's hardening).\n 'client-unilateral-withdraw': {\n minTier: 1,\n enabled: false,\n factors: [{ anyOf: ['totp', 'email-otp'], count: 2 }],\n warn: { sharedDevice: 'block' },\n },\n // STRICT: filing stays tier-1; the destructive APPROVE demands an\n // off-device factor + shared-device block (mirrors export-bundle).\n 'user-request-withdrawal': { minTier: 1 },\n 'approve-user-withdrawal': {\n minTier: 2,\n factors: [{ anyOf: ['totp', 'email-otp'] }],\n warn: { sharedDevice: 'block' },\n },\n },\n}) as VaultPolicy\n\n/**\n * Merge a developer override onto a preset. Unspecified gates inherit;\n * specified gates fully replace the preset's entry for that gate.\n *\n * Example:\n *\n * ```ts\n * mergePolicy(PERSONAL_POLICY, {\n * gates: {\n * 'app:approve-large-payment': { minTier: 2, factors: [{ anyOf: ['totp'] }] },\n * },\n * })\n * // → PERSONAL_POLICY plus the new app gate; existing gates intact.\n * ```\n */\nexport function mergePolicy(\n base: VaultPolicy,\n override?: Partial<VaultPolicy>,\n): VaultPolicy {\n if (!override) return base\n const secret = override.secret ?? base.secret\n return {\n ...(secret !== undefined ? { secret } : {}),\n gates: {\n ...base.gates,\n ...(override.gates ?? {}),\n },\n }\n}\n","/**\n * Policy gate engine — the {@link checkGate} entry point.\n *\n * Given a configured {@link VaultPolicy}, an active session tier, and\n * the factor proofs an actor is presenting, decide whether the gate\n * permits the action. On denial, throws {@link PolicyDeniedError} with\n * a stable {@link PolicyDenyReason} so consumers can branch in error\n * UIs.\n *\n * @see https://github.com/vLannaAi/noy-db-docs/blob/main/content/docs/services/session-tiers.md → checkGate() API\n *\n * @module\n */\nimport { PolicyDeniedError, type PolicyDenyReason } from '../../kernel/errors.js'\nimport type {\n ActiveTier,\n FactorProof,\n GateName,\n GatePolicy,\n VaultPolicy,\n FactorRequirement,\n} from '../../kernel/types.js'\n\n/** Default freshness window — 5 minutes. */\nexport const DEFAULT_FRESHNESS_MS = 5 * 60 * 1000\n\n/** Caller-supplied context for one `checkGate` invocation. */\nexport interface CheckGateContext {\n /** Tier the active session currently holds. */\n readonly activeTier: ActiveTier\n /** Proofs the actor is presenting for this gate. */\n readonly factors?: ReadonlyArray<FactorProof>\n /**\n * If the host knows the actor is on a shared device, set this to\n * `true` so the engine can apply `warn.sharedDevice` rules. Defaults\n * to `false`.\n */\n readonly sharedDevice?: boolean\n /**\n * Override `now()` for tests. Defaults to `Date.now()`.\n * @internal\n */\n readonly now?: number\n}\n\n/**\n * Decide whether `gate` permits the action under `context`. Throws\n * {@link PolicyDeniedError} on denial; resolves with `void` on success.\n *\n * Lookup rules:\n * - **Built-in gates** without a configured policy fail closed\n * (`enabled: false`).\n * - **App-defined gates** (`app:*`) without a configured policy are\n * treated as no-op (allow). The developer registered the policy if\n * they wanted enforcement; absence means the gate is informational.\n */\nexport async function checkGate(\n policy: VaultPolicy,\n gate: GateName,\n context: CheckGateContext,\n): Promise<void> {\n const configured = policy.gates[gate]\n if (!configured) {\n if (gate.startsWith('app:')) {\n // Custom app gate without a policy — the developer hasn't\n // registered one; engine treats it as an unenforced label.\n return\n }\n // Built-in gate without a policy — fail closed.\n throw deny(gate, 'disabled', { minTier: 1, enabled: false })\n }\n\n if (configured.enabled === false) {\n throw deny(gate, 'disabled', configured)\n }\n\n // Tier check first — cheap and a hard prerequisite.\n if (context.activeTier > configured.minTier) {\n // Higher number is a LOWER tier in this model (1 is most privileged).\n throw deny(gate, 'insufficient-tier', configured)\n }\n\n // Factor checks — every requirement entry must be satisfied.\n if (configured.factors && configured.factors.length > 0) {\n const presented = context.factors ?? []\n const now = context.now ?? Date.now()\n for (const requirement of configured.factors) {\n const matches = countMatchingFactors(presented, requirement, now)\n const need = requirement.count ?? 1\n if (matches.fresh < need) {\n if (matches.totalKindMatches < need) {\n throw deny(gate, 'missing-factor', configured)\n }\n // Some matched the kind list but not the freshness window.\n throw deny(gate, 'stale-proof', configured)\n }\n }\n }\n\n // Soft signals — only `'block'` raises here.\n if (configured.warn?.sharedDevice === 'block' && context.sharedDevice === true) {\n throw deny(gate, 'shared-device-blocked', configured)\n }\n}\n\n/**\n * Same as {@link checkGate} but returns a structured verdict instead\n * of throwing. Useful when an error UI wants to show the user\n * \"you'll need TOTP plus a recovery code to do that\" without first\n * triggering the action.\n */\nexport async function describeGate(\n policy: VaultPolicy,\n gate: GateName,\n context: CheckGateContext,\n): Promise<{ ok: true } | { ok: false; reason: PolicyDenyReason; required: GatePolicy }> {\n try {\n await checkGate(policy, gate, context)\n return { ok: true }\n } catch (err) {\n if (err instanceof PolicyDeniedError) {\n return { ok: false, reason: err.reason, required: err.required }\n }\n throw err\n }\n}\n\nfunction countMatchingFactors(\n presented: ReadonlyArray<FactorProof>,\n requirement: FactorRequirement,\n now: number,\n): { totalKindMatches: number; fresh: number } {\n const freshnessMs = requirement.freshnessMs ?? DEFAULT_FRESHNESS_MS\n let totalKindMatches = 0\n let fresh = 0\n for (const proof of presented) {\n if (!requirement.anyOf.includes(proof.kind)) continue\n totalKindMatches += 1\n const minted = proof.mintedAt ? Date.parse(proof.mintedAt) : now\n if (Number.isFinite(minted) && now - minted <= freshnessMs) {\n fresh += 1\n }\n }\n return { totalKindMatches, fresh }\n}\n\nfunction deny(gate: GateName, reason: PolicyDenyReason, required: GatePolicy): PolicyDeniedError {\n return new PolicyDeniedError(gate, reason, required)\n}\n","/**\n * Noydb-side policy / session-policy facade.\n *\n * Holds the vault-policy read/update/bootstrap logic (`getPolicy`,\n * `updatePolicy`, `bootstrapPolicy`) and the per-vault session-policy\n * enforcer wiring (`touchPolicy`, `checkPolicyOperation`). The session\n * *timer* and the managed-recovery enrolment check stay kernel-resident on\n * `Noydb` (interleaved with the instance lifecycle) and arrive here as the\n * `resetSessionTimer` / `assertRecoveryEnrolled` callbacks. The policy cache\n * and the enforcer map stay `Noydb`-resident too (touched by\n * `openVault`/`close`) and arrive by reference; behaviour is byte-identical\n * to the inline `Noydb` methods it replaced — every other dependency the\n * moving code touched on `this.*` arrives via {@link NoydbPolicyDeps}.\n *\n * Internal service — reached through `noydb.getPolicy(...)` etc. Public\n * contract ({@link NoydbPolicyApi} / {@link NoydbPolicyDeps} /\n * {@link NoydbPolicyFactory}) lives in the kernel spine; `createNoydb()`\n * wires this file's {@link createNoydbPolicy} in via a pre-resolved dynamic\n * import (the S4 gate recipe).\n */\nimport { ValidationError } from '../../kernel/errors.js'\nimport { PERSONAL_POLICY, mergePolicy } from './presets.js'\nimport { loadVaultPolicy, saveVaultPolicy } from './storage.js'\nimport type { VaultPolicy, ReAuthOperation, NoydbPolicyApi, NoydbPolicyDeps, NoydbPolicyFactory } from '../../kernel/types.js'\n\nexport class NoydbPolicy implements NoydbPolicyApi {\n constructor(private readonly deps: NoydbPolicyDeps) {}\n\n /**\n * Touch the policy enforcer for a vault (records activity, resets\n * idle timer). Also touches the legacy session timer. No-op if no enforcer.\n */\n touchPolicy(vault?: string): void {\n this.deps.resetSessionTimer()\n if (vault) {\n this.deps.policyEnforcers.get(vault)?.touch()\n }\n }\n\n /**\n * Check that a policy-guarded operation is permitted.\n * Throws `SessionPolicyError` if re-auth is required.\n */\n checkPolicyOperation(vault: string, op: ReAuthOperation): void {\n this.deps.policyEnforcers.get(vault)?.checkOperation(op)\n }\n\n /**\n * Read the active policy for a vault. Loads from `_meta/policy` on\n * first call; subsequent calls hit the in-memory cache. Throws\n * `ValidationError` if the vault has not been opened.\n */\n async getPolicy(vault: string): Promise<VaultPolicy> {\n if (this.deps.isClosed()) throw new ValidationError('Instance is closed')\n const cached = this.deps.policyCache.get(vault)\n if (cached) return cached\n await this.bootstrapPolicy(vault)\n return this.deps.policyCache.get(vault) ?? PERSONAL_POLICY\n }\n\n /**\n * Replace the policy document at `_meta/policy` and update the\n * in-memory cache. Gated by the `enroll-user` policy (a policy\n * change is fundamentally a privilege-management action).\n */\n async updatePolicy(vault: string, override: Partial<VaultPolicy>): Promise<VaultPolicy> {\n if (this.deps.isClosed()) throw new ValidationError('Instance is closed')\n const current = await this.getPolicy(vault)\n const merged = mergePolicy(current, override)\n if (this.deps.encrypted) {\n await saveVaultPolicy(this.deps.store, vault, merged)\n }\n this.deps.policyCache.set(vault, merged)\n return merged\n }\n\n /** Read or persist the vault policy at `_meta/policy` on first open. */\n async bootstrapPolicy(\n vault: string,\n opts?: { skipManagedCheck?: boolean },\n ): Promise<void> {\n const onDisk = await loadVaultPolicy(this.deps.store, vault)\n if (onDisk) {\n // Honour the on-disk document; developer overrides cannot\n // weaken what the vault committed to at creation time.\n this.deps.policyCache.set(vault, onDisk)\n await this.deps.assertRecoveryEnrolled(vault, onDisk, opts)\n return\n }\n // First time — persist the developer's policy (or default preset).\n const initial = this.deps.policyOption\n ? mergePolicy(PERSONAL_POLICY, this.deps.policyOption)\n : PERSONAL_POLICY\n await saveVaultPolicy(this.deps.store, vault, initial)\n this.deps.policyCache.set(vault, initial)\n await this.deps.assertRecoveryEnrolled(vault, initial, opts)\n }\n}\n\n/**\n * Factory that builds the `NoydbPolicy` service. `createNoydb()`\n * pre-resolves this via a dynamic import (mirrors\n * `with-party/directory/user-envelope/api.js#createUserApi`) and threads\n * it through `NoydbOptions.policyFactory` so `Noydb`'s constructor can\n * build `this.policyManager` synchronously.\n */\nexport const createNoydbPolicy: NoydbPolicyFactory = (deps) => new NoydbPolicy(deps)\n"],"mappings":"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","names":[]}
|
package/dist/chunk-SZJ3DLZA.js
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
NOYDB_FORMAT_VERSION
|
|
3
|
-
} from "./chunk-7MG7SJT7.js";
|
|
4
|
-
|
|
5
|
-
// src/kernel/enclave/record-envelope.ts
|
|
6
|
-
function buildRecordEnvelope(identity, body) {
|
|
7
|
-
return {
|
|
8
|
-
_noydb: NOYDB_FORMAT_VERSION,
|
|
9
|
-
_v: identity.version,
|
|
10
|
-
_ts: body.ts ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
11
|
-
_iv: body.iv,
|
|
12
|
-
_data: body.data,
|
|
13
|
-
...identity.by !== void 0 ? { _by: identity.by } : {},
|
|
14
|
-
...identity.tier !== void 0 && identity.tier > 0 ? { _tier: identity.tier } : {},
|
|
15
|
-
...body.cek !== void 0 ? { _cek: body.cek } : {},
|
|
16
|
-
...body.provenance !== void 0 ? { _source: body.provenance.source, _sourceTs: body.provenance.sourceTs } : {},
|
|
17
|
-
...body.extra ?? {}
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
async function buildSealedRecordEnvelope(identity, seal, body) {
|
|
21
|
-
const sealed = await seal(identity);
|
|
22
|
-
return buildRecordEnvelope(identity, {
|
|
23
|
-
...body,
|
|
24
|
-
iv: sealed._iv,
|
|
25
|
-
data: sealed._data,
|
|
26
|
-
cek: sealed._cek
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// src/kernel/enclave/record-keys/tombstone.ts
|
|
31
|
-
function isTombstoneShape(envelope) {
|
|
32
|
-
return envelope._data === "" && envelope._cek === void 0 && envelope._del !== true;
|
|
33
|
-
}
|
|
34
|
-
function isTombstone(envelope, encrypted) {
|
|
35
|
-
if (!encrypted) return false;
|
|
36
|
-
return isTombstoneShape(envelope);
|
|
37
|
-
}
|
|
38
|
-
function buildTombstone(ref, version, actor) {
|
|
39
|
-
return buildRecordEnvelope(
|
|
40
|
-
{ ...ref, version, ...actor ? { by: actor } : {} },
|
|
41
|
-
{ iv: "", data: "" }
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
function isDeleteMarker(envelope) {
|
|
45
|
-
return envelope._del === true;
|
|
46
|
-
}
|
|
47
|
-
function buildDeleteMarker(ref, version, actor) {
|
|
48
|
-
return {
|
|
49
|
-
...buildRecordEnvelope(
|
|
50
|
-
{ ...ref, version, ...actor ? { by: actor } : {} },
|
|
51
|
-
{ iv: "", data: "" }
|
|
52
|
-
),
|
|
53
|
-
_del: true
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export {
|
|
58
|
-
buildRecordEnvelope,
|
|
59
|
-
buildSealedRecordEnvelope,
|
|
60
|
-
isTombstoneShape,
|
|
61
|
-
isTombstone,
|
|
62
|
-
buildTombstone,
|
|
63
|
-
isDeleteMarker,
|
|
64
|
-
buildDeleteMarker
|
|
65
|
-
};
|
|
66
|
-
//# sourceMappingURL=chunk-SZJ3DLZA.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/kernel/enclave/record-envelope.ts","../src/kernel/enclave/record-keys/tombstone.ts"],"sourcesContent":["/**\n * The one place an `EncryptedEnvelope` is constructed (#1051).\n *\n * ## Why this exists\n *\n * 49 files built envelopes with an object literal, bypassing\n * `RecordCodec.buildEnvelope` (which had 4 callers). That is **writer\n * fan-out**: N independent places each had to know the envelope contract, and\n * nothing checked that they agreed.\n *\n * It only became load-bearing with #1041. Binding a record's identity into the\n * AEAD requires every writer to supply that identity — and a writer that\n * doesn't produces data the reader rejects. Reader fan-out you fix by threading\n * an argument through call sites; **writer fan-out cannot be migrated\n * incrementally**, because the first migrated writer emits envelopes the\n * unmigrated readers refuse.\n *\n * ## Why adopting it is safe\n *\n * `identity` is **required but not yet used**. Output is byte-identical to the\n * literals it replaces, so every producer can migrate independently and the\n * existing suite verifies each step. The behaviour change happens **once**,\n * when AAD is switched on here — by which point every writer already supplies\n * identity, and the compiler proved it.\n *\n * That ordering is deliberate: a required-but-unused parameter converts \"did\n * we find every writer?\" from a question into a compile error, the same trick\n * that made the `NOYDB_FORMAT_VERSION` single-sourcing safe in #1048.\n *\n * @packageDocumentation\n */\nimport { NOYDB_FORMAT_VERSION } from '../types.js'\nimport type { EncryptedEnvelope } from '../types.js'\nimport type { RecordIdentity } from './record-aad.js'\n\n/** The body an envelope carries, independent of who is writing it. */\nexport interface RecordEnvelopeBody {\n /** AES-GCM IV, base64. Empty string for a plaintext or tombstone envelope. */\n readonly iv: string\n /** Ciphertext (or plaintext JSON when the collection stores plaintext). */\n readonly data: string\n /** ISO timestamp. Defaults to now — pass it when the caller has a real one. */\n readonly ts?: string | undefined\n /** Wrapped per-record CEK, when the record has one. */\n readonly cek?: string | undefined\n readonly provenance?: { readonly source: string; readonly sourceTs: string } | undefined\n /**\n * Slots the envelope may additionally carry.\n *\n * `_tier`, `_by` and `_v` are deliberately NOT here — they come from\n * `identity`, which is the single source for all three. See\n * {@link buildRecordEnvelope}.\n */\n readonly extra?: Partial<Pick<EncryptedEnvelope, '_det' | '_sealed' | '_vdig' | '_bidx'>> | undefined\n}\n\n/**\n * Build an envelope for `identity`.\n *\n * ## `identity` is the SINGLE SOURCE for `_by`, `_tier` and `_v`\n *\n * All three are stamped from it, and `RecordEnvelopeBody` deliberately cannot\n * carry them. That is not tidiness — it is what makes the AAD binding safe.\n *\n * The caller encrypts the body under AAD derived from `{collection, id, tier,\n * by, version}`. A reader recomputes that AAD from the address it fetched from\n * plus `_tier`/`_by`/`_v` read back **off the envelope** (`recordAadFor`). So if the\n * identity a writer *declares* could differ from the fields it *stamps*, the\n * AAD would not reproduce and the record would be undecryptable — silently, at\n * write time, discoverable only on the next read, and invisible to every gate\n * because the envelope is perfectly well-formed.\n *\n * An earlier draft took both and asserted they agreed. The assertion fired 230\n * times on the existing tree, which is the argument against it: a rule that can\n * be violated is a rule someone must remember. Taking one source removes the\n * violation instead of reporting it.\n */\nexport function buildRecordEnvelope(\n identity: RecordIdentity,\n body: RecordEnvelopeBody,\n): EncryptedEnvelope {\n return {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: identity.version,\n _ts: body.ts ?? new Date().toISOString(),\n _iv: body.iv,\n _data: body.data,\n ...(identity.by !== undefined ? { _by: identity.by } : {}),\n ...(identity.tier !== undefined && identity.tier > 0 ? { _tier: identity.tier } : {}),\n ...(body.cek !== undefined ? { _cek: body.cek } : {}),\n ...(body.provenance !== undefined\n ? { _source: body.provenance.source, _sourceTs: body.provenance.sourceTs }\n : {}),\n ...(body.extra ?? {}),\n }\n}\n\n/**\n * Build an envelope from an already-sealed body — the output of\n * `writeEnvelopeBody` — **without the caller ever naming `_iv`/`_data`/`_cek`**.\n *\n * This exists because of a guard, and the guard was right. Migrating\n * `writeEnvelopeBody` callers to {@link buildRecordEnvelope} meant rewriting\n * `...body` (a spread, which names nothing) into `iv: body._iv, data:\n * body._data, cek: body._cek` — and `enclave-body-only` failed it: three new\n * protected-body accesses in files that previously had zero.\n *\n * That is the correct outcome rather than an obstacle. #1051 exists to move\n * knowledge of the envelope's shape *inward*; a migration that spreads the\n * protected field names outward to every caller would have defeated its own\n * purpose while looking like progress. The pairing belongs here.\n *\n * ## It takes a SEALER, not a sealed body — and that is load-bearing (#1041)\n *\n * The obvious shape is `(identity, alreadySealedBody, rest)`. That requires the\n * caller to name the identity TWICE — once for `writeEnvelopeBody` and once\n * here — and the two must agree byte for byte or the record is sealed under\n * AAD no reader can reproduce.\n *\n * They did not agree. `with-party/broker/seed.ts` sealed against\n * `{collection, id}` and stamped `{collection, id, by}`, so every broker seed\n * became unreadable the moment AAD switched on. Taking the sealer means the\n * identity is written once and handed to both — divergence stops being\n * possible rather than being something to remember.\n */\nexport async function buildSealedRecordEnvelope(\n identity: RecordIdentity,\n seal: (identity: RecordIdentity) => Promise<Pick<EncryptedEnvelope, '_iv' | '_data' | '_cek'>>,\n body: Omit<RecordEnvelopeBody, 'iv' | 'data' | 'cek'>,\n): Promise<EncryptedEnvelope> {\n const sealed = await seal(identity)\n return buildRecordEnvelope(identity, {\n ...body,\n iv: sealed._iv,\n data: sealed._data,\n cek: sealed._cek,\n })\n}\n","/**\n * Tombstone shape + predicate for the per-record-key (CEK) layer.\n *\n * A *tombstone* is the residue a GDPR crypto-shred (`vault.forget()`)\n * leaves on disk: the live envelope rewritten to `{ _noydb, _v, _ts, _by,\n * _iv:'', _data:'' }`, dropping `_iv`/`_data`/`_cek`/`_det`. With the wrapped\n * per-record CEK gone, the body — and every history version under the same\n * CEK — is permanently undecryptable, while the record KEY survives so the\n * version counter and \"record existed and was erased\" persist for the audit\n * ledger.\n *\n * These two helpers are the pure, collection-independent core of that\n * contract: {@link buildTombstone} mints the shape, {@link isTombstone}\n * recognises it on the read path. The orchestration that *writes* a tombstone\n * (`_writeTombstone`) and drives `vault.forget()` lives with the collection /\n * vault; it calls into these.\n */\nimport { type EncryptedEnvelope } from '../../types.js'\nimport { buildRecordEnvelope } from '../record-envelope.js'\nimport type { RecordRef } from '../record-aad.js'\n\n/**\n * Shape-only tombstone recognition for layers that have no per-collection\n * context (the sync engine, #590): a tombstone carries an empty `_data` and\n * no wrapped CEK. No live envelope can match — record bodies never serialize\n * to the empty string (the `_sync` meta envelope carries non-empty `_data`,\n * and legacy migration envelopes carry non-empty `_iv`/`_data`).\n */\nexport function isTombstoneShape(envelope: EncryptedEnvelope): boolean {\n return envelope._data === '' && envelope._cek === undefined && envelope._del !== true\n}\n\n/**\n * Is this envelope a crypto-shred tombstone?\n *\n * A tombstone carries no body (`_data` empty) and no wrapped CEK (`_cek`\n * absent) — decrypting it would call `decrypt('', '', dek)` → an AES-GCM\n * throw, so every read choke point must short-circuit to `null` instead.\n *\n * `encrypted` is the collection's encryption flag: on an unencrypted\n * collection there are no envelopes to shred, so nothing is ever a tombstone.\n * (Legacy migration envelopes carry non-empty `_iv`/`_data`, so they are not\n * tombstones and stay readable.)\n */\nexport function isTombstone(envelope: EncryptedEnvelope, encrypted: boolean): boolean {\n if (!encrypted) return false\n return isTombstoneShape(envelope)\n}\n\n/**\n * Mint a tombstone envelope from a record's live version + actor.\n *\n * Keeps `_v` (the displaced version) so the counter is monotonic across the\n * shred, stamps a fresh `_ts`, and records `_by` when an actor is supplied.\n * Deliberately omits `_iv`/`_data`/`_cek`/`_det` — that omission *is* the\n * erasure.\n */\nexport function buildTombstone(\n ref: RecordRef,\n version: number,\n actor: string,\n): EncryptedEnvelope {\n // `actor` rides on the IDENTITY, not the body — it is stamped as `_by` and\n // bound into the AAD from that one source (#1041).\n return buildRecordEnvelope(\n { ...ref, version, ...(actor ? { by: actor } : {}) },\n { iv: '', data: '' },\n )\n}\n\n/** #589: is this envelope an ordinary-delete marker (version-ordered, reads as absent)? */\nexport function isDeleteMarker(envelope: EncryptedEnvelope): boolean {\n return envelope._del === true\n}\n\n/**\n * Mint a delete marker from the deleted record's next version + actor (#589).\n * Minted at the NEXT version (`existing._v + 1`) — unlike `buildTombstone`, which\n * keeps the displaced `_v` — so it wins convergence over the pre-delete copy and a\n * re-create can still win over it at a higher version.\n */\nexport function buildDeleteMarker(\n ref: RecordRef,\n version: number,\n actor: string,\n): EncryptedEnvelope {\n // `_del` is not one of buildRecordEnvelope's declared slots — a delete marker\n // is a distinct envelope class, not a record body — so it is stamped here.\n return {\n ...buildRecordEnvelope(\n { ...ref, version, ...(actor ? { by: actor } : {}) },\n { iv: '', data: '' },\n ),\n _del: true,\n }\n}\n"],"mappings":";;;;;AA6EO,SAAS,oBACd,UACA,MACmB;AACnB,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,IAAI,SAAS;AAAA,IACb,KAAK,KAAK,OAAM,oBAAI,KAAK,GAAE,YAAY;AAAA,IACvC,KAAK,KAAK;AAAA,IACV,OAAO,KAAK;AAAA,IACZ,GAAI,SAAS,OAAO,SAAY,EAAE,KAAK,SAAS,GAAG,IAAI,CAAC;AAAA,IACxD,GAAI,SAAS,SAAS,UAAa,SAAS,OAAO,IAAI,EAAE,OAAO,SAAS,KAAK,IAAI,CAAC;AAAA,IACnF,GAAI,KAAK,QAAQ,SAAY,EAAE,MAAM,KAAK,IAAI,IAAI,CAAC;AAAA,IACnD,GAAI,KAAK,eAAe,SACpB,EAAE,SAAS,KAAK,WAAW,QAAQ,WAAW,KAAK,WAAW,SAAS,IACvE,CAAC;AAAA,IACL,GAAI,KAAK,SAAS,CAAC;AAAA,EACrB;AACF;AA8BA,eAAsB,0BACpB,UACA,MACA,MAC4B;AAC5B,QAAM,SAAS,MAAM,KAAK,QAAQ;AAClC,SAAO,oBAAoB,UAAU;AAAA,IACnC,GAAG;AAAA,IACH,IAAI,OAAO;AAAA,IACX,MAAM,OAAO;AAAA,IACb,KAAK,OAAO;AAAA,EACd,CAAC;AACH;;;AC7GO,SAAS,iBAAiB,UAAsC;AACrE,SAAO,SAAS,UAAU,MAAM,SAAS,SAAS,UAAa,SAAS,SAAS;AACnF;AAcO,SAAS,YAAY,UAA6B,WAA6B;AACpF,MAAI,CAAC,UAAW,QAAO;AACvB,SAAO,iBAAiB,QAAQ;AAClC;AAUO,SAAS,eACd,KACA,SACA,OACmB;AAGnB,SAAO;AAAA,IACL,EAAE,GAAG,KAAK,SAAS,GAAI,QAAQ,EAAE,IAAI,MAAM,IAAI,CAAC,EAAG;AAAA,IACnD,EAAE,IAAI,IAAI,MAAM,GAAG;AAAA,EACrB;AACF;AAGO,SAAS,eAAe,UAAsC;AACnE,SAAO,SAAS,SAAS;AAC3B;AAQO,SAAS,kBACd,KACA,SACA,OACmB;AAGnB,SAAO;AAAA,IACL,GAAG;AAAA,MACD,EAAE,GAAG,KAAK,SAAS,GAAI,QAAQ,EAAE,IAAI,MAAM,IAAI,CAAC,EAAG;AAAA,MACnD,EAAE,IAAI,IAAI,MAAM,GAAG;AAAA,IACrB;AAAA,IACA,MAAM;AAAA,EACR;AACF;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/port/with/i18n-strategy.ts","../src/kernel/paths.ts","../src/via/i18n/policy.ts","../src/via/i18n/script.ts","../src/via/i18n/binding.ts","../src/via/i18n/core.ts"],"sourcesContent":["/**\n * i18n strategy seam (#623 Task 7 — moved out of `via/i18n/strategy.ts`\n * and `via/i18n/dictionary.ts`, precedent: `port/with/lazy-strategy.ts`).\n * Lives on the `/with` port (the one seam the kernel spine may import\n * statically) so `Collection`/`Vault` can hold the `NO_I18N` default and the\n * two reserved-name/brand predicates without a spine→service static import.\n *\n * Core imports `I18nStrategy` type-only + `NO_I18N` stub; real\n * `applyI18nLocale` / `validateI18nTextValue` / `DictionaryHandle` are only\n * reachable via `withI18n()` in `via/i18n/active.ts`.\n *\n * Solo apps that don't use `i18nText()` fields, don't declare `dictKey()`\n * fields, and don't open a `vault.dictionary(...)` handle ship none of the\n * ~854 LOC behind this seam.\n *\n * Behavior under NO_I18N:\n *\n * - **applyI18nLocale** — returns the record unchanged. Apps without\n * any i18n descriptors never observe a difference; apps that\n * *did* declare i18nText/dictKey fields without opting into the\n * strategy still get raw values back (locale resolution silently\n * skipped). The validators below ensure the misconfiguration is\n * caught at write time instead.\n * - **validateI18nTextValue** — throws when called. Only fires when\n * a collection declared `i18nFields`; if you declared the field,\n * you must opt in.\n * - **buildDictionaryHandle** — throws when called. Only fires when\n * user code calls `vault.dictionary(...)`.\n *\n * #650 Task 1 (via-lookup extraction, phase D): the real\n * `buildDictionaryHandle` (in `via/i18n/active.ts`) now delegates to\n * `withLookup().buildLookupHandle` (`via/lookup/active.ts`) — same\n * handle (`LookupHandle`, aliased as `DictionaryHandle`), new home. This\n * interface's shape is unchanged.\n *\n * @internal\n */\n\nimport type { NoydbStore } from '../../kernel/types.js'\nimport type { LedgerStore } from '../../with-commit/history/ledger/store.js'\nimport type { UnlockedKeyring } from '../../with-party/team/keyring.js'\nimport type { NoydbEventEmitter } from '../../kernel/events.js'\nimport type { I18nTextDescriptor } from '../../via/i18n/core.js'\nimport type { Layer } from '../../via/i18n/policy.js'\nimport type { ScriptWarning } from '../../via/i18n/script.js'\nimport type { DictKeyDescriptor, DictionaryHandle, DictionaryOptions, StaticDictDescriptor } from '../../via/i18n/dictionary.js'\nimport type { ViaCryptoCtx } from '../../kernel/via/index.js'\nimport type { EncryptedEnvelope } from '../../kernel/types.js'\n\n/**\n * Options accepted by `I18nStrategy.buildDictionaryHandle`. Mirrors\n * the `DictionaryHandle` constructor verbatim — kept here so core\n * code never imports the dictionary module at runtime.\n *\n * @internal\n */\nexport interface BuildDictionaryHandleOptions<Keys extends string = string> {\n adapter: NoydbStore\n compartmentName: string\n dictionaryName: string\n keyring: UnlockedKeyring\n /**\n * The `reservedEnvelopes('_dict_')` capability (#629 Task 4) — DictionaryHandle's\n * sanctioned crypto door onto its `_dict_<name>` collection. Bound by the\n * Vault to its own `getDEK`, the same per-collection-name DEK resolver\n * every other collection uses.\n */\n reservedEnvelopes: ReturnType<ViaCryptoCtx['reservedEnvelopes']>\n encrypted: boolean\n ledger: LedgerStore | undefined\n options: DictionaryOptions\n findAndUpdateReferences:\n | ((\n dictionaryName: string,\n oldKey: string,\n newKey: string,\n ) => Promise<void>)\n | undefined\n emitter: NoydbEventEmitter\n /**\n * Used by the active strategy to satisfy the generic-key parameter\n * on the returned handle. The NO_I18N stub never reads it.\n */\n // marker generic — runtime sees no value\n _keyMarker?: Keys\n /** #650 Task 4 (#647) — choke-point participation hooks, passed through to `buildLookupHandle`. */\n onDirty?: ((collection: string, id: string, action: 'put' | 'delete', version: number) => Promise<void>) | undefined\n onRecordMutated?: ((collection: string, id: string, action: 'put' | 'delete', version: number) => Promise<void>) | undefined\n /**\n * #647 fix wave 1 — mints a version-ordered delete-marker envelope, passed through to\n * `buildLookupHandle`. See `port/with/lookup-strategy.ts`'s `BuildLookupHandleOptions` doc\n * comment for why this is injected rather than imported by the handle itself.\n */\n buildDeleteMarker: (identity: { collection: string; id: string }, version: number, actor: string) => EncryptedEnvelope\n /** #650 Task 5 (#648) — the real reference check, passed through to `buildLookupHandle`. */\n checkReferencesOnDelete?: ((key: string) => Promise<unknown>) | undefined\n}\n\n/**\n * @internal\n */\nexport interface I18nStrategy {\n /**\n * Resolve `i18nText` fields on a record to the requested locale and\n * return a new object. Returns the input unchanged under\n * `NO_I18N`.\n */\n applyI18nLocale(\n record: Record<string, unknown>,\n fields: Record<string, I18nTextDescriptor>,\n locale: string,\n fallback?: string | readonly string[],\n layer?: Layer,\n ): Record<string, unknown>\n\n /**\n * Validate that an i18nText field's value satisfies its descriptor\n * (required locales present, etc.). Throws under `NO_I18N` —\n * declaring i18nFields without opting in is a misconfiguration.\n */\n validateI18nTextValue(\n value: unknown,\n field: string,\n descriptor: I18nTextDescriptor,\n ): void\n\n /**\n * Enforce per-locale script constraints over an i18nText value map\n * (write-time). Returns the (possibly filtered) value plus any\n * non-fatal warnings. Returns the value unchanged when the field has\n * no `script` option, or under `NO_I18N`.\n */\n enforceScript(\n value: Record<string, unknown>,\n field: string,\n descriptor: I18nTextDescriptor,\n exempt?: ReadonlySet<string>,\n ): { value: Record<string, unknown>; warnings: ScriptWarning[] }\n\n /**\n * Per-field locales that are unchanged round-tripped densify fills (exempt\n * from write-time script enforcement). Empty under NO_I18N.\n */\n computeExemptFills(\n prior: Record<string, unknown> | undefined,\n incoming: Record<string, unknown>,\n fields: Record<string, I18nTextDescriptor>,\n ): Map<string, Set<string>>\n\n /**\n * Eager-fill empty i18n slots from each field's substitute chain and record\n * provenance in `record['_i18nFilled']`. Mutates `record`. No-op under\n * NO_I18N.\n */\n densify(\n record: Record<string, unknown>,\n prior: Record<string, unknown> | undefined,\n fields: Record<string, I18nTextDescriptor>,\n ): void\n\n /**\n * Construct a typed `DictionaryHandle` for the named dictionary.\n * Throws under `NO_I18N`.\n */\n buildDictionaryHandle<Keys extends string = string>(\n opts: BuildDictionaryHandleOptions<Keys>,\n ): DictionaryHandle<Keys>\n}\n\nfunction notEnabled(op: string): Error {\n return new Error(\n `${op} requires the i18n strategy. Import ` +\n '`{ withI18n }` from \"@noy-db/hub/i18n\" and pass it to ' +\n '`createNoydb({ i18nStrategy: withI18n() })`.',\n )\n}\n\n/**\n * No-i18n stub. Locale resolution is the identity; validation and\n * dictionary construction throw with an actionable pointer.\n *\n * @internal\n */\nexport const NO_I18N: I18nStrategy = {\n applyI18nLocale(record) { return record },\n validateI18nTextValue() { throw notEnabled('i18nText field validation') },\n enforceScript(value) { return { value, warnings: [] } },\n computeExemptFills() { return new Map<string, Set<string>>() },\n densify() {},\n buildDictionaryHandle() { throw notEnabled('vault.dictionary()') },\n}\n\n/**\n * Return true when a collection name is a reserved dictionary collection\n * (the `_dict_*` prefix). Mirrors `DICT_COLLECTION_PREFIX` — now on\n * `via/lookup/handle.ts` (#650 Task 1), re-exported from\n * `via/i18n/dictionary.ts` for compat — duplicated here (not\n * imported) so this port has no VALUE dependency back on the feature; keep\n * the two in sync if the prefix ever changes.\n */\nexport function isDictCollectionName(name: string): boolean {\n return name.startsWith('_dict_')\n}\n\n/** Runtime predicate for detecting a StaticDictDescriptor. */\nexport function isStaticDictDescriptor(x: unknown): x is StaticDictDescriptor {\n return (\n typeof x === 'object' &&\n x !== null &&\n (x as { _noydbStaticDict?: unknown })._noydbStaticDict === true\n )\n}\n\n/**\n * Runtime predicate for detecting an I18nTextDescriptor. Pure tag check —\n * moved here (#623 Task 11) alongside `isStaticDictDescriptor` so\n * `kernel/via/compose.ts` (`mergeViaFields`'s descriptor-shape classification)\n * can reach it through the port instead of importing `via/i18n/core.js`\n * directly. Re-exported from that module for compat with existing importers.\n */\nexport function isI18nTextDescriptor(x: unknown): x is I18nTextDescriptor {\n return (\n typeof x === 'object' &&\n x !== null &&\n (x as { _noydbI18nText?: unknown })._noydbI18nText === true\n )\n}\n\n/**\n * Runtime predicate for detecting a DictKeyDescriptor. Pure tag check —\n * moved here (#623 Task 11) for the same reason as `isI18nTextDescriptor`\n * above. Re-exported from `via/i18n/dictionary.js` for compat with\n * existing importers.\n */\nexport function isDictKeyDescriptor(x: unknown): x is DictKeyDescriptor {\n return (\n typeof x === 'object' &&\n x !== null &&\n (x as { _noydbDictKey?: unknown })._noydbDictKey === true\n )\n}\n\n/**\n * Type-only re-exports (#623 Task 8) — the kernel spine (collection.ts,\n * collection-config.ts, vault.ts, types.ts) imports these descriptor/handle\n * types through the port instead of reaching into `via/i18n/*`\n * directly, so `src/kernel/**` carries no via-i18n specifier at all.\n * `isolatedModules: true` erases these at build time — no runtime coupling.\n */\nexport type { I18nTextDescriptor } from '../../via/i18n/core.js'\nexport type { DictKeyDescriptor, DictionaryHandle, DictionaryOptions, StaticDictDescriptor } from '../../via/i18n/dictionary.js'\nexport type { Layer } from '../../via/i18n/policy.js'\nexport type { ScriptWarning } from '../../via/i18n/script.js'\n","/**\n * Generic dotted-path / `[]`-wildcard record helpers. Kernel-owned:\n * these carry zero i18n logic — they were extracted out of\n * `via/i18n/core.ts` (Task 7, #623) so kernel call-sites (put-time\n * validation, densify) can import them without a spine→service edge.\n *\n * @internal\n */\n\n/**\n * Return all leaf values at `path`, expanding `[].` array wildcards.\n *\n * - `'name'` → `[obj.name]`\n * - `'address.lineOne'` → `[obj.address.lineOne]`\n * - `'contacts[].title'` → `[obj.contacts[0].title, obj.contacts[1].title, …]`\n *\n * Returns an empty array when the path does not resolve (missing key,\n * wrong type, etc.). Used by `enforceI18nOnPut` to validate nested fields.\n */\nexport function getAtPath(obj: Record<string, unknown>, path: string): unknown[] {\n const arrayIdx = path.indexOf('[].')\n if (arrayIdx !== -1) {\n const arrayKey = path.slice(0, arrayIdx)\n const restPath = path.slice(arrayIdx + 3)\n const arr = obj[arrayKey]\n if (!Array.isArray(arr)) return []\n return arr.flatMap(item => {\n if (!item || typeof item !== 'object' || Array.isArray(item)) return []\n return getAtPath(item as Record<string, unknown>, restPath)\n })\n }\n const dotIdx = path.indexOf('.')\n if (dotIdx !== -1) {\n const head = path.slice(0, dotIdx)\n const rest = path.slice(dotIdx + 1)\n const nested = obj[head]\n if (!nested || typeof nested !== 'object' || Array.isArray(nested)) return []\n return getAtPath(nested as Record<string, unknown>, rest)\n }\n const val = obj[path]\n return val !== undefined ? [val] : []\n}\n\n/**\n * Mutate `obj` in-place, setting `value` at the nested `path`.\n * Supports dot notation (`'address.lineOne'`) but not array wildcards —\n * auto-translate on `contacts[].title` style paths is not supported.\n */\nexport function setAtPathInPlace(\n obj: Record<string, unknown>,\n path: string,\n value: unknown,\n): void {\n const dotIdx = path.indexOf('.')\n if (dotIdx !== -1) {\n const head = path.slice(0, dotIdx)\n const rest = path.slice(dotIdx + 1)\n const nested = obj[head]\n if (!nested || typeof nested !== 'object' || Array.isArray(nested)) return\n setAtPathInPlace(nested as Record<string, unknown>, rest, value)\n return\n }\n obj[path] = value\n}\n","/**\n * Per-layer i18n resolution policy.\n *\n * `onMissing` governs what happens when a multilingual field is resolved\n * to a target locale that is absent. It may be a single scalar policy or\n * a per-layer map, so a field can be lenient at the app read boundary but\n * strict inside a materialized view.\n *\n * Effective policy for layer `λ`:\n *\n * ```\n * explicit(λ) = typeof onMissing === 'object' ? onMissing[λ] : undefined\n * scalar = typeof onMissing === 'string' ? onMissing : undefined\n * policy(λ) = explicit(λ) ?? layerDefault(λ) ?? scalar ?? 'throw'\n * ```\n *\n * - `layerDefault('guard') = 'substitute'` — guards are lenient unless\n * EXPLICITLY overridden; they never inherit a scalar policy (a guard\n * reading a display value must not hard-fail on a missing locale).\n * - every other layer has no default, so it inherits the scalar, else\n * falls back to `'throw'` (today's behavior — zero breaking change).\n *\n * @public\n */\nexport type OnMissing = 'substitute' | 'null' | 'throw'\n\n/**\n * The contexts in which a multilingual field is resolved. Each can carry\n * its own `onMissing` policy.\n *\n * - `read` — ordinary app reads (`get`/`list`/query projection).\n * - `guard` — a guard callback reading a value.\n * - `join` — a joined record expanded onto a row.\n * - `mv` — materialized-view input.\n * - `derivation` — derivation input.\n * - `export` — bundle/cover export.\n */\nexport type Layer = 'read' | 'guard' | 'join' | 'mv' | 'derivation' | 'export'\n\n/** Field-level policy: a single scalar, or a per-layer map. */\nexport type OnMissingPolicy = OnMissing | Partial<Record<Layer, OnMissing>>\n\n/**\n * Resolve the effective `OnMissing` for a layer from a field's declared\n * policy. See module docs for the resolution rule.\n */\nexport function resolvePolicy(\n onMissing: OnMissingPolicy | undefined,\n layer: Layer,\n): OnMissing {\n const explicit =\n onMissing && typeof onMissing === 'object' ? onMissing[layer] : undefined\n const scalar = typeof onMissing === 'string' ? onMissing : undefined\n const layerDefault: OnMissing | undefined =\n layer === 'guard' ? 'substitute' : undefined\n return explicit ?? layerDefault ?? scalar ?? 'throw'\n}\n","/**\n * Per-locale script enforcement for `i18nText` fields (write-time).\n *\n * Each locale slot's string is validated against an allowed set of\n * Unicode scripts. `'auto'` infers the set from the locale code with\n * **asymmetric Latin tolerance**: every non-Latin-script locale\n * also allows `Latin`, because proper names and addresses in those\n * locales routinely embed Latin brand/building/technical names — while\n * Latin-script locales do NOT allow other scripts, so the common error\n * (e.g. Thai text dumped into an `en` slot) is still caught.\n *\n * The always-on baseline is `Common` (digits, punctuation), `Inherited`\n * and `Mark` (combining diacritics, joiners, harakat, tone marks), and\n * whitespace — so Latin digits and in-script combining marks never\n * false-reject.\n *\n * @public\n */\nimport { ScriptViolationError } from '../../kernel/errors.js'\nimport type { I18nTextDescriptor } from './core.js'\n\n/** Locales whose base language is written in the Latin script. */\nconst LATIN_BASE = new Set([\n 'en', 'fr', 'de', 'es', 'it', 'pt', 'nl', 'sv', 'no', 'da', 'fi', 'is',\n 'pl', 'cs', 'sk', 'hu', 'ro', 'hr', 'sl', 'et', 'lv', 'lt', 'tr', 'vi',\n 'id', 'ms', 'tl', 'sw', 'af', 'ca', 'gl', 'eu', 'cy', 'ga',\n])\n\n/** Base-language → primary (non-Latin) scripts. Latin is appended by inferScripts. */\nconst SCRIPT_TABLE: Record<string, readonly string[]> = {\n th: ['Thai'],\n ko: ['Hangul', 'Han'],\n ja: ['Han', 'Hiragana', 'Katakana'],\n zh: ['Han'],\n ar: ['Arabic'],\n fa: ['Arabic'],\n ur: ['Arabic'],\n ru: ['Cyrillic'],\n uk: ['Cyrillic'],\n bg: ['Cyrillic'],\n sr: ['Cyrillic'],\n he: ['Hebrew'],\n el: ['Greek'],\n hi: ['Devanagari'],\n ta: ['Tamil'],\n km: ['Khmer'],\n lo: ['Lao'],\n my: ['Myanmar'],\n}\n\n/** Map a BCP-47 script subtag (e.g. `Latn`, `Cyrl`) to allowed scripts. */\nconst SUBTAG_SCRIPTS: Record<string, readonly string[]> = {\n Latn: ['Latin'],\n Cyrl: ['Cyrillic', 'Latin'],\n Hans: ['Han', 'Latin'],\n Hant: ['Han', 'Latin'],\n Thai: ['Thai', 'Latin'],\n Arab: ['Arabic', 'Latin'],\n}\n\n/**\n * Infer the allowed Unicode scripts for a BCP-47 locale, with asymmetric\n * Latin tolerance. A script subtag (`th-Latn`) wins over the base\n * language. Unknown locales default to `['Latin']`.\n */\nexport function inferScripts(locale: string): readonly string[] {\n const parts = locale.split('-')\n const subtag = parts.find((t) => /^[A-Z][a-z]{3}$/.test(t))\n if (subtag && SUBTAG_SCRIPTS[subtag]) return SUBTAG_SCRIPTS[subtag]\n\n const base = (parts[0] ?? '').toLowerCase()\n if (LATIN_BASE.has(base)) return ['Latin']\n const primary = SCRIPT_TABLE[base]\n if (primary) return [...primary, 'Latin'] // asymmetric Latin tolerance\n return ['Latin']\n}\n\n/** Resolve the allowed scripts for a field's locale slot. */\nfunction allowedFor(descriptor: I18nTextDescriptor, locale: string): readonly string[] {\n const script = descriptor.options.script\n if (script && script !== 'auto') {\n const explicit = script[locale]\n if (explicit) return explicit\n }\n return inferScripts(locale)\n}\n\n/** Always-allowed baseline character classes (besides the named scripts). */\nconst BASELINE = String.raw`\\p{White_Space}\\p{Script=Common}\\p{Script=Inherited}\\p{Mark}`\n\n/** Build a whole-string matcher for the allowed scripts. */\nfunction fullMatcher(scripts: readonly string[]): RegExp {\n const cls = scripts.map((s) => `\\\\p{Script=${s}}`).join('')\n return new RegExp(`^[${BASELINE}${cls}]*$`, 'u')\n}\n\n/** Build a single-character matcher (for sampling / stripping). */\nfunction charMatcher(scripts: readonly string[]): RegExp {\n const cls = scripts.map((s) => `\\\\p{Script=${s}}`).join('')\n return new RegExp(`[${BASELINE}${cls}]`, 'u')\n}\n\n/** Collect a short sample of characters that violate the allowed scripts. */\nfunction offendingSample(str: string, scripts: readonly string[]): string {\n const ok = charMatcher(scripts)\n const bad: string[] = []\n for (const ch of str) {\n if (!ok.test(ch)) bad.push(ch)\n if (bad.length >= 8) break\n }\n return bad.join('')\n}\n\n/** Remove characters that violate the allowed scripts. */\nfunction stripDisallowed(str: string, scripts: readonly string[]): string {\n const ok = charMatcher(scripts)\n let out = ''\n for (const ch of str) if (ok.test(ch)) out += ch\n return out\n}\n\n/** A non-fatal script violation recorded under `'filter'`/`'warn'` modes. */\nexport interface ScriptWarning {\n readonly field: string\n readonly locale: string\n readonly expected: readonly string[]\n readonly sample: string\n}\n\n/**\n * Enforce a field's script constraint over an i18nText value map.\n *\n * - No `script` option ⇒ returns the value unchanged.\n * - `onScriptViolation: 'reject'` (default) ⇒ throws {@link ScriptViolationError}.\n * - `'filter'` ⇒ returns a copy with disallowed characters stripped + warnings.\n * - `'warn'` ⇒ returns the value unchanged + warnings.\n */\nexport function enforceScript(\n value: Record<string, unknown>,\n field: string,\n descriptor: I18nTextDescriptor,\n exempt?: ReadonlySet<string>,\n): { value: Record<string, unknown>; warnings: ScriptWarning[] } {\n const opt = descriptor.options\n if (!opt.script) return { value, warnings: [] }\n\n const mode = opt.onScriptViolation ?? 'reject'\n const warnings: ScriptWarning[] = []\n let out = value\n\n for (const [locale, raw] of Object.entries(value)) {\n if (exempt?.has(locale)) continue\n if (typeof raw !== 'string') continue\n const allowed = allowedFor(descriptor, locale)\n if (fullMatcher(allowed).test(raw)) continue\n\n const sample = offendingSample(raw, allowed)\n if (mode === 'reject') {\n throw new ScriptViolationError(field, locale, allowed, sample)\n }\n warnings.push({ field, locale, expected: allowed, sample })\n if (mode === 'filter') {\n if (out === value) out = { ...value }\n out[locale] = stripDisallowed(raw, allowed)\n }\n }\n\n return { value: out, warnings }\n}\n","/**\n * The i18n `NoydbVia` — wires the i18n engine (auto-translate/script\n * enforcement/validation/densify on write; locale + dict-label presentation\n * on read) into the kernel's generic Via port. Mirrors\n * `via/money/binding.ts`'s #553 static-link pattern.\n *\n * LIVE (#623 Task 8 wired the cutover): `i18nVia()`/`linkI18nVia()` are\n * the real put/read path for every i18n-declaring collection —\n * `collection.ts`'s `_putInternal`/`applyLocaleToRecord` (the call sites\n * this file's bodies were moved/adapted from) now delegate their i18n\n * stages to `this.via.encodeWrite`/`this.via.present` instead of running\n * the hand-wired i18n logic inline.\n *\n * `i18nText()`, `dictKey()`, `staticDict()` each call {@link linkI18nVia}\n * first — the same #553 pattern `money()` uses.\n */\nimport type { NoydbVia, ViaWriteCtx, ViaReadCtx } from '../../kernel/via/index.js'\nimport { installViaBinder } from '../../kernel/via/index.js'\nimport type { I18nTextDescriptor } from './core.js'\nimport { stripI18nFilled } from './core.js'\nimport type { DictKeyDescriptor, StaticDictDescriptor } from './dictionary.js'\nimport type { I18nStrategy } from '../../port/with/i18n-strategy.js'\nimport { isStaticDictDescriptor } from '../../port/with/i18n-strategy.js'\nimport { resolvePolicy, type Layer } from './policy.js'\nimport { getAtPath, setAtPathInPlace } from '../../kernel/paths.js'\nimport { TranslatorNotConfiguredError, LocaleNotSpecifiedError } from '../../kernel/errors.js'\n\n/**\n * Config a collection's i18n declarations resolve to — the binding's\n * construction input. Fields are loosely typed (`unknown`) at this seam\n * because the kernel's `ViaBinder` contract is opaque-config-in; the\n * concrete i18n types are applied inside the binding's own functions.\n */\nexport interface I18nViaConfig {\n i18nFields?: Record<string, unknown> // I18nTextDescriptor map\n dictKeyFields?: Record<string, unknown> // DictKeyDescriptor | StaticDictDescriptor map\n i18nDensifyFields?: Record<string, unknown> // I18nTextDescriptor subset (densifyOnWrite: true)\n strategy: unknown // I18nStrategy (real or NO_I18N)\n defaultLocale?: string\n autoTranslateHook?: (...args: unknown[]) => Promise<string>\n dictLabelResolver?: (...args: unknown[]) => Promise<string | undefined>\n i18nPutValidator?: (record: unknown) => void // the vault-built closure (unchanged wiring)\n collectionName: string\n}\n\n// ─── write pipeline ─────────────────────────────────────────────────────\n\n/**\n * Auto-translate missing i18nText translations. Runs BEFORE i18n\n * validation so translated values satisfy the required-locale constraint.\n * Throws `TranslatorNotConfiguredError` when a field has\n * `autoTranslate: true` but no hook was configured. Mutates `record`\n * in place (mirrors `collection.ts:1830-1874`).\n */\nasync function runI18nAutoTranslate(\n record: Record<string, unknown>,\n i18nFields: Record<string, I18nTextDescriptor>,\n cfg: I18nViaConfig,\n): Promise<void> {\n for (const [field, descriptor] of Object.entries(i18nFields)) {\n if (!descriptor.options.autoTranslate) continue\n // getAtPath returns [] for array-wildcard paths — auto-translate on\n // 'contacts[].field' style paths is not supported; skip silently.\n const leafValues = getAtPath(record, field)\n if (leafValues.length !== 1) continue\n const value = leafValues[0]\n if (!value || typeof value !== 'object' || Array.isArray(value)) continue\n const map = value as Record<string, string>\n // Determine which locales need translation. For 'all', translate all\n // declared languages that are missing. For 'any', only translate if\n // none are present. For string[], translate the listed required ones.\n const { languages, required } = descriptor.options\n const missing: string[] = languages.filter(\n (lang) => !(lang in map) || map[lang] === '',\n )\n if (missing.length === 0) continue\n // Find a source locale (first present non-empty value)\n const sourceLocale = languages.find((l) => l in map && map[l] !== '')\n if (!sourceLocale) continue\n if (!cfg.autoTranslateHook) {\n throw new TranslatorNotConfiguredError(field, cfg.collectionName)\n }\n // Only translate locales that are actually needed\n const toTranslate =\n required === 'any'\n ? [] // 'any' is already satisfied since sourceLocale exists\n : required === 'all'\n ? missing\n : missing.filter((l) => required.includes(l))\n const translated = { ...map }\n for (const targetLocale of toTranslate) {\n translated[targetLocale] = await cfg.autoTranslateHook(\n map[sourceLocale]!,\n sourceLocale,\n targetLocale,\n field,\n cfg.collectionName,\n )\n }\n setAtPathInPlace(record, field, translated)\n }\n}\n\n/**\n * i18nText script enforcement — runs AFTER auto-translate (so generated\n * values are checked too). Throws `ScriptViolationError` (from inside\n * `strategy.enforceScript`) under the default 'reject'; 'filter' strips\n * disallowed chars in place; 'warn' leaves the value unchanged. Mirrors\n * `collection.ts:1896-1927`.\n */\nfunction runI18nScriptEnforcement(\n record: Record<string, unknown>,\n i18nFields: Record<string, I18nTextDescriptor>,\n strategy: I18nStrategy,\n exemptFills: Map<string, Set<string>> | undefined,\n ctx: ViaWriteCtx,\n cfg: I18nViaConfig,\n): void {\n for (const [field, descriptor] of Object.entries(i18nFields)) {\n if (!descriptor.options.script) continue\n for (const leaf of getAtPath(record, field)) {\n if (!leaf || typeof leaf !== 'object' || Array.isArray(leaf)) continue\n const leafMap = leaf as Record<string, unknown>\n const { value: cleaned, warnings } = strategy.enforceScript(\n leafMap,\n field,\n descriptor,\n exemptFills?.get(field),\n )\n if (cleaned !== leafMap) Object.assign(leafMap, cleaned)\n // enforceScript only returns warnings under 'warn'/'filter' ('reject'\n // throws first), so this guard never fires — it makes that invariant\n // explicit and keeps `mode` off the optional-undefined type.\n const mode = descriptor.options.onScriptViolation\n if (mode === 'warn' || mode === 'filter') {\n for (const w of warnings) {\n // Exact original payload shape (collection.ts:1916-1922 pre-cutover).\n ctx.emit('i18n:script-violation', {\n vault: ctx.vault,\n collection: cfg.collectionName,\n id: ctx.id,\n mode,\n warning: w,\n })\n }\n }\n }\n }\n}\n\n/**\n * `encodeWrite` — translate → script → validate → densify, in the EXACT\n * order `_putInternal` runs them today (seam-map Part 2, stages 7-11).\n */\nasync function runI18nWriteStages(\n record: Record<string, unknown>,\n ctx: ViaWriteCtx,\n cfg: I18nViaConfig,\n): Promise<Record<string, unknown>> {\n const i18nFields = cfg.i18nFields as Record<string, I18nTextDescriptor> | undefined\n const i18nDensifyFields = cfg.i18nDensifyFields as Record<string, I18nTextDescriptor> | undefined\n const strategy = cfg.strategy as I18nStrategy\n\n // 1. Auto-translate.\n if (i18nFields) {\n await runI18nAutoTranslate(record, i18nFields, cfg)\n }\n\n // 2. densifyOnWrite: read prior fills so a round-tripped derived copy is\n // exempt from script enforcement and can be refreshed. Read once here,\n // reused by densify() below. `ctx.prior()` resolves the real prior\n // record (collection.ts wires it to `resolveDensifyPrior`, #623 Task 8).\n let densifyPrior: Record<string, unknown> | undefined\n let exemptFills: Map<string, Set<string>> | undefined\n if (i18nDensifyFields) {\n densifyPrior = (await ctx.prior()) ?? undefined\n exemptFills = strategy.computeExemptFills(densifyPrior, record, i18nDensifyFields)\n }\n\n // 3. Script enforcement.\n if (i18nFields) {\n runI18nScriptEnforcement(record, i18nFields, strategy, exemptFills, ctx, cfg)\n }\n\n // 4. i18nText validation — AFTER auto-translate + script so the record is\n // trustworthy. Throws MissingTranslationError when required translations\n // are absent. The vault-built closure (unchanged wiring).\n cfg.i18nPutValidator?.(record)\n\n // 5. Eager-fill empty slots + record provenance. Runs AFTER the authored\n // gates (required + script) so only authored slots are validated.\n if (i18nDensifyFields) {\n strategy.densify(record, densifyPrior, i18nDensifyFields)\n }\n\n return record\n}\n\n// ─── read pipeline ──────────────────────────────────────────────────────\n\n/**\n * `present` — i18nText locale resolution + dictKey/staticDict label\n * resolution + `_i18nFilled` stripping. Adapted from\n * `applyLocaleToRecord`'s i18n+dict+strip portions (`collection.ts:4184-\n * 4301`) — the money-decode portion of that method is a separate binding\n * (`via/money`) and is NOT this function's concern.\n */\nasync function runI18nPresent(\n record: Record<string, unknown>,\n ctx: ViaReadCtx,\n cfg: I18nViaConfig,\n): Promise<Record<string, unknown>> {\n const i18nFields = cfg.i18nFields as Record<string, I18nTextDescriptor> | undefined\n const dictKeyFields = cfg.dictKeyFields as Record<string, DictKeyDescriptor | StaticDictDescriptor> | undefined\n const strategy = cfg.strategy as I18nStrategy\n const hasI18n = i18nFields !== undefined && Object.keys(i18nFields).length > 0\n const hasDict = dictKeyFields !== undefined && Object.keys(dictKeyFields).length > 0\n if (!hasI18n && !hasDict) return record\n\n const locale = typeof ctx.locale === 'string' ? ctx.locale : undefined\n const fallback = ctx.fallback as string | readonly string[] | undefined\n const layer = ctx.layer as Layer\n\n let result = record\n\n // i18nText / dictKey resolution require an active locale — EXCEPT a\n // static dict declaring a `displayLocale`, which resolves its\n // `<field>Label` even under a locale-less read (the hybrid hinge). Only\n // this second gate relaxes, and ONLY for static-display fields — folding\n // `hasI18n` in here would let an i18nText-only collection fall through to\n // applyI18nLocale(…, undefined) on a locale-less read, breaking the\n // raw-{th,en}-map invariant.\n const hasStaticDisplay =\n hasDict &&\n dictKeyFields !== undefined &&\n Object.values(dictKeyFields).some(\n (d) => isStaticDictDescriptor(d) && d.displayLocale !== undefined,\n )\n\n // Strip the internal densify marker even when no locale is active\n // (applyI18nLocale, which normally strips it, is skipped on this path).\n // Non-mutating: never touches the cached/stored record object.\n if (!locale && !hasStaticDisplay) return stripI18nFilled(result)\n\n // 1. i18nText resolution — guarded on `locale`, because the relaxed gate\n // above can now be entered with `locale === undefined` (static-display).\n // The layer selects the field's per-layer `onMissing` policy inside\n // applyI18nLocale.\n if (locale && hasI18n && i18nFields) {\n result = strategy.applyI18nLocale(result, i18nFields, locale, fallback, layer)\n }\n\n // 2. dictKey / staticDict label resolution\n if (hasDict && dictKeyFields && cfg.dictLabelResolver && locale !== 'raw') {\n const withLabels = { ...result }\n const resolver = cfg.dictLabelResolver\n for (const [field, desc] of Object.entries(dictKeyFields)) {\n // dictKey default policy is 'null' (omit/null on miss) — today's\n // behavior — unless the field declares onMissing. 'substitute'\n // walks the declared substitute chain (passed as the resolver's\n // fallback); 'throw' raises LocaleNotSpecifiedError.\n const policy = desc.onMissing ? resolvePolicy(desc.onMissing, layer) : 'null'\n const fieldFallback =\n policy === 'substitute'\n ? (fallback ?? desc.substitute)\n : fallback\n // Per-field effective locale: a static dict falls back to its\n // `displayLocale` when no locale is active (the hybrid hinge); a\n // plain dictKey with no displayLocale gets `undefined` → its\n // <field>Label is omitted on a locale-less read (today's behavior).\n const effLocale =\n locale ??\n (isStaticDictDescriptor(desc) ? desc.displayLocale : undefined)\n // Resolve one key → label | null, honoring the policy. With no\n // effective locale there is nothing to resolve against.\n const resolveKey = async (key: string): Promise<string | null> => {\n if (!effLocale) {\n if (policy === 'throw') {\n throw new LocaleNotSpecifiedError(\n field,\n `dictKey \"${field}\": no locale active to resolve key \"${key}\".`,\n )\n }\n return null\n }\n const label = await resolver(desc.name, key, effLocale, fieldFallback)\n if (label === undefined) {\n if (policy === 'throw') {\n throw new LocaleNotSpecifiedError(\n field,\n `dictKey \"${field}\": no label for key \"${key}\" in locale \"${effLocale}\".`,\n )\n }\n return null\n }\n return label\n }\n\n if (field.includes('[].')) {\n // Wildcard path `arrayKey[].leaf`: add a per-element sibling\n // `<leaf>Label`. Single level + simple leaf.\n const parts = field.split('[].')\n const arrayKey = parts[0]!\n const leaf = parts[1]\n if (!leaf || leaf.includes('.')) continue\n const arr = (withLabels as Record<string, unknown>)[arrayKey]\n if (!Array.isArray(arr)) continue\n const labelKey = `${leaf}Label`\n ;(withLabels as Record<string, unknown>)[arrayKey] = await Promise.all(\n arr.map(async (el) => {\n if (!el || typeof el !== 'object' || Array.isArray(el)) return el\n const k = (el as Record<string, unknown>)[leaf]\n if (typeof k !== 'string') return el\n return { ...(el as Record<string, unknown>), [labelKey]: await resolveKey(k) }\n }),\n )\n continue\n }\n\n const val = result[field]\n if (Array.isArray(val)) {\n // Array-of-keys → [{ key, label }] pair objects (key preserved).\n withLabels[`${field}Label`] = await Promise.all(\n val.map(async (k) => ({\n key: k,\n label: typeof k === 'string' ? await resolveKey(k) : null,\n })),\n )\n } else if (typeof val === 'string') {\n const label = await resolveKey(val)\n // Scalar under 'null'/default omits the label key (today's\n // behavior); 'substitute' returns a value; 'throw' threw above.\n if (label !== null) withLabels[`${field}Label`] = label\n }\n }\n result = withLabels\n }\n\n // Final guard: the locale-less static-display path skips\n // applyI18nLocale's strip, so ensure the densify marker never leaks here\n // either. Non-mutating (no-op when absent or already stripped above).\n return stripI18nFilled(result)\n}\n\n// ─── introspection ──────────────────────────────────────────────────────\n\nfunction buildI18nDescribeFragment(cfg: I18nViaConfig): Record<string, unknown> {\n return {\n i18nFields: cfg.i18nFields ? Object.keys(cfg.i18nFields) : [],\n dictKeyFields: cfg.dictKeyFields ? Object.keys(cfg.dictKeyFields) : [],\n ...(cfg.defaultLocale !== undefined ? { defaultLocale: cfg.defaultLocale } : {}),\n }\n}\n\n// ─── binding ────────────────────────────────────────────────────────────\n\nexport function i18nVia(cfg: I18nViaConfig): NoydbVia {\n return {\n brand: 'i18n',\n posture: { encryptedAtRest: 'envelope', queryable: 'full', exportable: true, forgettable: true },\n // DictionaryHandle's `_dict_*` reserved collections (#629 Task 4) — the\n // codec boundary's `reservedEnvelopes` door may address any collection\n // name under this prefix.\n reservedPrefixes: ['_dict_'],\n covers: (field) =>\n (cfg.i18nFields !== undefined && field in cfg.i18nFields)\n || (cfg.dictKeyFields !== undefined && field in cfg.dictKeyFields),\n encodeWrite: async (record, ctx) => runI18nWriteStages(record, ctx, cfg),\n present: async (record, ctx) => runI18nPresent(record, ctx, cfg),\n describeFragment: () => buildI18nDescribeFragment(cfg),\n }\n}\n\nexport function linkI18nVia(): void {\n installViaBinder('i18n', (c) => i18nVia(c as I18nViaConfig))\n}\n","/**\n * i18nText schema type —\n *\n * `i18nText({ languages, required })` creates a descriptor for a\n * multi-language content field whose value is stored as a\n * `{ [locale]: string }` map (e.g. `{ en: 'Consulting', th: 'ที่ปรึกษา' }`).\n *\n * On put, the descriptor validates that required languages are present.\n * On read (when a `locale` option is passed), the map is collapsed to the\n * caller's locale string via the fallback chain.\n *\n * Design decisions\n * ────────────────\n *\n * **Descriptor pattern (not a Zod type).**\n * `i18nText()` returns a plain descriptor object used in the collection's\n * `i18nFields` option — same pattern as `ref()` / `dictKey()`. This keeps\n * `@noy-db/core` at zero runtime dependencies and avoids Zod v3 field-type\n * constraints. TypeScript inference is handled via the descriptor's type.\n *\n * **Enforcement at the collection boundary.**\n * The `required` option is checked by `Collection.put()` via the compartment's\n * registered `i18nFields`. Failed validation throws `MissingTranslationError`\n * — a distinct class from `SchemaValidationError` so callers can tell\n * \"wrong shape\" from \"missing translations\".\n *\n * **Resolution is post-decryption.**\n * Locale resolution happens AFTER `decryptRecord()`, as a pure in-memory\n * transform. No additional crypto work is needed. The resolved record is\n * returned in place of the stored one, with i18nText fields replaced by\n * their locale-resolved strings.\n *\n * **`locale: 'raw'`.**\n * Passing `{ locale: 'raw' }` skips resolution and returns the full\n * `{ [locale]: string }` map — useful for bilingual exports, admin UIs,\n * and any context where all translations must be visible at once.\n *\n * **Out of scope.**\n * Pluralization, RTL rendering, date/number formatting, per-locale CRDT\n * merging.\n */\n\nimport { MissingTranslationError, LocaleNotSpecifiedError } from '../../kernel/errors.js'\nimport type { OnMissing, OnMissingPolicy, Layer } from './policy.js'\nimport { resolvePolicy } from './policy.js'\nimport { inferScripts } from './script.js'\nimport { linkI18nVia } from './binding.js'\n\n// ─── I18nMap type helper ───────────────────────────────────────────────\n\n/** Flatten an intersection into a single object literal for nicer hovers. */\ntype Prettify<T> = { [K in keyof T]: T[K] } & {}\n\n/**\n * The stored shape of a multilingual field, inferred from its `required`\n * mode — so the compiler forces you to handle an absent optional locale\n * (`string | undefined`) instead of silently yielding `undefined`.\n *\n * Mirrors `i18nText({ languages, required })`:\n * - `'all'` (default) — every locale required: `{ th: string; en: string }`\n * - `'any'` — every locale optional: `{ th?: string; en?: string }`\n * (the \"at least one present\" guarantee is runtime-only — not expressible\n * in TypeScript — so each key is optional)\n * - `readonly L[]` — listed locales required, the rest optional:\n * `I18nMap<'th'|'en', ['th']>` → `{ th: string; en?: string }`\n *\n * @example\n * ```ts\n * type Lang = 'th' | 'en'\n * interface Contact {\n * name: I18nMap<Lang, 'any'> // { th?: string; en?: string }\n * legalName: I18nMap<Lang, ['th']> // { th: string; en?: string }\n * slug: I18nMap<Lang> // { th: string; en: string }\n * }\n * ```\n *\n * @public\n */\nexport type I18nMap<\n Langs extends string,\n Required extends 'all' | 'any' | readonly Langs[] = 'all',\n> = Required extends 'all'\n ? Record<Langs, string>\n : Required extends 'any'\n ? Partial<Record<Langs, string>>\n : Required extends readonly (infer R extends Langs)[]\n ? Prettify<Record<R, string> & Partial<Record<Exclude<Langs, R>, string>>>\n : never\n\n// ─── i18nText descriptor ───────────────────────────────────────────────\n\n/**\n * Options for `i18nText()`.\n *\n * `languages` declares the full set of supported locales. `required`\n * controls which must be present on every `put()`.\n *\n * `autoTranslate` is the per-field opt-in for the `plaintextTranslator`\n * hook. When `true` and a `plaintextTranslator` is configured\n * on `createNoydb()`, missing translations are generated before `put()`.\n * Default: `false`.\n */\nexport interface I18nTextOptions {\n /** All supported locale codes (BCP 47). */\n readonly languages: readonly string[]\n /**\n * Which locales must be present on every `put()`.\n *\n * - `'all'` — every declared language must be present.\n * - `'any'` — at least one declared language must be present.\n * - `string[]` — listed locales are required; others are optional.\n */\n readonly required: 'all' | 'any' | readonly string[]\n /**\n * Per-field opt-in for the `plaintextTranslator` hook.\n * When `true`, missing required translations are auto-generated\n * before `put()` if a translator is configured. Default: `false`.\n */\n readonly autoTranslate?: boolean\n /**\n * What to do when this field is resolved to a locale that is absent.\n * A single policy, or a per-layer map (read/guard/join/mv/derivation/\n * export). Default `'throw'` — today's behavior, zero breaking change.\n * See {@link OnMissingPolicy}.\n *\n * NOTE (current wiring): ALL layers are enforced — `read` (`get`/`list`),\n * `guard`, `derivation`, `mv`, `join`, `export`. Guard / derivation\n * `ctx.vault` reads resolve under their own layer policy (`guard` defaults to\n * the lenient `'substitute'`). The `mv` layer fires for materialized views\n * that declare `{ i18nLocale, i18nFields }` — UNION (group-key i18n fields\n * resolve before the unified-row bucketing) and query-form (resolved in\n * `GroupedReduction.run` before `groupAndReduce`); grouping a raw i18n field\n * without a locale throws. The `join` layer resolves a joined right-side i18n\n * field to the query locale (`toArray({ locale })` or the vault default; raw\n * when locale-less). The `export` layer fires for\n * `exportStream`/`exportJSON({ resolveLabels })` — records collapse to the\n * export locale.\n */\n readonly onMissing?: OnMissingPolicy\n /**\n * Ordered preferred-substitute locales used when `onMissing` resolves\n * to `'substitute'` and the target locale is absent. `'any'` as an\n * element means \"first non-empty value\". A caller-supplied `fallback`\n * at read time takes precedence over this declared list.\n */\n readonly substitute?: readonly string[]\n /**\n * Smart-substitute. When `true`, a missing-locale `substitute` walk that\n * misses the explicit chain prefers the available locale whose script is\n * nearest the target (same script, then Latin) rather than an arbitrary value\n * — e.g. a missing Thai label prefers another Thai (or Latin) translation over\n * an unreadable script. Default `false` (legacy first-non-empty behavior).\n */\n readonly smartSubstitute?: boolean\n /**\n * Per-locale script enforcement (write-time). `'auto'` infers the\n * allowed Unicode scripts per locale (asymmetric Latin tolerance); an\n * object overrides per slot. Absent ⇒ no check. See `./script.ts`.\n */\n readonly script?: 'auto' | Partial<Record<string, readonly string[]>>\n /**\n * What to do when a slot's value contains characters outside its\n * allowed script set. Default `'reject'`.\n */\n readonly onScriptViolation?: 'reject' | 'filter' | 'warn'\n /**\n * Eager-fill empty locale slots from the substitute chain at\n * write time, recording provenance in the internal `_i18nFilled` marker.\n * Mutually exclusive with an EXPLICIT `'throw'` onMissing policy (densify\n * fills every hole, so a throw would be unreachable). Without an explicit\n * `substitute`, fills from `'any'` (first non-empty). Default absent.\n */\n readonly densifyOnWrite?: boolean\n}\n\n/**\n * Descriptor returned by `i18nText()`. Attach to the collection's\n * `i18nFields` option:\n *\n * ```ts\n * const lineItems = company.collection<LineItem>('line-items', {\n * i18nFields: {\n * description: i18nText({ languages: ['en', 'th'], required: 'all' }),\n * },\n * })\n * ```\n */\nexport interface I18nTextDescriptor {\n readonly _noydbI18nText: true\n /** Via port brand marker — lets an `I18nTextDescriptor` satisfy the kernel's opaque `ViaDescriptor` (#623 Task 9). */\n readonly _viaBrand: 'i18n'\n readonly options: I18nTextOptions\n}\n\n/**\n * Create an `I18nTextDescriptor` for a multi-language content field.\n *\n * @param options Language list + enforcement mode.\n *\n * @example\n * ```ts\n * i18nText({ languages: ['en', 'th'], required: 'all' })\n * i18nText({ languages: ['en', 'th'], required: ['th'], autoTranslate: true })\n * ```\n */\nexport function i18nText(options: I18nTextOptions): I18nTextDescriptor {\n // The declaration is the Via binding's opt-in unit (#553): constructing\n // a descriptor statically links the i18n binding into the kernel's Via\n // port, so every later kernel consultation finds it already installed.\n linkI18nVia()\n if (options.densifyOnWrite === true && hasThrowPolicy(options.onMissing)) {\n throw new Error(\n `i18nText: densifyOnWrite cannot be combined with an explicit onMissing 'throw' ` +\n `policy — densify fills every empty slot, so a 'throw' would be unreachable. ` +\n `Remove the 'throw' policy or disable densifyOnWrite.`,\n )\n }\n return { _noydbI18nText: true, _viaBrand: 'i18n', options }\n}\n\n/** True when `onMissing` declares `'throw'` for any layer (scalar or per-layer). */\nfunction hasThrowPolicy(onMissing: OnMissingPolicy | undefined): boolean {\n if (onMissing === undefined) return false\n if (typeof onMissing === 'string') return onMissing === 'throw'\n return Object.values(onMissing).includes('throw')\n}\n\n// `isI18nTextDescriptor` now lives on the kernel port (#623 Task 11,\n// port/with/i18n-strategy.ts, alongside `isStaticDictDescriptor`) —\n// re-exported here for compat with existing importers of this module.\nexport { isI18nTextDescriptor } from '../../port/with/i18n-strategy.js'\n\n// ─── Validation helpers ────────────────────────────────────────────────\n\n/**\n * Validate that a value is a valid `{ [locale]: string }` map and that\n * all required locales are present. Throws `MissingTranslationError`\n * when the required constraint is violated.\n *\n * Called by `Collection.put()` for each registered `i18nField`.\n *\n * @param value The raw field value from the record being put.\n * @param field The field name (used in the thrown error message).\n * @param descriptor The `i18nText()` descriptor for this field.\n */\nexport function validateI18nTextValue(\n value: unknown,\n field: string,\n descriptor: I18nTextDescriptor,\n): void {\n const { options } = descriptor\n\n // Must be a non-null object\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n throw new MissingTranslationError(\n field,\n options.languages,\n `Field \"${field}\" must be a { [locale]: string } map, got ${typeof value}.`,\n )\n }\n\n const map = value as Record<string, unknown>\n\n // All values must be strings\n for (const [locale, v] of Object.entries(map)) {\n if (typeof v !== 'string') {\n throw new MissingTranslationError(\n field,\n [locale],\n `Field \"${field}\": locale \"${locale}\" must be a string, got ${typeof v}.`,\n )\n }\n }\n\n // Check required constraint\n const { required } = options\n if (required === 'all') {\n const missing = options.languages.filter(\n (lang) => !(lang in map) || map[lang] === '',\n )\n if (missing.length > 0) {\n throw new MissingTranslationError(\n field,\n missing,\n `Field \"${field}\" requires all declared languages. Missing: ${missing.join(', ')}.`,\n )\n }\n } else if (required === 'any') {\n const present = options.languages.some(\n (lang) => lang in map && map[lang] !== '',\n )\n if (!present) {\n throw new MissingTranslationError(\n field,\n options.languages,\n `Field \"${field}\" requires at least one declared language. None present.`,\n )\n }\n } else {\n // string[] — named required locales; TypeScript narrows required to readonly string[]\n const requiredList = required\n const missing = requiredList.filter(\n (lang) => !(lang in map) || map[lang] === '',\n )\n if (missing.length > 0) {\n throw new MissingTranslationError(\n field,\n missing,\n `Field \"${field}\" requires: ${requiredList.join(', ')}. Missing: ${missing.join(', ')}.`,\n )\n }\n }\n}\n\n// ─── Locale resolution ─────────────────────────────────────────────────\n\n/**\n * Resolve an i18nText value (`{ [locale]: string }` map) to a string\n * for the given locale.\n *\n * @param value The stored locale map.\n * @param locale The requested locale code, or `'raw'` to return the map.\n * @param fallback Single locale or ordered list; use `'any'` as the last\n * element to fall back to any available translation.\n * @param field Field name used in `LocaleNotSpecifiedError` messages.\n * @returns The resolved string, OR the original map when `locale === 'raw'`.\n */\n/** Options for the policy-aware form of {@link resolveI18nText}. */\nexport interface ResolveI18nOptions {\n /** Effective policy for the resolution layer. Default `'throw'`. */\n readonly policy?: OnMissing\n /** Declared substitute chain; applied only under policy `'substitute'`. */\n readonly substitute?: readonly string[]\n /**\n * Smart-substitute. When `true` and policy is `'substitute'`, after the\n * explicit chain misses, pick the available locale whose script is nearest the\n * target (same script first, then Latin's broad readability) instead of an\n * arbitrary value. Default `false`.\n */\n readonly smartSubstitute?: boolean\n}\n\n/** Normalize a single-or-list fallback into an array. */\nfunction toChain(fallback: string | readonly string[] | undefined): readonly string[] {\n return Array.isArray(fallback) ? fallback : fallback ? [fallback as string] : []\n}\n\n/** Walk a chain, returning the first non-empty value (or `'any'` match). */\nfunction pickFromChain(\n value: Record<string, string>,\n chain: readonly string[],\n): string | undefined {\n for (const fb of chain) {\n if (fb === 'any') {\n const any = Object.values(value).find((v) => v !== '')\n if (any !== undefined) return any\n } else if (value[fb] !== undefined && value[fb] !== '') {\n return value[fb]\n }\n }\n return undefined\n}\n\n// Legacy 4-arg form: can only throw or return — never null. Keeps every\n// existing call site's type unchanged (default policy is 'throw').\nexport function resolveI18nText(\n value: Record<string, string>,\n locale: string,\n fallback?: string | readonly string[],\n field?: string,\n): string | Record<string, string>\n// Policy-aware form: may return null under 'null'/'substitute' policies.\nexport function resolveI18nText(\n value: Record<string, string>,\n locale: string,\n fallback: string | readonly string[] | undefined,\n field: string | undefined,\n opts: ResolveI18nOptions,\n): string | Record<string, string> | null\nexport function resolveI18nText(\n value: Record<string, string>,\n locale: string,\n fallback?: string | readonly string[],\n field?: string,\n opts?: ResolveI18nOptions,\n): string | Record<string, string> | null {\n if (locale === 'raw') {\n return value\n }\n\n if (!locale) {\n throw new LocaleNotSpecifiedError(field ?? '<unknown>')\n }\n\n // Primary locale\n if (value[locale] !== undefined && value[locale] !== '') {\n return value[locale]\n }\n\n const policy: OnMissing = opts?.policy ?? 'throw'\n\n // Caller-supplied fallback ALWAYS applies first (backward compat +\n // explicit read-time override), regardless of policy.\n const callerChain = toChain(fallback)\n const callerHit = pickFromChain(value, callerChain)\n if (callerHit !== undefined) return callerHit\n\n // Declared substitute applies ONLY under policy 'substitute'.\n if (policy === 'substitute') {\n const subHit = pickFromChain(value, toChain(opts?.substitute))\n if (subHit !== undefined) return subHit\n // Smart-substitute: after the explicit chain, prefer the script-nearest\n // available locale over an arbitrary first-non-empty value.\n if (opts?.smartSubstitute) {\n const smartHit = pickNearestScript(value, locale)\n if (smartHit !== undefined) return smartHit\n }\n }\n\n // Exhausted.\n if (policy === 'throw') {\n throw new LocaleNotSpecifiedError(\n field ?? '<unknown>',\n `No translation available for locale \"${locale}\"` +\n (callerChain.length > 0 ? ` or fallback chain [${callerChain.join(', ')}]` : '') +\n '.',\n )\n }\n return null\n}\n\n/**\n * Smart-substitute: among the non-empty locales in `value`, pick the one\n * whose primary script is nearest the target `locale` — same script first, then\n * Latin (broadly readable), then any other — so a missing Thai label falls back\n * to another Thai (or Latin) value rather than, say, an Arabic one. First-seen\n * wins on ties. Returns the value string, or `undefined` when `value` has no\n * non-empty entry.\n */\nfunction pickNearestScript(value: Record<string, string>, target: string): string | undefined {\n const targetScript = inferScripts(target)[0] ?? 'Latin'\n let best: { score: number; v: string } | undefined\n for (const [loc, v] of Object.entries(value)) {\n if (typeof v !== 'string' || v === '') continue\n const s = inferScripts(loc)[0] ?? 'Latin'\n const score = s === targetScript ? 0 : s === 'Latin' ? 1 : 2\n if (best === undefined || score < best.score) best = { score, v }\n if (score === 0) break // nothing beats a same-script match\n }\n return best?.v\n}\n\n// ─── Path helpers (nested i18nFields like 'address.lineOne') ──────────\n\n// `getAtPath`/`setAtPathInPlace` are generic dotted-path/[]-wildcard record\n// helpers, not i18n logic — moved to `kernel/paths.ts` (Task 7, #623).\n// `getAtPath` re-exported here for compat with existing importers of this\n// module (embeddings/descriptor.ts, search/build-docs.ts); `setAtPathInPlace`\n// is not re-exported — its only consumer (via-i18n/binding.ts) imports it\n// directly from kernel/paths.ts.\nexport { getAtPath } from '../../kernel/paths.js'\n\n/** Recursively resolve i18nText at a single path within a record copy. */\nfunction applyAtPath(\n obj: Record<string, unknown>,\n path: string,\n locale: string,\n fallback: string | readonly string[] | undefined,\n opts: ResolveI18nOptions,\n): Record<string, unknown> {\n const arrayIdx = path.indexOf('[].')\n if (arrayIdx !== -1) {\n const arrayKey = path.slice(0, arrayIdx)\n const restPath = path.slice(arrayIdx + 3)\n const arr = obj[arrayKey]\n if (!Array.isArray(arr)) return obj\n return {\n ...obj,\n [arrayKey]: arr.map(item => {\n if (!item || typeof item !== 'object' || Array.isArray(item)) return item\n return applyAtPath(item as Record<string, unknown>, restPath, locale, fallback, opts)\n }),\n }\n }\n const dotIdx = path.indexOf('.')\n if (dotIdx !== -1) {\n const head = path.slice(0, dotIdx)\n const rest = path.slice(dotIdx + 1)\n const nested = obj[head]\n if (!nested || typeof nested !== 'object' || Array.isArray(nested)) return obj\n return {\n ...obj,\n [head]: applyAtPath(nested as Record<string, unknown>, rest, locale, fallback, opts),\n }\n }\n const raw = obj[path]\n if (raw === undefined || raw === null) return obj\n if (typeof raw !== 'object' || Array.isArray(raw)) return obj\n return {\n ...obj,\n [path]: resolveI18nText(raw as Record<string, string>, locale, fallback, path, opts),\n }\n}\n\n/**\n * Apply locale resolution to a single record, returning a new copy.\n *\n * For each field registered as an `i18nText` descriptor:\n * - If `locale === 'raw'`, the field value is left as the stored map.\n * - Otherwise, the field value is replaced with the resolved string.\n *\n * Field paths support dot notation (`'address.lineOne'`) and array\n * wildcards (`'contacts[].title'`). Top-level fields work as before.\n *\n * @param record The decrypted record.\n * @param i18nFields Map of field path → `I18nTextDescriptor`.\n * @param locale The requested locale (or `'raw'`).\n * @param fallback Fallback chain (optional).\n * @param layer Resolution layer (default `'read'`). Each field's\n * `onMissing` policy is resolved for this layer, so the\n * same record resolves leniently on a get but strictly\n * inside an mv/derivation.\n */\nexport function applyI18nLocale(\n record: Record<string, unknown>,\n i18nFields: Record<string, I18nTextDescriptor>,\n locale: string,\n fallback?: string | readonly string[],\n layer: Layer = 'read',\n): Record<string, unknown> {\n const fieldNames = Object.keys(i18nFields)\n if (fieldNames.length === 0) return record\n\n let result = record\n\n for (const [field, descriptor] of Object.entries(i18nFields)) {\n const { onMissing, substitute, smartSubstitute } = descriptor.options\n const opts: ResolveI18nOptions = {\n policy: resolvePolicy(onMissing, layer),\n ...(substitute !== undefined ? { substitute } : {}),\n ...(smartSubstitute ? { smartSubstitute } : {}),\n }\n result = applyAtPath(result, field, locale, fallback, opts)\n }\n\n // The internal densify provenance marker never leaves the store.\n result = stripI18nFilled(result)\n\n return result\n}\n\n/**\n * Sync i18n-text-only present-for-join dressing — the exact `join`-layer\n * partial application `kernel/query/join.ts` used to import and call\n * directly before #626's retirement (#650 Task 6): fixes `fallback`\n * `undefined` and `layer` `'join'`. `via/lookup/snapshot.ts`'s\n * `buildPresentForJoin` composes this with the lookup-label half to build\n * the `JoinableSource.presentForJoin` hook the join executor now calls\n * instead of reaching into this module.\n */\nexport function presentI18nForJoin(\n record: Record<string, unknown>,\n i18nFields: Record<string, I18nTextDescriptor>,\n locale: string,\n): Record<string, unknown> {\n return applyI18nLocale(record, i18nFields, locale, undefined, 'join')\n}\n\n/**\n * Remove the internal densify provenance marker (`_i18nFilled`) from a\n * read-facing record. NON-mutating: returns the same object when the\n * marker is absent, otherwise a shallow copy without the marker.\n *\n * MUST be applied on every user-facing read return — even locale-less ones,\n * which bypass {@link applyI18nLocale}. MUST NOT be applied on the internal\n * prior-read path (decryptRecord / resolveDensifyPrior), where densify needs\n * the marker.\n */\nexport function stripI18nFilled<T extends Record<string, unknown>>(record: T): T {\n if (!Object.prototype.hasOwnProperty.call(record, '_i18nFilled')) return record\n const rest: T = { ...record }\n delete (rest as Record<string, unknown>)._i18nFilled\n return rest\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/with-audit/attestation/issue.ts"],"sourcesContent":["import type { NoydbStore } from '../../kernel/types.js'\nimport { buildRecordAad, buildRecordEnvelope, encrypt, type EnclaveKey } from '../../kernel/enclave/index.js'\nimport { AttestationError } from '../../kernel/errors.js'\nimport { generateULID } from '../../with-pod/ulid.js'\nimport { loadOrCreateSigner, ATTESTATIONS_COLLECTION } from './signer.js'\nimport {\n computeFieldHashes, signPayloadCore, encodeQr, bytesToB64url,\n type AttestationFieldSchema, type QrPayload,\n} from '@noy-db/attestation'\n\n/** Everything issueAttestationCore needs from the Vault, injected for testability. */\nexport interface IssueContext {\n readonly store: NoydbStore\n readonly vault: string\n readonly role: string\n /** The _attestations collection DEK (AES-KW-wrapped under KEK by the keyring). */\n getDEK(): Promise<EnclaveKey>\n /** Decrypted source record + its envelope version, or null if absent. */\n readRecord(collection: string, id: string): Promise<{ record: Record<string, unknown>; version: number } | null>\n}\n\nexport interface IssueArgs {\n readonly collection: string\n readonly id: string\n readonly fieldSchema: AttestationFieldSchema\n}\nexport interface IssueResult {\n readonly docId: string\n readonly qr: string\n readonly payload: QrPayload\n readonly keyId: string\n readonly publicKeyB64: string\n}\n\nexport async function issueAttestationCore(ctx: IssueContext, args: IssueArgs): Promise<IssueResult> {\n if (ctx.role !== 'owner') {\n throw new AttestationError(`issueAttestation requires the 'owner' role; caller is '${ctx.role}'. Issuing a signed attestation is the firm's identity operation.`)\n }\n const src = await ctx.readRecord(args.collection, args.id)\n if (!src) throw new AttestationError(`issueAttestation: source record '${args.collection}/${args.id}' not found.`)\n\n const dek = await ctx.getDEK()\n // ONE signer implementation, from signer.ts. Lazily minted + persisted.\n const signer = await loadOrCreateSigner(ctx.store, ctx.vault, () => Promise.resolve(dek))\n\n const saltB64 = bytesToB64url(crypto.getRandomValues(new Uint8Array(16)))\n let fieldHashes: string[]\n try {\n fieldHashes = await computeFieldHashes(saltB64, args.fieldSchema, src.record)\n } catch (e) {\n throw new AttestationError(`issueAttestation: ${(e as Error).message}`)\n }\n const docId = generateULID()\n\n const sig = await signPayloadCore({ v: 1, docId, salt: saltB64, keyId: signer.keyId, fieldHashes }, signer.privateKeyPkcs8B64)\n const payload: QrPayload = { v: 1, docId, salt: saltB64, alg: 'ed25519', keyId: signer.keyId, fieldHashes, sig }\n\n const index = {\n docId, issuedAt: new Date().toISOString(), keyId: signer.keyId,\n fieldPaths: args.fieldSchema.fields.map((f) => f.path),\n sourceRefs: [{ collection: args.collection, id: args.id, version: src.version }],\n }\n const identity = { collection: ATTESTATIONS_COLLECTION, id: docId, version: 1 }\n const { iv, data } = await encrypt(JSON.stringify(index), dek, buildRecordAad(identity))\n const env = buildRecordEnvelope(\n identity,\n { ts: index.issuedAt, iv, data },\n )\n await ctx.store.put(ctx.vault, ATTESTATIONS_COLLECTION, docId, env)\n\n return { docId, qr: encodeQr(payload), payload, keyId: signer.keyId, publicKeyB64: signer.publicKeyB64 }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAKA;AAAA,EACE;AAAA,EAAoB;AAAA,EAAiB;AAAA,EAAU;AAAA,OAE1C;AA0BP,eAAsB,qBAAqB,KAAmB,MAAuC;AACnG,MAAI,IAAI,SAAS,SAAS;AACxB,UAAM,IAAI,iBAAiB,0DAA0D,IAAI,IAAI,mEAAmE;AAAA,EAClK;AACA,QAAM,MAAM,MAAM,IAAI,WAAW,KAAK,YAAY,KAAK,EAAE;AACzD,MAAI,CAAC,IAAK,OAAM,IAAI,iBAAiB,oCAAoC,KAAK,UAAU,IAAI,KAAK,EAAE,cAAc;AAEjH,QAAM,MAAM,MAAM,IAAI,OAAO;AAE7B,QAAM,SAAS,MAAM,mBAAmB,IAAI,OAAO,IAAI,OAAO,MAAM,QAAQ,QAAQ,GAAG,CAAC;AAExF,QAAM,UAAU,cAAc,OAAO,gBAAgB,IAAI,WAAW,EAAE,CAAC,CAAC;AACxE,MAAI;AACJ,MAAI;AACF,kBAAc,MAAM,mBAAmB,SAAS,KAAK,aAAa,IAAI,MAAM;AAAA,EAC9E,SAAS,GAAG;AACV,UAAM,IAAI,iBAAiB,qBAAsB,EAAY,OAAO,EAAE;AAAA,EACxE;AACA,QAAM,QAAQ,aAAa;AAE3B,QAAM,MAAM,MAAM,gBAAgB,EAAE,GAAG,GAAG,OAAO,MAAM,SAAS,OAAO,OAAO,OAAO,YAAY,GAAG,OAAO,kBAAkB;AAC7H,QAAM,UAAqB,EAAE,GAAG,GAAG,OAAO,MAAM,SAAS,KAAK,WAAW,OAAO,OAAO,OAAO,aAAa,IAAI;AAE/G,QAAM,QAAQ;AAAA,IACZ;AAAA,IAAO,WAAU,oBAAI,KAAK,GAAE,YAAY;AAAA,IAAG,OAAO,OAAO;AAAA,IACzD,YAAY,KAAK,YAAY,OAAO,IAAI,CAAC,MAAM,EAAE,IAAI;AAAA,IACrD,YAAY,CAAC,EAAE,YAAY,KAAK,YAAY,IAAI,KAAK,IAAI,SAAS,IAAI,QAAQ,CAAC;AAAA,EACjF;AACA,QAAM,WAAW,EAAE,YAAY,yBAAyB,IAAI,OAAO,SAAS,EAAE;AAC9E,QAAM,EAAE,IAAI,KAAK,IAAI,MAAM,QAAQ,KAAK,UAAU,KAAK,GAAG,KAAK,eAAe,QAAQ,CAAC;AACvF,QAAM,MAAM;AAAA,IACV;AAAA,IACA,EAAE,IAAI,MAAM,UAAU,IAAI,KAAK;AAAA,EACjC;AACA,QAAM,IAAI,MAAM,IAAI,IAAI,OAAO,yBAAyB,OAAO,GAAG;AAElE,SAAO,EAAE,OAAO,IAAI,SAAS,OAAO,GAAG,SAAS,OAAO,OAAO,OAAO,cAAc,OAAO,aAAa;AACzG;","names":[]}
|