@noy-db/hub 0.7.1-pre.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +147 -14
- package/LICENSE +202 -21
- package/NOTICE +1 -0
- package/README.md +5 -5
- package/codemods/0.8.0-pre.json +61 -0
- package/dist/api-OS747DS4.js +18 -0
- package/dist/as/index.js +11 -12
- package/dist/as/index.js.map +1 -1
- package/dist/at/index.js +9 -10
- package/dist/attestation/index.js +37 -26
- package/dist/attestation/index.js.map +1 -1
- package/dist/{backup-XKCXVKV3.js → backup-YE2VQ26S.js} +15 -16
- package/dist/backup-YE2VQ26S.js.map +1 -0
- package/dist/blobs/index.js +13 -14
- package/dist/blobs/index.js.map +1 -1
- package/dist/broker/index.js +12 -13
- package/dist/broker/index.js.map +1 -1
- package/dist/by/index.js +2 -2
- package/dist/capsule/contract.d.ts +159 -0
- package/dist/capsule/contract.js +95 -0
- package/dist/capsule/enclave-aes/bound.d.ts +52 -0
- package/dist/capsule/enclave-aes/capabilities.d.ts +2 -0
- package/dist/capsule/enclave-aes/classify/compare.d.ts +20 -0
- package/dist/{kernel/enclave → capsule/enclave-aes}/classify/find.d.ts +1 -1
- package/dist/{kernel/enclave → capsule/enclave-aes}/classify/reveal.d.ts +1 -1
- package/dist/{kernel/enclave → capsule/enclave-aes}/classify/verify.d.ts +2 -2
- package/dist/{kernel/enclave → capsule/enclave-aes}/classify/write.d.ts +1 -1
- package/dist/{kernel/enclave → capsule/enclave-aes}/crypto.d.ts +33 -129
- package/dist/capsule/enclave-aes/index.d.ts +113 -0
- package/dist/capsule/enclave-aes/index.js +335 -0
- package/dist/capsule/enclave-aes/index.js.map +1 -0
- package/dist/capsule/enclave-aes/primitives.d.ts +29 -0
- package/dist/capsule/index.d.ts +27 -0
- package/dist/capsule/plumbing/ct-equal.d.ts +11 -0
- package/dist/{kernel/enclave/record-keys → capsule/plumbing}/deterministic.d.ts +8 -21
- package/dist/capsule/plumbing/digest.d.ts +122 -0
- package/dist/{kernel/enclave/record-keys → capsule/plumbing}/envelope-body.d.ts +44 -48
- package/dist/capsule/plumbing/index.d.ts +100 -0
- package/dist/capsule/plumbing/lifecycle.d.ts +50 -0
- package/dist/{kernel/enclave/record-keys → capsule/plumbing}/record-codec.d.ts +80 -20
- package/dist/{kernel/enclave → capsule/plumbing}/record-envelope.d.ts +1 -1
- package/dist/capsule/plumbing/rekey-blob.d.ts +33 -0
- package/dist/capsule/plumbing/rekey.d.ts +44 -0
- package/dist/capsule/plumbing/sealed-slot.d.ts +22 -0
- package/dist/capsule/plumbing/sealed-slots.d.ts +37 -0
- package/dist/capsule/plumbing/sealing.d.ts +29 -0
- package/dist/capsule/plumbing/sign.d.ts +9 -0
- package/dist/{kernel/enclave/record-keys → capsule/plumbing}/tombstone.d.ts +2 -2
- package/dist/capsule-VOLX3QRQ.js +209 -0
- package/dist/cargo/index.js +39 -36
- package/dist/{chunk-Q2MPFCQ7.js → chunk-23D6M6VM.js} +5 -5
- package/dist/chunk-23D6M6VM.js.map +1 -0
- package/dist/{chunk-R7BX2NB3.js → chunk-244QBK7Z.js} +4 -4
- package/dist/chunk-244QBK7Z.js.map +1 -0
- package/dist/chunk-2AFX33YA.js +936 -0
- package/dist/chunk-2AFX33YA.js.map +1 -0
- package/dist/{chunk-MVMXZYXT.js → chunk-2GHDLTPE.js} +2 -2
- package/dist/{chunk-GYGLAVCX.js → chunk-2MG3SW7Q.js} +6 -2
- package/dist/chunk-2MG3SW7Q.js.map +1 -0
- package/dist/{chunk-XLMEZIAJ.js → chunk-2ODVB6LZ.js} +2 -2
- package/dist/{chunk-HJUWN7JN.js → chunk-2PVXF5CS.js} +33 -8
- package/dist/chunk-2PVXF5CS.js.map +1 -0
- package/dist/{chunk-YJRT5UQM.js → chunk-2RH777HH.js} +21 -20
- package/dist/{chunk-YJRT5UQM.js.map → chunk-2RH777HH.js.map} +1 -1
- package/dist/{chunk-7O3Y4PPD.js → chunk-37EPTBBR.js} +153 -16
- package/dist/chunk-37EPTBBR.js.map +1 -0
- package/dist/{chunk-2ENE6445.js → chunk-3A5DUZ56.js} +102 -16
- package/dist/chunk-3A5DUZ56.js.map +1 -0
- package/dist/chunk-3EWS67C7.js +461 -0
- package/dist/chunk-3EWS67C7.js.map +1 -0
- package/dist/{chunk-SGZAIJCV.js → chunk-3L2NBKDR.js} +4 -8
- package/dist/chunk-3L2NBKDR.js.map +1 -0
- package/dist/{chunk-YMUFFJCO.js → chunk-3TDUWVWB.js} +5 -2
- package/dist/chunk-3TDUWVWB.js.map +1 -0
- package/dist/{chunk-4GVM6QZA.js → chunk-3XJQBBZD.js} +26 -28
- package/dist/chunk-3XJQBBZD.js.map +1 -0
- package/dist/{chunk-4ZS56W5S.js → chunk-42ALPZ2B.js} +672 -664
- package/dist/chunk-42ALPZ2B.js.map +1 -0
- package/dist/chunk-4CIQDWRB.js +524 -0
- package/dist/chunk-4CIQDWRB.js.map +1 -0
- package/dist/{chunk-RMS3NEA3.js → chunk-4JPMZTJY.js} +2 -2
- package/dist/{chunk-P3MG6QCN.js → chunk-4T3SE27M.js} +5 -9
- package/dist/chunk-4T3SE27M.js.map +1 -0
- package/dist/chunk-4V3Q35WG.js +204 -0
- package/dist/chunk-4V3Q35WG.js.map +1 -0
- package/dist/{chunk-NQKIUNW5.js → chunk-52MGURXO.js} +2 -2
- package/dist/{chunk-EQEYOJBM.js → chunk-5A4345TG.js} +4 -4
- package/dist/chunk-5A4345TG.js.map +1 -0
- package/dist/{chunk-334WSVOW.js → chunk-5FE75J4S.js} +6 -6
- package/dist/chunk-5FE75J4S.js.map +1 -0
- package/dist/chunk-5KC7QYEC.js +565 -0
- package/dist/chunk-5KC7QYEC.js.map +1 -0
- package/dist/{chunk-RSGLUIO6.js → chunk-5UMK7GRI.js} +13 -12
- package/dist/chunk-5UMK7GRI.js.map +1 -0
- package/dist/chunk-5WWDGFOS.js +275 -0
- package/dist/chunk-5WWDGFOS.js.map +1 -0
- package/dist/{chunk-QPQUVOZ2.js → chunk-6QVKPHBF.js} +3 -5
- package/dist/chunk-6QVKPHBF.js.map +1 -0
- package/dist/{chunk-ACAQ2DSG.js → chunk-747G6CT3.js} +2 -2
- package/dist/chunk-747G6CT3.js.map +1 -0
- package/dist/{chunk-QTQUH4DS.js → chunk-7R2Q7CPL.js} +16 -16
- package/dist/chunk-7R2Q7CPL.js.map +1 -0
- package/dist/{chunk-UGTBXF5U.js → chunk-7XMHMVTS.js} +3 -3
- package/dist/{chunk-YJX7EOJD.js → chunk-A4XMIZT3.js} +6 -6
- package/dist/{chunk-YJX7EOJD.js.map → chunk-A4XMIZT3.js.map} +1 -1
- package/dist/{chunk-A66I4JOA.js → chunk-AEQGFRU4.js} +4 -4
- package/dist/chunk-AEQGFRU4.js.map +1 -0
- package/dist/chunk-AL6ML4LA.js +1558 -0
- package/dist/chunk-AL6ML4LA.js.map +1 -0
- package/dist/{chunk-BZ3534YM.js → chunk-AUKKUPVB.js} +2 -2
- package/dist/{chunk-CUZLNGD5.js → chunk-B2YY6WDD.js} +1 -1
- package/dist/chunk-B2YY6WDD.js.map +1 -0
- package/dist/chunk-BKT776R5.js +1 -0
- package/dist/chunk-BNWA3WG5.js +22 -0
- package/dist/chunk-BNWA3WG5.js.map +1 -0
- package/dist/{chunk-VXANTWBJ.js → chunk-BPWYQ25R.js} +92 -6
- package/dist/{chunk-VXANTWBJ.js.map → chunk-BPWYQ25R.js.map} +1 -1
- package/dist/{chunk-6LKOJBV6.js → chunk-BVCUTXE3.js} +2 -2
- package/dist/chunk-CY2CYVWZ.js +41 -0
- package/dist/chunk-CY2CYVWZ.js.map +1 -0
- package/dist/{chunk-M4YPHYEH.js → chunk-DHHGL42E.js} +70 -25
- package/dist/chunk-DHHGL42E.js.map +1 -0
- package/dist/{chunk-VTFVLCUH.js → chunk-DIZLQVAA.js} +2 -2
- package/dist/{chunk-G73UVHCA.js → chunk-DLD5LGDS.js} +11 -12
- package/dist/chunk-DLD5LGDS.js.map +1 -0
- package/dist/{chunk-WQBG4SZS.js → chunk-DQESF6RP.js} +60 -49
- package/dist/chunk-DQESF6RP.js.map +1 -0
- package/dist/{chunk-LWBCUYZW.js → chunk-E2N2T5ZO.js} +2 -2
- package/dist/{chunk-3PGS7TYR.js → chunk-EGVJ7TM4.js} +29 -32
- package/dist/chunk-EGVJ7TM4.js.map +1 -0
- package/dist/{chunk-JVIBCBC7.js → chunk-EJLV62NI.js} +2 -2
- package/dist/{chunk-KKEESNPE.js → chunk-EYG2CY2X.js} +126 -19
- package/dist/chunk-EYG2CY2X.js.map +1 -0
- package/dist/{enclave-55PAM4YO.js → chunk-EZGV6F47.js} +83 -56
- package/dist/chunk-EZGV6F47.js.map +1 -0
- package/dist/{chunk-CHQCZZWC.js → chunk-EZOAKKTB.js} +36 -27
- package/dist/chunk-EZOAKKTB.js.map +1 -0
- package/dist/chunk-F6NCB7KT.js +13 -0
- package/dist/chunk-F6NCB7KT.js.map +1 -0
- package/dist/chunk-FFJFE4T7.js +100 -0
- package/dist/chunk-FFJFE4T7.js.map +1 -0
- package/dist/{chunk-JMGDHKQF.js → chunk-FLPCETP6.js} +2 -2
- package/dist/chunk-FOEDQATO.js +53 -0
- package/dist/chunk-FOEDQATO.js.map +1 -0
- package/dist/{chunk-DGOZ4UZD.js → chunk-FVH5QYY2.js} +2 -2
- package/dist/{chunk-HIWCKBEY.js → chunk-G2MVBDFP.js} +54 -28
- package/dist/chunk-G2MVBDFP.js.map +1 -0
- package/dist/chunk-GMKGGY7V.js +234 -0
- package/dist/chunk-GMKGGY7V.js.map +1 -0
- package/dist/{chunk-EIPVYUEP.js → chunk-GQ4MF3CM.js} +3 -3
- package/dist/chunk-GQ4MF3CM.js.map +1 -0
- package/dist/{chunk-PEOZ34EM.js → chunk-GSAK56VF.js} +1 -1
- package/dist/chunk-GSAK56VF.js.map +1 -0
- package/dist/{chunk-5VCRVKOZ.js → chunk-GUZET4SG.js} +12 -4
- package/dist/chunk-GUZET4SG.js.map +1 -0
- package/dist/{chunk-JBDFMYKQ.js → chunk-GZT3NQRA.js} +2 -2
- package/dist/{chunk-K23VKTN4.js → chunk-H23XHRTT.js} +19 -34
- package/dist/chunk-H23XHRTT.js.map +1 -0
- package/dist/{chunk-TFR7DSOV.js → chunk-H427H63K.js} +2 -2
- package/dist/{chunk-DFMWUOU5.js → chunk-H7JBY4P7.js} +23 -32
- package/dist/chunk-H7JBY4P7.js.map +1 -0
- package/dist/{chunk-SKGMN35F.js → chunk-HS554XAF.js} +3 -3
- package/dist/chunk-HS554XAF.js.map +1 -0
- package/dist/{chunk-HK67PX4J.js → chunk-HW7CMKUG.js} +1 -1
- package/dist/chunk-HW7CMKUG.js.map +1 -0
- package/dist/{chunk-3BVH633C.js → chunk-IMQKWR46.js} +5 -7
- package/dist/chunk-IMQKWR46.js.map +1 -0
- package/dist/{chunk-R42NSZI6.js → chunk-IUBMZPHM.js} +7 -7
- package/dist/chunk-IUBMZPHM.js.map +1 -0
- package/dist/{chunk-CUQPWYRX.js → chunk-IUT3GWP3.js} +75 -386
- package/dist/chunk-IUT3GWP3.js.map +1 -0
- package/dist/{chunk-RF6D3Y5E.js → chunk-JDEYF3PJ.js} +4 -8
- package/dist/{chunk-RF6D3Y5E.js.map → chunk-JDEYF3PJ.js.map} +1 -1
- package/dist/{chunk-PPTHY5QO.js → chunk-JIBUPZHA.js} +99 -8
- package/dist/chunk-JIBUPZHA.js.map +1 -0
- package/dist/{chunk-SMH6SRX7.js → chunk-JOSPH3E5.js} +2 -2
- package/dist/chunk-JQYKPKG6.js +193 -0
- package/dist/chunk-JQYKPKG6.js.map +1 -0
- package/dist/{chunk-7APJ6CO6.js → chunk-JSMTXZR3.js} +45 -13
- package/dist/chunk-JSMTXZR3.js.map +1 -0
- package/dist/chunk-JWWYRR4Q.js +12 -0
- package/dist/chunk-JWWYRR4Q.js.map +1 -0
- package/dist/{chunk-BVN6KXL2.js → chunk-KZXDLBY6.js} +14 -9
- package/dist/chunk-KZXDLBY6.js.map +1 -0
- package/dist/chunk-LGNDFRYC.js +23 -0
- package/dist/chunk-LGNDFRYC.js.map +1 -0
- package/dist/{chunk-XKWGNJ26.js → chunk-LIOVX5TJ.js} +7 -11
- package/dist/chunk-LIOVX5TJ.js.map +1 -0
- package/dist/{chunk-AYX7AINO.js → chunk-LNSVGRHO.js} +5 -7
- package/dist/chunk-LNSVGRHO.js.map +1 -0
- package/dist/chunk-M5B2W6YY.js +293 -0
- package/dist/chunk-M5B2W6YY.js.map +1 -0
- package/dist/chunk-MBMTND6D.js +456 -0
- package/dist/chunk-MBMTND6D.js.map +1 -0
- package/dist/{chunk-3BZZJJMQ.js → chunk-MILI22XQ.js} +3 -3
- package/dist/{chunk-A2HKRLPV.js → chunk-MXKI4ABF.js} +18 -59
- package/dist/chunk-MXKI4ABF.js.map +1 -0
- package/dist/{chunk-ZYIYHJ5R.js → chunk-MXOQ5JCG.js} +869 -238
- package/dist/chunk-MXOQ5JCG.js.map +1 -0
- package/dist/{chunk-V7ZRRCRJ.js → chunk-N7EVQD5S.js} +9 -13
- package/dist/chunk-N7EVQD5S.js.map +1 -0
- package/dist/chunk-N7UDP5VU.js +757 -0
- package/dist/chunk-N7UDP5VU.js.map +1 -0
- package/dist/chunk-NBQ3KK6X.js +270 -0
- package/dist/chunk-NBQ3KK6X.js.map +1 -0
- package/dist/{chunk-ZORTV6NH.js → chunk-NCO25JZO.js} +88 -4
- package/dist/chunk-NCO25JZO.js.map +1 -0
- package/dist/chunk-NH2UOV3B.js +18 -0
- package/dist/chunk-NH2UOV3B.js.map +1 -0
- package/dist/chunk-NYMLINRP.js +28 -0
- package/dist/chunk-NYMLINRP.js.map +1 -0
- package/dist/{chunk-YYP7WSEB.js → chunk-O2IMQSNA.js} +2 -2
- package/dist/chunk-O46CHQT7.js +215 -0
- package/dist/chunk-O46CHQT7.js.map +1 -0
- package/dist/chunk-OIEO4WDL.js +27 -0
- package/dist/chunk-OIEO4WDL.js.map +1 -0
- package/dist/{chunk-TRGTKX5E.js → chunk-OKSTSITU.js} +27 -4
- package/dist/chunk-OKSTSITU.js.map +1 -0
- package/dist/chunk-OYW3I5M4.js +31 -0
- package/dist/chunk-OYW3I5M4.js.map +1 -0
- package/dist/{chunk-Q7HZX3IF.js → chunk-PD64727P.js} +2 -2
- package/dist/chunk-PD64727P.js.map +1 -0
- package/dist/{chunk-FET5XCAT.js → chunk-PP3K67AJ.js} +34 -6
- package/dist/chunk-PP3K67AJ.js.map +1 -0
- package/dist/chunk-Q2XRFWOI.js +40 -0
- package/dist/chunk-Q2XRFWOI.js.map +1 -0
- package/dist/{chunk-QIZPZMUI.js → chunk-Q4UHJ5SN.js} +2 -2
- package/dist/{chunk-FAHMLERK.js → chunk-QBLT6POL.js} +2 -2
- package/dist/chunk-QMWY2FDS.js +157 -0
- package/dist/chunk-QMWY2FDS.js.map +1 -0
- package/dist/{chunk-LH5A3ZPG.js → chunk-RB4DOPGZ.js} +150 -22
- package/dist/chunk-RB4DOPGZ.js.map +1 -0
- package/dist/chunk-RHVMZSUU.js +7 -0
- package/dist/chunk-RHVMZSUU.js.map +1 -0
- package/dist/{chunk-BUE2D7PX.js → chunk-SMV2HRDU.js} +2 -2
- package/dist/chunk-SUZKW6UR.js +25 -0
- package/dist/chunk-SUZKW6UR.js.map +1 -0
- package/dist/{chunk-7MG7SJT7.js → chunk-SV2PM2OY.js} +1 -1
- package/dist/chunk-SV2PM2OY.js.map +1 -0
- package/dist/{chunk-UXVWEX5L.js → chunk-SYNY3VB5.js} +6 -2
- package/dist/chunk-SYNY3VB5.js.map +1 -0
- package/dist/{chunk-4GFX6MPA.js → chunk-TEHHROZL.js} +6 -8
- package/dist/chunk-TEHHROZL.js.map +1 -0
- package/dist/chunk-TKVUE4JF.js +1289 -0
- package/dist/chunk-TKVUE4JF.js.map +1 -0
- package/dist/{chunk-SFAWCTEM.js → chunk-TZZBXPZK.js} +2 -2
- package/dist/{chunk-F3W6YMDC.js → chunk-U2FZNEWJ.js} +4 -4
- package/dist/chunk-U2FZNEWJ.js.map +1 -0
- package/dist/{chunk-BLN54W3L.js → chunk-UA372JHH.js} +56 -3
- package/dist/chunk-UA372JHH.js.map +1 -0
- package/dist/{chunk-6YXCPL4T.js → chunk-UEFOQH74.js} +2 -2
- package/dist/chunk-UEFOQH74.js.map +1 -0
- package/dist/{chunk-2N5ML6HT.js → chunk-UIYESRD6.js} +9 -11
- package/dist/chunk-UIYESRD6.js.map +1 -0
- package/dist/{chunk-UHHPLO3I.js → chunk-V3RWOOSO.js} +4 -4
- package/dist/{chunk-KTFRCC5C.js → chunk-V7ADQF5O.js} +82 -8
- package/dist/chunk-V7ADQF5O.js.map +1 -0
- package/dist/{chunk-453F654R.js → chunk-VAORSCSU.js} +3 -3
- package/dist/chunk-VAORSCSU.js.map +1 -0
- package/dist/{chunk-GPNTB4Y7.js → chunk-VFHCKG5M.js} +6 -10
- package/dist/chunk-VFHCKG5M.js.map +1 -0
- package/dist/{chunk-2577DKXB.js → chunk-VHBKYN2J.js} +3 -3
- package/dist/chunk-VHBKYN2J.js.map +1 -0
- package/dist/chunk-VHM7HCKB.js +220 -0
- package/dist/chunk-VHM7HCKB.js.map +1 -0
- package/dist/{chunk-ZHKOPKE3.js → chunk-VKI2EB3N.js} +3 -3
- package/dist/chunk-VKI2EB3N.js.map +1 -0
- package/dist/{chunk-UDHWDSRL.js → chunk-VMV5SBE4.js} +16 -17
- package/dist/chunk-VMV5SBE4.js.map +1 -0
- package/dist/{chunk-SPYWXKJN.js → chunk-VQDZYB2B.js} +3 -3
- package/dist/chunk-VQDZYB2B.js.map +1 -0
- package/dist/{chunk-Q2PU57HC.js → chunk-VVOLDVIR.js} +2 -2
- package/dist/{chunk-3VF3WQ4F.js → chunk-WPOYWFSE.js} +7 -7
- package/dist/{chunk-3VF3WQ4F.js.map → chunk-WPOYWFSE.js.map} +1 -1
- package/dist/{chunk-OTQZ7ZWU.js → chunk-WXE4W2U6.js} +7 -11
- package/dist/chunk-WXE4W2U6.js.map +1 -0
- package/dist/chunk-XBKH4FOC.js +195 -0
- package/dist/chunk-XBKH4FOC.js.map +1 -0
- package/dist/{chunk-TUFM4UZP.js → chunk-XQRFSKYM.js} +2 -2
- package/dist/{chunk-3V4KWFX7.js → chunk-XSPFDUDG.js} +58 -53
- package/dist/chunk-XSPFDUDG.js.map +1 -0
- package/dist/{chunk-GY4WYNNG.js → chunk-Y2RKVFKR.js} +2 -2
- package/dist/{chunk-UP4BECPY.js → chunk-Y3LPTBG7.js} +89 -27
- package/dist/chunk-Y3LPTBG7.js.map +1 -0
- package/dist/{chunk-4OZNXTO4.js → chunk-YRXFFWG4.js} +2 -2
- package/dist/classified/index.js +5 -5
- package/dist/{classified-marker-BWOFVYAC.js → classified-marker-SIYKUU5L.js} +3 -3
- package/dist/classified-marker-SIYKUU5L.js.map +1 -0
- package/dist/collection-facade-CS7CA2XO.js +47 -0
- package/dist/{computed-VPOKQK4N.js → computed-FAD7SED4.js} +3 -3
- package/dist/consent/index.js +10 -11
- package/dist/consent/index.js.map +1 -1
- package/dist/cover/index.js +10 -11
- package/dist/coverage/index.js +306 -0
- package/dist/coverage/index.js.map +1 -0
- package/dist/custody/index.js +12 -13
- package/dist/{dead-filter-PKQDLOT4.js → dead-filter-4F3LWYKH.js} +11 -3
- package/dist/dead-filter-4F3LWYKH.js.map +1 -0
- package/dist/debug/index.js +11 -2
- package/dist/debug/index.js.map +1 -1
- package/dist/{delegation-DS5NRILW.js → delegation-NANZDG4N.js} +13 -16
- package/dist/delegation-NANZDG4N.js.map +1 -0
- package/dist/derivations/index.js +25 -23
- package/dist/derive-XLOJVXPU.js +20 -0
- package/dist/directory/index.js +10 -11
- package/dist/{dispatch-IEPAVQUM.js → dispatch-H4HV32AM.js} +5 -5
- package/dist/{dispatch-Q6MWLOJY.js → dispatch-JDZNGEB3.js} +20 -21
- package/dist/dispatch-JDZNGEB3.js.map +1 -0
- package/dist/executor-FMPVN6DT.js +35 -0
- package/dist/executor-LBBBRTN5.js +8 -0
- package/dist/executor-OSRZST2U.js +8 -0
- package/dist/export-accessible-RAOJAAU5.js +22 -0
- package/dist/extract-partition-JD5CUSTG.js +37 -0
- package/dist/{fanout-sidecar-S3QL53YX.js → fanout-sidecar-L7NHPIOC.js} +13 -15
- package/dist/fanout-sidecar-L7NHPIOC.js.map +1 -0
- package/dist/find-JRN4RNQ5.js +10 -0
- package/dist/forget/index.js +9 -10
- package/dist/forget/index.js.map +1 -1
- package/dist/guards/index.js +4 -4
- package/dist/history/index.js +13 -14
- package/dist/history/index.js.map +1 -1
- package/dist/i18n/index.js +14 -15
- package/dist/i18n/index.js.map +1 -1
- package/dist/index.d.ts +36 -14
- package/dist/index.js +970 -163
- package/dist/index.js.map +1 -1
- package/dist/indexing/index.js +13 -5
- package/dist/indexing/index.js.map +1 -1
- package/dist/introspection/index.js +11 -12
- package/dist/issue-YIVBZUTH.js +19 -0
- package/dist/ivf-flat-UZ6DQDLS.js +314 -0
- package/dist/ivf-flat-UZ6DQDLS.js.map +1 -0
- package/dist/{json-schema-V3M5MUCM.js → json-schema-3SHX72CC.js} +2 -1
- package/dist/json-schema-3SHX72CC.js.map +1 -0
- package/dist/kernel/attestation-types.d.ts +62 -0
- package/dist/kernel/collection-config.d.ts +5 -68
- package/dist/kernel/collection.d.ts +30 -9
- package/dist/kernel/cutover-transform.d.ts +1 -1
- package/dist/kernel/errors.d.ts +257 -38
- package/dist/kernel/generation-map.d.ts +48 -0
- package/dist/kernel/merge-authority.d.ts +1 -1
- package/dist/kernel/noydb.d.ts +6 -1
- package/dist/kernel/paths.d.ts +29 -5
- package/dist/kernel/prepared-write.d.ts +1 -1
- package/dist/kernel/present-cache.d.ts +58 -0
- package/dist/kernel/query/all.d.ts +7 -0
- package/dist/kernel/query/builder.d.ts +601 -270
- package/dist/kernel/query/civil-date.d.ts +64 -0
- package/dist/kernel/query/cursor.d.ts +40 -0
- package/dist/kernel/query/distinct-key.d.ts +98 -0
- package/dist/kernel/query/hydration.d.ts +76 -0
- package/dist/kernel/query/index.d.ts +31 -15
- package/dist/kernel/query/internal/core.d.ts +30 -0
- package/dist/kernel/query/internal/hooks.d.ts +22 -0
- package/dist/kernel/query/internal/maintenance.d.ts +43 -0
- package/dist/kernel/query/live/incremental.d.ts +314 -0
- package/dist/kernel/query/live/index.d.ts +22 -0
- package/dist/kernel/query/live/install.d.ts +2 -0
- package/dist/kernel/query/{live.d.ts → live/live.d.ts} +39 -9
- package/dist/kernel/query/live/methods.d.ts +107 -0
- package/dist/kernel/query/predicate.d.ts +119 -1
- package/dist/kernel/query/reduce/date-trunc.d.ts +75 -0
- package/dist/kernel/query/reduce/index.d.ts +36 -0
- package/dist/kernel/query/reduce/install.d.ts +2 -0
- package/dist/kernel/query/reduce/methods.d.ts +259 -0
- package/dist/kernel/query/reduce/scan-methods.d.ts +121 -0
- package/dist/kernel/query/relate/explain.d.ts +199 -0
- package/dist/kernel/query/relate/index.d.ts +48 -0
- package/dist/kernel/query/relate/install.d.ts +2 -0
- package/dist/kernel/query/relate/join-on.d.ts +126 -0
- package/dist/kernel/query/relate/join-reduce.d.ts +16 -0
- package/dist/kernel/query/relate/join.d.ts +452 -0
- package/dist/kernel/query/relate/methods.d.ts +426 -0
- package/dist/kernel/query/relate/partition.d.ts +87 -0
- package/dist/kernel/query/relate/scan-methods.d.ts +163 -0
- package/dist/kernel/query/relate/traverse.d.ts +109 -0
- package/dist/kernel/query/scan-builder.d.ts +79 -176
- package/dist/kernel/query/sort-key.d.ts +52 -0
- package/dist/kernel/secret-mode.d.ts +1 -1
- package/dist/kernel/tx-write-gate.d.ts +77 -0
- package/dist/kernel/types.d.ts +113 -8
- package/dist/kernel/validation.d.ts +27 -10
- package/dist/kernel/vault.d.ts +11 -6
- package/dist/kernel/via/compose.d.ts +3 -0
- package/dist/kernel/via/index.d.ts +56 -0
- package/dist/kernel/via/pipeline.d.ts +48 -0
- package/dist/kernel/write-queue.d.ts +17 -0
- package/dist/{ledger-EDXFFZQL.js → ledger-5ZMGE44K.js} +11 -12
- package/dist/liberate-WZSZM2W6.js +24 -0
- package/dist/link-set-MFXC24VK.js +29 -0
- package/dist/{managed-secret-NCWEMPUQ.js → managed-secret-MFTFT22X.js} +10 -11
- package/dist/materialized-views/index.js +30 -24
- package/dist/{migrate-cek-5ENH64AA.js → migrate-cek-DZRFFOHW.js} +2 -2
- package/dist/money/index.js +5 -5
- package/dist/noydb-ITIGNKUF.js +96 -0
- package/dist/overlay-views/index.js +4 -4
- package/dist/periods/index.js +12 -13
- package/dist/pod/index.js +74 -67
- package/dist/{pod-handle-ECVCDIXW.js → pod-handle-A3LET7NO.js} +10 -11
- package/dist/pod-handle-A3LET7NO.js.map +1 -0
- package/dist/policy/index.js +10 -11
- package/dist/port/on/index.d.ts +1 -1
- package/dist/port/to/index.d.ts +1 -1
- package/dist/port/with/blob-strategy.d.ts +10 -1
- package/dist/port/with/classified-strategy.d.ts +1 -1
- package/dist/port/with/collection-options.d.ts +6 -1
- package/dist/port/with/collection-registries.d.ts +1 -1
- package/dist/port/with/coverage-strategy.d.ts +83 -0
- package/dist/port/with/lookup-strategy.d.ts +2 -2
- package/dist/port/with/service-bus.d.ts +46 -0
- package/dist/port/with/strategies.d.ts +2 -0
- package/dist/portability/index.js +8 -8
- package/dist/{post-register-3IPCSG6Q.js → post-register-7ND27CF2.js} +6 -6
- package/dist/post-register-7ND27CF2.js.map +1 -0
- package/dist/query/all/index.js +31 -0
- package/dist/query/index.js +20 -32
- package/dist/query/live/index.js +21 -0
- package/dist/query/live/index.js.map +1 -0
- package/dist/query/reduce/index.js +33 -0
- package/dist/query/reduce/index.js.map +1 -0
- package/dist/query/relate/index.js +56 -0
- package/dist/query/relate/index.js.map +1 -0
- package/dist/reduce/index.js +72 -18
- package/dist/reduce/index.js.map +1 -1
- package/dist/register-DT5HZ2LZ.js +30 -0
- package/dist/registry-BHRZGZHF.js +8 -0
- package/dist/registry-ET6ZFFWA.js +34 -0
- package/dist/registry-HXFGLGTG.js +8 -0
- package/dist/registry-THCPDEOD.js +23 -0
- package/dist/request-withdrawal-AV2MJJKY.js +30 -0
- package/dist/{reveal-QZDHSGD4.js → reveal-B2TLP4JQ.js} +10 -9
- package/dist/reveal-B2TLP4JQ.js.map +1 -0
- package/dist/revoke-6DWIEOCV.js +24 -0
- package/dist/satellites/index.js +1 -1
- package/dist/schema-update/index.js +2 -2
- package/dist/sealed-record/index.js +16 -18
- package/dist/sealed-record/index.js.map +1 -1
- package/dist/search/index.js +11 -5
- package/dist/{seed-X5CC22CQ.js → seed-XNSE4U3S.js} +15 -18
- package/dist/seed-XNSE4U3S.js.map +1 -0
- package/dist/sequence/index.js +9 -10
- package/dist/session/index.js +9 -10
- package/dist/session/index.js.map +1 -1
- package/dist/shadow/index.js +2 -2
- package/dist/signer-MHGW3OIL.js +23 -0
- package/dist/snapshots/index.js +11 -11
- package/dist/stale-6GCFMOOR.js +28 -0
- package/dist/storage-BYN5LO6Z.js +21 -0
- package/dist/storage-BYN5LO6Z.js.map +1 -0
- package/dist/store/index.js +1 -1
- package/dist/{store-coordination-provider-4WZAIRHC.js → store-coordination-provider-C4BPT5XF.js} +11 -12
- package/dist/store-coordination-provider-C4BPT5XF.js.map +1 -0
- package/dist/sync/index.js +10 -11
- package/dist/sync/index.js.map +1 -1
- package/dist/team/index.js +17 -16
- package/dist/tiers/index.js +13 -12
- package/dist/to/index.js +2 -2
- package/dist/transactions/index.js +3 -3
- package/dist/util/index.js +1 -1
- package/dist/vault-head/index.js +11 -14
- package/dist/vault-head/index.js.map +1 -1
- package/dist/{verify-6MDTIUEV.js → verify-UKALW7C2.js} +14 -12
- package/dist/verify-UKALW7C2.js.map +1 -0
- package/dist/via/blob/index.d.ts +1 -0
- package/dist/via/classified/binding.d.ts +2 -2
- package/dist/via/classified/config-drift.d.ts +2 -2
- package/dist/via/classified/errors.d.ts +1 -1
- package/dist/via/geo/binding.d.ts +31 -0
- package/dist/via/geo/descriptor.d.ts +54 -0
- package/dist/via/geo/geohash.d.ts +95 -0
- package/dist/via/geo/index.d.ts +13 -0
- package/dist/via/geo/where.d.ts +50 -0
- package/dist/via/i18n/core.d.ts +1 -1
- package/dist/via/lookup/handle.d.ts +4 -4
- package/dist/via/lookup/registry.d.ts +1 -1
- package/dist/via/lookup/snapshot.d.ts +3 -3
- package/dist/walk-4VPK7AS4.js +20 -0
- package/dist/walk-4VPK7AS4.js.map +1 -0
- package/dist/with-audit/attestation/index.d.ts +2 -1
- package/dist/with-audit/attestation/issue.d.ts +2 -2
- package/dist/with-audit/attestation/revoke.d.ts +2 -2
- package/dist/with-audit/attestation/scheme.d.ts +7 -0
- package/dist/with-audit/attestation/signer.d.ts +1 -1
- package/dist/with-audit/attestation/strategy.d.ts +2 -2
- package/dist/with-audit/attestation/types.d.ts +10 -0
- package/dist/with-audit/attestation/vault-facade.d.ts +2 -2
- package/dist/with-audit/attestation/verifier.d.ts +6 -0
- package/dist/with-audit/consent/consent.d.ts +1 -1
- package/dist/with-audit/consent/strategy.d.ts +1 -1
- package/dist/with-audit/coverage/accounting.d.ts +112 -0
- package/dist/with-audit/coverage/active.d.ts +29 -0
- package/dist/with-audit/coverage/index.d.ts +61 -0
- package/dist/with-audit/coverage/sketch.d.ts +75 -0
- package/dist/with-audit/forget/subject-index.d.ts +1 -1
- package/dist/with-audit/periods/periods.d.ts +55 -7
- package/dist/with-audit/periods/reserved-collections.d.ts +3 -0
- package/dist/with-audit/periods/vault-facade.d.ts +18 -1
- package/dist/with-audit/sealed-record/index.d.ts +2 -2
- package/dist/with-audit/sealed-record/strategy.d.ts +1 -1
- package/dist/with-audit/tiers/index.d.ts +53 -2
- package/dist/with-audit/tiers/strategy.d.ts +8 -0
- package/dist/with-cargo/adopt-partition.d.ts +1 -1
- package/dist/with-cargo/extract-partition.d.ts +1 -1
- package/dist/with-cargo/floor.d.ts +3 -3
- package/dist/with-commit/history/history.d.ts +2 -2
- package/dist/with-commit/history/index.d.ts +1 -1
- package/dist/with-commit/history/ledger/store.d.ts +1 -1
- package/dist/with-commit/history/strategy.d.ts +1 -1
- package/dist/with-commit/history/time-machine.d.ts +1 -1
- package/dist/with-commit/numbering/index.d.ts +1 -1
- package/dist/with-commit/sequence/index.d.ts +1 -1
- package/dist/with-commit/tx/invariants.d.ts +1 -1
- package/dist/with-commit/tx/transaction.d.ts +13 -3
- package/dist/with-commit/vault-head/head.d.ts +1 -1
- package/dist/with-commit/vault-head/index.d.ts +1 -1
- package/dist/with-commit/vault-head/strategy.d.ts +1 -1
- package/dist/with-commit/vault-head/verify.d.ts +1 -1
- package/dist/with-formula/derivations/dispatch.d.ts +1 -1
- package/dist/with-formula/derivations/fanout-sidecar.d.ts +1 -1
- package/dist/with-formula/materialized-views/dependency-analyzer.d.ts +4 -3
- package/dist/with-formula/materialized-views/emit-memo.d.ts +40 -0
- package/dist/with-formula/materialized-views/executor.d.ts +8 -0
- package/dist/with-formula/materialized-views/index.d.ts +1 -1
- package/dist/with-formula/materialized-views/registry.d.ts +15 -0
- package/dist/with-formula/materialized-views/types.d.ts +106 -14
- package/dist/with-formula/materialized-views/window-stage.d.ts +11 -0
- package/dist/with-formula/overlay-views/types.d.ts +1 -1
- package/dist/with-formula/overlay-views/virtual-collection.d.ts +13 -4
- package/dist/with-lookup/embeddings/chunks.d.ts +79 -0
- package/dist/with-lookup/embeddings/descriptor.d.ts +21 -0
- package/dist/with-lookup/embeddings/index.d.ts +3 -0
- package/dist/with-lookup/embeddings/ivf-flat.d.ts +93 -0
- package/dist/with-lookup/embeddings/vector-index.d.ts +73 -0
- package/dist/with-lookup/embeddings/vector-set.d.ts +94 -1
- package/dist/with-lookup/embeddings/with-vector-index.d.ts +67 -0
- package/dist/with-lookup/indexing/collection-facade.d.ts +86 -3
- package/dist/with-lookup/indexing/compound-indexes.d.ts +129 -0
- package/dist/with-lookup/indexing/eager-indexes.d.ts +170 -1
- package/dist/with-lookup/indexing/index-snapshot.d.ts +62 -0
- package/dist/with-lookup/indexing/lazy-builder.d.ts +33 -0
- package/dist/with-lookup/indexing/persisted-field-indexes.d.ts +104 -0
- package/dist/with-lookup/indexing/persisted-indexes.d.ts +12 -0
- package/dist/with-lookup/indexing/sorted-indexes.d.ts +117 -0
- package/dist/with-lookup/indexing/unique-constraints.d.ts +106 -23
- package/dist/with-lookup/reduce/active.d.ts +2 -24
- package/dist/with-lookup/reduce/group-core.d.ts +43 -0
- package/dist/with-lookup/reduce/groupby.d.ts +195 -36
- package/dist/with-lookup/reduce/incremental-group.d.ts +153 -0
- package/dist/with-lookup/reduce/index.d.ts +26 -5
- package/dist/with-lookup/reduce/reducers.d.ts +255 -1
- package/dist/with-lookup/reduce/reduction.d.ts +44 -13
- package/dist/with-lookup/reduce/strategy.d.ts +43 -3
- package/dist/with-lookup/reduce/window.d.ts +262 -0
- package/dist/with-lookup/search/collection-facade.d.ts +45 -9
- package/dist/with-lookup/search/index-store.d.ts +5 -3
- package/dist/with-lookup/search/index.d.ts +4 -2
- package/dist/with-lookup/search/inverted-index.d.ts +38 -2
- package/dist/with-lookup/search/persisted-index-store.d.ts +5 -2
- package/dist/with-lookup/search/phrase.d.ts +28 -0
- package/dist/with-lookup/search/retrieve-types.d.ts +57 -1
- package/dist/with-lookup/search/serialize.d.ts +29 -3
- package/dist/with-lookup/search/strategy.d.ts +2 -6
- package/dist/with-party/broker/index.d.ts +3 -3
- package/dist/with-party/directory/cover/index.d.ts +1 -1
- package/dist/with-party/directory/cover/storage.d.ts +1 -1
- package/dist/with-party/directory/cover/types.d.ts +1 -1
- package/dist/with-party/directory/index.d.ts +1 -1
- package/dist/with-party/directory/types.d.ts +1 -1
- package/dist/with-party/directory/user-envelope/api.d.ts +1 -1
- package/dist/with-party/directory/user-envelope/storage.d.ts +1 -1
- package/dist/with-party/policy/engine.d.ts +1 -1
- package/dist/with-party/policy/index.d.ts +1 -1
- package/dist/with-party/policy/presets.d.ts +1 -1
- package/dist/with-party/team/authenticators.d.ts +91 -1
- package/dist/with-party/team/delegation.d.ts +1 -1
- package/dist/with-party/team/echo-secret.d.ts +2 -2
- package/dist/with-party/team/index.d.ts +4 -3
- package/dist/with-party/team/keyring.d.ts +2 -2
- package/dist/with-party/team/magic-link-grant.d.ts +1 -1
- package/dist/with-party/team/managed-secret.d.ts +1 -1
- package/dist/with-party/team/noydb-facade.d.ts +12 -3
- package/dist/with-party/team/recovery.d.ts +1 -1
- package/dist/with-party/team/roster-tag.d.ts +1 -1
- package/dist/with-party/team/rotate-recover.d.ts +1 -1
- package/dist/with-party/team/wrapped-deks.d.ts +1 -1
- package/dist/with-pod/format.d.ts +1 -1
- package/dist/with-pod/index.d.ts +1 -1
- package/dist/with-pod/pod.d.ts +1 -1
- package/dist/with-shape/blobs/blob-compaction.d.ts +17 -1
- package/dist/with-shape/blobs/blob-intent.d.ts +1 -1
- package/dist/with-shape/blobs/blob-set.d.ts +23 -4
- package/dist/with-shape/blobs/legacy-sweep.d.ts +35 -0
- package/dist/with-shape/introspection/describe.d.ts +7 -1
- package/dist/with-shape/introspection/field-meta.d.ts +18 -0
- package/dist/with-shape/introspection/types.d.ts +57 -1
- package/dist/with-shape/introspection/walk.d.ts +1 -1
- package/dist/with-shape/links/lazy-handle.d.ts +1 -1
- package/dist/with-shape/links/link-set.d.ts +1 -1
- package/dist/with-shape/links/vault-facade.d.ts +1 -1
- package/dist/with-shape/manifest/derive.d.ts +1 -1
- package/dist/with-shape/manifest/storage.d.ts +1 -1
- package/dist/with-shape/persisted-schemas/register.d.ts +1 -1
- package/dist/with-shape/persisted-schemas/storage.d.ts +1 -1
- package/dist/with-shape/satellites/dead-filter.d.ts +1 -1
- package/dist/with-shape/satellites/declare.d.ts +1 -1
- package/dist/with-shape/satellites/marker.d.ts +1 -1
- package/dist/with-shape/satellites/post-register.d.ts +1 -1
- package/dist/with-store/partitioned/index.d.ts +337 -0
- package/dist/with-sync/change-broadcast.d.ts +153 -0
- package/dist/with-sync/presence.d.ts +5 -10
- package/dist/withdraw-accessible-HL7GACUE.js +27 -0
- package/dist/withdraw-accessible-HL7GACUE.js.map +1 -0
- package/package.json +48 -12
- package/dist/api-WYW4YEQG.js +0 -19
- package/dist/backup-XKCXVKV3.js.map +0 -1
- package/dist/chunk-2577DKXB.js.map +0 -1
- package/dist/chunk-2ENE6445.js.map +0 -1
- package/dist/chunk-2N5ML6HT.js.map +0 -1
- package/dist/chunk-334WSVOW.js.map +0 -1
- package/dist/chunk-3BVH633C.js.map +0 -1
- package/dist/chunk-3PGS7TYR.js.map +0 -1
- package/dist/chunk-3V4KWFX7.js.map +0 -1
- package/dist/chunk-453F654R.js.map +0 -1
- package/dist/chunk-4GFX6MPA.js.map +0 -1
- package/dist/chunk-4GVM6QZA.js.map +0 -1
- package/dist/chunk-4ZS56W5S.js.map +0 -1
- package/dist/chunk-5VCRVKOZ.js.map +0 -1
- package/dist/chunk-6YXCPL4T.js.map +0 -1
- package/dist/chunk-7APJ6CO6.js.map +0 -1
- package/dist/chunk-7MG2LHO5.js +0 -1616
- package/dist/chunk-7MG2LHO5.js.map +0 -1
- package/dist/chunk-7MG7SJT7.js.map +0 -1
- package/dist/chunk-7O3Y4PPD.js.map +0 -1
- package/dist/chunk-A2HKRLPV.js.map +0 -1
- package/dist/chunk-A66I4JOA.js.map +0 -1
- package/dist/chunk-ACAQ2DSG.js.map +0 -1
- package/dist/chunk-ATL3ZVXT.js +0 -151
- package/dist/chunk-ATL3ZVXT.js.map +0 -1
- package/dist/chunk-AYX7AINO.js.map +0 -1
- package/dist/chunk-BLN54W3L.js.map +0 -1
- package/dist/chunk-BRLKZUBT.js +0 -95
- package/dist/chunk-BRLKZUBT.js.map +0 -1
- package/dist/chunk-BTDR2PXY.js +0 -29
- package/dist/chunk-BTDR2PXY.js.map +0 -1
- package/dist/chunk-BVN6KXL2.js.map +0 -1
- package/dist/chunk-CHQCZZWC.js.map +0 -1
- package/dist/chunk-CUQPWYRX.js.map +0 -1
- package/dist/chunk-CUZLNGD5.js.map +0 -1
- package/dist/chunk-DFMWUOU5.js.map +0 -1
- package/dist/chunk-EIPVYUEP.js.map +0 -1
- package/dist/chunk-EQEYOJBM.js.map +0 -1
- package/dist/chunk-F3W6YMDC.js.map +0 -1
- package/dist/chunk-FET5XCAT.js.map +0 -1
- package/dist/chunk-G73UVHCA.js.map +0 -1
- package/dist/chunk-GPNTB4Y7.js.map +0 -1
- package/dist/chunk-GYGLAVCX.js.map +0 -1
- package/dist/chunk-HIWCKBEY.js.map +0 -1
- package/dist/chunk-HJUWN7JN.js.map +0 -1
- package/dist/chunk-HK67PX4J.js.map +0 -1
- package/dist/chunk-HPVZCW43.js +0 -479
- package/dist/chunk-HPVZCW43.js.map +0 -1
- package/dist/chunk-I3ISCYT7.js +0 -159
- package/dist/chunk-I3ISCYT7.js.map +0 -1
- package/dist/chunk-K23VKTN4.js.map +0 -1
- package/dist/chunk-KKEESNPE.js.map +0 -1
- package/dist/chunk-KTFRCC5C.js.map +0 -1
- package/dist/chunk-LH5A3ZPG.js.map +0 -1
- package/dist/chunk-LP7BEXCT.js +0 -32
- package/dist/chunk-LP7BEXCT.js.map +0 -1
- package/dist/chunk-M4YPHYEH.js.map +0 -1
- package/dist/chunk-NSITFOCJ.js +0 -99
- package/dist/chunk-NSITFOCJ.js.map +0 -1
- package/dist/chunk-OTQZ7ZWU.js.map +0 -1
- package/dist/chunk-P3MG6QCN.js.map +0 -1
- package/dist/chunk-PEOZ34EM.js.map +0 -1
- package/dist/chunk-PPTHY5QO.js.map +0 -1
- package/dist/chunk-Q2MPFCQ7.js.map +0 -1
- package/dist/chunk-Q7HZX3IF.js.map +0 -1
- package/dist/chunk-QPQUVOZ2.js.map +0 -1
- package/dist/chunk-QTQUH4DS.js.map +0 -1
- package/dist/chunk-R42NSZI6.js.map +0 -1
- package/dist/chunk-R7BX2NB3.js.map +0 -1
- package/dist/chunk-RSGLUIO6.js.map +0 -1
- package/dist/chunk-RTBJ5IOO.js +0 -87
- package/dist/chunk-RTBJ5IOO.js.map +0 -1
- package/dist/chunk-SGZAIJCV.js.map +0 -1
- package/dist/chunk-SKGMN35F.js.map +0 -1
- package/dist/chunk-SPYWXKJN.js.map +0 -1
- package/dist/chunk-SZJ3DLZA.js +0 -66
- package/dist/chunk-SZJ3DLZA.js.map +0 -1
- package/dist/chunk-TRGTKX5E.js.map +0 -1
- package/dist/chunk-UDHWDSRL.js.map +0 -1
- package/dist/chunk-UP4BECPY.js.map +0 -1
- package/dist/chunk-UXVWEX5L.js.map +0 -1
- package/dist/chunk-V7ZRRCRJ.js.map +0 -1
- package/dist/chunk-WQBG4SZS.js.map +0 -1
- package/dist/chunk-XKWGNJ26.js.map +0 -1
- package/dist/chunk-YMUFFJCO.js.map +0 -1
- package/dist/chunk-ZHKOPKE3.js.map +0 -1
- package/dist/chunk-ZN4FD4PE.js +0 -364
- package/dist/chunk-ZN4FD4PE.js.map +0 -1
- package/dist/chunk-ZORTV6NH.js.map +0 -1
- package/dist/chunk-ZYIYHJ5R.js.map +0 -1
- package/dist/classified-marker-BWOFVYAC.js.map +0 -1
- package/dist/collection-facade-JSJYIKS4.js +0 -45
- package/dist/dead-filter-PKQDLOT4.js.map +0 -1
- package/dist/delegation-DS5NRILW.js.map +0 -1
- package/dist/derive-E642AOUB.js +0 -21
- package/dist/dispatch-Q6MWLOJY.js.map +0 -1
- package/dist/executor-5NIMLSKZ.js +0 -8
- package/dist/executor-7UQ3BZ4F.js +0 -29
- package/dist/executor-AQVXV5GZ.js +0 -8
- package/dist/export-accessible-ORMKLA3E.js +0 -22
- package/dist/extract-partition-NKYO3WNG.js +0 -37
- package/dist/fanout-sidecar-S3QL53YX.js.map +0 -1
- package/dist/find-NOGJ25VX.js +0 -10
- package/dist/issue-3DTQ7VJJ.js +0 -18
- package/dist/json-schema-V3M5MUCM.js.map +0 -1
- package/dist/kernel/enclave/classify/compare.d.ts +0 -10
- package/dist/kernel/enclave/index.d.ts +0 -87
- package/dist/kernel/enclave/record-keys/lifecycle.d.ts +0 -124
- package/dist/kernel/enclave/record-keys/rekey-blob.d.ts +0 -88
- package/dist/kernel/enclave/record-keys/rekey.d.ts +0 -91
- package/dist/kernel/enclave/record-keys/sealed-slot.d.ts +0 -14
- package/dist/kernel/enclave/record-keys/sealed-slots.d.ts +0 -123
- package/dist/kernel/enclave/record-keys/sealing.d.ts +0 -70
- package/dist/kernel/query/join.d.ts +0 -232
- package/dist/liberate-V35QUHJP.js +0 -24
- package/dist/link-set-2TTM3IZC.js +0 -30
- package/dist/noydb-62MX4QUG.js +0 -90
- package/dist/pod-handle-ECVCDIXW.js.map +0 -1
- package/dist/post-register-3IPCSG6Q.js.map +0 -1
- package/dist/register-HHLXEQDN.js +0 -31
- package/dist/registry-23WF3TGH.js +0 -8
- package/dist/registry-4AYVUNXK.js +0 -8
- package/dist/registry-JS3YFQQM.js +0 -18
- package/dist/registry-XX2Z7B46.js +0 -32
- package/dist/request-withdrawal-CHPATE4G.js +0 -30
- package/dist/reveal-QZDHSGD4.js.map +0 -1
- package/dist/revoke-7M2VW4ON.js +0 -23
- package/dist/seed-X5CC22CQ.js.map +0 -1
- package/dist/signer-SJQJVSM6.js +0 -24
- package/dist/stale-BZS6H2RY.js +0 -29
- package/dist/storage-RW4QBS23.js +0 -22
- package/dist/store-coordination-provider-4WZAIRHC.js.map +0 -1
- package/dist/verify-6MDTIUEV.js.map +0 -1
- package/dist/walk-ZURCH6RZ.js +0 -21
- package/dist/withdraw-accessible-PXR4IXDX.js +0 -27
- /package/dist/{api-WYW4YEQG.js.map → api-OS747DS4.js.map} +0 -0
- /package/dist/{computed-VPOKQK4N.js.map → capsule/contract.js.map} +0 -0
- /package/dist/{kernel/enclave → capsule/enclave-aes}/broker/proof.d.ts +0 -0
- /package/dist/{kernel/enclave → capsule/enclave-aes}/classify/bidx.d.ts +0 -0
- /package/dist/{kernel/enclave → capsule/enclave-aes}/classify/digest.d.ts +0 -0
- /package/dist/{kernel/enclave → capsule/enclave-aes}/classify/vdig.d.ts +0 -0
- /package/dist/{kernel/enclave/classify → capsule/plumbing}/kofn.d.ts +0 -0
- /package/dist/{kernel/enclave/classify → capsule/plumbing}/normalize.d.ts +0 -0
- /package/dist/{kernel/enclave → capsule/plumbing}/record-aad.d.ts +0 -0
- /package/dist/{collection-facade-JSJYIKS4.js.map → capsule-VOLX3QRQ.js.map} +0 -0
- /package/dist/{chunk-MVMXZYXT.js.map → chunk-2GHDLTPE.js.map} +0 -0
- /package/dist/{chunk-XLMEZIAJ.js.map → chunk-2ODVB6LZ.js.map} +0 -0
- /package/dist/{chunk-RMS3NEA3.js.map → chunk-4JPMZTJY.js.map} +0 -0
- /package/dist/{chunk-NQKIUNW5.js.map → chunk-52MGURXO.js.map} +0 -0
- /package/dist/{chunk-UGTBXF5U.js.map → chunk-7XMHMVTS.js.map} +0 -0
- /package/dist/{chunk-BZ3534YM.js.map → chunk-AUKKUPVB.js.map} +0 -0
- /package/dist/{derive-E642AOUB.js.map → chunk-BKT776R5.js.map} +0 -0
- /package/dist/{chunk-6LKOJBV6.js.map → chunk-BVCUTXE3.js.map} +0 -0
- /package/dist/{chunk-VTFVLCUH.js.map → chunk-DIZLQVAA.js.map} +0 -0
- /package/dist/{chunk-LWBCUYZW.js.map → chunk-E2N2T5ZO.js.map} +0 -0
- /package/dist/{chunk-JVIBCBC7.js.map → chunk-EJLV62NI.js.map} +0 -0
- /package/dist/{chunk-JMGDHKQF.js.map → chunk-FLPCETP6.js.map} +0 -0
- /package/dist/{chunk-DGOZ4UZD.js.map → chunk-FVH5QYY2.js.map} +0 -0
- /package/dist/{chunk-JBDFMYKQ.js.map → chunk-GZT3NQRA.js.map} +0 -0
- /package/dist/{chunk-TFR7DSOV.js.map → chunk-H427H63K.js.map} +0 -0
- /package/dist/{chunk-SMH6SRX7.js.map → chunk-JOSPH3E5.js.map} +0 -0
- /package/dist/{chunk-3BZZJJMQ.js.map → chunk-MILI22XQ.js.map} +0 -0
- /package/dist/{chunk-YYP7WSEB.js.map → chunk-O2IMQSNA.js.map} +0 -0
- /package/dist/{chunk-QIZPZMUI.js.map → chunk-Q4UHJ5SN.js.map} +0 -0
- /package/dist/{chunk-FAHMLERK.js.map → chunk-QBLT6POL.js.map} +0 -0
- /package/dist/{chunk-BUE2D7PX.js.map → chunk-SMV2HRDU.js.map} +0 -0
- /package/dist/{chunk-SFAWCTEM.js.map → chunk-TZZBXPZK.js.map} +0 -0
- /package/dist/{chunk-UHHPLO3I.js.map → chunk-V3RWOOSO.js.map} +0 -0
- /package/dist/{chunk-Q2PU57HC.js.map → chunk-VVOLDVIR.js.map} +0 -0
- /package/dist/{chunk-TUFM4UZP.js.map → chunk-XQRFSKYM.js.map} +0 -0
- /package/dist/{chunk-GY4WYNNG.js.map → chunk-Y2RKVFKR.js.map} +0 -0
- /package/dist/{chunk-4OZNXTO4.js.map → chunk-YRXFFWG4.js.map} +0 -0
- /package/dist/{enclave-55PAM4YO.js.map → collection-facade-CS7CA2XO.js.map} +0 -0
- /package/dist/{executor-5NIMLSKZ.js.map → computed-FAD7SED4.js.map} +0 -0
- /package/dist/{executor-7UQ3BZ4F.js.map → derive-XLOJVXPU.js.map} +0 -0
- /package/dist/{dispatch-IEPAVQUM.js.map → dispatch-H4HV32AM.js.map} +0 -0
- /package/dist/{executor-AQVXV5GZ.js.map → executor-FMPVN6DT.js.map} +0 -0
- /package/dist/{export-accessible-ORMKLA3E.js.map → executor-LBBBRTN5.js.map} +0 -0
- /package/dist/{extract-partition-NKYO3WNG.js.map → executor-OSRZST2U.js.map} +0 -0
- /package/dist/{find-NOGJ25VX.js.map → export-accessible-RAOJAAU5.js.map} +0 -0
- /package/dist/{issue-3DTQ7VJJ.js.map → extract-partition-JD5CUSTG.js.map} +0 -0
- /package/dist/{ledger-EDXFFZQL.js.map → find-JRN4RNQ5.js.map} +0 -0
- /package/dist/{liberate-V35QUHJP.js.map → issue-YIVBZUTH.js.map} +0 -0
- /package/dist/{link-set-2TTM3IZC.js.map → ledger-5ZMGE44K.js.map} +0 -0
- /package/dist/{managed-secret-NCWEMPUQ.js.map → liberate-WZSZM2W6.js.map} +0 -0
- /package/dist/{noydb-62MX4QUG.js.map → link-set-MFXC24VK.js.map} +0 -0
- /package/dist/{register-HHLXEQDN.js.map → managed-secret-MFTFT22X.js.map} +0 -0
- /package/dist/{migrate-cek-5ENH64AA.js.map → migrate-cek-DZRFFOHW.js.map} +0 -0
- /package/dist/{registry-23WF3TGH.js.map → noydb-ITIGNKUF.js.map} +0 -0
- /package/dist/{registry-4AYVUNXK.js.map → query/all/index.js.map} +0 -0
- /package/dist/{registry-JS3YFQQM.js.map → register-DT5HZ2LZ.js.map} +0 -0
- /package/dist/{registry-XX2Z7B46.js.map → registry-BHRZGZHF.js.map} +0 -0
- /package/dist/{request-withdrawal-CHPATE4G.js.map → registry-ET6ZFFWA.js.map} +0 -0
- /package/dist/{revoke-7M2VW4ON.js.map → registry-HXFGLGTG.js.map} +0 -0
- /package/dist/{signer-SJQJVSM6.js.map → registry-THCPDEOD.js.map} +0 -0
- /package/dist/{stale-BZS6H2RY.js.map → request-withdrawal-AV2MJJKY.js.map} +0 -0
- /package/dist/{storage-RW4QBS23.js.map → revoke-6DWIEOCV.js.map} +0 -0
- /package/dist/{walk-ZURCH6RZ.js.map → signer-MHGW3OIL.js.map} +0 -0
- /package/dist/{withdraw-accessible-PXR4IXDX.js.map → stale-6GCFMOOR.js.map} +0 -0
|
@@ -1,13 +1,17 @@
|
|
|
1
|
+
import {
|
|
2
|
+
matchDeclaredJoin
|
|
3
|
+
} from "./chunk-4V3Q35WG.js";
|
|
1
4
|
import {
|
|
2
5
|
readPath
|
|
3
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-5WWDGFOS.js";
|
|
4
7
|
import {
|
|
5
8
|
DanglingReferenceError,
|
|
6
9
|
JoinTooLargeError
|
|
7
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-37EPTBBR.js";
|
|
8
11
|
|
|
9
|
-
// src/kernel/query/join.ts
|
|
12
|
+
// src/kernel/query/relate/join.ts
|
|
10
13
|
var DEFAULT_JOIN_MAX_ROWS = 5e4;
|
|
14
|
+
var DEFAULT_CROSS_JOIN_MAX_ROWS = 5e4;
|
|
11
15
|
var JOIN_WARN_FRACTION = 0.8;
|
|
12
16
|
function referencesJoinAlias(clause, aliases) {
|
|
13
17
|
if (clause.type !== "field") return false;
|
|
@@ -24,6 +28,14 @@ function splitAroundJoins(clauses, joins) {
|
|
|
24
28
|
}
|
|
25
29
|
return { preJoin, postJoin };
|
|
26
30
|
}
|
|
31
|
+
function orderReferencesJoinAlias(orderBy, joins) {
|
|
32
|
+
if (joins.length === 0 || orderBy.length === 0) return false;
|
|
33
|
+
const aliases = new Set(joins.map((leg) => leg.as));
|
|
34
|
+
return orderBy.some((entry) => aliases.has(entry.field.split(".")[0]));
|
|
35
|
+
}
|
|
36
|
+
function joinsDropLeftRows(joins) {
|
|
37
|
+
return joins.some((leg) => leg.inner === true);
|
|
38
|
+
}
|
|
27
39
|
function coerceRefKey(value) {
|
|
28
40
|
if (value === null || value === void 0) return null;
|
|
29
41
|
if (typeof value === "string") return value;
|
|
@@ -58,6 +70,11 @@ function applyJoins(rows, joins, context, locale) {
|
|
|
58
70
|
return result;
|
|
59
71
|
}
|
|
60
72
|
function applyOneJoin(leftRows, leg, context, locale) {
|
|
73
|
+
const rows = applyOneJoinRaw(leftRows, leg, context, locale);
|
|
74
|
+
if (leg.inner !== true) return rows;
|
|
75
|
+
return rows.filter((row) => row !== null && typeof row === "object" && row[leg.as] != null);
|
|
76
|
+
}
|
|
77
|
+
function applyOneJoinRaw(leftRows, leg, context, locale) {
|
|
61
78
|
if (leg.isDictJoin) {
|
|
62
79
|
const dictSource = context.resolveDictSource?.(leg.field);
|
|
63
80
|
if (!dictSource) {
|
|
@@ -114,13 +131,37 @@ function applyOneJoin(leftRows, leg, context, locale) {
|
|
|
114
131
|
}
|
|
115
132
|
const effLocale = locale ?? context.defaultLocale;
|
|
116
133
|
const presentResolve = effLocale !== void 0 && source.presentForJoin !== void 0 ? (right) => right !== null && typeof right === "object" ? source.presentForJoin(right, effLocale) : right : void 0;
|
|
134
|
+
if (leg.on !== void 0) {
|
|
135
|
+
return declaredJoin(leftRows, leg, leg.on, rightSnapshot, maxRows, presentResolve);
|
|
136
|
+
}
|
|
117
137
|
const strategy = leg.strategy ?? (source.lookupById ? "nested" : "hash");
|
|
138
|
+
const direction = leg.direction ?? "left";
|
|
139
|
+
if (direction !== "left") {
|
|
140
|
+
return outerJoinFromRight(leftRows, leg, source, direction, presentResolve);
|
|
141
|
+
}
|
|
118
142
|
if (strategy === "nested" && source.lookupById) {
|
|
119
143
|
const lookup = (id) => source.lookupById?.(id);
|
|
120
144
|
return nestedLoopJoin(leftRows, leg, lookup, presentResolve);
|
|
121
145
|
}
|
|
122
146
|
return hashJoin(leftRows, leg, rightSnapshot, presentResolve);
|
|
123
147
|
}
|
|
148
|
+
function declaredJoin(leftRows, leg, on, rightSnapshot, maxRows, presentResolve) {
|
|
149
|
+
const matches = matchDeclaredJoin(leftRows, on, rightSnapshot, maxRows, (produced) => {
|
|
150
|
+
throw new JoinTooLargeError({
|
|
151
|
+
leftRows: leftRows.length,
|
|
152
|
+
rightRows: rightSnapshot.length,
|
|
153
|
+
maxRows,
|
|
154
|
+
side: "output",
|
|
155
|
+
message: `.joinOn("${leg.target}") produced more than ${maxRows} rows (${produced} and counting) from ${leftRows.length} left x ${rightSnapshot.length} right. A declared \`on\` is many-to-many, so the per-side ceilings do not bound the result. Narrow the predicate, filter the left side with where()/limit() before joining, or raise the ceiling via { maxRows }.`
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
const out = [];
|
|
159
|
+
for (const { left, right } of matches) {
|
|
160
|
+
const dressed = presentResolve && right !== void 0 ? presentResolve(right) : right;
|
|
161
|
+
out.push(attachJoin(left, leg, dressed, void 0));
|
|
162
|
+
}
|
|
163
|
+
return out;
|
|
164
|
+
}
|
|
124
165
|
function nestedLoopJoin(leftRows, leg, lookupById, presentResolve) {
|
|
125
166
|
const out = [];
|
|
126
167
|
for (const left of leftRows) {
|
|
@@ -151,6 +192,44 @@ function hashJoin(leftRows, leg, rightSnapshot, presentResolve) {
|
|
|
151
192
|
}
|
|
152
193
|
return out;
|
|
153
194
|
}
|
|
195
|
+
function reverseIndex(leftRows, field) {
|
|
196
|
+
return bucketByRefKey(leftRows, (left) => readPath(left, field));
|
|
197
|
+
}
|
|
198
|
+
function bucketByRefKey(items, readKey) {
|
|
199
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
200
|
+
for (const item of items) {
|
|
201
|
+
const key = coerceRefKey(readKey(item));
|
|
202
|
+
if (key === null) continue;
|
|
203
|
+
const bucket = buckets.get(key);
|
|
204
|
+
if (bucket) bucket.push(item);
|
|
205
|
+
else buckets.set(key, [item]);
|
|
206
|
+
}
|
|
207
|
+
return buckets;
|
|
208
|
+
}
|
|
209
|
+
function outerJoinFromRight(leftRows, leg, source, direction, presentResolve) {
|
|
210
|
+
const byRight = reverseIndex(leftRows, leg.field);
|
|
211
|
+
const matchedLeft = /* @__PURE__ */ new Set();
|
|
212
|
+
const out = [];
|
|
213
|
+
const entries = source.snapshotEntries?.() ?? source.snapshot().map((record) => ({ id: coerceRefKey(readPath(record, "id")), record }));
|
|
214
|
+
for (const { id: rid, record: right } of entries) {
|
|
215
|
+
const dressed = presentResolve ? presentResolve(right) : right;
|
|
216
|
+
const bucket = rid === null ? void 0 : byRight.get(rid);
|
|
217
|
+
if (bucket === void 0 || bucket.length === 0) {
|
|
218
|
+
out.push({ [leg.as]: dressed });
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
for (const left of bucket) {
|
|
222
|
+
matchedLeft.add(left);
|
|
223
|
+
out.push(attachJoin(left, leg, dressed, readPath(left, leg.field)));
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
for (const left of leftRows) {
|
|
227
|
+
if (matchedLeft.has(left)) continue;
|
|
228
|
+
const row = attachJoin(left, leg, void 0, readPath(left, leg.field));
|
|
229
|
+
if (direction === "full") out.push(row);
|
|
230
|
+
}
|
|
231
|
+
return out;
|
|
232
|
+
}
|
|
154
233
|
function attachJoin(left, leg, right, rawId) {
|
|
155
234
|
if (left === null || typeof left !== "object") {
|
|
156
235
|
return left;
|
|
@@ -182,8 +261,13 @@ function resetJoinWarnings() {
|
|
|
182
261
|
|
|
183
262
|
export {
|
|
184
263
|
DEFAULT_JOIN_MAX_ROWS,
|
|
264
|
+
DEFAULT_CROSS_JOIN_MAX_ROWS,
|
|
185
265
|
splitAroundJoins,
|
|
266
|
+
orderReferencesJoinAlias,
|
|
267
|
+
joinsDropLeftRows,
|
|
268
|
+
coerceRefKey,
|
|
186
269
|
applyJoins,
|
|
270
|
+
bucketByRefKey,
|
|
187
271
|
resetJoinWarnings
|
|
188
272
|
};
|
|
189
|
-
//# sourceMappingURL=chunk-
|
|
273
|
+
//# sourceMappingURL=chunk-NCO25JZO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/kernel/query/relate/join.ts"],"sourcesContent":["/**\n * Query DSL `.join()` — eager, single-FK, intra-vault joins.\n *\n * resolves a ref()-declared foreign key into an attached\n * right-side record under an alias, using one of two planner paths\n * selected automatically:\n *\n * - **nested-loop** — right-side source exposes `lookupById`, so\n * each left row costs O(1). This is the common path for joins\n * against a Collection, which backs `lookupById` with a Map\n * lookup.\n * - **hash** — right-side has only `snapshot()`. Build a\n * `Map<id, record>` once, probe per left row. Same asymptotic\n * cost for our collections, but the path exists as a fallback\n * for custom QuerySource implementations and as an explicit\n * test-only override via `{ strategy: 'hash' }`.\n *\n * Scope:\n *\n * - Equi-joins on declared `ref()` fields only. Joins on\n * undeclared fields throw at plan time with an actionable error\n * naming the field and collection.\n * - Same-vault only. Cross-vault correlation goes\n * through `queryAcross`; this is an architectural\n * invariant, not a limitation we plan to lift.\n * - Hard row ceiling via `JoinTooLargeError` — default 50k per\n * side, override via `{ maxRows }`. Warns at 80% of the ceiling\n * on the existing warn channel.\n * - Three ref-mode behaviors on dangling refs:\n * strict → `DanglingReferenceError`,\n * warn → attach `null` with a one-shot warning,\n * cascade → attach `null` silently (cascade is a delete-time\n * mode; any dangling refs still present at read time are\n * mid-flight cascades or orphans from earlier, not a DSL error).\n *\n * Partition-awareness seam:\n *\n * Every `JoinLeg` carries a `partitionScope` field that is always `'all'`.\n * The executor never reads it. See {@link JoinLeg.partitionScope} for the\n * two constraints (#1342) that decide how it may ever be populated — one of\n * them silently invalidates stored materialized views.\n *\n * Joins stay OUT of the ledger: reads don't touch `_ledger/`,\n * including joined reads.\n */\n\nimport type { RefDescriptor, RefMode } from '../../refs.js'\nimport type { Clause } from '../predicate.js'\nimport type { ViaPipeline } from '../../via/pipeline.js'\nimport { readPath } from '../predicate.js'\nimport { matchDeclaredJoin, type JoinOnPlan } from './join-on.js'\nimport { JoinTooLargeError, DanglingReferenceError } from '../../errors.js'\n\n/** Planner strategy for a single join leg. Auto-selected unless overridden. */\nexport type JoinStrategy = 'hash' | 'nested'\n\n/**\n * Which side of a join leg is preserved (#1289).\n *\n * - `'left'` — every left row survives, `null` under the alias when the\n * FK resolves to nothing. This is what `.join()` has always done, and it\n * is the default for a leg that names no direction.\n * - `'right'` — every RIGHT record survives, including one nothing points\n * at; a left row whose FK matches nothing is dropped.\n * - `'full'` — the union of the two.\n *\n * `'right'` and `'full'` are the only two that need the reverse index — see\n * {@link outerJoinFromRight}. A forward leg is driven by the left row's FK\n * and never has to ask \"did anything point at this\".\n */\nexport type JoinDirection = 'left' | 'right' | 'full'\n\n/** Default per-side row ceiling before `.join()` throws `JoinTooLargeError`. */\nexport const DEFAULT_JOIN_MAX_ROWS = 50_000\n\n/**\n * Default row ceiling for cross-join expansion. Matches JoinTooLargeError's ceiling.\n *\n * ⭐ #1458 — moved here from `kernel/query/builder.ts`. Find carries no\n * cross-join concept, and a constant is the cheapest thing to leave behind by\n * accident: it would have kept `builder.ts` as the const's home while every\n * reader of it lived in `relate/`.\n */\nexport const DEFAULT_CROSS_JOIN_MAX_ROWS = 50_000\n\n/**\n * Fraction of the row ceiling at which a one-shot warning is emitted.\n * At 80% we warn; at 100% we throw. The warn gives consumers a\n * heads-up before the hard error so they can raise the ceiling or\n * filter further without first hitting a broken query.\n */\nconst JOIN_WARN_FRACTION = 0.8\n\n/**\n * Internal representation of a single join leg in the query plan.\n *\n * This is the primary place the partition seam is honored: every leg carries\n * a `partitionScope` field that is always `'all'` and is never read by the\n * executor. See {@link JoinLeg.partitionScope}.\n */\nexport interface JoinLeg {\n /** Field on the left-side record holding the foreign key value. */\n readonly field: string\n /** Alias key under which the joined right-side record attaches. */\n readonly as: string\n /** Target collection name, resolved from the `ref()` declaration. */\n readonly target: string\n /** Ref mode controlling behavior on dangling refs at read time. */\n readonly mode: RefMode\n /** Manual planner strategy override. `undefined` → auto-select. */\n readonly strategy: JoinStrategy | undefined\n /** Per-side row ceiling override. `undefined` → DEFAULT_JOIN_MAX_ROWS. */\n readonly maxRows: number | undefined\n /**\n * Partition scope for future partition-aware joins. Always `'all'` today —\n * the executor never reads this field. Do not remove even though it looks\n * unused: it is a plan-shape seam.\n *\n * ⛔ TWO CONSTRAINTS BEFORE POPULATING THIS (#1342):\n *\n * 1. **It is a `queryHash` input on a HAND-COMPOSED path only — NOT for a\n * registered materialized view.** ⚠️ This paragraph asserted the\n * opposite until 2026-09-04; the correction is the measurement.\n * `MaterializedViewRegistry` feeds `computeQueryHash` from\n * `summarizeQueryPlan()` (`materialized-views/registry.ts:201,243`),\n * and that summary has never emitted `partitionScope`. `serializePlan()`\n * *does* emit `plan.joins` verbatim, and `canonicalizeQueryPlan` is\n * exported, so a consumer composing\n * `computeQueryHash(name, deps, canonicalizeQueryPlan(serializePlan(q)))`\n * by hand does carry the field in their hash. **That composition, and\n * only that one, is what this constraint binds** — it is also the\n * composition `__tests__/query-partition-scope.test.ts` builds, which is\n * why the file read as evidence for the stronger claim.\n * ⭐ So populating this field does NOT invalidate registered MVs. The\n * reason to leave it alone is smaller and still sufficient: it is a\n * DERIVED value — storing it buys nothing, and it is the one leg key\n * emitted UNCONDITIONALLY rather than omitted-at-default, so any later\n * move to summarise it (see #1389's rule) would shift every joined MV's\n * hash at once, for zero gain. Derive the scope in the EXECUTOR from\n * clauses the plan already carries. Pinned by\n * `__tests__/query-partition-scope.test.ts`, which now pins BOTH paths.\n *\n * 2. **The seam-change route was RULED OUT, and the pruning shipped\n * anyway** — ADR 0007, \"partitioning is collection-shaped\". Pruning only\n * pays on the `scan()` path (`query()` runs over an in-memory,\n * already-decrypted cache where `candidateRecords()`'s hash / sorted /\n * compound dispatch (#1344, #1345) narrows better than a partition ever\n * could). Buying it by teaching `NoydbStore.listPage` a filter would\n * have meant lifting the partition key out of the ciphertext into a\n * storage key or cleartext metadata — a permanent per-record\n * classification handed to the backend, and a change to the published\n * `@noy-db/hub/to` contract across every `to-*` adapter. **Ruled no.**\n * ⭐ The pruning was bought instead with information the store already\n * has: `listPage(vault, **collection**, …)` names the collection in\n * cleartext, so a partition modelled as its own collection is never\n * fetched because it is never asked for.\n *\n * ⭐ **THE SCOPE IS NOW DERIVED, IN THE EXECUTOR, AND THIS FIELD IS STILL\n * DORMANT.** `kernel/query/relate/partition.ts`'s `resolvePartitionScope()` is the\n * one decision function — `with-store/partitioned/` and `explain()` both\n * call it — and it takes the plan's top-level clause list, never a stored\n * leg. It is sound in one direction only: narrow ONLY on a whitelist of\n * provable shapes (`==` / `in` on the declared key at the top level of the\n * AND-ed clause list), and fall back to `'all'` for everything else —\n * `or` groups, negations, callback clauses, and any Via-covered clause\n * (its operand is in STORED form, not partition-key space, which is why\n * `candidateRecords` refuses the index for it too). A partition wrongly\n * excluded is silently missing data.\n */\n readonly partitionScope: 'all' | readonly string[]\n /**\n * Which side is preserved (#1289). `undefined` reads as `'left'` — the\n * pre-#1289 behaviour — so every plan built before this field existed, and\n * every serialized plan that omits it, keeps its meaning exactly.\n */\n readonly direction?: JoinDirection\n /**\n * INNER join (#1361) — drop every left row whose alias resolves to nothing,\n * instead of attaching `null` under it.\n *\n * Only `.join()` sets it (a right/full leg already drops on its own side),\n * and only when the caller passes `{ mode: 'inner' }`. Omitted rather than\n * written as `false` for the same reason `direction` is: a plan built\n * without it must serialize byte-identically to a pre-#1361 one, or every\n * stored `queryHash` moves.\n */\n readonly inner?: true\n /**\n * A DECLARED, deterministic join predicate (#1339) — composite equality or\n * a range — instead of the `ref()`-declared FK the rest of this file\n * resolves. Set only by `.joinOn()`, always through\n * {@link normalizeJoinOn}, and OMITTED on every other leg: a plan built by\n * `.join()` must serialize byte-identically to a pre-#1339 one, or every\n * stored `queryHash` moves (the same discipline `direction` and `inner`\n * follow above).\n *\n * ⭐ This is the field that separates `.joinOn()` from `.crossJoin({ on })`.\n * It is plain JSON, so it survives `serializePlan()` and\n * `summarizeQueryPlan()` and a materialized view can therefore DEPEND on\n * it. A closure cannot. See `join-on.ts`.\n */\n readonly on?: JoinOnPlan\n /**\n * When `true`, this is a dictionary join. The executor\n * resolves the left-field value against the dict snapshot and\n * attaches `{ ...labels, key }` rather than a right-side record.\n * `target` holds the dictionary name (not a collection name).\n */\n readonly isDictJoin?: true\n}\n\n/**\n * Minimal shape of a joinable right-side record source.\n *\n * Collections implement this structurally via their `QuerySource`;\n * sources without `lookupById` force the hash-join fallback. Kept as\n * a thin interface so tests can wire up plain-object sources without\n * pulling in the full Collection class.\n *\n * The optional `subscribe` is used by `Query.live()` to merge\n * right-side change streams into the live re-run trigger. Sources\n * that omit `subscribe` still work for live joins — they just\n * don't drive re-fires when their right side mutates. Collection\n * implements `subscribe` by hooking into the existing per-\n * vault event emitter.\n */\nexport interface JoinableSource {\n snapshot(): readonly unknown[]\n lookupById?(id: string): unknown\n /**\n * Default locale a label-resolving query falls back to when the query\n * itself is locale-less. Set by a `staticDict()`-backed source from its\n * `displayLocale` so `{ by: 'label' }` resolves under a locale-less read.\n * Plain `_dict_*`-backed sources omit it.\n */\n readonly displayLocale?: string\n /**\n * Sync present-for-join dressing (#626 retirement, #650 Task 6) — when\n * present and the query carries a locale, each joined right-side record\n * is passed through this hook (built by the right-side `Collection` from\n * its own i18n-text + lookup-label bindings) BEFORE it is attached under\n * the leg's alias — so a joined `i18nText` field resolves to a string\n * (not a raw `{ locale }` map) and a joined lookup field gains its\n * `<field>Label`. Locale-less queries leave joined fields raw\n * (consistent with a locale-less read). Replaces the old `i18nFields`\n * data field — the join executor no longer resolves i18n locale itself,\n * it just calls this hook.\n */\n readonly presentForJoin?: (record: unknown, locale: string) => unknown\n /**\n * The id-paired view of {@link snapshot} (#1289).\n *\n * ⚠️ A `Collection` snapshot record does NOT carry its own id — the id is\n * the cache key, not a field. The forward join never noticed, because it\n * reads the id off the LEFT row's FK and calls `lookupById`. A right/full\n * outer join has to ask each RIGHT record \"what is your id, and did\n * anything point at you\", and there is no field to read it from.\n *\n * Optional so a plain-object test source stays valid; `outerJoinFromRight`\n * falls back to an `id` FIELD on the record, which is what such sources\n * carry. A real Collection supplies this and the fallback never runs.\n */\n snapshotEntries?(): readonly { readonly id: string; readonly record: unknown }[]\n /**\n * Via RESULT decode for this source's own records (#1289) — the same\n * `via.decodeResults` a top-level `toArray()` applies (money's stored\n * scaled-int → canonical decimal, etc.).\n *\n * It exists because Via dressing keys by BARE FIELD NAME: the moment a\n * record moves under an alias (`{ client: { amount } }`, or both sides of\n * `crossJoinWith`) the top-level decode cannot see it, and the row silently\n * serves raw money. Distinct from `presentForJoin`, which is the LOCALE\n * half (i18n text + lookup labels) and only runs for a locale-carrying\n * query — this half is locale-free and always applies.\n */\n readonly decodeResults?: (record: unknown) => unknown\n /**\n * This source's own compiled Via pipeline (#1337 / #1338).\n *\n * The two halves above (`presentForJoin`, `decodeResults`) dress a record\n * that is ON ITS WAY OUT. Ordering, grouping and reduction happen while it\n * is still under an alias mid-plan, and they need the pipeline itself:\n * `compareForOrder` to sort an aliased money field by MAGNITUDE rather than\n * lexically over its stored scaled integer, and `wrapReducers` to rewrite\n * `sum('client.credit')` into the exact-BigInt money reducer (which also\n * applies the RIGHT collection's `queryable: 'none'` posture gate — the\n * gate whose silent absence is why joined aggregation was refused).\n *\n * A THUNK, not a property: `_applyMoneyFields` can rebuild a collection's\n * pipeline after this source object has been handed out, and a copied\n * reference would go quietly stale — the same discipline `decodeResults`\n * above already follows.\n *\n * Optional: a plain-object test source declares none, and every consumer\n * treats absence as \"no binding covers anything here\".\n */\n readonly via?: () => ViaPipeline | undefined\n /**\n * Subscribe to mutations on this source. The callback fires\n * AFTER the underlying record set has been updated. Returns an\n * unsubscribe function. Optional — sources without this method\n * cannot trigger live-join re-fires from their side.\n */\n subscribe?(cb: () => void): () => void\n}\n\n/**\n * Join resolution context attached to a `Query` when it's constructed\n * from a `Collection`. Holds everything the `.join()` method needs to\n * translate a field name into a target collection + ref mode, and\n * everything the executor needs to read the right side.\n *\n * Kept as a structural interface so `Vault` can implement it\n * without `Query` needing to import `Vault` (circular-import\n * avoid). The Collection wires this up in its `query()` method using\n * the `joinResolver` back-reference the Vault passes in.\n */\nexport interface JoinContext {\n /** Name of the left-side (owning) collection. */\n readonly leftCollection: string\n /**\n * The owning collection's default locale. Used to resolve joined\n * i18n fields at the `join` layer when a terminal call doesn't pass an\n * explicit locale — so `openVault({ locale })` flows to joins like it does\n * to `get`/`list`. A per-call `toArray({ locale })` overrides it.\n */\n readonly defaultLocale?: string\n /** Look up a `RefDescriptor` by field name on the left collection. */\n resolveRef(field: string): RefDescriptor | null\n /** Resolve a right-side source by target collection name. */\n resolveSource(collectionName: string): JoinableSource | null\n /**\n * Resolve a dictKey join source. Returns a `JoinableSource`\n * whose snapshot exposes `{ key, ...labels }` records, keyed by the\n * stable dictionary key. `null` when the field is not a dictKey.\n *\n * The source is built from the compartment's in-memory dictionary\n * snapshot — same data as `DictionaryHandle.list()`, O(1) per lookup.\n */\n resolveDictSource?(field: string): JoinableSource | null\n}\n\n/**\n * Does this clause address a field that only exists once join legs are\n * attached — i.e. is its path rooted at a join alias?\n *\n * Only `FieldClause` is inspectable. A `FilterClause` carries an opaque\n * function and a `WherePredicateClause` a named one, so neither can be\n * classified; both stay on the pre-join side, which is where they have\n * always run. See `splitAroundJoins`.\n */\nfunction referencesJoinAlias(clause: Clause, aliases: ReadonlySet<string>): boolean {\n if (clause.type !== 'field') return false\n // `where('client.name', …)` addresses the alias; so does the anti-join\n // form `where('client', '==', null)`, where the path IS the alias.\n return aliases.has(clause.field.split('.')[0]!)\n}\n\n/**\n * Split a plan's clauses into those evaluable before the join legs run and\n * those that need the joined shape (#1030).\n *\n * Join legs attach after `where` so the left set can be narrowed (and\n * index-driven) first. That is the right default, but it silently broke any\n * predicate addressing a joined alias: the field did not exist yet, so\n * `readPath` returned `undefined`, nothing matched, and the query returned an\n * empty result with no error.\n *\n * The split is deliberately narrow. When no clause addresses an alias — every\n * query written against the previous behaviour — `postJoin` is empty and the\n * caller takes its original path unchanged. The reordered pipeline therefore\n * only ever runs for queries that match nothing today.\n *\n * KNOWN RESIDUAL: `.filter(r => r.client?.name === 'Ann')` cannot be\n * classified (the predicate is a closure), so it still runs pre-join and still\n * sees no alias. Prefer `.where()` for anything addressing a joined field.\n *\n * Shared by the eager `Query` and the streaming `ScanBuilder` so the two\n * cannot drift on which side a clause belongs to.\n */\nexport function splitAroundJoins(\n clauses: readonly Clause[],\n joins: readonly JoinLeg[],\n): { readonly preJoin: readonly Clause[]; readonly postJoin: readonly Clause[] } {\n if (joins.length === 0 || clauses.length === 0) return { preJoin: clauses, postJoin: [] }\n const aliases = new Set(joins.map(leg => leg.as))\n const preJoin: Clause[] = []\n const postJoin: Clause[] = []\n for (const clause of clauses) {\n ;(referencesJoinAlias(clause, aliases) ? postJoin : preJoin).push(clause)\n }\n return { preJoin, postJoin }\n}\n\n/**\n * Does any `orderBy` entry address a field that only exists once the legs are\n * attached (#1337)?\n *\n * The ordering half of {@link splitAroundJoins}, kept beside it because the\n * two answer the same question about different parts of the plan, and because\n * `Query.toArray()` and `Query.explain()` must not drift on the answer — one\n * decides when the sort runs, the other reports it.\n *\n * ⚠️ Only `plan.joins` legs count. A `crossJoin` alias lives in the CLAUSE\n * list and its expansion already runs before ordering, so an ordering over\n * one has never needed moving.\n */\nexport function orderReferencesJoinAlias(\n orderBy: readonly { readonly field: string }[],\n joins: readonly JoinLeg[],\n): boolean {\n if (joins.length === 0 || orderBy.length === 0) return false\n const aliases = new Set(joins.map(leg => leg.as))\n return orderBy.some(entry => aliases.has(entry.field.split('.')[0]!))\n}\n\n/**\n * Does any leg drop left rows (#1361)?\n *\n * The entry condition for every terminal that must run the legs even though\n * nothing addresses an alias: an inner leg is no longer projection-only, so\n * `count()`, `exists()` and the ordering placement in `toArray()` all have to\n * ask. Kept beside {@link splitAroundJoins} and {@link orderReferencesJoinAlias}\n * because the three answer the same family of question, and because\n * `Query.toArray()` and `Query.explain()` must not drift on the answer.\n */\nexport function joinsDropLeftRows(joins: readonly JoinLeg[]): boolean {\n return joins.some(leg => leg.inner === true)\n}\n\n/**\n * Coerce an unknown FK value into a lookup key string.\n *\n * Legitimate ref values are strings or numbers — the same narrowing\n * the write-time `enforceRefsOnPut` path applies. Anything else\n * (objects, arrays, booleans, null, undefined) is treated as \"no\n * ref\" and returns `null`, so the join attaches `null` instead of\n * running `String({})` and producing `'[object Object]'` as a\n * bucket key. This matches the lint rule guidance and keeps\n * bizarre FK values from producing silently-wrong lookups.\n */\nexport function coerceRefKey(value: unknown): string | null {\n if (value === null || value === undefined) return null\n if (typeof value === 'string') return value\n if (typeof value === 'number' || typeof value === 'bigint') return String(value)\n return null\n}\n\n/**\n * Warn-channel deduplication for dangling-ref `'warn'` mode. Keyed\n * by `field → target:refId` so the same dangling ref only produces\n * one warning even across many rows or repeated queries.\n */\nconst warnedDanglingKeys = new Set<string>()\nfunction warnOnceDangling(field: string, target: string, refId: string): void {\n const key = `${field}→${target}:${refId}`\n if (warnedDanglingKeys.has(key)) return\n warnedDanglingKeys.add(key)\n console.warn(\n `[noy-db] .join() encountered dangling ref in 'warn' mode: ` +\n `field \"${field}\" → \"${target}:${refId}\" not found. Attaching null.`,\n )\n}\n\n/**\n * Track row-ceiling warnings to fire only once per (target, side).\n * Prevents per-query spam when a consumer is running the same query\n * repeatedly (e.g. in a reactive loop).\n */\nconst warnedCeilingKeys = new Set<string>()\nfunction warnCeilingApproaching(\n target: string,\n side: 'left' | 'right',\n rows: number,\n maxRows: number,\n): void {\n const key = `${target}:${side}`\n if (warnedCeilingKeys.has(key)) return\n warnedCeilingKeys.add(key)\n const pct = Math.round((rows / maxRows) * 100)\n console.warn(\n `[noy-db] .join() ${side} side is at ${pct}% of the ${maxRows}-row ` +\n `ceiling for target \"${target}\" (${rows} rows). Streaming joins over ` +\n `scan() are not yet supported for collections that need to exceed this.`,\n )\n}\n\n/**\n * Apply every join leg in the plan against a base set of left-side\n * rows. Called by the query executor after `where` / `orderBy` /\n * `offset` / `limit` have narrowed the left set.\n *\n * Each leg attaches a `leg.as` field to every row. Returns a new\n * array of plain objects — the original left rows are not mutated\n * (structural sharing is fine for the inner fields, but the\n * top-level object is a fresh clone so consumers can further mutate\n * safely).\n *\n * **Ordering:** joins run AFTER orderBy / limit / offset by DEFAULT, so\n * \"top 10 invoices with client\" sorts and paginates the left side first\n * (index-driven) and joins only the page. Two things flip that, and both\n * are decided by the plan, never by a flag: a `where` addressing an alias\n * (#1030, {@link splitAroundJoins}) and an `orderBy` addressing one (#1337,\n * {@link orderReferencesJoinAlias}). Either one moves the sort and the page\n * to AFTER the legs, because neither can be evaluated against a row where\n * the alias does not exist yet. ⚠️ That query necessarily loses the\n * index-driven ordering fast path — the cost of sorting on a field the\n * index does not hold. `Query.explain()` names which placement a plan gets.\n *\n * An INNER leg (#1361) moves only the PAGE, not the sort: the drop removes\n * rows, so `limit` must observe it, but the ordering is on a left-side field\n * that the drop cannot reorder. `toArray()` therefore sorts pre-join, joins,\n * and slices after — and `explain()` reports `pre-join` on the sort and\n * `post-join` on the page rather than one word for both.\n *\n * **Multi-FK chaining:** each leg's `maxRows` is enforced\n * against the current left-row count independently. Because\n * joins are equi-joins on the target's primary key (one-to-one or\n * one-to-null), the left row count is constant across legs — no\n * cartesian blowup. The per-leg left-side check is still necessary\n * so that a later leg with a tighter ceiling correctly fires on a\n * query like `.join('a', { maxRows: 100_000 }).join('b', { maxRows: 50 })`,\n * which should throw on the second leg if the left set exceeds 50.\n */\nexport function applyJoins(\n rows: readonly unknown[],\n joins: readonly JoinLeg[],\n context: JoinContext,\n locale?: string,\n): unknown[] {\n if (joins.length === 0) return [...rows]\n\n let result: unknown[] = [...rows]\n for (const leg of joins) {\n result = applyOneJoin(result, leg, context, locale)\n }\n return result\n}\n\n/**\n * One leg, plus the #1361 inner-join drop.\n *\n * The drop is applied to the leg's OUTPUT rather than threaded through the\n * three producers (nested-loop, hash, dict) — an unmatched row is `null` under\n * the alias in all three by construction, and `attachJoin` has already run, so\n * a strict-mode `DanglingReferenceError` still fires for a dangling ref that\n * `inner` would otherwise hide.\n */\nfunction applyOneJoin(\n leftRows: readonly unknown[],\n leg: JoinLeg,\n context: JoinContext,\n locale?: string,\n): unknown[] {\n const rows = applyOneJoinRaw(leftRows, leg, context, locale)\n if (leg.inner !== true) return rows\n return rows.filter(row => row !== null && typeof row === 'object' && (row as Record<string, unknown>)[leg.as] != null)\n}\n\nfunction applyOneJoinRaw(\n leftRows: readonly unknown[],\n leg: JoinLeg,\n context: JoinContext,\n locale?: string,\n): unknown[] {\n // Dict join path — resolve left-field value against the\n // dictionary snapshot and attach { key, ...labels } under leg.as.\n if (leg.isDictJoin) {\n const dictSource = context.resolveDictSource?.(leg.field)\n if (!dictSource) {\n throw new Error(\n `.join() field \"${leg.field}\" on \"${context.leftCollection}\" is declared as a ` +\n `dictKey join but the dict source could not be resolved. ` +\n `Ensure the dictionary has at least one entry.`,\n )\n }\n const out: unknown[] = []\n const snapshot = dictSource.snapshot()\n const dictMap = new Map<string, unknown>()\n for (const entry of snapshot) {\n const k = readPath(entry, 'key')\n if (typeof k === 'string') dictMap.set(k, entry)\n }\n for (const left of leftRows) {\n const rawId = readPath(left, leg.field)\n const key = coerceRefKey(rawId)\n const dictEntry = key === null ? undefined : dictMap.get(key)\n out.push({ ...(left as Record<string, unknown>), [leg.as]: dictEntry ?? null })\n }\n return out\n }\n\n const source = context.resolveSource(leg.target)\n if (!source) {\n throw new Error(\n `.join() cannot resolve target collection \"${leg.target}\" ` +\n `(referenced from field \"${leg.field}\" on \"${context.leftCollection}\"). ` +\n `Make sure the target collection has been opened via vault.collection() ` +\n `at least once before running the query.`,\n )\n }\n\n const maxRows = leg.maxRows ?? DEFAULT_JOIN_MAX_ROWS\n\n // Per-leg left-side ceiling check. In a\n // multi-FK chain, each leg's `maxRows` is enforced independently\n // against the current left-row count, so\n // `.join('a', { maxRows: 100_000 }).join('b', { maxRows: 50 })`\n // correctly throws on the second leg if the left set exceeds 50.\n if (leftRows.length > maxRows) {\n throw new JoinTooLargeError({\n leftRows: leftRows.length,\n rightRows: -1,\n maxRows,\n side: 'left',\n message:\n `.join() left side has ${leftRows.length} rows, exceeding the ${maxRows}-row ` +\n `ceiling for target \"${leg.target}\". Filter the left side further with ` +\n `where()/limit() before joining, or raise the ceiling via { maxRows }. ` +\n `Streaming joins over scan() are not yet supported.`,\n })\n }\n if (leftRows.length > maxRows * JOIN_WARN_FRACTION) {\n warnCeilingApproaching(leg.target, 'left', leftRows.length, maxRows)\n }\n\n const rightSnapshot = source.snapshot()\n if (rightSnapshot.length > maxRows) {\n throw new JoinTooLargeError({\n leftRows: leftRows.length,\n rightRows: rightSnapshot.length,\n maxRows,\n side: 'right',\n message:\n `.join() right side \"${leg.target}\" has ${rightSnapshot.length} rows, ` +\n `exceeding the ${maxRows}-row ceiling. Raise the ceiling via { maxRows } ` +\n `if the data genuinely fits in memory, or track for streaming joins.`,\n })\n }\n if (rightSnapshot.length > maxRows * JOIN_WARN_FRACTION) {\n warnCeilingApproaching(leg.target, 'right', rightSnapshot.length, maxRows)\n }\n\n // `join`-layer dressing (#650 Task 6, #626 retirement). When the query\n // carries a locale (per-call or the owning collection's default) and the\n // right side declares a `presentForJoin` hook, resolve each matched right\n // record through it before it's attached. Locale-less → leave raw.\n const effLocale = locale ?? context.defaultLocale\n const presentResolve: ((right: unknown) => unknown) | undefined =\n effLocale !== undefined && source.presentForJoin !== undefined\n ? (right) =>\n right !== null && typeof right === 'object'\n ? source.presentForJoin!(right, effLocale)\n : right\n : undefined\n\n // #1339 — a declared `on` replaces the FK lookup entirely: there is no\n // ref, so neither `lookupById` nor the id-keyed hash means anything. It\n // runs BEFORE the strategy/direction selection below because it answers\n // both questions itself (see `join-on.ts` for which strategy serves which\n // shape, and at what cost).\n if (leg.on !== undefined) {\n return declaredJoin(leftRows, leg, leg.on, rightSnapshot, maxRows, presentResolve)\n }\n\n // Strategy selection: explicit override wins; otherwise prefer\n // nested-loop when the source exposes lookupById (O(1) per row),\n // falling back to hash join when it doesn't.\n const strategy: JoinStrategy =\n leg.strategy ?? (source.lookupById ? 'nested' : 'hash')\n\n // #1289 — a right/full outer join cannot be driven by the left row's FK,\n // because the rows it must produce are exactly the ones no FK names. It\n // reverses the index instead: bucket the LEFT rows by their FK value, then\n // walk the right snapshot asking each record \"did anything point at me\".\n const direction = leg.direction ?? 'left'\n if (direction !== 'left') {\n return outerJoinFromRight(leftRows, leg, source, direction, presentResolve)\n }\n\n if (strategy === 'nested' && source.lookupById) {\n // Bind through an arrow so the `this` context of lookupById\n // doesn't drift — same pattern as the existing candidateRecords\n // helper in builder.ts.\n const lookup = (id: string): unknown => source.lookupById?.(id)\n return nestedLoopJoin(leftRows, leg, lookup, presentResolve)\n }\n return hashJoin(leftRows, leg, rightSnapshot, presentResolve)\n}\n\n/**\n * Execute a declared-`on` leg (#1339).\n *\n * The match set comes from `join-on.ts`; this function is only the part that\n * has to agree with the rest of `.join()` — the alias attachment, the\n * present/decode dressing, and the OUTPUT ceiling.\n *\n * ⚠️ The output ceiling is not redundant with the two side ceilings above. A\n * ref join is one-to-one, so `output === leftRows`; a declared join is\n * many-to-many, so 1,000 × 1,000 rows both comfortably under a 50,000-row\n * side ceiling can produce a million rows. Checking as rows are produced is\n * what makes an unbounded theta join an error rather than a hang.\n */\nfunction declaredJoin(\n leftRows: readonly unknown[],\n leg: JoinLeg,\n on: JoinOnPlan,\n rightSnapshot: readonly unknown[],\n maxRows: number,\n presentResolve?: (right: unknown) => unknown,\n): unknown[] {\n const matches = matchDeclaredJoin(leftRows, on, rightSnapshot, maxRows, produced => {\n throw new JoinTooLargeError({\n leftRows: leftRows.length,\n rightRows: rightSnapshot.length,\n maxRows,\n side: 'output',\n message:\n `.joinOn(\"${leg.target}\") produced more than ${maxRows} rows (${produced} and counting) from ` +\n `${leftRows.length} left x ${rightSnapshot.length} right. A declared \\`on\\` is many-to-many, so ` +\n `the per-side ceilings do not bound the result. Narrow the predicate, filter the left side ` +\n `with where()/limit() before joining, or raise the ceiling via { maxRows }.`,\n })\n })\n const out: unknown[] = []\n for (const { left, right } of matches) {\n const dressed = presentResolve && right !== undefined ? presentResolve(right) : right\n // `rawId` is `undefined` on purpose: a declared join has no ref, so\n // \"matched nothing\" is never a DANGLING ref — `attachJoin` reads a null\n // key as \"no reference at all\" and attaches null without consulting the\n // ref mode. An unmatched row is data, not corruption.\n out.push(attachJoin(left, leg, dressed, undefined))\n }\n return out\n}\n\nfunction nestedLoopJoin(\n leftRows: readonly unknown[],\n leg: JoinLeg,\n lookupById: (id: string) => unknown,\n presentResolve?: (right: unknown) => unknown,\n): unknown[] {\n const out: unknown[] = []\n for (const left of leftRows) {\n const rawId = readPath(left, leg.field)\n const key = coerceRefKey(rawId)\n let right = key === null ? undefined : lookupById(key)\n if (presentResolve && right !== undefined) right = presentResolve(right)\n out.push(attachJoin(left, leg, right, rawId))\n }\n return out\n}\n\nfunction hashJoin(\n leftRows: readonly unknown[],\n leg: JoinLeg,\n rightSnapshot: readonly unknown[],\n presentResolve?: (right: unknown) => unknown,\n): unknown[] {\n // Build the right-side hash once per query execution. We key on\n // the `id` field because ref() always points to a target's primary\n // key — non-equi and non-id joins are out of scope for.\n const rightMap = new Map<string, unknown>()\n for (const record of rightSnapshot) {\n const rawId = readPath(record, 'id')\n const key = coerceRefKey(rawId)\n if (key !== null) {\n rightMap.set(key, record)\n }\n }\n const out: unknown[] = []\n for (const left of leftRows) {\n const rawId = readPath(left, leg.field)\n const key = coerceRefKey(rawId)\n let right = key === null ? undefined : rightMap.get(key)\n if (presentResolve && right !== undefined) right = presentResolve(right)\n out.push(attachJoin(left, leg, right, rawId))\n }\n return out\n}\n\n/**\n * Bucket the left rows by the FK value they carry, so the right side can be\n * asked \"did anything point at this record\" in O(1).\n *\n * This IS the reverse index #1289 names. It is built per execution and lives\n * only for the length of the join: nothing is persisted, no store is touched,\n * and it costs one pass over the left set that the forward path does not pay.\n * Left rows with a null/uncoercible FK are absent from every bucket — they are\n * \"no reference at all\", never a match.\n */\nfunction reverseIndex(leftRows: readonly unknown[], field: string): Map<string, unknown[]> {\n return bucketByRefKey(leftRows, left => readPath(left, field))\n}\n\n/**\n * The reverse-FK index, generalised over what sits in the bucket (#1352).\n *\n * `outerJoinFromRight` buckets bare left ROWS by their FK; `traverse()`\n * buckets id-paired ENTRIES, because a child row alone cannot say what its\n * own id is (a Collection snapshot record carries no `id` field — the id is\n * the cache key). Same question — \"who points at this?\" — same coercion\n * rules, so it is deliberately one implementation rather than two that can\n * drift on what counts as a usable FK value.\n *\n * `readKey` extracts the raw FK from an item; `coerceRefKey` then decides\n * whether it is a key at all. An item whose FK is nullish, or is neither a\n * string nor a number, is dropped — \"no reference\", not \"a reference to\n * `[object Object]`\".\n */\nexport function bucketByRefKey<V>(\n items: readonly V[],\n readKey: (item: V) => unknown,\n): Map<string, V[]> {\n const buckets = new Map<string, V[]>()\n for (const item of items) {\n const key = coerceRefKey(readKey(item))\n if (key === null) continue\n const bucket = buckets.get(key)\n if (bucket) bucket.push(item)\n else buckets.set(key, [item])\n }\n return buckets\n}\n\n/**\n * Right / full outer join (#1289).\n *\n * Walks the RIGHT snapshot as the driving relation. A right record with a\n * non-empty bucket emits one row per left row in it (identical in shape to\n * what the forward path would have produced); a right record nothing points\n * at emits a LEFT-LESS row — `{ [leg.as]: right }` and nothing else, which is\n * SQL's \"the left columns are NULL\" rendered in an object language.\n *\n * `'full'` then appends the left rows the right side never claimed, in their\n * original order, with `null` under the alias — i.e. exactly the rows the\n * forward left-outer path would emit for them, ref-mode behaviour included.\n * `'right'` drops those rows, but still runs the ref-mode check on them: a\n * strict dangling ref is a data-integrity finding, and hiding it behind a\n * change of join direction would make corruption depend on which method the\n * caller happened to type.\n */\nfunction outerJoinFromRight(\n leftRows: readonly unknown[],\n leg: JoinLeg,\n source: JoinableSource,\n direction: JoinDirection,\n presentResolve?: (right: unknown) => unknown,\n): unknown[] {\n const byRight = reverseIndex(leftRows, leg.field)\n const matchedLeft = new Set<unknown>()\n const out: unknown[] = []\n\n // Prefer the id-paired view: a Collection record has no `id` field, so\n // reading one off the record would leave every bucket unmatched and turn a\n // right join into \"every right record is an orphan\" — wrong, and quietly so\n // in `cascade`/`warn` mode. The field fallback serves plain-object sources.\n const entries: readonly { id: string | null; record: unknown }[] =\n source.snapshotEntries?.() ??\n source.snapshot().map(record => ({ id: coerceRefKey(readPath(record, 'id')), record }))\n\n for (const { id: rid, record: right } of entries) {\n const dressed = presentResolve ? presentResolve(right) : right\n const bucket = rid === null ? undefined : byRight.get(rid)\n if (bucket === undefined || bucket.length === 0) {\n // Nothing points at this record — the row that only a right/full outer\n // join can produce.\n out.push({ [leg.as]: dressed })\n continue\n }\n for (const left of bucket) {\n matchedLeft.add(left)\n out.push(attachJoin(left, leg, dressed, readPath(left, leg.field)))\n }\n }\n\n for (const left of leftRows) {\n if (matchedLeft.has(left)) continue\n // Unmatched left row: `attachJoin` with an undefined right applies the\n // ref mode (strict throws, warn warns once) and attaches null.\n const row = attachJoin(left, leg, undefined, readPath(left, leg.field))\n if (direction === 'full') out.push(row)\n }\n\n return out\n}\n\n/**\n * Attach the resolved right-side record (or null) to the left row\n * under the alias, applying ref-mode semantics for the dangling\n * case.\n *\n * A left-side record whose FK field is null/undefined is NOT a\n * dangling ref — it's \"no reference at all\", which is always\n * allowed regardless of mode. This matches the write-time\n * `enforceRefsOnPut` behavior: \"Nullish ref values are allowed —\n * treat them as 'no reference'.\"\n *\n * Only non-null FKs pointing at non-existent targets trigger the\n * mode behavior.\n */\nfunction attachJoin(\n left: unknown,\n leg: JoinLeg,\n right: unknown,\n rawId: unknown,\n): unknown {\n if (left === null || typeof left !== 'object') {\n // Pathological input — return as-is. Shouldn't happen in\n // practice because QuerySource yields objects, but defensive\n // because plan execution is untyped at this layer.\n return left\n }\n const merged: Record<string, unknown> = { ...(left as Record<string, unknown>) }\n\n // \"No ref at all\" — null/undefined FK value, or a non-string/non-\n // number FK that coerceRefKey treated as no-ref. Never throws\n // regardless of mode; matches the write-time policy that nullish\n // refs are allowed.\n const refKey = coerceRefKey(rawId)\n if (right === undefined) {\n if (refKey !== null && leg.mode === 'strict') {\n throw new DanglingReferenceError({\n field: leg.field,\n target: leg.target,\n refId: refKey,\n message:\n `.join() strict dangling: record references \"${leg.target}:${refKey}\" ` +\n `via field \"${leg.field}\", but no such record exists. Use ref() mode 'warn' ` +\n `or 'cascade' if dangling refs are acceptable, or run ` +\n `vault.checkIntegrity() to find and fix the orphans.`,\n })\n }\n if (refKey !== null && leg.mode === 'warn') {\n warnOnceDangling(leg.field, leg.target, refKey)\n }\n // For 'cascade' and null refs we attach null silently. Cascade\n // is a delete-time mode; any dangling refs visible at read time\n // are either mid-flight or pre-existing orphans, not a DSL error.\n merged[leg.as] = null\n } else {\n merged[leg.as] = right\n }\n return merged\n}\n\n/**\n * Test-only: reset the join warning deduplication state between\n * tests. Production code never calls this — the dedup state is\n * intentionally process-scoped so a noisy query doesn't spam the\n * console once per component render.\n */\nexport function resetJoinWarnings(): void {\n warnedDanglingKeys.clear()\n warnedCeilingKeys.clear()\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// src/capsule/plumbing/kofn.ts
|
|
2
|
+
function evaluateKofN(results, min) {
|
|
3
|
+
if (!Number.isInteger(min) || min < 1 || min > results.length) {
|
|
4
|
+
throw new Error(
|
|
5
|
+
`evaluateKofN: min ${min} out of range 1..${results.length} \u2014 caller bug (matchGroup validates bounds up front, before any PBKDF2)`
|
|
6
|
+
);
|
|
7
|
+
}
|
|
8
|
+
let count = 0;
|
|
9
|
+
for (const r of results) {
|
|
10
|
+
if (r) count += 1;
|
|
11
|
+
}
|
|
12
|
+
return count >= min;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export {
|
|
16
|
+
evaluateKofN
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=chunk-NH2UOV3B.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/capsule/plumbing/kofn.ts"],"sourcesContent":["/**\n * k-of-n aggregate for matchGroup (§3). Deliberately a full scan that\n * never breaks: per-member results must never influence control flow in\n * a way an observer could time or decompose. Returns ONLY the aggregate.\n * @module\n */\nexport function evaluateKofN(results: readonly boolean[], min: number): boolean {\n if (!Number.isInteger(min) || min < 1 || min > results.length) {\n throw new Error(\n `evaluateKofN: min ${min} out of range 1..${results.length} — caller bug ` +\n `(matchGroup validates bounds up front, before any PBKDF2)`,\n )\n }\n let count = 0\n for (const r of results) {\n if (r) count += 1 // no short-circuit — collect, never break\n }\n return count >= min\n}\n"],"mappings":";AAMO,SAAS,aAAa,SAA6B,KAAsB;AAC9E,MAAI,CAAC,OAAO,UAAU,GAAG,KAAK,MAAM,KAAK,MAAM,QAAQ,QAAQ;AAC7D,UAAM,IAAI;AAAA,MACR,qBAAqB,GAAG,oBAAoB,QAAQ,MAAM;AAAA,IAE5D;AAAA,EACF;AACA,MAAI,QAAQ;AACZ,aAAW,KAAK,SAAS;AACvB,QAAI,EAAG,UAAS;AAAA,EAClB;AACA,SAAO,SAAS;AAClB;","names":[]}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// src/with-lookup/embeddings/with-vector-index.ts
|
|
2
|
+
var DEFAULT_INDEX_MIN_VECTORS = 2e4;
|
|
3
|
+
function withVectorIndex(opts = {}) {
|
|
4
|
+
const minVectors = opts.minVectors ?? DEFAULT_INDEX_MIN_VECTORS;
|
|
5
|
+
const nprobe = opts.nprobe ?? 8;
|
|
6
|
+
const nlist = opts.nlist;
|
|
7
|
+
const sampleSize = opts.sampleSize ?? 4096;
|
|
8
|
+
const iterations = opts.iterations ?? 6;
|
|
9
|
+
const seed = opts.seed ?? 2654435769;
|
|
10
|
+
return {
|
|
11
|
+
minVectors,
|
|
12
|
+
nprobe,
|
|
13
|
+
nlist,
|
|
14
|
+
sampleSize,
|
|
15
|
+
iterations,
|
|
16
|
+
seed,
|
|
17
|
+
async create() {
|
|
18
|
+
const { IvfFlatIndex } = await import("./ivf-flat-UZ6DQDLS.js");
|
|
19
|
+
return new IvfFlatIndex({ nlist, nprobe, sampleSize, iterations, seed });
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export {
|
|
25
|
+
DEFAULT_INDEX_MIN_VECTORS,
|
|
26
|
+
withVectorIndex
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=chunk-NYMLINRP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/with-lookup/embeddings/with-vector-index.ts"],"sourcesContent":["/**\n * `withVectorIndex()` — the opt-in for the approximate vector index (#1360).\n *\n * ```ts\n * import { withVectorIndex } from '@noy-db/hub/search'\n *\n * const col = vault.collection('docs', {\n * embeddings: { source: 'body', encode, dim: 768, model: 'e5-base',\n * index: withVectorIndex({ nprobe: 12 }) },\n * })\n * ```\n *\n * Three properties, each load-bearing:\n *\n * 1. **Opt-in.** No `index` on the descriptor and every search is exact brute\n * force, byte for byte the pre-#1360 path. Nothing about this file runs.\n * 2. **Tree-shaken.** The algorithm arrives through `await import()` inside\n * {@link create}, so a consumer of `@noy-db/hub/search` who never calls\n * this function never links `ivf-flat.js` into any chunk.\n * 3. **Still gated by scale even once opted in.** {@link\n * VectorIndexConfig.minVectors} defaults to the measured crossover, so a\n * small corpus pays no build cost and gets exact answers — opting in\n * declares a willingness to index, not an instruction to index now.\n */\nimport type { VectorIndex, VectorIndexConfig } from './vector-index.js'\n\nexport interface VectorIndexOptions {\n /**\n * Stay exact below this many VECTORS. Default 20,000.\n *\n * Chosen from `vector-brute-force.bench.ts`: below ~20k points the\n * brute-force scan is inside a 100 ms interactive budget at every dimension\n * measured (the tightest row, 1536d, crosses at ~18-48k depending on the\n * machine), and IVF's build — tens of brute-force-query-equivalents — has no\n * query volume to amortise against down there. Counts POINTS, not records — #1360\n * chunking puts one point per chunk, so 2,500 documents at 8 chunks each\n * already crosses this.\n */\n readonly minVectors?: number\n /**\n * Lists probed per query — **the recall dial**. Default 8.\n *\n * Recall rises monotonically with `nprobe`, and `nprobe = nlist` is\n * exhaustive — the same answer as brute force, by construction.\n *\n * MEASURED recall@10 at this default, against exact brute force on a\n * clustered corpus: **0.895** (768d, 100k vectors), **0.942** (384d, 100k),\n * **0.918** (1536d, 50k), **0.928** (64d, 20k — the CI assertion in\n * `__tests__/embeddings-ivf-recall.test.ts`). Raising it to 16 buys ~0.95\n * for roughly double the scan.\n *\n * Raise it when a miss costs more than a millisecond — and prefer\n * `{ exact: true }` on the query over `nprobe: nlist` when the answer must\n * be exact, because that says what you mean and survives an `nlist` change.\n */\n readonly nprobe?: number\n /** Partitions. Default: derived from the corpus size — see `defaultNlist`. */\n readonly nlist?: number\n /** Points sampled to fit the centroids. Default 4096. */\n readonly sampleSize?: number\n /** Lloyd iterations over the sample. Default 6. */\n readonly iterations?: number\n /** k-means++ seed. Default fixed, so the same corpus yields the same index. */\n readonly seed?: number\n}\n\n/** Vectors below which an opted-in collection still answers exactly. */\nexport const DEFAULT_INDEX_MIN_VECTORS = 20_000\n\nexport function withVectorIndex(opts: VectorIndexOptions = {}): VectorIndexConfig {\n const minVectors = opts.minVectors ?? DEFAULT_INDEX_MIN_VECTORS\n const nprobe = opts.nprobe ?? 8\n const nlist = opts.nlist\n const sampleSize = opts.sampleSize ?? 4096\n const iterations = opts.iterations ?? 6\n const seed = opts.seed ?? 0x9e3779b9\n return {\n minVectors, nprobe, nlist, sampleSize, iterations, seed,\n async create(): Promise<VectorIndex> {\n const { IvfFlatIndex } = await import('./ivf-flat.js')\n return new IvfFlatIndex({ nlist, nprobe, sampleSize, iterations, seed })\n },\n }\n}\n"],"mappings":";AAmEO,IAAM,4BAA4B;AAElC,SAAS,gBAAgB,OAA2B,CAAC,GAAsB;AAChF,QAAM,aAAa,KAAK,cAAc;AACtC,QAAM,SAAS,KAAK,UAAU;AAC9B,QAAM,QAAQ,KAAK;AACnB,QAAM,aAAa,KAAK,cAAc;AACtC,QAAM,aAAa,KAAK,cAAc;AACtC,QAAM,OAAO,KAAK,QAAQ;AAC1B,SAAO;AAAA,IACL;AAAA,IAAY;AAAA,IAAQ;AAAA,IAAO;AAAA,IAAY;AAAA,IAAY;AAAA,IACnD,MAAM,SAA+B;AACnC,YAAM,EAAE,aAAa,IAAI,MAAM,OAAO,wBAAe;AACrD,aAAO,IAAI,aAAa,EAAE,OAAO,QAAQ,YAAY,YAAY,KAAK,CAAC;AAAA,IACzE;AAAA,EACF;AACF;","names":[]}
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
IllegalTransitionError,
|
|
3
3
|
RecordLockedError,
|
|
4
4
|
ValidationError
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-37EPTBBR.js";
|
|
6
6
|
|
|
7
7
|
// src/with-audit/guards/with-guard.ts
|
|
8
8
|
function withGuard(strategy) {
|
|
@@ -124,4 +124,4 @@ export {
|
|
|
124
124
|
immutableGuard,
|
|
125
125
|
transitionGuard
|
|
126
126
|
};
|
|
127
|
-
//# sourceMappingURL=chunk-
|
|
127
|
+
//# sourceMappingURL=chunk-O2IMQSNA.js.map
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildLiveReduction,
|
|
3
|
+
compareReduced
|
|
4
|
+
} from "./chunk-N7UDP5VU.js";
|
|
5
|
+
import {
|
|
6
|
+
canonicalGroupKey
|
|
7
|
+
} from "./chunk-XZHEOSQ2.js";
|
|
8
|
+
import {
|
|
9
|
+
bindDistinctReducers,
|
|
10
|
+
moneySum,
|
|
11
|
+
sum
|
|
12
|
+
} from "./chunk-MBMTND6D.js";
|
|
13
|
+
import {
|
|
14
|
+
isDateTruncKey,
|
|
15
|
+
projectDateTruncKeys
|
|
16
|
+
} from "./chunk-XBKH4FOC.js";
|
|
17
|
+
import {
|
|
18
|
+
readPath
|
|
19
|
+
} from "./chunk-5WWDGFOS.js";
|
|
20
|
+
|
|
21
|
+
// src/with-lookup/reduce/window.ts
|
|
22
|
+
function isWindowFn(v) {
|
|
23
|
+
return typeof v === "object" && v !== null && v.__window === true;
|
|
24
|
+
}
|
|
25
|
+
function rowNumber() {
|
|
26
|
+
return {
|
|
27
|
+
__window: true,
|
|
28
|
+
op: "rowNumber",
|
|
29
|
+
evaluate: (rows) => rows.map((_, i) => i + 1)
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function rank() {
|
|
33
|
+
return {
|
|
34
|
+
__window: true,
|
|
35
|
+
op: "rank",
|
|
36
|
+
evaluate: (_rows, peerStart) => peerStart.map((start) => start + 1)
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function assertOffset(op, offset) {
|
|
40
|
+
if (!Number.isInteger(offset) || offset < 0) {
|
|
41
|
+
throw new Error(`${op}(): offset must be a non-negative integer, got ${offset}.`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function lag(field, offset = 1, defaultValue) {
|
|
45
|
+
assertOffset("lag", offset);
|
|
46
|
+
return {
|
|
47
|
+
__window: true,
|
|
48
|
+
op: "lag",
|
|
49
|
+
evaluate: (rows) => rows.map((_, i) => i - offset >= 0 ? readPath(rows[i - offset], field) : defaultValue)
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function lead(field, offset = 1, defaultValue) {
|
|
53
|
+
assertOffset("lead", offset);
|
|
54
|
+
return {
|
|
55
|
+
__window: true,
|
|
56
|
+
op: "lead",
|
|
57
|
+
evaluate: (rows) => rows.map((_, i) => i + offset < rows.length ? readPath(rows[i + offset], field) : defaultValue)
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function runningSum(field) {
|
|
61
|
+
return sum(field);
|
|
62
|
+
}
|
|
63
|
+
function runningMoneySum(field) {
|
|
64
|
+
return moneySum(field);
|
|
65
|
+
}
|
|
66
|
+
function asArray(v) {
|
|
67
|
+
if (v === void 0) return [];
|
|
68
|
+
return Array.isArray(v) ? v : [v];
|
|
69
|
+
}
|
|
70
|
+
function normalizeWindow(spec) {
|
|
71
|
+
const derived = [];
|
|
72
|
+
const keyOf = (k) => {
|
|
73
|
+
if (!isDateTruncKey(k)) return k;
|
|
74
|
+
derived.push(k);
|
|
75
|
+
return k.as;
|
|
76
|
+
};
|
|
77
|
+
const partitionKeys = asArray(spec.partitionBy).map(keyOf);
|
|
78
|
+
const orderBy = asArray(spec.orderBy).map((entry) => {
|
|
79
|
+
if (typeof entry === "string" || isDateTruncKey(entry)) {
|
|
80
|
+
return { key: keyOf(entry), direction: "asc" };
|
|
81
|
+
}
|
|
82
|
+
return { key: keyOf(entry.field), direction: entry.direction ?? "asc" };
|
|
83
|
+
});
|
|
84
|
+
return { partitionKeys, orderBy, derived };
|
|
85
|
+
}
|
|
86
|
+
function applyWindow(records, spec, select) {
|
|
87
|
+
const { partitionKeys, orderBy, derived } = normalizeWindow(spec);
|
|
88
|
+
const n = records.length;
|
|
89
|
+
if (n === 0) return [];
|
|
90
|
+
const keyRows = derived.length === 0 ? records : projectDateTruncKeys(records, derived);
|
|
91
|
+
const partitions = /* @__PURE__ */ new Map();
|
|
92
|
+
for (let i = 0; i < n; i++) {
|
|
93
|
+
let dedupKey = "";
|
|
94
|
+
if (partitionKeys.length > 0) {
|
|
95
|
+
const keyValues = {};
|
|
96
|
+
for (const f of partitionKeys) keyValues[f] = readPath(keyRows[i], f);
|
|
97
|
+
dedupKey = canonicalGroupKey(partitionKeys, keyValues);
|
|
98
|
+
}
|
|
99
|
+
const bucket = partitions.get(dedupKey);
|
|
100
|
+
if (bucket) bucket.push(i);
|
|
101
|
+
else partitions.set(dedupKey, [i]);
|
|
102
|
+
}
|
|
103
|
+
const compareByKeys = (a, b) => {
|
|
104
|
+
for (const { key, direction } of orderBy) {
|
|
105
|
+
const cmp = compareReduced(readPath(keyRows[a], key), readPath(keyRows[b], key));
|
|
106
|
+
if (cmp !== 0) return direction === "asc" ? cmp : -cmp;
|
|
107
|
+
}
|
|
108
|
+
return 0;
|
|
109
|
+
};
|
|
110
|
+
const slots = Object.entries(select);
|
|
111
|
+
const out = records.map((r) => ({ ...r }));
|
|
112
|
+
for (const indices of partitions.values()) {
|
|
113
|
+
indices.sort(compareByKeys);
|
|
114
|
+
const ordered = indices.map((i) => records[i]);
|
|
115
|
+
const peerStart = new Array(indices.length);
|
|
116
|
+
for (let k = 0; k < indices.length; k++) {
|
|
117
|
+
peerStart[k] = k === 0 || compareByKeys(indices[k - 1], indices[k]) !== 0 ? k : peerStart[k - 1];
|
|
118
|
+
}
|
|
119
|
+
for (const [name, slot] of slots) {
|
|
120
|
+
if (isWindowFn(slot)) {
|
|
121
|
+
const values = slot.evaluate(ordered, peerStart);
|
|
122
|
+
for (let k = 0; k < indices.length; k++) out[indices[k]][name] = values[k];
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
let state = slot.init();
|
|
126
|
+
for (let k = 0; k < indices.length; k++) {
|
|
127
|
+
state = slot.step(state, ordered[k]);
|
|
128
|
+
out[indices[k]][name] = slot.finalize(state);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return out;
|
|
133
|
+
}
|
|
134
|
+
function withWindow() {
|
|
135
|
+
return (executeRecords, spec, upstreams, via) => new WindowedQuery(executeRecords, spec, upstreams, via);
|
|
136
|
+
}
|
|
137
|
+
var WindowedQuery = class {
|
|
138
|
+
constructor(executeRecords, spec, upstreams, via) {
|
|
139
|
+
this.executeRecords = executeRecords;
|
|
140
|
+
this.spec = spec;
|
|
141
|
+
this.upstreams = upstreams;
|
|
142
|
+
this.via = via;
|
|
143
|
+
}
|
|
144
|
+
executeRecords;
|
|
145
|
+
spec;
|
|
146
|
+
upstreams;
|
|
147
|
+
via;
|
|
148
|
+
/**
|
|
149
|
+
* Attach window outputs to every row. Each slot is either a
|
|
150
|
+
* {@link WindowFn} (`rowNumber`, `rank`, `lag`, `lead`) or a `Reducer`,
|
|
151
|
+
* which runs as a running aggregate over `rows unbounded preceding →
|
|
152
|
+
* current row`.
|
|
153
|
+
*
|
|
154
|
+
* Reducers are rewritten through the collection's Via pipeline exactly as
|
|
155
|
+
* `.aggregate()` rewrites them, so a `sum` over a declared money field
|
|
156
|
+
* becomes the exact BigInt accumulator and a `countDistinct` dedups on the
|
|
157
|
+
* canonical index key.
|
|
158
|
+
*/
|
|
159
|
+
select(spec) {
|
|
160
|
+
const reducersOnly = {};
|
|
161
|
+
for (const [k, v] of Object.entries(spec)) {
|
|
162
|
+
if (!isWindowFn(v)) reducersOnly[k] = v;
|
|
163
|
+
}
|
|
164
|
+
const wrapped = bindDistinctReducers(
|
|
165
|
+
this.via ? this.via.wrapReducers(reducersOnly) : reducersOnly,
|
|
166
|
+
this.via
|
|
167
|
+
);
|
|
168
|
+
const effective = { ...spec };
|
|
169
|
+
for (const [k, v] of Object.entries(wrapped)) effective[k] = v;
|
|
170
|
+
return new WindowSelection(
|
|
171
|
+
this.executeRecords,
|
|
172
|
+
this.spec,
|
|
173
|
+
effective,
|
|
174
|
+
this.upstreams
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
var WindowSelection = class {
|
|
179
|
+
constructor(executeRecords, spec, select, upstreams) {
|
|
180
|
+
this.executeRecords = executeRecords;
|
|
181
|
+
this.spec = spec;
|
|
182
|
+
this.select = select;
|
|
183
|
+
this.upstreams = upstreams;
|
|
184
|
+
}
|
|
185
|
+
executeRecords;
|
|
186
|
+
spec;
|
|
187
|
+
select;
|
|
188
|
+
upstreams;
|
|
189
|
+
/** Execute the query and return every row, widened with the window outputs. */
|
|
190
|
+
run() {
|
|
191
|
+
return applyWindow(this.executeRecords(), this.spec, this.select);
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Reactive terminal — re-runs the whole window pipeline on every upstream
|
|
195
|
+
* change, the same naive-recompute contract `GroupedReduction.live()` has.
|
|
196
|
+
* Always call `live.stop()` when finished.
|
|
197
|
+
*/
|
|
198
|
+
live() {
|
|
199
|
+
return buildLiveReduction(() => this.run(), this.upstreams);
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
export {
|
|
204
|
+
rowNumber,
|
|
205
|
+
rank,
|
|
206
|
+
lag,
|
|
207
|
+
lead,
|
|
208
|
+
runningSum,
|
|
209
|
+
runningMoneySum,
|
|
210
|
+
applyWindow,
|
|
211
|
+
withWindow,
|
|
212
|
+
WindowedQuery,
|
|
213
|
+
WindowSelection
|
|
214
|
+
};
|
|
215
|
+
//# sourceMappingURL=chunk-O46CHQT7.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/with-lookup/reduce/window.ts"],"sourcesContent":["/**\n * Query DSL `.window()` — SQL window functions over the query's result rows\n * (#1349).\n *\n * ```ts\n * invoices.query()\n * .where('status', '==', 'open')\n * .window({ partitionBy: 'clientId', orderBy: 'date' })\n * .select({ balance: runningSum('amount'), prev: lag('amount', 1), n: rowNumber() })\n * .run()\n * ```\n *\n * Pure in-hub post-processing: the store holds ciphertext, so this runs after\n * decryption like every other query stage. No index is consulted — see\n * \"Complexity\" below for why the sorted-index fast path is deliberately not\n * taken in v1.\n *\n * ## What it is, precisely\n *\n * A window function adds COLUMNS to a row; it never adds, removes or reorders\n * rows. `.select()` therefore returns the query's own rows, in the query's own\n * order, each widened with the window outputs. `orderBy` inside `.window()`\n * decides how a PARTITION is walked; `Query.orderBy()` decides how the RESULT\n * is presented. That is SQL's split and both are honoured independently.\n *\n * ⭐ Distinguished from `.groupBy()` by ARITY: `.groupBy().aggregate()` emits\n * one row per bucket and drops the source rows; `.window().select()` keeps\n * every source row and attaches per-row values computed over its partition.\n *\n * ## The frame — `rows unbounded preceding → current row`, and only that\n *\n * A running aggregate at position `i` of its partition sees exactly rows\n * `0..i`. There is no `RANGE`, no `n preceding`, no `following`, and no\n * `frame` option to pass — explicit frames are a separate feature, and a\n * half-built frame surface is worse than none. `lag`/`lead` are navigation,\n * not aggregation, so they are unaffected by the frame.\n *\n * ## Ordering inside a partition is TOTAL\n *\n * Rows are sorted by the `orderBy` keys and, where those compare equal, by\n * their UPSTREAM POSITION — the sort is a stable sort over an ascending index\n * array, so equal keys keep the order the query produced them in. Without that\n * final key, `lag`/`lead` over equal keys would be a coin flip between runs.\n *\n * The value comparator is {@link compareReduced}, shared with the post-group\n * ordering of #1336 rather than reinvented, and for the same reason: a money\n * value reaches this stage DECODED, as an exact decimal string, and lexical\n * order gets `'9882.00'` vs `'10004.00'` backwards. (The pre-group row\n * pipeline asks `ViaPipeline.compareForOrder` instead — that reads the STORED\n * scaled-integer form, which is not what a decoded row holds, so it cannot\n * serve here.)\n *\n * PEER-ship for `rank` is decided by the `orderBy` keys ALONE, never by the\n * upstream tie-break — otherwise no two rows would ever be peers and `rank`\n * would collapse into `rowNumber`.\n *\n * ## Complexity, and the index question\n *\n * O(n log n): one partition pass, then a sort per partition. #1344's sorted\n * indexes could in principle make the sort a merge, but the input here is the\n * query's already-materialised, already-DECODED result rows — the index is\n * over stored (encoded) values on the collection, and it has no way to express\n * \"sorted within each partition of `clientId`\". Taking a fast path would mean\n * proving identical output including the upstream tie-break, which the index\n * cannot witness. So v1 sorts. This is the correct path, not a placeholder.\n *\n * ## Opting in — and why there is a second opt-in at all\n *\n * `withReduce()` alone does NOT light this up: `.window()` throws until the\n * strategy is built as `withReduce({ window: withWindow() })`. That is not\n * ceremony for its own sake — it is the SAME no-op-stub-until-opted-in rule\n * that keeps `Reduction`/`GroupedQuery` out of the floor bundle, applied one\n * level down. `withReduce()`'s returned object is a live value the bundler\n * cannot prove unused, so a `window()` method that named {@link WindowedQuery}\n * directly made this whole engine reachable from `withReduce` and charged it\n * to every consumer who opted into ordinary aggregation and will never call\n * `.window()`. Measured: the `analytics` bundle scenario went 960 → 1,845\n * gzipped bytes, +92%. Passing the factory in means the engine is reachable\n * only from a consumer that names `withWindow`.\n * ⛔ Do not \"simplify\" this back into `withReduce()` — `check-bundle.mjs`'s\n * `analytics` scenario carries a `WindowedQuery` eager-import canary that will\n * fail if you do.\n *\n * ## Not in `explain()`\n *\n * Same shape as #1336's post-group ops: `explain()` is a terminal on `Query`,\n * and `.window()` leaves `Query` for `WindowedQuery`, so there is no\n * `explain()` in the chain past this point to add a node to. The window stage\n * also has nothing to choose — one dispatch, over rows already in memory.\n */\n\nimport { readPath } from '../../kernel/query/predicate.js'\nimport { canonicalGroupKey } from './canonical-key.js'\nimport { compareReduced } from './groupby.js'\nimport type { Reducer } from './reducers.js'\nimport { bindDistinctReducers, sum, moneySum } from './reducers.js'\nimport type { ReductionUpstream, LiveReduction } from './reduction.js'\nimport { buildLiveReduction } from './reduction.js'\nimport type { DateTruncKey } from '../../kernel/query/reduce/date-trunc.js'\nimport { isDateTruncKey, projectDateTruncKeys } from '../../kernel/query/reduce/date-trunc.js'\nimport type { MoneyString } from '../../via/money/branded.js'\nimport type { ViaPipeline } from '../../kernel/via/pipeline.js'\n\n// ---------------------------------------------------------------------------\n// Spec surface\n// ---------------------------------------------------------------------------\n\n/** One ordering key inside a window: a field name, a `dateTrunc()` key, or either with a direction. */\nexport type WindowOrderInput<F extends string = string> =\n | F\n | DateTruncKey\n | { readonly field: F | DateTruncKey; readonly direction?: 'asc' | 'desc' }\n\n/**\n * The window definition passed to `.window()`.\n *\n * Both members are optional and mean what SQL's omissions mean: no\n * `partitionBy` is one partition holding the whole relation; no `orderBy`\n * makes every row in a partition a peer (so `rank()` is 1 throughout and a\n * running aggregate sees the rows in upstream order).\n */\nexport interface WindowSpec<F extends string = string> {\n /** Field name(s) and/or `dateTrunc()` key(s) to partition on. */\n readonly partitionBy?: F | DateTruncKey | readonly (F | DateTruncKey)[]\n /** How each partition is walked. Successive keys are tie-breakers. */\n readonly orderBy?: WindowOrderInput<F> | readonly WindowOrderInput<F>[]\n}\n\n/**\n * A non-aggregating window function (ranking or navigation). Built by the\n * factories below — the shape is opaque to consumers.\n */\nexport interface WindowFn<R = unknown> {\n readonly __window: true\n readonly op: 'rowNumber' | 'rank' | 'lag' | 'lead'\n /**\n * Compute one value per row of an ORDERED partition.\n * `peerStart[i]` is the index of the first row that compares equal to row\n * `i` under the window's `orderBy` keys.\n */\n evaluate(rows: readonly unknown[], peerStart: readonly number[]): R[]\n}\n\n/**\n * A `.select()` slot: either a window function or an ordinary {@link Reducer},\n * which runs as a RUNNING aggregate under the v1 frame. Any reducer works —\n * `count()`, `sum()`, `countDistinct()`, a custom one — so `runningSum` and\n * `runningMoneySum` below are named conveniences, not a separate mechanism.\n */\nexport type WindowSelectSpec = Readonly<Record<string, WindowFn<unknown> | Reducer<unknown, unknown>>>\n\n/** Result type of one `.select()` slot. */\ntype WindowSlotResult<V> =\n V extends WindowFn<infer R> ? R : V extends Reducer<infer R, unknown> ? R : unknown\n\n/** A window result row: the source record widened with the selected outputs. */\nexport type WindowRow<T, Spec extends WindowSelectSpec> = T & {\n [K in keyof Spec]: WindowSlotResult<Spec[K]>\n}\n\nfunction isWindowFn(v: unknown): v is WindowFn<unknown> {\n return typeof v === 'object' && v !== null && (v as { __window?: unknown }).__window === true\n}\n\n// ---------------------------------------------------------------------------\n// Window function factories\n// ---------------------------------------------------------------------------\n\n/**\n * Sequential position of the row within its partition, starting at 1. NEVER\n * repeats — two rows that tie under `orderBy` still get distinct numbers,\n * resolved by the upstream tie-break. Use {@link rank} when ties should share\n * a number.\n */\nexport function rowNumber(): WindowFn<number> {\n return {\n __window: true,\n op: 'rowNumber',\n evaluate: (rows) => rows.map((_, i) => i + 1),\n }\n}\n\n/**\n * Competition rank within the partition, starting at 1. Rows that compare\n * EQUAL under the window's `orderBy` keys share a rank, and the next distinct\n * value SKIPS the ranks they consumed — `1, 2, 2, 4`. This is the only place\n * `rank` and {@link rowNumber} differ, so a fixture without ties cannot tell\n * them apart.\n *\n * With no `orderBy` every row is a peer and every rank is 1.\n */\nexport function rank(): WindowFn<number> {\n return {\n __window: true,\n op: 'rank',\n evaluate: (_rows, peerStart) => peerStart.map((start) => start + 1),\n }\n}\n\nfunction assertOffset(op: 'lag' | 'lead', offset: number): void {\n if (!Number.isInteger(offset) || offset < 0) {\n throw new Error(`${op}(): offset must be a non-negative integer, got ${offset}.`)\n }\n}\n\n/**\n * Value of `field` from the row `offset` positions EARLIER in the partition.\n * Returns `defaultValue` (default `undefined`) for the first `offset` rows.\n */\nexport function lag<R = unknown>(field: string, offset = 1, defaultValue?: R): WindowFn<R | undefined> {\n assertOffset('lag', offset)\n return {\n __window: true,\n op: 'lag',\n evaluate: (rows) =>\n rows.map((_, i) => (i - offset >= 0 ? (readPath(rows[i - offset], field) as R) : defaultValue)),\n }\n}\n\n/**\n * Value of `field` from the row `offset` positions LATER in the partition.\n * Returns `defaultValue` (default `undefined`) for the last `offset` rows.\n */\nexport function lead<R = unknown>(field: string, offset = 1, defaultValue?: R): WindowFn<R | undefined> {\n assertOffset('lead', offset)\n return {\n __window: true,\n op: 'lead',\n evaluate: (rows) =>\n rows.map((_, i) => (i + offset < rows.length ? (readPath(rows[i + offset], field) as R) : defaultValue)),\n }\n}\n\n/**\n * Running total of a numeric `field` over `rows unbounded preceding → current\n * row`. Identical to passing `sum(field)` — named for the reading.\n *\n * ⚠️ For a declared money field use {@link runningMoneySum}: it is the same\n * reducer, but typed `MoneyString` to match what the exact BigInt rewrite\n * actually returns.\n */\nexport function runningSum(field: string): Reducer<number> {\n return sum(field)\n}\n\n/**\n * Running total of a **declared money field**, exact at any magnitude.\n *\n * The reducer is the ordinary money `sum`, and it is rewritten by\n * `ViaPipeline.wrapReducers` into `via/money/money-reducer.ts`'s BigInt\n * accumulator at `.select()` time — the SAME rewrite `.aggregate()` and\n * `.groupBy()` get, so a running balance and a grand total cannot disagree.\n * Nothing here touches a float: values accumulate as scaled `bigint`s and each\n * row's value is `formatScaledInt`'d out of the state at that point.\n */\nexport function runningMoneySum(field: string): Reducer<MoneyString> {\n return moneySum(field)\n}\n\n// ---------------------------------------------------------------------------\n// Engine\n// ---------------------------------------------------------------------------\n\ninterface NormalizedOrder {\n /** Output key to read (a derived key's `as`, or the plain field name). */\n readonly key: string\n readonly direction: 'asc' | 'desc'\n}\n\ninterface NormalizedWindow {\n readonly partitionKeys: readonly string[]\n readonly orderBy: readonly NormalizedOrder[]\n readonly derived: readonly DateTruncKey[]\n}\n\nfunction asArray<V>(v: V | readonly V[] | undefined): readonly V[] {\n if (v === undefined) return []\n return Array.isArray(v) ? (v as readonly V[]) : [v as V]\n}\n\n/**\n * Resolve the spec into flat key lists plus the derived calendar keys that\n * must be projected before any of them can be read.\n *\n * NOT exported: `NormalizedWindow` is an implementation shape, and exporting\n * the function without it trips `check:types` (a subpath must be able to name\n * every type its own signatures mention).\n */\nfunction normalizeWindow(spec: WindowSpec): NormalizedWindow {\n const derived: DateTruncKey[] = []\n const keyOf = (k: string | DateTruncKey): string => {\n if (!isDateTruncKey(k)) return k\n derived.push(k)\n return k.as\n }\n const partitionKeys = asArray<string | DateTruncKey>(spec.partitionBy).map(keyOf)\n const orderBy = asArray<WindowOrderInput>(spec.orderBy).map((entry): NormalizedOrder => {\n if (typeof entry === 'string' || isDateTruncKey(entry)) {\n return { key: keyOf(entry), direction: 'asc' }\n }\n return { key: keyOf(entry.field), direction: entry.direction ?? 'asc' }\n })\n return { partitionKeys, orderBy, derived }\n}\n\n/**\n * Execute the window stage. Pure function over a row array — exported for\n * tests and for any future `scan().window()` reuse.\n *\n * Rows are returned in INPUT order, each a shallow copy widened with the\n * selected outputs. A `dateTrunc()` partition key is read off an internal\n * projection and is deliberately NOT stamped on the output row — unlike\n * `.groupBy()`, where the derived key IS the result key.\n */\nexport function applyWindow<R>(\n records: readonly unknown[],\n spec: WindowSpec,\n select: WindowSelectSpec,\n): R[] {\n const { partitionKeys, orderBy, derived } = normalizeWindow(spec)\n const n = records.length\n if (n === 0) return []\n\n // Keys are read off a projected copy so a derived calendar bucket looks like\n // an ordinary field; the OUTPUT is built from the untouched original.\n const keyRows: readonly unknown[] =\n derived.length === 0 ? records : projectDateTruncKeys(records, derived)\n\n // Partition. Indices, not rows, so the upstream position survives as the\n // final ordering key. Map preserves insertion order (irrelevant to output\n // ordering here, but it keeps the walk deterministic).\n const partitions = new Map<string, number[]>()\n for (let i = 0; i < n; i++) {\n let dedupKey = ''\n if (partitionKeys.length > 0) {\n const keyValues: Record<string, unknown> = {}\n for (const f of partitionKeys) keyValues[f] = readPath(keyRows[i], f)\n dedupKey = canonicalGroupKey(partitionKeys, keyValues)\n }\n const bucket = partitions.get(dedupKey)\n if (bucket) bucket.push(i)\n else partitions.set(dedupKey, [i])\n }\n\n // Compare two rows by the orderBy keys ONLY — peer-ship for `rank` is\n // decided here, so the upstream tie-break must not participate.\n const compareByKeys = (a: number, b: number): number => {\n for (const { key, direction } of orderBy) {\n const cmp = compareReduced(readPath(keyRows[a], key), readPath(keyRows[b], key))\n if (cmp !== 0) return direction === 'asc' ? cmp : -cmp\n }\n return 0\n }\n\n const slots = Object.entries(select)\n const out: Record<string, unknown>[] = records.map((r) => ({ ...(r as Record<string, unknown>) }))\n\n for (const indices of partitions.values()) {\n // Stable sort over an ascending index array ⇒ equal keys keep upstream\n // order, which is what makes the ordering total.\n indices.sort(compareByKeys)\n const ordered = indices.map((i) => records[i])\n\n // peerStart[k] = index of the first row of k's tie-group under `orderBy`.\n const peerStart: number[] = new Array<number>(indices.length)\n for (let k = 0; k < indices.length; k++) {\n peerStart[k] = k === 0 || compareByKeys(indices[k - 1]!, indices[k]!) !== 0 ? k : peerStart[k - 1]!\n }\n\n for (const [name, slot] of slots) {\n if (isWindowFn(slot)) {\n const values = slot.evaluate(ordered, peerStart)\n for (let k = 0; k < indices.length; k++) out[indices[k]!]![name] = values[k]\n continue\n }\n // Running aggregate under the v1 frame: step, then finalize, per row.\n let state = slot.init()\n for (let k = 0; k < indices.length; k++) {\n state = slot.step(state, ordered[k])\n out[indices[k]!]![name] = slot.finalize(state)\n }\n }\n }\n\n return out as R[]\n}\n\n// ---------------------------------------------------------------------------\n// Chainable wrappers\n// ---------------------------------------------------------------------------\n\n/**\n * What `withWindow()` hands to `withReduce()`. Named as a type so\n * `strategy.ts` / `active.ts` can speak it in a TYPE-ONLY import and never\n * pull this module into their runtime graph.\n */\nexport type WindowFactory = <T>(\n executeRecords: () => readonly unknown[],\n spec: WindowSpec,\n upstreams: readonly ReductionUpstream[],\n via?: ViaPipeline,\n) => WindowedQuery<T>\n\n/**\n * Light up `.window()` on `Query`.\n *\n * ```ts\n * import { withReduce, withWindow } from '@noy-db/hub/reduce'\n * createNoydb({ store, user, secret, reduceStrategy: withReduce({ window: withWindow() }) })\n * ```\n *\n * The only reference to {@link WindowedQuery} outside this module's own\n * consumers — see \"Opting in\" in the module docs for why that matters.\n */\nexport function withWindow(): WindowFactory {\n return <T>(\n executeRecords: () => readonly unknown[],\n spec: WindowSpec,\n upstreams: readonly ReductionUpstream[],\n via?: ViaPipeline,\n ): WindowedQuery<T> => new WindowedQuery<T>(executeRecords, spec, upstreams, via)\n}\n\n/**\n * Chainable wrapper returned by `Query.window(spec)`. Terminates with\n * `.select(spec)`, which is the only operation on it — a window with nothing\n * selected computes nothing.\n */\nexport class WindowedQuery<T> {\n constructor(\n private readonly executeRecords: () => readonly unknown[],\n private readonly spec: WindowSpec,\n private readonly upstreams: readonly ReductionUpstream[],\n private readonly via?: ViaPipeline,\n ) {\n // T is phantom on the wrapper so a consumer still sees the row type on\n // hover. Reference it to keep lint quiet.\n void undefined as T | undefined\n }\n\n /**\n * Attach window outputs to every row. Each slot is either a\n * {@link WindowFn} (`rowNumber`, `rank`, `lag`, `lead`) or a `Reducer`,\n * which runs as a running aggregate over `rows unbounded preceding →\n * current row`.\n *\n * Reducers are rewritten through the collection's Via pipeline exactly as\n * `.aggregate()` rewrites them, so a `sum` over a declared money field\n * becomes the exact BigInt accumulator and a `countDistinct` dedups on the\n * canonical index key.\n */\n select<Spec extends WindowSelectSpec>(spec: Spec): WindowSelection<WindowRow<T, Spec>> {\n const reducersOnly: Record<string, Reducer<unknown, unknown>> = {}\n for (const [k, v] of Object.entries(spec)) {\n if (!isWindowFn(v)) reducersOnly[k] = v\n }\n const wrapped = bindDistinctReducers(\n this.via ? this.via.wrapReducers(reducersOnly) : reducersOnly,\n this.via,\n )\n const effective: Record<string, WindowFn<unknown> | Reducer<unknown, unknown>> = { ...spec }\n for (const [k, v] of Object.entries(wrapped)) effective[k] = v\n return new WindowSelection<WindowRow<T, Spec>>(\n this.executeRecords,\n this.spec,\n effective,\n this.upstreams,\n )\n }\n}\n\n/**\n * The `.window(...).select(...)` terminal. Mirrors `GroupedReduction`'s shape\n * — `.run()` and `.live()` — minus the post-group stage: ordering and limiting\n * of window OUTPUT rows belong on the underlying `Query`, before `.window()`,\n * because a window never changes the row set.\n */\nexport class WindowSelection<R> {\n constructor(\n private readonly executeRecords: () => readonly unknown[],\n private readonly spec: WindowSpec,\n private readonly select: WindowSelectSpec,\n private readonly upstreams: readonly ReductionUpstream[],\n ) {}\n\n /** Execute the query and return every row, widened with the window outputs. */\n run(): R[] {\n return applyWindow<R>(this.executeRecords(), this.spec, this.select)\n }\n\n /**\n * Reactive terminal — re-runs the whole window pipeline on every upstream\n * change, the same naive-recompute contract `GroupedReduction.live()` has.\n * Always call `live.stop()` when finished.\n */\n live(): LiveReduction<R[]> {\n return buildLiveReduction<R[]>(() => this.run(), this.upstreams)\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import {
|
|
2
|
+
NoydbError
|
|
3
|
+
} from "./chunk-37EPTBBR.js";
|
|
4
|
+
|
|
5
|
+
// src/capsule/contract.ts
|
|
6
|
+
function assertCapsuleSupports(caps, group, requirer) {
|
|
7
|
+
if (!caps.has(group)) throw new CapsuleNotSupportedError(group, requirer);
|
|
8
|
+
}
|
|
9
|
+
var CapsuleNotSupportedError = class extends NoydbError {
|
|
10
|
+
constructor(group, requirer) {
|
|
11
|
+
super(
|
|
12
|
+
"CAPSULE_NOT_SUPPORTED",
|
|
13
|
+
`Capsule does not support the "${group}" group, which "${requirer}" requires. An exclave capsule refuses "authenticate" and "seal" by design \u2014 services that need them cannot be used with it. Check capabilities().`
|
|
14
|
+
);
|
|
15
|
+
this.group = group;
|
|
16
|
+
this.requirer = requirer;
|
|
17
|
+
this.name = "CapsuleNotSupportedError";
|
|
18
|
+
}
|
|
19
|
+
group;
|
|
20
|
+
requirer;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export {
|
|
24
|
+
assertCapsuleSupports,
|
|
25
|
+
CapsuleNotSupportedError
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=chunk-OIEO4WDL.js.map
|