@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 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/kernel/query/internal/hooks.ts","../src/kernel/query/cursor.ts","../src/kernel/query/builder.ts"],"sourcesContent":["/**\n * #1458 — the plan-level seam between Find and the Relate extension.\n *\n * Find owns the executor, and the executor has to be able to run a plan that\n * carries join legs or a `crossJoin` clause. Those clauses are Relate's to\n * BUILD but Find's to EXECUTE, so the split cannot be made by moving code:\n * `toArray`, `matchedRecords` and `executeClausePipeline` are Find methods\n * that must call into `relate/join.ts`.\n *\n * ⭐ **The slot is provably full whenever it is read.** Every call site is\n * guarded by `plan.joins.length > 0` or by a `crossJoin` clause being present,\n * and only Relate's builders can put either into a plan — so a Find-only\n * consumer never reaches a hook, which is exactly why Find's import graph can\n * stay free of `relate/`.\n *\n * ⚠️ The one way to reach an empty slot is to hand-build a `QueryPlan` with\n * legs and pass it to the `Query` constructor. `QueryPlan` is a published,\n * consumer-constructible type, so that is a real path rather than a\n * theoretical one — and it is why `relateHooks()` throws\n * {@link QueryExtensionMissingError} instead of asserting non-null.\n */\nimport { QueryExtensionMissingError } from '../../errors.js'\nimport type { Clause, CrossJoinClause } from '../predicate.js'\nimport type { JoinableSource, JoinContext, JoinLeg } from '../relate/join.js'\nimport type { OrderBy } from '../builder.js'\n\n/** The Relate entry points Find's executor calls. Every one is join-conditional. */\nexport interface RelateHooks {\n applyJoins(\n rows: readonly unknown[],\n joins: readonly JoinLeg[],\n ctx: JoinContext,\n locale?: string,\n ): unknown[]\n splitAroundJoins(\n clauses: readonly Clause[],\n joins: readonly JoinLeg[],\n ): { preJoin: readonly Clause[]; postJoin: readonly Clause[] }\n orderReferencesJoinAlias(orderBy: readonly OrderBy[], joins: readonly JoinLeg[]): boolean\n joinsDropLeftRows(joins: readonly JoinLeg[]): boolean\n applyCrossJoin(leftRel: unknown[], clause: CrossJoinClause, rightSource: JoinableSource): unknown[]\n}\n\nlet installed: RelateHooks | undefined\n\n/** Called once by `@noy-db/hub/query/relate` on load. */\nexport function installRelateHooks(hooks: RelateHooks): void {\n installed = hooks\n}\n\n/**\n * The Relate hooks, or the actionable error. Read only from a guarded branch —\n * see this module's header for why that makes the throw unreachable for a\n * consumer who never built a join.\n */\nexport function relateHooks(): RelateHooks {\n if (installed === undefined) {\n throw new QueryExtensionMissingError('join', '@noy-db/hub/query/relate')\n }\n return installed\n}\n","/**\n * Keyset cursors for `Query.page()` / `Query.after()` (#1346).\n *\n * A cursor names a POSITION — the `(sortKey, id)` of the last row a page\n * served — not an offset. That is the whole point: a record inserted or\n * deleted before the position cannot shift the next window, where\n * `offset(n)` would re-serve or skip a row.\n *\n * The encoding is deliberately OPAQUE: consumers must treat the string as a\n * token and pass it back verbatim, so the shape stays free to change. It is\n * an encoding, NOT a signature — a cursor carries no secret and travels only\n * as far as the caller sends it. The `shape` token is an integrity check\n * against consumer mistakes (a cursor replayed against another sort order or\n * another collection), not against an adversary.\n *\n * Portability: hub/src must run in a browser/Worker/Deno/Bun, so the base64\n * step uses `btoa`/`atob` over a `TextEncoder` byte string — never `Buffer`.\n */\n\nimport type { OrderBy } from './builder.js'\n\n/** Bumped if the encoded payload's shape ever changes; old cursors then refuse. */\nconst CURSOR_VERSION = 1\n\n/** The decoded keyset a cursor names. */\nexport interface KeysetCursor {\n /** The sort spec + source identity this cursor was minted for. */\n readonly shape: string\n /** The row's sort-key values, one per `orderBy` entry. */\n readonly values: readonly unknown[]\n /** The row's record id — the tiebreak that makes the keyset a total order. */\n readonly id: string\n}\n\n/**\n * The token a cursor is bound to. Two queries may resume each other's cursors\n * only when this matches: same source, same ordered sort spec.\n */\nexport function keysetShape(identity: string | undefined, orderBy: readonly OrderBy[]): string {\n const spec = orderBy.map(o => `${o.field}:${o.direction}:${o.by ?? 'value'}`).join(',')\n return `${identity ?? '(anonymous source)'}::${spec}`\n}\n\n/**\n * Tag the value types the order comparator distinguishes. Everything else it\n * treats as equal anyway (see `compareValues`), so encoding it as `null`\n * loses nothing the comparison would have used — the id tiebreak carries the\n * page forward.\n */\nfunction encodeValue(v: unknown): unknown {\n if (v instanceof Date) return { $d: v.toISOString() }\n if (typeof v === 'number' || typeof v === 'string' || typeof v === 'boolean') return v\n return null\n}\n\nfunction decodeValue(v: unknown): unknown {\n if (v !== null && typeof v === 'object' && '$d' in (v as Record<string, unknown>)) {\n return new Date((v as { $d: string }).$d)\n }\n return v\n}\n\nfunction toBase64(text: string): string {\n const bytes = new TextEncoder().encode(text)\n let binary = ''\n for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]!)\n return btoa(binary)\n}\n\nfunction fromBase64(b64: string): string {\n const binary = atob(b64)\n const bytes = new Uint8Array(binary.length)\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i)\n return new TextDecoder().decode(bytes)\n}\n\nexport function encodeCursor(cursor: KeysetCursor): string {\n return toBase64(\n JSON.stringify({\n v: CURSOR_VERSION,\n k: cursor.shape,\n s: cursor.values.map(encodeValue),\n i: cursor.id,\n }),\n )\n}\n\n/**\n * Decode a cursor and REFUSE it unless it was minted for `expectedShape`.\n * Silently returning a nonsense window for a mismatched cursor is the\n * failure mode this exists to prevent.\n */\nexport function decodeCursor(raw: string, expectedShape: string): KeysetCursor {\n let payload: { v?: unknown; k?: unknown; s?: unknown; i?: unknown }\n try {\n payload = JSON.parse(fromBase64(raw)) as typeof payload\n } catch {\n throw new Error(\n `Query.after(): the value passed is not a valid keyset cursor. ` +\n `Pass back the \\`nextCursor\\` from a previous .page() call, verbatim.`,\n )\n }\n if (\n payload === null ||\n typeof payload !== 'object' ||\n payload.v !== CURSOR_VERSION ||\n typeof payload.k !== 'string' ||\n !Array.isArray(payload.s) ||\n typeof payload.i !== 'string'\n ) {\n throw new Error(\n `Query.after(): the value passed is not a valid keyset cursor ` +\n `(or was minted by an incompatible version). Pass back the ` +\n `\\`nextCursor\\` from a previous .page() call, verbatim.`,\n )\n }\n if (payload.k !== expectedShape) {\n throw new Error(\n `Query.after(): this cursor was minted for a different query shape. ` +\n `Cursor: \"${payload.k}\"; this query: \"${expectedShape}\". A keyset ` +\n `cursor is only valid for the same collection and the same ` +\n `orderBy(...) spec that produced it.`,\n )\n }\n return { shape: payload.k, values: payload.s.map(decodeValue), id: payload.i }\n}\n","/**\n * Chainable, immutable query builder.\n *\n * Each builder operation returns a NEW Query — the underlying plan is never\n * mutated. This makes plans safe to share, cache, and serialize.\n */\n\nimport type { QueryField } from '../types.js'\nimport type { Clause, CrossJoinClause, FieldClause, FilterClause, GroupClause, Operator, WherePredicateClause } from './predicate.js'\nimport { evaluateClause, hasFnClause, normalizeMatches, normalizeSubqueryOperand } from './predicate.js'\nimport type { CollectionIndexes } from '../../with-lookup/indexing/eager-indexes.js'\n// ─── #1458 — Relate is TYPE-ONLY here ────────────────────────────────────\n// `JoinLeg` / `JoinContext` describe a plan Find must be able to EXECUTE, and\n// a type import is erased, so naming them costs the Find bundle nothing. The\n// runtime half arrives through `internal/hooks.ts`; see that file for why the\n// slot is always full by the time Find reads it.\nimport type { JoinableSource, JoinContext, JoinLeg } from './relate/join.js'\nimport { relateHooks } from './internal/hooks.js'\nimport { CrossJoinSourceUnknownError, FieldNotQueryableError } from '../errors.js'\nimport { QueryExtensionMissingError } from '../errors.js'\nimport { gateTerminal } from './hydration.js'\nimport type { HydrationGate } from './hydration.js'\nimport type { SourceChange } from './live/incremental.js'\n// ⚠️ The reduce STRATEGY module, and nothing else from `with-lookup/reduce`.\n// It is the null-object seam that makes the aggregate service opt-in (309 B,\n// no transitive runtime deps) — see its own header. The engine behind it\n// arrives only through `@noy-db/hub/query/reduce`.\nimport { NO_REDUCE, type ReduceStrategy } from '../../with-lookup/reduce/strategy.js'\nimport type { ViaPipeline } from '../via/pipeline.js'\nimport { isViaPrefixProbe } from '../via/index.js'\nimport { decodeCursor, encodeCursor, keysetShape } from './cursor.js'\n\n// ─── #1458 — the five join-conditional Relate entry points ────────────────\n//\n// Each of these was a direct import from `relate/join.ts`. They are now thin\n// shims: the empty-plan answer inline (byte-identical to the first line of the\n// real function, which is what makes the shim faithful rather than a second\n// implementation), and a hook call otherwise. Call sites are unchanged, so the\n// executor below reads exactly as it did before the split.\n//\n// ⭐ The inline branch is not an optimisation — it is the PROOF that a\n// Find-only consumer never reaches `relateHooks()`. A plan with no legs and no\n// crossJoin clause is answered entirely by these first lines.\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 return relateHooks().splitAroundJoins(clauses, joins)\n}\n\nfunction orderReferencesJoinAlias(orderBy: readonly OrderBy[], joins: readonly JoinLeg[]): boolean {\n if (joins.length === 0 || orderBy.length === 0) return false\n return relateHooks().orderReferencesJoinAlias(orderBy, joins)\n}\n\nfunction joinsDropLeftRows(joins: readonly JoinLeg[]): boolean {\n if (joins.length === 0) return false\n return relateHooks().joinsDropLeftRows(joins)\n}\n\nfunction 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 return relateHooks().applyJoins(rows, joins, context, locale)\n}\n\nfunction applyCrossJoin(\n leftRel: unknown[],\n clause: CrossJoinClause,\n rightSource: JoinableSource,\n): unknown[] {\n // No early-out: reaching this line means the plan HAS a crossJoin clause,\n // which only `@noy-db/hub/query/relate` can build.\n return relateHooks().applyCrossJoin(leftRel, clause, rightSource)\n}\n\nexport interface OrderBy {\n readonly field: string\n readonly direction: 'asc' | 'desc'\n /**\n * Sort key for a `dictKey`/`staticDict` field: `'value'` (default)\n * sorts by the stored code; `'label'` sorts by the code's resolved label at\n * the query locale (`toArray({ locale })`, or a `staticDict` `displayLocale`).\n * Falls back to the code when no label resolves.\n */\n readonly by?: 'value' | 'label'\n}\n\n/**\n * A complete query plan: zero-or-more clauses, optional ordering, pagination,\n * and optional joins.\n *\n * Plans are JSON-serializable as long as no FilterClause is present and no\n * join leg carries a manual `strategy` override (JoinLeg itself is plain\n * data, so it serializes cleanly).\n *\n * Plans are intentionally NOT parametric on T — see `predicate.ts` FilterClause\n * for the variance reasoning. The public `Query<T>` API attaches the type tag.\n */\nexport interface QueryPlan {\n readonly clauses: readonly Clause[]\n readonly orderBy: readonly OrderBy[]\n readonly limit: number | undefined\n readonly offset: number\n /**\n * Opaque keyset cursor from `.after(cursor)` (#1346). When present, the\n * window starts strictly after the `(sortKey, id)` the cursor names,\n * instead of at a positional offset.\n *\n * OPTIONAL, unlike its `limit`/`offset` neighbours: `QueryPlan` is an\n * exported type that consumers construct, so a required new property would\n * be a breaking change where an optional one is additive.\n */\n readonly after?: string | undefined\n /**\n * Zero-or-more join legs to apply after where/orderBy/limit/offset.\n * Each leg attaches a resolved right-side record (or null) under its\n * alias. See `query/join.ts` for the full semantics.\n */\n readonly joins: readonly JoinLeg[]\n}\n\nconst EMPTY_PLAN: QueryPlan = {\n clauses: [],\n orderBy: [],\n limit: undefined,\n offset: 0,\n after: undefined,\n joins: [],\n}\n\n/**\n * Guard for the terminals that reduce rather than project (#1030). Grouping\n * or aggregating over a joined alias silently bucketed every row under\n * `undefined`, because these terminals never apply join legs at all.\n *\n * ⭐ **`aggregate()` and `groupBy()` NO LONGER CALL THIS — #1338 supplied the\n * work the analysis below specifies, and they route instead of refusing.**\n * The remaining caller is `distinct()`, whose Via question is a different one\n * (`distinctKeyOf` canonicalises through the LEFT pipeline's index key, so an\n * aliased value would dedup on the wrong canonicaliser) and which no issue has\n * asked for. Everything below is the analysis #1338 was built from; it is kept\n * because it names WHICH properties had to hold, and `join-reduce.ts` is where\n * each one is now discharged:\n *\n * - the right side's reducer rewrite AND its posture gate, in one call —\n * `joinAliasBinding` hands each aliased reducer to the right collection's\n * own `wrapReducers` under its bare field name;\n * - right-side change streams merged into the live upstreams —\n * `Query.rightSideUpstreams()`, shared with `live()`;\n * - and the case the analysis could not see, because the grouped terminal\n * is one object further along the chain than `Query.aggregate()`: a\n * reducer over an alias under a LEFT group key, which returned a confident\n * `0`. `refuseAliasBinding` refuses it.\n *\n * Refusing rather than reordering was a DELIBERATE, REVIEWED DECISION\n * (2026-08-10), not an oversight. What follows is why, so it is not\n * re-litigated from scratch — and so nobody \"fixes\" it for the wrong reason.\n *\n * It is NOT a cardinality problem. A ref join is an equi-join on the target's\n * PRIMARY KEY, so every left row matches at most one right record and the row\n * count is constant across legs (see `join.ts`). Aggregating over joined rows\n * is perfectly well-defined; `count()` is unambiguous. Anyone who reads this\n * guard as \"the semantics are unclear\" has the wrong model.\n *\n * The actual blocker is that the Via pipeline is LEFT-SCOPED. `aggregate()`\n * runs `this.source.via.wrapReducers(spec)`, which resolves `postureFor(field)`\n * against the LEFT collection's field map. For `sum('client.balance')` that map\n * has no entry, so two things silently do not happen:\n *\n * - money's exact-BigInt reducer rewrite is skipped, and a generic sum runs\n * over stored scaled-integer strings — silently wrong numbers;\n * - `refuseUnqueryableReducers` does not fire, so the `queryable: 'none'`\n * gate that would refuse the field never applies.\n *\n * A gate that silently does not apply is worse than a missing feature, which\n * is why this refuses instead of guessing. Supporting joined aggregation means\n * resolving a joined field's posture and reducers from the RIGHT collection's\n * Via pipeline (via `joinContext.resolveSource`), plus merging right-side\n * change streams into the live-reduction upstreams the way `Query.live()`\n * already does — otherwise a live joined aggregate silently stops updating.\n * That is the work. It is not \"apply the legs here\".\n *\n * Two things that are already handled, so they are not reasons to defer: the\n * MV dependency analyzer already treats `plan.joins` targets as sources and\n * folds them into the queryHash, and `.crossJoin()` — whose clause lives in\n * the clause list — already aggregates correctly today. The error below points\n * there because it is a real answer, not a consolation.\n *\n * Deliberately NOT tracked as an issue: no consumer has asked, and #984 is the\n * cautionary tale — a speculative deferral whose premises had drifted out of\n * sync with the code by the time anyone re-read it. Build this when a real\n * query needs it, and design it against that query.\n * ⭐ It was tracked as one three weeks later (#1338, the accounting-report\n * shape) and built against that query — which is the paragraph above working,\n * not failing.\n */\n\n/**\n * Source of records that a query executes against.\n *\n * The interface is non-parametric to keep variance friendly: callers cast\n * their typed source (e.g. `QuerySource<Invoice>`) into this opaque shape.\n *\n * `getIndexes` and `lookupById` are optional fast-path hooks. When both are\n * present and a where clause matches an indexed field, the executor uses\n * the index to skip a linear scan. Sources without these methods (or with\n * `getIndexes` returning `null`) always fall back to a linear scan.\n */\nexport interface QuerySource<T> {\n /** Snapshot of all current records. The query never mutates this array. */\n snapshot(): readonly T[]\n /**\n * Subscribe to mutations; returns an unsubscribe function.\n *\n * A source that knows WHICH record changed passes the delta (#1341) so\n * `.live()` can patch its result set rather than re-run the plan. Calling\n * `cb()` with no argument stays valid — it means \"something changed\", and\n * the live query answers with a full re-run.\n */\n subscribe?(cb: (change?: SourceChange) => void): () => void\n /** Index store for the indexed-fast-path. Optional. */\n getIndexes?(): CollectionIndexes | null\n /** O(1) record lookup by id, used to materialize index hits. */\n lookupById?(id: string): T | undefined\n /**\n * The backing collection's compiled Via pipeline (money now; more Via\n * features later), used to rewrite `where()` operands, decode results,\n * order, and rewrite aggregate reducers for covered fields.\n */\n via?: ViaPipeline\n /**\n * Id-paired snapshot for `Query._idArray()` (the `retrieve({within})`\n * id projection). Optional: only collection-backed queries supply it.\n */\n snapshotEntries?(): readonly { id: string; record: T }[]\n /**\n * #1414 — cold-collection gate. Present only on collection-backed eager\n * sources. While `isHydrated()` is false the collection's snapshot is empty\n * by ABSENCE, not by content, so every terminal returns a pending result\n * (awaitable, and throwing on synchronous use) instead of a confident empty.\n * See `query/hydration.ts`.\n */\n hydration?: HydrationGate\n /**\n * Stable name for this source (`<vault>/<collection>`), used to bind a\n * keyset cursor to the query that minted it (#1346) so a cursor replayed\n * against another collection is refused rather than silently mis-paged.\n */\n identity?: string\n /**\n * #1417 — monotonic mutation counter for the backing cache. Two reads\n * returning the same number means nothing changed between them, which is\n * what lets `page()`/`after()` reuse one sort across a page walk instead of\n * re-sorting the whole collection per page.\n *\n * Optional, and absence is safe: a source that does not supply it simply\n * gets no memo. It is a CHANGE COUNTER, never a content hash — see\n * `kernel/generation-map.ts` for why it is maintained by the container\n * rather than at the mutation sites.\n */\n snapshotVersion?(): number\n}\n\n/**\n * @internal #1458 — exported so the extension mixins in `query/{live,reduce,\n * relate}/` can name the source they read. Not part of the published surface:\n * `QuerySource<T>` above is what a consumer implements.\n */\nexport interface InternalSource {\n snapshot(): readonly unknown[]\n subscribe?(cb: (change?: SourceChange) => void): () => void\n getIndexes?(): CollectionIndexes | null\n lookupById?(id: string): unknown\n via?: ViaPipeline\n snapshotEntries?(): readonly { id: string; record: unknown }[]\n hydration?: HydrationGate\n identity?: string\n snapshotVersion?(): number\n}\n\n/**\n * Declared deterministic predicate. Carries the consumer's\n * stable `hash` (for function-body identity), the function itself,\n * and is keyed by name when registered on a `Query<T>` via\n * `_withPredicates()`.\n */\nexport interface DeclaredPredicate {\n hash: string\n fn: (record: unknown, ctx?: unknown) => boolean\n}\n\n/**\n * The chainable query builder over an eager collection's decrypted cache.\n *\n * ## Its terminals are SYNCHRONOUS (#1413)\n *\n * `toArray()`, `ids()`, `page()`, `first()`, `count()` and `exists()` return\n * their value directly — `T[]`, `string[]`, `{ rows, nextCursor }`, `T | null`,\n * `number`, `boolean` — **not** a `Promise` of it. That is the architecture\n * showing through, not an oversight: `Query` runs over `source.snapshot()`, an\n * already-decrypted in-memory view. Decryption happened at hydration, so by the\n * time a plan executes there is nothing left to await. Making these async would\n * break every call site and erase the one property that distinguishes a cached\n * query from a fetch.\n *\n * ⚠️ **So `.catch()` / `.then()` on a terminal's result is not part of the\n * contract.** `query().toArray().catch(fn)` fails with *\"catch is not a\n * function\"* on a loaded collection. Handle errors with `try` / `catch` around\n * the call.\n *\n * `await` is always safe, though — awaiting a plain array yields the array —\n * and on an unhydrated collection it is REQUIRED. See below.\n *\n * ## The one exception, and it is not an async terminal (#1414)\n *\n * On a collection that has never been loaded, a terminal cannot answer: the\n * snapshot is empty by ABSENCE, not by content. Rather than return a confident\n * `[]` / `0` / `false`, it returns a **pending result** — a thenable that\n * hydrates and re-runs the terminal when awaited, and throws\n * {@link CollectionNotHydratedError} on every use that READS it — `.length`,\n * indexing, iteration, spread, `JSON.stringify`, any property access.\n * `Array.isArray` answers `true`, so the ordinary defensive guard for a `T[]`\n * reaches that throw rather than silently substituting `[]` (#1462); `typeof`\n * and truthiness are the two uses that cannot throw, and\n * `query/hydration.ts` enumerates why. It is deliberately NOT a\n * promise-shaped array: the moment the collection is hydrated the very same\n * call returns the plain synchronous value again. Write\n * `await collection.query().toArray()` — correct in both states — or\n * `await collection.list()` first and then read synchronously.\n * See `query/hydration.ts`.\n *\n * ## Where the same name IS async\n *\n * `PartitionedQuery.toArray()` (`with-store/partitioned/index.ts`) and the lazy\n * builder's `LazyQuery.toArray()` (`with-lookup/indexing/lazy-builder.ts`)\n * return `Promise<T[]>`. Both genuinely fetch — across partition legs, or\n * through the persisted `_idx/` side-car — so both genuinely await. Same\n * method name, different contract, because the surface underneath differs.\n *\n * ---\n *\n * All non-terminal methods return a NEW Query — the original is unchanged.\n * Type parameter T flows through the public API for ergonomics, but the\n * internal storage uses `unknown` so `Collection<T>` stays covariant.\n *\n * The optional `joinContext` is attached when the Query is constructed via\n * `Collection.query()` (Collection passes in a context built from the Vault's\n * join resolver). A Query constructed via `new Query` directly — e.g. from\n * tests with a plain-object source — has no joinContext, and calling `.join()`\n * on it throws with an actionable error. See `query/join.ts` for the full\n * design.\n */\nexport class Query<T, S extends keyof T = never, Q extends keyof T & string = never, M extends keyof T & string = never> {\n private readonly source: InternalSource\n private readonly plan: QueryPlan\n private readonly joinContext: JoinContext | undefined\n private readonly reduceStrategy: ReduceStrategy\n private readonly predicates: ReadonlyMap<string, DeclaredPredicate> | undefined\n\n constructor(\n source: QuerySource<T>,\n plan: QueryPlan = EMPTY_PLAN,\n joinContext?: JoinContext,\n reduceStrategy: ReduceStrategy = NO_REDUCE,\n predicates?: ReadonlyMap<string, DeclaredPredicate>,\n ) {\n this.source = source as InternalSource\n this.plan = plan\n this.joinContext = joinContext\n this.reduceStrategy = reduceStrategy\n this.predicates = predicates\n }\n\n /**\n * @internal — accessor for the materialized-view dependency\n * analyzer. Not part of the public API; consumers should use the\n * builder methods, not inspect the plan directly.\n */\n _plan(): QueryPlan {\n return this.plan\n }\n\n /**\n * @internal — accessor for the materialized-view dependency\n * analyzer. Returns the join resolution context (or `undefined` for\n * queries constructed without a Collection backing).\n */\n _joinContext(): JoinContext | undefined {\n return this.joinContext\n }\n\n /**\n * @internal #1414 — clone this Query with the cold-collection gate REMOVED.\n *\n * For engine-internal readers only. The materialized-view engine reads its\n * source collections through the public `collection.query()` on paths that\n * are synchronous by construction (registration inspects the plan; the\n * executor's row scan is called from inside a write commit), and it has\n * always read whatever the in-memory cache held. Gating those would turn a\n * pre-existing read into a throw for consumers who never asked a question —\n * so this preserves that behaviour EXACTLY, and confines #1414's change to\n * the surface a consumer or a guard actually calls.\n *\n * ⚠️ It does not make an unhydrated read correct — an MV computed over a\n * cold source is the same defect wearing a different hat. That is tracked\n * separately; do not reach for this to silence the gate in new code.\n */\n _ungated(): Query<T, S, Q, M> {\n if (this.source.hydration === undefined) return this\n const rest: InternalSource = { ...this.source }\n delete rest.hydration\n return new Query<T, S, Q, M>(rest as QuerySource<T>, this.plan, this.joinContext, this.reduceStrategy, this.predicates)\n }\n\n /**\n * @internal — clone this Query with a declared-predicate map\n * attached. Used by the materialized-view registry to enable\n * `.wherePredicate(name, ctx?)` for the MV's query callback.\n * Consumers don't call this directly.\n */\n _withPredicates(predicates: ReadonlyMap<string, DeclaredPredicate>): Query<T, S, Q, M> {\n return new Query<T, S, Q, M>(\n this.source as QuerySource<T>,\n this.plan,\n this.joinContext,\n this.reduceStrategy,\n predicates,\n )\n }\n\n /**\n * @internal — the ids of records matching this query's plan,\n * recovered by reference identity: `executePlanWithSource` returns the\n * ORIGINAL snapshot record references (money-decode and joins are applied\n * later, in `toArray`), so each matched record is found in the id-paired\n * `snapshotEntries()` map. Used by `collection.retrieve({ within })`.\n * Throws if the source is not collection-backed (no `snapshotEntries`).\n */\n _idArray(): string[] {\n const entries = this.source.snapshotEntries?.()\n if (entries === undefined) {\n throw new Error(\n 'Query._idArray(): the query source has no snapshotEntries(); ' +\n 'retrieve({ within }) requires a collection-backed query (collection.query()).',\n )\n }\n if (this.plan.clauses.some(c => c.type === 'crossJoin')) {\n throw new Error(\n 'Query._idArray(): retrieve({ within }) does not support crossJoin queries ' +\n '(cross-join produces new row objects, breaking id recovery). ' +\n 'Use where/filter/and/or, or a projection .join().',\n )\n }\n const refToId = new Map<unknown, string>()\n for (const { id, record } of entries) refToId.set(record, id)\n const matched = executePlanWithSource(this.source, this.plan, this.joinContext)\n const ids: string[] = []\n for (const r of matched) {\n const id = refToId.get(r)\n if (id !== undefined) ids.push(id)\n }\n return ids\n }\n\n /**\n * The ids of the records this query matches (#1351) — the public spelling\n * of {@link _idArray}, and the eager half of the subquery operand:\n * `where(f, 'in', inner.ids())` and `where(f, 'in', inner)` build the SAME\n * clause. Reach for the explicit form when you want to reuse the id set, or\n * to see it.\n *\n * Requires a collection-backed query (`collection.query()`); a `crossJoin`\n * plan is refused, because it produces new row objects and there is no id\n * to recover.\n *\n * **Synchronous** (#1413) — returns `string[]`, not a promise; the cache it reads is\n * already decrypted. `await` is safe and is REQUIRED on an unhydrated collection\n * (#1414); `.catch()` is not available. See the {@link Query} class doc.\n */\n ids(): string[] {\n const _h = this.source.hydration\n if (_h !== undefined && !_h.isHydrated()) return gateTerminal(_h, 'ids', () => this.ids())\n return this._idArray()\n }\n\n /**\n * @internal — the id-operand contract `normalizeSubqueryOperand()`\n * (`predicate.ts`) duck-types when this Query is passed as the operand of\n * `in`/`!in`. Separate from {@link ids} so the failure a subquery hits is\n * phrased as a subquery failure rather than as a `retrieve({ within })` one.\n */\n _asIdOperand(): { readonly ids: readonly string[]; readonly from: string } {\n if (this.source.snapshotEntries === undefined) {\n throw new Error(\n \"where(..., 'in', <subquery>): the inner query's source is not \" +\n 'collection-backed (no snapshotEntries()). Pass a query obtained from ' +\n 'collection.query(), or pass a literal array of values.',\n )\n }\n return { ids: this._idArray(), from: this.source.identity ?? '(unnamed)' }\n }\n\n /**\n * Filter by a registered deterministic predicate. Requires\n * the Query to have been augmented with a predicates map (typically\n * via the materialized-view registry — bare Queries constructed\n * outside an MV throw on `.wherePredicate()`).\n *\n * `ctx` is an optional opaque value passed verbatim to the predicate\n * function. Both `predicateHash` (from the registration) and a\n * canonical-JSON hash of `ctx` fold into the MV's `queryHash`, so\n * either changing forces refresh on next visit.\n */\n wherePredicate(name: string, ctx?: unknown): Query<T, S, Q, M> {\n if (!this.predicates) {\n throw new Error(\n `.wherePredicate(\"${name}\"): no predicates registered on this Query. ` +\n `Function-based predicates require the Query to be obtained from ` +\n `inside a materialized-view query() callback whose strategy declares ` +\n `\\`predicates: { ${name}: { hash, fn } }\\`.`,\n )\n }\n const decl = this.predicates.get(name)\n if (!decl) {\n throw new Error(\n `.wherePredicate(\"${name}\"): predicate not registered. ` +\n `Available: ${[...this.predicates.keys()].join(', ') || '(none)'}.`,\n )\n }\n const clause: WherePredicateClause = {\n type: 'wherePredicate',\n name,\n ctx,\n predicateHash: decl.hash,\n ctxHash: canonicalCtxHash(ctx),\n fn: decl.fn,\n }\n return new Query<T, S, Q, M>(\n this.source as QuerySource<T>,\n { ...this.plan, clauses: [...this.plan.clauses, clause] },\n this.joinContext,\n this.reduceStrategy,\n this.predicates,\n )\n }\n\n /**\n * Add a field comparison. Multiple where() calls are AND-combined.\n *\n * A declared money field compares in MAJOR units: the operand\n * (`10000`, `'10000.00'`, or `{ amount, currency }` in multi mode) is\n * quantized into stored scaled-int space at build time and evaluated\n * BigInt-exact per record. A malformed operand or a string operator\n * (`contains`/`startsWith`) throws here, at the call site.\n *\n * Consults the Via pipeline's posture before building a clause (#629\n * Task 8): a field whose posture is `queryable: 'none'` (e.g. a\n * `blobFields` slot) throws `FieldNotQueryableError` here, at the call\n * site. Every other posture is unaffected — the existing per-binding\n * `buildClause` machinery runs exactly as before.\n */\n where(field: QueryField<T, S, Q>, op: Operator, value: unknown): Query<T, S, Q, M> {\n const via = this.source.via\n if (via?.postureFor(field)?.queryable === 'none') throw new FieldNotQueryableError(field)\n // #1357: a 'matches' operand is refused-or-normalized HERE, at the call\n // site — an anchored literal prefix lowers to `startsWith` (taking the\n // sorted index), anything else serializes to `{ source, flags }` so the\n // pattern folds into an MV's queryHash. Every other operator is identity.\n // #1351: a SUBQUERY operand of `in`/`!in` is resolved to its id array\n // HERE, once, at build time — so everything downstream (the hash-index\n // dispatch in `candidateRecords`, the queryHash fold, `explain()`) sees a\n // literal array and needs no subquery awareness at all. The operand is\n // therefore a SNAPSHOT of the inner result — read\n // `normalizeSubqueryOperand`'s doc for what that costs a `.live()` query\n // (an inner-collection change does not re-fire it).\n const { op: sop, value: sval, subquery } = normalizeSubqueryOperand(op, value)\n const { op: mop, value: mval } = normalizeMatches(sop, sval)\n const viaClause = via?.buildClause(field, mop, mval)\n const clause: FieldClause = viaClause\n ? {\n type: 'field',\n field,\n op: mop,\n value: mval,\n ...(subquery ? { subquery } : {}),\n via: {\n brand: viaClause.brand,\n payload: viaClause.payload,\n evaluate: (actual: unknown, evalOp: string) => via!.evaluateClause(viaClause, actual, evalOp),\n indexValue: via!.indexProbe(viaClause, mop),\n },\n }\n : { type: 'field', field, op: mop, value: mval, ...(subquery ? { subquery } : {}) }\n return new Query<T, S, Q, M>(\n this.source as QuerySource<T>,\n { ...this.plan, clauses: [...this.plan.clauses, clause] },\n this.joinContext,\n this.reduceStrategy,\n this.predicates,\n )\n }\n\n /**\n * Logical OR group. Pass a callback that builds a sub-query.\n * Each clause inside the callback is OR-combined; the group itself\n * joins the parent plan with AND.\n */\n or(builder: (q: Query<T, S, Q, M>) => Query<T, S, Q, M>): Query<T, S, Q, M> {\n const sub = builder(\n new Query<T, S, Q, M>(this.source as QuerySource<T>, EMPTY_PLAN, this.joinContext, this.reduceStrategy, this.predicates),\n )\n const group: GroupClause = {\n type: 'group',\n op: 'or',\n clauses: sub.plan.clauses,\n }\n return new Query<T, S, Q, M>(\n this.source as QuerySource<T>,\n { ...this.plan, clauses: [...this.plan.clauses, group] },\n this.joinContext,\n this.reduceStrategy,\n this.predicates,\n )\n }\n\n /**\n * Logical AND group. Same shape as `or()` but every clause inside the group\n * must match. Useful for explicit grouping inside a larger OR.\n */\n and(builder: (q: Query<T, S, Q, M>) => Query<T, S, Q, M>): Query<T, S, Q, M> {\n const sub = builder(\n new Query<T, S, Q, M>(this.source as QuerySource<T>, EMPTY_PLAN, this.joinContext, this.reduceStrategy, this.predicates),\n )\n const group: GroupClause = {\n type: 'group',\n op: 'and',\n clauses: sub.plan.clauses,\n }\n return new Query<T, S, Q, M>(\n this.source as QuerySource<T>,\n { ...this.plan, clauses: [...this.plan.clauses, group] },\n this.joinContext,\n this.reduceStrategy,\n this.predicates,\n )\n }\n\n /** Escape hatch: add an arbitrary predicate function. Not serializable. */\n filter(fn: (record: T) => boolean): Query<T, S, Q, M> {\n const clause: FilterClause = {\n type: 'filter',\n fn: fn as (record: unknown) => boolean,\n }\n return new Query<T, S, Q, M>(\n this.source as QuerySource<T>,\n { ...this.plan, clauses: [...this.plan.clauses, clause] },\n this.joinContext,\n this.reduceStrategy,\n this.predicates,\n )\n }\n\n /**\n * Sort by a field. Subsequent calls are tie-breakers. Pass\n * `{ by: 'label' }` to sort a `dictKey`/`staticDict` field by its resolved\n * label at the query locale instead of the stored code.\n *\n * Consults the Via pipeline's posture (#629 Task 8): a field whose posture\n * is `queryable: 'none'` throws `FieldNotQueryableError` here, at the call\n * site — same gate as `where()`.\n */\n orderBy(field: QueryField<T, S>, direction: 'asc' | 'desc' = 'asc', opts?: { by?: 'value' | 'label' }): Query<T, S, Q, M> {\n if (this.source.via?.postureFor(field)?.queryable === 'none') throw new FieldNotQueryableError(field)\n const entry: OrderBy = opts?.by === 'label' ? { field, direction, by: 'label' } : { field, direction }\n return new Query<T, S, Q, M>(\n this.source as QuerySource<T>,\n { ...this.plan, orderBy: [...this.plan.orderBy, entry] },\n this.joinContext,\n this.reduceStrategy,\n this.predicates,\n )\n }\n\n /** Cap the result size. */\n limit(n: number): Query<T, S, Q, M> {\n return new Query<T, S, Q, M>(\n this.source as QuerySource<T>,\n { ...this.plan, limit: n },\n this.joinContext,\n this.reduceStrategy,\n this.predicates,\n )\n }\n\n /**\n * Resume strictly after the row an opaque keyset cursor names (#1346).\n *\n * ```ts\n * const first = people.query().orderBy('name').limit(20).page()\n * const next = people.query().orderBy('name').limit(20).after(first.nextCursor!).page()\n * ```\n *\n * Unlike `offset(n)`, the window is anchored to a `(sortKey, id)` position,\n * so a record inserted or deleted before it — including the cursor's own\n * row — cannot re-serve or skip a record.\n *\n * The cursor is OPAQUE: pass back a `nextCursor` from `.page()` verbatim\n * and do not parse it. It is validated when the query executes (not here —\n * the sort spec it is bound to may still be added to the chain), and a\n * cursor from a different collection or a different `orderBy(...)` spec is\n * REFUSED rather than mis-paged.\n *\n * Requires at least one `orderBy(...)`, an id-paired (collection-backed)\n * source, no join legs and no `offset()`; each is a loud error at execution.\n */\n after(cursor: string): Query<T, S, Q, M> {\n if (typeof cursor !== 'string' || cursor.length === 0) {\n throw new Error('Query.after(): a cursor must be a non-empty string — pass back the `nextCursor` from .page().')\n }\n return new Query<T, S, Q, M>(\n this.source as QuerySource<T>,\n { ...this.plan, after: cursor },\n this.joinContext,\n this.reduceStrategy,\n this.predicates,\n )\n }\n\n /** Skip the first N matching records (after ordering). */\n offset(n: number): Query<T, S, Q, M> {\n return new Query<T, S, Q, M>(\n this.source as QuerySource<T>,\n { ...this.plan, offset: n },\n this.joinContext,\n this.reduceStrategy,\n this.predicates,\n )\n }\n\n /**\n * Resolve a `ref()`-declared foreign key and attach the right-side\n * record under `opts.as`. — eager, single-FK, intra-\n * vault joins.\n *\n * ```ts\n * const rows = invoices.query()\n * .where('status', '==', 'open')\n * .join('clientId', { as: 'client' })\n * .toArray()\n * // → [{ id, amount, client: { id, name, ... } }, ...]\n * ```\n *\n * Preconditions:\n * - The Query must have a `joinContext` (constructed via\n * `Collection.query()`, not `new Query`).\n * - `field` must have a matching `refs: { [field]: ref('<target>') }`\n * declaration on the left collection.\n * - The target collection must be reachable via the vault\n * (either currently open or openable on demand).\n *\n * Strategy:\n * - Nested-loop against `lookupById` when the target source\n * provides it (the common path for Collection targets).\n * - Hash join otherwise, or when `{ strategy: 'hash' }` is\n * explicitly passed for test purposes.\n *\n * Ref-mode semantics on dangling refs (left record has a non-null\n * FK value pointing at a right-side id that doesn't exist):\n * - `strict` → throws `DanglingReferenceError` with the full\n * field / target / refId context.\n * - `warn` → attaches `null` and emits a one-shot warning per\n * unique dangling pair.\n * - `cascade` → attaches `null` silently. Cascade is a\n * delete-time mode; dangling refs visible at read time are\n * either mid-flight cascades or pre-existing orphans, not a\n * DSL-level error.\n *\n * A left-side record whose FK field is `null` / `undefined` is NOT\n * a dangling ref — it's \"no reference at all\", always allowed\n * regardless of mode.\n *\n * The return type widens `T` with `Record<As, R | null>`. The `R`\n * parameter is optional — supply it explicitly for type-checked\n * access to the joined fields:\n *\n * ```ts\n * invoices.query().join<'client', Client>('clientId', { as: 'client' })\n * // ^^^^^^^^^^^^^^^^^^^ alias literal + right-side type\n * ```\n *\n * Without the generic, the joined field is typed as `unknown`, which\n * still works but requires a cast to access its properties.\n *\n * Joins stay intra-vault by construction — cross-vault\n * correlation goes through `Noydb.queryAcross`, not\n * `.join()`.\n */\n /**\n * Execute the plan and return the matching records. When the plan\n * carries any join legs, they are applied after `where` / `orderBy`\n * / `limit` / `offset` narrow the left set — UNLESS a clause (#1030) or\n * the ordering (#1337) addresses a join alias, in which case the legs run\n * first and the sort/page observe the joined relation. See the `.join()`\n * doc for the ordering rationale, and `.explain()` for which one a given\n * plan gets.\n *\n * `opts.locale` resolves JOINED right-side i18n fields at the\n * `join` layer to that locale; without it, the owning collection's default\n * locale applies, and a locale-less query leaves joined i18n fields raw.\n * (Left/base i18n fields are resolved by `get`/`list`, not here.)\n *\n * **Synchronous** (#1413) — returns `T[]`, not a promise; the cache it reads is\n * already decrypted. `await` is safe and is REQUIRED on an unhydrated collection\n * (#1414); `.catch()` is not available. See the {@link Query} class doc.\n */\n toArray(opts?: { locale?: string }): T[] {\n const _h = this.source.hydration\n if (_h !== undefined && !_h.isHydrated()) return gateTerminal(_h, 'toArray', () => this.toArray(opts))\n // A cursor was applied: the window is decided by the keyset, not by\n // offset/limit slicing. Same rows `page()` would serve, same signature.\n if (this.plan.after !== undefined) return this.executeKeyset(opts).rows\n\n const { preJoin, postJoin } = splitAroundJoins(this.plan.clauses, this.plan.joins)\n // #1337 — an ORDERING that addresses an alias moves the sort/page after\n // the legs for exactly the reason #1030's predicate did: the field does\n // not exist yet. The failure was quieter than #1030's, not louder — every\n // sort key read `undefined`, so the sort was a stable no-op and the page\n // came back in insertion order looking merely unlucky.\n const orderPostJoin = orderReferencesJoinAlias(this.plan.orderBy, this.plan.joins)\n\n // #1361 — an inner leg DROPS left rows, so pagination cannot precede it.\n // The SORT still can: the ordering is on a left-side field (an ordering on\n // the alias is `orderPostJoin` above), and removing rows never reorders the\n // ones that remain. So this path keeps the pre-join sort — index-driven\n // narrowing and all — and moves only offset/limit behind the legs.\n const innerDrops = joinsDropLeftRows(this.plan.joins)\n\n if (postJoin.length === 0 && !orderPostJoin) {\n // Decode Via-covered fields (e.g. money: stored scaled-int → canonical\n // decimal) so query().toArray() matches get()/sum(), which already\n // apply the same decode. Decode the left/base records before joins\n // (right-side aliased fields belong to other collections and are out\n // of this source's Via scope).\n const pagePlan = innerDrops ? { ...this.plan, offset: 0, limit: undefined } : this.plan\n // Safe to present at the caller's locale here: `executePlanWithSource`\n // has already filtered, ordered and paged, so no predicate or comparator\n // can see a formatted value (#1416).\n const base = this.decodeVia(\n executePlanWithSource(this.source, pagePlan, this.joinContext, opts?.locale, this.aliasVia()),\n opts?.locale,\n )\n if (this.plan.joins.length === 0) return this.dressAliases(base) as T[]\n const joined = applyJoins(base, this.plan.joins, this.requireJoinContext('toArray'), opts?.locale)\n if (!innerDrops) return this.dressAliases(joined) as T[]\n const from = this.plan.offset\n return this.dressAliases(\n this.plan.limit === undefined ? joined.slice(from) : joined.slice(from, from + this.plan.limit),\n ) as T[]\n }\n\n // #1030 — at least one predicate addresses a join alias, so it cannot be\n // evaluated until the legs are attached. Narrow with the pre-join clauses\n // (still index-driven), join, then filter, and only THEN sort/paginate:\n // ordering and limit must observe the post-join predicate, not precede it.\n //\n // The left-side JoinTooLargeError ceiling is now measured against the\n // pre-join set only. That is inherent — a predicate on an alias cannot\n // narrow a set the alias does not exist in yet — and a loud ceiling error\n // beats today's silent empty result.\n const joinContext = this.requireJoinContext('toArray')\n // ⛔ #1416 — PRESENT LAST ON THIS PATH TOO. This used to present BEFORE the\n // post-join filter, which had two consequences. The one that blocks the\n // locale is that a formatted money value would reach a `where()` predicate;\n // the one that was already wrong is that money's `evaluateClause` expects\n // the RAW STORED value (see `candidateRecords`' #1415 note), and the\n // ordinary non-join path filters and sorts on raw — so this path alone\n // compared and ordered against decoded values. Presenting after the plan\n // finishes fixes both and matches `dressAliases`' stated rule.\n //\n // Callback clauses are unaffected: `fnViewDecoder` builds their decoded\n // view separately and always did.\n const narrowed = executePlanWithSource(\n this.source,\n { ...this.plan, clauses: preJoin, orderBy: [], limit: undefined, offset: 0 },\n joinContext,\n opts?.locale,\n )\n const joined = applyJoins(narrowed, this.plan.joins, joinContext, opts?.locale)\n const filtered = filterRecords(joined, postJoin, fnViewDecoder(this.source))\n const paged = applyOrderAndPage(filtered, this.plan, this.source, joinContext, opts?.locale, this.aliasVia())\n return this.dressAliases(this.decodeVia(paged, opts?.locale)) as T[]\n }\n\n /**\n * Apply each aliased side's OWN Via result decode, in place of the\n * top-level decode that cannot reach it (#1289, and the fix for #1335).\n *\n * `decodeVia` keys by bare field name, so it dresses exactly the fields\n * sitting at the top of the row. Everything a join puts under an alias —\n * a `.join()`/`.rightJoin()` right record, a `.crossJoin()` right record,\n * and BOTH sides of a `.crossJoinWith()` pair — is therefore invisible to\n * it, and was served raw: a self cross-join returned `\"10.00\"` on the left\n * and `\"1000\"` on the right of the same field (#1335).\n *\n * Runs LAST, after every filter, sort and page. That is deliberate: a\n * `where()` operand is built in raw stored space, so dressing earlier would\n * make a post-join predicate compare a decoded string against a raw one.\n * Dressing is presentation; it belongs after the plan has finished.\n *\n * Each alias is decoded by the Via pipeline of the collection the record\n * came FROM — money on the right side is the right side's declaration, not\n * this collection's. A source that declares no result decode returns the\n * record unchanged, so the whole pass is a no-op for the common query and\n * is skipped entirely when the plan has no aliases.\n */\n private dressAliases(rows: readonly unknown[]): unknown[] {\n if (rows.length === 0) return rows as unknown[]\n const ctx = this.joinContext\n if (!ctx) return rows as unknown[]\n\n const targets: { path: string; decode: (r: unknown) => unknown }[] = []\n const push = (path: string, collection: string): void => {\n const decode = ctx.resolveSource(collection)?.decodeResults\n if (decode) targets.push({ path, decode })\n }\n for (const clause of this.plan.clauses) {\n if (clause.type !== 'crossJoin') continue\n push(clause.as, clause.target)\n // The left half of a `crossJoinWith` pair is THIS collection's record,\n // moved under an alias — its decode is this source's own.\n if (clause.leftAs !== undefined) push(clause.leftAs, ctx.leftCollection)\n }\n for (const leg of this.plan.joins) {\n // A dict join attaches `{ key, ...labels }`, not a collection record —\n // there is no Via pipeline behind it to decode.\n if (leg.isDictJoin === true) continue\n push(leg.as, leg.target)\n }\n if (targets.length === 0) return rows as unknown[]\n\n return rows.map(row => {\n if (row === null || typeof row !== 'object') return row\n let out: Record<string, unknown> | undefined\n for (const { path, decode } of targets) {\n const value = (row as Record<string, unknown>)[path]\n if (value === null || value === undefined || typeof value !== 'object') continue\n const dressed = decode(value)\n if (dressed === value) continue\n out ??= { ...(row as Record<string, unknown>) }\n out[path] = dressed\n }\n return out ?? row\n })\n }\n\n /**\n * Alias → the Via pipeline of the collection whose records sit under it\n * (#1337). Every alias this plan can produce: a `.join()`/`.rightJoin()`\n * leg, a `.crossJoin()` right side, and both sides of `.crossJoinWith()`.\n *\n * ⭐ **Ordering compares in RAW STORED SPACE, never in dressed space, and\n * that is what forces this map to exist.** `dressAliases` runs LAST — after\n * every filter, sort and page — because a `where` operand is built raw. So\n * the sort sees money as its stored scaled integer, where a generic compare\n * is lexical and gets `'9882'` vs `'10004'` backwards. The left side has\n * always avoided that by asking `source.via.compareForOrder`; an aliased\n * field needs the same question asked of the RIGHT side's pipeline, keyed\n * by the field name WITHOUT the alias prefix (a pipeline covers bare field\n * names — that is the whole of #1335's shape).\n *\n * Empty when no alias resolves a pipeline, in which case the comparator\n * falls back to exactly what it did before.\n */\n private aliasVia(): ReadonlyMap<string, ViaPipeline> | undefined {\n const ctx = this.joinContext\n if (!ctx) return undefined\n const out = new Map<string, ViaPipeline>()\n const push = (alias: string, collection: string): void => {\n const via = ctx.resolveSource(collection)?.via?.()\n if (via) out.set(alias, via)\n }\n for (const clause of this.plan.clauses) {\n if (clause.type !== 'crossJoin') continue\n push(clause.as, clause.target)\n if (clause.leftAs !== undefined) push(clause.leftAs, ctx.leftCollection)\n }\n for (const leg of this.plan.joins) {\n // A dict join attaches `{ key, ...labels }` — no collection pipeline.\n if (leg.isDictJoin === true) continue\n push(leg.as, leg.target)\n }\n return out.size > 0 ? out : undefined\n }\n\n /**\n * Joins need a `JoinContext`. Unreachable in practice — `.join()` throws\n * when one is missing — but belt-and-braces for a plan built through the\n * raw `Query` constructor with joins pre-populated.\n */\n private requireJoinContext(terminal: string): JoinContext {\n if (!this.joinContext) {\n throw new Error(\n `Query.${terminal}(): plan carries ${this.plan.joins.length} join leg(s) ` +\n `but no JoinContext is attached. This usually means the Query was ` +\n `constructed via the raw Query constructor with a plan that had joins ` +\n `pre-populated. Use collection.query().join(...) instead.`,\n )\n }\n return this.joinContext\n }\n\n /**\n * Present this source's Via-covered fields on read, so `query().toArray()`\n * agrees with `get()`/`list()` about what a record contains (#1416).\n *\n * ⛔ THIS USED TO RUN `decodeResults`, WHICH IS NOT THE SAME QUESTION. That\n * hook is money's stored→canonical decode and nothing else, so a\n * `computed({ mode: 'virtual' })` field read `undefined` on a query row while\n * `get()` returned it — the same record with two shapes depending on which\n * verb produced it, and a caller summing that field over a query result got\n * `NaN` with no error. Reported at `receiptAmount get=84715.00 query=undefined`.\n *\n * The old doc comment defended the omission of money's `<field>Formatted` /\n * `<field>Number` virtuals on the grounds that \"the query layer carries no\n * locale context\", and that reasoning was right: fabricating a guessed-locale\n * string here would make it-IT via `get()` disagree with en-US here. ⚠️ But\n * the premise had gone stale — `toArray({ locale })` exists and threads its\n * locale into `executePlanWithSource`, `applyJoins` and `applyOrderAndPage`.\n * This was the one call site that never received it, which is also why joined\n * ALIASES were dressed while the base row was not.\n *\n * So this presents at `'raw'`: values — money's canonical decode and every\n * virtual computed field — while money's binding gates the locale-formatted\n * virtuals on `locale !== 'raw'`, so nothing is guessed.\n *\n * ⛔ HONOURING `toArray({ locale })` HERE IS A SEPARATE CHANGE, and the\n * obvious implementation is measurably wrong. Presenting twice — once raw for\n * the plan, once at the locale for output — silently yields the RAW result:\n *\n * presentSync(stored, raw) -> { amount: \"84715.00\" }\n * presentSync(that, 'en-US') -> { amount: \"84715.00\" } <-- no siblings\n * presentSync(stored, 'en-US') -> { amount: \"84715.00\",\n * amountFormatted: \"THB 84,715.00\", ... }\n *\n * because the second pass sees an already-decoded value and re-emits no\n * siblings. So formatting has to happen in ONE pass at the final locale —\n * and one of this method's call sites runs BEFORE the post-join filter,\n * where a formatted value would change what a `where()` predicate compares\n * against. That is the same rule `dressAliases` states: dressing is\n * presentation and belongs after the plan has finished. Deciding it needs\n * its own change; leaving `toArray({ locale })` inert for base rows is the\n * status quo, not a new hole.\n *\n * ⚠️ SYNCHRONOUS, so it folds only the bindings that declared\n * `presentIsSync` — money and computed. A collection also using i18n or\n * lookup keeps those fields undressed here, exactly as today; `presentSync`\n * reports them and `explain()` says so rather than leaving a silent hole.\n * Making this complete would mean making `toArray()` async, which is the\n * contract #1413 deliberately established.\n */\n private decodeVia(records: readonly unknown[], locale?: string): unknown[] {\n const via = this.source.via\n if (!via) return records as unknown[]\n const ctx = { locale: locale ?? 'raw', layer: 'read' as const }\n return records.map(r => via.presentSync(r as Record<string, unknown>, ctx).record)\n }\n\n /**\n * Terminal sibling of `toArray()` that also returns the cursor for the next\n * page (#1346): `{ rows, nextCursor }`, where `nextCursor` is `null` once\n * the last page has been served.\n *\n * ```ts\n * const { rows, nextCursor } = people.query().orderBy('name').limit(20).page()\n * ```\n *\n * Without a sorted index this is still a scan with a keyset filter — stable,\n * not fast. The fast path is a separate concern (#1344).\n *\n * Same requirements as `.after()`: at least one `orderBy(...)`, an id-paired\n * (collection-backed) source, no join legs, no `offset()`.\n *\n * **Synchronous** (#1413) — returns `{ rows, nextCursor }`, not a promise; the cache it reads is\n * already decrypted. `await` is safe and is REQUIRED on an unhydrated collection\n * (#1414); `.catch()` is not available. See the {@link Query} class doc.\n */\n page(opts?: { locale?: string }): { rows: T[]; nextCursor: string | null } {\n const _h = this.source.hydration\n if (_h !== undefined && !_h.isHydrated()) return gateTerminal(_h, 'page', () => this.page(opts))\n return this.executeKeyset(opts)\n }\n\n /**\n * The keyset engine behind `page()` / `after()`.\n *\n * It deliberately does NOT reuse `applyOrderAndPage`: paging by keyset needs\n * a TOTAL order (the id breaks ties that the ordinary sort leaves to input\n * order) and needs the id alongside each row to mint the cursor. Both are\n * properties of this path only, so the ordinary read path is untouched.\n */\n private executeKeyset(opts?: { locale?: string }): { rows: T[]; nextCursor: string | null } {\n const plan = this.plan\n if (plan.orderBy.length === 0) {\n throw new Error(\n 'Query.page()/after(): keyset pagination requires at least one orderBy(...) — ' +\n 'a cursor names a position in a sort order, so there must be one to name.',\n )\n }\n if (plan.offset > 0) {\n throw new Error(\n 'Query.page()/after(): offset() cannot be combined with a keyset cursor. ' +\n 'They are two different pagination strategies — drop offset() and page with after(nextCursor).',\n )\n }\n if (plan.joins.length > 0 || plan.clauses.some(c => c.type === 'crossJoin')) {\n throw new Error(\n 'Query.page()/after(): keyset pagination does not support join legs or crossJoin ' +\n '(joined rows are new objects, so the record id the cursor needs is not recoverable). ' +\n 'Page the left side, then join per page.',\n )\n }\n // #1417 — the PRESENCE check, not the call. Materializing the id-paired\n // snapshot is O(n) and allocates a fresh array plus an object per row; on\n // a memo hit nothing below needs it, and paying for it here made the fast\n // path linear in the collection again. Arrow-bound so `this` cannot drift\n // (same discipline as `candidateRecords`).\n const source = this.source\n const snapshotEntries = source.snapshotEntries === undefined\n ? undefined\n : (): readonly { id: string; record: unknown }[] => source.snapshotEntries!()\n if (snapshotEntries === undefined) {\n throw new Error(\n 'Query.page()/after(): the query source has no snapshotEntries(); keyset pagination ' +\n 'requires a collection-backed query (collection.query()).',\n )\n }\n // ⛔ #1417 — EVERY LINE BELOW USED TO RUN PER PAGE. Building `refToId`,\n // re-matching, computing an order key per row, and sorting the whole\n // collection are each O(n) or worse, so a 100-page walk of a 10k\n // collection paid ~100 full sorts: measured 4.4 ms/page against a 0.3 ms\n // first page, which is the opposite of what keyset paging is for. Nothing\n // here was seeking linearly by design — the linear seek below was merely\n // the cheapest of four O(n) passes.\n //\n // The order is a pure function of (matched set, order spec, locale), and\n // the cache tells us when the matched set can have moved, so the whole\n // block is memoized on the source's mutation counter. `after()` then\n // BISECTS a run it already holds.\n const memoKey = keysetMemoKey(this.source, plan, opts?.locale)\n const cached = memoKey === null ? undefined : readKeysetMemo(memoKey)\n let sorted: KeysetRow[]\n let keyPlan: OrderKeyPlan\n if (cached) {\n sorted = cached.sorted\n keyPlan = cached.keyPlan\n } else {\n const refToId = new Map<unknown, string>()\n for (const { id, record } of snapshotEntries()) refToId.set(record, id)\n\n // Match without ordering or paging — this path owns both.\n const matched = executePlanWithSource(\n this.source,\n { ...plan, orderBy: [], limit: undefined, offset: 0, after: undefined },\n this.joinContext,\n opts?.locale,\n )\n\n const labelMaps = buildOrderLabelMaps(plan.orderBy, this.joinContext, opts?.locale, this.source.via)\n keyPlan = buildOrderKeyPlan(plan.orderBy, this.source.via, labelMaps)\n sorted = matched\n .map(record => ({ record, id: refToId.get(record) ?? '', key: orderKeyOf(keyPlan, record) }))\n .sort((a, b) => compareOrderKeys(keyPlan, a.key, b.key) || compareIds(a.id, b.id))\n if (memoKey !== null) writeKeysetMemo(memoKey, { sorted, keyPlan })\n }\n\n const shape = keysetShape(this.source.identity, plan.orderBy)\n let start = 0\n if (plan.after !== undefined) {\n const cursor = decodeCursor(plan.after, shape)\n // Strictly after the cursor's position. The row itself may be gone —\n // that is exactly the case an offset cannot survive, and a bisect\n // survives it for the same reason a scan did: the predicate is\n // \"ordered strictly after this key\", not \"equals this row\".\n //\n // `sorted` is totally ordered by (key, id) — the sort comparator above\n // breaks every tie on the id — so the predicate is monotone and a\n // binary search finds the same index `findIndex` did, in O(log n).\n start = lowerBound(\n sorted,\n r => (compareOrderKeys(keyPlan, r.key, cursor.values) || compareIds(r.id, cursor.id)) > 0,\n )\n }\n\n const end = plan.limit === undefined ? sorted.length : start + plan.limit\n const window = sorted.slice(start, end)\n const last = window[window.length - 1]\n const nextCursor =\n last !== undefined && end < sorted.length\n ? encodeCursor({ shape, values: last.key, id: last.id })\n : null\n return { rows: this.decodeVia(window.map(r => r.record)) as T[], nextCursor }\n }\n\n /**\n * Return the first matching record, or null. Joins are applied. `opts.locale`\n * resolves joined i18n fields.\n *\n * **Synchronous** (#1413) — returns `T | null`, not a promise; the cache it reads is\n * already decrypted. `await` is safe and is REQUIRED on an unhydrated collection\n * (#1414); `.catch()` is not available. See the {@link Query} class doc.\n */\n first(opts?: { locale?: string }): T | null {\n const _h = this.source.hydration\n if (_h !== undefined && !_h.isHydrated()) return gateTerminal(_h, 'first', () => this.first(opts))\n const arr = this.limit(1).toArray(opts)\n return arr[0] ?? null\n }\n\n /**\n * Return the number of matching records (after where/filter,\n * before limit). **Joins are normally NOT applied** — count() reports the\n * left-side cardinality, because joins are projection-only\n * (they attach an aliased field; they never filter). Running joins\n * here just to discard the aliases would be wasteful, and in strict\n * mode it could throw `DanglingReferenceError` for a call whose\n * intent is purely to count.\n *\n * The exception (#1030) is a `where` clause addressing a join alias. Then\n * the legs must run, because the predicate is part of what is being\n * counted — skipping them would report the unfiltered left cardinality.\n * A strict-mode `DanglingReferenceError` becomes reachable from `count()`\n * in exactly that case, which is acceptable: the caller asked to filter on\n * the joined side, so they asked for the join.\n *\n * **Synchronous** (#1413) — returns `number`, not a promise; the cache it reads is\n * already decrypted. `await` is safe and is REQUIRED on an unhydrated collection\n * (#1414); `.catch()` is not available. See the {@link Query} class doc.\n */\n count(): number {\n const _h = this.source.hydration\n if (_h !== undefined && !_h.isHydrated()) return gateTerminal(_h, 'count', () => this.count())\n return this.matchedRecords('count').length\n }\n\n /**\n * The match set every reduce-shaped terminal reports over: `count()`,\n * `distinct()`, and `exists()`'s non-short-circuit fallbacks.\n *\n * Extracted (#1347) rather than copied a third time, because \"which records\n * does this terminal see\" is an INVARIANT across them — `distinct()`\n * returning values `count()` never counted would be a bug nobody would look\n * for. It is deliberately the `count()` pipeline: where/filter apply, joins\n * apply only when a predicate addresses one (#1030), and orderBy/limit/offset\n * do NOT — those describe a page, and a reduction is not paginated.\n */\n private matchedRecords(terminal: string, forceJoins = false): readonly unknown[] {\n if (this.plan.clauses.some(c => c.type === 'crossJoin')) {\n if (!this.joinContext) {\n throw new Error(\n `Query.${terminal}(): plan contains crossJoin clauses but no JoinContext is attached.`,\n )\n }\n return executeClausePipeline(this.source, this.plan.clauses, this.joinContext)\n }\n // Use the same index-aware candidate machinery as toArray(); skip the\n // index-driving clause from re-evaluation. The length BEFORE limit/offset\n // is what `count()` documents.\n const { preJoin, postJoin } = splitAroundJoins(this.plan.clauses, this.plan.joins)\n const { candidates, remainingClauses } = candidateRecords(this.source, preJoin)\n const narrowed =\n remainingClauses.length === 0\n ? candidates\n : filterRecords(candidates, remainingClauses, fnViewDecoder(this.source))\n // #1289 — a left leg is projection-only, so the left match set IS the\n // answer. A right/full leg is not: it adds a row per unreferenced right\n // record and (for 'right') drops the unmatched left ones. Those legs have\n // to run or every reduce-shaped terminal is simply wrong — #1289 found\n // this for count(), and it holds identically for distinct() and exists()\n // now that #1347 made them share this pipeline.\n // #1361 adds a third reshaping leg: an INNER leg drops the left rows whose\n // alias resolved to nothing, so the left match set is no longer the answer.\n const reshapes =\n this.plan.joins.some(leg => leg.direction !== undefined && leg.direction !== 'left') ||\n joinsDropLeftRows(this.plan.joins)\n // #1338 — `forceJoins` is the third reason the legs have to run: a group\n // key or a reducer addresses an alias, so the relation being reduced IS\n // the joined one. Same pipeline, same order; only the entry condition is\n // new, which is what keeps \"which records does this terminal see\" one\n // definition rather than four.\n if (postJoin.length === 0 && !reshapes && !forceJoins) return narrowed\n // #1030 — the predicate lives on the joined side, so the legs are part of\n // the count. Same pipeline as toArray(), minus ordering and pagination.\n const joined = applyJoins(narrowed, this.plan.joins, this.requireJoinContext(terminal))\n return filterRecords(joined, postJoin, fnViewDecoder(this.source))\n }\n\n /**\n * Whether ANY record matches (#1347) — `count() > 0` without paying for the\n * records after the first.\n *\n * The saving is real rather than cosmetic: `count()` evaluates every\n * remaining clause against every candidate, so a `.filter(fn)` over 10_000\n * records calls `fn` 10_000 times to answer a yes/no question. This returns\n * at the first hit, and `__tests__/query-distinct-exists.test.ts` witnesses\n * that by COUNTING the predicate's invocations — a boolean assertion cannot\n * tell a short-circuit from a full scan.\n *\n * Same match set as `count()`. Two shapes do NOT short-circuit and fall\n * back to it, because both must materialize the relation before anything\n * can be tested: a `crossJoin` expansion, and a `where` clause addressing a\n * join alias (#1030). Both still answer correctly.\n *\n * **Synchronous** (#1413) — returns `boolean`, not a promise; the cache it reads is\n * already decrypted. `await` is safe and is REQUIRED on an unhydrated collection\n * (#1414); `.catch()` is not available. See the {@link Query} class doc.\n */\n exists(): boolean {\n const _h = this.source.hydration\n if (_h !== undefined && !_h.isHydrated()) return gateTerminal(_h, 'exists', () => this.exists())\n if (this.plan.clauses.some(c => c.type === 'crossJoin')) {\n return this.matchedRecords('exists').length > 0\n }\n const { preJoin, postJoin } = splitAroundJoins(this.plan.clauses, this.plan.joins)\n // #1361 — an inner leg can empty a non-empty candidate set, so the\n // short-circuit below (which never runs the legs) would answer `true` for a\n // query whose every row is unmatched. Same reason #1030 falls back.\n if (postJoin.length > 0 || joinsDropLeftRows(this.plan.joins)) {\n return this.matchedRecords('exists').length > 0\n }\n const { candidates, remainingClauses } = candidateRecords(this.source, preJoin)\n // The index answered the whole predicate — its candidate set IS the match\n // set, so emptiness is the answer and nothing needs evaluating.\n if (remainingClauses.length === 0) return candidates.length > 0\n return anyMatches(candidates, remainingClauses, fnViewDecoder(this.source))\n }\n\n /**\n * Return the plan as a JSON-friendly object. FilterClause entries are\n * stripped (their `fn` cannot be serialized) and replaced with\n * { type: 'filter', fn: '[function]' } so devtools can still see them.\n */\n toPlan(): unknown {\n return serializePlan(this.plan)\n }\n\n}\n\n// ─── #1458 — the extension stubs ─────────────────────────────────────────\n//\n// One entry per method that ships in a group other than Find. Installed on\n// `Query.prototype` at module load and OVERWRITTEN by the group's own\n// `install()` when its subpath is imported.\n//\n// ⭐ **Deliberately not class members.** A stub declared on the class would own\n// the method's TYPE, and the whole mechanism depends on the type arriving with\n// the subpath: `interface Query extends RelateSurface` cannot merge `join`\n// into a class that already declares it. So these are installed\n// descriptor-wise, invisible to TypeScript — which is exactly right, because\n// the compile error for a missing group is the primary signal and this is the\n// runtime backstop underneath it.\n//\n// ⚠️ Do not \"improve\" this into a Proxy. A missing method must be a throw at\n// the call, not a trap on every property read of every Query in the process.\nconst EXTENSION_METHODS: readonly (readonly [string, string])[] = [\n ['subscribe', '@noy-db/hub/query/live'],\n ['live', '@noy-db/hub/query/live'],\n ['aggregate', '@noy-db/hub/query/reduce'],\n ['groupBy', '@noy-db/hub/query/reduce'],\n ['window', '@noy-db/hub/query/reduce'],\n ['distinct', '@noy-db/hub/query/reduce'],\n ['join', '@noy-db/hub/query/relate'],\n ['joinOn', '@noy-db/hub/query/relate'],\n ['rightJoin', '@noy-db/hub/query/relate'],\n ['fullOuterJoin', '@noy-db/hub/query/relate'],\n ['crossJoin', '@noy-db/hub/query/relate'],\n ['crossJoinWith', '@noy-db/hub/query/relate'],\n ['traverse', '@noy-db/hub/query/relate'],\n ['ancestorsOf', '@noy-db/hub/query/relate'],\n ['descendantsOf', '@noy-db/hub/query/relate'],\n ['explain', '@noy-db/hub/query/relate'],\n]\n\nfor (const [method, subpath] of EXTENSION_METHODS) {\n Object.defineProperty(Query.prototype, method, {\n value: function extensionMissing(): never {\n throw new QueryExtensionMissingError(method, subpath)\n },\n writable: true,\n enumerable: false,\n configurable: true,\n })\n}\n\n\n/**\n * Index-aware execution: try the indexed fast path first, fall back to a\n * full scan otherwise. Mirrors `executePlan` for the public surface but\n * takes a `QuerySource` so it can consult `getIndexes()` and `lookupById()`.\n */\nfunction executePlanWithSource(\n source: InternalSource,\n plan: QueryPlan,\n joinContext?: JoinContext,\n locale?: string,\n aliasVia?: ReadonlyMap<string, ViaPipeline>,\n): unknown[] {\n const hasCrossJoins = plan.clauses.some(c => c.type === 'crossJoin')\n\n let result: unknown[]\n if (hasCrossJoins) {\n if (!joinContext) {\n throw new Error(\n `Query.toArray(): plan contains crossJoin clauses but no JoinContext is attached. ` +\n `Use collection.query() instead of new Query() for cross-join support.`,\n )\n }\n result = executeClausePipeline(source, plan.clauses, joinContext)\n } else {\n const ordered = orderedIndexRows(source, plan) ?? compoundOrderedRows(source, plan)\n if (ordered) return ordered\n // Index-aware fast path: only the clauses NOT consumed by the index need\n // re-evaluation. For a single-clause query against an indexed field,\n // `remainingClauses` is empty and we skip per-record predicate evaluation.\n const { candidates, remainingClauses } = candidateRecords(source, plan.clauses)\n result =\n remainingClauses.length === 0\n ? [...candidates]\n : filterRecords(candidates, remainingClauses, fnViewDecoder(source))\n }\n\n return applyOrderAndPage(result, plan, source, joinContext, locale, aliasVia)\n}\n\n/**\n * The tail of every execution path: sort, then offset, then limit.\n *\n * Extracted so the post-join filtering path (#1030) applies the identical\n * ordering and pagination rules. Pagination MUST come after any post-join\n * predicate — slicing first would page a set the filter has not seen yet.\n */\nfunction applyOrderAndPage(\n rows: unknown[],\n plan: QueryPlan,\n source: InternalSource,\n joinContext?: JoinContext,\n locale?: string,\n aliasVia?: ReadonlyMap<string, ViaPipeline>,\n): unknown[] {\n let result = rows\n if (plan.orderBy.length > 0) {\n // dictKey label-sort: for any `orderBy(..., { by: 'label' })`, build a\n // sync code→label resolver at the query locale so the sort compares\n // labels. `source.via` also feeds the #650 Task 7 matrix-tier fallback\n // (fields `joinContext.resolveDictSource` doesn't bridge).\n const labelMaps = buildOrderLabelMaps(plan.orderBy, joinContext, locale, source.via)\n result = sortRecords(result, plan.orderBy, source.via, labelMaps, aliasVia)\n }\n if (plan.offset > 0) {\n result = result.slice(plan.offset)\n }\n if (plan.limit !== undefined) {\n result = result.slice(0, plan.limit)\n }\n return result\n}\n\nconst RANGE_OPERATORS: ReadonlySet<string> = new Set(['<', '<=', '>', '>=', 'between', 'startsWith'])\n\nexport function isRangeOperator(op: string): op is '<' | '<=' | '>' | '>=' | 'between' | 'startsWith' {\n return RANGE_OPERATORS.has(op)\n}\n\n/**\n * #1344 ordered fast path: answer `orderBy(field, dir).limit(n)` from a\n * sorted index instead of sorting the whole decrypted snapshot.\n *\n * Returns `null` — meaning \"fall back\" — unless EVERY guard holds, because\n * an index-served page must be byte-identical to the scan-and-sort one:\n *\n * - no where clauses (the index prefix is only the answer for the whole\n * collection; with a filter the first `n` index rows may not survive it),\n * - exactly one `orderBy`, no `{ by: 'label' }` (label sort resolves\n * through the dict registry, not the stored key),\n * - an explicit `limit` (without one there is nothing to save),\n * - a sorted index covering the field whose entry count equals the\n * snapshot size — a record with a nullish or non-orderable value is\n * absent from the index but `sortRecords` still places it (last in\n * `asc`, first in `desc`), so partial coverage must not take this path,\n * - the Via pipeline does not order the field (money/lookup supply their\n * own `compareForOrder`, which the stored-key order need not match).\n */\nfunction orderedIndexRows(source: InternalSource, plan: QueryPlan): unknown[] | null {\n const limit = plan.limit\n if (limit === undefined || plan.clauses.length > 0 || plan.orderBy.length !== 1) return null\n const [order] = plan.orderBy\n if (!order || order.by === 'label') return null\n const indexes = source.getIndexes?.()\n if (!indexes || !source.lookupById || !indexes.hasSorted(order.field)) return null\n // Arrow-bound so `this` can't drift (same discipline as `candidateRecords`).\n const lookupById = (id: string): unknown => source.lookupById?.(id)\n if (viaOrdersField(source.via, order.field)) return null\n const snapshot = source.snapshot()\n if (indexes.sortedSize(order.field) !== snapshot.length) return null\n const ids = indexes.orderedIds(order.field, order.direction)\n if (!ids) return null\n const out: unknown[] = []\n for (let i = plan.offset; i < ids.length && out.length < limit; i++) {\n const record = lookupById(ids[i]!)\n if (record !== undefined) out.push(record)\n }\n return out\n}\n\n/**\n * True when a Via binding claims the ORDERING of this field. Probed with\n * two equal strings: `compareForOrder` returns `undefined` for any field\n * no binding covers (money checks its field map first; lookup checks its\n * `sortBy` declaration), and a number for one it does.\n */\nexport function viaOrdersField(via: ViaPipeline | undefined, field: string): boolean {\n return via !== undefined && via.compareForOrder(field, '', '') !== undefined\n}\n\n/**\n * A range operand for the component just past a compound index's equality\n * prefix. `op` repeats {@link isRangeOperator}'s union rather than importing\n * `RangeOperator`, keeping this file's import list unchanged.\n */\n/**\n * The only slice of an index store the compound PICKERS read. Declared\n * structurally (#1375) so `query/explain.ts` can share these pickers rather\n * than re-implementing them — the mirror this file's `explain()` header warns\n * about is one function narrower for every picker that moves here.\n */\nexport interface CompoundTupleSource {\n compoundTuples(): ReadonlyArray<readonly string[]>\n}\n\nexport interface CompoundRange {\n readonly op: '<' | '<=' | '>' | '>=' | 'between' | 'startsWith'\n readonly value: unknown\n}\n\nexport interface CompoundPick {\n readonly fields: readonly string[]\n /** Equality operands for `fields[0..values.length-1]`, in index order. */\n readonly values: readonly unknown[]\n readonly range?: CompoundRange\n /** Indices into the plan's clause list that this pick answers. */\n readonly consumed: ReadonlySet<number>\n}\n\n/**\n * Split the top-level clauses into the `==` and range clauses a compound\n * index could answer. Via-covered clauses are excluded for the same reason\n * `candidateRecords` excludes them from the sorted path — a binding's\n * `indexProbe` yields an equality operand in STORED form, never an ordered\n * one, and this path compares raw operands. A repeated field keeps its FIRST\n * clause; the duplicate stays in `remainingClauses` and is re-evaluated.\n */\nexport function indexableClauses(clauses: readonly Clause[]): {\n eq: Map<string, { value: unknown; at: number }>\n ranges: Map<string, { op: CompoundRange['op']; value: unknown; at: number }>\n} {\n const eq = new Map<string, { value: unknown; at: number }>()\n const ranges = new Map<string, { op: CompoundRange['op']; value: unknown; at: number }>()\n for (let i = 0; i < clauses.length; i++) {\n const clause = clauses[i]!\n if (clause.type !== 'field' || clause.via !== undefined) continue\n if (clause.op === '==') {\n if (!eq.has(clause.field)) eq.set(clause.field, { value: clause.value, at: i })\n } else if (isRangeOperator(clause.op)) {\n if (!ranges.has(clause.field)) ranges.set(clause.field, { op: clause.op, value: clause.value, at: i })\n }\n }\n return { eq, ranges }\n}\n\n/**\n * Choose the declared field tuple that answers the most clauses: the longest\n * equality PREFIX of the tuple, plus a range on the component immediately\n * after it. A pick answering fewer than two clauses is declined — the\n * single-field hash or sorted index already covers that, at lower cost.\n */\nexport function pickCompound(indexes: CompoundTupleSource, clauses: readonly Clause[]): CompoundPick | null {\n const { eq, ranges } = indexableClauses(clauses)\n if (eq.size === 0) return null\n let best: CompoundPick | null = null\n for (const fields of indexes.compoundTuples()) {\n const values: unknown[] = []\n const consumed = new Set<number>()\n let depth = 0\n while (depth < fields.length) {\n const hit = eq.get(fields[depth]!)\n if (!hit) break\n values.push(hit.value)\n consumed.add(hit.at)\n depth++\n }\n if (depth === 0) continue\n let range: CompoundRange | undefined\n if (depth < fields.length) {\n const hit = ranges.get(fields[depth]!)\n if (hit) {\n range = { op: hit.op, value: hit.value }\n consumed.add(hit.at)\n }\n }\n if (consumed.size < 2) continue\n if (!best || consumed.size > best.consumed.size) {\n best = { fields, values, consumed, ...(range ? { range } : {}) }\n }\n }\n return best\n}\n\n/**\n * #1345 candidate fast path: narrow through a compound index instead of\n * scanning, for `where(a, '==', x).where(b, '==', y)` and for\n * `where(a, '==', x).where(b, '>=', d)`.\n *\n * Returns `null` — fall back — unless the index COVERS THE SNAPSHOT. A record\n * whose value for any component is nullish or has no order-defined runtime\n * type is absent from the tuple index, and the consumed clauses leave the\n * plan, so an under-covering index would silently drop matching records.\n */\nfunction compoundCandidates(\n source: InternalSource,\n indexes: CollectionIndexes,\n lookupById: (id: string) => unknown,\n clauses: readonly Clause[],\n): CandidateResult | null {\n const pick = pickCompound(indexes, clauses)\n if (!pick) return null\n if (indexes.compoundSize(pick.fields) !== source.snapshot().length) return null\n const ids = indexes.lookupCompound(pick.fields, pick.values, pick.range)\n if (!ids) return null\n // ⛔ #1425: A TUPLE MATCH IS A SUPERSET, NOT AN ANSWER — #1415's defect, one\n // dispatch over. Compound keys ARE type-tagged, so none of #1415's\n // string↔number↔boolean coercion reaches here; what still leaks is Date\n // object identity, because two `Date`s at the same instant encode to the\n // same key and the scan compares with `===`. Measured on #1415's branch:\n //\n // where('d','==',new Date(D1.getTime())).where('k','==','x')\n // index:compound → ['a'] scan → []\n //\n // So EVERY consumed clause stays in the plan and `filterRecords` re-applies\n // the very predicate the scan applies — the two answers are then equal BY\n // CONSTRUCTION, not by a type rule that has to enumerate what the tuple\n // encoder happens to collapse. Same posture as `prefixCandidates` below,\n // and for the same reason.\n //\n // ⚠️ This makes the compound arm a pure candidate NARROWER: it consumes\n // nothing. That is the point — the narrowing is where the win was, and the\n // re-filter runs over a set the executor has already materialized. Do not\n // \"optimise\" it back by dropping the clauses the tuple matched exactly;\n // exactness is a property of the operand against the STORED values, which\n // the probe cannot see.\n return { candidates: materializeIds(ids, lookupById), remainingClauses: clauses }\n}\n\n/**\n * #1345 ordered fast path: answer the headline shape\n * `where(a, '==', x).orderBy(b).limit(n)` from a `[a, b]` compound index —\n * the equality prefix is a contiguous run already sorted by `b`, so neither\n * the filter nor the sort has to touch the rest of the snapshot.\n *\n * Guards, on top of the ones {@link orderedIndexRows} carries for the\n * single-field case:\n *\n * - EVERY clause must be a via-free `==` on a distinct field, because\n * nothing re-filters the rows this returns,\n * - the tuple must be exactly those fields followed by the order field.\n * A LONGER tuple would break tie order: entries equal on the order\n * component are then ranked by the components after it, whereas\n * `sortRecords()` leaves them in insertion order,\n * - the index must cover the snapshot, same reason as above.\n */\nfunction compoundOrderedRows(source: InternalSource, plan: QueryPlan): unknown[] | null {\n const limit = plan.limit\n if (limit === undefined || plan.clauses.length === 0 || plan.orderBy.length !== 1) return null\n const [order] = plan.orderBy\n if (!order || order.by === 'label') return null\n const indexes = source.getIndexes?.()\n if (!indexes || !source.lookupById) return null\n if (viaOrdersField(source.via, order.field)) return null\n const { eq } = indexableClauses(plan.clauses)\n if (eq.size !== plan.clauses.length) return null\n const match = pickCompoundOrder(indexes, eq, order.field)\n if (!match) return null\n const snapshot = source.snapshot()\n if (indexes.compoundSize(match.fields) !== snapshot.length) return null\n const ids = indexes.compoundOrderedIds(match.fields, match.values, order.direction)\n if (!ids) return null\n // Arrow-bound so `this` can't drift (same discipline as `candidateRecords`).\n const lookupById = (id: string): unknown => source.lookupById?.(id)\n const out: unknown[] = []\n // ⛔ #1425: this path returns rows NOTHING ELSE FILTERS, so it cannot take\n // `compoundCandidates`' fix of pushing the clauses back into the plan —\n // there is no later filter here to push them into. Nor can it re-filter\n // AFTER the limit: that would drop rows from a page the scan would have\n // kept, trading a wrong-rows bug for a wrong-page-size bug.\n //\n // It re-applies the predicate INSIDE the walk instead, and counts the\n // offset in MATCHING rows rather than in index positions — which is what\n // `offset` means everywhere else. Cost is bounded by the equality-prefix\n // run the index already narrowed to, and in the overwhelming case (no\n // superset row) the loop still stops at `offset + limit`, exactly as\n // before. Declining the fast path outright was the alternative and would\n // have cost the headline `where(a,'==',x).orderBy(b).limit(n)` shape its\n // whole reason for existing.\n //\n // Safe to evaluate bare: the guards above already require every clause to\n // be a via-free `==` on a distinct field, so there is no callback clause\n // needing the decoded view `filterRecords` builds.\n let matched = 0\n for (let i = 0; i < ids.length && out.length < limit; i++) {\n const record = lookupById(ids[i]!)\n if (record === undefined) continue\n let hit = true\n for (const clause of plan.clauses) {\n if (!evaluateClause(record, clause)) {\n hit = false\n break\n }\n }\n if (!hit) continue\n if (matched++ < plan.offset) continue\n out.push(record)\n }\n return out\n}\n\n/** The declared tuple that is exactly `eq`'s fields followed by `orderField`. */\nexport function pickCompoundOrder(\n indexes: CompoundTupleSource,\n eq: ReadonlyMap<string, { value: unknown; at: number }>,\n orderField: string,\n): { fields: readonly string[]; values: readonly unknown[] } | null {\n for (const fields of indexes.compoundTuples()) {\n if (fields.length !== eq.size + 1) continue\n if (fields[fields.length - 1] !== orderField) continue\n const values: unknown[] = []\n for (let i = 0; i < fields.length - 1; i++) {\n const hit = eq.get(fields[i]!)\n if (!hit) break\n values.push(hit.value)\n }\n if (values.length === fields.length - 1) return { fields, values }\n }\n return null\n}\n\ninterface CandidateResult {\n /** The reduced candidate set, materialized to record objects. */\n readonly candidates: readonly unknown[]\n /** The clauses that the index could not satisfy and must still be evaluated. */\n readonly remainingClauses: readonly Clause[]\n}\n\n/**\n * Pick a candidate record set using the index store when possible.\n *\n * Strategy: scan the top-level clauses for the FIRST `==` or `in` clause\n * against an indexed field. If found, use the index to materialize a\n * candidate set and return the OTHER clauses as `remainingClauses`. The\n * caller skips re-evaluating the index-driving clause because the index\n * is authoritative for that field.\n *\n * This is a deliberately simple planner. A future optimizer could pick\n * the most selective index, intersect multiple indexes, or push composite\n * keys through. For the single-index fast path is good enough.\n */\n/** @internal #1458 — used by the extension mixins in `query/reduce/`. */\nexport function candidateRecords(source: InternalSource, clauses: readonly Clause[]): CandidateResult {\n const indexes = source.getIndexes?.()\n if (!indexes || !source.lookupById || clauses.length === 0) {\n return { candidates: source.snapshot(), remainingClauses: clauses }\n }\n // Bind the lookup method through an arrow so it doesn't drift from\n // its `this` context — keeps the unbound-method lint rule happy.\n const lookupById = (id: string): unknown => source.lookupById?.(id)\n\n // #1345: a compound index consuming an equality PREFIX (plus an optional\n // range on the next component) removes MORE clauses from the plan than any\n // single-clause choice below, so it is tried first.\n const compound = compoundCandidates(source, indexes, lookupById, clauses)\n if (compound) return compound\n\n // #1355: a Via binding may probe with a PREFIX COVER instead of an\n // equality operand. Tried before the single-clause loop below for the\n // same reason compound is — it is the narrowest thing the index can do\n // for that clause — but unlike every other arm it CONSUMES NOTHING.\n const prefixed = prefixCandidates(indexes, lookupById, clauses)\n if (prefixed) return prefixed\n\n for (let i = 0; i < clauses.length; i++) {\n const clause = clauses[i]!\n if (clause.type !== 'field') continue\n if (!indexes.has(clause.field) && !indexes.hasSorted(clause.field)) continue\n // A Via-covered clause (e.g. money) only carries a build-time\n // evaluator payload for per-record comparison by default — `buildClause`\n // does not rewrite `clause.value` into the index's stored representation\n // (e.g. multi-currency money operands are `{ amount, currency }`\n // objects; the index would stringify their keys to a no-match\n // sentinel). A binding MAY additionally supply `indexValue` (#625,\n // via `NoydbVia.indexProbe`) — the STORED-form operand for a direct\n // probe (fixed-mode money `==`/`in` today). When it's absent, skip the\n // index fast path for this clause; the fallback scan evaluates it via\n // `clause.via.evaluate`. MIXED-ERA DATA (money, #672 fixed, incl. the\n // #672 review's C1 finding): the index bucket this probe hits is no\n // longer keyed by the RAW stored string — EAGER-mode `CollectionIndexes`\n // canonicalizes money keys through `ViaPipeline.canonicalizeIndexKey` at\n // EVERY bucket-mutation site (`build`, `upsert`, `remove`), not just\n // build/rebuild, so a legacy non-canonical scaled value (predates the\n // field's money() declaration) lands in — and stays in — the SAME bucket\n // a canonical probe looks up, across later put()/delete() too. LAZY\n // mode's `PersistedCollectionIndex` gained the SAME guarantee (#677) —\n // its bucket-mutation sites (`ingest`/`upsert`/`remove`) canonicalize\n // through the same `ViaPipeline.canonicalizeIndexKey`, and its probe\n // path (`lazy-builder.ts`'s `resolveCandidateIds()`) canonicalizes the\n // `==`/`in` lookup value before calling `lookupEqual`/`lookupIn` — see\n // `moneyIndexProbe`'s doc comment (via-money/where.ts) for the full\n // story — lazy mode's post-filter is now Via-aware too (#684), so\n // end-to-end `lazyQuery().where()` money parity with this eager path\n // holds at every scale (`orderBy` ordering parity remains open, #695).\n if (clause.via && clause.via.indexValue === undefined) continue\n const probeValue = clause.via ? clause.via.indexValue : clause.value\n\n let ids: ReadonlySet<string> | null = null\n // ⛔ #1415: A HASH BUCKET IS A SUPERSET, NOT AN ANSWER. The bucket key is\n // `stringifyBucketKey`, so `1` and `'1'` — and `true` and `'true'`, and a\n // Date and its ISO spelling, and two distinct Date objects at the same\n // instant — share one bucket, while the scan compares with `===`. Handing\n // the bucket back AND dropping the clause from `remainingClauses` is what\n // made `where('pin','==',1100400123450)` return a row that\n // `.filter(r => r.pin === v)` and the unindexed collection both reject.\n // So the equality arms set `exact: false` and the clause STAYS in the\n // plan; `filterRecords` re-applies the very predicate the scan path\n // applies, which makes the two answers equal BY CONSTRUCTION rather than\n // by a type rule that has to enumerate the coercions.\n //\n // Why not decline the operand at the probe, the way `isProbeableBucketKey`\n // declines objects and nullish (#1402)? Because \"type-mismatched\" is not a\n // property of the OPERAND — it is a property of the operand against the\n // STORED values, which the probe cannot see without new per-bucket type\n // bookkeeping, and even that would not cover two Date objects at one\n // instant (equal keys, `===` false). Why not make the bucket key\n // type-aware? That moves stored index keys: it splits `distinct()`'s\n // buckets (`distinct-key.ts` is the ONE definition, shared with the\n // scanned `distinct()`) and invalidates persisted index sidecars — a much\n // larger blast radius than re-filtering a set the executor has already\n // materialized.\n //\n // ⛔ RANGE STAYS EXACT. `lookupRange` is served by the SORTED index, whose\n // comparisons are the scan's own (#1344, measured on this issue: `!=`,\n // `startsWith` and the range operators never disagreed). Retaining those\n // clauses would be a cost with no defect behind it.\n let exact = true\n if (clause.op === '==') {\n ids = indexes.lookupEqual(clause.field, probeValue)\n exact = false\n } else if (clause.op === 'in' && Array.isArray(probeValue)) {\n ids = indexes.lookupIn(clause.field, probeValue)\n exact = false\n } else if (clause.via === undefined && isRangeOperator(clause.op)) {\n // #1344 sorted index: `<`/`<=`/`>`/`>=`/`between`/`startsWith`.\n // `null` when no SORTED index covers the field (a hash-only field\n // keeps falling through to the scan). Via-covered clauses are\n // excluded deliberately — `indexProbe` only yields an EQUALITY\n // operand today, never an ordered one, so a money range must still\n // be evaluated per record by the binding.\n ids = indexes.lookupRange(clause.field, clause.op, clause.value)\n }\n\n if (ids !== null) {\n // Found an index-eligible clause: materialize the candidate set. The\n // clause leaves the plan only when the index answer is EXACT — see the\n // #1415 note above for why the equality arms are supersets.\n const remaining: Clause[] = []\n for (let j = 0; j < clauses.length; j++) {\n if (j !== i || !exact) remaining.push(clauses[j]!)\n }\n return {\n candidates: materializeIds(ids, lookupById),\n remainingClauses: remaining,\n }\n }\n // Not index-eligible — keep scanning in case a later clause is a\n // better candidate.\n }\n\n // No clause was index-eligible — fall back to a full scan.\n return { candidates: source.snapshot(), remainingClauses: clauses }\n}\n\n/**\n * #1355 prefix fast path: narrow through a UNION of sorted-index\n * `startsWith` slices named by a Via binding's {@link ViaPrefixProbe}.\n *\n * ⛔ EVERY CLAUSE STAYS IN `remainingClauses`, INCLUDING THIS ONE. A prefix\n * cover is a SUPERSET by contract (`kernel/via/index.ts`), so the binding's\n * `evaluateClause` is still the answer — dropping the clause here would\n * return the cover's corners as matches. That also means this path needs no\n * snapshot-coverage guard of its own: it removes nothing from the plan, so\n * an under-covering index cannot make it return a record the predicate has\n * not seen. What it DOES need is the other half of the same soundness\n * argument, and it is the binding's to hold — a record absent from the\n * index must be one `evaluateClause` would reject anyway. Geo's is: the\n * index key is the geohash derived from `lat`/`lng`, so a record with no\n * key has no usable point, and a clause over no point never matches.\n *\n * Returns `null` — fall back — when no clause carries a prefix probe, or\n * when the field has no sorted index to slice.\n */\nfunction prefixCandidates(\n indexes: CollectionIndexes,\n lookupById: (id: string) => unknown,\n clauses: readonly Clause[],\n): CandidateResult | null {\n for (const clause of clauses) {\n if (clause.type !== 'field' || clause.via === undefined) continue\n const probe = clause.via.indexValue\n if (!isViaPrefixProbe(probe)) continue\n if (!indexes.hasSorted(clause.field)) continue\n const ids = new Set<string>()\n for (const prefix of probe.prefixes) {\n const hit = indexes.lookupRange(clause.field, 'startsWith', prefix)\n if (hit === null) return null\n for (const id of hit) ids.add(id)\n }\n return { candidates: materializeIds(ids, lookupById), remainingClauses: clauses }\n }\n return null\n}\n\nfunction materializeIds(\n ids: ReadonlySet<string>,\n lookupById: (id: string) => unknown,\n): unknown[] {\n const out: unknown[] = []\n for (const id of ids) {\n const record = lookupById(id)\n if (record !== undefined) out.push(record)\n }\n return out\n}\n\n/**\n * Execute a plan against a snapshot of records.\n * Pure function — same input, same output, no side effects.\n *\n * Records are typed as `unknown` because plans are non-parametric; callers\n * cast the return type at the API surface (see `Query.toArray()`).\n */\nexport function executePlan(records: readonly unknown[], plan: QueryPlan): unknown[] {\n if (plan.clauses.some(c => c.type === 'crossJoin')) {\n throw new Error(\n `executePlan(): does not support crossJoin clauses. ` +\n `executePlan is a stateless pure function — it cannot resolve cross-join right-side ` +\n `collections. Use Query.toArray() (via collection.query()) instead.`,\n )\n }\n let result = filterRecords(records, plan.clauses)\n if (plan.orderBy.length > 0) {\n result = sortRecords(result, plan.orderBy)\n }\n if (plan.offset > 0) {\n result = result.slice(plan.offset)\n }\n if (plan.limit !== undefined) {\n result = result.slice(0, plan.limit)\n }\n return result\n}\n\n/**\n * Build the per-record DECODED view factory for user-callback clauses\n * (`filter` / `wherePredicate`) — those callbacks must see the canonical\n * shape (e.g. money's decimal string), never a Via-transformed stored\n * form. Field clauses are NOT affected: their operands were pre-built\n * into raw stored space at build time. Returns undefined when the\n * source's Via pipeline declares no result decode.\n */\n/** @internal #1458 — used by `query/internal/maintenance.ts`. */\nexport function fnViewDecoder(source: InternalSource): ((r: unknown) => unknown) | undefined {\n const via = source.via\n if (!via || !via.hasResultDecode) return undefined\n return r => via.decodeResults(r)\n}\n\n/** A clause compiled to a per-row test. `fnView` is the decoded record, when one was built. */\ntype CompiledClause = (record: unknown, fnView: unknown) => boolean\n\n/**\n * #1437 — compile the two clause shapes that dominate the indexed read path,\n * once per query instead of interpreting them once per row.\n *\n * ⛔ THIS IS PAYING BACK A COST #1415 INTRODUCED ON PURPOSE. Before #1415 an\n * `==` served from the hash index left the plan entirely; now it stays and\n * `filterRecords` re-checks every candidate, which is what makes the index and\n * the scan agree by construction. Correct, and it halved the index's advantage:\n * measured 4.94x over a linear scan at `e43c1c7a~1`, 2.34x on main — against a\n * DoD guard asserting `> 2`, so the regression landed green and first surfaced\n * as an unrelated PR failing three retries.\n *\n * The re-check itself is not the expense; reaching it is. Per candidate row the\n * generic path is `evaluateClause`'s switch, `evaluateFieldClause`, `readPath`\n * (which tests the field for a `.` on every call), then `evaluateOperator`'s\n * switch — five calls and two switches to perform one `===`.\n *\n * ⚠️ The specialisations must be OBSERVATIONALLY IDENTICAL to the generic path,\n * including its edge cases, or this reintroduces the #1402 class from the other\n * side: a nullish record reads as `undefined` rather than throwing, exactly as\n * `readPath` does, and `in` keeps `Array.isArray` gating and SameValueZero\n * membership (a `Set` matches `includes` on `NaN` and on object identity\n * alike). Anything else — a via-covered clause, a dotted path, any other\n * operator — falls through to the interpreter unchanged.\n */\nfunction compileClause(clause: Clause): CompiledClause {\n if (clause.type === 'field' && clause.via === undefined && !clause.field.includes('.')) {\n const field = clause.field\n const value = clause.value\n if (clause.op === '==') {\n return (r) => (r === null || r === undefined ? undefined : (r as Record<string, unknown>)[field]) === value\n }\n if (clause.op === 'in') {\n // A non-array operand matches nothing under `in`, same as `includes`.\n const set = Array.isArray(value) ? new Set(value as readonly unknown[]) : null\n if (set !== null) {\n return (r) => set.has(r === null || r === undefined ? undefined : (r as Record<string, unknown>)[field])\n }\n return () => false\n }\n }\n return (r, fnView) => evaluateClause(r, clause, fnView)\n}\n\n/** @internal #1458 — used by `query/internal/maintenance.ts`. */\nexport function filterRecords(\n records: readonly unknown[],\n clauses: readonly Clause[],\n decodeForFns?: (r: unknown) => unknown,\n): unknown[] {\n if (clauses.length === 0) return [...records]\n // Decode once per record, and only when a callback clause will consume it.\n const needsFnView = decodeForFns !== undefined && hasFnClause(clauses)\n // Compile once per QUERY, not once per row (#1437).\n const compiled = clauses.map(compileClause)\n const out: unknown[] = []\n for (const r of records) {\n const fnView = needsFnView ? decodeForFns(r) : undefined\n let matches = true\n for (const test of compiled) {\n if (!test(r, fnView)) {\n matches = false\n break\n }\n }\n if (matches) out.push(r)\n }\n return out\n}\n\n/**\n * `filterRecords(...).length > 0`, without building the array or looking past\n * the first match — the engine behind `Query.exists()` (#1347).\n *\n * Kept as a separate loop rather than a `limit`-aware `filterRecords`: the\n * hot read path should not grow a branch it never takes, and the two loops\n * are three lines each.\n */\nfunction anyMatches(\n records: readonly unknown[],\n clauses: readonly Clause[],\n decodeForFns?: (r: unknown) => unknown,\n): boolean {\n if (clauses.length === 0) return records.length > 0\n const needsFnView = decodeForFns !== undefined && hasFnClause(clauses)\n for (const r of records) {\n const fnView = needsFnView ? decodeForFns(r) : undefined\n let matches = true\n for (const clause of clauses) {\n if (!evaluateClause(r, clause, fnView)) {\n matches = false\n break\n }\n }\n if (matches) return true\n }\n return false\n}\n\n/**\n * Walk the clause list in declaration order, batching filter clauses and\n * expanding on crossJoin clauses. Falls back to `candidateRecords + filterRecords`\n * (index fast-path) when no crossJoin clauses are present.\n *\n * Precondition: `joinContext` must be non-null when any `CrossJoinClause` is in `clauses`.\n */\n/** @internal #1458 — used by the extension mixins in `query/reduce/`. */\nexport function executeClausePipeline(\n source: InternalSource,\n clauses: readonly Clause[],\n joinContext: JoinContext,\n): unknown[] {\n let rel: unknown[] = [...source.snapshot()]\n let filterBatch: Clause[] = []\n const decodeForFns = fnViewDecoder(source)\n\n for (const clause of clauses) {\n if (clause.type === 'crossJoin') {\n if (filterBatch.length > 0) {\n rel = filterRecords(rel, filterBatch, decodeForFns)\n filterBatch = []\n }\n const rightSource = joinContext.resolveSource(clause.target)\n if (!rightSource) {\n throw new CrossJoinSourceUnknownError(clause.target, joinContext.leftCollection)\n }\n rel = applyCrossJoin(rel, clause, rightSource)\n } else {\n filterBatch.push(clause)\n }\n }\n\n if (filterBatch.length > 0) {\n rel = filterRecords(rel, filterBatch, decodeForFns)\n }\n\n return rel\n}\n\n/**\n * One `orderBy` entry, resolved: how to read its sort value off a record and\n * how to compare two of those values.\n *\n * Split out of `sortRecords` so the keyset path (`page()`/`after()`) can\n * compare a row against a cursor's STORED values with exactly the ordering\n * the sort used — the alternative was a second comparator that would drift.\n */\ninterface OrderKeyPlan {\n readonly entries: readonly {\n readonly field: string\n readonly direction: 'asc' | 'desc'\n readonly labelResolver: ((code: string) => string | undefined) | undefined\n /**\n * The pipeline to ask for this entry's exact ordering, and the name to\n * ask it about (#1337). For a left-side field that is the source's own\n * pipeline and the field verbatim; for `client.credit` it is the RIGHT\n * collection's pipeline and `credit`, because a pipeline covers bare\n * field names. `undefined` → the generic comparator, as before.\n */\n readonly via: ViaPipeline | undefined\n readonly viaField: string\n }[]\n}\n\n/**\n * One row of a keyset page order: the record, its id, and its precomputed\n * order key. Held by the #1417 memo so a page walk sorts once, not per page.\n */\ninterface KeysetRow {\n readonly record: unknown\n readonly id: string\n readonly key: readonly unknown[]\n}\n\ninterface KeysetMemoEntry {\n readonly sorted: KeysetRow[]\n readonly keyPlan: OrderKeyPlan\n}\n\n/**\n * #1417 — the keyset page order, remembered between `after()` calls.\n *\n * Keyed by source identity + the source's mutation counter + a fingerprint of\n * everything the order depends on. A cache MISS is always safe (it just\n * re-sorts); a stale HIT would serve rows from before a write, so the counter\n * is maintained by the cache container itself rather than at its eleven write\n * sites — see `kernel/generation-map.ts`.\n *\n * ⚠️ Bounded to a handful of entries, evicted oldest-first. It holds record\n * REFERENCES, which the collection cache holds anyway, so a live entry costs\n * an array; an unbounded map keyed on a string would instead pin one array per\n * collection ever paged, for the life of the process.\n */\nconst KEYSET_MEMO_LIMIT = 8\nconst keysetMemo = new Map<string, KeysetMemoEntry>()\n\nfunction readKeysetMemo(key: string): KeysetMemoEntry | undefined {\n const hit = keysetMemo.get(key)\n if (hit) {\n // Refresh recency: re-inserting moves it to the end of the iteration order.\n keysetMemo.delete(key)\n keysetMemo.set(key, hit)\n }\n return hit\n}\n\nfunction writeKeysetMemo(key: string, entry: KeysetMemoEntry): void {\n keysetMemo.set(key, entry)\n while (keysetMemo.size > KEYSET_MEMO_LIMIT) {\n const oldest = keysetMemo.keys().next()\n if (oldest.done === true) break\n keysetMemo.delete(oldest.value)\n }\n}\n\n/**\n * A key that is EQUAL only when the sorted order provably is, and `null` when\n * that cannot be decided cheaply.\n *\n * ⛔ Returning `null` is the safe answer and the default for anything not\n * explicitly understood. A memo that guesses is a stale-read bug; a memo that\n * declines is merely the old cost. So: no source identity or no mutation\n * counter, a callback/predicate/group clause (whose identity lives in a\n * closure this cannot see), or an operand that is not a primitive, Date, or\n * array of those — no key, no memo.\n *\n * `clause.via` is deliberately absent from the fingerprint: it is derived by\n * the source's own pipeline from (field, op, value), all three of which ARE in\n * the key, so including it would add closure identity without adding\n * discrimination.\n */\nfunction keysetMemoKey(\n source: InternalSource,\n plan: QueryPlan,\n locale: string | undefined,\n): string | null {\n const identity = source.identity\n const version = source.snapshotVersion?.()\n if (identity === undefined || version === undefined) return null\n\n const parts: string[] = [identity, String(version), locale ?? '']\n for (const clause of plan.clauses) {\n if (clause.type !== 'field') return null\n const value = fingerprintOperand(clause.value)\n if (value === null) return null\n parts.push(`w:${clause.field}:${clause.op}:${value}`)\n }\n for (const o of plan.orderBy) parts.push(`o:${o.field}:${o.direction}:${o.by ?? 'value'}`)\n return parts.join('\\u0000')\n}\n\n/** A stable spelling of an operand, or `null` when there is no safe one. */\nfunction fingerprintOperand(value: unknown): string | null {\n if (value === null) return 'null'\n if (value === undefined) return 'undefined'\n if (value instanceof Date) return `D${value.getTime()}`\n // A number's spelling is TAGGED so it cannot collapse into the string of the\n // same digits — that collapse is exactly what #1415 was about, and a memo\n // key that reintroduced it would serve `pin == 1` the page for `pin == '1'`.\n if (typeof value === 'string') return `s${value}`\n if (typeof value === 'number') return `n${value}`\n if (typeof value === 'bigint') return `g${value}`\n if (typeof value === 'boolean') return `b${value}`\n if (Array.isArray(value)) {\n const each = value.map(fingerprintOperand)\n if (each.some(e => e === null)) return null\n return `[${each.join(',')}]`\n }\n return null\n}\n\n/**\n * First index where `pred` becomes true, or `arr.length` if it never does.\n *\n * Requires `pred` to be MONOTONE over `arr` — false for a prefix, then true\n * for the rest. `executeKeyset`'s predicate is \"ordered strictly after the\n * cursor\" over an array totally ordered by (key, id), which is exactly that.\n */\nfunction lowerBound<T>(arr: readonly T[], pred: (item: T) => boolean): number {\n let lo = 0\n let hi = arr.length\n while (lo < hi) {\n const mid = (lo + hi) >>> 1\n if (pred(arr[mid]!)) hi = mid\n else lo = mid + 1\n }\n return lo\n}\n\n/** @internal #1458 — used by `query/internal/maintenance.ts`. */\nexport function buildOrderKeyPlan(\n orderBy: readonly OrderBy[],\n via?: ViaPipeline,\n labelMaps?: Map<string, (code: string) => string | undefined>,\n aliasVia?: ReadonlyMap<string, ViaPipeline>,\n): OrderKeyPlan {\n return {\n entries: orderBy.map(({ field, direction, by }) => {\n const dot = field.indexOf('.')\n const aliased = dot > 0 ? aliasVia?.get(field.slice(0, dot)) : undefined\n return {\n field,\n direction,\n labelResolver: by === 'label' ? labelMaps?.get(field) : undefined,\n via: aliased ?? via,\n viaField: aliased ? field.slice(dot + 1) : field,\n }\n }),\n }\n}\n\n/** The sort-key tuple of one record, in `orderBy` order. */\n/** @internal #1458 — used by `query/internal/maintenance.ts`. */\nexport function orderKeyOf(plan: OrderKeyPlan, record: unknown): unknown[] {\n return plan.entries.map(({ field, labelResolver }) => {\n const v = readField(record, field)\n // dictKey/lookup label-sort: compare resolved labels (fallback to the\n // code when unresolved), so e.g. honorific codes sort by their locale label.\n if (labelResolver) return (typeof v === 'string' ? labelResolver(v) : undefined) ?? v\n return v\n })\n}\n\n/** @internal #1458 — used by `query/internal/maintenance.ts`. */\nexport function compareOrderKeys(plan: OrderKeyPlan, a: readonly unknown[], b: readonly unknown[]): number {\n for (let i = 0; i < plan.entries.length; i++) {\n const { direction, labelResolver, via, viaField } = plan.entries[i]!\n const av = a[i]\n const bv = b[i]\n // A Via-covered field (e.g. money) may store a representation the\n // generic comparator would order wrong (money's scaled-integer\n // strings sort lexically, not numerically: '9882' > '10004'). Ask\n // the pipeline for an exact ordering first; fall back to the\n // generic comparator when no binding covers the field. Label-resolved\n // values are already plain strings, so they skip the pipeline.\n const viaCmp = labelResolver ? undefined : via?.compareForOrder(viaField, av, bv)\n const cmp = viaCmp !== undefined ? viaCmp : compareValues(av, bv)\n if (cmp !== 0) return direction === 'asc' ? cmp : -cmp\n }\n return 0\n}\n\n/** Ids are opaque strings; lexical order is enough to make the keyset total. */\nfunction compareIds(a: string, b: string): number {\n return a < b ? -1 : a > b ? 1 : 0\n}\n\n/**\n * Exported (#1342) for the cross-collection union read path: a union's sort\n * runs AFTER the legs are concatenated, and it has to be the same comparator\n * a single collection's `orderBy` uses or two queries over the same rows\n * would order them differently.\n */\nexport function sortRecords(\n records: unknown[],\n orderBy: readonly OrderBy[],\n via?: ViaPipeline,\n labelMaps?: Map<string, (code: string) => string | undefined>,\n aliasVia?: ReadonlyMap<string, ViaPipeline>,\n): unknown[] {\n const plan = buildOrderKeyPlan(orderBy, via, labelMaps, aliasVia)\n // Stable sort: Array.prototype.sort is required to be stable since ES2019.\n return [...records].sort((a, b) =>\n compareOrderKeys(plan, orderKeyOf(plan, a), orderKeyOf(plan, b)),\n )\n}\n\n/**\n * dictKey/lookup label-sort: for each `orderBy(..., { by: 'label' })`\n * field, build a sync per-key label RESOLVER at the query `locale` (falling\n * back to a `staticDict` `displayLocale`). Two sources, tried in order:\n *\n * 1. `joinContext.resolveDictSource(field)` — the pre-existing dict-registry\n * bridge (unchanged from before #650 Task 7): covers dictKey/staticDict\n * AND their native `dict()`/`lookup(static)`/`lookup(reserved)` aliases\n * (`registry.ts`'s `collectLookupDictCompat` bridges those tiers into the\n * same vault registries this reads). Builds an EAGER `code -> label` map\n * from the source's full snapshot, same as always.\n * 2. `via.resolveOrderLabel(field, key, locale)` (#650 Task 7) — the\n * fallback for lookup fields the bridge above doesn't cover (matrix/\n * collection tier — no vault registry backs it). Per-key, LAZY (no full\n * snapshot enumeration API at this layer), memoized per field so a\n * repeated key within one sort doesn't re-resolve.\n *\n * Fields with neither source available are skipped — the sort then falls\n * back to the raw stored code for them.\n */\nfunction buildOrderLabelMaps(\n orderBy: readonly OrderBy[],\n joinContext: JoinContext | undefined,\n locale: string | undefined,\n via: ViaPipeline | undefined,\n): Map<string, (code: string) => string | undefined> | undefined {\n let maps: Map<string, (code: string) => string | undefined> | undefined\n for (const { field, by } of orderBy) {\n if (by !== 'label') continue\n const dictSource = joinContext?.resolveDictSource?.(field)\n if (dictSource) {\n const loc = locale ?? dictSource.displayLocale\n if (loc === undefined) continue\n const codeToLabel = new Map<string, string>()\n for (const entry of dictSource.snapshot()) {\n const k = (entry as Record<string, unknown>)['key']\n const labels = (entry as Record<string, unknown>)['labels'] as Record<string, string> | undefined\n const label = labels?.[loc]\n if (typeof k === 'string' && typeof label === 'string') codeToLabel.set(k, label)\n }\n ;(maps ??= new Map()).set(field, (code: string) => codeToLabel.get(code))\n continue\n }\n if (via) {\n const cache = new Map<string, string | undefined>()\n ;(maps ??= new Map()).set(field, (code: string) => {\n if (!cache.has(code)) cache.set(code, via.resolveOrderLabel(field, code, locale))\n return cache.get(code)\n })\n }\n }\n return maps\n}\n\nfunction readField(record: unknown, field: string): unknown {\n if (record === null || record === undefined) return undefined\n if (!field.includes('.')) {\n return (record as Record<string, unknown>)[field]\n }\n const segments = field.split('.')\n let cursor: unknown = record\n for (const segment of segments) {\n if (cursor === null || cursor === undefined) return undefined\n cursor = (cursor as Record<string, unknown>)[segment]\n }\n return cursor\n}\n\nfunction compareValues(a: unknown, b: unknown): number {\n // Nullish goes last in asc order.\n if (a === undefined || a === null) return b === undefined || b === null ? 0 : 1\n if (b === undefined || b === null) return -1\n if (typeof a === 'number' && typeof b === 'number') return a - b\n if (typeof a === 'string' && typeof b === 'string') return a < b ? -1 : a > b ? 1 : 0\n if (a instanceof Date && b instanceof Date) return a.getTime() - b.getTime()\n // Mixed/unsupported types: treat as equal so the sort stays stable.\n // (Deliberate choice — we don't try to coerce arbitrary objects to strings.)\n return 0\n}\n\nfunction serializePlan(plan: QueryPlan): unknown {\n return {\n clauses: plan.clauses.map(serializeClause),\n orderBy: plan.orderBy,\n limit: plan.limit,\n offset: plan.offset,\n after: plan.after,\n joins: plan.joins,\n }\n}\n\nfunction serializeClause(clause: Clause): unknown {\n if (clause.type === 'filter') {\n return { type: 'filter', fn: '[function]' }\n }\n if (clause.type === 'wherePredicate') {\n // Strip the live `fn` reference (non-serializable) but keep the\n // identity-carrying fields so distinct predicates still serialize\n // distinctly. `predicateHash` + `ctxHash` are the hash identity;\n // `name` is the named predicate reference. This matters because\n // A previous fall-through (return clause) exposed the live fn and produced\n // identical serializations for distinct predicates with different ctx values.\n return {\n type: 'wherePredicate',\n name: clause.name,\n ctx: clause.ctx,\n predicateHash: clause.predicateHash,\n ctxHash: clause.ctxHash,\n fn: '[function]',\n }\n }\n if (clause.type === 'group') {\n return {\n type: 'group',\n op: clause.op,\n clauses: clause.clauses.map(serializeClause),\n }\n }\n if (clause.type === 'crossJoin') {\n return {\n type: 'crossJoin',\n target: clause.target,\n as: clause.as,\n // Identity, not decoration: `leftAs` changes the SHAPE of every row\n // (#1289), so two plans differing only in it are different queries.\n // Omitted when unset so a `.crossJoin()` plan serializes exactly as it\n // did before #1289 and no stored queryHash moves.\n ...(clause.leftAs !== undefined && { leftAs: clause.leftAs }),\n on: clause.on ? '[function]' : undefined,\n onPredicateName: clause.onPredicateName,\n maxRows: clause.maxRows,\n // Part of the identity, not decoration: `outer` changes which rows come\n // back, so omitting it here would let an inner-mode plan be reused for an\n // outer-mode query under the same hash (#1130).\n outer: clause.outer,\n }\n }\n return clause\n}\n\n/**\n * Compute a stable hash of a `ctx` value supplied to\n * `.wherePredicate(name, ctx)`. Canonical-JSON: keys sorted at each\n * level so `{a, b}` and `{b, a}` hash to the same value. Undefined ctx\n * hashes to the empty string. The hash is sync because it just runs\n * a cheap djb2-style fold — used at builder time, not security-sensitive.\n *\n * @internal\n */\nfunction canonicalCtxHash(ctx: unknown): string {\n if (ctx === undefined) return \"\"\n const canonical = JSON.stringify(ctx, (_key, value) => {\n if (value && typeof value === \"object\" && !Array.isArray(value)) {\n const sorted: Record<string, unknown> = {}\n for (const k of Object.keys(value as Record<string, unknown>).sort()) {\n sorted[k] = (value as Record<string, unknown>)[k]\n }\n return sorted\n }\n return value\n })\n // djb2 fold over the canonical string; converted to hex.\n let h = 5381\n for (let i = 0; i < canonical.length; i++) {\n h = ((h << 5) + h) ^ canonical.charCodeAt(i)\n }\n return (h >>> 0).toString(16).padStart(8, \"0\")\n}\n\n/**\n * Build a dict-label resolver for `Query.groupBy(field)` when the\n * grouping field is a `dictKey`. Extracted from the inline closure\n * inside `groupBy` so the multi-key path (which has no meaningful\n * `<field>Label` shape) can skip it cleanly. Pure refactor — no\n * behaviour change for the single-field path.\n *\n * Returns `undefined` when:\n * - the join context lacks a `resolveDictSource` hook, or\n * - no dictionary source is registered for `field`.\n *\n * @internal\n */\n/** @internal #1458 — used by the extension mixins in `query/reduce/`. */\nexport function buildDictLabelResolver(\n joinCtx: JoinContext | undefined,\n field: string,\n):\n | ((key: string, locale: string, fallback?: string | readonly string[]) => Promise<string | undefined>)\n | undefined {\n if (!joinCtx?.resolveDictSource) return undefined\n const dictSource = joinCtx.resolveDictSource(field)\n if (!dictSource) return undefined\n const snapshot = dictSource.snapshot()\n // A staticDict-backed source carries a `displayLocale`; use it as the\n // locale default when the query is locale-less, so `{ by: 'label' }` still\n // resolves under a locale-less read. Plain _dict_* sources omit it.\n const displayLocale = dictSource.displayLocale\n const dictMap = new Map<string, Record<string, string>>()\n for (const entry of snapshot) {\n const k = (entry as Record<string, unknown>)['key']\n const labels = (entry as Record<string, unknown>)['labels']\n if (typeof k === 'string' && labels && typeof labels === 'object') {\n dictMap.set(k, labels as Record<string, string>)\n }\n }\n return async (\n key: string,\n locale: string,\n fallback?: string | readonly string[],\n ): Promise<string | undefined> => {\n const effLocale = locale || displayLocale\n if (!effLocale) return undefined\n const labels = dictMap.get(key)\n if (!labels) return undefined\n if (labels[effLocale] !== undefined) return labels[effLocale]\n const chain = Array.isArray(fallback)\n ? (fallback as readonly string[])\n : fallback\n ? [fallback as string]\n : []\n for (const fb of chain) {\n if (fb === 'any') {\n const any = Object.values(labels)[0]\n if (any !== undefined) return any\n } else if (labels[fb] !== undefined) {\n return labels[fb]\n }\n }\n return undefined\n }\n}\n"],"mappings":"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","names":["joined"]}
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import {
|
|
2
2
|
buildRecordAad,
|
|
3
3
|
openEnvelopeJson
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-KJFW62P4.js";
|
|
5
5
|
import {
|
|
6
6
|
buildRecordEnvelope
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-SEE332EV.js";
|
|
8
8
|
import {
|
|
9
9
|
encrypt
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-UYB234ZR.js";
|
|
11
11
|
import {
|
|
12
12
|
ConflictError,
|
|
13
13
|
USER_ENVELOPE_COLLECTION,
|
|
14
14
|
USER_ENVELOPE_MAX_BYTES,
|
|
15
15
|
UserEnvelopeOversizedError
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-244VXYPG.js";
|
|
17
17
|
|
|
18
18
|
// src/with-party/directory/storage.ts
|
|
19
19
|
var META_COLLECTION = "_meta";
|
|
@@ -142,4 +142,4 @@ export {
|
|
|
142
142
|
deleteUserEnvelope,
|
|
143
143
|
listUserEnvelopeIds
|
|
144
144
|
};
|
|
145
|
-
//# sourceMappingURL=chunk-
|
|
145
|
+
//# sourceMappingURL=chunk-7VCXZDA4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/with-party/directory/storage.ts","../src/with-party/directory/visibility.ts","../src/with-party/directory/user-envelope/storage.ts"],"sourcesContent":["/**\n * Persistence helpers for the vault-level user-directory toggle\n * (`_meta/directory`). Mirrors the bypass-AES pattern used by\n * `_meta/policy` — the directory document is plain JSON, the\n * envelope's `_iv` field is left empty.\n *\n * @see https://github.com/noy-db/docs/blob/main/content/docs/services/user-envelope.md → Directory visibility\n * @see https://github.com/noy-db/docs/blob/main/content/docs/services/plaintext-bypass.md — every `_iv: ''` write site\n *\n * @module\n */\nimport { buildRecordEnvelope } from '../../kernel/enclave/index.js'\nimport type { NoydbStore } from '../../kernel/types.js'\nimport type { DirectoryConfig } from './types.js'\n\n/** Reserved collection name for vault-level metadata documents. */\nexport const META_COLLECTION = '_meta'\n/** Reserved id for the vault-level directory document. */\nexport const DIRECTORY_RECORD_ID = 'directory'\n\n/**\n * Read the directory toggle from `_meta/directory`. Returns `undefined`\n * when no document has been persisted — callers treat that as the\n * default-on case (`{ enabled: true }`).\n *\n * Tolerates corrupted documents the same way `_meta/policy` does: a\n * JSON parse failure surfaces as `undefined`, not a thrown error, so a\n * bad write never permanently breaks team enumeration.\n */\nexport async function readDirectoryConfig(\n store: NoydbStore,\n vault: string,\n): Promise<DirectoryConfig | undefined> {\n const envelope = await store.get(vault, META_COLLECTION, DIRECTORY_RECORD_ID)\n if (!envelope) return undefined\n try {\n const parsed = JSON.parse(envelope._data) as unknown\n if (!isDirectoryConfig(parsed)) return undefined\n return parsed\n } catch {\n return undefined\n }\n}\n\n/**\n * Persist the directory toggle at `_meta/directory`. Idempotent — call\n * on every `db.setDirectoryEnabled()` invocation. Owner-only at the\n * caller site; this primitive does not check roles.\n */\nexport async function persistDirectoryConfig(\n store: NoydbStore,\n vault: string,\n config: DirectoryConfig,\n): Promise<void> {\n const envelope = buildRecordEnvelope(\n { collection: META_COLLECTION, id: DIRECTORY_RECORD_ID, version: 1 },\n { iv: '', data: JSON.stringify({ enabled: config.enabled }) },\n )\n await store.put(vault, META_COLLECTION, DIRECTORY_RECORD_ID, envelope)\n}\n\nfunction isDirectoryConfig(x: unknown): x is DirectoryConfig {\n if (x === null || typeof x !== 'object') return false\n if (!('enabled' in x)) return false\n return typeof (x as { enabled: unknown }).enabled === 'boolean'\n}\n","/**\n * Persistence helpers for the per-user visibility flag\n * (`_meta/visibility/<keyringId>`). Mirrors the bypass-AES pattern used\n * by `_meta/policy` — the visibility document is plain JSON, the\n * envelope's `_iv` field is left empty.\n *\n * Stored alongside the keyring file rather than inside the encrypted\n * user envelope (`_users/<keyringId>`) because:\n *\n * - `UserEnvelope<T>.data` is opaque-to-hub by contract — hub does not\n * introspect or reserve any keys inside it. Adding `hidden` there\n * would violate that contract.\n * - `listUsersWithEnvelopes` filters by the flag, and the filter must\n * work even when decryption fails (legacy keyrings predating the\n * envelope feature, or a corrupted envelope).\n *\n * @see https://github.com/noy-db/docs/blob/main/content/docs/services/user-envelope.md → Directory visibility\n * @see https://github.com/noy-db/docs/blob/main/content/docs/services/plaintext-bypass.md — every `_iv: ''` write site\n *\n * @module\n */\nimport { buildRecordEnvelope } from '../../kernel/enclave/index.js'\nimport type { NoydbStore } from '../../kernel/types.js'\nimport type { UserVisibility } from './types.js'\nimport { META_COLLECTION } from './storage.js'\n\n/** Prefix for per-user visibility records inside `_meta`. */\nexport const VISIBILITY_RECORD_PREFIX = 'visibility/'\n\n/** Compose the `_meta` record id for a keyring's visibility doc. */\nexport function visibilityRecordId(keyringId: string): string {\n return VISIBILITY_RECORD_PREFIX + keyringId\n}\n\n/**\n * Read the visibility flag for `keyringId`. Returns `undefined` when no\n * document has been persisted — callers treat that as the default-visible\n * case (`{ hidden: false }`).\n */\nexport async function readUserVisibility(\n store: NoydbStore,\n vault: string,\n keyringId: string,\n): Promise<UserVisibility | undefined> {\n const envelope = await store.get(vault, META_COLLECTION, visibilityRecordId(keyringId))\n if (!envelope) return undefined\n try {\n const parsed = JSON.parse(envelope._data) as unknown\n if (!isUserVisibility(parsed)) return undefined\n return parsed\n } catch {\n return undefined\n }\n}\n\n/**\n * Persist the visibility flag for `keyringId` at\n * `_meta/visibility/<keyringId>`. Idempotent — call on every\n * `vault.user.setMyVisibility()` invocation. Own-only at the caller\n * site; this primitive does not enforce keyring ownership.\n */\nexport async function persistUserVisibility(\n store: NoydbStore,\n vault: string,\n keyringId: string,\n visibility: UserVisibility,\n): Promise<void> {\n const recordId = visibilityRecordId(keyringId)\n const envelope = buildRecordEnvelope(\n { collection: META_COLLECTION, id: recordId, version: 1 },\n { iv: '', data: JSON.stringify({ hidden: visibility.hidden }) },\n )\n await store.put(vault, META_COLLECTION, recordId, envelope)\n}\n\n/**\n * Delete the visibility flag for `keyringId`. Called from `revoke()`\n * alongside `deleteUserEnvelope` so the sidecar does not leak to a\n * re-granted principal with the same `userId`. Idempotent — the store's\n * `delete()` is already a no-op when the record is absent.\n */\nexport async function deleteUserVisibility(\n store: NoydbStore,\n vault: string,\n keyringId: string,\n): Promise<void> {\n await store.delete(vault, META_COLLECTION, visibilityRecordId(keyringId))\n}\n\nfunction isUserVisibility(x: unknown): x is UserVisibility {\n if (x === null || typeof x !== 'object') return false\n if (!('hidden' in x)) return false\n return typeof (x as { hidden: unknown }).hidden === 'boolean'\n}\n","/**\n * Persistence helpers for per-principal user envelopes stored at\n * `_users/<keyringId>` (logically: `_meta/user/<keyringId>`).\n *\n * Unlike `_meta/policy` and `_meta/handle` which are plaintext, user\n * envelopes carry user data and are encrypted with a dedicated\n * {@link USER_ENVELOPE_COLLECTION} DEK (provisioned at vault open and\n * propagated to every keyring via the system-collection DEK path in\n * `team/keyring.ts`).\n *\n * This module is the **storage primitive** layer. The public API\n * (`vault.user.*`) sits on top of this; permission gates, own-only\n * write enforcement, and presence-channel propagation live there.\n *\n * @see design-history/2026-05-05-user-envelope-design.md\n *\n * @module\n */\nimport type { NoydbStore, UserEnvelope } from '../../../kernel/types.js'\nimport { buildRecordAad, buildRecordEnvelope, encrypt, openEnvelopeJson, type EnclaveKey } from '../../../kernel/enclave/index.js'\nimport { ConflictError, UserEnvelopeOversizedError } from '../../../kernel/errors.js'\nimport {\n USER_ENVELOPE_COLLECTION,\n USER_ENVELOPE_MAX_BYTES,\n} from '../../../kernel/constants.js'\n\n/**\n * Read and decrypt the user envelope for `keyringId`. Returns `null`\n * when no envelope has been persisted (either the principal has never\n * called `updateMe`, or the keyring predates this feature).\n *\n * Decryption errors propagate — a tampered or wrong-keyed envelope\n * surfaces as the underlying crypto error rather than masquerading as\n * \"not found\".\n */\nexport async function loadUserEnvelope<T = unknown>(\n store: NoydbStore,\n vault: string,\n keyringId: string,\n dek: EnclaveKey,\n): Promise<UserEnvelope<T> | null> {\n const envelope = await store.get(vault, USER_ENVELOPE_COLLECTION, keyringId)\n if (!envelope) return null\n const plaintext = await openEnvelopeJson({ collection: USER_ENVELOPE_COLLECTION, id: keyringId }, envelope, dek)\n const data = JSON.parse(plaintext) as T\n return {\n keyringId,\n data,\n _v: envelope._v,\n _ts: envelope._ts,\n }\n}\n\n/**\n * Encrypt and persist the user envelope for `keyringId`. The new\n * version is `(prior._v ?? 0) + 1`. Pass `expectedVersion` to enable\n * optimistic-concurrency checks: a mismatch with the stored version\n * throws {@link ConflictError} with the actual stored version.\n *\n * `expectedVersion: 0` means \"expect no prior envelope\"; the write\n * succeeds only if no envelope exists yet.\n *\n * Soft-caps the JSON-serialized payload at {@link USER_ENVELOPE_MAX_BYTES};\n * larger payloads throw {@link UserEnvelopeOversizedError}.\n */\nexport async function saveUserEnvelope<T>(\n store: NoydbStore,\n vault: string,\n keyringId: string,\n payload: T,\n dek: EnclaveKey,\n expectedVersion?: number,\n): Promise<UserEnvelope<T>> {\n const json = JSON.stringify(payload)\n // TextEncoder counts bytes correctly for multi-byte UTF-8 (Thai text,\n // emoji, etc.) — JSON.stringify().length would undercount.\n const bytes = new TextEncoder().encode(json).byteLength\n if (bytes > USER_ENVELOPE_MAX_BYTES) {\n throw new UserEnvelopeOversizedError(bytes)\n }\n\n const prior = await store.get(vault, USER_ENVELOPE_COLLECTION, keyringId)\n if (expectedVersion !== undefined) {\n const priorVersion = prior?._v ?? 0\n if (priorVersion !== expectedVersion) {\n throw new ConflictError(\n priorVersion,\n `User envelope for \"${keyringId}\" expected version ${expectedVersion}, ` +\n `actual ${priorVersion}`,\n )\n }\n }\n\n const nextVersion = (prior?._v ?? 0) + 1\n const ts = new Date().toISOString()\n const identity = { collection: USER_ENVELOPE_COLLECTION, id: keyringId, version: nextVersion }\n const { iv, data } = await encrypt(json, dek, buildRecordAad(identity))\n\n const envelope = buildRecordEnvelope(\n identity,\n { ts, iv, data },\n )\n await store.put(vault, USER_ENVELOPE_COLLECTION, keyringId, envelope)\n\n return {\n keyringId,\n data: payload,\n _v: nextVersion,\n _ts: ts,\n }\n}\n\n/**\n * Delete the user envelope for `keyringId`. Idempotent — no error if\n * the envelope is already absent. Called from the keyring revoke path\n * (cascade-delete) and is a no-op for keyrings that never wrote.\n */\nexport async function deleteUserEnvelope(\n store: NoydbStore,\n vault: string,\n keyringId: string,\n): Promise<void> {\n await store.delete(vault, USER_ENVELOPE_COLLECTION, keyringId)\n}\n\n/**\n * List the keyring ids that have a user envelope persisted in `vault`.\n * Order is store-defined — callers that need a stable order should sort.\n */\nexport async function listUserEnvelopeIds(\n store: NoydbStore,\n vault: string,\n): Promise<string[]> {\n return store.list(vault, USER_ENVELOPE_COLLECTION)\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CargoNotEnabledError
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-244VXYPG.js";
|
|
4
4
|
|
|
5
5
|
// src/with-cargo/strategy.ts
|
|
6
6
|
var NO_CARGO = {
|
|
@@ -12,4 +12,4 @@ var NO_CARGO = {
|
|
|
12
12
|
export {
|
|
13
13
|
NO_CARGO
|
|
14
14
|
};
|
|
15
|
-
//# sourceMappingURL=chunk-
|
|
15
|
+
//# sourceMappingURL=chunk-A6IJU4TK.js.map
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import {
|
|
2
2
|
assertTierAccess
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-SOIQ4MM4.js";
|
|
4
4
|
import {
|
|
5
5
|
dekKey,
|
|
6
6
|
liveRecordIsElevated,
|
|
7
7
|
liveRecordTier
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-JCN44NCY.js";
|
|
9
9
|
import {
|
|
10
10
|
buildRecordAad,
|
|
11
11
|
openEnvelopeJson,
|
|
12
12
|
writeEnvelopeBody
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-KJFW62P4.js";
|
|
14
14
|
import {
|
|
15
15
|
buildRecordEnvelope,
|
|
16
16
|
buildSealedRecordEnvelope
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-SEE332EV.js";
|
|
18
18
|
import {
|
|
19
19
|
base64ToBuffer,
|
|
20
20
|
bufferToBase64,
|
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
sha256Hex,
|
|
28
28
|
unwrapCek,
|
|
29
29
|
wrapCek
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-UYB234ZR.js";
|
|
31
31
|
import {
|
|
32
32
|
BLOB_ADDRESS_KEY_ID,
|
|
33
33
|
BlobIntentPendingError,
|
|
@@ -39,7 +39,7 @@ import {
|
|
|
39
39
|
UnsupportedTierCompositionError,
|
|
40
40
|
ValidationError,
|
|
41
41
|
isConflictError
|
|
42
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-244VXYPG.js";
|
|
43
43
|
|
|
44
44
|
// src/with-shape/blobs/blob-pinning.ts
|
|
45
45
|
function memoryBlobPinStore() {
|
|
@@ -452,6 +452,8 @@ var BlobSet = class _BlobSet {
|
|
|
452
452
|
* a cleared view: see `ownerRecordElevated()`/`ownerTier()`.
|
|
453
453
|
*/
|
|
454
454
|
clearedTier;
|
|
455
|
+
/** #1452 — see `BlobsStrategyOpenArgs.assertOwnerWritable`. */
|
|
456
|
+
assertOwnerWritable;
|
|
455
457
|
constructor(opts) {
|
|
456
458
|
this.store = opts.store;
|
|
457
459
|
this.vault = opts.vault;
|
|
@@ -469,6 +471,7 @@ var BlobSet = class _BlobSet {
|
|
|
469
471
|
this.keyring = opts.keyring;
|
|
470
472
|
this.clearedTier = opts.clearedTier;
|
|
471
473
|
this.pinCache = opts.pinCache;
|
|
474
|
+
this.assertOwnerWritable = opts.assertOwnerWritable;
|
|
472
475
|
}
|
|
473
476
|
/**
|
|
474
477
|
* #724 I1 completion: a legacy (non-`perRecordKeys`) blob has no per-blob
|
|
@@ -2155,6 +2158,7 @@ var BlobSet = class _BlobSet {
|
|
|
2155
2158
|
async put(slotName, data, opts) {
|
|
2156
2159
|
this.assertKeyPartSafe(this.recordId, "record id");
|
|
2157
2160
|
this.assertKeyPartSafe(slotName, "slot name");
|
|
2161
|
+
await this.assertOwnerWritable?.();
|
|
2158
2162
|
await this.resolvePendingIntent();
|
|
2159
2163
|
if (this.objectStore && this.blobFields?.[slotName]?.external) {
|
|
2160
2164
|
const policy = this.blobFields[slotName];
|
|
@@ -2503,6 +2507,7 @@ var BlobSet = class _BlobSet {
|
|
|
2503
2507
|
* bucket. Writes the external slot record (the catalog entry).
|
|
2504
2508
|
*/
|
|
2505
2509
|
async adoptExternal(slotName, ref) {
|
|
2510
|
+
await this.assertOwnerWritable?.();
|
|
2506
2511
|
this.assertKeyPartSafe(this.recordId, "record id");
|
|
2507
2512
|
this.assertKeyPartSafe(slotName, "slot name");
|
|
2508
2513
|
this.assertExternalDeclared(slotName);
|
|
@@ -2591,10 +2596,32 @@ var BlobSet = class _BlobSet {
|
|
|
2591
2596
|
});
|
|
2592
2597
|
}
|
|
2593
2598
|
/**
|
|
2594
|
-
* Delete the named slot from this record.
|
|
2595
|
-
*
|
|
2599
|
+
* Delete the named slot from this record and decrement the blob's refCount.
|
|
2600
|
+
* At refCount 0 an erasable blob (`perRecordKeys`) is crypto-shredded on the
|
|
2601
|
+
* spot; a legacy blob keeps its chunks until
|
|
2602
|
+
* `vault.compact({ reclaimLegacyBlobs: true })` reclaims them (#1453), or
|
|
2603
|
+
* `blob(id).migrate()` makes it erasable first.
|
|
2604
|
+
*
|
|
2605
|
+
* Gated on the owning record (#1452): refused where an update of the record
|
|
2606
|
+
* would be refused.
|
|
2596
2607
|
*/
|
|
2597
2608
|
async delete(slotName) {
|
|
2609
|
+
await this.assertOwnerWritable?.();
|
|
2610
|
+
return this.releaseSlot(slotName);
|
|
2611
|
+
}
|
|
2612
|
+
/**
|
|
2613
|
+
* #1451 — release EVERY slot this record holds. Called by
|
|
2614
|
+
* `Collection.delete()` after the record is gone, so "the record is deleted"
|
|
2615
|
+
* and "its attachments are released" are one operation. Ungated: the record
|
|
2616
|
+
* delete itself already passed the gate bus. Ref-counted like any release —
|
|
2617
|
+
* content another record still holds survives.
|
|
2618
|
+
*/
|
|
2619
|
+
async releaseAll() {
|
|
2620
|
+
const { slots } = await this.loadSlots();
|
|
2621
|
+
for (const name of Object.keys(slots)) await this.releaseSlot(name);
|
|
2622
|
+
}
|
|
2623
|
+
/** The body of {@link delete}, minus the owner gate. */
|
|
2624
|
+
async releaseSlot(slotName) {
|
|
2598
2625
|
await this.resolvePendingIntent();
|
|
2599
2626
|
let eTagToRelease;
|
|
2600
2627
|
let externalKeyToDelete;
|
|
@@ -2901,6 +2928,7 @@ var BlobSet = class _BlobSet {
|
|
|
2901
2928
|
* `rehomeForTier`) — no separate tier-scoping needed for the content side.
|
|
2902
2929
|
*/
|
|
2903
2930
|
async publish(slotName, label) {
|
|
2931
|
+
await this.assertOwnerWritable?.();
|
|
2904
2932
|
this.assertKeyPartSafe(this.recordId, "record id");
|
|
2905
2933
|
this.assertKeyPartSafe(slotName, "slot name");
|
|
2906
2934
|
this.assertKeyPartSafe(label, "version label");
|
|
@@ -2964,6 +2992,7 @@ var BlobSet = class _BlobSet {
|
|
|
2964
2992
|
* Delete a published version. Decrements refCount on its blob.
|
|
2965
2993
|
*/
|
|
2966
2994
|
async deleteVersion(slotName, label) {
|
|
2995
|
+
await this.assertOwnerWritable?.();
|
|
2967
2996
|
await this.resolvePendingIntent();
|
|
2968
2997
|
const record = await this.loadVersionRecord(slotName, label);
|
|
2969
2998
|
if (!record) return;
|
|
@@ -3137,4 +3166,4 @@ export {
|
|
|
3137
3166
|
DEFAULT_CHUNK_SIZE,
|
|
3138
3167
|
BlobSet
|
|
3139
3168
|
};
|
|
3140
|
-
//# sourceMappingURL=chunk-
|
|
3169
|
+
//# sourceMappingURL=chunk-ANWPSTZU.js.map
|