@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
|
@@ -1,34 +1,112 @@
|
|
|
1
1
|
import {
|
|
2
|
+
canonicalizeQueryPlan,
|
|
2
3
|
isCollectLeg,
|
|
3
4
|
resolveLegOwner,
|
|
5
|
+
ungatedMvContext,
|
|
4
6
|
wrapDbWithPredicates
|
|
5
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-NWHBJQAL.js";
|
|
6
8
|
import {
|
|
7
9
|
canonicalizeMoneyFieldsAsDecimal,
|
|
8
10
|
decodeMoneyFields,
|
|
9
11
|
exactMath
|
|
10
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-WY2XXTET.js";
|
|
11
13
|
import {
|
|
12
|
-
|
|
13
|
-
} from "./chunk-
|
|
14
|
-
import {
|
|
15
|
-
DEFAULT_JOIN_MAX_ROWS
|
|
16
|
-
} from "./chunk-ZORTV6NH.js";
|
|
14
|
+
applyWindow
|
|
15
|
+
} from "./chunk-T52GX4SA.js";
|
|
17
16
|
import {
|
|
18
17
|
groupAndReduce
|
|
19
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-CF5UU4S7.js";
|
|
19
|
+
import {
|
|
20
|
+
putDerivedOutput
|
|
21
|
+
} from "./chunk-K6W7BVZ6.js";
|
|
20
22
|
import {
|
|
21
23
|
canonicalGroupKey
|
|
22
24
|
} from "./chunk-XZHEOSQ2.js";
|
|
25
|
+
import {
|
|
26
|
+
bindDistinctReducers
|
|
27
|
+
} from "./chunk-F2TDU7MQ.js";
|
|
28
|
+
import {
|
|
29
|
+
groupKeyName,
|
|
30
|
+
isDateTruncKey,
|
|
31
|
+
projectDateTruncKeys
|
|
32
|
+
} from "./chunk-XBKH4FOC.js";
|
|
33
|
+
import {
|
|
34
|
+
DEFAULT_JOIN_MAX_ROWS
|
|
35
|
+
} from "./chunk-4I522ERM.js";
|
|
23
36
|
import {
|
|
24
37
|
applyI18nLocale
|
|
25
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-GHLTDZRS.js";
|
|
39
|
+
import {
|
|
40
|
+
viaBinder
|
|
41
|
+
} from "./chunk-Z5HTYMMQ.js";
|
|
26
42
|
import {
|
|
27
43
|
JoinTooLargeError,
|
|
28
44
|
LocaleNotSpecifiedError,
|
|
29
45
|
MaterializedViewConfigError,
|
|
30
46
|
MaterializedViewTooLargeError
|
|
31
|
-
} from "./chunk-
|
|
47
|
+
} from "./chunk-244VXYPG.js";
|
|
48
|
+
|
|
49
|
+
// src/with-formula/materialized-views/window-stage.ts
|
|
50
|
+
function isWindowFn(v) {
|
|
51
|
+
return typeof v === "object" && v !== null && v.__window === true;
|
|
52
|
+
}
|
|
53
|
+
function applyDeclaredWindow(rows, window, moneyFields) {
|
|
54
|
+
if (rows.length === 0) return rows;
|
|
55
|
+
let select = window.select;
|
|
56
|
+
if (moneyFields) {
|
|
57
|
+
const reducersOnly = {};
|
|
58
|
+
for (const [k, v] of Object.entries(select)) {
|
|
59
|
+
if (!isWindowFn(v)) reducersOnly[k] = v;
|
|
60
|
+
}
|
|
61
|
+
if (Object.keys(reducersOnly).length > 0) {
|
|
62
|
+
const binding = viaBinder("money")({ moneyFields });
|
|
63
|
+
let wrapped = binding.wrapReducers(reducersOnly);
|
|
64
|
+
wrapped = bindDistinctReducers(wrapped, {
|
|
65
|
+
canonicalizeIndexKey: (f, v) => binding.canonicalizeIndexKey?.(f, v)
|
|
66
|
+
});
|
|
67
|
+
select = { ...select, ...wrapped };
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const spec = {
|
|
71
|
+
...window.partitionBy !== void 0 && { partitionBy: window.partitionBy },
|
|
72
|
+
...window.orderBy !== void 0 && { orderBy: window.orderBy }
|
|
73
|
+
};
|
|
74
|
+
return applyWindow(rows, spec, select);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// src/with-formula/materialized-views/emit-memo.ts
|
|
78
|
+
var MAX_MEMOIZED_ROWS = 2e4;
|
|
79
|
+
var memos = /* @__PURE__ */ new Map();
|
|
80
|
+
function emitMemoKey(vault, mvName, outputCollection) {
|
|
81
|
+
return `${vault}\0${mvName}\0${outputCollection}`;
|
|
82
|
+
}
|
|
83
|
+
function readEmitMemo(key, stamp) {
|
|
84
|
+
if (stamp === null) return null;
|
|
85
|
+
const hit = memos.get(key);
|
|
86
|
+
if (!hit || hit.stamp !== stamp) {
|
|
87
|
+
if (hit) memos.delete(key);
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
return hit.rows;
|
|
91
|
+
}
|
|
92
|
+
function writeEmitMemo(key, stamp, rows) {
|
|
93
|
+
if (stamp === null || rows.size > MAX_MEMOIZED_ROWS) {
|
|
94
|
+
memos.delete(key);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
memos.set(key, { stamp, rows });
|
|
98
|
+
}
|
|
99
|
+
function rowContentKey(row, queryHash) {
|
|
100
|
+
try {
|
|
101
|
+
const content = {};
|
|
102
|
+
for (const k of Object.keys(row)) {
|
|
103
|
+
if (k !== "_materializedFrom") content[k] = row[k];
|
|
104
|
+
}
|
|
105
|
+
return `${queryHash}\0${canonicalizeQueryPlan(content)}`;
|
|
106
|
+
} catch {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
32
110
|
|
|
33
111
|
// src/with-formula/materialized-views/executor.ts
|
|
34
112
|
var DEFAULT_MAX_ROWS = 1e5;
|
|
@@ -55,7 +133,7 @@ async function materializeUnionResult(spec, db) {
|
|
|
55
133
|
let q = coll.query();
|
|
56
134
|
if (arm.join?.length) {
|
|
57
135
|
for (const leg of arm.join) {
|
|
58
|
-
q = q.join(leg.field, { as: leg.as, maxRows: leg.maxRows, strategy: leg.strategy });
|
|
136
|
+
q = "on" in leg ? q.joinOn(leg.target, { as: leg.as, on: leg.on, mode: leg.mode, maxRows: leg.maxRows }) : q.join(leg.field, { as: leg.as, maxRows: leg.maxRows, strategy: leg.strategy });
|
|
59
137
|
}
|
|
60
138
|
}
|
|
61
139
|
const sourceRows = q.toArray();
|
|
@@ -67,9 +145,18 @@ async function materializeUnionResult(spec, db) {
|
|
|
67
145
|
}
|
|
68
146
|
return finalizeMappedRows(spec, unified);
|
|
69
147
|
}
|
|
148
|
+
function applyWindowStage(spec, rows) {
|
|
149
|
+
if (!spec.window) return rows;
|
|
150
|
+
return applyDeclaredWindow(rows, spec.window, spec.moneyFields);
|
|
151
|
+
}
|
|
70
152
|
function finalizeMappedRows(spec, unified) {
|
|
71
|
-
if (!spec.groupBy) return unified;
|
|
72
|
-
const
|
|
153
|
+
if (!spec.groupBy) return applyWindowStage(spec, unified);
|
|
154
|
+
const groupKeys = Array.isArray(spec.groupBy) ? spec.groupBy : [spec.groupBy];
|
|
155
|
+
const groupFields = groupKeys.map(groupKeyName);
|
|
156
|
+
const derivedKeys = groupKeys.filter(isDateTruncKey);
|
|
157
|
+
if (derivedKeys.length > 0) {
|
|
158
|
+
unified = projectDateTruncKeys(unified, derivedKeys);
|
|
159
|
+
}
|
|
73
160
|
if (spec.i18nLocale !== void 0 && spec.i18nFields !== void 0) {
|
|
74
161
|
const groupI18n = {};
|
|
75
162
|
for (const f of groupFields) {
|
|
@@ -101,11 +188,14 @@ function finalizeMappedRows(spec, unified) {
|
|
|
101
188
|
}
|
|
102
189
|
return [...seen.values()];
|
|
103
190
|
}
|
|
104
|
-
return
|
|
191
|
+
return applyWindowStage(
|
|
192
|
+
spec,
|
|
193
|
+
groupAndReduce(unified, groupFields, spec.aggregate, spec.moneyFields)
|
|
194
|
+
);
|
|
105
195
|
}
|
|
106
196
|
function applyDerive(spec, rows) {
|
|
107
197
|
const groupFields = new Set(
|
|
108
|
-
spec.groupBy === void 0 ? [] :
|
|
198
|
+
spec.groupBy === void 0 ? [] : (Array.isArray(spec.groupBy) ? spec.groupBy : [spec.groupBy]).map(groupKeyName)
|
|
109
199
|
);
|
|
110
200
|
return rows.map((row) => {
|
|
111
201
|
const view = spec.moneyFields ? decodeMoneyFields(row, spec.moneyFields, "raw") : row;
|
|
@@ -229,7 +319,7 @@ var MaterializedViewExecutor = {
|
|
|
229
319
|
const maxRows = spec.maxRows ?? DEFAULT_MAX_ROWS;
|
|
230
320
|
const onEmpty = spec.onEmpty ?? "delete";
|
|
231
321
|
const strict = spec.strict ?? false;
|
|
232
|
-
const baseCtx = accessor.getQueryContext();
|
|
322
|
+
const baseCtx = ungatedMvContext(accessor.getQueryContext());
|
|
233
323
|
const ctxForQuery = spec.predicates ? wrapDbWithPredicates(baseCtx, spec.predicates) : baseCtx;
|
|
234
324
|
let rows;
|
|
235
325
|
if (spec.unionSources) {
|
|
@@ -264,9 +354,19 @@ var MaterializedViewExecutor = {
|
|
|
264
354
|
};
|
|
265
355
|
enrichedRows.push({ id, record: { ...row, _materializedFrom: meta } });
|
|
266
356
|
}
|
|
357
|
+
const memoKey = emitMemoKey(vaultName, spec.name, reg.outputCollection);
|
|
358
|
+
const priorEmitted = readEmitMemo(memoKey, outputColl._cacheStamp);
|
|
359
|
+
const emitted = /* @__PURE__ */ new Map();
|
|
267
360
|
let written = 0;
|
|
361
|
+
let skipped = 0;
|
|
268
362
|
let failed = 0;
|
|
269
363
|
for (const { id, record } of enrichedRows) {
|
|
364
|
+
const contentKey = rowContentKey(record, reg.queryHash);
|
|
365
|
+
if (contentKey !== null && txCtx === null && !outputColl._derivedWriteGated(record) && priorEmitted?.get(id) === contentKey) {
|
|
366
|
+
skipped++;
|
|
367
|
+
emitted.set(id, contentKey);
|
|
368
|
+
continue;
|
|
369
|
+
}
|
|
270
370
|
try {
|
|
271
371
|
if (txCtx !== null) {
|
|
272
372
|
const prior = await adapter.get(vaultName, reg.outputCollection, id);
|
|
@@ -275,12 +375,18 @@ var MaterializedViewExecutor = {
|
|
|
275
375
|
priorEnvelope: prior
|
|
276
376
|
});
|
|
277
377
|
}
|
|
378
|
+
let landed = false;
|
|
278
379
|
if (accessor.dispatchCtx) {
|
|
279
|
-
if (await putDerivedOutput(outputColl, id, record, accessor.dispatchCtx) === "written")
|
|
380
|
+
if (await putDerivedOutput(outputColl, id, record, accessor.dispatchCtx) === "written") {
|
|
381
|
+
written++;
|
|
382
|
+
landed = true;
|
|
383
|
+
}
|
|
280
384
|
} else {
|
|
281
385
|
await outputColl.put(id, record);
|
|
282
386
|
written++;
|
|
387
|
+
landed = true;
|
|
283
388
|
}
|
|
389
|
+
if (landed && contentKey !== null) emitted.set(id, contentKey);
|
|
284
390
|
} catch (err) {
|
|
285
391
|
failed++;
|
|
286
392
|
if (strict) throw err;
|
|
@@ -322,7 +428,8 @@ var MaterializedViewExecutor = {
|
|
|
322
428
|
}
|
|
323
429
|
}
|
|
324
430
|
}
|
|
325
|
-
|
|
431
|
+
writeEmitMemo(memoKey, outputColl._cacheStamp, emitted);
|
|
432
|
+
return { written, skipped, deleted, failed, residueUndecodable, residueDeclined };
|
|
326
433
|
}
|
|
327
434
|
};
|
|
328
435
|
async function listOutputIds(outputColl) {
|
|
@@ -342,4 +449,4 @@ async function listOutputIds(outputColl) {
|
|
|
342
449
|
export {
|
|
343
450
|
MaterializedViewExecutor
|
|
344
451
|
};
|
|
345
|
-
//# sourceMappingURL=chunk-
|
|
452
|
+
//# sourceMappingURL=chunk-QBBUZ3I3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/with-formula/materialized-views/window-stage.ts","../src/with-formula/materialized-views/emit-memo.ts","../src/with-formula/materialized-views/executor.ts"],"sourcesContent":["/**\n * #1411 — the declared window stage of a materialized view.\n *\n * `unionSources` → `map` → `groupBy` → `aggregate` → **`window`** → `derive`.\n *\n * ## Why a window is safe here when `derive` is deliberately single-row\n *\n * `derive`'s contract is *pure, single-row, no cross-row access* — a window is\n * the opposite of all three. The difference is not caution, it is that\n * materialization is a FULL RECOMPUTE: the executor holds every row the view\n * will store, in one array, before it writes any of them. So an\n * order-dependent, cross-row pass runs exactly once over exactly the rows that\n * get stored, and its output is then an ordinary column. A per-row recompute\n * could not do this — inserting a row early in a partition moves every later\n * row's running total.\n *\n * ## Why this does not simply call `applyWindow`\n *\n * ⚠️ `applyWindow` does no Via rewriting. On the ad-hoc builder,\n * `Query.window().select()` rewrites reducer slots through the COLLECTION's\n * Via pipeline first, which is what makes `runningMoneySum` exact. A UNION-mode\n * MV has no collection — its rows are MAPPED — so it has the same answer\n * `aggregate` already uses: the MV's own `moneyFields` descriptors, bound\n * through the kernel's Via port. This mirrors `groupAndReduce`'s money block\n * line for line, deliberately: two places that must agree about what a money\n * reducer is, doing it the same way.\n *\n * Without that rewrite the failure is silent and specific — a running total\n * over decimal strings accumulates in float and returns\n * `0.6000000000000001` where the aggregate on the same rows returns `'0.60'`.\n */\nimport { applyWindow } from '../../with-lookup/reduce/window.js'\nimport type { WindowSelectSpec, WindowSpec } from '../../with-lookup/reduce/window.js'\nimport { bindDistinctReducers } from '../../with-lookup/reduce/reducers.js'\nimport type { Reducer } from '../../with-lookup/reduce/reducers.js'\nimport type { ReduceSpec } from '../../with-lookup/reduce/reduction.js'\nimport { viaBinder } from '../../kernel/via/index.js'\nimport type { MaterializedViewWindow, MoneyDescriptorMap } from './types.js'\n\n/** Is this slot a window function rather than a reducer? */\nfunction isWindowFn(v: unknown): boolean {\n return typeof v === 'object' && v !== null && (v as { __window?: unknown }).__window === true\n}\n\n/**\n * Apply a declared window to the finished row set.\n *\n * `moneyFields` is the MV's own descriptor map; when present, every REDUCER\n * slot is rewritten exactly as `aggregate`'s are. Window functions\n * (`rowNumber`, `rank`, `lag`, `lead`) are passed through untouched — they\n * navigate rows rather than accumulate values, so there is nothing to make\n * exact.\n */\nexport function applyDeclaredWindow(\n rows: readonly Record<string, unknown>[],\n window: MaterializedViewWindow,\n moneyFields?: MoneyDescriptorMap,\n): ReadonlyArray<Record<string, unknown>> {\n if (rows.length === 0) return rows\n\n let select: WindowSelectSpec = window.select\n if (moneyFields) {\n const reducersOnly: Record<string, Reducer<unknown, unknown>> = {}\n for (const [k, v] of Object.entries(select)) {\n if (!isWindowFn(v)) reducersOnly[k] = v as Reducer<unknown, unknown>\n }\n if (Object.keys(reducersOnly).length > 0) {\n const binding = viaBinder('money')({ moneyFields })\n let wrapped = binding.wrapReducers!(reducersOnly as ReduceSpec) as Record<\n string,\n Reducer<unknown, unknown>\n >\n wrapped = bindDistinctReducers(wrapped as ReduceSpec, {\n canonicalizeIndexKey: (f, v) => binding.canonicalizeIndexKey?.(f, v),\n }) as Record<string, Reducer<unknown, unknown>>\n select = { ...select, ...wrapped }\n }\n }\n\n // `applyWindow` takes the partition/order spec and the select list\n // separately, so strip `select` off rather than pass it twice. Built by\n // spreading absent keys away rather than assigning `undefined` — the package\n // compiles under `exactOptionalPropertyTypes`, where the two differ.\n const spec: WindowSpec = {\n ...(window.partitionBy !== undefined && { partitionBy: window.partitionBy }),\n ...(window.orderBy !== undefined && { orderBy: window.orderBy }),\n }\n return applyWindow<Record<string, unknown>>(rows, spec, select)\n}\n","/**\n * Skip re-writing materialized-view output rows whose content has not changed\n * (#1418).\n *\n * `MaterializedViewExecutor.refresh()` recomputes the whole view and then\n * writes EVERY output row, on every source write. Measured on one MV with a\n * single union arm, writing rows the MV's own `map` drops:\n *\n * 250 receipts / 250 bills → 23.0 ms per source write\n * 450 receipts / 450 bills → 41.6 ms per source write\n *\n * 1.8x the sources, 1.8x the cost — because the thing that grew was the OUTPUT\n * ROW COUNT, and each row is an encrypt-and-store round trip. The query and the\n * aggregation are not where the time goes.\n *\n * ## Why this, and not \"skip the refresh when the row maps to nothing\"\n *\n * The issue proposed short-circuiting the refresh when the written row's `map`\n * returns null. That cannot be built as stated, and the reason is worth\n * recording so nobody re-attempts it:\n *\n * 1. `materializeUnionResult` feeds `map` rows from `coll.query().toArray()`,\n * which applies `decodeVia` — money arrives as a canonical decimal string,\n * not the stored scaled integer. Probing `arm.map(writtenRecord)` at\n * dispatch time hands `map` a DIFFERENTLY SHAPED row, so any `map` that\n * filters on a money field can answer `null` where the real pipeline would\n * not. The view then silently stops updating, which is far worse than the\n * latency it was meant to fix.\n * 2. Skipping also requires that the row contributed nothing BEFORE, or an\n * update that removes a row from the view is dropped. The prior record is\n * not passed to the dispatcher, and is a stored record, so it hits (1)\n * twice over.\n * 3. An arm with `join` legs has the right side attached before `map` runs, so\n * a probe would have to resolve the legs too.\n *\n * Comparing the row we are ABOUT to write against the row we LAST wrote sides\n * steps all three. It needs no prior record, it is form-agnostic (query, union\n * and projection all benefit), and it degrades to the right thing: a write that\n * changes one group rewrites one row instead of all of them.\n *\n * ## Why the entries are canonical strings and not short hashes\n *\n * A hash collision here means a row that is never rewritten — a silently stale\n * view with no symptom. At the 20k-row cap below, an 8-byte hash carries a\n * couple of percent chance of one collision somewhere, which is not a trade\n * worth making for memory. So entries hold the full canonical string, and\n * memory is bounded by refusing to memoize a view larger than the cap.\n *\n * ## Why a mutation stamp, and what it does NOT cover\n *\n * The memo is only sound while nothing else writes the output collection —\n * tombstoning, `invalidateMVAtRest`, forget/erase and sync cut-over all can. So\n * a refresh records the output collection's mutation stamp AFTER its writes,\n * and the next refresh discards the whole set unless the stamp is still where\n * it left it. That is a \"nobody else touched this\" test rather than an\n * enumeration of writers — the same reasoning that made #1417's keyset memo and\n * #1426's slot guard safe, and it does not rot when a new writer is added.\n *\n * ⚠️ It covers writers that go THROUGH the output `Collection`. A writer that\n * bypasses it and edits the store directly moves neither the stamp nor the\n * collection's own cache — but such a writer already makes `list()` on that\n * collection wrong, so it is a broader defect than this memo.\n *\n * ## ⛔ The memo stands down when a REDUNDANT write is still observable\n *\n * `Collection._cacheStamp` returns `null` — no memo — whenever writing the same\n * bytes again would have an effect beyond the stored bytes. This is the half\n * that is easy to get wrong, and it was found by a failing test rather than by\n * reasoning, so the cases are recorded:\n *\n * - **A `beforePut` gate handler.** Measured: with `withPeriods()` and a\n * closed period, an unchanged MV row previously produced a\n * `PeriodClosedError` from `put`, which `putDerivedOutput` converts into a\n * `derivation:skipped-frozen` event and an audit record. Skipping the write\n * silences that — `written=0 skipped=2 events=0` where the suite expects one\n * event. A performance change must not quietly narrow a compliance signal.\n * - **Explicit history.** A put records a version, so skipping changes what\n * `history()` returns. (Arguably an improvement — 450 identical versions per\n * source write is not useful — but that is a product call, not this one.)\n * - **Sync (`onDirty`) and the search index.** Both mark state from the fact\n * that a write happened, independently of what was written.\n * - **Lazy mode**, which has no eager cache to stamp.\n *\n * The asymmetry is what makes this the right default: opting out costs the old\n * write path, opting in wrongly changes behaviour with no symptom at all.\n *\n * ⭐ So an MV whose OUTPUT collection carries periods, history, sync or search\n * gets no speedup. That is deliberate, and it is the first thing to check when\n * this fix appears not to help a real workload — the answer is per output\n * collection, not per vault.\n *\n * ⛔ A row is recorded ONLY when the write actually landed. A `putDerivedOutput`\n * that declines (the frozen-period skip) or throws leaves no entry, so the next\n * refresh writes it again rather than believing a row exists that does not.\n *\n * @module\n */\nimport { canonicalizeQueryPlan } from './query-hash.js'\n\n/**\n * Views larger than this are not memoized at all. The memo would otherwise\n * hold a canonical string per row for the process's life, and a view this size\n * is dominated by its write cost in ways one skip cannot rescue.\n */\nconst MAX_MEMOIZED_ROWS = 20_000\n\ninterface EmitMemo {\n /** The output collection's mutation stamp when this set was written. */\n readonly stamp: number\n /** `outputId -> canonical content string` for rows this MV actually wrote. */\n readonly rows: Map<string, string>\n}\n\nconst memos = new Map<string, EmitMemo>()\n\n/**\n * Identity of one MV's output, per vault — MV names are not globally unique.\n *\n * ⚠️ `\\0` written as the ESCAPE, not as a raw byte. A raw NUL in the source\n * makes git classify the whole file as binary, so it stops diffing and stops\n * being reviewable — caught here by a `Bin 0 -> 8811 bytes` line in a diffstat.\n * The separator itself is right: no vault or collection name can contain one.\n */\nexport function emitMemoKey(vault: string, mvName: string, outputCollection: string): string {\n return `${vault}\\0${mvName}\\0${outputCollection}`\n}\n\n/**\n * The rows this MV last wrote, or `null` when the memo cannot be trusted —\n * nothing recorded yet, or the output collection moved under us.\n *\n * `stamp` of `null` means the collection cannot supply one (lazy mode), which\n * is treated as \"no memo\" rather than \"unchanged\".\n */\nexport function readEmitMemo(key: string, stamp: number | null): ReadonlyMap<string, string> | null {\n if (stamp === null) return null\n const hit = memos.get(key)\n if (!hit || hit.stamp !== stamp) {\n // Someone else wrote the output collection. Everything we believed about\n // its contents is now a guess, so drop all of it rather than reconcile.\n if (hit) memos.delete(key)\n return null\n }\n return hit.rows\n}\n\n/** Record what this refresh actually left on disk. A `null` stamp records nothing. */\nexport function writeEmitMemo(key: string, stamp: number | null, rows: Map<string, string>): void {\n if (stamp === null || rows.size > MAX_MEMOIZED_ROWS) {\n memos.delete(key)\n return\n }\n memos.set(key, { stamp, rows })\n}\n\n/** Forget one MV's output entirely. Used when a refresh could not complete cleanly. */\nexport function dropEmitMemo(key: string): void {\n memos.delete(key)\n}\n\n/**\n * A canonical string for the row a refresh is about to write, or `null` when no\n * safe one exists.\n *\n * The MV's `queryHash` is folded in so a strategy change rewrites every row\n * even where the projected content happens to match — a row carrying a stale\n * `_materializedFrom.queryHash` is stale by definition (`stale.ts`).\n *\n * `_materializedFrom` itself is excluded: its `materializedAt` moves on every\n * refresh, so including it would make every comparison differ and the memo a\n * pure cost.\n *\n * ⛔ Returns `null` rather than throwing on anything `JSON.stringify` refuses\n * (a `BigInt`, a cycle). Declining to memoize costs the old write; guessing\n * costs a stale view.\n */\nexport function rowContentKey(row: Record<string, unknown>, queryHash: string): string | null {\n try {\n // `_materializedFrom` is excluded by rebuilding without it rather than by\n // destructuring into an unused binding — same result, no dead name.\n const content: Record<string, unknown> = {}\n for (const k of Object.keys(row)) {\n if (k !== '_materializedFrom') content[k] = row[k]\n }\n return `${queryHash}\\0${canonicalizeQueryPlan(content)}`\n } catch {\n return null\n }\n}\n\n/** Test seam — the process-wide memo must not leak between test cases. */\nexport function _clearEmitMemos(): void {\n memos.clear()\n}\n","import { groupKeyName, isDateTruncKey, projectDateTruncKeys, type GroupKey } from '../../kernel/query/reduce/date-trunc.js'\nimport type { Collection } from '../../kernel/collection.js'\nimport type { TxContext } from '../../with-commit/tx/transaction.js'\nimport type { EncryptedEnvelope } from '../../kernel/types.js'\nimport { MaterializedViewTooLargeError, MaterializedViewConfigError, LocaleNotSpecifiedError, JoinTooLargeError } from '../../kernel/errors.js'\nimport { DEFAULT_JOIN_MAX_ROWS } from '../../kernel/query/relate/join.js'\nimport type { MaterializedFromMeta, MVQueryContext, MaterializedViewSpec, ProjectionJoinLeg } from './types.js'\nimport type { RegisteredMV } from './registry.js'\nimport { wrapDbWithPredicates, ungatedMvContext } from './registry.js'\nimport { groupAndReduce } from '../../with-lookup/reduce/groupby.js'\nimport { applyDeclaredWindow } from './window-stage.js'\nimport { canonicalGroupKey } from '../../with-lookup/reduce/canonical-key.js'\nimport { applyI18nLocale, type I18nTextDescriptor } from '../../via/i18n/core.js'\nimport { canonicalizeMoneyFieldsAsDecimal, decodeMoneyFields } from '../../via/money/normalize.js'\nimport { exactMath } from '../../via/money/exact.js'\nimport { putDerivedOutput, type PutDerivedOutputCtx } from '../../kernel/via/dispatch.js'\nimport { isCollectLeg, resolveLegOwner, type RefLookup } from './projection-legs.js' // #1140\nimport { emitMemoKey, readEmitMemo, writeEmitMemo, rowContentKey } from './emit-memo.js' // #1418\n\n/**\n * Accessor shape passed in from the owning Vault. Mirrors v1's\n * `DerivationStaleAccessor` — provides the per-collection resolver\n * and the active TxContext so refresh writes/tombstones register on\n * `_executed` for rollback symmetry.\n */\nexport interface MVExecutorAccessor {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n getCollection(name: string): Collection<any>\n getActiveTxContext(): TxContext | null\n /**\n * Vault-shaped accessor passed to the MV's `query()` callback at\n * each refresh. Same instance the registry used at registration\n * time; threading through the executor lets the refresh path\n * re-evaluate the closure against the live vault state.\n */\n getQueryContext(): MVQueryContext\n /**\n * #638 Task 5 — ctx for `putDerivedOutput`'s frozen-period skip+audit. #641: the lazy\n * resolve-on-read caller (`stale.ts#resolveStaleMVOnRead`) now supplies one too — built at\n * the `Collection.get()`/`list()` entry point with a `'resolve-on-read'` sentinel id (no\n * real \"reacting write\" for a read-triggered materialize, mirroring `refreshView()`'s\n * `'refreshView'` sentinel). Still declared optional here since `MVExecutorAccessor` is a\n * general shape and a future caller could reasonably omit it.\n */\n dispatchCtx?: PutDerivedOutputCtx\n}\n\nexport interface RefreshResult {\n /** Rows newly written / overwritten. */\n written: number\n /**\n * #1418 — rows whose content was byte-identical to what this MV last wrote,\n * so the encrypt-and-store round trip was skipped. Counted separately from\n * `written` on purpose: `written` means \"a row was persisted\", and reporting\n * a skip as a write would make the two indistinguishable to anyone\n * diagnosing whether a refresh actually did anything.\n */\n skipped: number\n /** Rows tombstoned via `_internalDelete` (only when `onEmpty: 'delete'`). */\n deleted: number\n /** Failed row writes (non-strict mode). */\n failed: number\n /** #782/#785 — `outputCollection:id` entries from the tombstone pass whose ownership stamp\n * couldn't be decoded under the collection's default DEK (undecodable, mirroring\n * `invalidateMVAtRest`'s #776 posture) — ownership UNCONFIRMED. Only populated when\n * `onEmpty: 'delete'`. */\n residueUndecodable: string[]\n /** #782/#785 — `outputCollection:id` entries that decoded, stamp-matched this MV, but\n * `_internalDelete` declined (the #718 tier-elevation gate) — ownership CONFIRMED, a real\n * silent survival, surfaced rather than dropped. Only populated when `onEmpty: 'delete'`. */\n residueDeclined: string[]\n}\n\n/** Default cost ceiling — overridable per-MV via `spec.maxRows`. */\nconst DEFAULT_MAX_ROWS = 100_000\n\n/**\n * Materialize a query terminal that may be a `Query<T>` (call\n * `.toArray()`), an `Reduction<R>` (call `.run()` returning a\n * single object — wrap as a one-row array), or a `GroupedReduction<R>`\n * (call `.run()` returning an array of grouped rows). Branches on\n * available terminal at runtime — no type-discrimination at registration.\n */\nasync function materializeQueryResult(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n q: any,\n mvName: string,\n i18nLocale?: string,\n i18nFields?: Record<string, I18nTextDescriptor>,\n): Promise<ReadonlyArray<Record<string, unknown>>> {\n if (typeof q?.toArray === 'function') {\n // Query<T> — non-aggregate path. `.toArray()` returns Promise<T[]>.\n return await q.toArray()\n }\n if (typeof q?.run === 'function') {\n // Reduction<R> or GroupedReduction<R>. `.run()` is synchronous\n // and returns either a single object (Reduction) or an array of\n // rows (GroupedReduction). Promise.resolve() normalizes both\n // sync and async (future) variants.\n // Query-form MV grouping: when the MV declares i18nLocale, pass it +\n // i18nFields so a GroupedReduction resolves i18n group keys before\n // bucketing (the Reduction path ignores the extra arg).\n const runOpts = i18nLocale !== undefined ? { locale: i18nLocale, i18nFields } : undefined\n const result: unknown = await Promise.resolve(q.run(runOpts))\n if (Array.isArray(result)) {\n return result as ReadonlyArray<Record<string, unknown>>\n }\n // Single-aggregate result — wrap as one-row array. The consumer's\n // `rowKey()` should return a stable identity (often a literal\n // constant like `'total'`) since there's only one row.\n return [result as Record<string, unknown>]\n }\n throw new Error(\n `MV \"${mvName}\": query() must return a Query<T>, Reduction, or GroupedReduction. ` +\n `Got something without a .toArray() or .run() terminal.`,\n )\n}\n\n/**\n * Materialize a UNION-form MV: read every arm's source\n * collection, apply each arm's `map` to project rows into the unified\n * MV row shape, concatenate the mapped streams, then optionally run\n * `groupBy` + `aggregate` over the result.\n *\n * Modes (driven by `spec.groupBy` / `spec.aggregate`):\n *\n * - No `groupBy` → return the concatenated mapped rows unchanged.\n * - `groupBy` without `aggregate` → dedupe by composite group key,\n * keep the first row seen per key (later arms don't overwrite\n * earlier arms — Map insertion order rules).\n * - `groupBy` + `aggregate` → delegate to the shared `groupAndReduce`\n * pipeline used by `Query.groupBy().aggregate()`.\n *\n * Per-arm `map` is the schema-unification boundary; the strategy's\n * `TRow` type parameter enforces that every arm projects into the\n * same shape at compile time.\n *\n * @internal\n */\nasync function materializeUnionResult<TRow extends Record<string, unknown>>(\n spec: MaterializedViewSpec<TRow>,\n db: MVQueryContext,\n): Promise<ReadonlyArray<Record<string, unknown>>> {\n const unified: TRow[] = []\n for (const arm of spec.unionSources!) {\n const coll = db.collection<Record<string, unknown>>(arm.collection)\n // Optional per-arm FK joins: chain `.join(field, { as, ... })` for\n // each declared leg before terminating. The aliased right-side\n // record lands at `sourceRow[leg.as]`, where the arm's `map` reads\n // it. Cast to `any` because the chained join widens the row type but\n // the executor treats every row as `Record<string, unknown>` — same\n // pattern the query-form join path uses.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let q: any = coll.query()\n if (arm.join?.length) {\n for (const leg of arm.join) {\n // #1411 — a declared leg is `Query.joinOn()`; a ref leg is `Query.join()`.\n q = 'on' in leg\n ? q.joinOn(leg.target, { as: leg.as, on: leg.on, mode: leg.mode, maxRows: leg.maxRows })\n : q.join(leg.field, { as: leg.as, maxRows: leg.maxRows, strategy: leg.strategy })\n }\n }\n const sourceRows = q.toArray() as ReadonlyArray<Record<string, unknown>>\n for (const r of sourceRows) {\n const mapped = arm.map(r)\n // null / undefined means \"omit this source row\" — skip without\n // pushing so groupBy/aggregate never see a null entry.\n if (mapped == null) continue\n unified.push(mapped)\n }\n }\n\n return finalizeMappedRows(spec, unified)\n}\n\n\n/**\n * #1411 — the window stage, applied at every exit from the grouping tail.\n *\n * A no-op without `spec.window`, so the ungrouped and grouped paths can both\n * call it unconditionally rather than each remembering to.\n */\nfunction applyWindowStage<TRow extends Record<string, unknown>>(\n spec: MaterializedViewSpec<TRow>,\n rows: ReadonlyArray<Record<string, unknown>>,\n): ReadonlyArray<Record<string, unknown>> {\n if (!spec.window) return rows\n return applyDeclaredWindow(rows, spec.window, spec.moneyFields)\n}\n\n/**\n * Shared post-map tail for the UNION and projection (#810) forms:\n * optional `groupBy` (+ `aggregate`) over the mapped-row stream.\n * Extracted verbatim from `materializeUnionResult` so both forms feed\n * the identical grouping pipeline — i18n group-key resolution, the\n * object-group-key guard, dedup-without-aggregate, and the shared\n * `groupAndReduce` delegate.\n *\n * @internal\n */\nfunction finalizeMappedRows<TRow extends Record<string, unknown>>(\n spec: MaterializedViewSpec<TRow>,\n unified: TRow[],\n): ReadonlyArray<Record<string, unknown>> {\n // #1411 — a window with no grouping is a legitimate shape: the pilot's\n // running total is per-row, not per-bucket. Both exits go through the same\n // stage so the two cannot drift on whether a window ran.\n if (!spec.groupBy) return applyWindowStage(spec, unified)\n\n const groupKeys: readonly GroupKey[] = Array.isArray(spec.groupBy)\n ? (spec.groupBy as readonly GroupKey[])\n : [spec.groupBy as GroupKey]\n const groupFields: readonly string[] = groupKeys.map(groupKeyName)\n\n // Derived calendar keys (#1350) are bucketed onto the mapped row first, so\n // every rule below — the i18n resolution, the object-key refusal, the dedup\n // path and `groupAndReduce` — sees an ordinary stored field.\n const derivedKeys = groupKeys.filter(isDateTruncKey)\n if (derivedKeys.length > 0) {\n unified = projectDateTruncKeys(unified, derivedKeys)\n }\n\n // i18n-aware group keys. An `i18nText` group field carries a raw\n // `{ locale: string }` map, an unstable object key. When `i18nLocale` is\n // declared (with `i18nFields` describing those fields), resolve the declared\n // group-key i18n fields to it at the `mv` layer FIRST — the same unified-rows\n // boundary where money is threaded — so buckets are stable strings and the\n // `mv`-layer `onMissing` policy fires here.\n if (spec.i18nLocale !== undefined && spec.i18nFields !== undefined) {\n const groupI18n: Record<string, I18nTextDescriptor> = {}\n for (const f of groupFields) {\n const d = spec.i18nFields[f]\n if (d !== undefined) groupI18n[f] = d\n }\n if (Object.keys(groupI18n).length > 0) {\n for (let i = 0; i < unified.length; i++) {\n unified[i] = applyI18nLocale(unified[i] as Record<string, unknown>, groupI18n, spec.i18nLocale, undefined, 'mv') as TRow\n }\n }\n }\n // Guard (always): a remaining object-valued group key — an undeclared i18n\n // field or a locale-less MV — would bucket on a map. Refuse, don't bucket wrong.\n for (const f of groupFields) {\n for (const row of unified) {\n const v = (row as Record<string, unknown>)[f]\n if (v !== null && typeof v === 'object') {\n throw new LocaleNotSpecifiedError(\n f,\n `Materialized view \"${spec.name}\" groups by \"${f}\", whose value is a raw i18n locale map — ` +\n `an unstable object group key. Declare { i18nLocale, i18nFields } on the MV to resolve it at ` +\n `the 'mv' layer, or group by a dictKey/staticDict code (the stable key) and resolve the label at read time.`,\n )\n }\n }\n }\n\n // groupBy without aggregate — dedupe by composite key, keep first\n // seen row per key. Useful for cross-arm uniqueness (e.g. unify two\n // sibling collections, keeping one row per natural key).\n if (!spec.aggregate) {\n const seen = new Map<string, TRow>()\n for (const row of unified) {\n const k = canonicalGroupKey(groupFields, row as Record<string, unknown>)\n if (!seen.has(k)) seen.set(k, row)\n }\n return [...seen.values()]\n }\n\n // groupBy + aggregate — delegate to the shared pipeline used by\n // `Query.groupBy().aggregate()`. Result rows carry each grouped\n // field in declaration order followed by the spec's reducer outputs.\n return applyWindowStage(\n spec,\n groupAndReduce<Record<string, unknown>>(unified, groupFields, spec.aggregate, spec.moneyFields),\n )\n}\n\n/**\n * Apply the spec's `derive` to each finished row (#1007).\n *\n * Three rules, all of them about keeping the hook narrow enough that the\n * engine never has to reason about the function:\n *\n * - a `null` / `undefined` return leaves the row untouched;\n * - a returned key that collides with a `groupBy` field is refused — group\n * keys are the row's identity and feed `rowKey`, so letting `derive`\n * rewrite one would silently re-home the row into a different bucket than\n * the one it was aggregated for;\n * - a derived field declared in `moneyFields` is quantised through its\n * descriptor, so the stored value is exact at the declared scale instead of\n * whatever the user's arithmetic produced.\n *\n * @internal\n */\nfunction applyDerive<TRow extends Record<string, unknown>>(\n spec: MaterializedViewSpec<TRow>,\n rows: ReadonlyArray<Record<string, unknown>>,\n): ReadonlyArray<Record<string, unknown>> {\n const groupFields = new Set<string>(\n spec.groupBy === undefined\n ? []\n : (Array.isArray(spec.groupBy) ? spec.groupBy : [spec.groupBy]).map(groupKeyName),\n )\n return rows.map((row) => {\n // `derive` sees the row the way a READER would: money decoded to its\n // canonical decimal form, not the scaled integer the reducer left behind.\n // Handing over `1005` where the schema says `10.05` would make every\n // derived money expression quietly wrong by a factor of the scale.\n // `'raw'` keeps it at the exact decimal rather than a locale-formatted\n // string, which is what `exact.*` consumes.\n const view = spec.moneyFields ? decodeMoneyFields(row, spec.moneyFields, 'raw') : row\n const patch = spec.derive!(view as TRow, exactMath)\n if (patch === null || patch === undefined) return row\n for (const key of Object.keys(patch)) {\n if (groupFields.has(key)) {\n throw new MaterializedViewConfigError(\n `Materialized view \"${spec.name}\": derive() returned the group key \"${key}\". ` +\n 'A group key is the row\\'s identity and feeds rowKey — rewriting it would re-home the ' +\n 'row into a bucket it was not aggregated for. Emit a differently-named field instead.',\n )\n }\n }\n // Canonicalize the PATCH only, into the DECIMAL form the money-aware\n // reducers emit — not the scaled-integer storage form a collection uses.\n // An MV row's money fields are decimal strings, so a derived field\n // quantised into storage form reads back as the scaled integer beside\n // correctly-decoded siblings: `\"1000000\"` next to `\"10000.00\"` (#1018).\n // Precision is still enforced; only the output shape differs.\n const canonical = spec.moneyFields\n ? canonicalizeMoneyFieldsAsDecimal(patch, spec.moneyFields)\n : patch\n return { ...row, ...canonical }\n })\n}\n\n/**\n * Materialize a projection-form MV (#810): hydrate the primary source\n * rows, resolve forward FK legs through the same `.join()` machinery\n * the UNION arms use, attach reverse \"collect\" legs via one\n * hash-grouped snapshot pass per leg, then run the projection `map`\n * (null / undefined omits the primary row) and the shared post-map\n * grouping tail.\n *\n * @internal\n */\nasync function materializeProjectionResult<TRow extends Record<string, unknown>>(\n spec: MaterializedViewSpec<TRow>,\n db: MVQueryContext,\n): Promise<ReadonlyArray<Record<string, unknown>>> {\n const projection = spec.projection!\n const coll = db.collection<Record<string, unknown>>(projection.source)\n // ROOT forward legs chain through the query builder exactly like UNION arm\n // joins — ref() resolution, dangling-mode semantics, presentation dressing,\n // and ceilings all ride the existing `.join()` path. Cast to `any` for the\n // same reason `materializeUnionResult` does.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let q: any = coll.query()\n for (const leg of projection.joins) {\n if (isCollectLeg(leg) || leg.from !== undefined) continue\n q = q.join(leg.field, { as: leg.as, maxRows: leg.maxRows, strategy: leg.strategy })\n }\n let rows = q.toArray() as Array<Record<string, unknown>>\n // Remaining legs in DECLARATION order — which is what makes `from` work: a leg\n // may only name an alias declared earlier, so by the time it runs, the rows it\n // attaches to are already on the row. Root collect legs are in this loop too;\n // they were never part of the query chain.\n for (const leg of projection.joins) {\n if (isCollectLeg(leg)) {\n rows = applyCollectLeg(rows, leg, spec.name, projection.source, projection.joins, db)\n } else if (leg.from !== undefined) {\n rows = applyLegRelativeForwardLeg(rows, leg, spec.name, projection.source, projection.joins, db)\n }\n }\n const mapped: TRow[] = []\n for (const r of rows) {\n const m = projection.map(r)\n // null / undefined means \"omit this primary row\" — same contract\n // as the UNION arm `map`.\n if (m == null) continue\n mapped.push(m)\n }\n return finalizeMappedRows(spec, mapped)\n}\n\n/**\n * A `RefLookup` backed by the live join contexts — the executor's answer to the\n * same question the registry answers from the ref registry. Reads through, so a\n * ref declared after `openVault()` (the only place refs CAN be declared) is\n * visible here.\n *\n * @internal\n */\nfunction legOwnerLookup(db: MVQueryContext): RefLookup {\n return (collection, field) => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const q = db.collection<Record<string, unknown>>(collection).query() as any\n return (q._joinContext?.()?.resolveRef(field) as { target: string } | null | undefined) ?? null\n }\n}\n\n/**\n * Attach one FORWARD leg that hangs off another leg's alias (#1140).\n *\n * Root forward legs ride `Query.join()` and are resolved before this runs; a\n * leg-relative one cannot, because the FK it follows lives on an already-attached\n * record rather than on a column of the primary query. It is therefore resolved\n * the same way a collect leg is — one snapshot of the target collection, indexed\n * by id — which keeps it O(N+M) rather than one `get()` per row.\n *\n * Attaches `null` when the `from` alias is null (a dangling ref upstream), when\n * the FK is nullish, or when the target row is missing. That is deliberately\n * outer-by-nature and matches the collect leg's empty array: a projection MV\n * must not drop a primary row because something two hops away is absent.\n *\n * @internal\n */\nfunction applyLegRelativeForwardLeg(\n primaryRows: ReadonlyArray<Record<string, unknown>>,\n leg: Extract<ProjectionJoinLeg, { field: string }>,\n mvName: string,\n source: string,\n joins: ReadonlyArray<ProjectionJoinLeg>,\n db: MVQueryContext,\n): Array<Record<string, unknown>> {\n const lookup = legOwnerLookup(db)\n const owner = resolveLegOwner(leg, joins, source, lookup)\n const refDesc = owner === null ? null : lookup(owner, leg.field)\n if (owner === null || refDesc === null) {\n throw new MaterializedViewConfigError(\n `\"${mvName}\": projection leg \"${leg.as}\" requires a ref() on field \"${leg.field}\" of `\n + `collection \"${owner ?? `(behind from: \"${leg.from}\")`}\" — declare it on that collection, `\n + `then retry`,\n )\n }\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const targetQ = db.collection<Record<string, unknown>>(refDesc.target).query() as any\n const byId = new Map<string, Record<string, unknown>>()\n for (const row of targetQ.toArray() as Array<Record<string, unknown>>) {\n const id = coerceCollectKey(row.id)\n if (id !== null) byId.set(id, row)\n }\n return primaryRows.map((row) => {\n const anchor = leg.from === undefined\n ? row\n : (row[leg.from] as Record<string, unknown> | null | undefined)\n const key = anchor == null ? null : coerceCollectKey(anchor[leg.field])\n return { ...row, [leg.as]: key === null ? null : byId.get(key) ?? null }\n })\n}\n\n/**\n * Attach one reverse \"collect\" leg (#810): every row of `leg.collect`\n * whose `leg.on` field references the ATTACH POINT's id lands in a\n * possibly-empty ARRAY under `leg.as` on that primary row. One\n * snapshot pass over the collect collection, hash-grouped by the `on`\n * FK — O(N+M), mirroring the forward hash-join fallback.\n *\n * The attach point is the primary record, or — with `from` (#1140) — the record\n * already attached under that alias. Matching then keys off `row[from].id`\n * instead of `row.id`, and `leg.on` must ref THAT leg's collection. A row whose\n * `from` alias is null (a dangling forward ref) gets `[]`, which is the same\n * outer-by-nature semantics a root collect leg already has for a primary record\n * with no children.\n *\n * Semantic check (first materialization, not factory time — parity\n * with join-time ref errors): `leg.on` must carry a `ref()` declared\n * on the collect collection targeting the attach point's collection.\n *\n * @internal\n */\nfunction applyCollectLeg(\n primaryRows: ReadonlyArray<Record<string, unknown>>,\n leg: { readonly collect: string; readonly on: string; readonly as: string; readonly from?: string; readonly maxRows?: number },\n mvName: string,\n source: string,\n joins: ReadonlyArray<ProjectionJoinLeg>,\n db: MVQueryContext,\n): Array<Record<string, unknown>> {\n const childColl = db.collection<Record<string, unknown>>(leg.collect)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const childQ = childColl.query() as any\n const refDesc = childQ._joinContext?.()?.resolveRef(leg.on) as { target: string } | null | undefined\n // The collection this leg matches AGAINST: the projection source for a root\n // leg, the `from` leg's own target otherwise (#1140).\n const expected = resolveLegOwner(leg, joins, source, legOwnerLookup(db))\n const expectedName = expected ?? source\n if (refDesc == null) {\n throw new MaterializedViewConfigError(\n `\"${mvName}\": projection collect leg \"${leg.as}\" requires a ref() on field \"${leg.on}\" of `\n + `collection \"${leg.collect}\" targeting \"${expectedName}\" — declare `\n + `refs: { ${leg.on}: ref('${expectedName}') } on collection \"${leg.collect}\", then retry`,\n )\n }\n if (refDesc.target !== expectedName) {\n throw new MaterializedViewConfigError(\n `\"${mvName}\": projection collect leg \"${leg.as}\" expects field \"${leg.on}\" of collection `\n + `\"${leg.collect}\" to reference ${leg.from === undefined\n ? `the projection source \"${expectedName}\"`\n : `\"${expectedName}\" (the collection behind from: \"${leg.from}\")`}`\n + `, but its ref() targets \"${refDesc.target}\"`,\n )\n }\n const maxRows = leg.maxRows ?? DEFAULT_JOIN_MAX_ROWS\n const groups = new Map<string, Array<Record<string, unknown>>>()\n for (const child of childQ.toArray() as Array<Record<string, unknown>>) {\n const key = coerceCollectKey(child[leg.on])\n // Nullish / non-scalar FK values mean \"no reference\" — same\n // narrowing as the forward join path's key coercion.\n if (key === null) continue\n const bucket = groups.get(key)\n if (bucket) bucket.push(child)\n else groups.set(key, [child])\n }\n const out: Array<Record<string, unknown>> = []\n for (const row of primaryRows) {\n // `from` matches against the attached record's id, not the primary row's.\n const anchor = leg.from === undefined\n ? row\n : (row[leg.from] as Record<string, unknown> | null | undefined)\n const key = anchor == null ? null : coerceCollectKey(anchor.id)\n const children = key === null ? [] : groups.get(key) ?? []\n if (children.length > maxRows) {\n throw new JoinTooLargeError({\n leftRows: primaryRows.length,\n rightRows: children.length,\n maxRows,\n side: 'right',\n message:\n `projection MV \"${mvName}\": collect leg \"${leg.as}\" gathered ${children.length} ` +\n `\"${leg.collect}\" rows for one \"${source}\" record, exceeding the ${maxRows}-row ` +\n `per-primary-row ceiling. Raise the ceiling via { maxRows } on the leg if the ` +\n `fan-out genuinely fits in memory, or restructure the child collection.`,\n })\n }\n out.push({ ...row, [leg.as]: children })\n }\n return out\n}\n\n/**\n * Coerce an unknown FK value into a collect-grouping key. Same\n * narrowing as the join path's `coerceRefKey` (not exported from\n * there): strings and numbers are legitimate ref values; anything\n * else is \"no reference\" and returns `null`.\n *\n * @internal\n */\nfunction coerceCollectKey(value: unknown): string | null {\n if (value === null || value === undefined) return null\n if (typeof value === 'string') return value\n if (typeof value === 'number' || typeof value === 'bigint') return String(value)\n return null\n}\n\n/**\n * Run an MV's `query()` and write the result rows to the output\n * collection. Same-DEK encryption: routes through the standard\n * `Collection.put` pipeline, so the output collection's DEK is what\n * gets used (matches the v2 spec's \"same DEK as the left-most source\"\n * invariant — `Collection.put` looks up the DEK by collection name,\n * and the output collection IS the MV's owned collection).\n *\n * Stamps `_materializedFrom` onto every emitted row.\n *\n * **Tombstoning:** when `spec.onEmpty: 'delete'` (default), rows\n * that existed in a prior refresh but no longer appear in the new\n * materialized result are deleted via `Collection._internalDelete` —\n * the housekeeping bypass primitive prevents user\n * `onDelete` guards on the output collection from firing on these\n * system-internal deletes. `onEmpty: 'keep'` opts out (rows from\n * prior refreshes linger even when the new result lacks them).\n *\n * **Cost ceiling:** if the materialized row count exceeds\n * `spec.maxRows` (default 100k), throws `MaterializedViewTooLargeError`\n * before any writes hit the store — so strict-mode rollback is\n * clean.\n *\n * **Strict mode:** `spec.strict === true` re-throws on any\n * row-write failure; the active TxContext registration means the\n * source-write rolls back atomically via `revertExecuted`.\n *\n * @internal\n */\nexport const MaterializedViewExecutor = {\n async refresh(\n reg: RegisteredMV,\n accessor: MVExecutorAccessor,\n ): Promise<RefreshResult> {\n const spec = reg.spec\n const outputColl = accessor.getCollection(reg.outputCollection)\n const maxRows = spec.maxRows ?? DEFAULT_MAX_ROWS\n const onEmpty = spec.onEmpty ?? 'delete'\n const strict = spec.strict ?? false\n\n // 1. Materialize the query (branches on terminal shape). If the\n // MV declared predicates, wrap the query context the same way\n // the registry did at registration time so `.wherePredicate()`\n // calls resolve to the registered functions.\n // #1414 — `ungatedMvContext` keeps the engine's synchronous source reads\n // exactly as they were before the cold-collection gate existed.\n const baseCtx = ungatedMvContext(accessor.getQueryContext())\n const ctxForQuery: MVQueryContext = spec.predicates\n ? wrapDbWithPredicates(baseCtx, spec.predicates)\n : baseCtx\n // UNION-form strategies: read every arm, map to the unified\n // row shape, concatenate, then optionally groupBy + aggregate.\n // Projection-form strategies (#810): hydrate the primary source,\n // attach forward + collect legs, map, then the same optional\n // grouping tail. The single-source `query()` path is untouched.\n let rows: ReadonlyArray<Record<string, unknown>>\n if (spec.unionSources) {\n rows = await materializeUnionResult(spec, ctxForQuery)\n } else if (spec.projection) {\n rows = await materializeProjectionResult(spec, ctxForQuery)\n } else {\n const q = spec.query!(ctxForQuery)\n rows = await materializeQueryResult(q, spec.name, spec.i18nLocale, spec.i18nFields)\n }\n\n // #1007 — the post-aggregate projection. Applied here, after every form has\n // produced its finished rows, so union / projection / query all get the\n // same single definition of \"last step before materialisation\".\n if (spec.derive) rows = applyDerive(spec, rows)\n\n // #777 — exclude this MV's OWN previously-stamped output rows from the\n // input scan. A same-collection Query-form MV copies the whole source row\n // verbatim into its output, so a stale output row can itself satisfy the\n // MV's own input filter (when the filter is on a field disjoint from the\n // partition field) and get re-selected as if it were live source — the\n // row self-perpetuates after its true source is gone. Prior output is\n // never this MV's own source.\n rows = rows.filter((row) => {\n const stamp = row._materializedFrom as { mvName?: string } | undefined\n return stamp?.mvName !== spec.name\n })\n\n // 2. Cost ceiling check BEFORE any writes — keeps the rollback\n // clean if the source-write is wrapped in a transaction.\n if (rows.length > maxRows) {\n throw new MaterializedViewTooLargeError(spec.name, rows.length, maxRows)\n }\n\n const txCtx = accessor.getActiveTxContext()\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const adapter = (outputColl as any).adapter as {\n get(v: string, c: string, i: string): Promise<EncryptedEnvelope | null>\n }\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const vaultName = (outputColl as any).vault as string\n\n // 3. Compute the post-refresh id set so we can diff against the\n // prior-emitted id set for tombstoning (when onEmpty === 'delete').\n const newIds = new Set<string>()\n const enrichedRows: Array<{ id: string; record: Record<string, unknown> }> = []\n for (const row of rows) {\n const id = spec.rowKey(row)\n newIds.add(id)\n const meta: MaterializedFromMeta = {\n mvName: spec.name,\n queryHash: reg.queryHash,\n sourceVersions: {},\n materializedAt: new Date().toISOString(),\n }\n enrichedRows.push({ id, record: { ...row, _materializedFrom: meta } })\n }\n\n // 4. Write the new rows — skipping any whose content is unchanged (#1418).\n //\n // ⛔ THE OUTPUT ROW COUNT, NOT THE SOURCE SCAN, IS WHAT MADE THIS EXPENSIVE.\n // This loop used to encrypt-and-store EVERY row of the view on EVERY source\n // write, so per-write cost tracked the size of the view: measured 23 ms at\n // 250 output rows and 41.6 ms at 450, for source writes the MV's own `map`\n // dropped entirely. Comparing against what this MV last wrote turns \"one\n // source write rewrites the whole view\" into \"one source write rewrites the\n // groups that moved\". See `emit-memo.ts` for why this, and not a\n // predict-whether-the-refresh-is-needed short circuit.\n const memoKey = emitMemoKey(vaultName, spec.name, reg.outputCollection)\n // Read the stamp BEFORE writing: it has to describe the collection as this\n // refresh found it, so a write by anyone else since last time invalidates.\n const priorEmitted = readEmitMemo(memoKey, outputColl._cacheStamp)\n const emitted = new Map<string, string>()\n\n let written = 0\n let skipped = 0\n let failed = 0\n for (const { id, record } of enrichedRows) {\n const contentKey = rowContentKey(record, reg.queryHash)\n // ⚠️ A txCtx changes what a \"skip\" means: the rollback journal below\n // needs an entry for every row the transaction could revert, and a row we\n // never wrote has nothing to revert TO. Rather than reason about partial\n // journals, the memo stands down inside a transaction entirely.\n // #1439 — and only when no `beforePut` gate can fire FOR THIS ROW. Asking\n // the bus \"is anything registered\" instead disabled the skip for every\n // collection in any vault carrying a guard or a periods strategy —\n // measured by the reporter at 54 redundant writes per source write with\n // guards alone, which is close to every real consumer.\n if (\n contentKey !== null && txCtx === null\n && !outputColl._derivedWriteGated(record)\n && priorEmitted?.get(id) === contentKey\n ) {\n skipped++\n emitted.set(id, contentKey)\n continue\n }\n try {\n if (txCtx !== null) {\n const prior = await adapter.get(vaultName, reg.outputCollection, id)\n txCtx._executed.push({\n op: { type: 'put', vaultName, collectionName: reg.outputCollection, id },\n priorEnvelope: prior,\n })\n }\n let landed = false\n if (accessor.dispatchCtx) {\n if (await putDerivedOutput(outputColl, id, record, accessor.dispatchCtx) === 'written') {\n written++\n landed = true\n }\n } else {\n await outputColl.put(id, record)\n written++\n landed = true\n }\n // ⛔ ONLY a write that actually landed is remembered. `putDerivedOutput`\n // declines inside a frozen period, and recording that row would make\n // every later refresh skip a row that is not there.\n if (landed && contentKey !== null) emitted.set(id, contentKey)\n } catch (err) {\n failed++\n if (strict) throw err\n \n console.warn(`[mv] \"${spec.name}\" row write failed:`, err)\n }\n }\n\n // 5. Tombstone rows that existed before but don't appear now.\n // `onEmpty: 'keep'` skips this pass entirely. Uses\n // `_internalDelete` so a user-registered `onDelete` on the\n // output collection does NOT fire on housekeeping (composition fix).\n let deleted = 0\n const residueUndecodable: string[] = []\n const residueDeclined: string[] = []\n if (onEmpty === 'delete') {\n const priorIds = await listOutputIds(outputColl)\n for (const priorId of priorIds) {\n if (newIds.has(priorId)) continue\n // #762 — a same-collection partition MV (`output: { collection: <source>, partition }`,\n // the DERIV-PP30-001 shape) writes INTO its own source collection, so `listOutputIds`\n // also returns untouched USER source rows here. Decode each candidate and only\n // tombstone rows THIS MV stamped via `_materializedFrom.mvName` — the exact discipline\n // `invalidateMVAtRest` uses (stale.ts:151-162). An unstamped row, or one stamped by a\n // different MV, is never this MV's to delete.\n const priorEnvelope = await adapter.get(vaultName, reg.outputCollection, priorId)\n if (priorEnvelope === null) continue\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const priorDecoded = await (outputColl as any)._decodeEnvelope(priorEnvelope, priorId)\n if (priorDecoded === null) {\n // #782 part a — ownership unknown (undecodable, e.g. elevated above tier 0 on a\n // tiered output collection): can't rule out this being THIS MV's own stamped row.\n // Surface it rather than silently skip (mirrors invalidateMVAtRest's #776 posture —\n // previously this leg had NO residue channel at all).\n residueUndecodable.push(`${reg.outputCollection}:${priorId}`)\n continue\n }\n const priorStampedBy =\n typeof priorDecoded === 'object'\n ? (priorDecoded as Record<string, unknown>)._materializedFrom as { mvName?: string } | undefined\n : undefined\n if (priorStampedBy?.mvName !== spec.name) continue\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const outAny = outputColl as any\n if (typeof outAny._internalDelete === 'function') {\n // #776 part b — gate on the boolean, matching invalidateMVAtRest's discipline\n // (stale.ts): `_internalDelete` returns `false` for a #718 elevated-skip (no\n // erasure happened), and that must not inflate the tombstone count.\n if (await outAny._internalDelete(priorId, txCtx)) {\n deleted++\n } else {\n // #782 part b — decoded AND stamp-owned, but erasure was declined (#718\n // tier-elevation gate). Ownership IS confirmed here — a real silent survival,\n // not a legit stamp-mismatch skip. Surface it too.\n residueDeclined.push(`${reg.outputCollection}:${priorId}`)\n }\n } else {\n // Defensive fallback — should never hit in real flow since\n // every Collection has `_internalDelete`.\n await outputColl.delete(priorId)\n deleted++\n }\n } catch (err) {\n failed++\n if (strict) throw err\n\n console.warn(`[mv] \"${spec.name}\" tombstone failed for id=\"${priorId}\":`, err)\n }\n }\n }\n\n // Record the stamp AFTER every write and tombstone, so the next refresh's\n // check means \"nothing has happened to this collection since I finished\".\n // A row that failed, was declined, or was tombstoned is simply absent from\n // `emitted` and will be written again.\n writeEmitMemo(memoKey, outputColl._cacheStamp, emitted)\n\n return { written, skipped, deleted, failed, residueUndecodable, residueDeclined }\n },\n}\n\n/**\n * List ids currently present in the MV's output collection via the\n * adapter directly (avoids triggering the lazy resolve-on-read path\n * we're INSIDE). Returns an empty array if the collection doesn't\n * exist or the adapter doesn't surface a list method.\n *\n * @internal\n */\nasync function listOutputIds(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n outputColl: Collection<any>,\n): Promise<string[]> {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const cAny = outputColl as any\n const adapter = cAny.adapter as { list?: (v: string, c: string) => Promise<readonly string[]> }\n const vault = cAny.vault as string\n const name = cAny.name as string\n if (typeof adapter?.list !== 'function') return []\n try {\n const ids = await adapter.list(vault, name)\n return [...ids]\n } catch {\n return []\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
installViaBinder
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-Z5HTYMMQ.js";
|
|
4
4
|
import {
|
|
5
5
|
SealedHandle
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-ODVPTDPK.js";
|
|
7
7
|
import {
|
|
8
8
|
ClassifiedConfigError,
|
|
9
9
|
ClassifiedNotEnabledError
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-244VXYPG.js";
|
|
11
11
|
|
|
12
12
|
// src/via/classified/descriptor.ts
|
|
13
13
|
function isClassifiedFieldSpec(x) {
|
|
@@ -218,6 +218,8 @@ function classifiedVia(cfg) {
|
|
|
218
218
|
brand: "classified",
|
|
219
219
|
posture: { encryptedAtRest: "sealed", queryable: "det-exact", exportable: false, forgettable: true },
|
|
220
220
|
covers: (field) => field in byField,
|
|
221
|
+
coveredFields: Object.keys(byField),
|
|
222
|
+
// #1447 — the FIELD only; the sensitivity label is deliberately NOT reported
|
|
221
223
|
// async (rather than a bare passthrough) so a refusal is always a
|
|
222
224
|
// rejected Promise for direct callers, matching every other async-stack
|
|
223
225
|
// hook's calling convention — `enforceClassifiedWrite` itself stays sync.
|
|
@@ -262,4 +264,4 @@ export {
|
|
|
262
264
|
enforceClassifiedWrite,
|
|
263
265
|
NO_CLASSIFIED
|
|
264
266
|
};
|
|
265
|
-
//# sourceMappingURL=chunk-
|
|
267
|
+
//# sourceMappingURL=chunk-QOOUUR4A.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/via/classified/descriptor.ts","../src/via/classified/errors.ts","../src/via/classified/resolve.ts","../src/via/classified/write.ts","../src/via/classified/guards.ts","../src/via/classified/binding.ts","../src/port/with/classified-strategy.ts"],"sourcesContent":["/**\n * Classified fields — behavioral sensitive-field descriptors (stage 1).\n * Design: design-history/2026-07-04-classified-fields-design.md\n * Law: open on write, declarative on read — read-side behavior is this\n * closed vocabulary; there are no read-side callbacks.\n * @module\n */\n\nexport type ClassifiedStorage = 'recoverable' | 'never' | 'digest-only'\n\nexport type ClassifiedList =\n | { readonly kind: 'omit' }\n | { readonly kind: 'mask'; readonly pattern: string }\n | { readonly kind: 'rider'; readonly rider: string }\n\nexport type ClassifiedRider = (value: unknown) => unknown\n\nexport interface ClassifiedFieldSpec {\n readonly _noydbClassified: true\n /**\n * Via port brand marker — lets a `ClassifiedFieldSpec` satisfy the\n * kernel's opaque `ViaDescriptor` (#629 Task 5). Optional (unlike\n * `MoneyDescriptor._viaBrand`/`I18nTextDescriptor._viaBrand`, which are\n * required): every `classified.*()` preset factory stamps it, but the\n * pre-existing test suite's hand-rolled `ClassifiedFieldSpec` fixtures\n * (built without going through a preset) predate this field and would\n * fail to compile if it were mandatory.\n */\n readonly _viaBrand?: 'classified'\n readonly preset: string\n readonly storage: ClassifiedStorage\n readonly list: ClassifiedList\n readonly sensitivity: 'pii' | 'secret'\n /** Write-time safe projections; companion field name is `<field>_<rider>`. */\n readonly riders?: Record<string, ClassifiedRider>\n /** Write-time validator: error message, or null when valid. */\n readonly validate?: (value: unknown) => string | null\n /** Digest-only verify policy (stage 2). Mode both sides normalize under. */\n readonly verifyNormalize?: 'password' | 'secret-answer'\n /** Decorate ok:true verdicts with mustRotate after this many days (I1). */\n readonly rotateDays?: number\n /** Refuse reuse of the last N values on rotate (cap 8, spec Q4). */\n readonly notLastN?: number\n /** Member of the collection's matchGroup (secretAnswer preset). */\n readonly verifyGroupMember?: true\n /**\n * Opt into a store-visible blind-index (`_bidx`) tag so equal values become\n * queryable/joinable while staying digest-only. Digest-only knob (R7); gated\n * behind the collection's `acknowledgeEquatableRisk` door (R8). Equal values\n * produce equal tags — a partition leak a DEK holder can offline-dictionary\n * at the PBKDF2 floor. Absent/false ⇒ refused-by-default.\n */\n readonly equatable?: true\n}\n\nexport interface ClassifiedGroup {\n readonly _noydbClassifiedGroup: true\n /** Via port brand marker — see {@link ClassifiedFieldSpec._viaBrand}. */\n readonly _viaBrand?: 'classified'\n readonly preset: string\n /** member record-field name -> spec (differential per-member policy). */\n readonly members: Record<string, ClassifiedFieldSpec>\n}\n\nexport type ClassifiedEntry = ClassifiedFieldSpec | ClassifiedGroup\n\nexport function isClassifiedFieldSpec(x: unknown): x is ClassifiedFieldSpec {\n return typeof x === 'object' && x !== null\n && (x as { _noydbClassified?: unknown })._noydbClassified === true\n}\n\nexport function isClassifiedGroup(x: unknown): x is ClassifiedGroup {\n return typeof x === 'object' && x !== null\n && (x as { _noydbClassifiedGroup?: unknown })._noydbClassifiedGroup === true\n}\n","/**\n * Configuration/write errors for classified fields. @module\n *\n * `ClassifiedConfigError` / `ClassifiedRevealError` moved to `kernel/errors.ts`\n * (stage 2) so `kernel/enclave/classify/*` can throw them without importing\n * with-*. Re-exported here under the same names so existing import paths\n * keep working.\n */\nexport { ClassifiedConfigError, ClassifiedRevealError, ClassifiedVerifyError, ClassifiedRotationError } from '../../kernel/errors.js'\n\nexport class ClassifiedNeverStoredError extends Error {\n constructor(public readonly collection: string, public readonly field: string) {\n super(`Field \"${field}\" in collection \"${collection}\" is classified storage:'never' `\n + `(e.g. a CVC) and must not be persisted. Validate it at capture and drop it before put().`)\n this.name = 'ClassifiedNeverStoredError'\n }\n}\n\nexport class ClassifiedValidationError extends Error {\n constructor(public readonly collection: string, public readonly field: string, detail: string) {\n super(`Classified field \"${field}\" in collection \"${collection}\" failed validation: ${detail}`)\n this.name = 'ClassifiedValidationError'\n }\n}\n","/** Flatten a classifiedFields config into a per-field map + rider computed entries. @module */\n\nimport { isClassifiedGroup, type ClassifiedEntry, type ClassifiedFieldSpec } from './descriptor.js'\nimport { ClassifiedConfigError } from './errors.js'\n\nexport type { ClassifiedEntry, ClassifiedFieldSpec, ClassifiedGroup, ClassifiedList } from './descriptor.js'\nexport { ClassifiedConfigError } from './errors.js'\n\nexport interface ResolvedClassified {\n readonly byField: Record<string, ClassifiedFieldSpec>\n readonly riderComputed: Record<string, (record: Record<string, unknown>) => unknown>\n}\n\nexport function resolveClassifiedFields(\n collection: string,\n config: Record<string, ClassifiedEntry>,\n): ResolvedClassified {\n const byField: Record<string, ClassifiedFieldSpec> = {}\n const claim = (field: string, spec: ClassifiedFieldSpec): void => {\n if (byField[field] !== undefined) {\n throw new ClassifiedConfigError(collection,\n `field \"${field}\" is claimed twice — storage forms are mutually exclusive per field (R5): ` +\n `a field is digest-only OR recoverable OR never, exactly one`)\n }\n byField[field] = spec\n }\n for (const [key, entry] of Object.entries(config)) {\n if (isClassifiedGroup(entry)) {\n for (const [field, spec] of Object.entries(entry.members)) claim(field, spec)\n } else {\n claim(key, entry)\n }\n }\n const riderComputed: Record<string, (record: Record<string, unknown>) => unknown> = {}\n for (const [field, spec] of Object.entries(byField)) {\n for (const [name, rider] of Object.entries(spec.riders ?? {})) {\n const companion = `${field}_${name}`\n if (byField[companion] !== undefined || riderComputed[companion] !== undefined) {\n throw new ClassifiedConfigError(collection, `rider companion \"${companion}\" collides with a declared field`)\n }\n riderComputed[companion] = (record) =>\n record[field] === undefined ? undefined : rider(record[field])\n }\n }\n return { byField, riderComputed }\n}\n","/** Write-path enforcement: storage:'never' rejection + preset validators.\n * Runs BEFORE riders/computed and BEFORE schema validation. Pure. @module */\n\nimport type { ClassifiedFieldSpec } from './descriptor.js'\nimport { ClassifiedNeverStoredError, ClassifiedValidationError } from './errors.js'\n\nexport function enforceClassifiedWrite(\n record: Record<string, unknown>,\n byField: Record<string, ClassifiedFieldSpec>,\n collection: string,\n): void {\n for (const [field, spec] of Object.entries(byField)) {\n const value = record[field]\n if (value === undefined) continue\n if (value === null && spec.storage === 'digest-only') continue // explicit clear (C6 branch 3)\n if (spec.storage === 'never') throw new ClassifiedNeverStoredError(collection, field)\n const problem = spec.validate?.(value) ?? null\n if (problem !== null) throw new ClassifiedValidationError(collection, field, problem)\n }\n}\n","/**\n * Refusal matrix R1-R5 (spec) — ONE guard, run at BOTH doors:\n * `collection()` config resolution AND `_applyClassifiedFields` (the reconcile\n * seam), because crdt/conflictPolicy/perRecordKeys are construction-only\n * while classifiedFields can attach later (C5's lesson). @module\n */\nimport type { ClassifiedFieldSpec } from './descriptor.js'\nimport { ClassifiedConfigError } from '../../kernel/errors.js'\n\nexport interface ClassifiedGuardCtx {\n readonly perRecordKeys: boolean\n readonly crdt: boolean\n readonly hasConflictPolicy: boolean\n /** False on plaintext (`encrypt: false`) collections — no vdig/seal path exists. */\n readonly storeCiphertext: boolean\n readonly deterministicFields: ReadonlySet<string> | null\n readonly indexedFields: ReadonlySet<string>\n readonly textIndexFields: ReadonlySet<string>\n readonly vectorSourceFields: ReadonlySet<string>\n readonly subjectKeyField: string | undefined\n readonly bareSensitiveFields: ReadonlySet<string>\n /** Collection-level gate for the `equatable` knob (R8 double door). */\n readonly acknowledgeEquatableRisk: boolean\n}\n\nexport function guardClassifiedCompat(\n collection: string,\n byField: Record<string, ClassifiedFieldSpec>,\n ctx: ClassifiedGuardCtx,\n): void {\n const digestOnly = Object.entries(byField)\n .filter(([, s]) => s.storage === 'digest-only')\n const protectedForms = Object.values(byField)\n .filter((s) => s.storage === 'digest-only' || s.storage === 'recoverable')\n\n // R2 — merge resolvers bypass the write pipeline entirely (C5): a merge\n // could carry stale/foreign _vdig or resurrect plaintext (the CRDT put\n // branch persists via encryptJsonString with no vdig backstop). Fail-loud.\n if (protectedForms.length > 0 && (ctx.crdt || ctx.hasConflictPolicy)) {\n throw new ClassifiedConfigError(collection,\n 'digest-only/recoverable classified fields cannot combine with a crdt mode or a ' +\n 'conflictPolicy resolver — merge paths bypass write enforcement (R2)')\n }\n // R7 — `equatable` is a digest-only knob: it drives the `_bidx` blind-index\n // slot, which only exists on the digest-only write path. A recoverable/never\n // field carrying it would silently no-op (recoverable equality is `_det`'s\n // job). Refuse rather than accept-and-ignore. Checked over ALL specs, before\n // the digest-only early-return below, precisely to catch the non-digest case.\n for (const [f, spec] of Object.entries(byField)) {\n if (spec.equatable === true && spec.storage !== 'digest-only') {\n throw new ClassifiedConfigError(collection,\n `field \"${f}\" declares equatable but storage is '${spec.storage}' — equatable is a ` +\n `digest-only knob; recoverable equality is _det's job (R7)`)\n }\n }\n\n // R8 — the equatable double door (mirrors deterministicFields ×\n // acknowledgeDeterministicRisk): any field opting into `equatable` requires\n // the collection to acknowledge the partition-leak risk. One-directional —\n // `acknowledgeEquatableRisk: true` with ZERO equatable members is a silent\n // no-op (never throws here), so the ack can sit on a collection config\n // ahead of the field landing.\n const hasEquatable = Object.values(byField).some((s) => s.equatable === true)\n if (hasEquatable && ctx.acknowledgeEquatableRisk !== true) {\n throw new ClassifiedConfigError(collection,\n `classified equatable fields require \\`acknowledgeEquatableRisk: true\\` — equal values ` +\n `produce equal store-visible index tags (a partition leak a DEK holder can offline-` +\n `dictionary at the PBKDF2 floor); the door is the real control for low-entropy fields (R8)`)\n }\n\n if (digestOnly.length === 0) return\n\n // Digest-only on a plaintext collection: the codec's vdig block is gated on\n // storeCiphertext, so the secret would persist as raw plaintext. Refuse.\n if (!ctx.storeCiphertext) {\n throw new ClassifiedConfigError(collection,\n `storage:'digest-only' requires an encrypted collection — with encrypt: false the ` +\n `write path skips the digest slot entirely and the secret would persist as raw plaintext`)\n }\n // R1 — vdig slot keys are CEK-only (I3); without perRecordKeys a digest\n // would survive forget() in backups as offline-crackable material.\n if (!ctx.perRecordKeys) {\n throw new ClassifiedConfigError(collection,\n `storage:'digest-only' requires perRecordKeys: true — vdig keys derive from the ` +\n `per-record CEK so forget() shreds them (R1)`)\n }\n for (const [f, spec] of digestOnly) {\n // notLastN cap: presets clamp this at construction, but a raw spec object\n // bypasses the preset — enforce the same 0..8 cap in the policy projection.\n const n = spec.notLastN ?? 0\n if (!Number.isInteger(n) || n < 0 || n > 8) {\n throw new ClassifiedConfigError(collection,\n `digest-only field \"${f}\" declares notLastN ${n} — must be an integer 0..8 ` +\n `(write cost is n × 600K PBKDF2; ring blast radius is documented)`)\n }\n if (ctx.bareSensitiveFields.has(f)) {\n // R5 — the sealed block runs before the vdig block in the codec, so the\n // overlap would seal the value recoverably (silent downgrade + I4\n // double-slot). Storage forms are mutually exclusive per field.\n throw new ClassifiedConfigError(collection,\n `field \"${f}\" is digest-only AND listed in sensitive[] — storage forms are mutually exclusive per field (R5)`)\n }\n if (ctx.deterministicFields?.has(f)) {\n throw new ClassifiedConfigError(collection,\n `digest-only field \"${f}\" cannot be deterministic — equality-correlatable ciphertext defeats per-write salts (R3)`)\n }\n if (ctx.indexedFields.has(f) || ctx.textIndexFields.has(f)\n || ctx.vectorSourceFields.has(f) || ctx.subjectKeyField === f) {\n throw new ClassifiedConfigError(collection,\n `digest-only field \"${f}\" cannot be indexed, text-indexed, embedded, or a forget-subject key (R4)`)\n }\n }\n}\n","/**\n * The classified `NoydbVia` (#629 Task 5, LIVE since Task 6) — wires\n * classified-fields declaration/write-enforcement/at-rest sealing/erasure\n * into the kernel's generic Via port. Mirrors `via/money/binding.ts`'s\n * inline declaration-time validation and `via/i18n/binding.ts`'s\n * `linkXVia` static-link pattern — except the link itself is EAGER\n * (`port/with/classified-strategy.ts` calls `linkClassifiedVia()` at module\n * load, not lazily from a `classified.*()` preset call): several fixtures\n * build a raw `ClassifiedFieldSpec` literal without ever calling a preset,\n * and the binder must be installed before `compileVias` needs it\n * regardless.\n *\n * `compileVias` (`kernel/collection-config.ts`) compiles this binding\n * in whenever a collection declares `classifiedFields` — money then i18n\n * then classified, order pinned. `kernel/collection.ts`'s `_putInternal`\n * runs `enforceClassifiedWrite`'s effect via the pipeline's `enforceWrite`\n * phase; the codec's `encodeAtRest`/`decodeAtRest` hooks (Task 3's boundary)\n * replace the inline `sensitiveFields` seal path for any collection this\n * binding is compiled into.\n *\n * `declare` — `classifiedVia(cfg)` runs `resolveClassifiedFields` +\n * `guardClassifiedCompat` at CONSTRUCTION time (the same #553 pattern\n * `moneyVia`'s `validateMoneyFieldPaths(moneyFields)` call uses) —\n * mirrors today's \"door 1\" (`collection-config.ts`'s\n * `resolveCollectionConfig`). Both may throw `ClassifiedConfigError`.\n */\nimport type { NoydbVia, ViaWriteCtx, ViaCryptoCtx, SealedSlotRef, ViaEraseCtx, ViaEraseReport } from '../../kernel/via/index.js'\nimport { installViaBinder } from '../../kernel/via/index.js'\nimport { SealedHandle } from '../../kernel/types.js'\nimport { resolveClassifiedFields, type ClassifiedEntry } from './resolve.js'\nimport { guardClassifiedCompat, type ClassifiedGuardCtx } from './guards.js'\nimport { enforceClassifiedWrite } from './write.js'\nimport type { ClassifiedFieldSpec } from './descriptor.js'\n\n/**\n * One classified per-slot shred/residue verdict — mirrors\n * `RecordCodec.SealedShredSlot` (`kernel/enclave/record-keys/record-codec.ts`)\n * byte-for-byte. Duplicated here (not imported) so this binding never\n * reaches into `kernel/enclave/` (`via-enclave-isolation`, #629) — the\n * closure that PRODUCES real values of this shape is codec-owned and\n * injected via {@link ClassifiedViaConfig.classifySealedShred}.\n */\nexport interface ClassifiedShredSlot {\n readonly field: string\n readonly class: 'shreddable' | 'dekResidue' | 'live-shreddable+dekResidue-in-backups'\n}\n\n/**\n * Config a classified collection's declarations resolve to — the binding's\n * construction input. `entries`/`guardCtx` are the raw \"door 1\" inputs\n * (`resolveClassifiedFields`/`guardClassifiedCompat`'s own parameters);\n * `classifySealedShred`/`purgeSealedCekEnvelopes` are OPTIONAL codec/vault-\n * provided closures for the `erase` hook — undefined in this dormant task\n * (no caller wires them yet), wired for real in #629 Task 10 (\"posture\n * enforcement — forget + erase hooks live\").\n */\nexport interface ClassifiedViaConfig {\n readonly entries: Record<string, ClassifiedEntry>\n readonly collectionName: string\n readonly guardCtx: ClassifiedGuardCtx\n /**\n * Codec-provided closure mirroring `RecordCodec.classifySealedShred` —\n * classifies a live envelope's `_sealed` slots for crypto-shred\n * completeness (see that method's doc comment for the shreddable/\n * dekResidue/both-class semantics). `live` is `ViaEraseCtx.live`'s opaque\n * envelope, passed straight through. NOT `readonly` (#629 Task 10):\n * `compileVias` builds this cfg before the owning `Collection`'s\n * `RecordCodec` exists, so `Collection`'s constructor mutates this field\n * in place once `this.codec` is available — the closure `eraseClassified`\n * reads is looked up at CALL time, not at binding-construction time, so\n * the late assignment is picked up correctly.\n */\n classifySealedShred?: (live: unknown) => Promise<{ readonly slots: readonly ClassifiedShredSlot[] }>\n /**\n * Vault-provided closure that purges every `_sealed_cek/<collection>/<id>/*`\n * host-delivery envelope for one record (mirrors `rotateRecordCek`'s own\n * prefix-delete) and returns the count purged. Deliberately left UNWIRED\n * by `compileVias` (#629 Task 10) — `forget-sealed-erasure.test.ts`\n * proves this purge is UNCONDITIONAL on `sealRecordToHost` usage alone,\n * independent of whether `classifiedFields` is declared (a bare\n * `sensitive: [...]` collection exercises it with no classified binding\n * at all) — vault.ts keeps owning it directly so that case stays correct.\n */\n readonly purgeSealedCekEnvelopes?: (id: string) => Promise<number>\n}\n\n/** Fields declared `storage: 'recoverable'` (digest-only stays codec-inline; `'never'` is rejected by `enforceWrite` before either hook runs). */\nfunction recoverableFields(byField: Record<string, ClassifiedFieldSpec>): string[] {\n return Object.entries(byField).filter(([, spec]) => spec.storage === 'recoverable').map(([field]) => field)\n}\n\n/**\n * The full set this binding's `encodeAtRest`/`decodeAtRest` seal: declared\n * recoverable classified fields UNION bare `sensitive[]` fields — mirrors\n * `collection-config.ts`'s pre-cutover \"recoverable classified fields are\n * unioned into sensitiveFields... zero new crypto code\" semantics. Once this\n * binding is compiled into a collection's pipeline, `hasAtRestHooks` is true\n * and the codec's inline `sensitiveFields` seal path (record-codec.ts) is\n * DEAD for that collection — mutually exclusive with the hook path (#629\n * Task 3) — so bare `sensitive[]` fields MUST seal through here too, or\n * they'd silently stop being sealed at all (#629 Task 6 reconciliation).\n * `guardCtx.bareSensitiveFields` is the exact same `Set` the collection's\n * refusal-matrix guard already carries (`ClassifiedGuardCtx`).\n */\nfunction sealFieldNames(byField: Record<string, ClassifiedFieldSpec>, guardCtx: ClassifiedGuardCtx): string[] {\n return [...recoverableFields(byField), ...guardCtx.bareSensitiveFields]\n}\n\n/**\n * Seal every named field present with a defined value into its own sealed\n * slot via `crypto.sealedSlots`, peeling it out of the record.\n */\nasync function encodeClassifiedAtRest(\n record: Record<string, unknown>,\n crypto: ViaCryptoCtx,\n fields: readonly string[],\n): Promise<{ record: Record<string, unknown>; sealed?: Record<string, SealedSlotRef> }> {\n let open = record\n let sealed: Record<string, SealedSlotRef> | undefined\n for (const field of fields) {\n if (!(field in record)) continue\n const value = record[field]\n if (value === undefined) continue\n const ref = await crypto.sealedSlots.seal(field, value)\n if (open === record) open = { ...record }\n delete open[field]\n sealed ??= {}\n sealed[field] = ref\n }\n return sealed ? { record: open, sealed } : { record }\n}\n\n/**\n * Restore every named field's sealed slot back onto the record: an opaque\n * `SealedHandle` under `asHandles` (never materialises plaintext into the\n * cache — `SealedHandle.toJSON()` returns `'[sealed]'`, the export-redaction\n * guarantee `reveal()` alone can lift), the plaintext value otherwise.\n */\nasync function decodeClassifiedAtRest(\n record: Record<string, unknown>,\n sealed: Record<string, SealedSlotRef>,\n crypto: ViaCryptoCtx,\n opts: { asHandles: boolean },\n fields: readonly string[],\n): Promise<Record<string, unknown>> {\n let out = record\n for (const field of fields) {\n const ref = sealed[field]\n if (ref === undefined) continue\n if (out === record) out = { ...record }\n out[field] = opts.asHandles\n ? new SealedHandle(() => crypto.sealedSlots.unseal(field, ref))\n : await crypto.sealedSlots.unseal(field, ref)\n }\n return out\n}\n\n/**\n * `forget()`'s per-ref erasure participation: classify the live envelope's\n * sealed slots (via the codec-provided closure) and mark each shreddable\n * one deleted on this call's sealed-slots capability, then purge the\n * record's sealed-CEK host-delivery envelopes (via the vault-provided\n * closure). Both closures are optional — undefined (this dormant task's\n * only caller, its own unit tests) reports a zero-shredded, zero-residue\n * no-op rather than throwing.\n */\nasync function eraseClassified(\n ctx: ViaEraseCtx,\n cfg: ClassifiedViaConfig,\n): Promise<ViaEraseReport> {\n let shredded = 0\n const residue: unknown[] = []\n\n if (cfg.classifySealedShred) {\n const { slots } = await cfg.classifySealedShred(ctx.live)\n for (const slot of slots) {\n if (slot.class === 'shreddable' || slot.class === 'live-shreddable+dekResidue-in-backups') {\n shredded += 1\n await ctx.crypto.sealedSlots.delete(slot.field)\n }\n if (slot.class === 'dekResidue' || slot.class === 'live-shreddable+dekResidue-in-backups') {\n residue.push({ kind: 'classified-sealed-dek-residue', field: slot.field })\n }\n }\n }\n\n if (cfg.purgeSealedCekEnvelopes) {\n shredded += await cfg.purgeSealedCekEnvelopes(ctx.id)\n }\n\n return { shredded, residue }\n}\n\nfunction buildClassifiedDescribeFragment(byField: Record<string, ClassifiedFieldSpec>): Record<string, unknown> {\n return {\n classifiedFields: Object.fromEntries(\n Object.entries(byField).map(([field, spec]) => [field, { storage: spec.storage, sensitivity: spec.sensitivity }]),\n ),\n }\n}\n\nexport function classifiedVia(cfg: ClassifiedViaConfig): NoydbVia {\n // declare — door 1: resolve + guard, exactly like collection-config.ts's\n // resolveCollectionConfig does today. Throws ClassifiedConfigError on any\n // R1-R8 refusal-matrix violation or field-collision.\n const resolved = resolveClassifiedFields(cfg.collectionName, cfg.entries)\n guardClassifiedCompat(cfg.collectionName, resolved.byField, cfg.guardCtx)\n const byField = resolved.byField\n const sealFields = sealFieldNames(byField, cfg.guardCtx)\n\n return {\n brand: 'classified',\n posture: { encryptedAtRest: 'sealed', queryable: 'det-exact', exportable: false, forgettable: true },\n covers: (field) => field in byField,\n // async (rather than a bare passthrough) so a refusal is always a\n // rejected Promise for direct callers, matching every other async-stack\n // hook's calling convention — `enforceClassifiedWrite` itself stays sync.\n enforceWrite: async (record: Record<string, unknown>, _ctx: ViaWriteCtx) =>\n enforceClassifiedWrite(record, byField, cfg.collectionName),\n encodeAtRest: (record, crypto) => encodeClassifiedAtRest(record, crypto, sealFields),\n decodeAtRest: (record, sealed, crypto, opts) => decodeClassifiedAtRest(record, sealed, crypto, opts, sealFields),\n erase: (ctx) => eraseClassified(ctx, cfg),\n describeFragment: () => buildClassifiedDescribeFragment(byField),\n }\n}\n\nexport function linkClassifiedVia(): void {\n installViaBinder('classified', (c) => classifiedVia(c as ClassifiedViaConfig))\n}\n","/**\n * Classified strategy seam (#629 Task 5 — moved out of\n * `via/classified/strategy.ts`, precedent: `port/with/i18n-strategy.ts`).\n * Lives on the `/with` port (the one seam the kernel spine may import\n * statically) so `Collection`/`Vault` can hold the `NO_CLASSIFIED` default\n * without a spine→service static import.\n *\n * This file (unlike `via/classified/**`) is NOT subject to the\n * `via-enclave-isolation` architecture guard — it may import `EnclaveKey`\n * from the enclave barrel freely, the same way `port/with/i18n-strategy.ts`\n * did before #629 Task 4's DictionaryHandle cutover.\n *\n * The ② capability seam for classified read-egress ops (stage 1: reveal;\n * stage 2: verify).\n *\n * @internal\n */\nimport type { ClassifiedFieldSpec } from '../../via/classified/descriptor.js'\nimport { ClassifiedNotEnabledError } from '../../kernel/errors.js'\nimport type { EncryptedEnvelope } from '../../kernel/types.js'\nimport type { EnclaveKey } from '../../kernel/enclave/index.js'\nimport { linkClassifiedVia } from '../../via/classified/binding.js'\n\n// #629 Task 10 — re-export the classified binding's erase-cfg TYPE (not\n// `via/classified/binding.js` directly) so the kernel spine can name\n// it for the post-construction `classifySealedShred` wiring, same rationale\n// as `resolveClassifiedFields`/`guardClassifiedCompat` above.\nexport type { ClassifiedViaConfig } from '../../via/classified/binding.js'\n\nexport type { ClassifiedVerdict } from '../../kernel/types.js'\nimport type { ClassifiedVerdict } from '../../kernel/types.js'\n\n// #629 Task 6 — the classified binding's construction-time resolve/guard,\n// re-exported here (not `via/classified/{resolve,guards}.js` directly)\n// so the kernel spine keeps importing only this one `/with` port seam, same\n// rationale as `NO_CLASSIFIED` below.\nexport { resolveClassifiedFields, type ClassifiedEntry, type ResolvedClassified } from '../../via/classified/resolve.js'\nexport { guardClassifiedCompat, type ClassifiedGuardCtx } from '../../via/classified/guards.js'\nexport type { ClassifiedFieldSpec }\n\n// Install the classified Via binder EAGERLY — unlike money()/i18nText(),\n// several classified fixtures (both hub tests and consumer code) build a raw\n// `ClassifiedFieldSpec` object literal without ever calling a\n// `classified.*()` preset (bypassing `via/classified/presets.ts`\n// entirely — an intentionally supported pattern, see that module's Task 5\n// doc comment). Linking lazily at preset-call time (the money/i18n pattern)\n// would leave `viaBinder('classified')` unlinked for those declarations.\n// This port module is already unconditionally imported by the kernel spine\n// (for the `NO_CLASSIFIED` strategy default below), so linking here\n// guarantees the binder is always installed before `compileVias`\n// ever needs it, regardless of how a collection's classifiedFields were\n// constructed.\nlinkClassifiedVia()\n\nexport interface ClassifiedRevealCtx {\n readonly collection: string\n readonly spec: ClassifiedFieldSpec\n /** True on an encrypted collection — false selects the plaintext-body read. */\n readonly encrypted: boolean\n readonly getEnvelope: (id: string) => Promise<EncryptedEnvelope | null>\n readonly resolveCek: (env: EncryptedEnvelope) => Promise<EnclaveKey | undefined>\n readonly getDEK: () => Promise<EnclaveKey>\n readonly onAccess?: ((op: 'reveal', id: string) => Promise<void>) | undefined\n}\n\nexport interface ClassifiedVerifyCtx {\n readonly collection: string\n readonly spec: ClassifiedFieldSpec\n readonly getEnvelope: (id: string) => Promise<EncryptedEnvelope | null> // raw envelope, NOT a decrypted view\n readonly resolveCek: (env: EncryptedEnvelope) => Promise<EnclaveKey | undefined>\n readonly getDEK: () => Promise<EnclaveKey>\n readonly now: () => number // injected (Q7)\n /** Group members resolved by the collection (matchGroup only). */\n readonly groupMembers?: ReadonlyArray<{ readonly field: string; readonly spec: ClassifiedFieldSpec }>\n readonly onAccess?: ((op: 'verify' | 'find', id: string) => Promise<void>) | undefined\n}\n\nexport interface ClassifiedStrategy {\n reveal(ctx: ClassifiedRevealCtx, id: string, field: string): Promise<unknown>\n verify(ctx: ClassifiedVerifyCtx, id: string, field: string, candidate: string): Promise<ClassifiedVerdict>\n verifyText(ctx: ClassifiedVerifyCtx, id: string, field: string, candidate: string): Promise<ClassifiedVerdict>\n matchGroup(ctx: ClassifiedVerifyCtx, id: string, answers: Record<string, string>,\n opts: { readonly min: number }): Promise<{ readonly passed: boolean }>\n computeTarget(ctx: ClassifiedVerifyCtx, field: string, candidate: string, costByte?: number): Promise<string | null>\n}\n\nexport const NO_CLASSIFIED: ClassifiedStrategy = {\n async reveal() { throw new ClassifiedNotEnabledError() },\n async verify() { throw new ClassifiedNotEnabledError() },\n async verifyText() { throw new ClassifiedNotEnabledError() },\n async matchGroup() { throw new ClassifiedNotEnabledError() },\n async computeTarget() { throw new ClassifiedNotEnabledError() },\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/via/classified/descriptor.ts","../src/via/classified/errors.ts","../src/via/classified/resolve.ts","../src/via/classified/write.ts","../src/via/classified/guards.ts","../src/via/classified/binding.ts","../src/port/with/classified-strategy.ts"],"sourcesContent":["/**\n * Classified fields — behavioral sensitive-field descriptors (stage 1).\n * Design: design-history/2026-07-04-classified-fields-design.md\n * Law: open on write, declarative on read — read-side behavior is this\n * closed vocabulary; there are no read-side callbacks.\n * @module\n */\n\nexport type ClassifiedStorage = 'recoverable' | 'never' | 'digest-only'\n\nexport type ClassifiedList =\n | { readonly kind: 'omit' }\n | { readonly kind: 'mask'; readonly pattern: string }\n | { readonly kind: 'rider'; readonly rider: string }\n\nexport type ClassifiedRider = (value: unknown) => unknown\n\nexport interface ClassifiedFieldSpec {\n readonly _noydbClassified: true\n /**\n * Via port brand marker — lets a `ClassifiedFieldSpec` satisfy the\n * kernel's opaque `ViaDescriptor` (#629 Task 5). Optional (unlike\n * `MoneyDescriptor._viaBrand`/`I18nTextDescriptor._viaBrand`, which are\n * required): every `classified.*()` preset factory stamps it, but the\n * pre-existing test suite's hand-rolled `ClassifiedFieldSpec` fixtures\n * (built without going through a preset) predate this field and would\n * fail to compile if it were mandatory.\n */\n readonly _viaBrand?: 'classified'\n readonly preset: string\n readonly storage: ClassifiedStorage\n readonly list: ClassifiedList\n readonly sensitivity: 'pii' | 'secret'\n /** Write-time safe projections; companion field name is `<field>_<rider>`. */\n readonly riders?: Record<string, ClassifiedRider>\n /** Write-time validator: error message, or null when valid. */\n readonly validate?: (value: unknown) => string | null\n /** Digest-only verify policy (stage 2). Mode both sides normalize under. */\n readonly verifyNormalize?: 'password' | 'secret-answer'\n /** Decorate ok:true verdicts with mustRotate after this many days (I1). */\n readonly rotateDays?: number\n /** Refuse reuse of the last N values on rotate (cap 8, spec Q4). */\n readonly notLastN?: number\n /** Member of the collection's matchGroup (secretAnswer preset). */\n readonly verifyGroupMember?: true\n /**\n * Opt into a store-visible blind-index (`_bidx`) tag so equal values become\n * queryable/joinable while staying digest-only. Digest-only knob (R7); gated\n * behind the collection's `acknowledgeEquatableRisk` door (R8). Equal values\n * produce equal tags — a partition leak a DEK holder can offline-dictionary\n * at the PBKDF2 floor. Absent/false ⇒ refused-by-default.\n */\n readonly equatable?: true\n}\n\nexport interface ClassifiedGroup {\n readonly _noydbClassifiedGroup: true\n /** Via port brand marker — see {@link ClassifiedFieldSpec._viaBrand}. */\n readonly _viaBrand?: 'classified'\n readonly preset: string\n /** member record-field name -> spec (differential per-member policy). */\n readonly members: Record<string, ClassifiedFieldSpec>\n}\n\nexport type ClassifiedEntry = ClassifiedFieldSpec | ClassifiedGroup\n\nexport function isClassifiedFieldSpec(x: unknown): x is ClassifiedFieldSpec {\n return typeof x === 'object' && x !== null\n && (x as { _noydbClassified?: unknown })._noydbClassified === true\n}\n\nexport function isClassifiedGroup(x: unknown): x is ClassifiedGroup {\n return typeof x === 'object' && x !== null\n && (x as { _noydbClassifiedGroup?: unknown })._noydbClassifiedGroup === true\n}\n","/**\n * Configuration/write errors for classified fields. @module\n *\n * `ClassifiedConfigError` / `ClassifiedRevealError` moved to `kernel/errors.ts`\n * (stage 2) so `kernel/enclave/classify/*` can throw them without importing\n * with-*. Re-exported here under the same names so existing import paths\n * keep working.\n */\nexport { ClassifiedConfigError, ClassifiedRevealError, ClassifiedVerifyError, ClassifiedRotationError } from '../../kernel/errors.js'\n\nexport class ClassifiedNeverStoredError extends Error {\n constructor(public readonly collection: string, public readonly field: string) {\n super(`Field \"${field}\" in collection \"${collection}\" is classified storage:'never' `\n + `(e.g. a CVC) and must not be persisted. Validate it at capture and drop it before put().`)\n this.name = 'ClassifiedNeverStoredError'\n }\n}\n\nexport class ClassifiedValidationError extends Error {\n constructor(public readonly collection: string, public readonly field: string, detail: string) {\n super(`Classified field \"${field}\" in collection \"${collection}\" failed validation: ${detail}`)\n this.name = 'ClassifiedValidationError'\n }\n}\n","/** Flatten a classifiedFields config into a per-field map + rider computed entries. @module */\n\nimport { isClassifiedGroup, type ClassifiedEntry, type ClassifiedFieldSpec } from './descriptor.js'\nimport { ClassifiedConfigError } from './errors.js'\n\nexport type { ClassifiedEntry, ClassifiedFieldSpec, ClassifiedGroup, ClassifiedList } from './descriptor.js'\nexport { ClassifiedConfigError } from './errors.js'\n\nexport interface ResolvedClassified {\n readonly byField: Record<string, ClassifiedFieldSpec>\n readonly riderComputed: Record<string, (record: Record<string, unknown>) => unknown>\n}\n\nexport function resolveClassifiedFields(\n collection: string,\n config: Record<string, ClassifiedEntry>,\n): ResolvedClassified {\n const byField: Record<string, ClassifiedFieldSpec> = {}\n const claim = (field: string, spec: ClassifiedFieldSpec): void => {\n if (byField[field] !== undefined) {\n throw new ClassifiedConfigError(collection,\n `field \"${field}\" is claimed twice — storage forms are mutually exclusive per field (R5): ` +\n `a field is digest-only OR recoverable OR never, exactly one`)\n }\n byField[field] = spec\n }\n for (const [key, entry] of Object.entries(config)) {\n if (isClassifiedGroup(entry)) {\n for (const [field, spec] of Object.entries(entry.members)) claim(field, spec)\n } else {\n claim(key, entry)\n }\n }\n const riderComputed: Record<string, (record: Record<string, unknown>) => unknown> = {}\n for (const [field, spec] of Object.entries(byField)) {\n for (const [name, rider] of Object.entries(spec.riders ?? {})) {\n const companion = `${field}_${name}`\n if (byField[companion] !== undefined || riderComputed[companion] !== undefined) {\n throw new ClassifiedConfigError(collection, `rider companion \"${companion}\" collides with a declared field`)\n }\n riderComputed[companion] = (record) =>\n record[field] === undefined ? undefined : rider(record[field])\n }\n }\n return { byField, riderComputed }\n}\n","/** Write-path enforcement: storage:'never' rejection + preset validators.\n * Runs BEFORE riders/computed and BEFORE schema validation. Pure. @module */\n\nimport type { ClassifiedFieldSpec } from './descriptor.js'\nimport { ClassifiedNeverStoredError, ClassifiedValidationError } from './errors.js'\n\nexport function enforceClassifiedWrite(\n record: Record<string, unknown>,\n byField: Record<string, ClassifiedFieldSpec>,\n collection: string,\n): void {\n for (const [field, spec] of Object.entries(byField)) {\n const value = record[field]\n if (value === undefined) continue\n if (value === null && spec.storage === 'digest-only') continue // explicit clear (C6 branch 3)\n if (spec.storage === 'never') throw new ClassifiedNeverStoredError(collection, field)\n const problem = spec.validate?.(value) ?? null\n if (problem !== null) throw new ClassifiedValidationError(collection, field, problem)\n }\n}\n","/**\n * Refusal matrix R1-R5 (spec) — ONE guard, run at BOTH doors:\n * `collection()` config resolution AND `_applyClassifiedFields` (the reconcile\n * seam), because crdt/conflictPolicy/perRecordKeys are construction-only\n * while classifiedFields can attach later (C5's lesson). @module\n */\nimport type { ClassifiedFieldSpec } from './descriptor.js'\nimport { ClassifiedConfigError } from '../../kernel/errors.js'\n\nexport interface ClassifiedGuardCtx {\n readonly perRecordKeys: boolean\n readonly crdt: boolean\n readonly hasConflictPolicy: boolean\n /** False on plaintext (`encrypt: false`) collections — no vdig/seal path exists. */\n readonly storeCiphertext: boolean\n readonly deterministicFields: ReadonlySet<string> | null\n readonly indexedFields: ReadonlySet<string>\n readonly textIndexFields: ReadonlySet<string>\n readonly vectorSourceFields: ReadonlySet<string>\n readonly subjectKeyField: string | undefined\n readonly bareSensitiveFields: ReadonlySet<string>\n /** Collection-level gate for the `equatable` knob (R8 double door). */\n readonly acknowledgeEquatableRisk: boolean\n}\n\nexport function guardClassifiedCompat(\n collection: string,\n byField: Record<string, ClassifiedFieldSpec>,\n ctx: ClassifiedGuardCtx,\n): void {\n const digestOnly = Object.entries(byField)\n .filter(([, s]) => s.storage === 'digest-only')\n const protectedForms = Object.values(byField)\n .filter((s) => s.storage === 'digest-only' || s.storage === 'recoverable')\n\n // R2 — merge resolvers bypass the write pipeline entirely (C5): a merge\n // could carry stale/foreign _vdig or resurrect plaintext (the CRDT put\n // branch persists via encryptJsonString with no vdig backstop). Fail-loud.\n if (protectedForms.length > 0 && (ctx.crdt || ctx.hasConflictPolicy)) {\n throw new ClassifiedConfigError(collection,\n 'digest-only/recoverable classified fields cannot combine with a crdt mode or a ' +\n 'conflictPolicy resolver — merge paths bypass write enforcement (R2)')\n }\n // R7 — `equatable` is a digest-only knob: it drives the `_bidx` blind-index\n // slot, which only exists on the digest-only write path. A recoverable/never\n // field carrying it would silently no-op (recoverable equality is `_det`'s\n // job). Refuse rather than accept-and-ignore. Checked over ALL specs, before\n // the digest-only early-return below, precisely to catch the non-digest case.\n for (const [f, spec] of Object.entries(byField)) {\n if (spec.equatable === true && spec.storage !== 'digest-only') {\n throw new ClassifiedConfigError(collection,\n `field \"${f}\" declares equatable but storage is '${spec.storage}' — equatable is a ` +\n `digest-only knob; recoverable equality is _det's job (R7)`)\n }\n }\n\n // R8 — the equatable double door (mirrors deterministicFields ×\n // acknowledgeDeterministicRisk): any field opting into `equatable` requires\n // the collection to acknowledge the partition-leak risk. One-directional —\n // `acknowledgeEquatableRisk: true` with ZERO equatable members is a silent\n // no-op (never throws here), so the ack can sit on a collection config\n // ahead of the field landing.\n const hasEquatable = Object.values(byField).some((s) => s.equatable === true)\n if (hasEquatable && ctx.acknowledgeEquatableRisk !== true) {\n throw new ClassifiedConfigError(collection,\n `classified equatable fields require \\`acknowledgeEquatableRisk: true\\` — equal values ` +\n `produce equal store-visible index tags (a partition leak a DEK holder can offline-` +\n `dictionary at the PBKDF2 floor); the door is the real control for low-entropy fields (R8)`)\n }\n\n if (digestOnly.length === 0) return\n\n // Digest-only on a plaintext collection: the codec's vdig block is gated on\n // storeCiphertext, so the secret would persist as raw plaintext. Refuse.\n if (!ctx.storeCiphertext) {\n throw new ClassifiedConfigError(collection,\n `storage:'digest-only' requires an encrypted collection — with encrypt: false the ` +\n `write path skips the digest slot entirely and the secret would persist as raw plaintext`)\n }\n // R1 — vdig slot keys are CEK-only (I3); without perRecordKeys a digest\n // would survive forget() in backups as offline-crackable material.\n if (!ctx.perRecordKeys) {\n throw new ClassifiedConfigError(collection,\n `storage:'digest-only' requires perRecordKeys: true — vdig keys derive from the ` +\n `per-record CEK so forget() shreds them (R1)`)\n }\n for (const [f, spec] of digestOnly) {\n // notLastN cap: presets clamp this at construction, but a raw spec object\n // bypasses the preset — enforce the same 0..8 cap in the policy projection.\n const n = spec.notLastN ?? 0\n if (!Number.isInteger(n) || n < 0 || n > 8) {\n throw new ClassifiedConfigError(collection,\n `digest-only field \"${f}\" declares notLastN ${n} — must be an integer 0..8 ` +\n `(write cost is n × 600K PBKDF2; ring blast radius is documented)`)\n }\n if (ctx.bareSensitiveFields.has(f)) {\n // R5 — the sealed block runs before the vdig block in the codec, so the\n // overlap would seal the value recoverably (silent downgrade + I4\n // double-slot). Storage forms are mutually exclusive per field.\n throw new ClassifiedConfigError(collection,\n `field \"${f}\" is digest-only AND listed in sensitive[] — storage forms are mutually exclusive per field (R5)`)\n }\n if (ctx.deterministicFields?.has(f)) {\n throw new ClassifiedConfigError(collection,\n `digest-only field \"${f}\" cannot be deterministic — equality-correlatable ciphertext defeats per-write salts (R3)`)\n }\n if (ctx.indexedFields.has(f) || ctx.textIndexFields.has(f)\n || ctx.vectorSourceFields.has(f) || ctx.subjectKeyField === f) {\n throw new ClassifiedConfigError(collection,\n `digest-only field \"${f}\" cannot be indexed, text-indexed, embedded, or a forget-subject key (R4)`)\n }\n }\n}\n","/**\n * The classified `NoydbVia` (#629 Task 5, LIVE since Task 6) — wires\n * classified-fields declaration/write-enforcement/at-rest sealing/erasure\n * into the kernel's generic Via port. Mirrors `via/money/binding.ts`'s\n * inline declaration-time validation and `via/i18n/binding.ts`'s\n * `linkXVia` static-link pattern — except the link itself is EAGER\n * (`port/with/classified-strategy.ts` calls `linkClassifiedVia()` at module\n * load, not lazily from a `classified.*()` preset call): several fixtures\n * build a raw `ClassifiedFieldSpec` literal without ever calling a preset,\n * and the binder must be installed before `compileVias` needs it\n * regardless.\n *\n * `compileVias` (`kernel/collection-config.ts`) compiles this binding\n * in whenever a collection declares `classifiedFields` — money then i18n\n * then classified, order pinned. `kernel/collection.ts`'s `_putInternal`\n * runs `enforceClassifiedWrite`'s effect via the pipeline's `enforceWrite`\n * phase; the codec's `encodeAtRest`/`decodeAtRest` hooks (Task 3's boundary)\n * replace the inline `sensitiveFields` seal path for any collection this\n * binding is compiled into.\n *\n * `declare` — `classifiedVia(cfg)` runs `resolveClassifiedFields` +\n * `guardClassifiedCompat` at CONSTRUCTION time (the same #553 pattern\n * `moneyVia`'s `validateMoneyFieldPaths(moneyFields)` call uses) —\n * mirrors today's \"door 1\" (`collection-config.ts`'s\n * `resolveCollectionConfig`). Both may throw `ClassifiedConfigError`.\n */\nimport type { NoydbVia, ViaWriteCtx, ViaCryptoCtx, SealedSlotRef, ViaEraseCtx, ViaEraseReport } from '../../kernel/via/index.js'\nimport { installViaBinder } from '../../kernel/via/index.js'\nimport { SealedHandle } from '../../kernel/types.js'\nimport { resolveClassifiedFields, type ClassifiedEntry } from './resolve.js'\nimport { guardClassifiedCompat, type ClassifiedGuardCtx } from './guards.js'\nimport { enforceClassifiedWrite } from './write.js'\nimport type { ClassifiedFieldSpec } from './descriptor.js'\n\n/**\n * One classified per-slot shred/residue verdict — mirrors\n * `RecordCodec.SealedShredSlot` (`kernel/enclave/record-keys/record-codec.ts`)\n * byte-for-byte. Duplicated here (not imported) so this binding never\n * reaches into `kernel/enclave/` (`via-enclave-isolation`, #629) — the\n * closure that PRODUCES real values of this shape is codec-owned and\n * injected via {@link ClassifiedViaConfig.classifySealedShred}.\n */\nexport interface ClassifiedShredSlot {\n readonly field: string\n readonly class: 'shreddable' | 'dekResidue' | 'live-shreddable+dekResidue-in-backups'\n}\n\n/**\n * Config a classified collection's declarations resolve to — the binding's\n * construction input. `entries`/`guardCtx` are the raw \"door 1\" inputs\n * (`resolveClassifiedFields`/`guardClassifiedCompat`'s own parameters);\n * `classifySealedShred`/`purgeSealedCekEnvelopes` are OPTIONAL codec/vault-\n * provided closures for the `erase` hook — undefined in this dormant task\n * (no caller wires them yet), wired for real in #629 Task 10 (\"posture\n * enforcement — forget + erase hooks live\").\n */\nexport interface ClassifiedViaConfig {\n readonly entries: Record<string, ClassifiedEntry>\n readonly collectionName: string\n readonly guardCtx: ClassifiedGuardCtx\n /**\n * Codec-provided closure mirroring `RecordCodec.classifySealedShred` —\n * classifies a live envelope's `_sealed` slots for crypto-shred\n * completeness (see that method's doc comment for the shreddable/\n * dekResidue/both-class semantics). `live` is `ViaEraseCtx.live`'s opaque\n * envelope, passed straight through. NOT `readonly` (#629 Task 10):\n * `compileVias` builds this cfg before the owning `Collection`'s\n * `RecordCodec` exists, so `Collection`'s constructor mutates this field\n * in place once `this.codec` is available — the closure `eraseClassified`\n * reads is looked up at CALL time, not at binding-construction time, so\n * the late assignment is picked up correctly.\n */\n classifySealedShred?: (live: unknown) => Promise<{ readonly slots: readonly ClassifiedShredSlot[] }>\n /**\n * Vault-provided closure that purges every `_sealed_cek/<collection>/<id>/*`\n * host-delivery envelope for one record (mirrors `rotateRecordCek`'s own\n * prefix-delete) and returns the count purged. Deliberately left UNWIRED\n * by `compileVias` (#629 Task 10) — `forget-sealed-erasure.test.ts`\n * proves this purge is UNCONDITIONAL on `sealRecordToHost` usage alone,\n * independent of whether `classifiedFields` is declared (a bare\n * `sensitive: [...]` collection exercises it with no classified binding\n * at all) — vault.ts keeps owning it directly so that case stays correct.\n */\n readonly purgeSealedCekEnvelopes?: (id: string) => Promise<number>\n}\n\n/** Fields declared `storage: 'recoverable'` (digest-only stays codec-inline; `'never'` is rejected by `enforceWrite` before either hook runs). */\nfunction recoverableFields(byField: Record<string, ClassifiedFieldSpec>): string[] {\n return Object.entries(byField).filter(([, spec]) => spec.storage === 'recoverable').map(([field]) => field)\n}\n\n/**\n * The full set this binding's `encodeAtRest`/`decodeAtRest` seal: declared\n * recoverable classified fields UNION bare `sensitive[]` fields — mirrors\n * `collection-config.ts`'s pre-cutover \"recoverable classified fields are\n * unioned into sensitiveFields... zero new crypto code\" semantics. Once this\n * binding is compiled into a collection's pipeline, `hasAtRestHooks` is true\n * and the codec's inline `sensitiveFields` seal path (record-codec.ts) is\n * DEAD for that collection — mutually exclusive with the hook path (#629\n * Task 3) — so bare `sensitive[]` fields MUST seal through here too, or\n * they'd silently stop being sealed at all (#629 Task 6 reconciliation).\n * `guardCtx.bareSensitiveFields` is the exact same `Set` the collection's\n * refusal-matrix guard already carries (`ClassifiedGuardCtx`).\n */\nfunction sealFieldNames(byField: Record<string, ClassifiedFieldSpec>, guardCtx: ClassifiedGuardCtx): string[] {\n return [...recoverableFields(byField), ...guardCtx.bareSensitiveFields]\n}\n\n/**\n * Seal every named field present with a defined value into its own sealed\n * slot via `crypto.sealedSlots`, peeling it out of the record.\n */\nasync function encodeClassifiedAtRest(\n record: Record<string, unknown>,\n crypto: ViaCryptoCtx,\n fields: readonly string[],\n): Promise<{ record: Record<string, unknown>; sealed?: Record<string, SealedSlotRef> }> {\n let open = record\n let sealed: Record<string, SealedSlotRef> | undefined\n for (const field of fields) {\n if (!(field in record)) continue\n const value = record[field]\n if (value === undefined) continue\n const ref = await crypto.sealedSlots.seal(field, value)\n if (open === record) open = { ...record }\n delete open[field]\n sealed ??= {}\n sealed[field] = ref\n }\n return sealed ? { record: open, sealed } : { record }\n}\n\n/**\n * Restore every named field's sealed slot back onto the record: an opaque\n * `SealedHandle` under `asHandles` (never materialises plaintext into the\n * cache — `SealedHandle.toJSON()` returns `'[sealed]'`, the export-redaction\n * guarantee `reveal()` alone can lift), the plaintext value otherwise.\n */\nasync function decodeClassifiedAtRest(\n record: Record<string, unknown>,\n sealed: Record<string, SealedSlotRef>,\n crypto: ViaCryptoCtx,\n opts: { asHandles: boolean },\n fields: readonly string[],\n): Promise<Record<string, unknown>> {\n let out = record\n for (const field of fields) {\n const ref = sealed[field]\n if (ref === undefined) continue\n if (out === record) out = { ...record }\n out[field] = opts.asHandles\n ? new SealedHandle(() => crypto.sealedSlots.unseal(field, ref))\n : await crypto.sealedSlots.unseal(field, ref)\n }\n return out\n}\n\n/**\n * `forget()`'s per-ref erasure participation: classify the live envelope's\n * sealed slots (via the codec-provided closure) and mark each shreddable\n * one deleted on this call's sealed-slots capability, then purge the\n * record's sealed-CEK host-delivery envelopes (via the vault-provided\n * closure). Both closures are optional — undefined (this dormant task's\n * only caller, its own unit tests) reports a zero-shredded, zero-residue\n * no-op rather than throwing.\n */\nasync function eraseClassified(\n ctx: ViaEraseCtx,\n cfg: ClassifiedViaConfig,\n): Promise<ViaEraseReport> {\n let shredded = 0\n const residue: unknown[] = []\n\n if (cfg.classifySealedShred) {\n const { slots } = await cfg.classifySealedShred(ctx.live)\n for (const slot of slots) {\n if (slot.class === 'shreddable' || slot.class === 'live-shreddable+dekResidue-in-backups') {\n shredded += 1\n await ctx.crypto.sealedSlots.delete(slot.field)\n }\n if (slot.class === 'dekResidue' || slot.class === 'live-shreddable+dekResidue-in-backups') {\n residue.push({ kind: 'classified-sealed-dek-residue', field: slot.field })\n }\n }\n }\n\n if (cfg.purgeSealedCekEnvelopes) {\n shredded += await cfg.purgeSealedCekEnvelopes(ctx.id)\n }\n\n return { shredded, residue }\n}\n\nfunction buildClassifiedDescribeFragment(byField: Record<string, ClassifiedFieldSpec>): Record<string, unknown> {\n return {\n classifiedFields: Object.fromEntries(\n Object.entries(byField).map(([field, spec]) => [field, { storage: spec.storage, sensitivity: spec.sensitivity }]),\n ),\n }\n}\n\nexport function classifiedVia(cfg: ClassifiedViaConfig): NoydbVia {\n // declare — door 1: resolve + guard, exactly like collection-config.ts's\n // resolveCollectionConfig does today. Throws ClassifiedConfigError on any\n // R1-R8 refusal-matrix violation or field-collision.\n const resolved = resolveClassifiedFields(cfg.collectionName, cfg.entries)\n guardClassifiedCompat(cfg.collectionName, resolved.byField, cfg.guardCtx)\n const byField = resolved.byField\n const sealFields = sealFieldNames(byField, cfg.guardCtx)\n\n return {\n brand: 'classified',\n posture: { encryptedAtRest: 'sealed', queryable: 'det-exact', exportable: false, forgettable: true },\n covers: (field) => field in byField,\n coveredFields: Object.keys(byField), // #1447 — the FIELD only; the sensitivity label is deliberately NOT reported\n // async (rather than a bare passthrough) so a refusal is always a\n // rejected Promise for direct callers, matching every other async-stack\n // hook's calling convention — `enforceClassifiedWrite` itself stays sync.\n enforceWrite: async (record: Record<string, unknown>, _ctx: ViaWriteCtx) =>\n enforceClassifiedWrite(record, byField, cfg.collectionName),\n encodeAtRest: (record, crypto) => encodeClassifiedAtRest(record, crypto, sealFields),\n decodeAtRest: (record, sealed, crypto, opts) => decodeClassifiedAtRest(record, sealed, crypto, opts, sealFields),\n erase: (ctx) => eraseClassified(ctx, cfg),\n describeFragment: () => buildClassifiedDescribeFragment(byField),\n }\n}\n\nexport function linkClassifiedVia(): void {\n installViaBinder('classified', (c) => classifiedVia(c as ClassifiedViaConfig))\n}\n","/**\n * Classified strategy seam (#629 Task 5 — moved out of\n * `via/classified/strategy.ts`, precedent: `port/with/i18n-strategy.ts`).\n * Lives on the `/with` port (the one seam the kernel spine may import\n * statically) so `Collection`/`Vault` can hold the `NO_CLASSIFIED` default\n * without a spine→service static import.\n *\n * This file (unlike `via/classified/**`) is NOT subject to the\n * `via-enclave-isolation` architecture guard — it may import `EnclaveKey`\n * from the enclave barrel freely, the same way `port/with/i18n-strategy.ts`\n * did before #629 Task 4's DictionaryHandle cutover.\n *\n * The ② capability seam for classified read-egress ops (stage 1: reveal;\n * stage 2: verify).\n *\n * @internal\n */\nimport type { ClassifiedFieldSpec } from '../../via/classified/descriptor.js'\nimport { ClassifiedNotEnabledError } from '../../kernel/errors.js'\nimport type { EncryptedEnvelope } from '../../kernel/types.js'\nimport type { EnclaveKey } from '../../kernel/enclave/index.js'\nimport { linkClassifiedVia } from '../../via/classified/binding.js'\n\n// #629 Task 10 — re-export the classified binding's erase-cfg TYPE (not\n// `via/classified/binding.js` directly) so the kernel spine can name\n// it for the post-construction `classifySealedShred` wiring, same rationale\n// as `resolveClassifiedFields`/`guardClassifiedCompat` above.\nexport type { ClassifiedViaConfig } from '../../via/classified/binding.js'\n\nexport type { ClassifiedVerdict } from '../../kernel/types.js'\nimport type { ClassifiedVerdict } from '../../kernel/types.js'\n\n// #629 Task 6 — the classified binding's construction-time resolve/guard,\n// re-exported here (not `via/classified/{resolve,guards}.js` directly)\n// so the kernel spine keeps importing only this one `/with` port seam, same\n// rationale as `NO_CLASSIFIED` below.\nexport { resolveClassifiedFields, type ClassifiedEntry, type ResolvedClassified } from '../../via/classified/resolve.js'\nexport { guardClassifiedCompat, type ClassifiedGuardCtx } from '../../via/classified/guards.js'\nexport type { ClassifiedFieldSpec }\n\n// Install the classified Via binder EAGERLY — unlike money()/i18nText(),\n// several classified fixtures (both hub tests and consumer code) build a raw\n// `ClassifiedFieldSpec` object literal without ever calling a\n// `classified.*()` preset (bypassing `via/classified/presets.ts`\n// entirely — an intentionally supported pattern, see that module's Task 5\n// doc comment). Linking lazily at preset-call time (the money/i18n pattern)\n// would leave `viaBinder('classified')` unlinked for those declarations.\n// This port module is already unconditionally imported by the kernel spine\n// (for the `NO_CLASSIFIED` strategy default below), so linking here\n// guarantees the binder is always installed before `compileVias`\n// ever needs it, regardless of how a collection's classifiedFields were\n// constructed.\nlinkClassifiedVia()\n\nexport interface ClassifiedRevealCtx {\n readonly collection: string\n readonly spec: ClassifiedFieldSpec\n /** True on an encrypted collection — false selects the plaintext-body read. */\n readonly encrypted: boolean\n readonly getEnvelope: (id: string) => Promise<EncryptedEnvelope | null>\n readonly resolveCek: (env: EncryptedEnvelope) => Promise<EnclaveKey | undefined>\n readonly getDEK: () => Promise<EnclaveKey>\n readonly onAccess?: ((op: 'reveal', id: string) => Promise<void>) | undefined\n}\n\nexport interface ClassifiedVerifyCtx {\n readonly collection: string\n readonly spec: ClassifiedFieldSpec\n readonly getEnvelope: (id: string) => Promise<EncryptedEnvelope | null> // raw envelope, NOT a decrypted view\n readonly resolveCek: (env: EncryptedEnvelope) => Promise<EnclaveKey | undefined>\n readonly getDEK: () => Promise<EnclaveKey>\n readonly now: () => number // injected (Q7)\n /** Group members resolved by the collection (matchGroup only). */\n readonly groupMembers?: ReadonlyArray<{ readonly field: string; readonly spec: ClassifiedFieldSpec }>\n readonly onAccess?: ((op: 'verify' | 'find', id: string) => Promise<void>) | undefined\n}\n\nexport interface ClassifiedStrategy {\n reveal(ctx: ClassifiedRevealCtx, id: string, field: string): Promise<unknown>\n verify(ctx: ClassifiedVerifyCtx, id: string, field: string, candidate: string): Promise<ClassifiedVerdict>\n verifyText(ctx: ClassifiedVerifyCtx, id: string, field: string, candidate: string): Promise<ClassifiedVerdict>\n matchGroup(ctx: ClassifiedVerifyCtx, id: string, answers: Record<string, string>,\n opts: { readonly min: number }): Promise<{ readonly passed: boolean }>\n computeTarget(ctx: ClassifiedVerifyCtx, field: string, candidate: string, costByte?: number): Promise<string | null>\n}\n\nexport const NO_CLASSIFIED: ClassifiedStrategy = {\n async reveal() { throw new ClassifiedNotEnabledError() },\n async verify() { throw new ClassifiedNotEnabledError() },\n async verifyText() { throw new ClassifiedNotEnabledError() },\n async matchGroup() { throw new ClassifiedNotEnabledError() },\n async computeTarget() { throw new ClassifiedNotEnabledError() },\n}\n"],"mappings":"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","names":[]}
|