@noy-db/hub 0.6.0-pre.8 → 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-J7FM3RAU.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-PXCBVDFY.js → chunk-5ATC6UT4.js} +40 -7
- package/dist/chunk-5ATC6UT4.js.map +1 -0
- 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-JXIDGFKS.js → chunk-5O5ZSW7N.js} +4 -2
- package/dist/chunk-5O5ZSW7N.js.map +1 -0
- 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-IMZLOJTK.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-WK5XUYYF.js → chunk-JYPRZWCZ.js} +473 -231
- 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-H73G4XF4.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 +14 -8
- 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 +18 -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/index.d.ts +3 -3
- package/dist/with-audit/periods/periods.d.ts +82 -2
- package/dist/with-audit/periods/strategy.d.ts +1 -1
- package/dist/with-audit/periods/vault-facade.d.ts +54 -1
- package/dist/with-audit/periods/window.d.ts +10 -0
- 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-shape/introspection/index.d.ts +1 -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-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-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-H73G4XF4.js.map +0 -1
- package/dist/chunk-HNGSV2YC.js.map +0 -1
- package/dist/chunk-IGJCYUT5.js.map +0 -1
- package/dist/chunk-IMZLOJTK.js.map +0 -1
- package/dist/chunk-J7FM3RAU.js.map +0 -1
- package/dist/chunk-JJNOLSG5.js.map +0 -1
- package/dist/chunk-JRKZTEZZ.js.map +0 -1
- package/dist/chunk-JXIDGFKS.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-PXCBVDFY.js.map +0 -1
- package/dist/chunk-Q6TEJXBX.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-WK5XUYYF.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-3MT74MZS.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-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-3MT74MZS.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
|
@@ -1,5 +1,31 @@
|
|
|
1
|
+
import type { RecordIdentity } from '../../kernel/enclave/index.js';
|
|
1
2
|
import type { NoydbStore, EncryptedEnvelope, HistoryOptions, PruneOptions } from '../../kernel/types.js';
|
|
2
3
|
import { type EnclaveKey } from '../../kernel/enclave/index.js';
|
|
4
|
+
/**
|
|
5
|
+
* The identity a history snapshot is **sealed against** — its STORAGE location,
|
|
6
|
+
* not the live record it is a copy of (#1041).
|
|
7
|
+
*
|
|
8
|
+
* ## Why storage, and why this is a decision rather than a detail
|
|
9
|
+
*
|
|
10
|
+
* A snapshot is a copy, so two identities are available: the live record
|
|
11
|
+
* (`collection`/`recordId`) or where the bytes actually land
|
|
12
|
+
* (`_history`/`historyId(...)`). They are not equivalent under attack.
|
|
13
|
+
*
|
|
14
|
+
* Binding the LIVE identity makes a snapshot's AAD **indistinguishable from the
|
|
15
|
+
* live record's at the same version** — so an untrusted store could serve a
|
|
16
|
+
* history entry *as the current record* and the client would accept it. It also
|
|
17
|
+
* leaves entries relocatable within `_history`.
|
|
18
|
+
*
|
|
19
|
+
* Binding STORAGE identity closes both. The cost is that the id must be known
|
|
20
|
+
* *before* the envelope is sealed, where `saveHistory` previously derived it
|
|
21
|
+
* *after* (from `envelope._v`) — which is precisely the restructure this
|
|
22
|
+
* function exists to make possible.
|
|
23
|
+
*
|
|
24
|
+
* `saveHistory` uses this too, so the sealed identity and the put location have
|
|
25
|
+
* **one definition** and cannot drift apart. Changing the layout here changes
|
|
26
|
+
* both at once, by construction.
|
|
27
|
+
*/
|
|
28
|
+
export declare function historyIdentity(collection: string, recordId: string, version: number): RecordIdentity;
|
|
3
29
|
/** Save a history entry (a complete encrypted envelope snapshot). */
|
|
4
30
|
export declare function saveHistory(adapter: NoydbStore, vault: string, collection: string, recordId: string, envelope: EncryptedEnvelope): Promise<void>;
|
|
5
31
|
/** Get history entries for a record, sorted newest-first. */
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
*/
|
|
18
18
|
export { withHistory } from './active.js';
|
|
19
19
|
export type { HistoryStrategy } from './strategy.js';
|
|
20
|
-
export { saveHistory, getHistory, getVersionEnvelope, pruneHistory, clearHistory, } from './history.js';
|
|
20
|
+
export { saveHistory, historyIdentity, getHistory, getVersionEnvelope, pruneHistory, clearHistory, } from './history.js';
|
|
21
21
|
export { diff, formatDiff } from './diff.js';
|
|
22
22
|
export type { ChangeType, DiffEntry } from './diff.js';
|
|
23
23
|
export { LedgerStore, LEDGER_COLLECTION, LEDGER_DELTAS_COLLECTION, envelopePayloadHash, } from './ledger/store.js';
|
|
@@ -30,3 +30,4 @@ export { VaultInstant, CollectionInstant } from './time-machine.js';
|
|
|
30
30
|
export type { VaultEngine } from './time-machine.js';
|
|
31
31
|
/** The un-opted-in stub for this service — exported so callers can compare against it (#844). */
|
|
32
32
|
export { NO_HISTORY } from './strategy.js';
|
|
33
|
+
export type { RecordIdentity } from '../../kernel/enclave/index.js';
|
|
@@ -237,7 +237,13 @@ export declare class LedgerStore {
|
|
|
237
237
|
* version/timestamp/actor) fully intact for audit purposes.
|
|
238
238
|
*/
|
|
239
239
|
purgeRecordDeltas(collection: string, id: string): Promise<number>;
|
|
240
|
-
/**
|
|
240
|
+
/**
|
|
241
|
+
* Encrypt a JSON Patch into an envelope for storage. Mirrors encryptEntry.
|
|
242
|
+
*
|
|
243
|
+
* `index` is the ledger index this delta will be stored under — the caller
|
|
244
|
+
* knows it before the entry exists, and it is what makes the envelope's
|
|
245
|
+
* identity bindable (#1051).
|
|
246
|
+
*/
|
|
241
247
|
private encryptDelta;
|
|
242
248
|
/**
|
|
243
249
|
* Read all entries in ascending-index order. Used internally by
|
|
@@ -33,7 +33,7 @@ import type { LedgerStore } from './ledger/store.js';
|
|
|
33
33
|
import type { JsonPatch } from './ledger/patch.js';
|
|
34
34
|
import type { DiffEntry } from './diff.js';
|
|
35
35
|
import type { VaultInstant, VaultEngine } from './time-machine.js';
|
|
36
|
-
import type { EnclaveKey } from '../../kernel/enclave/index.js';
|
|
36
|
+
import type { EnclaveKey, RecordIdentity } from '../../kernel/enclave/index.js';
|
|
37
37
|
/**
|
|
38
38
|
* Options accepted by `HistoryStrategy.buildLedger`. Mirrors the
|
|
39
39
|
* `LedgerStore` constructor verbatim — kept in this file so `core`
|
|
@@ -58,6 +58,16 @@ export interface HistoryStrategy {
|
|
|
58
58
|
* `NO_HISTORY`.
|
|
59
59
|
*/
|
|
60
60
|
saveHistory(adapter: NoydbStore, vault: string, collection: string, recordId: string, envelope: EncryptedEnvelope): Promise<void>;
|
|
61
|
+
/**
|
|
62
|
+
* The identity a snapshot of `collection/recordId@version` must be **sealed
|
|
63
|
+
* against** — its `_history` storage location (#1041).
|
|
64
|
+
*
|
|
65
|
+
* On the port because the kernel writes history snapshots but must not import
|
|
66
|
+
* `with-commit` to learn its layout. Exposing it here keeps the derivation in
|
|
67
|
+
* the module that owns the layout, and `saveHistory` uses the same function,
|
|
68
|
+
* so the sealed identity and the put location cannot drift.
|
|
69
|
+
*/
|
|
70
|
+
historyIdentity(collection: string, recordId: string, version: number): RecordIdentity;
|
|
61
71
|
/**
|
|
62
72
|
* List history envelopes for a record, newest first. Throws under
|
|
63
73
|
* `NO_HISTORY` — callers reach this via `collection.history()` /
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @category capability
|
|
3
|
-
* Deferred numbering engine — store-clock-ordered, gap-free serials assigned
|
|
4
|
-
* at an explicit numbering pass. See the design spec.
|
|
5
|
-
*/
|
|
6
1
|
import type { NoydbStore } from '../../kernel/types.js';
|
|
7
2
|
import { type EnclaveKey } from '../../kernel/enclave/index.js';
|
|
8
3
|
import type { DeferredNumberingConfig } from './descriptor.js';
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The vault head's storage layer (#1044).
|
|
3
|
+
*
|
|
4
|
+
* A bucket is an ordinary encrypted record at `_head/<collection>::<n>`, so it
|
|
5
|
+
* inherits #1041's identity binding for free: the store cannot relocate a
|
|
6
|
+
* bucket, re-author it, or serve one bucket's bytes as another's. What it can
|
|
7
|
+
* still do is serve an OLD bucket, which is why {@link readBucket} enforces
|
|
8
|
+
* monotonicity against the caller's own record of what it last wrote.
|
|
9
|
+
*
|
|
10
|
+
* @packageDocumentation
|
|
11
|
+
*/
|
|
12
|
+
import { type EnclaveKey } from '../../kernel/enclave/index.js';
|
|
13
|
+
import type { NoydbStore } from '../../kernel/types.js';
|
|
14
|
+
/** `{ recordId → version }` for one bucket. */
|
|
15
|
+
export type BucketBody = Record<string, number>;
|
|
16
|
+
/**
|
|
17
|
+
* FNV-1a over `collection/id`. A hash, not a cipher: the bucket a record lands
|
|
18
|
+
* in is not secret — the store already sees which bucket was written, and it
|
|
19
|
+
* already saw the record's own address. Choosing something stronger would buy
|
|
20
|
+
* nothing and cost every write.
|
|
21
|
+
*/
|
|
22
|
+
export declare function bucketIndex(collection: string, id: string, buckets: number): number;
|
|
23
|
+
export declare function bucketId(collection: string, id: string, buckets: number): string;
|
|
24
|
+
export declare function readBucket(store: NoydbStore, vault: string, dek: EnclaveKey, bucket: string): Promise<{
|
|
25
|
+
body: BucketBody;
|
|
26
|
+
version: number;
|
|
27
|
+
}>;
|
|
28
|
+
export declare function writeBucket(store: NoydbStore, vault: string, dek: EnclaveKey, bucket: string, body: BucketBody, expectedVersion: number): Promise<void>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@noy-db/hub/vault-head` — detect a store that WITHHOLDS (#1044).
|
|
3
|
+
*
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
export { withVaultHead } from './active.js';
|
|
7
|
+
export { verifyVaultHead, type HeadDiscrepancy, type HeadVerifyResult, type HeadVerdict, type HeadUnverifiableReason } from './verify.js';
|
|
8
|
+
export { NO_VAULT_HEAD, VAULT_HEAD_COLLECTION, DEFAULT_HEAD_BUCKETS, type VaultHeadStrategy, type WithVaultHeadOptions, type HeadEntry, } from './strategy.js';
|
|
9
|
+
export type { NoydbStore, EncryptedEnvelope } from '../../kernel/types.js';
|
|
10
|
+
export type { EnclaveKey } from '../../kernel/enclave/index.js';
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `withVaultHead()` — the opt-in detector for **omission** (#1044).
|
|
3
|
+
*
|
|
4
|
+
* ## What it is for, and what it deliberately is not
|
|
5
|
+
*
|
|
6
|
+
* #1041 made every envelope self-authenticating at its identity, and #1042
|
|
7
|
+
* made the merge reject one that is not. What neither can catch is **absence**:
|
|
8
|
+
* a store that serves a genuine, unmodified `v1` when `v7` exists, or serves
|
|
9
|
+
* nothing at all. An authentic old envelope is indistinguishable from an
|
|
10
|
+
* authentic current one without external knowledge of what *should* be there.
|
|
11
|
+
*
|
|
12
|
+
* The head is that external knowledge: an authenticated `{id → version}`
|
|
13
|
+
* manifest the client writes and the store cannot forge. It is **not** a Merkle
|
|
14
|
+
* chain over content — content integrity is already handled, so the head needs
|
|
15
|
+
* only versions.
|
|
16
|
+
*
|
|
17
|
+
* ## Why it is opt-in when AAD is not
|
|
18
|
+
*
|
|
19
|
+
* AAD costs nothing to coordinate and closes *alteration*, so it is kernel. The
|
|
20
|
+
* head costs a write per commit and needs anti-entropy; on a single-device
|
|
21
|
+
* offline vault it defends against nothing. Making it kernel would tax every
|
|
22
|
+
* user for a multi-writer property. ADR 0003, Decision 3.
|
|
23
|
+
*
|
|
24
|
+
* `SECURITY.md` states the split exactly: a store cannot alter, relocate,
|
|
25
|
+
* re-tier, re-author or rewind a record; **without `withVaultHead()` it can
|
|
26
|
+
* still withhold or omit.**
|
|
27
|
+
*
|
|
28
|
+
* ## Bucketed, and why that is not a compromise
|
|
29
|
+
*
|
|
30
|
+
* ADR 0003 left head granularity open and asked for it to be sized early.
|
|
31
|
+
* Measured, at the documented 50K-record vault ceiling:
|
|
32
|
+
*
|
|
33
|
+
* | shape | write cost per commit | detection |
|
|
34
|
+
* |---|---|---|
|
|
35
|
+
* | one per-vault manifest | **1.1 MiB** | per-record |
|
|
36
|
+
* | one per collection | the same problem, renamed | per-record |
|
|
37
|
+
* | **bucketed, 256 buckets** | **~4.4 KiB** | per-record |
|
|
38
|
+
*
|
|
39
|
+
* Bucketing changes *only* write amplification. Each bucket still lists every
|
|
40
|
+
* one of its records' versions, so detection stays per-record — which is why
|
|
41
|
+
* this is not a trade-off between cost and strength. Verifying one pulled
|
|
42
|
+
* record reads one bucket rather than a megabyte.
|
|
43
|
+
*
|
|
44
|
+
* ## Wired as a bus OBSERVER, not a call in `collection.ts`
|
|
45
|
+
*
|
|
46
|
+
* That is what `kernel-surface` means by "register on the ServiceBus instead of
|
|
47
|
+
* growing this file", and it keeps the hot write path untouched for anyone who
|
|
48
|
+
* has not opted in: nothing is registered at all, so `hasHandlers` stays false
|
|
49
|
+
* and the dispatch never happens.
|
|
50
|
+
*
|
|
51
|
+
* Both `afterPut` AND `afterDelete`, because a delete is a version bump like
|
|
52
|
+
* any other. A head that stopped tracking deleted records would let a store
|
|
53
|
+
* resurrect one by withholding the tombstone — precisely the omission this
|
|
54
|
+
* exists to catch.
|
|
55
|
+
*
|
|
56
|
+
* ⚠️ The registration must be UNCONDITIONAL on anything but `enabled`. Its first
|
|
57
|
+
* draft sat inside `#registerForgetHooks()`, which returns early when no forget
|
|
58
|
+
* subjects are declared, so the head silently recorded nothing unless the vault
|
|
59
|
+
* happened to use an unrelated feature. The tests caught it only because they
|
|
60
|
+
* asserted a COUNT rather than "no error" — a head that records nothing raises
|
|
61
|
+
* no errors and sweeps perfectly clean.
|
|
62
|
+
*
|
|
63
|
+
* @packageDocumentation
|
|
64
|
+
*/
|
|
65
|
+
import type { NoydbStore, EncryptedEnvelope } from '../../kernel/types.js';
|
|
66
|
+
import type { EnclaveKey } from '../../kernel/enclave/index.js';
|
|
67
|
+
/** Reserved collection the head's buckets live in. */
|
|
68
|
+
export declare const VAULT_HEAD_COLLECTION: "_head";
|
|
69
|
+
/** Default bucket count — see the sizing table above. */
|
|
70
|
+
export declare const DEFAULT_HEAD_BUCKETS = 256;
|
|
71
|
+
export interface WithVaultHeadOptions {
|
|
72
|
+
/**
|
|
73
|
+
* How many buckets the manifest is split across. Higher means smaller writes
|
|
74
|
+
* and more reads to sweep the whole vault; lower means the opposite.
|
|
75
|
+
* Changing it on an existing vault re-homes every entry, so treat it as a
|
|
76
|
+
* layout decision rather than a tuning knob.
|
|
77
|
+
*/
|
|
78
|
+
readonly buckets?: number;
|
|
79
|
+
}
|
|
80
|
+
/** One record's expected state, as the client last committed it. */
|
|
81
|
+
export interface HeadEntry {
|
|
82
|
+
readonly collection: string;
|
|
83
|
+
readonly id: string;
|
|
84
|
+
readonly version: number;
|
|
85
|
+
}
|
|
86
|
+
export interface VaultHeadStrategy {
|
|
87
|
+
/**
|
|
88
|
+
* Is the head actually keeping a manifest?
|
|
89
|
+
*
|
|
90
|
+
* An explicit flag rather than an identity check against the stub: the kernel
|
|
91
|
+
* decides whether to register the write-path observer at all, and
|
|
92
|
+
* `port-layering` forbids it importing `NO_VAULT_HEAD` to compare. Without
|
|
93
|
+
* this, every write in a vault that never opted in would still pay a cache
|
|
94
|
+
* lookup and a no-op call.
|
|
95
|
+
*/
|
|
96
|
+
readonly enabled: boolean;
|
|
97
|
+
/** Bucket a record id lands in — pure, so callers can pre-group a batch. */
|
|
98
|
+
bucketFor(collection: string, id: string): string;
|
|
99
|
+
/**
|
|
100
|
+
* Record `entry` as the client's expectation for that record.
|
|
101
|
+
*
|
|
102
|
+
* Called on every committed write, INSIDE the same logical operation, so
|
|
103
|
+
* there is no window where the record exists and the head does not know it.
|
|
104
|
+
*/
|
|
105
|
+
note(store: NoydbStore, vault: string, getDEK: (collection: string) => Promise<EnclaveKey>, entry: HeadEntry): Promise<void>;
|
|
106
|
+
/**
|
|
107
|
+
* What the client expects for `collection/id`, or `null` if the head has
|
|
108
|
+
* never seen it.
|
|
109
|
+
*/
|
|
110
|
+
expected(store: NoydbStore, vault: string, getDEK: (collection: string) => Promise<EnclaveKey>, collection: string, id: string): Promise<number | null>;
|
|
111
|
+
/**
|
|
112
|
+
* Every record the head knows about in `collection` — the set a sweep
|
|
113
|
+
* compares against what the store actually serves, which is how DELETION
|
|
114
|
+
* SUPPRESSION is caught. A withheld record is absent from the store but
|
|
115
|
+
* present here.
|
|
116
|
+
*/
|
|
117
|
+
knownIn(store: NoydbStore, vault: string, getDEK: (collection: string) => Promise<EnclaveKey>, collection: string): Promise<ReadonlyMap<string, number>>;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* The un-opted-in stub. `note` is a NO-OP rather than a throw: the write path
|
|
121
|
+
* calls it unconditionally, and a vault without the head must simply not keep
|
|
122
|
+
* one. The READ side throws, because asking what the head expects when there is
|
|
123
|
+
* no head is a caller error, not a silent "nothing to report" — the latter
|
|
124
|
+
* would look exactly like a clean sweep.
|
|
125
|
+
*/
|
|
126
|
+
export declare const NO_VAULT_HEAD: VaultHeadStrategy;
|
|
127
|
+
export type { EncryptedEnvelope };
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The sweep — comparing what the head expects against what the store serves (#1044).
|
|
3
|
+
*
|
|
4
|
+
* This is the only place absence becomes visible. #1041 and #1042 can reject a
|
|
5
|
+
* record that lies about itself; neither can notice one that never arrived, or
|
|
6
|
+
* one served at an older version than the client wrote. Both are indistinguishable
|
|
7
|
+
* from the truth without an independent record of what should be there.
|
|
8
|
+
*
|
|
9
|
+
* @packageDocumentation
|
|
10
|
+
*/
|
|
11
|
+
import type { NoydbStore } from '../../kernel/types.js';
|
|
12
|
+
import type { EnclaveKey } from '../../kernel/enclave/index.js';
|
|
13
|
+
import type { VaultHeadStrategy } from './strategy.js';
|
|
14
|
+
/** One record the store is not serving faithfully. */
|
|
15
|
+
export interface HeadDiscrepancy {
|
|
16
|
+
readonly collection: string;
|
|
17
|
+
readonly id: string;
|
|
18
|
+
/** What the client last committed. */
|
|
19
|
+
readonly expected: number;
|
|
20
|
+
/**
|
|
21
|
+
* What the store serves now — or `null` when it serves nothing.
|
|
22
|
+
*
|
|
23
|
+
* The two are different attacks wearing the same result. `null` is
|
|
24
|
+
* **suppression**: the record is gone. A lower number is **rollback**: an
|
|
25
|
+
* authentic older version served in place of the current one, which is the
|
|
26
|
+
* case no amount of per-envelope authentication can see.
|
|
27
|
+
*/
|
|
28
|
+
readonly actual: number | null;
|
|
29
|
+
readonly kind: 'withheld' | 'rolled-back';
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Why a sweep could not reach a conclusion.
|
|
33
|
+
*
|
|
34
|
+
* - `'no-expectations'` — the head holds nothing for this collection. A fresh
|
|
35
|
+
* vault, a head switched on after the fact, or a **restore from a snapshot**:
|
|
36
|
+
* `_head` is `_`-prefixed, so `loadAll` excludes it and a restored vault has
|
|
37
|
+
* no head to compare against.
|
|
38
|
+
* - `'store-cannot-cas'` — the store does not advertise `capabilities.casAtomic`,
|
|
39
|
+
* so two writers racing on one bucket can silently lose an entry. A lost entry
|
|
40
|
+
* is a record the sweep stops expecting, which is a false clean.
|
|
41
|
+
*/
|
|
42
|
+
export type HeadUnverifiableReason = 'no-expectations' | 'store-cannot-cas';
|
|
43
|
+
/**
|
|
44
|
+
* ## Three-way, deliberately (#1101)
|
|
45
|
+
*
|
|
46
|
+
* - `'verified'` — the head held expectations, every one was met, and the store
|
|
47
|
+
* can serialize head writes.
|
|
48
|
+
* - `'unverifiable'` — the sweep could not conclude. See `because`.
|
|
49
|
+
* - `'tampered'` — at least one discrepancy. Positive evidence, so it wins over
|
|
50
|
+
* any `unverifiable` reason present at the same time.
|
|
51
|
+
*
|
|
52
|
+
* **The middle value is the point, and collapsing it is wrong in a different
|
|
53
|
+
* direction each way:** folded into "clean" it hides withholding, which is the
|
|
54
|
+
* one thing this service exists to catch; folded into "tampered" it cries wolf
|
|
55
|
+
* on a vault that is merely unexamined.
|
|
56
|
+
*
|
|
57
|
+
* That is not hypothetical. #1044's own first bug was a head that recorded
|
|
58
|
+
* nothing and swept **perfectly clean** — the degraded state rendered
|
|
59
|
+
* identically to a healthy one, which is why its test asserts `checked` before
|
|
60
|
+
* anything else. A two-way verdict makes that state a supported outcome.
|
|
61
|
+
*/
|
|
62
|
+
export type HeadVerdict = 'verified' | 'unverifiable' | 'tampered';
|
|
63
|
+
export interface HeadVerifyResult {
|
|
64
|
+
readonly verdict: HeadVerdict;
|
|
65
|
+
readonly checked: number;
|
|
66
|
+
readonly discrepancies: readonly HeadDiscrepancy[];
|
|
67
|
+
/**
|
|
68
|
+
* Non-empty only when `verdict === 'unverifiable'`.
|
|
69
|
+
*
|
|
70
|
+
* There is deliberately no `clean: boolean`. It could not distinguish "no
|
|
71
|
+
* expectations" from "all expectations met" — both rendered `true` — and that
|
|
72
|
+
* indistinguishability *was* the defect. Replacing it rather than keeping it
|
|
73
|
+
* alongside forces every caller to face the three-way.
|
|
74
|
+
*/
|
|
75
|
+
readonly because: readonly HeadUnverifiableReason[];
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Sweep one collection.
|
|
79
|
+
*
|
|
80
|
+
* **A record the store serves that the head does NOT know is not reported.**
|
|
81
|
+
* That is not an oversight: the head can be enabled on an existing vault, and
|
|
82
|
+
* every pre-existing record would otherwise read as an anomaly. The head's
|
|
83
|
+
* claim is one-directional — *what I wrote must still be there* — and an
|
|
84
|
+
* unknown record simply falls outside it.
|
|
85
|
+
*
|
|
86
|
+
* **A HIGHER version than expected is also not reported**, for the same reason:
|
|
87
|
+
* another device legitimately advanced it. The head detects going backwards, not
|
|
88
|
+
* moving forwards.
|
|
89
|
+
*/
|
|
90
|
+
export declare function verifyVaultHead(head: VaultHeadStrategy, store: NoydbStore, vault: string, getDEK: (collection: string) => Promise<EnclaveKey>, collection: string): Promise<HeadVerifyResult>;
|
|
@@ -65,6 +65,10 @@ export declare function summarizeUnionPlan<T extends Record<string, unknown>>(sp
|
|
|
65
65
|
* one-to-one attachments and collect legs are independent
|
|
66
66
|
* hash-grouped passes, so declaration order never changes the
|
|
67
67
|
* materialized rows — a pure reorder must NOT force a refresh.
|
|
68
|
+
* `from` (#1140) constrains the legal orderings (a leg must follow the
|
|
69
|
+
* alias it attaches to) without making order meaningful: each descriptor
|
|
70
|
+
* carries its own `@alias`, and aliases are unique, so the sorted set
|
|
71
|
+
* still determines the leg graph exactly.
|
|
68
72
|
*
|
|
69
73
|
* The projection `map` is NOT fingerprinted (identical limitation as
|
|
70
74
|
* the UNION arm `map`); consumers must bump the MV's `name` when
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Projection-leg topology (#810, extended by #1140).
|
|
3
|
+
*
|
|
4
|
+
* A projection MV's legs originally all attached to the PRIMARY row: a forward
|
|
5
|
+
* leg named an FK field on `projection.source`, and a reverse `collect` leg's
|
|
6
|
+
* `on` field had to `ref()` the source itself. Anything two FKs away was
|
|
7
|
+
* therefore inexpressible — `bill → entity → client` has no leg shape, because
|
|
8
|
+
* the bill has no `clientId` and `clients.entityId` refs `entities`, not
|
|
9
|
+
* `bills`.
|
|
10
|
+
*
|
|
11
|
+
* `from` closes that: a leg may attach to a previously-declared ALIAS instead of
|
|
12
|
+
* to the primary row. This module owns the two questions that follow from it —
|
|
13
|
+
* *is this leg graph well-formed?* and *which collection does a leg's rows come
|
|
14
|
+
* from?* — so neither the registry nor the executor has to re-derive them.
|
|
15
|
+
*
|
|
16
|
+
* **Why cycles are impossible by construction, and there is no depth cap.**
|
|
17
|
+
* `from` may only name an alias declared EARLIER in `joins`. A leg can therefore
|
|
18
|
+
* never reach forward, the graph is a forest rooted at the primary row, and its
|
|
19
|
+
* depth is bounded by the number of legs. Validation refuses an unknown or
|
|
20
|
+
* not-yet-declared alias, which is the same check.
|
|
21
|
+
*/
|
|
22
|
+
import type { ProjectionJoinLeg, ProjectionSpec } from './types.js';
|
|
23
|
+
/** Reverse (one-to-many) leg — discriminated on `collect`, as the type is. */
|
|
24
|
+
export declare function isCollectLeg(leg: ProjectionJoinLeg): leg is Extract<ProjectionJoinLeg, {
|
|
25
|
+
collect: string;
|
|
26
|
+
}>;
|
|
27
|
+
/**
|
|
28
|
+
* Refuse a malformed leg graph where `withMaterializedView()` checks the rest of
|
|
29
|
+
* the leg shape — at spec CONSTRUCTION, not at vault open and not at first
|
|
30
|
+
* materialization. Alias wiring is pure configuration: it needs no refs, no
|
|
31
|
+
* records and no store, so the earliest failure is the best one.
|
|
32
|
+
* (Ref EXISTENCE still resolves at first materialization, unchanged — refs
|
|
33
|
+
* cannot exist until after `openVault()` returns.)
|
|
34
|
+
*/
|
|
35
|
+
export declare function validateProjectionLegs<T extends Record<string, unknown>>(mvName: string, projection: ProjectionSpec<T>): void;
|
|
36
|
+
/**
|
|
37
|
+
* The collection a leg's rows come from — the primary source for a root leg, the
|
|
38
|
+
* `from` leg's own target otherwise.
|
|
39
|
+
*
|
|
40
|
+
* Returns `null` when a forward `ref()` somewhere along the chain is not
|
|
41
|
+
* declared yet, which at registration time is the normal case rather than an
|
|
42
|
+
* error: refs are declared after `openVault()` returns, so the registry retries
|
|
43
|
+
* this on every dispatch until it resolves (`_pendingForwardDeps`).
|
|
44
|
+
*
|
|
45
|
+
* `resolveRef` is passed in rather than imported so this module stays free of
|
|
46
|
+
* vault wiring — the registry hands it the ref registry's `getOutbound`, the
|
|
47
|
+
* executor hands it a join context lookup. Both answer the same question.
|
|
48
|
+
*/
|
|
49
|
+
export type RefLookup = (collection: string, field: string) => {
|
|
50
|
+
target: string;
|
|
51
|
+
} | null;
|
|
52
|
+
export declare function resolveLegOwner(leg: ProjectionJoinLeg, joins: ReadonlyArray<ProjectionJoinLeg>, source: string, resolveRef: RefLookup): string | null;
|
|
53
|
+
/**
|
|
54
|
+
* The collection a FORWARD leg resolves INTO — i.e. its dependency. `null` while
|
|
55
|
+
* any ref in the chain (including this leg's own) is still undeclared.
|
|
56
|
+
*/
|
|
57
|
+
export declare function resolveForwardLegTarget(leg: Extract<ProjectionJoinLeg, {
|
|
58
|
+
field: string;
|
|
59
|
+
}>, joins: ReadonlyArray<ProjectionJoinLeg>, source: string, resolveRef: RefLookup): string | null;
|
|
@@ -54,6 +54,33 @@ export declare class MaterializedViewRegistry {
|
|
|
54
54
|
* target has resolved (see `_resolvePendingForwardDeps`).
|
|
55
55
|
*/
|
|
56
56
|
private readonly _pendingForwardDeps;
|
|
57
|
+
/**
|
|
58
|
+
* Query-form strategies whose `query()` callback could not be planned at
|
|
59
|
+
* registration time because a `.join()` names a field whose `ref()` is not
|
|
60
|
+
* declared YET (#1139).
|
|
61
|
+
*
|
|
62
|
+
* Registration runs inside `openVault()`; a collection's refs can only be
|
|
63
|
+
* declared afterwards, so for a query-form MV that joins a declared FK there
|
|
64
|
+
* is NO call ordering the consumer can choose — the plan is simply built too
|
|
65
|
+
* early. Rather than failing the vault open, the strategy is parked here and
|
|
66
|
+
* replanned from {@link resolvePendingPlans}, which every write dispatch and
|
|
67
|
+
* `vault.refreshView()` call runs first. This is the query-form counterpart
|
|
68
|
+
* of `_pendingForwardDeps`, one level up: that defers a leg's TARGET, this
|
|
69
|
+
* defers the whole plan.
|
|
70
|
+
*
|
|
71
|
+
* Only `RefNotDeclaredError` parks a strategy. Every other planning failure
|
|
72
|
+
* still throws out of `openVault()` exactly as before, so a typo'd source or
|
|
73
|
+
* a malformed spec keeps its loud, early error.
|
|
74
|
+
*
|
|
75
|
+
* A parked strategy is invisible until it resolves: it contributes no
|
|
76
|
+
* `_bySource` entries and no cycle-detection edges (same caveat as a
|
|
77
|
+
* late-resolved forward target — `edges()` runs once at vault open). It also
|
|
78
|
+
* cannot be dispatched, which is why {@link hasPendingPlans} forces the
|
|
79
|
+
* conservative branch in `Collection._txAtomicSafe`: the atomic write path
|
|
80
|
+
* skips MV dispatch, and skipping it here would mean the write that was
|
|
81
|
+
* supposed to trigger the first replan is the one that gets missed.
|
|
82
|
+
*/
|
|
83
|
+
private readonly _pendingPlans;
|
|
57
84
|
/**
|
|
58
85
|
* Register an MV. Invokes `spec.query()` once at registration time to
|
|
59
86
|
* read the plan + join context; the resulting `Query<T>` is discarded
|
|
@@ -68,6 +95,29 @@ export declare class MaterializedViewRegistry {
|
|
|
68
95
|
register(spec: MaterializedViewSpec<any>, db: MVQueryContext, options?: {
|
|
69
96
|
knownCollections?: (name: string) => boolean;
|
|
70
97
|
}): Promise<void>;
|
|
98
|
+
/**
|
|
99
|
+
* `true` while any query-form strategy is still unplanned (#1139). Read by
|
|
100
|
+
* `Collection._txAtomicSafe`, which must refuse the atomic write path while
|
|
101
|
+
* this holds — see the `_pendingPlans` doc comment for why.
|
|
102
|
+
*/
|
|
103
|
+
hasPendingPlans(): boolean;
|
|
104
|
+
/**
|
|
105
|
+
* Replan every parked query-form strategy (#1139). Called at the head of both
|
|
106
|
+
* write dispatchers and of `vault.refreshView()`, so a strategy resolves on the
|
|
107
|
+
* first write or refresh after its source collection's refs are declared —
|
|
108
|
+
* which is the earliest moment it could produce a correct plan, and strictly
|
|
109
|
+
* before the first moment it could have any output to produce.
|
|
110
|
+
*
|
|
111
|
+
* Each entry is handed straight back to {@link register}, so a strategy that
|
|
112
|
+
* is STILL unplannable simply re-parks itself and the next dispatch tries
|
|
113
|
+
* again. Idempotent and cheap: the array empties as strategies resolve, and
|
|
114
|
+
* both callers skip the await entirely once it is empty.
|
|
115
|
+
*
|
|
116
|
+
* A late-resolved strategy does NOT retro-feed `edges()` — the unified cycle
|
|
117
|
+
* pass runs once at vault open, before refs exist. Same caveat, and the same
|
|
118
|
+
* reason, as a late-resolved forward-leg target.
|
|
119
|
+
*/
|
|
120
|
+
resolvePendingPlans(): Promise<void>;
|
|
71
121
|
/** All MVs that depend on `source`, in registration order. */
|
|
72
122
|
mvsForSource(source: string): ReadonlyArray<RegisteredMV>;
|
|
73
123
|
/**
|
|
@@ -154,19 +154,27 @@ export interface ProjectionSpec<TRow extends Record<string, unknown>> {
|
|
|
154
154
|
* FK on the projection source into an attached right-side record
|
|
155
155
|
* (record | null) under `as`.
|
|
156
156
|
* - **Reverse "collect" leg** — every row of `collect` whose `on`
|
|
157
|
-
* field references the
|
|
157
|
+
* field references the attach point's id, attached as a
|
|
158
158
|
* possibly-empty ARRAY under `as`. `on` must carry a `ref()`
|
|
159
|
-
* declared on the `collect` collection targeting
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
*
|
|
159
|
+
* declared on the `collect` collection targeting that attach point
|
|
160
|
+
* — checked at first materialization (parity with join-time ref
|
|
161
|
+
* errors). `maxRows` here is a PER-ROW fan-out ceiling (default:
|
|
162
|
+
* the join default); exceeding it throws `JoinTooLargeError`.
|
|
163
|
+
*
|
|
164
|
+
* Both kinds attach to the primary row by default, and to a
|
|
165
|
+
* previously-declared alias when `from` is set (#1140).
|
|
164
166
|
*/
|
|
165
167
|
export type ProjectionJoinLeg = {
|
|
166
|
-
/** FK field on
|
|
168
|
+
/** FK field on this leg's attach point (must have a `ref()` declared). */
|
|
167
169
|
readonly field: string;
|
|
168
170
|
/** Alias under which the resolved right-side record attaches. */
|
|
169
171
|
readonly as: string;
|
|
172
|
+
/**
|
|
173
|
+
* Attach to a previously-declared FORWARD leg's alias instead of to the
|
|
174
|
+
* primary row (#1140) — `field` is then read off that leg's record and
|
|
175
|
+
* resolved through a `ref()` on ITS collection. See the union's doc.
|
|
176
|
+
*/
|
|
177
|
+
readonly from?: string;
|
|
170
178
|
/** Per-side row ceiling override. `undefined` → the join default. */
|
|
171
179
|
readonly maxRows?: number;
|
|
172
180
|
/** Planner strategy override. `undefined` → auto-select. */
|
|
@@ -174,11 +182,40 @@ export type ProjectionJoinLeg = {
|
|
|
174
182
|
} | {
|
|
175
183
|
/** Sibling collection to collect from. */
|
|
176
184
|
readonly collect: string;
|
|
177
|
-
/** FK field on `collect`
|
|
185
|
+
/** FK field on `collect` — a `ref()` targeting this leg's attach point. */
|
|
178
186
|
readonly on: string;
|
|
179
187
|
/** Alias under which the collected array attaches. */
|
|
180
188
|
readonly as: string;
|
|
181
|
-
/**
|
|
189
|
+
/**
|
|
190
|
+
* Attach to a previously-declared FORWARD leg's alias instead of to the
|
|
191
|
+
* primary row (#1140): `on` must then `ref()` THAT leg's collection, and
|
|
192
|
+
* rows are matched against that leg's record id.
|
|
193
|
+
*
|
|
194
|
+
* This is what makes a two-hop lookup expressible. For
|
|
195
|
+
* `bill → entity → client`, the client is not reachable from the bill: a
|
|
196
|
+
* forward leg would need a `bill.clientId` that does not exist, and a
|
|
197
|
+
* collect leg would need `clients.entityId` to ref `bills` when it refs
|
|
198
|
+
* `entities`. With `from` it is one line:
|
|
199
|
+
*
|
|
200
|
+
* ```ts
|
|
201
|
+
* joins: [
|
|
202
|
+
* { field: 'entityId', as: 'entity' },
|
|
203
|
+
* { from: 'entity', collect: 'clients', on: 'entityId', as: 'clients' },
|
|
204
|
+
* ]
|
|
205
|
+
* ```
|
|
206
|
+
*
|
|
207
|
+
* The alternatives it replaces are both bad: denormalizing a redundant FK
|
|
208
|
+
* onto the source reintroduces exactly the duplicated relationship a
|
|
209
|
+
* projection MV exists to avoid, and dropping back to app code forfeits
|
|
210
|
+
* the dependency tracking it was adopted for.
|
|
211
|
+
*
|
|
212
|
+
* `from` may only name a leg declared EARLIER, and only a FORWARD one — a
|
|
213
|
+
* collect leg holds an array, not a record. Both are refused at
|
|
214
|
+
* registration. The backward-only rule is also why no depth cap is
|
|
215
|
+
* needed: a cycle cannot be spelled.
|
|
216
|
+
*/
|
|
217
|
+
readonly from?: string;
|
|
218
|
+
/** Per-row fan-out ceiling. `undefined` → the join default. */
|
|
182
219
|
readonly maxRows?: number;
|
|
183
220
|
};
|
|
184
221
|
/**
|
|
@@ -198,6 +235,23 @@ export interface MaterializedViewSpec<TRow extends Record<string, unknown>> {
|
|
|
198
235
|
* without pre-existing in-scope references; called again at each
|
|
199
236
|
* refresh.
|
|
200
237
|
*
|
|
238
|
+
* **One exception to "at registration time" (#1139).** Registration runs
|
|
239
|
+
* inside `openVault()`, and a collection's `refs` can only be declared after
|
|
240
|
+
* that returns — so a query that `.join()`s a declared FK cannot possibly
|
|
241
|
+
* resolve it on the registration call. When that happens the strategy is
|
|
242
|
+
* PARKED rather than failed, and replanned on the first write dispatch or
|
|
243
|
+
* `vault.refreshView()` — by which time the refs exist. The callback must
|
|
244
|
+
* therefore be safe to invoke more than once before the view first
|
|
245
|
+
* materializes, which it already had to be (it runs again at every refresh).
|
|
246
|
+
*
|
|
247
|
+
* Every other planning failure — a typo'd collection, a malformed spec, a
|
|
248
|
+
* throw from your own callback — still surfaces out of `openVault()`
|
|
249
|
+
* immediately. Only a not-yet-declared ref defers.
|
|
250
|
+
*
|
|
251
|
+
* While parked, the strategy is invisible: it contributes no cycle-detection
|
|
252
|
+
* edge (that pass runs once, at vault open) and appears in neither
|
|
253
|
+
* `refreshView()` nor the source dispatch map until it resolves.
|
|
254
|
+
*
|
|
201
255
|
* Built via the same `Query<T>` chainable builder used elsewhere —
|
|
202
256
|
* `.where()`, `.join()`, `.groupBy()`, `.aggregate()`. The
|
|
203
257
|
* dependency analyzer walks the returned plan to determine source
|
|
@@ -243,10 +297,14 @@ export interface MaterializedViewSpec<TRow extends Record<string, unknown>> {
|
|
|
243
297
|
*
|
|
244
298
|
* Dependencies are all AUTO: `{source} ∪ forward ref() targets ∪
|
|
245
299
|
* collect collections` (explicit {@link sources} remains additive).
|
|
246
|
-
* Forward targets resolve from the
|
|
300
|
+
* Forward targets resolve from the attach point's `ref()`
|
|
247
301
|
* declarations; those are declared by user code AFTER the vault
|
|
248
302
|
* opens (registration time), so the registry folds them into the
|
|
249
303
|
* dependency set on the first MV dispatch that finds them declared.
|
|
304
|
+
* A leg-relative forward leg (#1140) resolves its whole `from` chain
|
|
305
|
+
* the same way, so a two-hop leg simply lands one dispatch later
|
|
306
|
+
* than a one-hop one. A collect leg needs none of this: its
|
|
307
|
+
* dependency is the literal `collect` name whatever it attaches to.
|
|
250
308
|
*/
|
|
251
309
|
projection?: ProjectionSpec<TRow>;
|
|
252
310
|
/**
|
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Persistence helpers for `_meta/public-envelope` — the cover's
|
|
3
|
-
* frozen wire location. Mirrors the bypass-AES pattern used by
|
|
4
|
-
* `_meta/handle` and `_meta/policy` — the document is plaintext
|
|
5
|
-
* JSON, the envelope's `_iv` field is left empty.
|
|
6
|
-
*
|
|
7
|
-
* @module
|
|
8
|
-
*/
|
|
9
1
|
import type { NoydbStore } from '../../../kernel/types.js';
|
|
10
2
|
import type { Cover } from './types.js';
|
|
11
3
|
/**
|
|
@@ -1,14 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Persistence helpers for the vault-level user-directory toggle
|
|
3
|
-
* (`_meta/directory`). Mirrors the bypass-AES pattern used by
|
|
4
|
-
* `_meta/policy` — the directory document is plain JSON, the
|
|
5
|
-
* envelope's `_iv` field is left empty.
|
|
6
|
-
*
|
|
7
|
-
* @see https://github.com/vLannaAi/noy-db-docs/blob/main/content/docs/services/user-envelope.md → Directory visibility
|
|
8
|
-
* @see https://github.com/vLannaAi/noy-db-docs/blob/main/content/docs/services/plaintext-bypass.md — every `_iv: ''` write site
|
|
9
|
-
*
|
|
10
|
-
* @module
|
|
11
|
-
*/
|
|
12
1
|
import type { NoydbStore } from '../../kernel/types.js';
|
|
13
2
|
import type { DirectoryConfig } from './types.js';
|
|
14
3
|
/** Reserved collection name for vault-level metadata documents. */
|