@noy-db/hub 0.7.0 → 0.8.0-pre.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 +105 -14
- package/LICENSE +202 -21
- package/NOTICE +1 -0
- package/README.md +27 -10
- package/codemods/0.8.0-pre.json +61 -0
- package/dist/api-GVYEKSJE.js +19 -0
- package/dist/as/index.js +11 -11
- package/dist/at/index.js +9 -9
- package/dist/attestation/index.js +20 -20
- package/dist/{backup-IJTB4S4M.js → backup-7TFRVFLH.js} +21 -15
- package/dist/backup-7TFRVFLH.js.map +1 -0
- package/dist/blobs/index.js +13 -13
- package/dist/broker/index.js +12 -12
- package/dist/by/index.js +2 -2
- package/dist/cargo/index.js +39 -36
- package/dist/{chunk-7O3Y4PPD.js → chunk-244VXYPG.js} +140 -16
- package/dist/chunk-244VXYPG.js.map +1 -0
- package/dist/{chunk-BUE2D7PX.js → chunk-32YV3TJT.js} +2 -2
- package/dist/{chunk-3RCJJBNR.js → chunk-3ELRMVJK.js} +12 -12
- package/dist/{chunk-6GMZ7HEE.js → chunk-3F7GLNAE.js} +6 -6
- package/dist/{chunk-2Y4IMKA6.js → chunk-3H5KLDZN.js} +4 -4
- package/dist/{chunk-VTFVLCUH.js → chunk-3JWHAR6E.js} +2 -2
- package/dist/{chunk-YMUFFJCO.js → chunk-3TDUWVWB.js} +5 -2
- package/dist/chunk-3TDUWVWB.js.map +1 -0
- package/dist/{chunk-JBDFMYKQ.js → chunk-4AF3TUMP.js} +2 -2
- package/dist/{chunk-ZORTV6NH.js → chunk-4I522ERM.js} +88 -4
- package/dist/chunk-4I522ERM.js.map +1 -0
- package/dist/{chunk-MUM7IANK.js → chunk-4MXI3ODD.js} +4 -4
- package/dist/chunk-4MXI3ODD.js.map +1 -0
- package/dist/{chunk-BLN54W3L.js → chunk-5FDLC6G7.js} +56 -3
- package/dist/chunk-5FDLC6G7.js.map +1 -0
- package/dist/chunk-5O7D6ZTW.js +53 -0
- package/dist/chunk-5O7D6ZTW.js.map +1 -0
- package/dist/{chunk-J6FXAEUG.js → chunk-6B3VNR4P.js} +12 -12
- package/dist/{chunk-TUFM4UZP.js → chunk-6K7DPM7D.js} +2 -2
- package/dist/{chunk-K6LHRFBL.js → chunk-6LMQ5R26.js} +7 -7
- package/dist/{chunk-SPXXX5E4.js → chunk-6LNL42F5.js} +94 -32
- package/dist/chunk-6LNL42F5.js.map +1 -0
- package/dist/{chunk-XLMEZIAJ.js → chunk-6OWXYZK2.js} +2 -2
- package/dist/{chunk-BOWNCWZT.js → chunk-6QSQQLSE.js} +3 -3
- package/dist/chunk-7JE7BDYJ.js +1558 -0
- package/dist/chunk-7JE7BDYJ.js.map +1 -0
- package/dist/{chunk-KG7TZKZG.js → chunk-7VCXZDA4.js} +5 -5
- package/dist/chunk-7VCXZDA4.js.map +1 -0
- package/dist/{chunk-NQKIUNW5.js → chunk-A6IJU4TK.js} +2 -2
- package/dist/{chunk-BM5TWITZ.js → chunk-ANWPSTZU.js} +38 -9
- package/dist/chunk-ANWPSTZU.js.map +1 -0
- package/dist/{chunk-QIZPZMUI.js → chunk-AOWGXU6D.js} +2 -2
- package/dist/{chunk-CUZLNGD5.js → chunk-B2YY6WDD.js} +1 -1
- package/dist/chunk-B2YY6WDD.js.map +1 -0
- package/dist/{chunk-SFAWCTEM.js → chunk-B57AFBY2.js} +2 -2
- package/dist/{chunk-GPEQUXHL.js → chunk-B6SJIBQK.js} +4 -4
- package/dist/chunk-BJ2IXQ5Q.js +100 -0
- package/dist/chunk-BJ2IXQ5Q.js.map +1 -0
- package/dist/{chunk-Q2PU57HC.js → chunk-BK2HHQGN.js} +2 -2
- package/dist/chunk-BKT776R5.js +1 -0
- package/dist/{chunk-KUX3OB6D.js → chunk-BP6DARYA.js} +33 -5
- package/dist/chunk-BP6DARYA.js.map +1 -0
- package/dist/{chunk-FXBIP2WD.js → chunk-BUDAGWL5.js} +6 -6
- package/dist/chunk-CF5UU4S7.js +757 -0
- package/dist/chunk-CF5UU4S7.js.map +1 -0
- package/dist/{chunk-BOET4NA4.js → chunk-CKNGS5MH.js} +3 -3
- package/dist/chunk-CY2CYVWZ.js +41 -0
- package/dist/chunk-CY2CYVWZ.js.map +1 -0
- package/dist/{chunk-2577DKXB.js → chunk-DC5QVPV7.js} +2 -2
- package/dist/chunk-DC5QVPV7.js.map +1 -0
- package/dist/{chunk-YSRUYAVU.js → chunk-DE4DH2RZ.js} +2 -2
- package/dist/{chunk-6I2RQCET.js → chunk-DF73H4UN.js} +4 -4
- package/dist/{chunk-4GVM6QZA.js → chunk-ENAG3IY7.js} +2 -2
- package/dist/chunk-ENAG3IY7.js.map +1 -0
- package/dist/{chunk-K7NTTA6P.js → chunk-EOVMT6TB.js} +2 -2
- package/dist/chunk-F24ZZTHQ.js +193 -0
- package/dist/chunk-F24ZZTHQ.js.map +1 -0
- package/dist/chunk-F2TDU7MQ.js +456 -0
- package/dist/chunk-F2TDU7MQ.js.map +1 -0
- package/dist/chunk-F6NCB7KT.js +13 -0
- package/dist/chunk-F6NCB7KT.js.map +1 -0
- package/dist/{chunk-SPYWXKJN.js → chunk-F7XGHL5O.js} +3 -3
- package/dist/chunk-F7XGHL5O.js.map +1 -0
- package/dist/{chunk-XTXOCYOJ.js → chunk-FCKWQE2H.js} +5 -5
- package/dist/{chunk-U4FOQDY4.js → chunk-FH2L2E34.js} +4 -4
- package/dist/chunk-FH2L2E34.js.map +1 -0
- package/dist/{chunk-4OZNXTO4.js → chunk-FN5EBVTQ.js} +2 -2
- package/dist/chunk-FQ54DWUQ.js +270 -0
- package/dist/chunk-FQ54DWUQ.js.map +1 -0
- package/dist/{chunk-NKHRDYOR.js → chunk-FQ5VRHIB.js} +4 -4
- package/dist/{chunk-FAHMLERK.js → chunk-FW22ZCXT.js} +2 -2
- package/dist/chunk-FXQBGFOX.js +524 -0
- package/dist/chunk-FXQBGFOX.js.map +1 -0
- package/dist/{chunk-AO42KJO6.js → chunk-GF5BZ7D4.js} +45 -9
- package/dist/chunk-GF5BZ7D4.js.map +1 -0
- package/dist/{chunk-TRGTKX5E.js → chunk-GHLTDZRS.js} +5 -3
- package/dist/{chunk-TRGTKX5E.js.map → chunk-GHLTDZRS.js.map} +1 -1
- package/dist/{chunk-5WDXHNSW.js → chunk-HBPPGWUM.js} +5 -5
- package/dist/chunk-HBPPGWUM.js.map +1 -0
- package/dist/{chunk-KTFRCC5C.js → chunk-HBRLNOHL.js} +82 -8
- package/dist/chunk-HBRLNOHL.js.map +1 -0
- package/dist/chunk-HLEK5VAN.js +275 -0
- package/dist/chunk-HLEK5VAN.js.map +1 -0
- package/dist/{chunk-RMS3NEA3.js → chunk-HT2AHGQI.js} +2 -2
- package/dist/{chunk-CHJBLCOG.js → chunk-HVSCEIYL.js} +7 -7
- package/dist/{chunk-UXWB3FPF.js → chunk-I3JDRCMW.js} +150 -22
- package/dist/chunk-I3JDRCMW.js.map +1 -0
- package/dist/{chunk-GY4WYNNG.js → chunk-ID6Z6E66.js} +2 -2
- package/dist/{chunk-EYBQEIUY.js → chunk-IEX7NK2K.js} +3 -3
- package/dist/{chunk-KUJDV5QH.js → chunk-ISZQJBML.js} +5 -5
- package/dist/{chunk-LWBCUYZW.js → chunk-IT22PWKV.js} +2 -2
- package/dist/{chunk-EQEYOJBM.js → chunk-IUWCVHQ7.js} +3 -3
- package/dist/chunk-IUWCVHQ7.js.map +1 -0
- package/dist/{chunk-7V4TP3AF.js → chunk-J6UOHJY5.js} +4 -4
- package/dist/{chunk-JMGDHKQF.js → chunk-JCN44NCY.js} +2 -2
- package/dist/{chunk-CARABLSQ.js → chunk-K6W7BVZ6.js} +3 -3
- package/dist/{chunk-77K4PG6P.js → chunk-KJFW62P4.js} +29 -11
- package/dist/chunk-KJFW62P4.js.map +1 -0
- package/dist/{chunk-453F654R.js → chunk-L7DOS3TE.js} +2 -2
- package/dist/chunk-LGNDFRYC.js +23 -0
- package/dist/chunk-LGNDFRYC.js.map +1 -0
- package/dist/{chunk-WEQEYLCS.js → chunk-LGRLME4M.js} +7 -7
- package/dist/{chunk-RMF67KCG.js → chunk-LQ4ZHOKP.js} +2 -2
- package/dist/{chunk-ZVO4QVPD.js → chunk-M522UYZ2.js} +5 -5
- package/dist/{chunk-G56KBWFY.js → chunk-M7NI3IWE.js} +45 -12
- package/dist/chunk-M7NI3IWE.js.map +1 -0
- package/dist/chunk-MDWKM2XC.js +293 -0
- package/dist/chunk-MDWKM2XC.js.map +1 -0
- package/dist/chunk-MKXXMNJH.js +204 -0
- package/dist/chunk-MKXXMNJH.js.map +1 -0
- package/dist/{chunk-SKGMN35F.js → chunk-MLPHLJIQ.js} +3 -3
- package/dist/chunk-MLPHLJIQ.js.map +1 -0
- package/dist/{chunk-2N4GY74U.js → chunk-MTL7MXGR.js} +6 -6
- package/dist/{chunk-TFR7DSOV.js → chunk-MVZ2TPVP.js} +2 -2
- package/dist/{chunk-CPWQB3N5.js → chunk-N5DNADLQ.js} +7 -7
- package/dist/{chunk-ELNXJMGB.js → chunk-NNARWO72.js} +6 -6
- package/dist/{chunk-PT43Y56J.js → chunk-NRT6QZQB.js} +102 -16
- package/dist/chunk-NRT6QZQB.js.map +1 -0
- package/dist/{chunk-QIBVIOXO.js → chunk-NWHBJQAL.js} +99 -8
- package/dist/chunk-NWHBJQAL.js.map +1 -0
- package/dist/chunk-NYMLINRP.js +28 -0
- package/dist/chunk-NYMLINRP.js.map +1 -0
- package/dist/{chunk-7MG7SJT7.js → chunk-ODVPTDPK.js} +1 -1
- package/dist/chunk-ODVPTDPK.js.map +1 -0
- package/dist/chunk-ORDURZBU.js +461 -0
- package/dist/chunk-ORDURZBU.js.map +1 -0
- package/dist/{chunk-6YXCPL4T.js → chunk-PDCG6PR5.js} +2 -2
- package/dist/{chunk-REDOOY2Q.js → chunk-PSIV7CJV.js} +2 -2
- package/dist/{chunk-NA2NIJZI.js → chunk-QBBUZ3I3.js} +126 -19
- package/dist/chunk-QBBUZ3I3.js.map +1 -0
- package/dist/{chunk-5VCRVKOZ.js → chunk-QOOUUR4A.js} +6 -4
- package/dist/{chunk-5VCRVKOZ.js.map → chunk-QOOUUR4A.js.map} +1 -1
- package/dist/{chunk-ANATMFIO.js → chunk-QWFHIOD2.js} +5 -5
- package/dist/{chunk-X2DLENDQ.js → chunk-QWGU66MP.js} +3 -3
- package/dist/chunk-RHVMZSUU.js +7 -0
- package/dist/chunk-RHVMZSUU.js.map +1 -0
- package/dist/{chunk-BSFNRLK2.js → chunk-S57HTZ6X.js} +5 -5
- package/dist/{chunk-SZJ3DLZA.js → chunk-SEE332EV.js} +2 -2
- package/dist/{chunk-YYP7WSEB.js → chunk-SI3V7D4G.js} +2 -2
- package/dist/{chunk-UGTBXF5U.js → chunk-SOIQ4MM4.js} +3 -3
- package/dist/chunk-SUZKW6UR.js +25 -0
- package/dist/chunk-SUZKW6UR.js.map +1 -0
- package/dist/{chunk-VXGSWL6L.js → chunk-SYVZW77S.js} +6 -6
- package/dist/{chunk-6GOE5PGN.js → chunk-T2LBQ5DV.js} +883 -227
- package/dist/chunk-T2LBQ5DV.js.map +1 -0
- package/dist/chunk-T52GX4SA.js +215 -0
- package/dist/chunk-T52GX4SA.js.map +1 -0
- package/dist/{chunk-MVMXZYXT.js → chunk-TKUOEU2F.js} +2 -2
- package/dist/chunk-TOPYQ6GA.js +31 -0
- package/dist/chunk-TOPYQ6GA.js.map +1 -0
- package/dist/{chunk-SMH6SRX7.js → chunk-TROR3ALR.js} +2 -2
- package/dist/{chunk-2C3AQB46.js → chunk-UD5EVGZ7.js} +42 -389
- package/dist/chunk-UD5EVGZ7.js.map +1 -0
- package/dist/{chunk-KJIMGIWO.js → chunk-UPD5NWI5.js} +65 -17
- package/dist/chunk-UPD5NWI5.js.map +1 -0
- package/dist/{chunk-SL3JAAKN.js → chunk-UYB234ZR.js} +30 -2
- package/dist/chunk-UYB234ZR.js.map +1 -0
- package/dist/chunk-VHM7HCKB.js +220 -0
- package/dist/chunk-VHM7HCKB.js.map +1 -0
- package/dist/{chunk-DGOZ4UZD.js → chunk-VNNRUGMM.js} +2 -2
- package/dist/{chunk-HDOU6I2Y.js → chunk-VNPEWFPD.js} +4 -4
- package/dist/{chunk-L7CIOOBW.js → chunk-WNJ4AVGE.js} +2 -2
- package/dist/{chunk-FMZY5Q6L.js → chunk-WX5ADGTZ.js} +3 -3
- package/dist/{chunk-VXANTWBJ.js → chunk-WY2XXTET.js} +92 -6
- package/dist/{chunk-VXANTWBJ.js.map → chunk-WY2XXTET.js.map} +1 -1
- package/dist/{chunk-6X6SEMEE.js → chunk-X25NWUZB.js} +33 -8
- package/dist/chunk-X25NWUZB.js.map +1 -0
- package/dist/{chunk-Q7HZX3IF.js → chunk-X4773RBR.js} +2 -2
- package/dist/chunk-XBKH4FOC.js +195 -0
- package/dist/chunk-XBKH4FOC.js.map +1 -0
- package/dist/{chunk-ANSIZYEG.js → chunk-YNIUIERI.js} +3 -3
- package/dist/chunk-YSK2CU2Q.js +936 -0
- package/dist/chunk-YSK2CU2Q.js.map +1 -0
- package/dist/{chunk-UXVWEX5L.js → chunk-Z5HTYMMQ.js} +6 -2
- package/dist/chunk-Z5HTYMMQ.js.map +1 -0
- package/dist/{chunk-RRNRNANG.js → chunk-ZE4CHIED.js} +66 -75
- package/dist/chunk-ZE4CHIED.js.map +1 -0
- package/dist/chunk-ZSX4S5XB.js +1289 -0
- package/dist/chunk-ZSX4S5XB.js.map +1 -0
- package/dist/{chunk-BZ3534YM.js → chunk-ZUVBC32X.js} +2 -2
- package/dist/{chunk-L742JPKZ.js → chunk-ZXABPVM6.js} +6 -6
- package/dist/classified/index.js +5 -5
- package/dist/{classified-marker-LI2SF2E4.js → classified-marker-W3USLL5M.js} +3 -3
- package/dist/collection-facade-QU6IJBN3.js +48 -0
- package/dist/{computed-VPOKQK4N.js → computed-TPFBX7U4.js} +3 -3
- package/dist/consent/index.js +9 -9
- package/dist/cover/index.js +10 -10
- package/dist/coverage/index.js +306 -0
- package/dist/coverage/index.js.map +1 -0
- package/dist/custody/index.js +12 -12
- package/dist/{dead-filter-TSWZQRR5.js → dead-filter-U2UYKSZL.js} +2 -2
- package/dist/debug/index.js +1 -1
- package/dist/{delegation-OVIFFPG4.js → delegation-S3AEPW2T.js} +11 -11
- package/dist/derivations/index.js +25 -22
- package/dist/derive-OX7F6TGG.js +21 -0
- package/dist/directory/index.js +10 -10
- package/dist/{dispatch-WC6X2M6C.js → dispatch-3CQDJV5Q.js} +5 -5
- package/dist/{dispatch-S73TK3IY.js → dispatch-RH4LHKBH.js} +21 -21
- package/dist/{enclave-KJOTOH7X.js → enclave-27SMF6GF.js} +15 -9
- package/dist/executor-B6SRO2QS.js +36 -0
- package/dist/executor-BI5CHWRY.js +8 -0
- package/dist/executor-RBKM5W5K.js +8 -0
- package/dist/export-accessible-VMA3YM5V.js +22 -0
- package/dist/extract-partition-NF7PXGPP.js +37 -0
- package/dist/{fanout-sidecar-WUFXNYP4.js → fanout-sidecar-OT6RYLOL.js} +9 -9
- package/dist/find-LZMP26KF.js +10 -0
- package/dist/forget/index.js +9 -9
- package/dist/guards/index.js +4 -4
- package/dist/history/index.js +13 -13
- package/dist/i18n/index.js +14 -14
- package/dist/index.d.ts +29 -6
- package/dist/index.js +999 -191
- 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 -11
- package/dist/issue-IHARXWW5.js +18 -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/collection-config.d.ts +4 -20
- package/dist/kernel/collection.d.ts +29 -8
- package/dist/kernel/enclave/crypto.d.ts +16 -0
- package/dist/kernel/enclave/index.d.ts +1 -1
- package/dist/kernel/enclave/record-keys/record-codec.d.ts +25 -0
- package/dist/kernel/errors.d.ts +227 -36
- package/dist/kernel/generation-map.d.ts +48 -0
- package/dist/kernel/memory-store.d.ts +35 -7
- package/dist/kernel/noydb.d.ts +6 -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/tx-write-gate.d.ts +77 -0
- package/dist/kernel/types.d.ts +71 -3
- package/dist/kernel/validation.d.ts +27 -10
- package/dist/kernel/vault.d.ts +9 -4
- 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/{ledger-F33ZVMTK.js → ledger-KZPCMVZY.js} +11 -11
- package/dist/liberate-GRLCZMW4.js +24 -0
- package/dist/link-set-JCMJ7ULP.js +30 -0
- package/dist/{managed-secret-PQYKSR6T.js → managed-secret-S3MQ6SH6.js} +10 -10
- package/dist/materialized-views/index.js +30 -23
- package/dist/{migrate-cek-5ENH64AA.js → migrate-cek-V7GKJZ7O.js} +2 -2
- package/dist/money/index.js +5 -5
- package/dist/noydb-SWQJ3MZS.js +97 -0
- package/dist/overlay-views/index.js +4 -4
- package/dist/periods/index.js +12 -12
- package/dist/pod/index.js +75 -68
- package/dist/{pod-handle-Q736KYON.js → pod-handle-WGDFB4C2.js} +9 -9
- package/dist/policy/index.js +10 -10
- package/dist/port/with/blob-strategy.d.ts +9 -0
- package/dist/port/with/collection-options.d.ts +5 -0
- package/dist/port/with/coverage-strategy.d.ts +83 -0
- 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-LNE2FE2A.js → post-register-SLSXIPBV.js} +6 -6
- 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-F3OYE7MJ.js +31 -0
- package/dist/registry-CILQFXFK.js +8 -0
- package/dist/registry-XNNYQVKV.js +8 -0
- package/dist/registry-YCDZV3VW.js +35 -0
- package/dist/registry-ZGYS33TE.js +24 -0
- package/dist/request-withdrawal-Z5NC6TXT.js +30 -0
- package/dist/{reveal-67RDQRIN.js → reveal-4BCKPEC2.js} +6 -6
- package/dist/revoke-ZL62WC2D.js +23 -0
- package/dist/satellites/index.js +1 -1
- package/dist/schema-update/index.js +2 -2
- package/dist/sealed-record/index.js +12 -12
- package/dist/search/index.js +11 -5
- package/dist/{seed-G42JYN56.js → seed-4JS2RJ4A.js} +12 -12
- package/dist/sequence/index.js +9 -9
- package/dist/session/index.js +9 -9
- package/dist/shadow/index.js +2 -2
- package/dist/signer-MBZZMXTC.js +24 -0
- package/dist/snapshots/index.js +10 -10
- package/dist/{stale-DDL7WQEZ.js → stale-TJ3DYZMQ.js} +10 -10
- package/dist/storage-SVMKRGCW.js +22 -0
- package/dist/{store-coordination-provider-MEQ2MJQG.js → store-coordination-provider-2O2VUHKW.js} +10 -10
- package/dist/sync/index.js +10 -10
- package/dist/team/index.js +17 -15
- package/dist/tiers/index.js +13 -11
- 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 +8 -8
- package/dist/{verify-KOV2G5D6.js → verify-RVT67IMH.js} +5 -5
- package/dist/via/blob/index.d.ts +1 -0
- 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/registry.d.ts +1 -1
- package/dist/via/lookup/snapshot.d.ts +3 -3
- package/dist/walk-HJ42EISE.js +21 -0
- package/dist/walk-HJ42EISE.js.map +1 -0
- 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/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 +17 -0
- package/dist/with-audit/tiers/index.d.ts +51 -0
- package/dist/with-audit/tiers/strategy.d.ts +8 -0
- package/dist/with-cargo/floor.d.ts +2 -2
- package/dist/with-commit/tx/invariants.d.ts +1 -1
- package/dist/with-commit/tx/transaction.d.ts +13 -3
- 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 +85 -2
- 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 +44 -8
- 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/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/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/index.d.ts +3 -2
- package/dist/with-party/team/keyring.d.ts +13 -6
- 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/wrapped-deks.d.ts +4 -4
- package/dist/with-pod/format.d.ts +1 -1
- package/dist/with-pod/pod.d.ts +5 -5
- package/dist/with-shape/blobs/blob-compaction.d.ts +16 -0
- package/dist/with-shape/blobs/blob-set.d.ts +21 -2
- package/dist/with-shape/blobs/legacy-sweep.d.ts +35 -0
- package/dist/with-shape/introspection/describe.d.ts +6 -0
- 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/links/vault-facade.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/withdraw-accessible-5NZUPAVA.js +27 -0
- package/dist/withdraw-accessible-5NZUPAVA.js.map +1 -0
- package/package.json +37 -10
- package/dist/api-TXFOVOXX.js +0 -19
- package/dist/backup-IJTB4S4M.js.map +0 -1
- package/dist/chunk-2577DKXB.js.map +0 -1
- package/dist/chunk-2C3AQB46.js.map +0 -1
- package/dist/chunk-4GVM6QZA.js.map +0 -1
- package/dist/chunk-5WDXHNSW.js.map +0 -1
- package/dist/chunk-6GOE5PGN.js.map +0 -1
- package/dist/chunk-6X6SEMEE.js.map +0 -1
- package/dist/chunk-77K4PG6P.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-AO42KJO6.js.map +0 -1
- package/dist/chunk-ATL3ZVXT.js +0 -151
- package/dist/chunk-ATL3ZVXT.js.map +0 -1
- package/dist/chunk-BLN54W3L.js.map +0 -1
- package/dist/chunk-BM5TWITZ.js.map +0 -1
- package/dist/chunk-CUZLNGD5.js.map +0 -1
- package/dist/chunk-EQEYOJBM.js.map +0 -1
- package/dist/chunk-G56KBWFY.js.map +0 -1
- package/dist/chunk-I3ISCYT7.js +0 -159
- package/dist/chunk-I3ISCYT7.js.map +0 -1
- package/dist/chunk-KG7TZKZG.js.map +0 -1
- package/dist/chunk-KJIMGIWO.js.map +0 -1
- package/dist/chunk-KTFRCC5C.js.map +0 -1
- package/dist/chunk-KUX3OB6D.js.map +0 -1
- package/dist/chunk-MUM7IANK.js.map +0 -1
- package/dist/chunk-NA2NIJZI.js.map +0 -1
- package/dist/chunk-NSITFOCJ.js +0 -99
- package/dist/chunk-NSITFOCJ.js.map +0 -1
- package/dist/chunk-PT43Y56J.js.map +0 -1
- package/dist/chunk-QIBVIOXO.js.map +0 -1
- package/dist/chunk-RRNRNANG.js.map +0 -1
- package/dist/chunk-RTBJ5IOO.js +0 -87
- package/dist/chunk-RTBJ5IOO.js.map +0 -1
- package/dist/chunk-SKGMN35F.js.map +0 -1
- package/dist/chunk-SL3JAAKN.js.map +0 -1
- package/dist/chunk-SPXXX5E4.js.map +0 -1
- package/dist/chunk-SPYWXKJN.js.map +0 -1
- package/dist/chunk-U4FOQDY4.js.map +0 -1
- package/dist/chunk-UXVWEX5L.js.map +0 -1
- package/dist/chunk-UXWB3FPF.js.map +0 -1
- package/dist/chunk-YMUFFJCO.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/collection-facade-4GRREZ6C.js +0 -45
- package/dist/derive-6O5SWQKN.js +0 -21
- package/dist/executor-5NIMLSKZ.js +0 -8
- package/dist/executor-AQVXV5GZ.js +0 -8
- package/dist/executor-PUAO6AKJ.js +0 -29
- package/dist/export-accessible-72EQNBMR.js +0 -22
- package/dist/extract-partition-PUYNU3UF.js +0 -37
- package/dist/find-2ABFCZX4.js +0 -10
- package/dist/issue-SIDORTSZ.js +0 -18
- package/dist/json-schema-V3M5MUCM.js.map +0 -1
- package/dist/kernel/query/join.d.ts +0 -232
- package/dist/liberate-LCDPNAG2.js +0 -24
- package/dist/link-set-FKNWAYKS.js +0 -30
- package/dist/noydb-DUXZPKSN.js +0 -90
- package/dist/register-I2DZXGAR.js +0 -31
- package/dist/registry-23WF3TGH.js +0 -8
- package/dist/registry-4AYVUNXK.js +0 -8
- package/dist/registry-VSSQPIGF.js +0 -18
- package/dist/registry-YLEWMGAC.js +0 -32
- package/dist/request-withdrawal-KFQHEZ25.js +0 -30
- package/dist/revoke-DQDZAZZM.js +0 -23
- package/dist/signer-WAMDZHEN.js +0 -24
- package/dist/storage-FLR73HHF.js +0 -22
- package/dist/walk-3UQBRMDV.js +0 -21
- package/dist/withdraw-accessible-EL5GXZBS.js +0 -27
- /package/dist/{api-TXFOVOXX.js.map → api-GVYEKSJE.js.map} +0 -0
- /package/dist/{chunk-BUE2D7PX.js.map → chunk-32YV3TJT.js.map} +0 -0
- /package/dist/{chunk-3RCJJBNR.js.map → chunk-3ELRMVJK.js.map} +0 -0
- /package/dist/{chunk-6GMZ7HEE.js.map → chunk-3F7GLNAE.js.map} +0 -0
- /package/dist/{chunk-2Y4IMKA6.js.map → chunk-3H5KLDZN.js.map} +0 -0
- /package/dist/{chunk-VTFVLCUH.js.map → chunk-3JWHAR6E.js.map} +0 -0
- /package/dist/{chunk-JBDFMYKQ.js.map → chunk-4AF3TUMP.js.map} +0 -0
- /package/dist/{chunk-J6FXAEUG.js.map → chunk-6B3VNR4P.js.map} +0 -0
- /package/dist/{chunk-TUFM4UZP.js.map → chunk-6K7DPM7D.js.map} +0 -0
- /package/dist/{chunk-K6LHRFBL.js.map → chunk-6LMQ5R26.js.map} +0 -0
- /package/dist/{chunk-XLMEZIAJ.js.map → chunk-6OWXYZK2.js.map} +0 -0
- /package/dist/{chunk-BOWNCWZT.js.map → chunk-6QSQQLSE.js.map} +0 -0
- /package/dist/{chunk-NQKIUNW5.js.map → chunk-A6IJU4TK.js.map} +0 -0
- /package/dist/{chunk-QIZPZMUI.js.map → chunk-AOWGXU6D.js.map} +0 -0
- /package/dist/{chunk-SFAWCTEM.js.map → chunk-B57AFBY2.js.map} +0 -0
- /package/dist/{chunk-GPEQUXHL.js.map → chunk-B6SJIBQK.js.map} +0 -0
- /package/dist/{chunk-Q2PU57HC.js.map → chunk-BK2HHQGN.js.map} +0 -0
- /package/dist/{collection-facade-4GRREZ6C.js.map → chunk-BKT776R5.js.map} +0 -0
- /package/dist/{chunk-FXBIP2WD.js.map → chunk-BUDAGWL5.js.map} +0 -0
- /package/dist/{chunk-BOET4NA4.js.map → chunk-CKNGS5MH.js.map} +0 -0
- /package/dist/{chunk-YSRUYAVU.js.map → chunk-DE4DH2RZ.js.map} +0 -0
- /package/dist/{chunk-6I2RQCET.js.map → chunk-DF73H4UN.js.map} +0 -0
- /package/dist/{chunk-K7NTTA6P.js.map → chunk-EOVMT6TB.js.map} +0 -0
- /package/dist/{chunk-XTXOCYOJ.js.map → chunk-FCKWQE2H.js.map} +0 -0
- /package/dist/{chunk-4OZNXTO4.js.map → chunk-FN5EBVTQ.js.map} +0 -0
- /package/dist/{chunk-NKHRDYOR.js.map → chunk-FQ5VRHIB.js.map} +0 -0
- /package/dist/{chunk-FAHMLERK.js.map → chunk-FW22ZCXT.js.map} +0 -0
- /package/dist/{chunk-RMS3NEA3.js.map → chunk-HT2AHGQI.js.map} +0 -0
- /package/dist/{chunk-CHJBLCOG.js.map → chunk-HVSCEIYL.js.map} +0 -0
- /package/dist/{chunk-GY4WYNNG.js.map → chunk-ID6Z6E66.js.map} +0 -0
- /package/dist/{chunk-EYBQEIUY.js.map → chunk-IEX7NK2K.js.map} +0 -0
- /package/dist/{chunk-KUJDV5QH.js.map → chunk-ISZQJBML.js.map} +0 -0
- /package/dist/{chunk-LWBCUYZW.js.map → chunk-IT22PWKV.js.map} +0 -0
- /package/dist/{chunk-7V4TP3AF.js.map → chunk-J6UOHJY5.js.map} +0 -0
- /package/dist/{chunk-JMGDHKQF.js.map → chunk-JCN44NCY.js.map} +0 -0
- /package/dist/{chunk-CARABLSQ.js.map → chunk-K6W7BVZ6.js.map} +0 -0
- /package/dist/{chunk-453F654R.js.map → chunk-L7DOS3TE.js.map} +0 -0
- /package/dist/{chunk-WEQEYLCS.js.map → chunk-LGRLME4M.js.map} +0 -0
- /package/dist/{chunk-RMF67KCG.js.map → chunk-LQ4ZHOKP.js.map} +0 -0
- /package/dist/{chunk-ZVO4QVPD.js.map → chunk-M522UYZ2.js.map} +0 -0
- /package/dist/{chunk-2N4GY74U.js.map → chunk-MTL7MXGR.js.map} +0 -0
- /package/dist/{chunk-TFR7DSOV.js.map → chunk-MVZ2TPVP.js.map} +0 -0
- /package/dist/{chunk-CPWQB3N5.js.map → chunk-N5DNADLQ.js.map} +0 -0
- /package/dist/{chunk-ELNXJMGB.js.map → chunk-NNARWO72.js.map} +0 -0
- /package/dist/{chunk-6YXCPL4T.js.map → chunk-PDCG6PR5.js.map} +0 -0
- /package/dist/{chunk-REDOOY2Q.js.map → chunk-PSIV7CJV.js.map} +0 -0
- /package/dist/{chunk-ANATMFIO.js.map → chunk-QWFHIOD2.js.map} +0 -0
- /package/dist/{chunk-X2DLENDQ.js.map → chunk-QWGU66MP.js.map} +0 -0
- /package/dist/{chunk-BSFNRLK2.js.map → chunk-S57HTZ6X.js.map} +0 -0
- /package/dist/{chunk-SZJ3DLZA.js.map → chunk-SEE332EV.js.map} +0 -0
- /package/dist/{chunk-YYP7WSEB.js.map → chunk-SI3V7D4G.js.map} +0 -0
- /package/dist/{chunk-UGTBXF5U.js.map → chunk-SOIQ4MM4.js.map} +0 -0
- /package/dist/{chunk-VXGSWL6L.js.map → chunk-SYVZW77S.js.map} +0 -0
- /package/dist/{chunk-MVMXZYXT.js.map → chunk-TKUOEU2F.js.map} +0 -0
- /package/dist/{chunk-SMH6SRX7.js.map → chunk-TROR3ALR.js.map} +0 -0
- /package/dist/{chunk-DGOZ4UZD.js.map → chunk-VNNRUGMM.js.map} +0 -0
- /package/dist/{chunk-HDOU6I2Y.js.map → chunk-VNPEWFPD.js.map} +0 -0
- /package/dist/{chunk-L7CIOOBW.js.map → chunk-WNJ4AVGE.js.map} +0 -0
- /package/dist/{chunk-FMZY5Q6L.js.map → chunk-WX5ADGTZ.js.map} +0 -0
- /package/dist/{chunk-Q7HZX3IF.js.map → chunk-X4773RBR.js.map} +0 -0
- /package/dist/{chunk-ANSIZYEG.js.map → chunk-YNIUIERI.js.map} +0 -0
- /package/dist/{chunk-BZ3534YM.js.map → chunk-ZUVBC32X.js.map} +0 -0
- /package/dist/{chunk-L742JPKZ.js.map → chunk-ZXABPVM6.js.map} +0 -0
- /package/dist/{classified-marker-LI2SF2E4.js.map → classified-marker-W3USLL5M.js.map} +0 -0
- /package/dist/{computed-VPOKQK4N.js.map → collection-facade-QU6IJBN3.js.map} +0 -0
- /package/dist/{derive-6O5SWQKN.js.map → computed-TPFBX7U4.js.map} +0 -0
- /package/dist/{dead-filter-TSWZQRR5.js.map → dead-filter-U2UYKSZL.js.map} +0 -0
- /package/dist/{delegation-OVIFFPG4.js.map → delegation-S3AEPW2T.js.map} +0 -0
- /package/dist/{enclave-KJOTOH7X.js.map → derive-OX7F6TGG.js.map} +0 -0
- /package/dist/{dispatch-WC6X2M6C.js.map → dispatch-3CQDJV5Q.js.map} +0 -0
- /package/dist/{dispatch-S73TK3IY.js.map → dispatch-RH4LHKBH.js.map} +0 -0
- /package/dist/{executor-5NIMLSKZ.js.map → enclave-27SMF6GF.js.map} +0 -0
- /package/dist/{executor-AQVXV5GZ.js.map → executor-B6SRO2QS.js.map} +0 -0
- /package/dist/{executor-PUAO6AKJ.js.map → executor-BI5CHWRY.js.map} +0 -0
- /package/dist/{export-accessible-72EQNBMR.js.map → executor-RBKM5W5K.js.map} +0 -0
- /package/dist/{extract-partition-PUYNU3UF.js.map → export-accessible-VMA3YM5V.js.map} +0 -0
- /package/dist/{find-2ABFCZX4.js.map → extract-partition-NF7PXGPP.js.map} +0 -0
- /package/dist/{fanout-sidecar-WUFXNYP4.js.map → fanout-sidecar-OT6RYLOL.js.map} +0 -0
- /package/dist/{issue-SIDORTSZ.js.map → find-LZMP26KF.js.map} +0 -0
- /package/dist/{ledger-F33ZVMTK.js.map → issue-IHARXWW5.js.map} +0 -0
- /package/dist/{liberate-LCDPNAG2.js.map → ledger-KZPCMVZY.js.map} +0 -0
- /package/dist/{link-set-FKNWAYKS.js.map → liberate-GRLCZMW4.js.map} +0 -0
- /package/dist/{managed-secret-PQYKSR6T.js.map → link-set-JCMJ7ULP.js.map} +0 -0
- /package/dist/{noydb-DUXZPKSN.js.map → managed-secret-S3MQ6SH6.js.map} +0 -0
- /package/dist/{migrate-cek-5ENH64AA.js.map → migrate-cek-V7GKJZ7O.js.map} +0 -0
- /package/dist/{register-I2DZXGAR.js.map → noydb-SWQJ3MZS.js.map} +0 -0
- /package/dist/{pod-handle-Q736KYON.js.map → pod-handle-WGDFB4C2.js.map} +0 -0
- /package/dist/{post-register-LNE2FE2A.js.map → post-register-SLSXIPBV.js.map} +0 -0
- /package/dist/{registry-23WF3TGH.js.map → query/all/index.js.map} +0 -0
- /package/dist/{registry-4AYVUNXK.js.map → register-F3OYE7MJ.js.map} +0 -0
- /package/dist/{registry-VSSQPIGF.js.map → registry-CILQFXFK.js.map} +0 -0
- /package/dist/{registry-YLEWMGAC.js.map → registry-XNNYQVKV.js.map} +0 -0
- /package/dist/{request-withdrawal-KFQHEZ25.js.map → registry-YCDZV3VW.js.map} +0 -0
- /package/dist/{revoke-DQDZAZZM.js.map → registry-ZGYS33TE.js.map} +0 -0
- /package/dist/{signer-WAMDZHEN.js.map → request-withdrawal-Z5NC6TXT.js.map} +0 -0
- /package/dist/{reveal-67RDQRIN.js.map → reveal-4BCKPEC2.js.map} +0 -0
- /package/dist/{stale-DDL7WQEZ.js.map → revoke-ZL62WC2D.js.map} +0 -0
- /package/dist/{seed-G42JYN56.js.map → seed-4JS2RJ4A.js.map} +0 -0
- /package/dist/{storage-FLR73HHF.js.map → signer-MBZZMXTC.js.map} +0 -0
- /package/dist/{walk-3UQBRMDV.js.map → stale-TJ3DYZMQ.js.map} +0 -0
- /package/dist/{withdraw-accessible-EL5GXZBS.js.map → storage-SVMKRGCW.js.map} +0 -0
- /package/dist/{store-coordination-provider-MEQ2MJQG.js.map → store-coordination-provider-2O2VUHKW.js.map} +0 -0
- /package/dist/{verify-KOV2G5D6.js.map → verify-RVT67IMH.js.map} +0 -0
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getAtPath
|
|
3
|
+
} from "./chunk-GHLTDZRS.js";
|
|
4
|
+
import {
|
|
5
|
+
EmbeddingModelMismatchError
|
|
6
|
+
} from "./chunk-244VXYPG.js";
|
|
7
|
+
|
|
8
|
+
// src/with-lookup/embeddings/descriptor.ts
|
|
9
|
+
function embeddingSourceText(record, source) {
|
|
10
|
+
const fields = typeof source === "string" ? [source] : source;
|
|
11
|
+
const parts = [];
|
|
12
|
+
for (const f of fields) {
|
|
13
|
+
for (const leaf of getAtPath(record, f)) {
|
|
14
|
+
if (typeof leaf === "string" && leaf !== "") parts.push(leaf);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return parts.join(" ");
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// src/with-lookup/embeddings/vec-id.ts
|
|
21
|
+
function encodeVecId(collection, recordId) {
|
|
22
|
+
if (collection.includes("/")) {
|
|
23
|
+
throw new Error(
|
|
24
|
+
`encodeVecId: collection name "${collection}" must not contain "/" \u2014 it would make the "${collection}/${recordId}" _vec id ambiguous against another collection's rows.`
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
return `${collection}/${recordId}`;
|
|
28
|
+
}
|
|
29
|
+
function decodeVecId(collection, vecId) {
|
|
30
|
+
const prefix = `${collection}/`;
|
|
31
|
+
if (!vecId.startsWith(prefix)) return null;
|
|
32
|
+
return vecId.slice(prefix.length);
|
|
33
|
+
}
|
|
34
|
+
function isVecIdFor(collection, vecId) {
|
|
35
|
+
return vecId.startsWith(`${collection}/`);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// src/with-lookup/embeddings/chunks.ts
|
|
39
|
+
function normalizeChunkSpans(spans, textLength) {
|
|
40
|
+
const out = [];
|
|
41
|
+
for (const s of spans) {
|
|
42
|
+
if (!Number.isInteger(s.start) || !Number.isInteger(s.end)) continue;
|
|
43
|
+
if (s.start < 0 || s.end > textLength || s.end <= s.start) continue;
|
|
44
|
+
out.push({ id: s.id ?? `c${out.length}`, start: s.start, end: s.end });
|
|
45
|
+
}
|
|
46
|
+
return out;
|
|
47
|
+
}
|
|
48
|
+
async function deriveChunkVectors(text, descriptor) {
|
|
49
|
+
if (!descriptor.chunk) return [];
|
|
50
|
+
const spans = normalizeChunkSpans(descriptor.chunk(text), text.length);
|
|
51
|
+
if (spans.length === 0) return [];
|
|
52
|
+
const out = [];
|
|
53
|
+
for (const span of spans) {
|
|
54
|
+
out.push({ ...span, vec: await descriptor.encode(text.slice(span.start, span.end)) });
|
|
55
|
+
}
|
|
56
|
+
return out;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// src/with-lookup/embeddings/cosine.ts
|
|
60
|
+
function cosine(a, b) {
|
|
61
|
+
if (a.length !== b.length) return 0;
|
|
62
|
+
let dot = 0, na = 0, nb = 0;
|
|
63
|
+
for (let i = 0; i < a.length; i++) {
|
|
64
|
+
const x = a[i], y = b[i];
|
|
65
|
+
dot += x * y;
|
|
66
|
+
na += x * x;
|
|
67
|
+
nb += y * y;
|
|
68
|
+
}
|
|
69
|
+
if (na === 0 || nb === 0) return 0;
|
|
70
|
+
return dot / (Math.sqrt(na) * Math.sqrt(nb));
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// src/with-lookup/embeddings/vector-set.ts
|
|
74
|
+
function pointsIn(v) {
|
|
75
|
+
if (v.chunks && v.chunks.length > 0) return v.chunks.length;
|
|
76
|
+
return v.vec ? 1 : 0;
|
|
77
|
+
}
|
|
78
|
+
var VectorSet = class {
|
|
79
|
+
/**
|
|
80
|
+
* `indexConfig` is `withVectorIndex()`'s return value, taken from the
|
|
81
|
+
* collection's `embeddings.index`. Absent — the overwhelmingly common case —
|
|
82
|
+
* and this class behaves exactly as it did before #1360 part 2.
|
|
83
|
+
*/
|
|
84
|
+
constructor(indexConfig) {
|
|
85
|
+
this.indexConfig = indexConfig;
|
|
86
|
+
}
|
|
87
|
+
indexConfig;
|
|
88
|
+
vectors;
|
|
89
|
+
/** id → position in `vectors`, so an incremental write is O(1), not O(n). */
|
|
90
|
+
posById = /* @__PURE__ */ new Map();
|
|
91
|
+
/** model → live record count, so the model guard is O(1) per query on the indexed path. */
|
|
92
|
+
modelCounts = /* @__PURE__ */ new Map();
|
|
93
|
+
points = 0;
|
|
94
|
+
index;
|
|
95
|
+
indexing;
|
|
96
|
+
/**
|
|
97
|
+
* Set when a build produced NO partitions — a corpus of nothing but
|
|
98
|
+
* zero-norm or mismatched-dimension vectors. An empty index answers every
|
|
99
|
+
* query with `[]`, which is a WRONG answer rather than a slow one (the exact
|
|
100
|
+
* path scores those vectors 0 and returns them), so the set falls back to
|
|
101
|
+
* brute force and does not retry the build on every query.
|
|
102
|
+
*/
|
|
103
|
+
indexUnusable = false;
|
|
104
|
+
get loaded() {
|
|
105
|
+
return this.vectors !== void 0;
|
|
106
|
+
}
|
|
107
|
+
/** Live VECTOR count (chunks included) — what `minVectors` is compared against. */
|
|
108
|
+
get pointCount() {
|
|
109
|
+
return this.points;
|
|
110
|
+
}
|
|
111
|
+
/** Test/benchmark introspection: whether an approximate index is currently serving queries. */
|
|
112
|
+
get indexed() {
|
|
113
|
+
return this.index !== void 0;
|
|
114
|
+
}
|
|
115
|
+
async ensureLoaded(load) {
|
|
116
|
+
if (this.vectors !== void 0) return;
|
|
117
|
+
const loaded = await load();
|
|
118
|
+
this.vectors = loaded;
|
|
119
|
+
this.posById = /* @__PURE__ */ new Map();
|
|
120
|
+
this.modelCounts = /* @__PURE__ */ new Map();
|
|
121
|
+
this.points = 0;
|
|
122
|
+
for (let i = 0; i < loaded.length; i++) {
|
|
123
|
+
const v = loaded[i];
|
|
124
|
+
this.posById.set(v.id, i);
|
|
125
|
+
this.points += pointsIn(v);
|
|
126
|
+
this.modelCounts.set(v.model, (this.modelCounts.get(v.model) ?? 0) + 1);
|
|
127
|
+
}
|
|
128
|
+
this.index = void 0;
|
|
129
|
+
this.indexUnusable = false;
|
|
130
|
+
}
|
|
131
|
+
markDirty() {
|
|
132
|
+
this.vectors = void 0;
|
|
133
|
+
this.posById = /* @__PURE__ */ new Map();
|
|
134
|
+
this.modelCounts = /* @__PURE__ */ new Map();
|
|
135
|
+
this.points = 0;
|
|
136
|
+
this.index = void 0;
|
|
137
|
+
this.indexing = void 0;
|
|
138
|
+
this.indexUnusable = false;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Incrementally insert or replace one record's vectors.
|
|
142
|
+
*
|
|
143
|
+
* This is what makes an approximate index viable at all here. `markDirty()`
|
|
144
|
+
* drops the whole set, so before #1360 part 2 every `put()` cost a full
|
|
145
|
+
* re-load on the next query — survivable for a brute-force scan that has no
|
|
146
|
+
* build step, fatal for an index whose build is tens of query-equivalents.
|
|
147
|
+
* `embedOnWrite` already holds the vectors it just encoded, so it can hand
|
|
148
|
+
* them over instead of throwing the set away.
|
|
149
|
+
*
|
|
150
|
+
* No-op when the set is not loaded: an unloaded set is already "dirty", and
|
|
151
|
+
* the next query loads everything from the sidecars anyway.
|
|
152
|
+
*/
|
|
153
|
+
upsert(vector) {
|
|
154
|
+
const all = this.vectors;
|
|
155
|
+
if (all === void 0) return;
|
|
156
|
+
const at = this.posById.get(vector.id);
|
|
157
|
+
if (at !== void 0) {
|
|
158
|
+
const prev = all[at];
|
|
159
|
+
this.points -= pointsIn(prev);
|
|
160
|
+
this.decModel(prev.model);
|
|
161
|
+
all[at] = vector;
|
|
162
|
+
} else {
|
|
163
|
+
this.posById.set(vector.id, all.length);
|
|
164
|
+
all.push(vector);
|
|
165
|
+
}
|
|
166
|
+
this.points += pointsIn(vector);
|
|
167
|
+
this.modelCounts.set(vector.model, (this.modelCounts.get(vector.model) ?? 0) + 1);
|
|
168
|
+
this.index?.upsert(vector);
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Incrementally drop one record's vectors. Removal is a SWAP with the last
|
|
172
|
+
* element, not a splice: `vectors` order is whatever `adapter.list()`
|
|
173
|
+
* returned and has never been part of any contract, so preserving it would
|
|
174
|
+
* buy nothing and cost an O(n) index rebuild on every `forget()`.
|
|
175
|
+
*/
|
|
176
|
+
removeRecord(id) {
|
|
177
|
+
const all = this.vectors;
|
|
178
|
+
if (all === void 0) return;
|
|
179
|
+
const at = this.posById.get(id);
|
|
180
|
+
if (at === void 0) return;
|
|
181
|
+
const removed = all[at];
|
|
182
|
+
this.points -= pointsIn(removed);
|
|
183
|
+
this.decModel(removed.model);
|
|
184
|
+
const last = all.pop();
|
|
185
|
+
if (at < all.length) {
|
|
186
|
+
all[at] = last;
|
|
187
|
+
this.posById.set(last.id, at);
|
|
188
|
+
}
|
|
189
|
+
this.posById.delete(id);
|
|
190
|
+
this.index?.remove(id);
|
|
191
|
+
}
|
|
192
|
+
decModel(model) {
|
|
193
|
+
const n = (this.modelCounts.get(model) ?? 0) - 1;
|
|
194
|
+
if (n <= 0) this.modelCounts.delete(model);
|
|
195
|
+
else this.modelCounts.set(model, n);
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Brute-force cosine kNN, one hit per RECORD. **Always exact.**
|
|
199
|
+
*
|
|
200
|
+
* #1360 best-chunk folding: a chunked record contributes its single BEST
|
|
201
|
+
* chunk score, never one hit per chunk and never a sum. Summing would make a
|
|
202
|
+
* long document outrank a short exact match purely for having more chunks —
|
|
203
|
+
* the folding is what keeps the score comparable across record lengths, and
|
|
204
|
+
* what keeps `k` a count of records rather than of fragments.
|
|
205
|
+
*/
|
|
206
|
+
cosineTopK(query, k, opts = {}) {
|
|
207
|
+
const all = this.vectors ?? [];
|
|
208
|
+
const minScore = opts.minScore ?? -Infinity;
|
|
209
|
+
const hits = [];
|
|
210
|
+
for (const v of all) {
|
|
211
|
+
if (opts.expectModel !== void 0 && v.model !== opts.expectModel) {
|
|
212
|
+
throw new EmbeddingModelMismatchError(opts.expectModel, v.model);
|
|
213
|
+
}
|
|
214
|
+
if (v.chunks && v.chunks.length > 0) {
|
|
215
|
+
let best;
|
|
216
|
+
let bestScore = -Infinity;
|
|
217
|
+
for (const c of v.chunks) {
|
|
218
|
+
const s = cosine(query, c.vec);
|
|
219
|
+
if (s > bestScore) {
|
|
220
|
+
bestScore = s;
|
|
221
|
+
best = c;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
if (best !== void 0 && bestScore >= minScore) {
|
|
225
|
+
hits.push({ id: v.id, score: bestScore, chunk: { id: best.id, start: best.start, end: best.end } });
|
|
226
|
+
}
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
if (!v.vec) continue;
|
|
230
|
+
const score = cosine(query, v.vec);
|
|
231
|
+
if (score >= minScore) hits.push({ id: v.id, score });
|
|
232
|
+
}
|
|
233
|
+
hits.sort((a, b) => b.score - a.score);
|
|
234
|
+
return hits.slice(0, k);
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* kNN under the collection's policy: approximate when an index is opted in
|
|
238
|
+
* AND the corpus is at or above `minVectors`, exact otherwise.
|
|
239
|
+
*
|
|
240
|
+
* ⭐ The default below the threshold is EXACT, deliberately: an index that
|
|
241
|
+
* builds on a 300-vector collection pays a build the queries can never
|
|
242
|
+
* amortise, and buys a recall cliff for a scan that was already sub-millisecond.
|
|
243
|
+
*/
|
|
244
|
+
async topK(query, k, opts = {}) {
|
|
245
|
+
const cfg = this.indexConfig;
|
|
246
|
+
if (opts.exact === true || cfg === void 0 || this.indexUnusable || this.points < cfg.minVectors) {
|
|
247
|
+
return this.cosineTopK(query, k, opts);
|
|
248
|
+
}
|
|
249
|
+
if (opts.expectModel !== void 0) {
|
|
250
|
+
for (const model of this.modelCounts.keys()) {
|
|
251
|
+
if (model !== opts.expectModel) throw new EmbeddingModelMismatchError(opts.expectModel, model);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
await this.ensureIndex(cfg);
|
|
255
|
+
const idx = this.index;
|
|
256
|
+
if (idx === void 0) return this.cosineTopK(query, k, opts);
|
|
257
|
+
return idx.search(query, k, {
|
|
258
|
+
...opts.minScore !== void 0 ? { minScore: opts.minScore } : {},
|
|
259
|
+
...opts.nprobe !== void 0 ? { nprobe: opts.nprobe } : {}
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
/** Build (or rebuild, once churn has made it stale) the index. Concurrency-safe. */
|
|
263
|
+
async ensureIndex(cfg) {
|
|
264
|
+
if (this.index !== void 0 && !this.index.stale) return;
|
|
265
|
+
if (this.indexing !== void 0) return this.indexing;
|
|
266
|
+
const build = (async () => {
|
|
267
|
+
const idx = await cfg.create();
|
|
268
|
+
idx.build(this.vectors ?? []);
|
|
269
|
+
if (idx.nlist === 0) {
|
|
270
|
+
this.indexUnusable = true;
|
|
271
|
+
this.index = void 0;
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
this.index = idx;
|
|
275
|
+
})();
|
|
276
|
+
this.indexing = build;
|
|
277
|
+
try {
|
|
278
|
+
await build;
|
|
279
|
+
} finally {
|
|
280
|
+
this.indexing = void 0;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
export {
|
|
286
|
+
embeddingSourceText,
|
|
287
|
+
VectorSet,
|
|
288
|
+
encodeVecId,
|
|
289
|
+
decodeVecId,
|
|
290
|
+
isVecIdFor,
|
|
291
|
+
deriveChunkVectors
|
|
292
|
+
};
|
|
293
|
+
//# sourceMappingURL=chunk-MDWKM2XC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/with-lookup/embeddings/descriptor.ts","../src/with-lookup/embeddings/vec-id.ts","../src/with-lookup/embeddings/chunks.ts","../src/with-lookup/embeddings/cosine.ts","../src/with-lookup/embeddings/vector-set.ts"],"sourcesContent":["/** Per-collection embedding config (L2). The encode hook is host/remote — no bundled model. */\nimport { getAtPath } from '../../via/i18n/core.js'\nimport type { EmbeddingChunkSpan } from './chunks.js'\nimport type { VectorIndexConfig } from './vector-index.js'\n\nexport interface EmbeddingDescriptor {\n readonly source: string | readonly string[]\n readonly encode: (text: string) => Promise<Float32Array>\n readonly dim: number\n readonly model: string\n /**\n * Optional sub-document splitter (#1360). Given the record's joined source\n * text (`embeddingSourceText(record, source)`), return the spans to encode\n * separately — `start`/`end` are character offsets into THAT string. When\n * declared and non-empty, the record is scored by its BEST chunk and the\n * winning span comes back on the hit; when absent or empty, the record keeps\n * exactly one whole-text vector, as before.\n */\n readonly chunk?: (text: string) => readonly EmbeddingChunkSpan[]\n /**\n * Opt into the approximate vector index (#1360 part 2) with\n * `index: withVectorIndex()`. Absent — the default — and every semantic\n * query is an exact brute-force cosine scan, unchanged.\n *\n * Opting in is not an instruction to index NOW: the index is built only once\n * the collection holds at least `minVectors` vectors, and any single query\n * can still demand exactness with `{ exact: true }`.\n */\n readonly index?: VectorIndexConfig\n}\n\n/** Concatenate the record's source-field text (skips empties; supports nested/[]-wildcard paths). */\nexport function embeddingSourceText(record: Record<string, unknown>, source: string | readonly string[]): string {\n const fields = typeof source === 'string' ? [source] : source\n const parts: string[] = []\n for (const f of fields) {\n for (const leaf of getAtPath(record, f)) {\n if (typeof leaf === 'string' && leaf !== '') parts.push(leaf)\n }\n }\n return parts.join(' ')\n}\n","/**\n * Collection-namespaced `_vec` side-car ids (#726).\n *\n * `_vec` embedding side-cars used to be keyed by the bare record id,\n * vault-wide — two collections sharing a record id shared one `_vec` row.\n * This was verified to be a clobber/crash bug, NOT a confidentiality leak:\n * every collection has its own DEK, and AES-GCM auth-tag verification means\n * decrypting a foreign collection's `_vec` row under the wrong DEK throws\n * `TamperedError` rather than returning wrong plaintext — no disclosure\n * mechanism exists. The real bug was id collision: a same-id write/forget in\n * one collection could clobber or delete the other collection's row, and a\n * collection whose `similarTo()` / cold semantic `retrieve()` encountered a\n * foreign same-id row crashed with an uncaught `TamperedError` (a DoS). The\n * store-collection bucket stays the literal `'_vec'`; the id becomes\n * composite: `${collection}/${recordId}`. Mirrors `encodeIdxId`\n * (`../indexing/persisted-indexes.js`).\n *\n * Decode is deliberately NOT split-on-`/`: the collection is always known\n * at the decode site (`ctx.name`), so `decodeVecId` strips that known\n * prefix — correct even when `recordId` itself contains `/`.\n *\n * Precondition: `collection` itself must not contain `/` — otherwise\n * `${collection}/${recordId}` is ambiguous (e.g. collection `'a'` would\n * misattribute collection `'a/b'`'s rows via prefix match in `isVecIdFor`).\n * Collection names are NOT currently restricted to a `/`-free charset by\n * `vault.collection()`, so `encodeVecId` enforces the precondition itself,\n * failing loud at the write boundary rather than silently misencoding.\n */\n\n/**\n * Encode the `_vec` side-car id for a (collection, recordId) pair.\n * Format: `<collection>/<recordId>` — no escaping; `recordId` may contain `/`.\n *\n * Throws if `collection` contains `/`: that would make the composite id\n * ambiguous against `isVecIdFor`'s prefix match (collection `'a'` would\n * appear to own collection `'a/b'`'s rows), reintroducing the clobber/crash\n * risk the namespacing fix exists to close.\n */\nexport function encodeVecId(collection: string, recordId: string): string {\n if (collection.includes('/')) {\n throw new Error(\n `encodeVecId: collection name \"${collection}\" must not contain \"/\" — ` +\n `it would make the \"${collection}/${recordId}\" _vec id ambiguous against another collection's rows.`,\n )\n }\n return `${collection}/${recordId}`\n}\n\n/**\n * Decode a `_vec` id back to the bare record id, given the KNOWN owning\n * collection — strips the `<collection>/` prefix rather than splitting on\n * `/`, so a `recordId` containing `/` round-trips correctly. Returns `null`\n * if `vecId` does not belong to `collection`.\n */\nexport function decodeVecId(collection: string, vecId: string): string | null {\n const prefix = `${collection}/`\n if (!vecId.startsWith(prefix)) return null\n return vecId.slice(prefix.length)\n}\n\n/** Predicate form of {@link decodeVecId} — used to filter `list()` results. */\nexport function isVecIdFor(collection: string, vecId: string): boolean {\n return vecId.startsWith(`${collection}/`)\n}\n","/**\n * Sub-document chunking (#1360) — multiple vectors per record.\n *\n * A long document encoded as ONE vector averages its topics away: a contract\n * whose fortieth clause is the only relevant one scores like a contract about\n * nothing in particular. Chunking encodes SPANS of the record's source text\n * separately, and scores a record by its BEST chunk.\n *\n * ## What a span indexes into — the load-bearing definition\n *\n * `start` / `end` are **character offsets into\n * `embeddingSourceText(record, descriptor.source)`** — the joined source text,\n * NOT into any single field. When `source` names several fields the text is\n * their `' '`-join, so an offset can sit past a join boundary; that is exactly\n * why the offsets are defined against the join and not against a field. The\n * consumer reconstructs the snippet with the same call:\n *\n * ```ts\n * const text = embeddingSourceText(record, descriptor.source)\n * const snippet = text.slice(hit.chunk.start, hit.chunk.end)\n * ```\n *\n * `similarTo()` does precisely that to fill `hit.snippet`, so a returned span\n * is checkable against the record the consumer already holds.\n *\n * ## What is deliberately NOT here\n *\n * No bundled splitter. The splitter is host-supplied like `encode` — chunking\n * a legal clause, a markdown section and a chat transcript are different\n * problems and hub has no business guessing.\n *\n * The approximate index that was deferred here HAS since been built — it is\n * `ivf-flat.ts`, opted into with `withVectorIndex()`, and it is OFF by default\n * (see `vector-set.ts`'s `topK`). This file's own multiplier is what gated it:\n * chunking stores one vector per chunk, so a corpus of R records at C chunks\n * each brute-forces R·C vectors, and the index threshold counts VECTORS.\n * ⛔ Managed plaintext vector backends (pgvector, Vectorize, Qdrant) remain\n * excluded BY DECISION, and building an in-hub index does not reopen that: the\n * backend would hold plaintext vectors, and embedding inversion leaks the text\n * back out. The index built here never leaves the hub and is never persisted.\n */\nimport type { EmbeddingDescriptor } from './descriptor.js'\n\n/** A span the host's splitter proposes: `[start, end)` into the joined source text. */\nexport interface EmbeddingChunkSpan {\n readonly start: number\n readonly end: number\n /** Stable chunk id; defaults to `c<index>` when the splitter does not supply one. */\n readonly id?: string\n}\n\n/** A chunk as it is stored and returned — a span with a resolved id, no vector. */\nexport interface EmbeddingChunk {\n readonly id: string\n readonly start: number\n readonly end: number\n}\n\n/** A chunk plus its vector, as held in memory by {@link VectorSet}. */\nexport interface StoredChunk extends EmbeddingChunk {\n readonly vec: Float32Array\n}\n\n/**\n * Normalise the splitter's output: drop empty/inverted/out-of-range spans,\n * resolve ids. Invalid spans are DROPPED rather than thrown on — a splitter is\n * host code running over host text, and one degenerate span (a trailing\n * separator, a zero-width match) must not fail the write; a record that ends up\n * with no usable span falls back to the whole-record vector, which is the\n * pre-#1360 behaviour and never worse than not indexing the record at all.\n */\nexport function normalizeChunkSpans(spans: readonly EmbeddingChunkSpan[], textLength: number): EmbeddingChunk[] {\n const out: EmbeddingChunk[] = []\n for (const s of spans) {\n if (!Number.isInteger(s.start) || !Number.isInteger(s.end)) continue\n if (s.start < 0 || s.end > textLength || s.end <= s.start) continue\n out.push({ id: s.id ?? `c${out.length}`, start: s.start, end: s.end })\n }\n return out\n}\n\n/**\n * Encode each chunk of `text` under the descriptor's `encode` hook.\n * Returns `[]` when no `chunk` hook is declared or it yields no usable span —\n * the caller then stores the single whole-record vector, unchanged.\n *\n * Dimension is checked per chunk by the caller (it owns the error's field\n * name), so this stays a pure derive.\n */\nexport async function deriveChunkVectors(\n text: string,\n descriptor: EmbeddingDescriptor,\n): Promise<(EmbeddingChunk & { vec: Float32Array })[]> {\n if (!descriptor.chunk) return []\n const spans = normalizeChunkSpans(descriptor.chunk(text), text.length)\n if (spans.length === 0) return []\n const out: (EmbeddingChunk & { vec: Float32Array })[] = []\n for (const span of spans) {\n out.push({ ...span, vec: await descriptor.encode(text.slice(span.start, span.end)) })\n }\n return out\n}\n","/** Cosine similarity in [-1,1]; 0 on zero-norm or length mismatch (no NaN). (L2) */\nexport function cosine(a: Float32Array | number[], b: Float32Array | number[]): number {\n if (a.length !== b.length) return 0\n let dot = 0, na = 0, nb = 0\n for (let i = 0; i < a.length; i++) {\n const x = a[i]!, y = b[i]!\n dot += x * y; na += x * x; nb += y * y\n }\n if (na === 0 || nb === 0) return 0\n return dot / (Math.sqrt(na) * Math.sqrt(nb))\n}\n","/** In-memory vector set for L2 semantic retrieval. Loaded once per session from\n * decrypted _vec sidecars (injected loader), brute-force cosine kNN, model-guarded.\n * #1360 part 2 adds an OPT-IN approximate index in front of the brute force. */\nimport { cosine } from './cosine.js'\nimport type { EmbeddingChunk, StoredChunk } from './chunks.js'\nimport type { VectorIndex, VectorIndexConfig } from './vector-index.js'\nimport { EmbeddingModelMismatchError } from '../../kernel/errors.js'\n\n/**\n * One record's vectors. Exactly one of `vec` (whole-record, the pre-#1360\n * shape) and `chunks` (sub-document, #1360) is populated by the loader; a row\n * with neither is inert and scores nothing.\n */\nexport interface StoredVector {\n readonly id: string\n readonly model: string\n readonly vec?: Float32Array\n /** #1360 — sub-document chunks. When present, the record is scored by its BEST chunk. */\n readonly chunks?: readonly StoredChunk[]\n}\nexport interface VectorHit {\n readonly id: string\n readonly score: number\n /** #1360 — the winning chunk's span, when the record was scored via chunks. */\n readonly chunk?: EmbeddingChunk\n}\n\n/** Options accepted by {@link VectorSet.topK}. */\nexport interface VectorTopKOptions {\n readonly minScore?: number\n readonly expectModel?: string\n /**\n * Force the exact brute-force scan for this query, whatever the corpus size\n * and whatever `index` the descriptor declares. Exactness stays REACHABLE:\n * an approximate default that cannot be turned off is a correctness change\n * dressed as a performance one.\n */\n readonly exact?: boolean\n /** Per-query recall dial; overrides the configured `nprobe`. Ignored on the exact path. */\n readonly nprobe?: number\n}\n\n/** Points contributed by one stored record — chunked records contribute one per chunk. */\nfunction pointsIn(v: StoredVector): number {\n if (v.chunks && v.chunks.length > 0) return v.chunks.length\n return v.vec ? 1 : 0\n}\n\nexport class VectorSet {\n private vectors: StoredVector[] | undefined\n /** id → position in `vectors`, so an incremental write is O(1), not O(n). */\n private posById = new Map<string, number>()\n /** model → live record count, so the model guard is O(1) per query on the indexed path. */\n private modelCounts = new Map<string, number>()\n private points = 0\n private index: VectorIndex | undefined\n private indexing: Promise<void> | undefined\n /**\n * Set when a build produced NO partitions — a corpus of nothing but\n * zero-norm or mismatched-dimension vectors. An empty index answers every\n * query with `[]`, which is a WRONG answer rather than a slow one (the exact\n * path scores those vectors 0 and returns them), so the set falls back to\n * brute force and does not retry the build on every query.\n */\n private indexUnusable = false\n\n /**\n * `indexConfig` is `withVectorIndex()`'s return value, taken from the\n * collection's `embeddings.index`. Absent — the overwhelmingly common case —\n * and this class behaves exactly as it did before #1360 part 2.\n */\n constructor(private readonly indexConfig?: VectorIndexConfig) {}\n\n get loaded(): boolean { return this.vectors !== undefined }\n /** Live VECTOR count (chunks included) — what `minVectors` is compared against. */\n get pointCount(): number { return this.points }\n /** Test/benchmark introspection: whether an approximate index is currently serving queries. */\n get indexed(): boolean { return this.index !== undefined }\n\n async ensureLoaded(load: () => Promise<StoredVector[]>): Promise<void> {\n if (this.vectors !== undefined) return\n const loaded = await load()\n this.vectors = loaded\n this.posById = new Map()\n this.modelCounts = new Map()\n this.points = 0\n for (let i = 0; i < loaded.length; i++) {\n const v = loaded[i]!\n this.posById.set(v.id, i)\n this.points += pointsIn(v)\n this.modelCounts.set(v.model, (this.modelCounts.get(v.model) ?? 0) + 1)\n }\n this.index = undefined\n this.indexUnusable = false\n }\n\n markDirty(): void {\n this.vectors = undefined\n this.posById = new Map()\n this.modelCounts = new Map()\n this.points = 0\n this.index = undefined\n this.indexing = undefined\n this.indexUnusable = false\n }\n\n /**\n * Incrementally insert or replace one record's vectors.\n *\n * This is what makes an approximate index viable at all here. `markDirty()`\n * drops the whole set, so before #1360 part 2 every `put()` cost a full\n * re-load on the next query — survivable for a brute-force scan that has no\n * build step, fatal for an index whose build is tens of query-equivalents.\n * `embedOnWrite` already holds the vectors it just encoded, so it can hand\n * them over instead of throwing the set away.\n *\n * No-op when the set is not loaded: an unloaded set is already \"dirty\", and\n * the next query loads everything from the sidecars anyway.\n */\n upsert(vector: StoredVector): void {\n const all = this.vectors\n if (all === undefined) return\n const at = this.posById.get(vector.id)\n if (at !== undefined) {\n const prev = all[at]!\n this.points -= pointsIn(prev)\n this.decModel(prev.model)\n all[at] = vector\n } else {\n this.posById.set(vector.id, all.length)\n all.push(vector)\n }\n this.points += pointsIn(vector)\n this.modelCounts.set(vector.model, (this.modelCounts.get(vector.model) ?? 0) + 1)\n this.index?.upsert(vector)\n }\n\n /**\n * Incrementally drop one record's vectors. Removal is a SWAP with the last\n * element, not a splice: `vectors` order is whatever `adapter.list()`\n * returned and has never been part of any contract, so preserving it would\n * buy nothing and cost an O(n) index rebuild on every `forget()`.\n */\n removeRecord(id: string): void {\n const all = this.vectors\n if (all === undefined) return\n const at = this.posById.get(id)\n if (at === undefined) return\n const removed = all[at]!\n this.points -= pointsIn(removed)\n this.decModel(removed.model)\n const last = all.pop()!\n if (at < all.length) { all[at] = last; this.posById.set(last.id, at) }\n this.posById.delete(id)\n this.index?.remove(id)\n }\n\n private decModel(model: string): void {\n const n = (this.modelCounts.get(model) ?? 0) - 1\n if (n <= 0) this.modelCounts.delete(model)\n else this.modelCounts.set(model, n)\n }\n\n /**\n * Brute-force cosine kNN, one hit per RECORD. **Always exact.**\n *\n * #1360 best-chunk folding: a chunked record contributes its single BEST\n * chunk score, never one hit per chunk and never a sum. Summing would make a\n * long document outrank a short exact match purely for having more chunks —\n * the folding is what keeps the score comparable across record lengths, and\n * what keeps `k` a count of records rather than of fragments.\n */\n cosineTopK(query: Float32Array, k: number, opts: { minScore?: number; expectModel?: string } = {}): VectorHit[] {\n const all = this.vectors ?? []\n const minScore = opts.minScore ?? -Infinity\n const hits: VectorHit[] = []\n for (const v of all) {\n if (opts.expectModel !== undefined && v.model !== opts.expectModel) {\n throw new EmbeddingModelMismatchError(opts.expectModel, v.model)\n }\n if (v.chunks && v.chunks.length > 0) {\n let best: StoredChunk | undefined\n let bestScore = -Infinity\n for (const c of v.chunks) {\n const s = cosine(query, c.vec)\n if (s > bestScore) { bestScore = s; best = c }\n }\n if (best !== undefined && bestScore >= minScore) {\n hits.push({ id: v.id, score: bestScore, chunk: { id: best.id, start: best.start, end: best.end } })\n }\n continue\n }\n if (!v.vec) continue\n const score = cosine(query, v.vec)\n if (score >= minScore) hits.push({ id: v.id, score })\n }\n hits.sort((a, b) => b.score - a.score)\n return hits.slice(0, k)\n }\n\n /**\n * kNN under the collection's policy: approximate when an index is opted in\n * AND the corpus is at or above `minVectors`, exact otherwise.\n *\n * ⭐ The default below the threshold is EXACT, deliberately: an index that\n * builds on a 300-vector collection pays a build the queries can never\n * amortise, and buys a recall cliff for a scan that was already sub-millisecond.\n */\n async topK(query: Float32Array, k: number, opts: VectorTopKOptions = {}): Promise<VectorHit[]> {\n const cfg = this.indexConfig\n if (opts.exact === true || cfg === undefined || this.indexUnusable || this.points < cfg.minVectors) {\n return this.cosineTopK(query, k, opts)\n }\n // The exact path throws per-vector on a model mismatch as it scans; the\n // indexed path never scans every vector, so the same guard has to be a set\n // membership test. Same error, same trigger, O(1).\n if (opts.expectModel !== undefined) {\n for (const model of this.modelCounts.keys()) {\n if (model !== opts.expectModel) throw new EmbeddingModelMismatchError(opts.expectModel, model)\n }\n }\n await this.ensureIndex(cfg)\n const idx = this.index\n if (idx === undefined) return this.cosineTopK(query, k, opts)\n return idx.search(query, k, {\n ...(opts.minScore !== undefined ? { minScore: opts.minScore } : {}),\n ...(opts.nprobe !== undefined ? { nprobe: opts.nprobe } : {}),\n })\n }\n\n /** Build (or rebuild, once churn has made it stale) the index. Concurrency-safe. */\n private async ensureIndex(cfg: VectorIndexConfig): Promise<void> {\n if (this.index !== undefined && !this.index.stale) return\n if (this.indexing !== undefined) return this.indexing\n const build = (async () => {\n const idx = await cfg.create()\n idx.build(this.vectors ?? [])\n if (idx.nlist === 0) { this.indexUnusable = true; this.index = undefined; return }\n this.index = idx\n })()\n this.indexing = build\n try { await build } finally { this.indexing = undefined }\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import {
|
|
2
|
+
compareKeys,
|
|
3
|
+
toSortKey
|
|
4
|
+
} from "./chunk-LGNDFRYC.js";
|
|
5
|
+
import {
|
|
6
|
+
readPath
|
|
7
|
+
} from "./chunk-HLEK5VAN.js";
|
|
8
|
+
|
|
9
|
+
// src/kernel/query/relate/join-on.ts
|
|
10
|
+
var RANGE_OPS = /* @__PURE__ */ new Set(["<", "<=", ">", ">=", "between"]);
|
|
11
|
+
function isField(value) {
|
|
12
|
+
return typeof value === "string" && value.length > 0;
|
|
13
|
+
}
|
|
14
|
+
function normalizeJoinOn(on, target) {
|
|
15
|
+
if (Array.isArray(on)) {
|
|
16
|
+
const pairs = on;
|
|
17
|
+
if (pairs.length === 0) {
|
|
18
|
+
throw new Error(
|
|
19
|
+
`.joinOn("${target}"): a composite \`on\` needs at least one [leftField, rightField] pair. Pass e.g. on: [['clientId', 'clientId'], ['year', 'year']].`
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
const normalized = [];
|
|
23
|
+
for (const pair of pairs) {
|
|
24
|
+
if (!Array.isArray(pair) || pair.length !== 2 || !isField(pair[0]) || !isField(pair[1])) {
|
|
25
|
+
throw new Error(
|
|
26
|
+
`.joinOn("${target}"): every composite \`on\` entry must be a [leftField, rightField] pair of non-empty field names. Received: ${JSON.stringify(pair)}.`
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
normalized.push([pair[0], pair[1]]);
|
|
30
|
+
}
|
|
31
|
+
normalized.sort((a, b) => a[0] === b[0] ? a[1] < b[1] ? -1 : a[1] > b[1] ? 1 : 0 : a[0] < b[0] ? -1 : 1);
|
|
32
|
+
return { kind: "composite", pairs: normalized };
|
|
33
|
+
}
|
|
34
|
+
const spec = on;
|
|
35
|
+
if (!isField(spec.left)) {
|
|
36
|
+
throw new Error(`.joinOn("${target}"): a range \`on\` needs a non-empty \`left\` field name.`);
|
|
37
|
+
}
|
|
38
|
+
if (typeof spec.op !== "string" || !RANGE_OPS.has(spec.op)) {
|
|
39
|
+
throw new Error(
|
|
40
|
+
`.joinOn("${target}"): unknown \`on\` operator ${JSON.stringify(spec.op)}. Supported operators are ${[...RANGE_OPS].join(", ")}.`
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
if (spec.op === "between") {
|
|
44
|
+
if (!Array.isArray(spec.right) || spec.right.length !== 2 || !isField(spec.right[0]) || !isField(spec.right[1])) {
|
|
45
|
+
throw new Error(
|
|
46
|
+
`.joinOn("${target}"): \`between\` needs exactly two right-side boundary field names \u2014 on: { left: 'date', op: 'between', right: ['from', 'to'] }.`
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
return { kind: "range", left: spec.left, op: "between", right: [spec.right[0], spec.right[1]] };
|
|
50
|
+
}
|
|
51
|
+
if (!isField(spec.right)) {
|
|
52
|
+
throw new Error(`.joinOn("${target}"): the \`${spec.op}\` operator needs a single right-side field name.`);
|
|
53
|
+
}
|
|
54
|
+
return { kind: "range", left: spec.left, op: spec.op, right: [spec.right] };
|
|
55
|
+
}
|
|
56
|
+
function describeJoinOn(on) {
|
|
57
|
+
if (on.kind === "composite") return on.pairs.map(([l, r]) => `${l} = ${r}`).join(" AND ");
|
|
58
|
+
if (on.op === "between") return `${on.left} between [${on.right.join(", ")}]`;
|
|
59
|
+
return `${on.left} ${on.op} ${on.right[0]}`;
|
|
60
|
+
}
|
|
61
|
+
function joinOnDispatch(on) {
|
|
62
|
+
return on.kind === "composite" ? "join:composite-hash" : "join:sorted-range";
|
|
63
|
+
}
|
|
64
|
+
function tupleKey(values) {
|
|
65
|
+
let out = "";
|
|
66
|
+
for (const value of values) {
|
|
67
|
+
const sk = toSortKey(value, void 0);
|
|
68
|
+
if (!sk) return void 0;
|
|
69
|
+
const text = String(sk.key);
|
|
70
|
+
out += `${sk.kind}:${text.length}:${text}|`;
|
|
71
|
+
}
|
|
72
|
+
return out;
|
|
73
|
+
}
|
|
74
|
+
function matchDeclaredJoin(leftRows, on, rightSnapshot, maxRows, onOverflow) {
|
|
75
|
+
const out = [];
|
|
76
|
+
const push = (left, right) => {
|
|
77
|
+
if (out.length >= maxRows) onOverflow(out.length + 1);
|
|
78
|
+
out.push({ left, right });
|
|
79
|
+
};
|
|
80
|
+
if (on.kind === "composite") {
|
|
81
|
+
compositeHashJoin(leftRows, on, rightSnapshot, push);
|
|
82
|
+
} else {
|
|
83
|
+
sortedRangeJoin(leftRows, on, rightSnapshot, push);
|
|
84
|
+
}
|
|
85
|
+
return out;
|
|
86
|
+
}
|
|
87
|
+
function compositeHashJoin(leftRows, on, rightSnapshot, push) {
|
|
88
|
+
const leftFields = on.pairs.map((p) => p[0]);
|
|
89
|
+
const rightFields = on.pairs.map((p) => p[1]);
|
|
90
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
91
|
+
for (const record of rightSnapshot) {
|
|
92
|
+
const key = tupleKey(rightFields.map((f) => readPath(record, f)));
|
|
93
|
+
if (key === void 0) continue;
|
|
94
|
+
const bucket = buckets.get(key);
|
|
95
|
+
if (bucket) bucket.push(record);
|
|
96
|
+
else buckets.set(key, [record]);
|
|
97
|
+
}
|
|
98
|
+
for (const left of leftRows) {
|
|
99
|
+
const key = tupleKey(leftFields.map((f) => readPath(left, f)));
|
|
100
|
+
const bucket = key === void 0 ? void 0 : buckets.get(key);
|
|
101
|
+
if (!bucket || bucket.length === 0) {
|
|
102
|
+
push(left, void 0);
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
for (const right of bucket) push(left, right);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function sortedRangeJoin(leftRows, on, rightSnapshot, push) {
|
|
109
|
+
const lowField = on.right[0];
|
|
110
|
+
const highField = on.op === "between" ? on.right[1] : void 0;
|
|
111
|
+
const entries = [];
|
|
112
|
+
for (const record of rightSnapshot) {
|
|
113
|
+
const key = toSortKey(readPath(record, lowField), void 0);
|
|
114
|
+
if (!key) continue;
|
|
115
|
+
const hi = highField === void 0 ? void 0 : toSortKey(readPath(record, highField), void 0);
|
|
116
|
+
if (highField !== void 0 && !hi) continue;
|
|
117
|
+
entries.push({ key, hi, record });
|
|
118
|
+
}
|
|
119
|
+
entries.sort((a, b) => compareKeys(a.key, b.key));
|
|
120
|
+
for (const left of leftRows) {
|
|
121
|
+
const probe = toSortKey(readPath(left, on.left), void 0);
|
|
122
|
+
if (!probe) {
|
|
123
|
+
push(left, void 0);
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
const [bandStart, bandEnd] = kindBand(entries, probe.kind);
|
|
127
|
+
const lo = lowerBound(entries, probe, bandStart, bandEnd);
|
|
128
|
+
const hi = upperBound(entries, probe, bandStart, bandEnd);
|
|
129
|
+
let matched = false;
|
|
130
|
+
const emit = (from, to, keep) => {
|
|
131
|
+
for (let i = from; i < to; i++) {
|
|
132
|
+
const entry = entries[i];
|
|
133
|
+
if (keep && !keep(entry)) continue;
|
|
134
|
+
matched = true;
|
|
135
|
+
push(left, entry.record);
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
switch (on.op) {
|
|
139
|
+
// `left.field < right.field` — the right keys strictly ABOVE the probe.
|
|
140
|
+
case "<":
|
|
141
|
+
emit(hi, bandEnd);
|
|
142
|
+
break;
|
|
143
|
+
case "<=":
|
|
144
|
+
emit(lo, bandEnd);
|
|
145
|
+
break;
|
|
146
|
+
case ">":
|
|
147
|
+
emit(bandStart, lo);
|
|
148
|
+
break;
|
|
149
|
+
case ">=":
|
|
150
|
+
emit(bandStart, hi);
|
|
151
|
+
break;
|
|
152
|
+
// `right.from <= left.field <= right.to`. Sorted by `from`, so the
|
|
153
|
+
// candidates are the prefix whose `from` is at or below the probe; the
|
|
154
|
+
// `to` bound is then a filter over that prefix, which is what makes the
|
|
155
|
+
// interval case O(p) per left row rather than O(log m).
|
|
156
|
+
case "between":
|
|
157
|
+
emit(bandStart, hi, (e) => e.hi !== void 0 && compareKeys(e.hi, probe) >= 0);
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
if (!matched) push(left, void 0);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
function kindBand(entries, kind) {
|
|
164
|
+
const bound = (strict) => {
|
|
165
|
+
let lo = 0;
|
|
166
|
+
let hi = entries.length;
|
|
167
|
+
while (lo < hi) {
|
|
168
|
+
const mid = lo + hi >>> 1;
|
|
169
|
+
const d = entries[mid].key.kind - kind;
|
|
170
|
+
if (strict ? d < 0 : d <= 0) lo = mid + 1;
|
|
171
|
+
else hi = mid;
|
|
172
|
+
}
|
|
173
|
+
return lo;
|
|
174
|
+
};
|
|
175
|
+
return [bound(true), bound(false)];
|
|
176
|
+
}
|
|
177
|
+
function lowerBound(entries, probe, from = 0, to = entries.length) {
|
|
178
|
+
let lo = from;
|
|
179
|
+
let hi = to;
|
|
180
|
+
while (lo < hi) {
|
|
181
|
+
const mid = lo + hi >>> 1;
|
|
182
|
+
if (compareKeys(entries[mid].key, probe) < 0) lo = mid + 1;
|
|
183
|
+
else hi = mid;
|
|
184
|
+
}
|
|
185
|
+
return lo;
|
|
186
|
+
}
|
|
187
|
+
function upperBound(entries, probe, from = 0, to = entries.length) {
|
|
188
|
+
let lo = from;
|
|
189
|
+
let hi = to;
|
|
190
|
+
while (lo < hi) {
|
|
191
|
+
const mid = lo + hi >>> 1;
|
|
192
|
+
if (compareKeys(entries[mid].key, probe) <= 0) lo = mid + 1;
|
|
193
|
+
else hi = mid;
|
|
194
|
+
}
|
|
195
|
+
return lo;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export {
|
|
199
|
+
normalizeJoinOn,
|
|
200
|
+
describeJoinOn,
|
|
201
|
+
joinOnDispatch,
|
|
202
|
+
matchDeclaredJoin
|
|
203
|
+
};
|
|
204
|
+
//# sourceMappingURL=chunk-MKXXMNJH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/kernel/query/relate/join-on.ts"],"sourcesContent":["/**\n * Declared non-equi and composite joins — `.joinOn(target, { on })` (#1339).\n *\n * `join.ts` resolves a `ref()`-declared FK against the target's `id`. That is\n * one shape of join. This module is the other two the query DSL could not\n * express at all:\n *\n * - **composite equality** — `on: [['clientId','clientId'], ['year','year']]`\n * - **range / theta** — `on: { left: 'date', op: 'between', right: ['from','to'] }`\n *\n * ⭐ THE DECLARED FORM IS THE WHOLE POINT, and it is the only reason this is\n * not `crossJoin({ on: fn })` with extra steps. `crossJoin`'s `on` is a\n * closure: it pairs arbitrary rows perfectly and serializes to the sentinel\n * `'[inline]'`, which is why a materialized view over one has its drift\n * detection disabled. A `JoinOnPlan` is plain JSON, so `serializePlan()`\n * emits it verbatim, `summarizeQueryPlan()` folds it into the MV\n * `queryHash`, and two plans differing only in their `on` are two different\n * queries — pinned by `__tests__/query-join-on.test.ts`.\n *\n * ⛔ THE NORMAL FORM IS PART OF THE HASH. `normalizeJoinOn` is the ONLY place\n * a `JoinOnSpec` becomes a `JoinOnPlan`, and it sorts composite pairs so two\n * logically identical joins hash identically (an AND of equalities is\n * commutative). Changing the normal form moves every stored `queryHash` for a\n * `joinOn` MV. Adding a new `on` KIND does not, because the leg is omitted\n * entirely when absent — the same discipline `direction` (#1289) and `inner`\n * (#1361) follow.\n *\n * **Key encoding.** Both strategies key on {@link SortKey} — the per-component\n * ordered key #1345's `CompoundIndex` already uses — rather than a second,\n * hand-rolled encoding. That buys the kind-ranking invariant for free: the\n * string `'2026'` and the number `2026` live in different kinds and never\n * match, exactly as `predicate.ts`'s `isComparable` refuses to compare them.\n * A component whose value has no order-defined type (nullish, boolean,\n * object, array) makes the whole record unkeyable and it drops out of the\n * probe — same rule as `CompoundIndex`, where a record is indexed only when\n * EVERY component has an ordered value.\n *\n * **Cost, stated honestly:**\n *\n * | strategy | build | per left row | total |\n * |---|---|---|---|\n * | `join:composite-hash` | O(m) one pass | O(1) + matches | **O(n + m + output)** |\n * | `join:sorted-range` (`< <= > >=`) | O(m log m) one sort | O(log m) + matches | **O(m log m + n log m + output)** |\n * | `join:sorted-range` (`between`) | O(m log m) | O(log m + p), p = rights whose `from` ≤ probe | **O(m log m + n·p)** — degrades to O(n·m) when every interval starts early |\n *\n * ⚠️ Neither is index-aware in the `lookupRange`/`lookupCompound` sense: a\n * `JoinableSource` exposes `snapshot()` and `lookupById()` and nothing else,\n * so the right collection's declared indexes are not reachable from here.\n * The sort/hash is built per execution over the right SNAPSHOT. Reaching a\n * real index would mean widening the published `JoinableSource` seam and\n * taking a kernel→`with-lookup` runtime edge for a service that is opt-in;\n * that is a separate decision, not a detail of this one.\n *\n * ⚠️ **A theta join EXPANDS rows**, which the ref join never does — so the\n * per-side `maxRows` ceilings are not sufficient on their own. The OUTPUT is\n * checked against the same ceiling as it is produced, and the join throws\n * `JoinTooLargeError` with `side: 'output'` rather than allocating an\n * unbounded cartesian product. That check is the difference between an error\n * and a hang.\n */\n\nimport { readPath } from '../predicate.js'\nimport { compareKeys, toSortKey, type SortKey } from '../sort-key.js'\n\n/** Comparison operators a declared range join understands. */\nexport type JoinOnOp = '<' | '<=' | '>' | '>=' | 'between'\n\n/**\n * The consumer-facing `on`, in either of the two shapes #1339 proposed.\n *\n * - `[['clientId','clientId'], ['year','year']]` — composite equality; every\n * pair must match. Each pair is `[leftField, rightField]`.\n * - `{ left, op, right }` — a comparison of ONE left field against one right\n * field (`< <= > >=`), or against a right INTERVAL for `between`, where\n * `right` names the two boundary fields `[fromField, toField]` and the\n * bounds are inclusive.\n */\nexport type JoinOnSpec =\n | readonly (readonly [string, string])[]\n | {\n readonly left: string\n readonly op: Exclude<JoinOnOp, 'between'>\n readonly right: string\n }\n | {\n readonly left: string\n readonly op: 'between'\n readonly right: readonly [string, string]\n }\n\n/**\n * The normalised, serialisable form stored on the {@link JoinLeg}. This is\n * what lands in `toPlan()` and in the MV `queryHash` — see the module header\n * before changing its shape.\n */\nexport type JoinOnPlan =\n | {\n readonly kind: 'composite'\n /** `[leftField, rightField]` pairs, sorted by left then right field. */\n readonly pairs: readonly (readonly [string, string])[]\n }\n | {\n readonly kind: 'range'\n readonly left: string\n readonly op: JoinOnOp\n /** One right field, or the two inclusive boundary fields for `between`. */\n readonly right: readonly string[]\n }\n\nconst RANGE_OPS: ReadonlySet<string> = new Set(['<', '<=', '>', '>=', 'between'])\n\nfunction isField(value: unknown): value is string {\n return typeof value === 'string' && value.length > 0\n}\n\n/**\n * Validate and normalise a consumer `on` into its plan form.\n *\n * Every refusal is at PLAN time, with the offending shape named: an `on` that\n * cannot be serialised deterministically must never reach a `queryHash`,\n * because a hash over an invalid plan is a hash nothing can reproduce.\n */\nexport function normalizeJoinOn(on: JoinOnSpec, target: string): JoinOnPlan {\n if (Array.isArray(on)) {\n const pairs = on as readonly unknown[]\n if (pairs.length === 0) {\n throw new Error(\n `.joinOn(\"${target}\"): a composite \\`on\\` needs at least one [leftField, rightField] pair. ` +\n `Pass e.g. on: [['clientId', 'clientId'], ['year', 'year']].`,\n )\n }\n const normalized: [string, string][] = []\n for (const pair of pairs) {\n if (!Array.isArray(pair) || pair.length !== 2 || !isField(pair[0]) || !isField(pair[1])) {\n throw new Error(\n `.joinOn(\"${target}\"): every composite \\`on\\` entry must be a [leftField, rightField] pair of ` +\n `non-empty field names. Received: ${JSON.stringify(pair)}.`,\n )\n }\n normalized.push([pair[0], pair[1]])\n }\n // Sorted so a caller reordering the pairs does not change the queryHash —\n // an AND of equalities is commutative, so two such plans ARE the same\n // query and a reorder must not force every MV row to rebuild.\n normalized.sort((a, b) => (a[0] === b[0] ? (a[1] < b[1] ? -1 : a[1] > b[1] ? 1 : 0) : a[0] < b[0] ? -1 : 1))\n return { kind: 'composite', pairs: normalized }\n }\n\n const spec = on as { left?: unknown; op?: unknown; right?: unknown }\n if (!isField(spec.left)) {\n throw new Error(`.joinOn(\"${target}\"): a range \\`on\\` needs a non-empty \\`left\\` field name.`)\n }\n if (typeof spec.op !== 'string' || !RANGE_OPS.has(spec.op)) {\n throw new Error(\n `.joinOn(\"${target}\"): unknown \\`on\\` operator ${JSON.stringify(spec.op)}. ` +\n `Supported operators are ${[...RANGE_OPS].join(', ')}.`,\n )\n }\n if (spec.op === 'between') {\n if (!Array.isArray(spec.right) || spec.right.length !== 2 || !isField(spec.right[0]) || !isField(spec.right[1])) {\n throw new Error(\n `.joinOn(\"${target}\"): \\`between\\` needs exactly two right-side boundary field names — ` +\n `on: { left: 'date', op: 'between', right: ['from', 'to'] }.`,\n )\n }\n return { kind: 'range', left: spec.left, op: 'between', right: [spec.right[0], spec.right[1]] }\n }\n if (!isField(spec.right)) {\n throw new Error(`.joinOn(\"${target}\"): the \\`${spec.op}\\` operator needs a single right-side field name.`)\n }\n return { kind: 'range', left: spec.left, op: spec.op as JoinOnOp, right: [spec.right] }\n}\n\n/** A short, stable rendering of the predicate for `explain()`'s detail line. */\nexport function describeJoinOn(on: JoinOnPlan): string {\n if (on.kind === 'composite') return on.pairs.map(([l, r]) => `${l} = ${r}`).join(' AND ')\n if (on.op === 'between') return `${on.left} between [${on.right.join(', ')}]`\n return `${on.left} ${on.op} ${on.right[0]}`\n}\n\n/** `explain()`'s dispatch label for a declared-`on` leg. */\nexport function joinOnDispatch(on: JoinOnPlan): 'join:composite-hash' | 'join:sorted-range' {\n return on.kind === 'composite' ? 'join:composite-hash' : 'join:sorted-range'\n}\n\n/**\n * Length-prefixed tuple key. `${kind}:${len}:${value}` per component means a\n * string component may contain any byte — including the separator — without\n * colliding with a neighbouring component, which a plain `join('\u0000')`\n * cannot promise. `undefined` when ANY component has no ordered key, matching\n * `CompoundIndex`: a record with one unkeyable component is not in the index.\n */\nfunction tupleKey(values: readonly unknown[]): string | undefined {\n let out = ''\n for (const value of values) {\n const sk = toSortKey(value, undefined)\n if (!sk) return undefined\n const text = String(sk.key)\n out += `${sk.kind}:${text.length}:${text}|`\n }\n return out\n}\n\n/** One row the declared join produced: the left row and its matched right record. */\nexport interface JoinOnMatch {\n readonly left: unknown\n /** `undefined` when this left row matched nothing — the left-outer row. */\n readonly right: unknown\n}\n\n/**\n * Run a declared `on` against the right snapshot, emitting one\n * {@link JoinOnMatch} per matched pair plus one `right: undefined` match per\n * left row that matched nothing (the caller applies ref-mode / inner-drop\n * semantics, exactly as it does for the ref join).\n *\n * `onOverflow` is called the moment the produced row count would exceed the\n * ceiling; it is expected to throw. Passing the check as a callback keeps the\n * error's wording — which names the leg and the ceiling — with the leg.\n */\nexport function matchDeclaredJoin(\n leftRows: readonly unknown[],\n on: JoinOnPlan,\n rightSnapshot: readonly unknown[],\n maxRows: number,\n onOverflow: (produced: number) => never,\n): JoinOnMatch[] {\n const out: JoinOnMatch[] = []\n const push = (left: unknown, right: unknown): void => {\n if (out.length >= maxRows) onOverflow(out.length + 1)\n out.push({ left, right })\n }\n if (on.kind === 'composite') {\n compositeHashJoin(leftRows, on, rightSnapshot, push)\n } else {\n sortedRangeJoin(leftRows, on, rightSnapshot, push)\n }\n return out\n}\n\n/** Hash join over a tuple key — O(n + m + output). */\nfunction compositeHashJoin(\n leftRows: readonly unknown[],\n on: Extract<JoinOnPlan, { kind: 'composite' }>,\n rightSnapshot: readonly unknown[],\n push: (left: unknown, right: unknown) => void,\n): void {\n const leftFields = on.pairs.map(p => p[0])\n const rightFields = on.pairs.map(p => p[1])\n const buckets = new Map<string, unknown[]>()\n for (const record of rightSnapshot) {\n const key = tupleKey(rightFields.map(f => readPath(record, f)))\n if (key === undefined) continue\n const bucket = buckets.get(key)\n if (bucket) bucket.push(record)\n else buckets.set(key, [record])\n }\n for (const left of leftRows) {\n const key = tupleKey(leftFields.map(f => readPath(left, f)))\n const bucket = key === undefined ? undefined : buckets.get(key)\n if (!bucket || bucket.length === 0) {\n push(left, undefined)\n continue\n }\n for (const right of bucket) push(left, right)\n }\n}\n\ninterface RangeEntry {\n readonly key: SortKey\n /** The upper boundary key, for `between` only. */\n readonly hi: SortKey | undefined\n readonly record: unknown\n}\n\n/**\n * Nested loop over a right side sorted ONCE by the probed field.\n *\n * Entries are ordered by `compareKeys`, which ranks by kind first, so the\n * slice a probe may reach is clamped to the probe's own kind band — a string\n * probe cannot walk into the number entries, mirroring the linear scan.\n */\nfunction sortedRangeJoin(\n leftRows: readonly unknown[],\n on: Extract<JoinOnPlan, { kind: 'range' }>,\n rightSnapshot: readonly unknown[],\n push: (left: unknown, right: unknown) => void,\n): void {\n const lowField = on.right[0]!\n const highField = on.op === 'between' ? on.right[1]! : undefined\n const entries: RangeEntry[] = []\n for (const record of rightSnapshot) {\n const key = toSortKey(readPath(record, lowField), undefined)\n if (!key) continue\n const hi = highField === undefined ? undefined : toSortKey(readPath(record, highField), undefined)\n if (highField !== undefined && !hi) continue\n entries.push({ key, hi, record })\n }\n entries.sort((a, b) => compareKeys(a.key, b.key))\n\n for (const left of leftRows) {\n const probe = toSortKey(readPath(left, on.left), undefined)\n if (!probe) {\n push(left, undefined)\n continue\n }\n // The contiguous run of entries sharing the probe's kind. Everything\n // outside it is incomparable, exactly as `isComparable` says.\n const [bandStart, bandEnd] = kindBand(entries, probe.kind)\n const lo = lowerBound(entries, probe, bandStart, bandEnd)\n const hi = upperBound(entries, probe, bandStart, bandEnd)\n\n let matched = false\n const emit = (from: number, to: number, keep?: (e: RangeEntry) => boolean): void => {\n for (let i = from; i < to; i++) {\n const entry = entries[i]!\n if (keep && !keep(entry)) continue\n matched = true\n push(left, entry.record)\n }\n }\n switch (on.op) {\n // `left.field < right.field` — the right keys strictly ABOVE the probe.\n case '<': emit(hi, bandEnd); break\n case '<=': emit(lo, bandEnd); break\n case '>': emit(bandStart, lo); break\n case '>=': emit(bandStart, hi); break\n // `right.from <= left.field <= right.to`. Sorted by `from`, so the\n // candidates are the prefix whose `from` is at or below the probe; the\n // `to` bound is then a filter over that prefix, which is what makes the\n // interval case O(p) per left row rather than O(log m).\n case 'between':\n emit(bandStart, hi, e => e.hi !== undefined && compareKeys(e.hi, probe) >= 0)\n break\n }\n if (!matched) push(left, undefined)\n }\n}\n\n/**\n * The half-open range of entries whose key has the given kind. Computed by\n * kind ALONE — a sentinel `SortKey` cannot express \"smallest of this kind\",\n * because `compareKeys` falls back to `<`/`>` on mixed key types and returns\n * 0 for a number sentinel against a string key, which would silently collapse\n * the band to nothing.\n */\nfunction kindBand(entries: readonly RangeEntry[], kind: number): [number, number] {\n const bound = (strict: boolean): number => {\n let lo = 0\n let hi = entries.length\n while (lo < hi) {\n const mid = (lo + hi) >>> 1\n const d = entries[mid]!.key.kind - kind\n if (strict ? d < 0 : d <= 0) lo = mid + 1\n else hi = mid\n }\n return lo\n }\n return [bound(true), bound(false)]\n}\n\nfunction lowerBound(entries: readonly RangeEntry[], probe: SortKey, from = 0, to = entries.length): number {\n let lo = from\n let hi = to\n while (lo < hi) {\n const mid = (lo + hi) >>> 1\n if (compareKeys(entries[mid]!.key, probe) < 0) lo = mid + 1\n else hi = mid\n }\n return lo\n}\n\nfunction upperBound(entries: readonly RangeEntry[], probe: SortKey, from = 0, to = entries.length): number {\n let lo = from\n let hi = to\n while (lo < hi) {\n const mid = (lo + hi) >>> 1\n if (compareKeys(entries[mid]!.key, probe) <= 0) lo = mid + 1\n else hi = mid\n }\n return lo\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
OverlayIdMismatchError
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-244VXYPG.js";
|
|
4
4
|
|
|
5
5
|
// src/with-formula/overlay-views/virtual-collection.ts
|
|
6
6
|
var OverlayedCollection = class {
|
|
@@ -168,7 +168,7 @@ var OverlayedCollection = class {
|
|
|
168
168
|
/** @throws — async iteration over a virtual collection is deferred. */
|
|
169
169
|
scan() {
|
|
170
170
|
throw new Error(
|
|
171
|
-
`OverlayedCollection "${this.spec.name}".scan() is not yet implemented for overlay views (#154). Use \`list()\` for now (no row-count ceiling at
|
|
171
|
+
`OverlayedCollection "${this.spec.name}".scan() is not yet implemented for overlay views (#154). Use \`list()\` for now (no row-count ceiling at pilot1 scale), or scan the underlying collections directly.`
|
|
172
172
|
);
|
|
173
173
|
}
|
|
174
174
|
/** @throws — lazy-mode query is not applicable to virtual collections. */
|
|
@@ -206,4 +206,4 @@ var OverlayedCollection = class {
|
|
|
206
206
|
export {
|
|
207
207
|
OverlayedCollection
|
|
208
208
|
};
|
|
209
|
-
//# sourceMappingURL=chunk-
|
|
209
|
+
//# sourceMappingURL=chunk-MLPHLJIQ.js.map
|