@noy-db/hub 0.6.0-pre.9 → 0.6.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 +7079 -0
- package/codemods/0.6.0-pre.json +211 -0
- package/dist/api-6X2VLZ7J.js +20 -0
- package/dist/attestation/index.js +19 -19
- package/dist/{backup-KULFZ2T4.js → backup-VL4GRIEW.js} +36 -18
- package/dist/backup-VL4GRIEW.js.map +1 -0
- package/dist/blobs/index.js +22 -20
- package/dist/blobs/index.js.map +1 -1
- package/dist/broker/index.js +12 -12
- package/dist/cargo/index.js +35 -35
- package/dist/{chunk-KUDZVJKQ.js → chunk-22GR3O4J.js} +2 -2
- package/dist/{chunk-CCZJJ4I2.js → chunk-2CBFYXJX.js} +6 -6
- package/dist/{chunk-JJNOLSG5.js → chunk-2J5IT37K.js} +15 -16
- package/dist/chunk-2J5IT37K.js.map +1 -0
- package/dist/{chunk-PNKHAKQ7.js → chunk-2ZCWHCLF.js} +17 -10
- package/dist/chunk-2ZCWHCLF.js.map +1 -0
- package/dist/{chunk-2BMRJ6LQ.js → chunk-2ZT4INZ4.js} +8 -11
- package/dist/{chunk-2BMRJ6LQ.js.map → chunk-2ZT4INZ4.js.map} +1 -1
- package/dist/{chunk-FAXZQ5UF.js → chunk-323MN67Z.js} +2 -2
- package/dist/{chunk-VMCCGUQB.js → chunk-36CEG6CM.js} +2 -2
- package/dist/{chunk-PDLLCOGD.js → chunk-3OE2QNSM.js} +20 -17
- package/dist/chunk-3OE2QNSM.js.map +1 -0
- package/dist/{chunk-AHLJSVRL.js → chunk-3YGUHUJA.js} +5 -7
- package/dist/chunk-3YGUHUJA.js.map +1 -0
- package/dist/{chunk-ZJADGNYF.js → chunk-4AOERLTV.js} +1 -1
- package/dist/chunk-4AOERLTV.js.map +1 -0
- package/dist/{chunk-BRVW2GS5.js → chunk-4ATF4BLF.js} +87 -34
- package/dist/chunk-4ATF4BLF.js.map +1 -0
- package/dist/{chunk-747LRSOO.js → chunk-4K6BIMLF.js} +2 -2
- package/dist/{chunk-5O5HRRTV.js → chunk-5ATC6UT4.js} +7 -7
- package/dist/{chunk-5O5HRRTV.js.map → chunk-5ATC6UT4.js.map} +1 -1
- package/dist/{chunk-4GZ6XOVW.js → chunk-5F7BZAGV.js} +44 -42
- package/dist/chunk-5F7BZAGV.js.map +1 -0
- package/dist/{chunk-FNSMZQS4.js → chunk-5IHGJHWC.js} +2 -2
- package/dist/{chunk-4I72F5DF.js → chunk-5LZZQMIC.js} +11 -14
- package/dist/chunk-5LZZQMIC.js.map +1 -0
- package/dist/{chunk-HPLWFNG4.js → chunk-5O5ZSW7N.js} +2 -2
- package/dist/{chunk-CEJWMBXO.js → chunk-5OT4G5N5.js} +6 -2
- package/dist/chunk-5OT4G5N5.js.map +1 -0
- package/dist/{chunk-GAG7QOVO.js → chunk-64WHKBMP.js} +53 -18
- package/dist/chunk-64WHKBMP.js.map +1 -0
- package/dist/{chunk-7TSYBD3E.js → chunk-65JXA63J.js} +2 -2
- package/dist/{chunk-Z45YRGFO.js → chunk-6NR36UNB.js} +2 -2
- package/dist/{chunk-W77KZHCW.js → chunk-6RH7PRTL.js} +16 -17
- package/dist/chunk-6RH7PRTL.js.map +1 -0
- package/dist/{chunk-3JVXVJ7L.js → chunk-7OBIBPCV.js} +10 -10
- package/dist/{chunk-AR2JDFAE.js → chunk-7Q3RHOA5.js} +2 -2
- package/dist/chunk-7ZGPQOFV.js +190 -0
- package/dist/chunk-7ZGPQOFV.js.map +1 -0
- package/dist/{chunk-QULVCV3M.js → chunk-AJGGBXWA.js} +4 -4
- package/dist/{chunk-CADUYBQD.js → chunk-ATL3ZVXT.js} +2 -2
- package/dist/{chunk-DMQCLZ4Z.js → chunk-ATY3ZASK.js} +2 -2
- package/dist/{chunk-4HDYQL3J.js → chunk-B4CRUZPR.js} +2 -2
- package/dist/{chunk-RV3ARMPN.js → chunk-BMU2DS3S.js} +30 -21
- package/dist/chunk-BMU2DS3S.js.map +1 -0
- package/dist/{chunk-6SAFL5YE.js → chunk-BZ3WMOYX.js} +3 -3
- package/dist/{chunk-UHXCLPGC.js → chunk-C3XWJCG7.js} +2 -2
- package/dist/chunk-C3XWJCG7.js.map +1 -0
- package/dist/{chunk-HXGUIPQB.js → chunk-CKKN25P2.js} +3 -3
- package/dist/{chunk-3URQC7EH.js → chunk-CXPOG3ZY.js} +355 -132
- package/dist/chunk-CXPOG3ZY.js.map +1 -0
- package/dist/{chunk-3FSX6LDG.js → chunk-D2YFQ7XG.js} +18 -3
- package/dist/{chunk-3FSX6LDG.js.map → chunk-D2YFQ7XG.js.map} +1 -1
- package/dist/{chunk-52JPHN5N.js → chunk-D6SXRMZZ.js} +27 -149
- package/dist/chunk-D6SXRMZZ.js.map +1 -0
- package/dist/{chunk-2DHSSLOD.js → chunk-DECNV4QK.js} +13 -15
- package/dist/chunk-DECNV4QK.js.map +1 -0
- package/dist/{chunk-6BU3L4UE.js → chunk-DNKVKO7K.js} +7 -10
- package/dist/chunk-DNKVKO7K.js.map +1 -0
- package/dist/{chunk-6HFM7EIT.js → chunk-EHRIDNZX.js} +2 -2
- package/dist/{chunk-3737A6EA.js → chunk-EHW7NLGD.js} +127 -31
- package/dist/chunk-EHW7NLGD.js.map +1 -0
- package/dist/{chunk-BEFVYAR5.js → chunk-EQOTJL76.js} +4 -4
- package/dist/chunk-EQOTJL76.js.map +1 -0
- package/dist/{chunk-E6427JU2.js → chunk-EV2TDHQZ.js} +19 -3
- package/dist/chunk-EV2TDHQZ.js.map +1 -0
- package/dist/{chunk-WFUIE565.js → chunk-FNYCT27B.js} +17 -14
- package/dist/chunk-FNYCT27B.js.map +1 -0
- package/dist/{chunk-RTAMLDWP.js → chunk-FU5VYEYK.js} +2 -2
- package/dist/chunk-FX3UIDCS.js +66 -0
- package/dist/chunk-FX3UIDCS.js.map +1 -0
- package/dist/{chunk-7F4DBNSP.js → chunk-GANFIM2M.js} +135 -18
- package/dist/chunk-GANFIM2M.js.map +1 -0
- package/dist/{chunk-4VUPLMZ6.js → chunk-GCU42IG7.js} +66 -71
- package/dist/chunk-GCU42IG7.js.map +1 -0
- package/dist/{chunk-RXYYFSBB.js → chunk-GKTW3KLV.js} +4 -4
- package/dist/chunk-HK67PX4J.js +27 -0
- package/dist/chunk-HK67PX4J.js.map +1 -0
- package/dist/{chunk-OF3L2SD6.js → chunk-HOPNIR5R.js} +2 -2
- package/dist/{chunk-WLZ47GSL.js → chunk-HSJBJIB2.js} +12 -10
- package/dist/{chunk-WLZ47GSL.js.map → chunk-HSJBJIB2.js.map} +1 -1
- package/dist/{chunk-ADW22QSB.js → chunk-HWI7GHJZ.js} +4 -4
- package/dist/{chunk-GQ3BX5EA.js → chunk-I3ISCYT7.js} +2 -2
- package/dist/{chunk-YJ6IONGA.js → chunk-IWKCJCLP.js} +11 -3
- package/dist/{chunk-YJ6IONGA.js.map → chunk-IWKCJCLP.js.map} +1 -1
- package/dist/{chunk-NJDQ4YSV.js → chunk-IWQPYT6S.js} +4 -4
- package/dist/{chunk-JRKZTEZZ.js → chunk-J6I5VR6P.js} +444 -73
- package/dist/chunk-J6I5VR6P.js.map +1 -0
- package/dist/{chunk-2Z3NCLNX.js → chunk-JHYKSMVX.js} +7 -7
- package/dist/{chunk-6FJWSWFT.js → chunk-JIHWBKMQ.js} +3 -3
- package/dist/{chunk-YAWK6AWF.js → chunk-JKATP6OE.js} +2 -2
- package/dist/{chunk-PL2GHSCM.js → chunk-JMJSCI7U.js} +157 -90
- package/dist/chunk-JMJSCI7U.js.map +1 -0
- package/dist/{chunk-Q6TEJXBX.js → chunk-JXHNUYQO.js} +31 -49
- package/dist/chunk-JXHNUYQO.js.map +1 -0
- package/dist/{chunk-2GAJGUNM.js → chunk-JYPRZWCZ.js} +343 -229
- package/dist/chunk-JYPRZWCZ.js.map +1 -0
- package/dist/{chunk-5ZKS6ZE2.js → chunk-K6CPIK3R.js} +4 -4
- package/dist/chunk-K6CPIK3R.js.map +1 -0
- package/dist/{chunk-CDB2HVQW.js → chunk-KM6ZXG7U.js} +14 -15
- package/dist/chunk-KM6ZXG7U.js.map +1 -0
- package/dist/{chunk-DG27IUVI.js → chunk-LC6NE4IQ.js} +2 -2
- package/dist/{chunk-WASHZV34.js → chunk-LIR2DJWP.js} +63 -25
- package/dist/chunk-LIR2DJWP.js.map +1 -0
- package/dist/{chunk-VZ3XFUQ7.js → chunk-LUYPYCHY.js} +16 -22
- package/dist/chunk-LUYPYCHY.js.map +1 -0
- package/dist/{chunk-G6S5VVHP.js → chunk-M7WBE3OR.js} +10 -10
- package/dist/chunk-M7WBE3OR.js.map +1 -0
- package/dist/{chunk-VJFMXYKP.js → chunk-MPKP6L5E.js} +2 -2
- package/dist/{chunk-IGJCYUT5.js → chunk-NSITFOCJ.js} +1 -1
- package/dist/chunk-NSITFOCJ.js.map +1 -0
- package/dist/{chunk-FUHKW252.js → chunk-OCJ3JA4O.js} +2 -2
- package/dist/{chunk-VCETL77O.js → chunk-ONPVHX2Y.js} +36 -7
- package/dist/chunk-ONPVHX2Y.js.map +1 -0
- package/dist/{chunk-WLYIROCJ.js → chunk-OQMCFHUX.js} +2 -2
- package/dist/{chunk-JRCYZEHU.js → chunk-OR2FYRYR.js} +2 -2
- package/dist/{chunk-HNHCQ556.js → chunk-PFWE7FJG.js} +2 -2
- package/dist/{chunk-NPP5R7FF.js → chunk-PJX72ICF.js} +22 -18
- package/dist/chunk-PJX72ICF.js.map +1 -0
- package/dist/{chunk-U5O6GIWZ.js → chunk-POFYIGQ2.js} +3 -3
- package/dist/{chunk-35EBKWQU.js → chunk-QH47SQLD.js} +4 -4
- package/dist/{chunk-FZ6NYJ7L.js → chunk-QQRRKO7W.js} +11 -8
- package/dist/chunk-QQRRKO7W.js.map +1 -0
- package/dist/{chunk-HVQGCKY4.js → chunk-QVXZFJBU.js} +2 -2
- package/dist/{chunk-FMQJZH4R.js → chunk-RDB66EKD.js} +6 -6
- package/dist/{chunk-X56RTUK3.js → chunk-RJZQ2PVD.js} +3 -3
- package/dist/{chunk-SUFG5E73.js → chunk-RPRASGEY.js} +2 -2
- package/dist/{chunk-XWX7GL56.js → chunk-S2I5MYSA.js} +7 -10
- package/dist/chunk-S2I5MYSA.js.map +1 -0
- package/dist/{chunk-FFDNKRCY.js → chunk-S6PJ6ZKE.js} +2 -2
- package/dist/chunk-S6PJ6ZKE.js.map +1 -0
- package/dist/{chunk-JIUVJ4M7.js → chunk-S7PM7Z4K.js} +3 -3
- package/dist/{chunk-55LKVALY.js → chunk-T7IR4N2S.js} +1 -3
- package/dist/chunk-T7IR4N2S.js.map +1 -0
- package/dist/{chunk-N35NC4JH.js → chunk-TKBB62DN.js} +2 -2
- package/dist/{chunk-YPYHVOXP.js → chunk-UJ4Z67UQ.js} +2 -2
- package/dist/chunk-UJ4Z67UQ.js.map +1 -0
- package/dist/{chunk-7MNBICB5.js → chunk-W3HAIN6U.js} +16 -14
- package/dist/chunk-W3HAIN6U.js.map +1 -0
- package/dist/{chunk-4UVDI4XE.js → chunk-WPZ5FVAS.js} +4 -4
- package/dist/{chunk-MSWYQLMQ.js → chunk-XINT4VJA.js} +2 -2
- package/dist/{chunk-7G6VDWXB.js → chunk-XPEPMK4Y.js} +3 -3
- package/dist/chunk-XPEPMK4Y.js.map +1 -0
- package/dist/{chunk-W3TVWF6N.js → chunk-YCGLAANM.js} +2 -2
- package/dist/{chunk-O2ERS4UJ.js → chunk-YTUFV7U7.js} +80 -51
- package/dist/chunk-YTUFV7U7.js.map +1 -0
- package/dist/{chunk-FDX7OWWI.js → chunk-YYV53EHO.js} +2 -2
- package/dist/{chunk-HNGSV2YC.js → chunk-Z3BZXPRO.js} +67 -10
- package/dist/chunk-Z3BZXPRO.js.map +1 -0
- package/dist/{chunk-6NVPFKN3.js → chunk-ZIMQDXTQ.js} +92 -35
- package/dist/chunk-ZIMQDXTQ.js.map +1 -0
- package/dist/{chunk-5JY5TSVY.js → chunk-ZJUZOJVW.js} +25 -31
- package/dist/chunk-ZJUZOJVW.js.map +1 -0
- package/dist/{chunk-3IXIU6FP.js → chunk-ZY6P7M52.js} +7 -10
- package/dist/chunk-ZY6P7M52.js.map +1 -0
- package/dist/{chunk-BWVKEOPE.js → chunk-ZYZJLYNS.js} +7 -11
- package/dist/chunk-ZYZJLYNS.js.map +1 -0
- package/dist/classified/index.js +5 -5
- package/dist/{classified-marker-2KJAXRRO.js → classified-marker-AZDSDG6V.js} +3 -3
- package/dist/collection-facade-WSUAYFJ4.js +45 -0
- package/dist/{computed-6G5M3UPH.js → computed-VG2PCM4L.js} +3 -3
- package/dist/consent/index.js +10 -10
- package/dist/cover/index.js +10 -3
- package/dist/custody/index.js +12 -11
- package/dist/{dead-filter-DCB62VWW.js → dead-filter-JNQNB3TA.js} +2 -2
- package/dist/debug/index.js +1 -1
- package/dist/{delegation-MO7YZYJS.js → delegation-5F36DRDH.js} +24 -23
- package/dist/delegation-5F36DRDH.js.map +1 -0
- package/dist/derivations/index.js +12 -12
- package/dist/derive-MPOGZ4NR.js +22 -0
- package/dist/directory/index.js +10 -10
- package/dist/{dispatch-MJ6SHB3Y.js → dispatch-3ZA733EY.js} +18 -18
- package/dist/{dispatch-FZEAWKVM.js → dispatch-TNM5CRLZ.js} +9 -6
- package/dist/dispatch-TNM5CRLZ.js.map +1 -0
- package/dist/{enclave-JU4YIEPB.js → enclave-Y2ALNDRD.js} +31 -9
- package/dist/executor-BBEEUFO3.js +9 -0
- package/dist/executor-G6G3YEWR.js +9 -0
- package/dist/executor-ZUTUMTPA.js +29 -0
- package/dist/export-accessible-S3KEB763.js +23 -0
- package/dist/extract-partition-KVCTSUVE.js +38 -0
- package/dist/{fanout-sidecar-NNAJQXMX.js → fanout-sidecar-3QZU7ZZX.js} +18 -27
- package/dist/fanout-sidecar-3QZU7ZZX.js.map +1 -0
- package/dist/find-V4FN5ITT.js +11 -0
- package/dist/forget/index.js +9 -9
- package/dist/guards/index.js +7 -7
- package/dist/history/index.js +23 -20
- package/dist/history/index.js.map +1 -1
- package/dist/i18n/index.js +14 -14
- package/dist/index.d.ts +30 -13
- package/dist/index.js +180 -188
- package/dist/index.js.map +1 -1
- package/dist/indexing/index.js +4 -4
- package/dist/introspection/index.js +11 -11
- package/dist/issue-5CFBWBRX.js +19 -0
- package/dist/kernel/collection.d.ts +8 -2
- package/dist/kernel/constants.d.ts +36 -0
- package/dist/kernel/enclave/crypto.d.ts +52 -4
- package/dist/kernel/enclave/index.d.ts +10 -3
- package/dist/kernel/enclave/record-aad.d.ts +131 -0
- package/dist/kernel/enclave/record-envelope.d.ts +76 -0
- package/dist/kernel/enclave/record-keys/envelope-body.d.ts +34 -2
- package/dist/kernel/enclave/record-keys/lifecycle.d.ts +22 -5
- package/dist/kernel/enclave/record-keys/record-codec.d.ts +47 -14
- package/dist/kernel/enclave/record-keys/rekey-blob.d.ts +88 -0
- package/dist/kernel/enclave/record-keys/rekey.d.ts +91 -0
- package/dist/kernel/enclave/record-keys/tombstone.d.ts +3 -2
- package/dist/kernel/errors.d.ts +132 -12
- package/dist/kernel/merge-authority.d.ts +25 -0
- package/dist/kernel/noydb.d.ts +27 -4
- package/dist/kernel/query/builder.d.ts +51 -4
- package/dist/kernel/query/join.d.ts +27 -0
- package/dist/kernel/query/live.d.ts +31 -9
- package/dist/kernel/query/predicate.d.ts +9 -0
- package/dist/kernel/refs.d.ts +3 -1
- package/dist/kernel/sync-policy.d.ts +0 -2
- package/dist/kernel/tier-visibility.d.ts +34 -0
- package/dist/kernel/types.d.ts +111 -13
- package/dist/kernel/vault.d.ts +6 -6
- package/dist/kernel/via/index.d.ts +11 -2
- package/dist/kernel/via/reconcile.d.ts +12 -0
- package/dist/{ledger-AETNF4OM.js → ledger-MQIIOTZB.js} +11 -11
- package/dist/liberate-LW7OKVBH.js +25 -0
- package/dist/{link-set-E5HNY67I.js → link-set-5PJBBR63.js} +11 -11
- package/dist/{managed-secret-CWQ6PND5.js → managed-secret-ETDG6AAE.js} +11 -3
- package/dist/materialized-views/index.js +24 -24
- package/dist/migrate-cek-V3VDRV24.js +19 -0
- package/dist/migrate-cek-V3VDRV24.js.map +1 -0
- package/dist/money/index.js +5 -5
- package/dist/noydb-LFDRMYZ5.js +85 -0
- package/dist/overlay-views/index.js +4 -4
- package/dist/periods/index.js +12 -12
- package/dist/pod/index.js +79 -89
- package/dist/pod-handle-AZ3CXY5Y.js +41 -0
- package/dist/pod-handle-AZ3CXY5Y.js.map +1 -0
- package/dist/policy/index.js +11 -4
- package/dist/port/to/index.d.ts +4 -4
- package/dist/port/to/locator.d.ts +54 -8
- package/dist/port/with/i18n-strategy.d.ts +4 -1
- package/dist/port/with/lookup-strategy.d.ts +4 -1
- package/dist/port/with/merge-authority.d.ts +52 -0
- package/dist/port/with/service-bus.d.ts +0 -4
- package/dist/port/with/strategies.d.ts +2 -0
- package/dist/port/with/team-strategy.d.ts +5 -1
- package/dist/portability/index.js +8 -8
- package/dist/{post-register-2XSSMGEQ.js → post-register-QCJYRMIK.js} +6 -6
- package/dist/query/index.js +6 -6
- package/dist/reduce/index.js +6 -6
- package/dist/register-JBOEHTVX.js +32 -0
- package/dist/registry-5DYHQFJS.js +9 -0
- package/dist/registry-EANV44W2.js +9 -0
- package/dist/registry-J25H6VB4.js +19 -0
- package/dist/registry-R23SQUQH.js +18 -0
- package/dist/request-withdrawal-KQ4W4UT5.js +31 -0
- package/dist/{reveal-BW36KCOQ.js → reveal-W7BKZSUP.js} +6 -6
- package/dist/revoke-H3VSTAIE.js +24 -0
- package/dist/satellites/index.js +1 -1
- package/dist/schema-update/index.js +2 -2
- package/dist/sealed-record/index.js +20 -13
- package/dist/sealed-record/index.js.map +1 -1
- package/dist/search/index.js +4 -4
- package/dist/{seed-GDV5PT4R.js → seed-55FPOMYP.js} +20 -22
- package/dist/seed-55FPOMYP.js.map +1 -0
- package/dist/sequence/index.js +9 -9
- package/dist/session/index.js +10 -10
- package/dist/shadow/index.js +2 -2
- package/dist/share-link/index.js +1 -1
- package/dist/signer-53AQ3BU2.js +25 -0
- package/dist/snapshots/index.js +10 -10
- package/dist/snapshots/index.js.map +1 -1
- package/dist/{stale-ARHFVL5U.js → stale-TH7SSVRV.js} +10 -10
- package/dist/storage-WSF7ZKTL.js +23 -0
- package/dist/{store-coordination-provider-GFCUOBR6.js → store-coordination-provider-R27VRD6K.js} +18 -12
- package/dist/store-coordination-provider-R27VRD6K.js.map +1 -0
- package/dist/sync/index.js +11 -11
- package/dist/team/index.js +15 -14
- package/dist/tiers/index.js +11 -10
- package/dist/to/index.js +17 -9
- package/dist/to/index.js.map +1 -1
- package/dist/transactions/index.js +4 -4
- package/dist/{ulid-PTAIMDG4.js → ulid-VQW6ERQN.js} +2 -2
- package/dist/util/index.js +1 -1
- package/dist/vault-head/index.js +115 -0
- package/dist/vault-head/index.js.map +1 -0
- package/dist/{verify-RO5RTZOJ.js → verify-M5LQH43C.js} +5 -5
- package/dist/via/blob/index.d.ts +3 -0
- package/dist/via/lookup/handle.d.ts +4 -1
- package/dist/walk-NABCHDZN.js +21 -0
- package/dist/with-audit/periods/periods.d.ts +1 -1
- package/dist/with-audit/periods/strategy.d.ts +1 -1
- package/dist/with-audit/sealed-record/index.d.ts +13 -0
- package/dist/with-audit/tiers/index.d.ts +17 -2
- package/dist/with-cargo/adopt-partition.d.ts +1 -1
- package/dist/with-cargo/extract-partition.d.ts +1 -1
- package/dist/with-cargo/index.d.ts +1 -1
- package/dist/with-commit/history/history.d.ts +26 -0
- package/dist/with-commit/history/index.d.ts +2 -1
- package/dist/with-commit/history/ledger/store.d.ts +7 -1
- package/dist/with-commit/history/strategy.d.ts +11 -1
- package/dist/with-commit/numbering/index.d.ts +0 -5
- package/dist/with-commit/vault-head/active.d.ts +2 -0
- package/dist/with-commit/vault-head/head.d.ts +28 -0
- package/dist/with-commit/vault-head/index.d.ts +10 -0
- package/dist/with-commit/vault-head/strategy.d.ts +127 -0
- package/dist/with-commit/vault-head/verify.d.ts +90 -0
- package/dist/with-formula/materialized-views/dependency-analyzer.d.ts +4 -0
- package/dist/with-formula/materialized-views/projection-legs.d.ts +59 -0
- package/dist/with-formula/materialized-views/registry.d.ts +50 -0
- package/dist/with-formula/materialized-views/types.d.ts +68 -10
- package/dist/with-party/directory/cover/storage.d.ts +0 -8
- package/dist/with-party/directory/storage.d.ts +0 -11
- package/dist/with-party/directory/visibility.d.ts +0 -21
- package/dist/with-party/policy/storage.d.ts +0 -10
- package/dist/with-party/team/index.d.ts +1 -1
- package/dist/with-party/team/keyring.d.ts +139 -2
- package/dist/with-party/team/noydb-facade.d.ts +5 -1
- package/dist/with-party/team/roster-tag.d.ts +101 -0
- package/dist/with-party/team/tiers.d.ts +2 -1
- package/dist/with-pod/format.d.ts +10 -12
- package/dist/with-pod/index.d.ts +10 -10
- package/dist/with-pod/open.d.ts +2 -2
- package/dist/with-pod/pod-handle.d.ts +19 -0
- package/dist/with-pod/pod-store.d.ts +0 -8
- package/dist/with-pod/{bundle.d.ts → pod.d.ts} +11 -19
- package/dist/with-pod/ulid.d.ts +1 -1
- package/dist/with-shape/blobs/blob-compaction.d.ts +13 -0
- package/dist/with-shape/blobs/blob-set.d.ts +83 -11
- package/dist/with-shape/blobs/orphan-report.d.ts +62 -0
- package/dist/with-sync/engine.d.ts +54 -5
- package/dist/with-sync/strategy.d.ts +3 -0
- package/dist/withdraw-accessible-VCINIG6V.js +28 -0
- package/package.json +10 -4
- package/dist/api-RXUMEKT3.js +0 -20
- package/dist/backup-KULFZ2T4.js.map +0 -1
- package/dist/bundle-handle-GFNHT52M.js +0 -36
- package/dist/bundle-handle-GFNHT52M.js.map +0 -1
- package/dist/chunk-2DHSSLOD.js.map +0 -1
- package/dist/chunk-2GAJGUNM.js.map +0 -1
- package/dist/chunk-3737A6EA.js.map +0 -1
- package/dist/chunk-3IXIU6FP.js.map +0 -1
- package/dist/chunk-3URQC7EH.js.map +0 -1
- package/dist/chunk-4GZ6XOVW.js.map +0 -1
- package/dist/chunk-4I72F5DF.js.map +0 -1
- package/dist/chunk-4VUPLMZ6.js.map +0 -1
- package/dist/chunk-52JPHN5N.js.map +0 -1
- package/dist/chunk-55LKVALY.js.map +0 -1
- package/dist/chunk-5JY5TSVY.js.map +0 -1
- package/dist/chunk-5ZKS6ZE2.js.map +0 -1
- package/dist/chunk-6BU3L4UE.js.map +0 -1
- package/dist/chunk-6NVPFKN3.js.map +0 -1
- package/dist/chunk-7F4DBNSP.js.map +0 -1
- package/dist/chunk-7G6VDWXB.js.map +0 -1
- package/dist/chunk-7H73RIE3.js +0 -45
- package/dist/chunk-7H73RIE3.js.map +0 -1
- package/dist/chunk-7MNBICB5.js.map +0 -1
- package/dist/chunk-AFHQATY4.js +0 -47
- package/dist/chunk-AFHQATY4.js.map +0 -1
- package/dist/chunk-AHLJSVRL.js.map +0 -1
- package/dist/chunk-BEFVYAR5.js.map +0 -1
- package/dist/chunk-BRVW2GS5.js.map +0 -1
- package/dist/chunk-BWVKEOPE.js.map +0 -1
- package/dist/chunk-CDB2HVQW.js.map +0 -1
- package/dist/chunk-CEJWMBXO.js.map +0 -1
- package/dist/chunk-E6427JU2.js.map +0 -1
- package/dist/chunk-FFDNKRCY.js.map +0 -1
- package/dist/chunk-FZ6NYJ7L.js.map +0 -1
- package/dist/chunk-G6S5VVHP.js.map +0 -1
- package/dist/chunk-GAG7QOVO.js.map +0 -1
- package/dist/chunk-HNGSV2YC.js.map +0 -1
- package/dist/chunk-IGJCYUT5.js.map +0 -1
- package/dist/chunk-JJNOLSG5.js.map +0 -1
- package/dist/chunk-JRKZTEZZ.js.map +0 -1
- package/dist/chunk-NPP5R7FF.js.map +0 -1
- package/dist/chunk-O2ERS4UJ.js.map +0 -1
- package/dist/chunk-PDLLCOGD.js.map +0 -1
- package/dist/chunk-PL2GHSCM.js.map +0 -1
- package/dist/chunk-PNKHAKQ7.js.map +0 -1
- package/dist/chunk-Q6TEJXBX.js.map +0 -1
- package/dist/chunk-RV3ARMPN.js.map +0 -1
- package/dist/chunk-UHXCLPGC.js.map +0 -1
- package/dist/chunk-VCETL77O.js.map +0 -1
- package/dist/chunk-VZ3XFUQ7.js.map +0 -1
- package/dist/chunk-W77KZHCW.js.map +0 -1
- package/dist/chunk-WASHZV34.js.map +0 -1
- package/dist/chunk-WFUIE565.js.map +0 -1
- package/dist/chunk-XWX7GL56.js.map +0 -1
- package/dist/chunk-YPYHVOXP.js.map +0 -1
- package/dist/chunk-ZJADGNYF.js.map +0 -1
- package/dist/collection-facade-QEJIM6BC.js +0 -45
- package/dist/delegation-MO7YZYJS.js.map +0 -1
- package/dist/derive-IUA6JFLB.js +0 -22
- package/dist/dispatch-FZEAWKVM.js.map +0 -1
- package/dist/executor-CYJQLKKI.js +0 -9
- package/dist/executor-S4QIKEHW.js +0 -9
- package/dist/executor-YIQB2S6N.js +0 -29
- package/dist/export-accessible-4S36PQNR.js +0 -23
- package/dist/extract-partition-IO7FDZ2P.js +0 -38
- package/dist/fanout-sidecar-NNAJQXMX.js.map +0 -1
- package/dist/find-RBBYKXI7.js +0 -11
- package/dist/issue-RIVHSY2S.js +0 -19
- package/dist/liberate-GFN4C7RR.js +0 -24
- package/dist/noydb-ASEXNJS6.js +0 -83
- package/dist/register-4EFJCVYD.js +0 -32
- package/dist/registry-4SDHHOJ7.js +0 -18
- package/dist/registry-CZVINVQH.js +0 -9
- package/dist/registry-IKUR2MXD.js +0 -9
- package/dist/registry-OYTFGWVK.js +0 -19
- package/dist/request-withdrawal-KGXGDPVQ.js +0 -31
- package/dist/revoke-JFN773KF.js +0 -24
- package/dist/seed-GDV5PT4R.js.map +0 -1
- package/dist/signer-TA55QB6R.js +0 -25
- package/dist/storage-V7MTFAQJ.js +0 -23
- package/dist/store-coordination-provider-GFCUOBR6.js.map +0 -1
- package/dist/walk-3ZECBFDA.js +0 -21
- package/dist/with-pod/bundle-handle.d.ts +0 -9
- package/dist/withdraw-accessible-7PG4DYQK.js +0 -28
- /package/dist/{api-RXUMEKT3.js.map → api-6X2VLZ7J.js.map} +0 -0
- /package/dist/{chunk-KUDZVJKQ.js.map → chunk-22GR3O4J.js.map} +0 -0
- /package/dist/{chunk-CCZJJ4I2.js.map → chunk-2CBFYXJX.js.map} +0 -0
- /package/dist/{chunk-FAXZQ5UF.js.map → chunk-323MN67Z.js.map} +0 -0
- /package/dist/{chunk-VMCCGUQB.js.map → chunk-36CEG6CM.js.map} +0 -0
- /package/dist/{chunk-747LRSOO.js.map → chunk-4K6BIMLF.js.map} +0 -0
- /package/dist/{chunk-FNSMZQS4.js.map → chunk-5IHGJHWC.js.map} +0 -0
- /package/dist/{chunk-HPLWFNG4.js.map → chunk-5O5ZSW7N.js.map} +0 -0
- /package/dist/{chunk-7TSYBD3E.js.map → chunk-65JXA63J.js.map} +0 -0
- /package/dist/{chunk-Z45YRGFO.js.map → chunk-6NR36UNB.js.map} +0 -0
- /package/dist/{chunk-3JVXVJ7L.js.map → chunk-7OBIBPCV.js.map} +0 -0
- /package/dist/{chunk-AR2JDFAE.js.map → chunk-7Q3RHOA5.js.map} +0 -0
- /package/dist/{chunk-QULVCV3M.js.map → chunk-AJGGBXWA.js.map} +0 -0
- /package/dist/{chunk-CADUYBQD.js.map → chunk-ATL3ZVXT.js.map} +0 -0
- /package/dist/{chunk-DMQCLZ4Z.js.map → chunk-ATY3ZASK.js.map} +0 -0
- /package/dist/{chunk-4HDYQL3J.js.map → chunk-B4CRUZPR.js.map} +0 -0
- /package/dist/{chunk-6SAFL5YE.js.map → chunk-BZ3WMOYX.js.map} +0 -0
- /package/dist/{chunk-HXGUIPQB.js.map → chunk-CKKN25P2.js.map} +0 -0
- /package/dist/{chunk-6HFM7EIT.js.map → chunk-EHRIDNZX.js.map} +0 -0
- /package/dist/{chunk-RTAMLDWP.js.map → chunk-FU5VYEYK.js.map} +0 -0
- /package/dist/{chunk-RXYYFSBB.js.map → chunk-GKTW3KLV.js.map} +0 -0
- /package/dist/{chunk-OF3L2SD6.js.map → chunk-HOPNIR5R.js.map} +0 -0
- /package/dist/{chunk-ADW22QSB.js.map → chunk-HWI7GHJZ.js.map} +0 -0
- /package/dist/{chunk-GQ3BX5EA.js.map → chunk-I3ISCYT7.js.map} +0 -0
- /package/dist/{chunk-NJDQ4YSV.js.map → chunk-IWQPYT6S.js.map} +0 -0
- /package/dist/{chunk-2Z3NCLNX.js.map → chunk-JHYKSMVX.js.map} +0 -0
- /package/dist/{chunk-6FJWSWFT.js.map → chunk-JIHWBKMQ.js.map} +0 -0
- /package/dist/{chunk-YAWK6AWF.js.map → chunk-JKATP6OE.js.map} +0 -0
- /package/dist/{chunk-DG27IUVI.js.map → chunk-LC6NE4IQ.js.map} +0 -0
- /package/dist/{chunk-VJFMXYKP.js.map → chunk-MPKP6L5E.js.map} +0 -0
- /package/dist/{chunk-FUHKW252.js.map → chunk-OCJ3JA4O.js.map} +0 -0
- /package/dist/{chunk-WLYIROCJ.js.map → chunk-OQMCFHUX.js.map} +0 -0
- /package/dist/{chunk-JRCYZEHU.js.map → chunk-OR2FYRYR.js.map} +0 -0
- /package/dist/{chunk-HNHCQ556.js.map → chunk-PFWE7FJG.js.map} +0 -0
- /package/dist/{chunk-U5O6GIWZ.js.map → chunk-POFYIGQ2.js.map} +0 -0
- /package/dist/{chunk-35EBKWQU.js.map → chunk-QH47SQLD.js.map} +0 -0
- /package/dist/{chunk-HVQGCKY4.js.map → chunk-QVXZFJBU.js.map} +0 -0
- /package/dist/{chunk-FMQJZH4R.js.map → chunk-RDB66EKD.js.map} +0 -0
- /package/dist/{chunk-X56RTUK3.js.map → chunk-RJZQ2PVD.js.map} +0 -0
- /package/dist/{chunk-SUFG5E73.js.map → chunk-RPRASGEY.js.map} +0 -0
- /package/dist/{chunk-JIUVJ4M7.js.map → chunk-S7PM7Z4K.js.map} +0 -0
- /package/dist/{chunk-N35NC4JH.js.map → chunk-TKBB62DN.js.map} +0 -0
- /package/dist/{chunk-4UVDI4XE.js.map → chunk-WPZ5FVAS.js.map} +0 -0
- /package/dist/{chunk-MSWYQLMQ.js.map → chunk-XINT4VJA.js.map} +0 -0
- /package/dist/{chunk-W3TVWF6N.js.map → chunk-YCGLAANM.js.map} +0 -0
- /package/dist/{chunk-FDX7OWWI.js.map → chunk-YYV53EHO.js.map} +0 -0
- /package/dist/{classified-marker-2KJAXRRO.js.map → classified-marker-AZDSDG6V.js.map} +0 -0
- /package/dist/{collection-facade-QEJIM6BC.js.map → collection-facade-WSUAYFJ4.js.map} +0 -0
- /package/dist/{computed-6G5M3UPH.js.map → computed-VG2PCM4L.js.map} +0 -0
- /package/dist/{dead-filter-DCB62VWW.js.map → dead-filter-JNQNB3TA.js.map} +0 -0
- /package/dist/{derive-IUA6JFLB.js.map → derive-MPOGZ4NR.js.map} +0 -0
- /package/dist/{dispatch-MJ6SHB3Y.js.map → dispatch-3ZA733EY.js.map} +0 -0
- /package/dist/{enclave-JU4YIEPB.js.map → enclave-Y2ALNDRD.js.map} +0 -0
- /package/dist/{executor-CYJQLKKI.js.map → executor-BBEEUFO3.js.map} +0 -0
- /package/dist/{executor-S4QIKEHW.js.map → executor-G6G3YEWR.js.map} +0 -0
- /package/dist/{executor-YIQB2S6N.js.map → executor-ZUTUMTPA.js.map} +0 -0
- /package/dist/{export-accessible-4S36PQNR.js.map → export-accessible-S3KEB763.js.map} +0 -0
- /package/dist/{extract-partition-IO7FDZ2P.js.map → extract-partition-KVCTSUVE.js.map} +0 -0
- /package/dist/{find-RBBYKXI7.js.map → find-V4FN5ITT.js.map} +0 -0
- /package/dist/{issue-RIVHSY2S.js.map → issue-5CFBWBRX.js.map} +0 -0
- /package/dist/{ledger-AETNF4OM.js.map → ledger-MQIIOTZB.js.map} +0 -0
- /package/dist/{liberate-GFN4C7RR.js.map → liberate-LW7OKVBH.js.map} +0 -0
- /package/dist/{link-set-E5HNY67I.js.map → link-set-5PJBBR63.js.map} +0 -0
- /package/dist/{managed-secret-CWQ6PND5.js.map → managed-secret-ETDG6AAE.js.map} +0 -0
- /package/dist/{noydb-ASEXNJS6.js.map → noydb-LFDRMYZ5.js.map} +0 -0
- /package/dist/{post-register-2XSSMGEQ.js.map → post-register-QCJYRMIK.js.map} +0 -0
- /package/dist/{register-4EFJCVYD.js.map → register-JBOEHTVX.js.map} +0 -0
- /package/dist/{registry-4SDHHOJ7.js.map → registry-5DYHQFJS.js.map} +0 -0
- /package/dist/{registry-CZVINVQH.js.map → registry-EANV44W2.js.map} +0 -0
- /package/dist/{registry-IKUR2MXD.js.map → registry-J25H6VB4.js.map} +0 -0
- /package/dist/{registry-OYTFGWVK.js.map → registry-R23SQUQH.js.map} +0 -0
- /package/dist/{request-withdrawal-KGXGDPVQ.js.map → request-withdrawal-KQ4W4UT5.js.map} +0 -0
- /package/dist/{reveal-BW36KCOQ.js.map → reveal-W7BKZSUP.js.map} +0 -0
- /package/dist/{revoke-JFN773KF.js.map → revoke-H3VSTAIE.js.map} +0 -0
- /package/dist/{signer-TA55QB6R.js.map → signer-53AQ3BU2.js.map} +0 -0
- /package/dist/{stale-ARHFVL5U.js.map → stale-TH7SSVRV.js.map} +0 -0
- /package/dist/{storage-V7MTFAQJ.js.map → storage-WSF7ZKTL.js.map} +0 -0
- /package/dist/{ulid-PTAIMDG4.js.map → ulid-VQW6ERQN.js.map} +0 -0
- /package/dist/{verify-RO5RTZOJ.js.map → verify-M5LQH43C.js.map} +0 -0
- /package/dist/{walk-3ZECBFDA.js.map → walk-NABCHDZN.js.map} +0 -0
- /package/dist/{withdraw-accessible-7PG4DYQK.js.map → withdraw-accessible-VCINIG6V.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/with-audit/portability/request-withdrawal.ts"],"sourcesContent":["/**\n * Two-party withdrawal ceremony.\n *\n * The conservative counterpart to `unilateralWithdrawal`: a non-owner —\n * including a read-only `client`/`viewer` who cannot self-serve a deletion —\n * files a durable REQUEST; an owner/admin reviews it and either APPROVES\n * (extract-and-dispose under firm authority) or REJECTS it. Every step is\n * audited in the tamper-evident ledger.\n *\n * requester: vault.user.requestWithdrawal({ scope, disposition?, legalBasis? })\n * owner: vault.user.listWithdrawalRequests()\n * vault.user.approveWithdrawal(requestId, { reKey }) → { bundle, snapshot? }\n * vault.user.rejectWithdrawal(requestId, { reason })\n *\n * Requests live in the reserved `_user_withdrawal_requests` namespace. The\n * record body is plaintext metadata (collection names + disposition + legal\n * basis — none secret in this trust model; the owner sees the data anyway) and\n * carries NO secret: the re-key secret is supplied by the approver at\n * approval time and conveyed to the requester out-of-band, so no secret is\n * stored at rest.\n */\nimport type { Vault } from '../../kernel/vault.js'\nimport { buildRecordEnvelope } from '../../kernel/enclave/index.js'\nimport { NoydbError } from '../../kernel/errors.js'\nimport { resolveAccessibleCollections, buildAccessibleBundle } from './export-accessible.js'\nimport { freezeAndDeleteClosure, randomId, type FrozenSnapshotRef, type WithdrawResult } from './withdraw-accessible.js'\n\nexport const WITHDRAWAL_REQUESTS_COLLECTION = '_user_withdrawal_requests'\n\n/** Raised when a request is missing, already decided, or expired. */\nexport class WithdrawalRequestError extends NoydbError {\n constructor(message: string) {\n super('WITHDRAWAL_REQUEST', message)\n this.name = 'WithdrawalRequestError'\n }\n}\n\nexport type WithdrawalRequestStatus = 'pending' | 'approved' | 'rejected'\n\nexport interface WithdrawalRequest {\n readonly requestId: string\n readonly requester: string\n readonly collections: readonly string[]\n readonly disposition: 'delete' | 'freeze'\n readonly legalBasis?: string\n readonly status: WithdrawalRequestStatus\n readonly requestedAt: string\n readonly expiresAt?: string\n readonly decidedAt?: string\n readonly decidedBy?: string\n readonly rejectReason?: string\n readonly snapshotSha256?: string\n}\n\nexport interface RequestWithdrawalOptions {\n readonly scope?: { readonly collections?: readonly string[] }\n readonly disposition?: 'delete' | 'freeze'\n readonly legalBasis?: string\n /** Time-to-live in ms; after this the request can no longer be approved. */\n readonly expiresInMs?: number\n}\n\nexport interface RequestWithdrawalResult {\n readonly requestId: string\n readonly status: WithdrawalRequestStatus\n readonly expiresAt?: string\n}\n\nfunction writeRequest(vault: Vault, req: WithdrawalRequest, expectedVersion: number): Promise<void> {\n const { name: vaultName, adapter } = vault._introspectState()\n const body = JSON.stringify(req)\n const actor = req.decidedBy ?? req.requester\n const env = buildRecordEnvelope(\n { collection: WITHDRAWAL_REQUESTS_COLLECTION, id: req.requestId, by: actor, version: expectedVersion + 1 },\n { ts: req.decidedAt ?? req.requestedAt, iv: '', data: body},\n )\n return adapter.put(vaultName, WITHDRAWAL_REQUESTS_COLLECTION, req.requestId, env, expectedVersion)\n}\n\nasync function readRequest(vault: Vault, requestId: string): Promise<{ req: WithdrawalRequest; version: number }> {\n const { name: vaultName, adapter } = vault._introspectState()\n const env = await adapter.get(vaultName, WITHDRAWAL_REQUESTS_COLLECTION, requestId)\n if (!env) throw new WithdrawalRequestError(`withdrawal request \"${requestId}\" not found`)\n return { req: JSON.parse(env._data) as WithdrawalRequest, version: env._v }\n}\n\n/**\n * Requester side. Files a durable request for the caller's accessible scope.\n * Gated by `user-request-withdrawal` (checked in the UserApi wrapper).\n */\nexport async function requestWithdrawal(\n vault: Vault,\n opts: RequestWithdrawalOptions = {},\n): Promise<RequestWithdrawalResult> {\n const { keyring } = vault._introspectState()\n // Resolve the requester's accessible collections (read access defines \"theirs\";\n // the owner — who can delete anything — executes the disposition on approval).\n const collections = resolveAccessibleCollections(keyring, opts.scope, false)\n if (!collections || collections.length === 0) {\n throw new WithdrawalRequestError(\n 'requestWithdrawal needs a concrete scope.collections (the caller has all-collection access — name the collections to withdraw)',\n )\n }\n const requestId = `wr-${randomId()}`\n const requestedAt = new Date().toISOString()\n const req: WithdrawalRequest = {\n requestId, requester: keyring.userId, collections, disposition: opts.disposition ?? 'delete',\n status: 'pending', requestedAt,\n ...(opts.legalBasis ? { legalBasis: opts.legalBasis } : {}),\n ...(opts.expiresInMs ? { expiresAt: new Date(Date.parse(requestedAt) + opts.expiresInMs).toISOString() } : {}),\n }\n await writeRequest(vault, req, 0) // create-only\n await vault._getLedgerOrNull()?.append({\n op: 'lifecycle', collection: '', id: '', version: 0, actor: keyring.userId, payloadHash: '',\n reason: `user-withdrawal-request:${requestId}:${keyring.userId}`,\n })\n return { requestId, status: 'pending', ...(req.expiresAt ? { expiresAt: req.expiresAt } : {}) }\n}\n\n/** Owner side. List filed requests (optionally by status). */\nexport async function listWithdrawalRequests(\n vault: Vault,\n opts: { status?: WithdrawalRequestStatus } = {},\n): Promise<WithdrawalRequest[]> {\n const { name: vaultName, adapter } = vault._introspectState()\n const ids = await adapter.list(vaultName, WITHDRAWAL_REQUESTS_COLLECTION)\n const out: WithdrawalRequest[] = []\n for (const id of ids) {\n const env = await adapter.get(vaultName, WITHDRAWAL_REQUESTS_COLLECTION, id)\n if (!env) continue\n const req = JSON.parse(env._data) as WithdrawalRequest\n if (!opts.status || req.status === opts.status) out.push(req)\n }\n return out\n}\n\nfunction assertApprover(vault: Vault): string {\n const { keyring } = vault._introspectState()\n // FR-6: custodian is INTENTIONALLY excluded (SAFER default — review flag).\n // Approving a two-party withdrawal is a destructive extract-and-dispose\n // exercised under FIRM authority — a governance act adjacent to grant/revoke,\n // which a non-owning custodian cannot do. It stays owner/admin-only.\n if (keyring.role !== 'owner' && keyring.role !== 'admin') {\n throw new WithdrawalRequestError('approveWithdrawal / rejectWithdrawal require an owner or admin')\n }\n return keyring.userId\n}\n\nfunction assertPending(req: WithdrawalRequest): void {\n if (req.status !== 'pending') {\n throw new WithdrawalRequestError(`withdrawal request \"${req.requestId}\" is already ${req.status}`)\n }\n if (req.expiresAt && Date.now() > Date.parse(req.expiresAt)) {\n throw new WithdrawalRequestError(`withdrawal request \"${req.requestId}\" expired at ${req.expiresAt}`)\n }\n}\n\nexport interface ApproveWithdrawalOptions {\n /** Re-key the handed-back bundle to a secret the requester will use. */\n readonly reKey?: { readonly secret: string }\n}\n\n/**\n * Owner side. Extract the requester's recorded scope under firm authority,\n * dispose of the source per the request's disposition, mark the request\n * approved, and return the re-keyed bundle to hand back. Gated by\n * `approve-user-withdrawal` (checked in the UserApi wrapper) + owner/admin role.\n */\nexport async function approveWithdrawal(\n vault: Vault,\n requestId: string,\n opts: ApproveWithdrawalOptions = {},\n): Promise<WithdrawResult> {\n const approver = assertApprover(vault)\n const { req, version } = await readRequest(vault, requestId)\n assertPending(req)\n\n // 1. Produce the requester's re-keyed portable copy FIRST (owner authority\n // holds every DEK, so the recorded collections are all readable).\n const bundle = await buildAccessibleBundle(vault, [...req.collections], opts.reKey)\n\n // 2. + 3. dispose of the source (freeze snapshot, optional → delete-closure).\n const snapshot: FrozenSnapshotRef | undefined = await freezeAndDeleteClosure(vault, req.collections, {\n disposition: req.disposition, actorUserId: approver, withdrawalId: `wd-${requestId}`,\n })\n\n // 4. mark approved + audit (OCC against the version we read).\n const decidedAt = new Date().toISOString()\n await writeRequest(vault, {\n ...req, status: 'approved', decidedAt, decidedBy: approver,\n ...(snapshot ? { snapshotSha256: snapshot.sha256 } : {}),\n }, version)\n await vault._getLedgerOrNull()?.append({\n op: 'lifecycle', collection: '', id: '', version: 0, actor: approver, payloadHash: '',\n reason: `user-withdrawal-approved:${requestId}:${req.requester}:${req.disposition}`,\n })\n\n return snapshot ? { bundle, snapshot } : { bundle }\n}\n\nexport interface RejectWithdrawalOptions {\n readonly reason?: string\n}\n\n/** Owner side. Decline a pending request (no data is touched). */\nexport async function rejectWithdrawal(\n vault: Vault,\n requestId: string,\n opts: RejectWithdrawalOptions = {},\n): Promise<WithdrawalRequest> {\n const approver = assertApprover(vault)\n const { req, version } = await readRequest(vault, requestId)\n assertPending(req)\n const decidedAt = new Date().toISOString()\n const updated: WithdrawalRequest = {\n ...req, status: 'rejected', decidedAt, decidedBy: approver,\n ...(opts.reason ? { rejectReason: opts.reason } : {}),\n }\n await writeRequest(vault, updated, version)\n await vault._getLedgerOrNull()?.append({\n op: 'lifecycle', collection: '', id: '', version: 0, actor: approver, payloadHash: '',\n reason: `user-withdrawal-rejected:${requestId}:${req.requester}`,\n })\n return updated\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ValidationError
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-Z3BZXPRO.js";
|
|
4
4
|
|
|
5
5
|
// src/with-audit/periods/window.ts
|
|
6
6
|
var PERIODS_COLLECTION = "_periods";
|
|
@@ -23,4 +23,4 @@ export {
|
|
|
23
23
|
PERIOD_REOPENS_COLLECTION,
|
|
24
24
|
periodExclusiveUpperBound
|
|
25
25
|
};
|
|
26
|
-
//# sourceMappingURL=chunk-
|
|
26
|
+
//# sourceMappingURL=chunk-5O5ZSW7N.js.map
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import {
|
|
2
|
+
validateProjectionLegs
|
|
3
|
+
} from "./chunk-GANFIM2M.js";
|
|
1
4
|
import {
|
|
2
5
|
MaterializedViewConfigError,
|
|
3
6
|
ValidationError
|
|
4
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-Z3BZXPRO.js";
|
|
5
8
|
|
|
6
9
|
// src/with-formula/materialized-views/with-materialized-view.ts
|
|
7
10
|
function withMaterializedView(spec) {
|
|
@@ -134,6 +137,7 @@ function withMaterializedView(spec) {
|
|
|
134
137
|
}
|
|
135
138
|
seenAs.add(l.as);
|
|
136
139
|
}
|
|
140
|
+
validateProjectionLegs(spec.name, spec.projection);
|
|
137
141
|
if (Array.isArray(spec.groupBy) && spec.groupBy.length === 0) {
|
|
138
142
|
throw new MaterializedViewConfigError(
|
|
139
143
|
`withMaterializedView "${spec.name}": groupBy must not be an empty array \u2014 omit it or provide at least one field name`
|
|
@@ -177,4 +181,4 @@ function withMaterializedView(spec) {
|
|
|
177
181
|
export {
|
|
178
182
|
withMaterializedView
|
|
179
183
|
};
|
|
180
|
-
//# sourceMappingURL=chunk-
|
|
184
|
+
//# sourceMappingURL=chunk-5OT4G5N5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/with-formula/materialized-views/with-materialized-view.ts"],"sourcesContent":["import { MaterializedViewConfigError, ValidationError } from '../../kernel/errors.js'\nimport type { MaterializedViewSpec, MaterializedViewStrategy } from './types.js'\nimport { validateProjectionLegs } from './projection-legs.js' // #1140\n\n/**\n * Register a materialized view: a declared query whose result is\n * persisted as a queryable collection and kept fresh as sources\n * change. Writes go through the standard `Collection.put` pipeline;\n * refresh-driven deletes route through `Collection._internalDelete` so\n * user `onDelete` guards on the output collection aren't tripped by\n * housekeeping.\n *\n * Three registration modes:\n * - **single-source** — declare `query: (db) => Query<TRow>`; the\n * dependency analyzer derives source collections from the plan.\n * - **UNION** — declare `unionSources: [{ collection, map }, ...]`\n * plus optional `groupBy` + `aggregate`; the executor reads each\n * arm, maps to the unified row shape, concatenates, then groups\n * and aggregates.\n * - **projection** (#810) — declare `projection: { source, joins,\n * map }`; one output row per primary record, enriched with\n * forward FK legs and reverse \"collect\" legs before `map` runs.\n *\n * The three modes are mutually exclusive — exactly one of `query` /\n * `unionSources` / `projection` must be set at registration time.\n *\n * See design-history/2026-05-20-dim14-mv-v2-design.md (single-source v2),\n * design-history/2026-05-21-dim14-mv-multikey-and-union.md (UNION),\n * and design-history/2026-07-25-join-projection-mv-design.md (projection).\n */\nexport function withMaterializedView<TRow extends Record<string, unknown>>(\n spec: MaterializedViewSpec<TRow>,\n): MaterializedViewStrategy {\n if (!spec.name || spec.name.length === 0) {\n throw new ValidationError('withMaterializedView: name is required')\n }\n // Mutual exclusion: exactly one of the three forms must be declared.\n const declaredForms = [spec.query, spec.unionSources, spec.projection]\n .filter((f) => f !== undefined).length\n if (declaredForms > 1) {\n throw new MaterializedViewConfigError(\n 'query, unionSources, and projection are mutually exclusive — pick one',\n )\n }\n if (declaredForms === 0) {\n throw new MaterializedViewConfigError(\n 'strategy must declare exactly one of query, unionSources, or projection',\n )\n }\n if (spec.query !== undefined && typeof spec.query !== 'function') {\n throw new ValidationError('withMaterializedView: query must be a function returning a Query<T>')\n }\n // UNION-form invariants.\n if (spec.unionSources) {\n // A single arm is a deliberate shape: map→group→aggregate over\n // ONE collection with a COMPUTED bucket key (e.g. month sliced from a\n // date field) — something the query form's stored-field groupBy cannot\n // express. The executor and dependency analyzer are arm-count-agnostic.\n if (spec.unionSources.length < 1) {\n throw new MaterializedViewConfigError(\n 'unionSources requires at least 1 source collection',\n )\n }\n const seen = new Set<string>()\n for (const s of spec.unionSources) {\n if (typeof s?.collection !== 'string' || s.collection.length === 0) {\n throw new MaterializedViewConfigError(\n 'each unionSources entry must declare a non-empty `collection` string',\n )\n }\n if (typeof s.map !== 'function') {\n throw new MaterializedViewConfigError(\n `unionSources entry for \"${s.collection}\" is missing a \\`map\\` function`,\n )\n }\n if (seen.has(s.collection)) {\n throw new MaterializedViewConfigError(\n `unionSources must reference distinct collections (duplicate: \"${s.collection}\")`,\n )\n }\n seen.add(s.collection)\n }\n if (Array.isArray(spec.groupBy) && spec.groupBy.length === 0) {\n throw new MaterializedViewConfigError(\n `withMaterializedView \"${spec.name}\": groupBy must not be an empty array — omit it or provide at least one field name`,\n )\n }\n if (spec.aggregate && !spec.groupBy) {\n throw new MaterializedViewConfigError(\n `withMaterializedView \"${spec.name}\": UNION strategy with aggregate requires groupBy — `\n + `use groupBy to declare the bucketing keys, or remove aggregate for a pure dedup MV`,\n )\n }\n // `moneyFields` only has meaning when there's an aggregate to\n // money-rewrite — it keys reducer outputs, so declaring it without\n // `aggregate` is a no-op config mistake.\n if (spec.moneyFields && !spec.aggregate) {\n throw new MaterializedViewConfigError(\n `withMaterializedView \"${spec.name}\": moneyFields requires aggregate — `\n + `moneyFields rewrites sum/min/max reducers over money output fields, `\n + `so it is meaningless without an aggregate spec`,\n )\n }\n // Per-arm joins resolve right-side collections that the union\n // dependency set (built from arm `collection`s alone) does NOT\n // include. The consumer must list those right-side collections in\n // `sources` so writes to them trigger MV refresh.\n if (spec.unionSources.some(s => s.join && s.join.length > 0) && (!spec.sources || spec.sources.length === 0)) {\n throw new MaterializedViewConfigError(\n `withMaterializedView \"${spec.name}\": a unionSources arm declares join(s) but `\n + `no \\`sources\\` are listed — declare sources: [...] with the right-side `\n + `(join-target) collection names so writes to them trigger MV refresh`,\n )\n }\n if (spec.predicates) {\n throw new MaterializedViewConfigError(\n `withMaterializedView \"${spec.name}\": predicates are not supported on UNION strategies — `\n + `UNION mode does not use a Query<T> chain, so .wherePredicate() cannot fire. `\n + `Use the query() form, or open an issue if per-arm predicates are needed`,\n )\n }\n }\n // Projection-form invariants (#810). Shape checks only — the\n // semantic ref() check on collect legs (the `on` field must carry a\n // ref() targeting the projection source) runs at first\n // materialization, parity with join-time ref errors.\n if (spec.projection) {\n const projection = spec.projection\n if (typeof projection.source !== 'string' || projection.source.length === 0) {\n throw new MaterializedViewConfigError(\n `withMaterializedView \"${spec.name}\": projection.source must be a non-empty collection name`,\n )\n }\n if (typeof projection.map !== 'function') {\n throw new MaterializedViewConfigError(\n `withMaterializedView \"${spec.name}\": projection is missing a \\`map\\` function`,\n )\n }\n if (!Array.isArray(projection.joins) || projection.joins.length < 1) {\n throw new MaterializedViewConfigError(\n `withMaterializedView \"${spec.name}\": projection.joins must declare at least 1 leg — `\n + `a leg-less single-source MV is the query() form's job`,\n )\n }\n const seenAs = new Set<string>()\n for (const leg of projection.joins) {\n const l = leg as { field?: unknown; collect?: unknown; on?: unknown; as?: unknown }\n const isForward = l.field !== undefined\n const isCollect = l.collect !== undefined\n if (isForward && isCollect) {\n throw new MaterializedViewConfigError(\n `withMaterializedView \"${spec.name}\": a projection leg cannot declare both \\`field\\` `\n + `(forward) and \\`collect\\` (reverse) — split it into two legs`,\n )\n }\n if (!isForward && !isCollect) {\n throw new MaterializedViewConfigError(\n `withMaterializedView \"${spec.name}\": each projection leg must declare either \\`field\\` `\n + `(forward FK) or \\`collect\\` (reverse one-to-many)`,\n )\n }\n if (isForward && (typeof l.field !== 'string' || l.field.length === 0)) {\n throw new MaterializedViewConfigError(\n `withMaterializedView \"${spec.name}\": a forward projection leg must declare a non-empty \\`field\\``,\n )\n }\n if (isCollect) {\n if (typeof l.collect !== 'string' || l.collect.length === 0) {\n throw new MaterializedViewConfigError(\n `withMaterializedView \"${spec.name}\": a collect projection leg must declare a non-empty \\`collect\\` collection name`,\n )\n }\n if (typeof l.on !== 'string' || l.on.length === 0) {\n throw new MaterializedViewConfigError(\n `withMaterializedView \"${spec.name}\": collect leg for \"${l.collect}\" must declare a non-empty \\`on\\` FK field`,\n )\n }\n }\n if (typeof l.as !== 'string' || l.as.length === 0) {\n throw new MaterializedViewConfigError(\n `withMaterializedView \"${spec.name}\": each projection leg must declare a non-empty \\`as\\` alias`,\n )\n }\n if (seenAs.has(l.as)) {\n throw new MaterializedViewConfigError(\n `withMaterializedView \"${spec.name}\": projection legs must attach under distinct \\`as\\` aliases (duplicate: \"${l.as}\")`,\n )\n }\n seenAs.add(l.as)\n }\n // #1140 — `from` wiring, checked here with the rest of the leg shape rather\n // than at vault open: it is pure configuration, so the earliest failure is\n // the best one. Owned by `projection-legs.ts` because the executor and the\n // registry both walk the same graph.\n validateProjectionLegs(spec.name, spec.projection)\n // Post-map grouping invariants — same rules as UNION (the mapped\n // stream feeds the same shared groupAndReduce tail).\n if (Array.isArray(spec.groupBy) && spec.groupBy.length === 0) {\n throw new MaterializedViewConfigError(\n `withMaterializedView \"${spec.name}\": groupBy must not be an empty array — omit it or provide at least one field name`,\n )\n }\n if (spec.aggregate && !spec.groupBy) {\n throw new MaterializedViewConfigError(\n `withMaterializedView \"${spec.name}\": projection strategy with aggregate requires groupBy — `\n + `use groupBy to declare the bucketing keys, or remove aggregate for a row-per-primary-record MV`,\n )\n }\n if (spec.moneyFields && !spec.aggregate) {\n throw new MaterializedViewConfigError(\n `withMaterializedView \"${spec.name}\": moneyFields requires aggregate — `\n + `moneyFields rewrites sum/min/max reducers over money output fields, `\n + `so it is meaningless without an aggregate spec`,\n )\n }\n if (spec.predicates) {\n throw new MaterializedViewConfigError(\n `withMaterializedView \"${spec.name}\": predicates are not supported on projection strategies — `\n + `projection mode does not use a Query<T> chain, so .wherePredicate() cannot fire. `\n + `Filter inside projection.map (return null to omit) instead`,\n )\n }\n }\n // i18nLocale + i18nFields drive compute-time i18n resolution of group-key\n // i18nText fields before bucketing — UNION mode (resolved on the unified rows)\n // AND query mode (resolved in GroupedReduction.run before groupAndReduce).\n // i18nLocale without i18nFields cannot resolve anything, so reject it early.\n if (spec.i18nLocale !== undefined && spec.i18nFields === undefined) {\n throw new MaterializedViewConfigError(\n `withMaterializedView \"${spec.name}\": i18nLocale requires i18nFields — `\n + `declare the i18nText descriptors of the group-key fields so they can be `\n + `resolved at the mv layer before bucketing.`,\n )\n }\n if (typeof spec.rowKey !== 'function') {\n throw new ValidationError('withMaterializedView: rowKey is required (no default; see spec § Type surface)')\n }\n if (spec.refresh !== 'eager' && spec.refresh !== 'lazy' && spec.refresh !== 'manual') {\n throw new ValidationError(\n `withMaterializedView: refresh must be 'eager' | 'lazy' | 'manual', got \"${String(spec.refresh)}\"`,\n )\n }\n return {\n __noydb_strategy: 'materialized-view',\n spec,\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,32 +1,34 @@
|
|
|
1
1
|
import {
|
|
2
|
+
isCollectLeg,
|
|
3
|
+
resolveLegOwner,
|
|
2
4
|
wrapDbWithPredicates
|
|
3
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-GANFIM2M.js";
|
|
4
6
|
import {
|
|
5
7
|
canonicalizeMoneyFieldsAsDecimal,
|
|
6
8
|
decodeMoneyFields,
|
|
7
9
|
exactMath
|
|
8
|
-
} from "./chunk-
|
|
9
|
-
import {
|
|
10
|
-
groupAndReduce
|
|
11
|
-
} from "./chunk-CCZJJ4I2.js";
|
|
10
|
+
} from "./chunk-GKTW3KLV.js";
|
|
12
11
|
import {
|
|
13
12
|
putDerivedOutput
|
|
14
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-K6CPIK3R.js";
|
|
15
14
|
import {
|
|
16
15
|
DEFAULT_JOIN_MAX_ROWS
|
|
17
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-EV2TDHQZ.js";
|
|
17
|
+
import {
|
|
18
|
+
groupAndReduce
|
|
19
|
+
} from "./chunk-2CBFYXJX.js";
|
|
18
20
|
import {
|
|
19
21
|
canonicalGroupKey
|
|
20
22
|
} from "./chunk-XZHEOSQ2.js";
|
|
21
23
|
import {
|
|
22
24
|
applyI18nLocale
|
|
23
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-XPEPMK4Y.js";
|
|
24
26
|
import {
|
|
25
27
|
JoinTooLargeError,
|
|
26
28
|
LocaleNotSpecifiedError,
|
|
27
29
|
MaterializedViewConfigError,
|
|
28
30
|
MaterializedViewTooLargeError
|
|
29
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-Z3BZXPRO.js";
|
|
30
32
|
|
|
31
33
|
// src/with-formula/materialized-views/executor.ts
|
|
32
34
|
var DEFAULT_MAX_ROWS = 1e5;
|
|
@@ -125,13 +127,16 @@ async function materializeProjectionResult(spec, db) {
|
|
|
125
127
|
const coll = db.collection(projection.source);
|
|
126
128
|
let q = coll.query();
|
|
127
129
|
for (const leg of projection.joins) {
|
|
128
|
-
if (
|
|
130
|
+
if (isCollectLeg(leg) || leg.from !== void 0) continue;
|
|
129
131
|
q = q.join(leg.field, { as: leg.as, maxRows: leg.maxRows, strategy: leg.strategy });
|
|
130
132
|
}
|
|
131
133
|
let rows = q.toArray();
|
|
132
134
|
for (const leg of projection.joins) {
|
|
133
|
-
if (
|
|
134
|
-
|
|
135
|
+
if (isCollectLeg(leg)) {
|
|
136
|
+
rows = applyCollectLeg(rows, leg, spec.name, projection.source, projection.joins, db);
|
|
137
|
+
} else if (leg.from !== void 0) {
|
|
138
|
+
rows = applyLegRelativeForwardLeg(rows, leg, spec.name, projection.source, projection.joins, db);
|
|
139
|
+
}
|
|
135
140
|
}
|
|
136
141
|
const mapped = [];
|
|
137
142
|
for (const r of rows) {
|
|
@@ -141,18 +146,47 @@ async function materializeProjectionResult(spec, db) {
|
|
|
141
146
|
}
|
|
142
147
|
return finalizeMappedRows(spec, mapped);
|
|
143
148
|
}
|
|
144
|
-
function
|
|
149
|
+
function legOwnerLookup(db) {
|
|
150
|
+
return (collection, field) => {
|
|
151
|
+
const q = db.collection(collection).query();
|
|
152
|
+
return q._joinContext?.()?.resolveRef(field) ?? null;
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
function applyLegRelativeForwardLeg(primaryRows, leg, mvName, source, joins, db) {
|
|
156
|
+
const lookup = legOwnerLookup(db);
|
|
157
|
+
const owner = resolveLegOwner(leg, joins, source, lookup);
|
|
158
|
+
const refDesc = owner === null ? null : lookup(owner, leg.field);
|
|
159
|
+
if (owner === null || refDesc === null) {
|
|
160
|
+
throw new MaterializedViewConfigError(
|
|
161
|
+
`"${mvName}": projection leg "${leg.as}" requires a ref() on field "${leg.field}" of collection "${owner ?? `(behind from: "${leg.from}")`}" \u2014 declare it on that collection, then retry`
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
const targetQ = db.collection(refDesc.target).query();
|
|
165
|
+
const byId = /* @__PURE__ */ new Map();
|
|
166
|
+
for (const row of targetQ.toArray()) {
|
|
167
|
+
const id = coerceCollectKey(row.id);
|
|
168
|
+
if (id !== null) byId.set(id, row);
|
|
169
|
+
}
|
|
170
|
+
return primaryRows.map((row) => {
|
|
171
|
+
const anchor = leg.from === void 0 ? row : row[leg.from];
|
|
172
|
+
const key = anchor == null ? null : coerceCollectKey(anchor[leg.field]);
|
|
173
|
+
return { ...row, [leg.as]: key === null ? null : byId.get(key) ?? null };
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
function applyCollectLeg(primaryRows, leg, mvName, source, joins, db) {
|
|
145
177
|
const childColl = db.collection(leg.collect);
|
|
146
178
|
const childQ = childColl.query();
|
|
147
179
|
const refDesc = childQ._joinContext?.()?.resolveRef(leg.on);
|
|
180
|
+
const expected = resolveLegOwner(leg, joins, source, legOwnerLookup(db));
|
|
181
|
+
const expectedName = expected ?? source;
|
|
148
182
|
if (refDesc == null) {
|
|
149
183
|
throw new MaterializedViewConfigError(
|
|
150
|
-
`"${mvName}": projection collect leg "${leg.as}" requires a ref() on field "${leg.on}" of collection "${leg.collect}" targeting "${
|
|
184
|
+
`"${mvName}": projection collect leg "${leg.as}" requires a ref() on field "${leg.on}" of collection "${leg.collect}" targeting "${expectedName}" \u2014 declare refs: { ${leg.on}: ref('${expectedName}') } on collection "${leg.collect}", then retry`
|
|
151
185
|
);
|
|
152
186
|
}
|
|
153
|
-
if (refDesc.target !==
|
|
187
|
+
if (refDesc.target !== expectedName) {
|
|
154
188
|
throw new MaterializedViewConfigError(
|
|
155
|
-
`"${mvName}": projection collect leg "${leg.as}" expects field "${leg.on}" of collection "${leg.collect}" to reference the projection source "${
|
|
189
|
+
`"${mvName}": projection collect leg "${leg.as}" expects field "${leg.on}" of collection "${leg.collect}" to reference ${leg.from === void 0 ? `the projection source "${expectedName}"` : `"${expectedName}" (the collection behind from: "${leg.from}")`}, but its ref() targets "${refDesc.target}"`
|
|
156
190
|
);
|
|
157
191
|
}
|
|
158
192
|
const maxRows = leg.maxRows ?? DEFAULT_JOIN_MAX_ROWS;
|
|
@@ -166,7 +200,8 @@ function applyCollectLeg(primaryRows, leg, mvName, source, db) {
|
|
|
166
200
|
}
|
|
167
201
|
const out = [];
|
|
168
202
|
for (const row of primaryRows) {
|
|
169
|
-
const
|
|
203
|
+
const anchor = leg.from === void 0 ? row : row[leg.from];
|
|
204
|
+
const key = anchor == null ? null : coerceCollectKey(anchor.id);
|
|
170
205
|
const children = key === null ? [] : groups.get(key) ?? [];
|
|
171
206
|
if (children.length > maxRows) {
|
|
172
207
|
throw new JoinTooLargeError({
|
|
@@ -307,4 +342,4 @@ async function listOutputIds(outputColl) {
|
|
|
307
342
|
export {
|
|
308
343
|
MaterializedViewExecutor
|
|
309
344
|
};
|
|
310
|
-
//# sourceMappingURL=chunk-
|
|
345
|
+
//# sourceMappingURL=chunk-64WHKBMP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/with-formula/materialized-views/executor.ts"],"sourcesContent":["import 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/join.js'\nimport type { MaterializedFromMeta, MVQueryContext, MaterializedViewSpec, ProjectionJoinLeg } from './types.js'\nimport type { RegisteredMV } from './registry.js'\nimport { wrapDbWithPredicates } from './registry.js'\nimport { groupAndReduce } from '../../with-lookup/reduce/groupby.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\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 /** 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 q = 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 * 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 if (!spec.groupBy) return unified\n\n const groupFields: readonly string[] =\n typeof spec.groupBy === 'string' ? [spec.groupBy] : spec.groupBy\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 groupAndReduce<Record<string, unknown>>(unified, groupFields, spec.aggregate, spec.moneyFields)\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 ? [] : typeof spec.groupBy === 'string' ? [spec.groupBy] : spec.groupBy,\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 const baseCtx = 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.\n let written = 0\n let failed = 0\n for (const { id, record } of enrichedRows) {\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 if (accessor.dispatchCtx) {\n if (await putDerivedOutput(outputColl, id, record, accessor.dispatchCtx) === 'written') written++\n } else {\n await outputColl.put(id, record)\n written++\n }\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 return { written, 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,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
DerivationCycleError,
|
|
3
3
|
MaterializedViewCycleError
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-Z3BZXPRO.js";
|
|
5
5
|
|
|
6
6
|
// src/kernel/via/graph.ts
|
|
7
7
|
var DEFAULT_POSTURE = { encryptedAtRest: "envelope", queryable: "full", exportable: true, forgettable: false };
|
|
@@ -341,4 +341,4 @@ export {
|
|
|
341
341
|
DEFAULT_POSTURE,
|
|
342
342
|
ViaGraph
|
|
343
343
|
};
|
|
344
|
-
//# sourceMappingURL=chunk-
|
|
344
|
+
//# sourceMappingURL=chunk-65JXA63J.js.map
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
} from "./chunk-Y2NBBT6K.js";
|
|
4
4
|
import {
|
|
5
5
|
sha256Hex
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-ONPVHX2Y.js";
|
|
7
7
|
|
|
8
8
|
// src/with-shape/persisted-schemas/derive.ts
|
|
9
9
|
function isZodSchema(value) {
|
|
@@ -79,4 +79,4 @@ export {
|
|
|
79
79
|
isZod4Schema,
|
|
80
80
|
derivePersistedSchema
|
|
81
81
|
};
|
|
82
|
-
//# sourceMappingURL=chunk-
|
|
82
|
+
//# sourceMappingURL=chunk-6NR36UNB.js.map
|
|
@@ -2,20 +2,21 @@ import {
|
|
|
2
2
|
ATTESTATIONS_COLLECTION,
|
|
3
3
|
REVOKED_RECORD_ID,
|
|
4
4
|
loadOrCreateSigner
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-2J5IT37K.js";
|
|
6
6
|
import {
|
|
7
|
+
buildRecordAad,
|
|
7
8
|
openEnvelopeJson
|
|
8
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-CXPOG3ZY.js";
|
|
9
10
|
import {
|
|
10
|
-
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
buildRecordEnvelope
|
|
12
|
+
} from "./chunk-FX3UIDCS.js";
|
|
12
13
|
import {
|
|
13
|
-
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
encrypt
|
|
15
|
+
} from "./chunk-ONPVHX2Y.js";
|
|
15
16
|
import {
|
|
16
17
|
AttestationError,
|
|
17
18
|
ConflictError
|
|
18
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-Z3BZXPRO.js";
|
|
19
20
|
|
|
20
21
|
// src/with-audit/attestation/revoke.ts
|
|
21
22
|
import { signRevocationList } from "@noy-db/attestation";
|
|
@@ -27,7 +28,7 @@ function requireOwner(ctx, op) {
|
|
|
27
28
|
async function readSet(store, vault, dek) {
|
|
28
29
|
const env = await store.get(vault, ATTESTATIONS_COLLECTION, REVOKED_RECORD_ID);
|
|
29
30
|
if (!env) return { docIds: /* @__PURE__ */ new Set(), version: void 0 };
|
|
30
|
-
const set = JSON.parse(await openEnvelopeJson(env, dek));
|
|
31
|
+
const set = JSON.parse(await openEnvelopeJson({ collection: ATTESTATIONS_COLLECTION, id: REVOKED_RECORD_ID }, env, dek));
|
|
31
32
|
return { docIds: new Set(set.docIds), version: env._v };
|
|
32
33
|
}
|
|
33
34
|
async function mutateSet(ctx, mutate) {
|
|
@@ -36,15 +37,13 @@ async function mutateSet(ctx, mutate) {
|
|
|
36
37
|
const { docIds, version } = await readSet(ctx.store, ctx.vault, dek);
|
|
37
38
|
mutate(docIds);
|
|
38
39
|
const payload = { docIds: [...docIds].sort(), updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
39
|
-
const { iv, data } = await encrypt(JSON.stringify(payload), dek);
|
|
40
40
|
const expectedVersion = version ?? 0;
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
};
|
|
41
|
+
const identity = { collection: ATTESTATIONS_COLLECTION, id: REVOKED_RECORD_ID, version: expectedVersion + 1 };
|
|
42
|
+
const { iv, data } = await encrypt(JSON.stringify(payload), dek, buildRecordAad(identity));
|
|
43
|
+
const env = buildRecordEnvelope(
|
|
44
|
+
identity,
|
|
45
|
+
{ ts: payload.updatedAt, iv, data }
|
|
46
|
+
);
|
|
48
47
|
try {
|
|
49
48
|
await ctx.store.put(ctx.vault, ATTESTATIONS_COLLECTION, REVOKED_RECORD_ID, env, expectedVersion);
|
|
50
49
|
return;
|
|
@@ -82,4 +81,4 @@ export {
|
|
|
82
81
|
getRevokedDocIdsCore,
|
|
83
82
|
publishRevocationListCore
|
|
84
83
|
};
|
|
85
|
-
//# sourceMappingURL=chunk-
|
|
84
|
+
//# sourceMappingURL=chunk-6RH7PRTL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/with-audit/attestation/revoke.ts"],"sourcesContent":["import type { NoydbStore } from '../../kernel/types.js'\nimport { buildRecordAad, buildRecordEnvelope, encrypt, openEnvelopeJson, type EnclaveKey } from '../../kernel/enclave/index.js'\nimport { AttestationError, ConflictError } from '../../kernel/errors.js'\nimport { loadOrCreateSigner, ATTESTATIONS_COLLECTION, REVOKED_RECORD_ID } from './signer.js'\nimport { signRevocationList, type RevocationList } from '@noy-db/attestation'\n\n/** Everything the revoke core needs from the Vault, injected for testability. */\nexport interface RevokeContext {\n readonly store: NoydbStore\n readonly vault: string\n readonly role: string\n /** The _attestations collection DEK. */\n getDEK(): Promise<EnclaveKey>\n}\n\ninterface RevokedSet {\n docIds: string[]\n updatedAt: string\n}\n\nfunction requireOwner(ctx: RevokeContext, op: string): void {\n if (ctx.role !== 'owner') {\n throw new AttestationError(`${op} requires the 'owner' role; caller is '${ctx.role}'. Revocation is the firm's identity operation.`)\n }\n}\n\nasync function readSet(store: NoydbStore, vault: string, dek: EnclaveKey): Promise<{ docIds: Set<string>; version: number | undefined }> {\n const env = await store.get(vault, ATTESTATIONS_COLLECTION, REVOKED_RECORD_ID)\n if (!env) return { docIds: new Set<string>(), version: undefined }\n const set = JSON.parse(await openEnvelopeJson({ collection: ATTESTATIONS_COLLECTION, id: REVOKED_RECORD_ID }, env, dek)) as RevokedSet\n return { docIds: new Set(set.docIds), version: env._v }\n}\n\n/** Read-modify-write the _revoked set with optimistic concurrency + one retry. */\nasync function mutateSet(ctx: RevokeContext, mutate: (ids: Set<string>) => void): Promise<void> {\n const dek = await ctx.getDEK()\n for (let attempt = 0; attempt < 2; attempt++) {\n const { docIds, version } = await readSet(ctx.store, ctx.vault, dek)\n mutate(docIds)\n const payload: RevokedSet = { docIds: [...docIds].sort(), updatedAt: new Date().toISOString() }\n const expectedVersion = version ?? 0\n const identity = { collection: ATTESTATIONS_COLLECTION, id: REVOKED_RECORD_ID, version: expectedVersion + 1 }\n const { iv, data } = await encrypt(JSON.stringify(payload), dek, buildRecordAad(identity))\n const env = buildRecordEnvelope(\n identity,\n { ts: payload.updatedAt, iv, data },\n )\n try {\n await ctx.store.put(ctx.vault, ATTESTATIONS_COLLECTION, REVOKED_RECORD_ID, env, expectedVersion)\n return\n } catch (e) {\n if (e instanceof ConflictError && attempt === 0) continue\n throw e\n }\n }\n}\n\nexport async function revokeDocCore(ctx: RevokeContext, docId: string): Promise<void> {\n requireOwner(ctx, 'revokeAttestation')\n const issued = await ctx.store.get(ctx.vault, ATTESTATIONS_COLLECTION, docId)\n if (!issued) throw new AttestationError(`revokeAttestation: attestation '${docId}' not found (was it issued by this vault?).`)\n await mutateSet(ctx, (ids) => ids.add(docId))\n}\n\nexport async function unrevokeDocCore(ctx: RevokeContext, docId: string): Promise<void> {\n requireOwner(ctx, 'unrevokeAttestation')\n await mutateSet(ctx, (ids) => ids.delete(docId))\n}\n\nexport async function getRevokedDocIdsCore(ctx: RevokeContext): Promise<string[]> {\n const dek = await ctx.getDEK()\n const { docIds } = await readSet(ctx.store, ctx.vault, dek)\n return [...docIds].sort()\n}\n\nexport async function publishRevocationListCore(ctx: RevokeContext): Promise<RevocationList> {\n requireOwner(ctx, 'publishRevocationList')\n const docIds = await getRevokedDocIdsCore(ctx)\n const signer = await loadOrCreateSigner(ctx.store, ctx.vault, () => ctx.getDEK())\n return signRevocationList(docIds, new Date().toISOString(), signer.keyId, signer.privateKeyPkcs8B64)\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAIA,SAAS,0BAA+C;AAgBxD,SAAS,aAAa,KAAoB,IAAkB;AAC1D,MAAI,IAAI,SAAS,SAAS;AACxB,UAAM,IAAI,iBAAiB,GAAG,EAAE,0CAA0C,IAAI,IAAI,iDAAiD;AAAA,EACrI;AACF;AAEA,eAAe,QAAQ,OAAmB,OAAe,KAAgF;AACvI,QAAM,MAAM,MAAM,MAAM,IAAI,OAAO,yBAAyB,iBAAiB;AAC7E,MAAI,CAAC,IAAK,QAAO,EAAE,QAAQ,oBAAI,IAAY,GAAG,SAAS,OAAU;AACjE,QAAM,MAAM,KAAK,MAAM,MAAM,iBAAiB,EAAE,YAAY,yBAAyB,IAAI,kBAAkB,GAAG,KAAK,GAAG,CAAC;AACvH,SAAO,EAAE,QAAQ,IAAI,IAAI,IAAI,MAAM,GAAG,SAAS,IAAI,GAAG;AACxD;AAGA,eAAe,UAAU,KAAoB,QAAmD;AAC9F,QAAM,MAAM,MAAM,IAAI,OAAO;AAC7B,WAAS,UAAU,GAAG,UAAU,GAAG,WAAW;AAC5C,UAAM,EAAE,QAAQ,QAAQ,IAAI,MAAM,QAAQ,IAAI,OAAO,IAAI,OAAO,GAAG;AACnE,WAAO,MAAM;AACb,UAAM,UAAsB,EAAE,QAAQ,CAAC,GAAG,MAAM,EAAE,KAAK,GAAG,YAAW,oBAAI,KAAK,GAAE,YAAY,EAAE;AAC9F,UAAM,kBAAkB,WAAW;AACnC,UAAM,WAAW,EAAE,YAAY,yBAAyB,IAAI,mBAAmB,SAAS,kBAAkB,EAAE;AAC5G,UAAM,EAAE,IAAI,KAAK,IAAI,MAAM,QAAQ,KAAK,UAAU,OAAO,GAAG,KAAK,eAAe,QAAQ,CAAC;AACzF,UAAM,MAAM;AAAA,MACV;AAAA,MACA,EAAE,IAAI,QAAQ,WAAW,IAAI,KAAK;AAAA,IACpC;AACA,QAAI;AACF,YAAM,IAAI,MAAM,IAAI,IAAI,OAAO,yBAAyB,mBAAmB,KAAK,eAAe;AAC/F;AAAA,IACF,SAAS,GAAG;AACV,UAAI,aAAa,iBAAiB,YAAY,EAAG;AACjD,YAAM;AAAA,IACR;AAAA,EACF;AACF;AAEA,eAAsB,cAAc,KAAoB,OAA8B;AACpF,eAAa,KAAK,mBAAmB;AACrC,QAAM,SAAS,MAAM,IAAI,MAAM,IAAI,IAAI,OAAO,yBAAyB,KAAK;AAC5E,MAAI,CAAC,OAAQ,OAAM,IAAI,iBAAiB,mCAAmC,KAAK,6CAA6C;AAC7H,QAAM,UAAU,KAAK,CAAC,QAAQ,IAAI,IAAI,KAAK,CAAC;AAC9C;AAEA,eAAsB,gBAAgB,KAAoB,OAA8B;AACtF,eAAa,KAAK,qBAAqB;AACvC,QAAM,UAAU,KAAK,CAAC,QAAQ,IAAI,OAAO,KAAK,CAAC;AACjD;AAEA,eAAsB,qBAAqB,KAAuC;AAChF,QAAM,MAAM,MAAM,IAAI,OAAO;AAC7B,QAAM,EAAE,OAAO,IAAI,MAAM,QAAQ,IAAI,OAAO,IAAI,OAAO,GAAG;AAC1D,SAAO,CAAC,GAAG,MAAM,EAAE,KAAK;AAC1B;AAEA,eAAsB,0BAA0B,KAA6C;AAC3F,eAAa,KAAK,uBAAuB;AACzC,QAAM,SAAS,MAAM,qBAAqB,GAAG;AAC7C,QAAM,SAAS,MAAM,mBAAmB,IAAI,OAAO,IAAI,OAAO,MAAM,IAAI,OAAO,CAAC;AAChF,SAAO,mBAAmB,SAAQ,oBAAI,KAAK,GAAE,YAAY,GAAG,OAAO,OAAO,OAAO,kBAAkB;AACrG;","names":[]}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getAtPath
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-XPEPMK4Y.js";
|
|
4
4
|
import {
|
|
5
5
|
SearchNotEnabledError
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-Z3BZXPRO.js";
|
|
7
7
|
|
|
8
8
|
// src/with-lookup/search/tokenize.ts
|
|
9
9
|
var WORD = /[\p{L}\p{N}]+/gu;
|
|
@@ -294,31 +294,31 @@ function buildBlobFieldEntries(filenamesByField) {
|
|
|
294
294
|
function withSearch() {
|
|
295
295
|
return {
|
|
296
296
|
async search(ctx, field, query, opts) {
|
|
297
|
-
const { search } = await import("./collection-facade-
|
|
297
|
+
const { search } = await import("./collection-facade-WSUAYFJ4.js");
|
|
298
298
|
return search(ctx, field, query, opts);
|
|
299
299
|
},
|
|
300
300
|
async retrieve(ctx, query, opts) {
|
|
301
|
-
const { retrieve } = await import("./collection-facade-
|
|
301
|
+
const { retrieve } = await import("./collection-facade-WSUAYFJ4.js");
|
|
302
302
|
return retrieve(ctx, query, opts);
|
|
303
303
|
},
|
|
304
304
|
async similarTo(ctx, vector, opts) {
|
|
305
|
-
const { similarTo } = await import("./collection-facade-
|
|
305
|
+
const { similarTo } = await import("./collection-facade-WSUAYFJ4.js");
|
|
306
306
|
return similarTo(ctx, vector, opts);
|
|
307
307
|
},
|
|
308
308
|
async warmIndex(ctx) {
|
|
309
|
-
const { warmIndex } = await import("./collection-facade-
|
|
309
|
+
const { warmIndex } = await import("./collection-facade-WSUAYFJ4.js");
|
|
310
310
|
return warmIndex(ctx);
|
|
311
311
|
},
|
|
312
312
|
async flushIndex(ctx) {
|
|
313
|
-
const { flushIndex } = await import("./collection-facade-
|
|
313
|
+
const { flushIndex } = await import("./collection-facade-WSUAYFJ4.js");
|
|
314
314
|
return flushIndex(ctx);
|
|
315
315
|
},
|
|
316
316
|
async embedOnWrite(ctx, id, record, version) {
|
|
317
|
-
const { embedOnWrite } = await import("./collection-facade-
|
|
317
|
+
const { embedOnWrite } = await import("./collection-facade-WSUAYFJ4.js");
|
|
318
318
|
return embedOnWrite(ctx, id, record, version);
|
|
319
319
|
},
|
|
320
320
|
async rebuildEmbeddings(ctx) {
|
|
321
|
-
const { rebuildEmbeddings } = await import("./collection-facade-
|
|
321
|
+
const { rebuildEmbeddings } = await import("./collection-facade-WSUAYFJ4.js");
|
|
322
322
|
return rebuildEmbeddings(ctx);
|
|
323
323
|
}
|
|
324
324
|
};
|
|
@@ -364,4 +364,4 @@ export {
|
|
|
364
364
|
buildBlobFieldEntries,
|
|
365
365
|
withSearch
|
|
366
366
|
};
|
|
367
|
-
//# sourceMappingURL=chunk-
|
|
367
|
+
//# sourceMappingURL=chunk-7OBIBPCV.js.map
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
decrypt,
|
|
3
3
|
deriveSealedFieldKey,
|
|
4
4
|
deriveSealedFieldKeyFromCek
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-ONPVHX2Y.js";
|
|
6
6
|
|
|
7
7
|
// src/kernel/enclave/record-keys/sealed-slot.ts
|
|
8
8
|
function parseSealedSlot(blob) {
|
|
@@ -26,4 +26,4 @@ export {
|
|
|
26
26
|
parseSealedSlot,
|
|
27
27
|
dualReadSealedSlot
|
|
28
28
|
};
|
|
29
|
-
//# sourceMappingURL=chunk-
|
|
29
|
+
//# sourceMappingURL=chunk-7Q3RHOA5.js.map
|