@noy-db/hub 0.3.0-pre.12 → 0.3.0-pre.13
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/dist/aggregate/index.js +4 -4
- package/dist/api-ZGS6LCOF.js +20 -0
- package/dist/as/index.js +11 -11
- package/dist/attestation/index.js +18 -18
- package/dist/{backup-2WVBIVXW.js → backup-BJ57IKAO.js} +28 -11
- package/dist/backup-BJ57IKAO.js.map +1 -0
- package/dist/blobs/index.js +12 -10
- package/dist/blobs/index.js.map +1 -1
- package/dist/broker/index.js +12 -12
- package/dist/bundle/index.js +25 -22
- package/dist/bundle/index.js.map +1 -1
- package/dist/by/index.js +2 -2
- package/dist/cargo/index.js +22 -22
- package/dist/{chunk-ZL6PRULX.js → chunk-2NVOWNI3.js} +4 -4
- package/dist/{chunk-WEHIQYQH.js → chunk-3B5VVCNY.js} +2 -2
- package/dist/{chunk-FF7S3XDW.js → chunk-3LQ2YKO4.js} +2 -2
- package/dist/{chunk-NAR6IDKH.js → chunk-3QCRBHCY.js} +2 -2
- package/dist/{chunk-SXPCZ6LL.js → chunk-454JXE57.js} +3 -3
- package/dist/{chunk-R3NHNVS5.js → chunk-4CTHCN4J.js} +12 -10
- package/dist/{chunk-R3NHNVS5.js.map → chunk-4CTHCN4J.js.map} +1 -1
- package/dist/{chunk-JGUZMC3I.js → chunk-4JBYV75E.js} +5 -5
- package/dist/{chunk-RXTMLYJS.js → chunk-4NXKCLLQ.js} +2 -2
- package/dist/{chunk-GXLZXD2W.js → chunk-4VNQOLML.js} +2 -2
- package/dist/{chunk-45QPICLE.js → chunk-5M5DVGV7.js} +2 -2
- package/dist/{chunk-EHW5KTTA.js → chunk-5O3XF4DV.js} +4 -4
- package/dist/chunk-5O3XF4DV.js.map +1 -0
- package/dist/{chunk-S2OWPVSO.js → chunk-5YOLBEQ6.js} +2 -2
- package/dist/{chunk-BDEMZD4F.js → chunk-6CRIV7DE.js} +2 -2
- package/dist/{chunk-VCUQR6ZL.js → chunk-6JTIAGHD.js} +3 -3
- package/dist/{chunk-K2DLLK34.js → chunk-6QTNZJBS.js} +3 -3
- package/dist/{chunk-UMC5QZTX.js → chunk-6T2SCQRU.js} +4 -4
- package/dist/{chunk-J3JIYFYL.js → chunk-7DSTRQIJ.js} +2 -2
- package/dist/{chunk-3QSOFZQB.js → chunk-AUSTCW2X.js} +10 -10
- package/dist/{chunk-PN5332SU.js → chunk-B3HJYUOF.js} +2 -2
- package/dist/{chunk-DIB2BOIH.js → chunk-BDVFPG6Y.js} +5 -5
- package/dist/{chunk-FZCGIJEJ.js → chunk-BIOUI4HL.js} +50 -1
- package/dist/chunk-BIOUI4HL.js.map +1 -0
- package/dist/{chunk-FYNE4WLC.js → chunk-CAF6WOK7.js} +2 -2
- package/dist/{chunk-AKEOHKMT.js → chunk-CDUQTA3Z.js} +110 -11
- package/dist/chunk-CDUQTA3Z.js.map +1 -0
- package/dist/{chunk-37WOJQWY.js → chunk-CIE2BASH.js} +2 -2
- package/dist/{chunk-BLUT46UP.js → chunk-CRI4OUV4.js} +2 -2
- package/dist/{chunk-Y5TWPBNW.js → chunk-DLG74CNB.js} +4 -4
- package/dist/{chunk-HIOLCOK3.js → chunk-E5ZQT5KX.js} +2 -2
- package/dist/{chunk-IQIVD7TP.js → chunk-EQO2UVP4.js} +6 -6
- package/dist/{chunk-US34HTOI.js → chunk-ERJ7FU55.js} +3 -3
- package/dist/{chunk-S7TAPIRS.js → chunk-EVVGJDRQ.js} +3 -3
- package/dist/{chunk-EXGDL2UQ.js → chunk-EVX47VBM.js} +2 -2
- package/dist/{chunk-NT2ZO4KI.js → chunk-EXK7QRWF.js} +5 -5
- package/dist/{chunk-7QLY64AD.js → chunk-EYZ6IQ6X.js} +5 -5
- package/dist/{chunk-QF5LGMSV.js → chunk-F64IRYG3.js} +2 -2
- package/dist/{chunk-PH7G7ZI7.js → chunk-FHS2HQSH.js} +5 -5
- package/dist/{chunk-HG76BZ6G.js → chunk-FM3G3NOY.js} +27 -9
- package/dist/chunk-FM3G3NOY.js.map +1 -0
- package/dist/{chunk-ZHOJOT6S.js → chunk-FUG4SFN3.js} +2 -2
- package/dist/{chunk-JRKE5MAZ.js → chunk-GKEWXIV5.js} +2 -2
- package/dist/{chunk-6MA575R5.js → chunk-GTGPO5KW.js} +5 -5
- package/dist/{chunk-XS6DLN67.js → chunk-HB3RFQSC.js} +3 -3
- package/dist/{chunk-VXZNSPJM.js → chunk-HDMEGAQE.js} +5 -5
- package/dist/chunk-HDQIIUPH.js +135 -0
- package/dist/chunk-HDQIIUPH.js.map +1 -0
- package/dist/{chunk-DJ7MRXNA.js → chunk-HTJQYHZP.js} +2 -2
- package/dist/{chunk-NRYNRSGV.js → chunk-I6GALP6E.js} +6 -6
- package/dist/{chunk-GL3JV5EV.js → chunk-IL6POWCW.js} +6 -6
- package/dist/{chunk-NEYKOESM.js → chunk-IU6SNYX6.js} +5 -5
- package/dist/{chunk-CCIR2OJH.js → chunk-J2ZX2XUV.js} +5 -5
- package/dist/{chunk-F3LGBRSV.js → chunk-JIF24JPM.js} +57 -15
- package/dist/chunk-JIF24JPM.js.map +1 -0
- package/dist/{chunk-NM3IFKBL.js → chunk-JKJOGPZN.js} +2 -2
- package/dist/{chunk-JC75UBMT.js → chunk-JNAI2HN2.js} +1 -1
- package/dist/{chunk-JC75UBMT.js.map → chunk-JNAI2HN2.js.map} +1 -1
- package/dist/{chunk-TVS6BUUR.js → chunk-JZUV47FZ.js} +2 -2
- package/dist/{chunk-5HNX4OD4.js → chunk-K5IMOGHB.js} +2 -2
- package/dist/{chunk-XJ47GS53.js → chunk-KSKBRKGJ.js} +3 -3
- package/dist/{chunk-INBQ43DI.js → chunk-LASZKVMO.js} +3 -3
- package/dist/{chunk-EVHBK7BN.js → chunk-LXEXBTKL.js} +4 -4
- package/dist/{chunk-6S7ENMRE.js → chunk-M4CV6BRT.js} +2 -2
- package/dist/{chunk-AAIIDAUC.js → chunk-MEFJPTZ4.js} +3 -3
- package/dist/{chunk-WHQHTNT7.js → chunk-MV43JSJF.js} +4 -4
- package/dist/{chunk-F44XWXOA.js → chunk-NJ4EOKMB.js} +4 -4
- package/dist/{chunk-ILF5GARW.js → chunk-NR5LT5RY.js} +7 -7
- package/dist/{chunk-TBNF5DV5.js → chunk-NWSGI5C7.js} +3 -3
- package/dist/{chunk-BDPAVYGJ.js → chunk-OSDB5WW3.js} +92 -15
- package/dist/chunk-OSDB5WW3.js.map +1 -0
- package/dist/chunk-PN2XMATY.js +37 -0
- package/dist/chunk-PN2XMATY.js.map +1 -0
- package/dist/{chunk-EIZ4YOG2.js → chunk-Q5VNKNE5.js} +3 -3
- package/dist/{chunk-TVOHSPVK.js → chunk-QLWMEXCT.js} +2 -2
- package/dist/{chunk-7GAXFU2O.js → chunk-QRB7NAOJ.js} +2 -2
- package/dist/{chunk-X6Y5MXTH.js → chunk-R4ROFEYC.js} +2 -2
- package/dist/{chunk-4BQXMCE5.js → chunk-RCVJZMFE.js} +4 -4
- package/dist/{chunk-QG5RQQBO.js → chunk-RIX4V2TB.js} +3 -3
- package/dist/{chunk-SAL5X5OK.js → chunk-RYCTDFUX.js} +2 -2
- package/dist/{chunk-CXC3JLAQ.js → chunk-RZ5SVOYR.js} +2 -2
- package/dist/{chunk-44IL5G3W.js → chunk-SLFHQTTW.js} +5 -5
- package/dist/chunk-SNZ6URZZ.js +2782 -0
- package/dist/chunk-SNZ6URZZ.js.map +1 -0
- package/dist/{chunk-2MTRJCBI.js → chunk-T2FFWNPK.js} +3 -3
- package/dist/{chunk-QYPDYN23.js → chunk-UNFPPVNI.js} +2 -2
- package/dist/{chunk-RNXJ2VO6.js → chunk-VFUPHI2Z.js} +63 -10
- package/dist/chunk-VFUPHI2Z.js.map +1 -0
- package/dist/{chunk-7ZOSHEVS.js → chunk-VLFCJYTL.js} +9 -9
- package/dist/{chunk-APHLCXVC.js → chunk-VN3DBQAU.js} +2 -2
- package/dist/{chunk-HK4XTXO4.js → chunk-VZRODIM3.js} +4 -4
- package/dist/{chunk-P2LJI6JE.js → chunk-W22IKJE2.js} +2 -2
- package/dist/{chunk-FJTWLQV3.js → chunk-X3YYQWOQ.js} +3 -3
- package/dist/{chunk-YCXKFB7J.js → chunk-X7QBD67R.js} +498 -274
- package/dist/chunk-X7QBD67R.js.map +1 -0
- package/dist/{chunk-HA6ZQWA2.js → chunk-XDYREZWE.js} +82 -10
- package/dist/chunk-XDYREZWE.js.map +1 -0
- package/dist/{chunk-HBBZWEC5.js → chunk-XWZVFISC.js} +40 -6
- package/dist/{chunk-HBBZWEC5.js.map → chunk-XWZVFISC.js.map} +1 -1
- package/dist/{chunk-SGJGWBSC.js → chunk-YFXZEAYK.js} +6 -6
- package/dist/{chunk-SIAIYP6G.js → chunk-ZAJAVEXY.js} +2 -2
- package/dist/{chunk-KKYEZCQG.js → chunk-ZICD77GM.js} +2 -2
- package/dist/{chunk-HGAB325C.js → chunk-ZJ2AK4V7.js} +2 -2
- package/dist/{chunk-HYG32HCM.js → chunk-ZUODRVHY.js} +2 -2
- package/dist/classified/index.js +5 -5
- package/dist/{classified-marker-M7K3OJPM.js → classified-marker-CZKA6ITE.js} +3 -3
- package/dist/collection-facade-TLWIPI76.js +44 -0
- package/dist/{computed-ORCGM5JE.js → computed-ZIQTYTDI.js} +3 -3
- package/dist/consent/index.js +9 -9
- package/dist/{dead-filter-OV5FGKOG.js → dead-filter-ESOBZZP5.js} +2 -2
- package/dist/delegation-W7ZV2322.js +25 -0
- package/dist/derivations/index.js +12 -12
- package/dist/derive-H2BJTLUI.js +21 -0
- package/dist/{enclave-XXFUKJC6.js → enclave-AP3I5W7O.js} +15 -9
- package/dist/executor-KGWTNEQD.js +9 -0
- package/dist/executor-OVEXR6RT.js +9 -0
- package/dist/executor-UNEH5ZYH.js +25 -0
- package/dist/export-accessible-PCMXSUZS.js +23 -0
- package/dist/extract-partition-SWHFSYJO.js +38 -0
- package/dist/{fanout-sidecar-IO2KDUWV.js → fanout-sidecar-A765THMX.js} +9 -9
- package/dist/find-N6345CNT.js +11 -0
- package/dist/forget/index.js +9 -9
- package/dist/guards/index.js +3 -3
- package/dist/history/index.js +14 -11
- package/dist/history/index.js.map +1 -1
- package/dist/i18n/index.js +14 -14
- package/dist/index.d.ts +5 -1
- package/dist/index.js +108 -89
- package/dist/index.js.map +1 -1
- package/dist/indexing/index.js +2 -2
- package/dist/issue-5OKB6I2R.js +19 -0
- package/dist/kernel/collection-config.d.ts +20 -0
- package/dist/kernel/collection.d.ts +31 -28
- package/dist/kernel/enclave/classify/verify.d.ts +3 -0
- package/dist/kernel/enclave/index.d.ts +2 -1
- package/dist/kernel/enclave/record-keys/deterministic.d.ts +1 -0
- package/dist/kernel/enclave/record-keys/lifecycle.d.ts +50 -0
- package/dist/kernel/enclave/record-keys/record-codec.d.ts +27 -0
- package/dist/kernel/errors.d.ts +74 -0
- package/dist/kernel/lazy-count.d.ts +13 -0
- package/dist/kernel/tier-visibility.d.ts +54 -0
- package/dist/kernel/types.d.ts +73 -0
- package/dist/kernel/vault.d.ts +8 -5
- package/dist/kernel/via/dispatch.d.ts +10 -0
- package/dist/{ledger-UAQKPWNM.js → ledger-GFBKVPV4.js} +11 -11
- package/dist/legacy/bundle.d.ts +1 -1
- package/dist/liberate-3VDOT4KO.js +24 -0
- package/dist/{link-set-DGYUOFVD.js → link-set-Z7Q2ASFX.js} +11 -11
- package/dist/materialized-views/index.js +18 -18
- package/dist/noydb-ZCJOYBDI.js +68 -0
- package/dist/on/index.js +9 -9
- package/dist/overlay-views/index.js +4 -4
- package/dist/periods/index.js +12 -12
- package/dist/pod/index.js +11 -11
- package/dist/{policy-5POYLI26.js → policy-Z3RUAIY2.js} +5 -5
- package/dist/port/with/blob-strategy.d.ts +17 -0
- package/dist/portability/index.js +8 -8
- package/dist/{post-register-LB3P4XQU.js → post-register-JTH76BLY.js} +6 -6
- package/dist/{public-envelope-GOG4LUM7.js → public-envelope-B4KNWVUA.js} +4 -4
- package/dist/query/index.js +5 -5
- package/dist/register-VAHONCID.js +23 -0
- package/dist/registry-7MLVD3VO.js +19 -0
- package/dist/registry-EPKPD5SM.js +18 -0
- package/dist/registry-P5T7PS2U.js +9 -0
- package/dist/request-withdrawal-TI3A5WPS.js +31 -0
- package/dist/{reveal-NPVROV4D.js → reveal-DIBHLUZX.js} +7 -7
- package/dist/reveal-DIBHLUZX.js.map +1 -0
- package/dist/revoke-FDRD6GRW.js +24 -0
- package/dist/satellites/index.js +1 -1
- package/dist/sealed-record/index.js +12 -12
- package/dist/{seed-VI4FU7UH.js → seed-Q6M2IZFL.js} +11 -11
- package/dist/session/index.js +9 -9
- package/dist/shadow/index.js +2 -2
- package/dist/signer-MUWEIUI6.js +25 -0
- package/dist/snapshots/index.js +10 -10
- package/dist/stale-OSQ7J3AA.js +29 -0
- package/dist/storage-MVFCGEQE.js +23 -0
- package/dist/{store-coordination-provider-5KDS2RRP.js → store-coordination-provider-64OEZFGS.js} +3 -3
- package/dist/sync/index.js +9 -9
- package/dist/team/index.js +15 -15
- package/dist/tiers/index.js +14 -10
- package/dist/to/index.js +1 -1
- package/dist/tx/index.js +3 -3
- package/dist/util/index.js +1 -1
- package/dist/{verify-QK76NJ4G.js → verify-ZASTRNPR.js} +9 -8
- package/dist/verify-ZASTRNPR.js.map +1 -0
- package/dist/{walk-XQCBKSBW.js → walk-SVNDIZ62.js} +11 -11
- package/dist/with/index.js +11 -11
- package/dist/with-audit/forget/strategy.d.ts +22 -0
- package/dist/with-audit/tiers/index.d.ts +275 -3
- package/dist/with-audit/tiers/strategy.d.ts +5 -4
- package/dist/with-cargo/describe-extraction.d.ts +9 -1
- package/dist/with-cargo/extract-partition.d.ts +9 -1
- package/dist/with-cargo/walk-closure.d.ts +32 -3
- package/dist/with-commit/history/history.d.ts +46 -0
- package/dist/with-commit/history/ledger/store.d.ts +21 -0
- package/dist/with-commit/history/strategy.d.ts +10 -0
- package/dist/with-commit/history/time-machine.d.ts +23 -0
- package/dist/with-commit/tx/elevated-handle.d.ts +2 -1
- package/dist/with-formula/materialized-views/executor.d.ts +9 -0
- package/dist/with-formula/materialized-views/stale.d.ts +52 -1
- package/dist/with-lookup/embeddings/index.d.ts +1 -0
- package/dist/with-lookup/embeddings/vec-id.d.ts +47 -0
- package/dist/with-lookup/indexing/collection-facade.d.ts +38 -1
- package/dist/with-lookup/search/collection-facade.d.ts +40 -0
- package/dist/with-lookup/search/persisted-index-store.d.ts +82 -2
- package/dist/with-lookup/search/strategy.d.ts +4 -0
- package/dist/with-shape/blobs/blob-intent.d.ts +153 -0
- package/dist/with-shape/blobs/blob-set.d.ts +949 -5
- package/dist/withdraw-accessible-WZIEVWSR.js +28 -0
- package/package.json +3 -3
- package/dist/api-3TH2GOFQ.js +0 -20
- package/dist/backup-2WVBIVXW.js.map +0 -1
- package/dist/chunk-65VLRG3I.js +0 -54
- package/dist/chunk-65VLRG3I.js.map +0 -1
- package/dist/chunk-AKEOHKMT.js.map +0 -1
- package/dist/chunk-BDPAVYGJ.js.map +0 -1
- package/dist/chunk-CZMCOFEA.js +0 -1221
- package/dist/chunk-CZMCOFEA.js.map +0 -1
- package/dist/chunk-EHW5KTTA.js.map +0 -1
- package/dist/chunk-F3LGBRSV.js.map +0 -1
- package/dist/chunk-FZCGIJEJ.js.map +0 -1
- package/dist/chunk-HA6ZQWA2.js.map +0 -1
- package/dist/chunk-HG76BZ6G.js.map +0 -1
- package/dist/chunk-RNXJ2VO6.js.map +0 -1
- package/dist/chunk-YCXKFB7J.js.map +0 -1
- package/dist/collection-facade-DWA735G2.js +0 -39
- package/dist/delegation-YVSHMIZZ.js +0 -25
- package/dist/derive-BUO555L5.js +0 -21
- package/dist/executor-6OCCE5VM.js +0 -25
- package/dist/executor-JFVAJY42.js +0 -9
- package/dist/executor-UPSH5O3F.js +0 -9
- package/dist/export-accessible-L4A2QZA5.js +0 -23
- package/dist/extract-partition-ZHQ4RGGM.js +0 -36
- package/dist/find-ZFZDZQ2U.js +0 -11
- package/dist/issue-OG4V23SQ.js +0 -19
- package/dist/liberate-GFUQJRK5.js +0 -24
- package/dist/noydb-AKH4AMCR.js +0 -67
- package/dist/register-ZI7YI7US.js +0 -23
- package/dist/registry-DZ2T4LL7.js +0 -9
- package/dist/registry-NVWEQ2GU.js +0 -18
- package/dist/registry-SEKL74ET.js +0 -19
- package/dist/request-withdrawal-ZP3JIRVS.js +0 -31
- package/dist/reveal-NPVROV4D.js.map +0 -1
- package/dist/revoke-VF6TAJK2.js +0 -24
- package/dist/signer-DRDDCCHW.js +0 -25
- package/dist/stale-TJXFQKOJ.js +0 -14
- package/dist/storage-GR7KZRH4.js +0 -23
- package/dist/verify-QK76NJ4G.js.map +0 -1
- package/dist/withdraw-accessible-FMN4LPJZ.js +0 -28
- /package/dist/{api-3TH2GOFQ.js.map → api-ZGS6LCOF.js.map} +0 -0
- /package/dist/{chunk-ZL6PRULX.js.map → chunk-2NVOWNI3.js.map} +0 -0
- /package/dist/{chunk-WEHIQYQH.js.map → chunk-3B5VVCNY.js.map} +0 -0
- /package/dist/{chunk-FF7S3XDW.js.map → chunk-3LQ2YKO4.js.map} +0 -0
- /package/dist/{chunk-NAR6IDKH.js.map → chunk-3QCRBHCY.js.map} +0 -0
- /package/dist/{chunk-SXPCZ6LL.js.map → chunk-454JXE57.js.map} +0 -0
- /package/dist/{chunk-JGUZMC3I.js.map → chunk-4JBYV75E.js.map} +0 -0
- /package/dist/{chunk-RXTMLYJS.js.map → chunk-4NXKCLLQ.js.map} +0 -0
- /package/dist/{chunk-GXLZXD2W.js.map → chunk-4VNQOLML.js.map} +0 -0
- /package/dist/{chunk-45QPICLE.js.map → chunk-5M5DVGV7.js.map} +0 -0
- /package/dist/{chunk-S2OWPVSO.js.map → chunk-5YOLBEQ6.js.map} +0 -0
- /package/dist/{chunk-BDEMZD4F.js.map → chunk-6CRIV7DE.js.map} +0 -0
- /package/dist/{chunk-VCUQR6ZL.js.map → chunk-6JTIAGHD.js.map} +0 -0
- /package/dist/{chunk-K2DLLK34.js.map → chunk-6QTNZJBS.js.map} +0 -0
- /package/dist/{chunk-UMC5QZTX.js.map → chunk-6T2SCQRU.js.map} +0 -0
- /package/dist/{chunk-J3JIYFYL.js.map → chunk-7DSTRQIJ.js.map} +0 -0
- /package/dist/{chunk-3QSOFZQB.js.map → chunk-AUSTCW2X.js.map} +0 -0
- /package/dist/{chunk-PN5332SU.js.map → chunk-B3HJYUOF.js.map} +0 -0
- /package/dist/{chunk-DIB2BOIH.js.map → chunk-BDVFPG6Y.js.map} +0 -0
- /package/dist/{chunk-FYNE4WLC.js.map → chunk-CAF6WOK7.js.map} +0 -0
- /package/dist/{chunk-37WOJQWY.js.map → chunk-CIE2BASH.js.map} +0 -0
- /package/dist/{chunk-BLUT46UP.js.map → chunk-CRI4OUV4.js.map} +0 -0
- /package/dist/{chunk-Y5TWPBNW.js.map → chunk-DLG74CNB.js.map} +0 -0
- /package/dist/{chunk-HIOLCOK3.js.map → chunk-E5ZQT5KX.js.map} +0 -0
- /package/dist/{chunk-IQIVD7TP.js.map → chunk-EQO2UVP4.js.map} +0 -0
- /package/dist/{chunk-US34HTOI.js.map → chunk-ERJ7FU55.js.map} +0 -0
- /package/dist/{chunk-S7TAPIRS.js.map → chunk-EVVGJDRQ.js.map} +0 -0
- /package/dist/{chunk-EXGDL2UQ.js.map → chunk-EVX47VBM.js.map} +0 -0
- /package/dist/{chunk-NT2ZO4KI.js.map → chunk-EXK7QRWF.js.map} +0 -0
- /package/dist/{chunk-7QLY64AD.js.map → chunk-EYZ6IQ6X.js.map} +0 -0
- /package/dist/{chunk-QF5LGMSV.js.map → chunk-F64IRYG3.js.map} +0 -0
- /package/dist/{chunk-PH7G7ZI7.js.map → chunk-FHS2HQSH.js.map} +0 -0
- /package/dist/{chunk-ZHOJOT6S.js.map → chunk-FUG4SFN3.js.map} +0 -0
- /package/dist/{chunk-JRKE5MAZ.js.map → chunk-GKEWXIV5.js.map} +0 -0
- /package/dist/{chunk-6MA575R5.js.map → chunk-GTGPO5KW.js.map} +0 -0
- /package/dist/{chunk-XS6DLN67.js.map → chunk-HB3RFQSC.js.map} +0 -0
- /package/dist/{chunk-VXZNSPJM.js.map → chunk-HDMEGAQE.js.map} +0 -0
- /package/dist/{chunk-DJ7MRXNA.js.map → chunk-HTJQYHZP.js.map} +0 -0
- /package/dist/{chunk-NRYNRSGV.js.map → chunk-I6GALP6E.js.map} +0 -0
- /package/dist/{chunk-GL3JV5EV.js.map → chunk-IL6POWCW.js.map} +0 -0
- /package/dist/{chunk-NEYKOESM.js.map → chunk-IU6SNYX6.js.map} +0 -0
- /package/dist/{chunk-CCIR2OJH.js.map → chunk-J2ZX2XUV.js.map} +0 -0
- /package/dist/{chunk-NM3IFKBL.js.map → chunk-JKJOGPZN.js.map} +0 -0
- /package/dist/{chunk-TVS6BUUR.js.map → chunk-JZUV47FZ.js.map} +0 -0
- /package/dist/{chunk-5HNX4OD4.js.map → chunk-K5IMOGHB.js.map} +0 -0
- /package/dist/{chunk-XJ47GS53.js.map → chunk-KSKBRKGJ.js.map} +0 -0
- /package/dist/{chunk-INBQ43DI.js.map → chunk-LASZKVMO.js.map} +0 -0
- /package/dist/{chunk-EVHBK7BN.js.map → chunk-LXEXBTKL.js.map} +0 -0
- /package/dist/{chunk-6S7ENMRE.js.map → chunk-M4CV6BRT.js.map} +0 -0
- /package/dist/{chunk-AAIIDAUC.js.map → chunk-MEFJPTZ4.js.map} +0 -0
- /package/dist/{chunk-WHQHTNT7.js.map → chunk-MV43JSJF.js.map} +0 -0
- /package/dist/{chunk-F44XWXOA.js.map → chunk-NJ4EOKMB.js.map} +0 -0
- /package/dist/{chunk-ILF5GARW.js.map → chunk-NR5LT5RY.js.map} +0 -0
- /package/dist/{chunk-TBNF5DV5.js.map → chunk-NWSGI5C7.js.map} +0 -0
- /package/dist/{chunk-EIZ4YOG2.js.map → chunk-Q5VNKNE5.js.map} +0 -0
- /package/dist/{chunk-TVOHSPVK.js.map → chunk-QLWMEXCT.js.map} +0 -0
- /package/dist/{chunk-7GAXFU2O.js.map → chunk-QRB7NAOJ.js.map} +0 -0
- /package/dist/{chunk-X6Y5MXTH.js.map → chunk-R4ROFEYC.js.map} +0 -0
- /package/dist/{chunk-4BQXMCE5.js.map → chunk-RCVJZMFE.js.map} +0 -0
- /package/dist/{chunk-QG5RQQBO.js.map → chunk-RIX4V2TB.js.map} +0 -0
- /package/dist/{chunk-SAL5X5OK.js.map → chunk-RYCTDFUX.js.map} +0 -0
- /package/dist/{chunk-CXC3JLAQ.js.map → chunk-RZ5SVOYR.js.map} +0 -0
- /package/dist/{chunk-44IL5G3W.js.map → chunk-SLFHQTTW.js.map} +0 -0
- /package/dist/{chunk-2MTRJCBI.js.map → chunk-T2FFWNPK.js.map} +0 -0
- /package/dist/{chunk-QYPDYN23.js.map → chunk-UNFPPVNI.js.map} +0 -0
- /package/dist/{chunk-7ZOSHEVS.js.map → chunk-VLFCJYTL.js.map} +0 -0
- /package/dist/{chunk-APHLCXVC.js.map → chunk-VN3DBQAU.js.map} +0 -0
- /package/dist/{chunk-HK4XTXO4.js.map → chunk-VZRODIM3.js.map} +0 -0
- /package/dist/{chunk-P2LJI6JE.js.map → chunk-W22IKJE2.js.map} +0 -0
- /package/dist/{chunk-FJTWLQV3.js.map → chunk-X3YYQWOQ.js.map} +0 -0
- /package/dist/{chunk-SGJGWBSC.js.map → chunk-YFXZEAYK.js.map} +0 -0
- /package/dist/{chunk-SIAIYP6G.js.map → chunk-ZAJAVEXY.js.map} +0 -0
- /package/dist/{chunk-KKYEZCQG.js.map → chunk-ZICD77GM.js.map} +0 -0
- /package/dist/{chunk-HGAB325C.js.map → chunk-ZJ2AK4V7.js.map} +0 -0
- /package/dist/{chunk-HYG32HCM.js.map → chunk-ZUODRVHY.js.map} +0 -0
- /package/dist/{classified-marker-M7K3OJPM.js.map → classified-marker-CZKA6ITE.js.map} +0 -0
- /package/dist/{collection-facade-DWA735G2.js.map → collection-facade-TLWIPI76.js.map} +0 -0
- /package/dist/{computed-ORCGM5JE.js.map → computed-ZIQTYTDI.js.map} +0 -0
- /package/dist/{dead-filter-OV5FGKOG.js.map → dead-filter-ESOBZZP5.js.map} +0 -0
- /package/dist/{delegation-YVSHMIZZ.js.map → delegation-W7ZV2322.js.map} +0 -0
- /package/dist/{derive-BUO555L5.js.map → derive-H2BJTLUI.js.map} +0 -0
- /package/dist/{enclave-XXFUKJC6.js.map → enclave-AP3I5W7O.js.map} +0 -0
- /package/dist/{executor-6OCCE5VM.js.map → executor-KGWTNEQD.js.map} +0 -0
- /package/dist/{executor-JFVAJY42.js.map → executor-OVEXR6RT.js.map} +0 -0
- /package/dist/{executor-UPSH5O3F.js.map → executor-UNEH5ZYH.js.map} +0 -0
- /package/dist/{export-accessible-L4A2QZA5.js.map → export-accessible-PCMXSUZS.js.map} +0 -0
- /package/dist/{extract-partition-ZHQ4RGGM.js.map → extract-partition-SWHFSYJO.js.map} +0 -0
- /package/dist/{fanout-sidecar-IO2KDUWV.js.map → fanout-sidecar-A765THMX.js.map} +0 -0
- /package/dist/{find-ZFZDZQ2U.js.map → find-N6345CNT.js.map} +0 -0
- /package/dist/{issue-OG4V23SQ.js.map → issue-5OKB6I2R.js.map} +0 -0
- /package/dist/{ledger-UAQKPWNM.js.map → ledger-GFBKVPV4.js.map} +0 -0
- /package/dist/{liberate-GFUQJRK5.js.map → liberate-3VDOT4KO.js.map} +0 -0
- /package/dist/{link-set-DGYUOFVD.js.map → link-set-Z7Q2ASFX.js.map} +0 -0
- /package/dist/{noydb-AKH4AMCR.js.map → noydb-ZCJOYBDI.js.map} +0 -0
- /package/dist/{policy-5POYLI26.js.map → policy-Z3RUAIY2.js.map} +0 -0
- /package/dist/{post-register-LB3P4XQU.js.map → post-register-JTH76BLY.js.map} +0 -0
- /package/dist/{public-envelope-GOG4LUM7.js.map → public-envelope-B4KNWVUA.js.map} +0 -0
- /package/dist/{register-ZI7YI7US.js.map → register-VAHONCID.js.map} +0 -0
- /package/dist/{registry-DZ2T4LL7.js.map → registry-7MLVD3VO.js.map} +0 -0
- /package/dist/{registry-NVWEQ2GU.js.map → registry-EPKPD5SM.js.map} +0 -0
- /package/dist/{registry-SEKL74ET.js.map → registry-P5T7PS2U.js.map} +0 -0
- /package/dist/{request-withdrawal-ZP3JIRVS.js.map → request-withdrawal-TI3A5WPS.js.map} +0 -0
- /package/dist/{revoke-VF6TAJK2.js.map → revoke-FDRD6GRW.js.map} +0 -0
- /package/dist/{seed-VI4FU7UH.js.map → seed-Q6M2IZFL.js.map} +0 -0
- /package/dist/{signer-DRDDCCHW.js.map → signer-MUWEIUI6.js.map} +0 -0
- /package/dist/{stale-TJXFQKOJ.js.map → stale-OSQ7J3AA.js.map} +0 -0
- /package/dist/{storage-GR7KZRH4.js.map → storage-MVFCGEQE.js.map} +0 -0
- /package/dist/{store-coordination-provider-5KDS2RRP.js.map → store-coordination-provider-64OEZFGS.js.map} +0 -0
- /package/dist/{walk-XQCBKSBW.js.map → walk-SVNDIZ62.js.map} +0 -0
- /package/dist/{withdraw-accessible-FMN4LPJZ.js.map → withdraw-accessible-WZIEVWSR.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/kernel/enclave/classify/verify.ts"],"sourcesContent":["/**\n * The enclave verify oracle (spec §3). Verdict-only egress: no path\n * distinguishes \"record missing\" / \"no digest\" / \"AAD-tamper\" / \"mismatch\"\n * beyond { ok: false } — existence oracles are oracles too. Every path that\n * cannot run a real comparison runs ONE dummy PBKDF2 + ONE dummy tag-compare\n * first (C4), so wall-clock cannot enumerate records/fields/answers. The\n * text door (verifyTextField) has no real PBKDF2 of its own, so it pays the\n * pad UNCONDITIONALLY — every outcome, including a real compare, costs the\n * same one PBKDF2 unit (no inverted exists-vs-absent oracle).\n * Elevated records (_tier > 0, with-audit tier moves) are non-comparable\n * through every door and pad-false exactly like missing records (#691) —\n * the tier-aware read surface is getAtTier, never verify.\n * Throws are reserved for caller/config bugs (ClassifiedVerifyError /\n * ClassifiedConfigError) and are exempt from the pad by design (R6 note).\n * @module\n */\nimport { generateSalt, base64ToBuffer, type EnclaveKey } from '../crypto.js'\nimport { pbkdf2VerifyDigest, VDIG_ITERATIONS } from './digest.js'\nimport { normalizeForVerify, type VerifyNormalizeMode } from './normalize.js'\nimport { blindedEqual } from './compare.js'\nimport { evaluateKofN } from './kofn.js'\nimport { openVdigPayload, type VdigPayload } from './vdig.js'\nimport { dualReadSealedSlot } from '../record-keys/sealed-slot.js'\nimport { ClassifiedConfigError, ClassifiedVerifyError } from '../../errors.js'\nimport type { EncryptedEnvelope, VdigFieldPolicy, ClassifiedVerdict } from '../../types.js'\n\nexport interface VerifyEngineCtx {\n readonly collection: string\n getEnvelope(id: string): Promise<EncryptedEnvelope | null>\n resolveCek(env: EncryptedEnvelope): Promise<EnclaveKey | undefined>\n getDEK(): Promise<EnclaveKey>\n readonly now: () => number\n}\n\n/**\n * C4 pad: one full-cost dummy digest + one dummy compare; result discarded.\n * Pad at `iter` when the caller holds an AUTHENTICATED payload.iter, so pad\n * cost tracks the real compare cost across future iteration bumps; the\n * fully-absent paths (no payload to read an iter from) use VDIG_ITERATIONS.\n */\nasync function padOnce(iter: number = VDIG_ITERATIONS): Promise<void> {\n const dummy = await pbkdf2VerifyDigest('noydb-classify-c4-pad', generateSalt(), iter)\n await blindedEqual(dummy, dummy)\n}\n\nasync function padFalse(): Promise<ClassifiedVerdict> {\n await padOnce()\n return { ok: false }\n}\n\n/** R6 verify-side transition evidence — config bug, fail-loud, pad-exempt. */\nfunction refuseSealedResidue(collection: string, field: string): never {\n throw new ClassifiedConfigError(collection,\n `field \"${field}\" carries a recoverable _sealed slot but no _vdig — storage-form ` +\n `transition detected (R6); refused fail-loud, never an ok:false masquerading as wrong-password`)\n}\n\nexport async function verifyDigestField(\n ctx: VerifyEngineCtx,\n id: string,\n field: string,\n candidate: string,\n policy: VdigFieldPolicy,\n): Promise<ClassifiedVerdict> {\n const env = await ctx.getEnvelope(id)\n // #691: an elevated envelope (_tier > 0) is non-comparable through every\n // tier-0 door — its key material is tier-DEK-wrapped and must never be\n // resolved here (the elevating session's warm cekCache would otherwise\n // leak past the tier audit). Exactly the missing-record pad path, checked\n // BEFORE the R6 residue probe so tier-0 callers learn nothing.\n if (env === null || (env._tier ?? 0) > 0) return padFalse()\n const blob = env._vdig?.[field]\n if (blob === undefined) {\n if (env._sealed?.[field] !== undefined) refuseSealedResidue(ctx.collection, field)\n return padFalse()\n }\n const cek = await ctx.resolveCek(env)\n if (cek === undefined) return padFalse()\n\n let payload: VdigPayload\n try {\n payload = await openVdigPayload(blob, cek, ctx.collection, id, field)\n } catch {\n return padFalse() // AAD/tamper (C1) → padded false; no tamper oracle to the caller\n }\n\n const normalized = normalizeForVerify(policy.normalize, candidate)\n const digest = await pbkdf2VerifyDigest(normalized, base64ToBuffer(payload.cur.salt), payload.iter)\n const ok = await blindedEqual(digest, base64ToBuffer(payload.cur.hash))\n if (!ok) return { ok: false } // I1: bare false — mustRotate never computed here\n\n if (policy.rotateDays !== undefined\n && ctx.now() > Date.parse(payload.cur.at) + policy.rotateDays * 86_400_000) {\n // Disclosing write-age-vs-policy to a SUCCESSFUL verifier is intended (audit F6).\n return { ok: true, mustRotate: true }\n }\n return { ok: true }\n}\n\nexport async function verifyTextField(\n ctx: VerifyEngineCtx,\n id: string,\n field: string,\n candidate: string,\n normalize: VerifyNormalizeMode,\n): Promise<ClassifiedVerdict> {\n // C4, single code path: (a) attempt the unseal where a slot exists, then\n // for EVERY outcome — present-correct, present-wrong, missing record,\n // missing slot, tampered — (b) run the one constant-cost pad, (c) run one\n // blindedEqual, (d) return the boolean. Unlike the digest door there is no\n // real PBKDF2 here (unseal is sub-ms AES-GCM), so skipping the pad on the\n // real compare would make exists-but-wrong ~100x FASTER than absent — an\n // inverted existence oracle. No branch below skips the dominant cost.\n const env = await ctx.getEnvelope(id)\n const blob = env?._sealed?.[field]\n let stored: string | undefined\n if (env !== null && (env._tier ?? 0) === 0 && blob !== undefined) { // #691: elevated ≡ missing\n const cek = await ctx.resolveCek(env)\n const dek = await ctx.getDEK()\n try {\n // Plaintext exists microseconds inside this function; only the boolean leaves.\n stored = String(JSON.parse(await dualReadSealedSlot(blob, field, ctx.collection, cek, dek)))\n } catch {\n stored = undefined // AAD/tamper (C1) → same padded compare tail as absent\n }\n }\n await padOnce()\n const a = new TextEncoder().encode(normalizeForVerify(normalize, candidate))\n const b = stored !== undefined\n ? new TextEncoder().encode(normalizeForVerify(normalize, stored))\n : a // no-compare dummy comparand — the verdict is forced false below\n const eq = await blindedEqual(a, b)\n return { ok: stored !== undefined && eq }\n}\n\nexport async function matchGroupFields(\n ctx: VerifyEngineCtx,\n id: string,\n answers: Record<string, string>,\n members: ReadonlyArray<{ readonly field: string; readonly policy: VdigFieldPolicy }>,\n opts: { readonly min: number },\n): Promise<{ readonly passed: boolean }> {\n // I2 step 1 — validate EVERYTHING up front, before any PBKDF2, throwing\n // uniformly at ~0 elapsed (no member-position leak via timing/throw type).\n if (!Number.isInteger(opts.min) || opts.min < 1 || opts.min > members.length) {\n throw new ClassifiedVerifyError(ctx.collection, '*',\n `matchGroup min ${opts.min} out of range 1..${members.length}`)\n }\n const normalized = new Map<string, string>()\n for (const m of members) {\n const answer = answers[m.field] // non-member answer keys: silently ignored\n if (answer === undefined) continue\n if (typeof answer !== 'string') {\n throw new ClassifiedVerifyError(ctx.collection, m.field, 'candidate must be a string')\n }\n normalized.set(m.field, normalizeForVerify(m.policy.normalize, answer))\n }\n\n const fetched = await ctx.getEnvelope(id)\n // #691: elevated ≡ missing — nulling the view here also skips the R6\n // residue probe (a tier-0 caller must not learn an elevated record's\n // storage form) and forces the cek-undefined pad path for every member.\n const env = fetched === null || (fetched._tier ?? 0) > 0 ? null : fetched\n if (env !== null) {\n for (const m of members) { // R6 evidence — uniform, before any PBKDF2\n if (env._sealed?.[m.field] !== undefined && env._vdig?.[m.field] === undefined) {\n refuseSealedResidue(ctx.collection, m.field)\n }\n }\n }\n const cek = env !== null ? await ctx.resolveCek(env) : undefined\n\n // I2 step 2+3 — iterate RESOLVED GROUP MEMBERS (denominator = |members|),\n // evaluate EVERY member (collect, never break), pad every no-compare slot.\n const results: boolean[] = []\n for (const m of members) {\n const candidate = normalized.get(m.field)\n const blob = env?._vdig?.[m.field]\n if (env === null || cek === undefined || blob === undefined) {\n await padOnce()\n results.push(false)\n continue\n }\n try {\n const payload = await openVdigPayload(blob, cek, ctx.collection, id, m.field)\n if (candidate === undefined) {\n // Slot present, answer absent: the payload's authenticated iter is in\n // hand — pad at IT (not the constant) so a future iteration bump\n // cannot desync this pad's cost from the real compare's cost.\n await padOnce(payload.iter)\n results.push(false)\n continue\n }\n const digest = await pbkdf2VerifyDigest(candidate, base64ToBuffer(payload.cur.salt), payload.iter)\n results.push(await blindedEqual(digest, base64ToBuffer(payload.cur.hash)))\n } catch {\n await padOnce()\n results.push(false)\n }\n }\n // Per-member results never appear in any return, error, or audit payload.\n return { passed: evaluateKofN(results, opts.min) }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -3,19 +3,19 @@ import {
|
|
|
3
3
|
} from "./chunk-VYYM3MEN.js";
|
|
4
4
|
import {
|
|
5
5
|
derivePersistedSchema
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-W22IKJE2.js";
|
|
7
7
|
import {
|
|
8
8
|
loadPersistedSchema
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-
|
|
11
|
-
import "./chunk-
|
|
12
|
-
import "./chunk-
|
|
13
|
-
import "./chunk-
|
|
14
|
-
import "./chunk-
|
|
9
|
+
} from "./chunk-VZRODIM3.js";
|
|
10
|
+
import "./chunk-XDYREZWE.js";
|
|
11
|
+
import "./chunk-7DSTRQIJ.js";
|
|
12
|
+
import "./chunk-HB3RFQSC.js";
|
|
13
|
+
import "./chunk-JKJOGPZN.js";
|
|
14
|
+
import "./chunk-5M5DVGV7.js";
|
|
15
15
|
import "./chunk-LP7BEXCT.js";
|
|
16
|
-
import "./chunk-
|
|
17
|
-
import "./chunk-
|
|
18
|
-
import "./chunk-
|
|
16
|
+
import "./chunk-CIE2BASH.js";
|
|
17
|
+
import "./chunk-JNAI2HN2.js";
|
|
18
|
+
import "./chunk-BIOUI4HL.js";
|
|
19
19
|
import "./chunk-PZ5AY32C.js";
|
|
20
20
|
|
|
21
21
|
// src/with-shape/introspection/walk.ts
|
|
@@ -238,4 +238,4 @@ function summariseAggregateOp(value) {
|
|
|
238
238
|
export {
|
|
239
239
|
dumpVaultSchema
|
|
240
240
|
};
|
|
241
|
-
//# sourceMappingURL=walk-
|
|
241
|
+
//# sourceMappingURL=walk-SVNDIZ62.js.map
|
package/dist/with/index.js
CHANGED
|
@@ -6,18 +6,18 @@ import {
|
|
|
6
6
|
assertCanImport,
|
|
7
7
|
canExport,
|
|
8
8
|
canImport
|
|
9
|
-
} from "../chunk-
|
|
10
|
-
import "../chunk-
|
|
11
|
-
import "../chunk-
|
|
12
|
-
import "../chunk-
|
|
13
|
-
import "../chunk-
|
|
14
|
-
import "../chunk-
|
|
15
|
-
import "../chunk-
|
|
16
|
-
import "../chunk-
|
|
9
|
+
} from "../chunk-6QTNZJBS.js";
|
|
10
|
+
import "../chunk-J2ZX2XUV.js";
|
|
11
|
+
import "../chunk-4JBYV75E.js";
|
|
12
|
+
import "../chunk-XDYREZWE.js";
|
|
13
|
+
import "../chunk-7DSTRQIJ.js";
|
|
14
|
+
import "../chunk-HB3RFQSC.js";
|
|
15
|
+
import "../chunk-JKJOGPZN.js";
|
|
16
|
+
import "../chunk-5M5DVGV7.js";
|
|
17
17
|
import "../chunk-LP7BEXCT.js";
|
|
18
|
-
import "../chunk-
|
|
19
|
-
import "../chunk-
|
|
20
|
-
import "../chunk-
|
|
18
|
+
import "../chunk-CIE2BASH.js";
|
|
19
|
+
import "../chunk-JNAI2HN2.js";
|
|
20
|
+
import "../chunk-BIOUI4HL.js";
|
|
21
21
|
import "../chunk-PZ5AY32C.js";
|
|
22
22
|
export {
|
|
23
23
|
ServiceBus,
|
|
@@ -138,6 +138,13 @@ export interface ForgetResult {
|
|
|
138
138
|
/** `collection:id:field` sealed slots that were DEK-derived (legacy, written before per-record CEKs) and thus NOT crypto-shredded
|
|
139
139
|
* by dropping `_cek` — the collection DEK is retained, so synced/backup copies stay decryptable (#M-1). */
|
|
140
140
|
readonly sealedResidue: readonly string[];
|
|
141
|
+
/** Count of `_ledger_deltas` rows hard-deleted across the shredded records (#734) — the
|
|
142
|
+
* erasure twin of #729's elevate-side purge. Entry metadata (that the record was mutated,
|
|
143
|
+
* at which version/timestamp/actor) is retained; only the plaintext delta content is removed. */
|
|
144
|
+
readonly ledgerDeltasPurged: number;
|
|
145
|
+
/** `collection:id` refs whose `_ledger_deltas` purge failed — plaintext delta residue still
|
|
146
|
+
* readable under the retained ledger DEK. Non-empty means erasure is INCOMPLETE. */
|
|
147
|
+
readonly ledgerDeltaResidue: readonly string[];
|
|
141
148
|
/** The single `op:'forget'` ledger entry appended for this erasure. */
|
|
142
149
|
readonly ledgerEntry: LedgerEntry;
|
|
143
150
|
/** #622 — record-grain derived artifacts (MV rows, per-record derived copies) erased
|
|
@@ -162,6 +169,21 @@ export interface ForgetResult {
|
|
|
162
169
|
* Always empty under the unconditional default. Non-empty means a `_sealed_cek` entry or a
|
|
163
170
|
* blob scan was skipped for an undeclared collection — reported, never a silent skip. */
|
|
164
171
|
readonly scopedPurgeResidue: readonly ScopedPurgeResidueNotice[];
|
|
172
|
+
/** #776/#782/#785 — `collection:id` MV-output rows that survived erasure invalidation (eager
|
|
173
|
+
* tombstone leg AND lazy/manual `invalidateMVAtRest`) despite belonging to the forgotten
|
|
174
|
+
* subject, because the `_materializedFrom` ownership stamp could NOT be decoded (undecodable
|
|
175
|
+
* under the collection's default DEK — e.g. elevated above tier 0 on a tiered output
|
|
176
|
+
* collection; ownership unconfirmed — could be a plain user record on a same-collection
|
|
177
|
+
* partition MV). Never erased, but surfaced here rather than silently skipped (the #724
|
|
178
|
+
* posture). Non-empty means the row may still hold the forgotten/pre-elevation contribution,
|
|
179
|
+
* decryptable by tier-holders. */
|
|
180
|
+
readonly derivedResidueUndecodable: readonly string[];
|
|
181
|
+
/** #782/#785 — `collection:id` MV-output rows that DID decode and stamp-match via
|
|
182
|
+
* `_materializedFrom`, but whose erasure was declined by the #718 tier-elevation gate
|
|
183
|
+
* (`_internalDelete` returned false). Ownership CONFIRMED here — a real silent survival,
|
|
184
|
+
* not a stamp-mismatch skip — surfaced rather than dropped. Non-empty means a live,
|
|
185
|
+
* tier-holder-decryptable copy of the forgotten contribution was deliberately retained. */
|
|
186
|
+
readonly derivedResidueDeclined: readonly string[];
|
|
165
187
|
}
|
|
166
188
|
/** #633 — the two `scopedPurgeResidue` skip reasons. Single source of truth: `purge-scope.ts`
|
|
167
189
|
* (the port-internal partition helpers) imports this rather than redeclaring it. */
|
|
@@ -26,6 +26,7 @@ export { TiersNotEnabledError } from '../../kernel/errors.js';
|
|
|
26
26
|
import { type RecordCodec, type EnclaveKey, type SealedShredSlot } from '../../kernel/enclave/index.js';
|
|
27
27
|
import type { UnlockedKeyring } from '../../with-party/team/keyring.js';
|
|
28
28
|
import type { Lru } from '../../kernel/cache/index.js';
|
|
29
|
+
import type { BlobFieldsConfig } from '../../with-shape/blobs/blob-compaction.js';
|
|
29
30
|
import { type NoydbStore, type EncryptedEnvelope, type GhostRecord, type TierMode, type CrossTierAccessEvent } from '../../kernel/types.js';
|
|
30
31
|
/** Everything the moving tier methods touched on `this.*`, as a flat context. */
|
|
31
32
|
export interface TiersContext<T> {
|
|
@@ -46,6 +47,168 @@ export interface TiersContext<T> {
|
|
|
46
47
|
* owns. `null` → no caching.
|
|
47
48
|
*/
|
|
48
49
|
readonly cekCache: Lru<string, EnclaveKey> | null;
|
|
50
|
+
/**
|
|
51
|
+
* Sync the collection's decoded-record cache after a tier move rewraps the
|
|
52
|
+
* envelope (#691). The lazy LRU is evicted on EVERY call — it is never
|
|
53
|
+
* re-seeded, since a lazy `#getRaw` miss refetches and decodes the fresh
|
|
54
|
+
* envelope via its adapter fallback (a stale LRU entry after a tier-0
|
|
55
|
+
* `putAtTier` overwrite was the #702 lazy-mode gap). `null` → also evict
|
|
56
|
+
* the eager cache entry; an `entry` → set the eager cache to the given
|
|
57
|
+
* decoded record/version (used by `demote()` landing back at tier 0 and
|
|
58
|
+
* `putAtTier`'s tier-0 write, #702 — the record is tier-0, so it must stay
|
|
59
|
+
* plain-`get()`-readable in-session).
|
|
60
|
+
*/
|
|
61
|
+
syncCache(id: string, entry: {
|
|
62
|
+
record: T;
|
|
63
|
+
version: number;
|
|
64
|
+
} | null): void;
|
|
65
|
+
/**
|
|
66
|
+
* Sync the collection's indexes after a tier move rewraps the envelope
|
|
67
|
+
* (#709). Persisted `_idx/<field>/<recordId>` side-cars hold the indexed
|
|
68
|
+
* field's PLAINTEXT value and are always encrypted under the tier-0 DEK,
|
|
69
|
+
* whatever the record's own tier — the same leak class `forget()` fixed
|
|
70
|
+
* via `purgePersistedIndexes` ("forget() crypto-shreds the body but keeps
|
|
71
|
+
* the collection DEK, under which these side-cars are encrypted — so
|
|
72
|
+
* without this they leave the indexed field VALUES readable"). `null` →
|
|
73
|
+
* the record just left tier 0: purge its persisted side-cars and drop its
|
|
74
|
+
* in-memory index entries. A record → it is tier-0 again: (re)build its
|
|
75
|
+
* entries from that record. Call this BEFORE {@link syncCache} — the
|
|
76
|
+
* implementation reads the pre-write cached value as "previous" to clean
|
|
77
|
+
* up stale index buckets, so it must run while that entry is still live.
|
|
78
|
+
* `version` stamps a rebuilt side-car's own envelope version — every
|
|
79
|
+
* caller has one in scope (the envelope it just wrote), including the
|
|
80
|
+
* purge (`null`) branches, which pass it along even though it's ignored
|
|
81
|
+
* there (#720: keeps the parameter honestly required, no dead default).
|
|
82
|
+
* `priorEnvelope` (#720) — the RAW envelope read BEFORE this call's own
|
|
83
|
+
* overwrite (already in scope as `existing`/`envelope` at every record-
|
|
84
|
+
* branch call site), so a lazy same-tier value change (a `putAtTier(0)`
|
|
85
|
+
* dropping an indexed field, a `demote(0)` off an elevated record) can
|
|
86
|
+
* still be tier-gate-decoded as "previous" once the live envelope itself
|
|
87
|
+
* has already moved past it. The `null`-record branches never pass one —
|
|
88
|
+
* see the implementation's doc comment for why they don't need to.
|
|
89
|
+
*/
|
|
90
|
+
syncIndexes(id: string, record: T | null, version: number, priorEnvelope?: EncryptedEnvelope): Promise<void>;
|
|
91
|
+
/** Sync the collection's SEARCH artifacts after a tier move (#721). Both the
|
|
92
|
+
* lexical `_ftindex` blob and the `_vec/<id>` embedding are encrypted under
|
|
93
|
+
* the tier-0 DEK and hold the record's derived plaintext (full field text /
|
|
94
|
+
* a text-invertible vector), so leaving them means elevation never hid what
|
|
95
|
+
* the record was searchable by — the `forget()` precedent, unapplied to
|
|
96
|
+
* elevate. `null` → the record left tier 0: purge its `_vec`, and
|
|
97
|
+
* invalidate the `_ftindex` blob (the cache-driven rebuild then excludes
|
|
98
|
+
* it). A record → it is tier-0 again: re-embed it, and invalidate
|
|
99
|
+
* `_ftindex` (rebuild includes it). No-op fast when the collection has no
|
|
100
|
+
* search. */
|
|
101
|
+
syncSearch(id: string, record: T | null, version?: number): Promise<void>;
|
|
102
|
+
/**
|
|
103
|
+
* Sync a record's `_history` snapshots after a tier move rewraps the live
|
|
104
|
+
* envelope (#712, at-rest hardening). Each snapshot carries its own key
|
|
105
|
+
* material (a direct DEK wrap, or a per-record `_cek` itself wrapped under
|
|
106
|
+
* the tier DEK) — `elevate()`'s live-body rewrap moves only the live
|
|
107
|
+
* envelope, leaving prior versions decryptable at rest under the tier the
|
|
108
|
+
* record has moved away from (the same leak class `forget()`'s
|
|
109
|
+
* `tombstoneHistory` closed for erasure). `fromDek`/`toDek` are the SAME
|
|
110
|
+
* DEKs the caller already resolved for the live rewrap — reuse them, don't
|
|
111
|
+
* recompute. No-op when the strategy is `NO_HISTORY`.
|
|
112
|
+
*/
|
|
113
|
+
syncHistory(id: string, fromDek: EnclaveKey, toDek: EnclaveKey): Promise<void>;
|
|
114
|
+
/**
|
|
115
|
+
* Save a raw pre-move envelope as a `_history` snapshot (#728). Tier moves
|
|
116
|
+
* (`putAtTier`/`elevate`/`demote`) bump `_v` and overwrite the live
|
|
117
|
+
* envelope without ever snapshotting the version that existed just before
|
|
118
|
+
* the move — so `history()` silently lost it. The caller (`tiers/index.ts`)
|
|
119
|
+
* builds `envelope` by reusing the SAME `rewrapBodyToDek(envelope, fromDek,
|
|
120
|
+
* toDek)` result it already computed for the live write, so the snapshot
|
|
121
|
+
* lands wrapped under the DESTINATION tier's DEK — never `ctx.codec.
|
|
122
|
+
* encryptRecord`, which always resolves the tier-0 DEK and would leak the
|
|
123
|
+
* pre-move body whenever `fromTier > 0`. No-op when history is disabled
|
|
124
|
+
* (folds the `historyConfig.enabled` gate so `tiers/index.ts` stays simple).
|
|
125
|
+
*/
|
|
126
|
+
saveHistorySnapshot(id: string, envelope: EncryptedEnvelope): Promise<void>;
|
|
127
|
+
/**
|
|
128
|
+
* `true` iff a real history strategy is wired (not `NO_HISTORY`) AND not
|
|
129
|
+
* explicitly disabled via `historyConfig.enabled`. `putAtTier` checks this
|
|
130
|
+
* BEFORE decrypting `existing` to build a snapshot (#728, #737 regression
|
|
131
|
+
* fix) — unlike elevate/demote, which reuse a `body` rewrap their live
|
|
132
|
+
* write needs unconditionally, putAtTier's live write never decrypts the
|
|
133
|
+
* prior envelope, so building a snapshot is the ONLY reason it would
|
|
134
|
+
* touch (and potentially throw decrypting) `existing`'s ciphertext. A
|
|
135
|
+
* derivation-free, history-disabled collection must not pay that decode —
|
|
136
|
+
* or risk it, on a corrupted/inaccessible prior body — same law
|
|
137
|
+
* `hasDerivedOutputs` already enforces for the derived-outputs decode.
|
|
138
|
+
*/
|
|
139
|
+
readonly historyEnabled: boolean;
|
|
140
|
+
/**
|
|
141
|
+
* Rehome a record's blob attachments after a tier move (#724 Arc 10 Task
|
|
142
|
+
* 2, at-rest hardening). A blob's home tier is its owning record's tier —
|
|
143
|
+
* the `_blob` DEK is tier-scoped (`dekKey('_blob', tier)`), so a solo-
|
|
144
|
+
* owned blob's content CEK must move with the record or it stays
|
|
145
|
+
* tier-0-unwrappable at rest even once the live body has moved (the same
|
|
146
|
+
* leak class `syncHistory` closes for `_history` snapshots). Delegates to
|
|
147
|
+
* `BlobSet.rehomeForTier`; no-op fast when the collection has no blob
|
|
148
|
+
* fields. Order-independent with the other sync hooks — touches only
|
|
149
|
+
* blob side structures, not this collection's own cache/indexes.
|
|
150
|
+
*/
|
|
151
|
+
syncBlobs(id: string, fromTier: number, toTier: number): Promise<void>;
|
|
152
|
+
/**
|
|
153
|
+
* Purge a record's tier-0-era plaintext ledger deltas after a tier move
|
|
154
|
+
* lands it above tier 0 (#729). The audit ledger is a flat, vault-wide,
|
|
155
|
+
* hash-chained log — a record's reverse-JSON-Patch deltas in
|
|
156
|
+
* `_ledger_deltas` are encrypted under one collection-wide `_ledger` DEK
|
|
157
|
+
* (not the record's own tier DEK), so `elevate()`/`putAtTier()`'s live-body
|
|
158
|
+
* rewrap never moves them: they stay readable at rest to any tier-0
|
|
159
|
+
* caller, the same leak class `syncHistory` closed for `_history`
|
|
160
|
+
* snapshots. Chain-safe: `verify()` reads only `_ledger` entry fields
|
|
161
|
+
* (including `deltaHash`, which lives on the entry, not the deleted delta
|
|
162
|
+
* row), never `_ledger_deltas`, so a purge cannot break it.
|
|
163
|
+
* **Irreversible** — the deleted plaintext cannot be restored by
|
|
164
|
+
* `demote()`. **Metadata-retained** — the `_ledger` entries (that the
|
|
165
|
+
* record was mutated, at which version/timestamp/actor) are untouched;
|
|
166
|
+
* only the delta *content* is purged. No-op when the collection has no
|
|
167
|
+
* ledger (`withHistory()` not enabled).
|
|
168
|
+
*/
|
|
169
|
+
syncLedger(id: string): Promise<void>;
|
|
170
|
+
/**
|
|
171
|
+
* Sync a record's derived outputs (materialized-view rows, rollup
|
|
172
|
+
* contributions, `withDerivation` outputs) after a tier move (#722).
|
|
173
|
+
* Those outputs are computed from this record and written to OTHER
|
|
174
|
+
* (output) collections via a plain `put` at tier 0 — `elevate()`'s live-
|
|
175
|
+
* body rewrap moves only the source envelope, so the output rows keep
|
|
176
|
+
* holding the source's tier-0-era plaintext, the same leak class
|
|
177
|
+
* `syncSearch`/`syncIndexes` closed for THIS collection's own artifacts.
|
|
178
|
+
* `elevated` (landing tier > 0) reuses the SAME onDelete fanout
|
|
179
|
+
* `forgetDerivedFanout` drives for `forget()` (`kernel/via/dispatch.ts`)
|
|
180
|
+
* — minus its `'ref'` cascade edge (elevate/demote never erase a
|
|
181
|
+
* *different* record) — to recompute this record's derived outputs as
|
|
182
|
+
* REMOVED. Recompute is tier-safe: the fanout's own source scan reads
|
|
183
|
+
* the elevated-excluding cache (#701/#709/#712), so it naturally omits
|
|
184
|
+
* the now-elevated record instead of re-embedding its plaintext. Landing
|
|
185
|
+
* back at tier 0 (`elevated === false`) is the reverse (Task 2, #722):
|
|
186
|
+
* `syncDerivedOutputs` instead runs the ordinary local-write add-
|
|
187
|
+
* dispatchers (`dispatchDerivations`/`dispatchMaterializedViews`, the
|
|
188
|
+
* same ones a plain `put()` fires) to restore the contribution —
|
|
189
|
+
* reversible, since the source's plaintext survives the elevate/demote
|
|
190
|
+
* rewrap round-trip. `record` is the decoded source record (PRE-move on
|
|
191
|
+
* the remove side, POST-move on the add side); only the rollup edge
|
|
192
|
+
* consumes it on remove, both add-dispatchers require it on add; `null`
|
|
193
|
+
* (tombstone/delete-marker) skips both. `version` stamps the add-
|
|
194
|
+
* dispatchers' `_derivedFrom.sourceVersion` metadata — reuses the version
|
|
195
|
+
* the tier op already has, no re-read; unused on the remove side. No-op
|
|
196
|
+
* fast when the collection has no MV/derivation source — each dispatcher
|
|
197
|
+
* below checks its own source before doing any work.
|
|
198
|
+
*/
|
|
199
|
+
syncDerived(id: string, record: T | null, elevated: boolean, version?: number): Promise<void>;
|
|
200
|
+
/**
|
|
201
|
+
* `true` iff the collection has a materialized-view or derivation source
|
|
202
|
+
* attached. Gates the {@link syncDerived} pre-move decode on the remove
|
|
203
|
+
* direction (`elevate()`, `putAtTier(tier>0)`, `demote()`'s intermediate-
|
|
204
|
+
* tier branch): those sites decode the record SOLELY to feed
|
|
205
|
+
* `syncDerived(..., true)`, whose dispatchers no-op immediately when the
|
|
206
|
+
* collection has no MV/derivation source — so a no-derivation collection
|
|
207
|
+
* would otherwise pay a full record-body decrypt on every tier move for
|
|
208
|
+
* nothing (#722 perf regression). `false` short-circuits the decode to
|
|
209
|
+
* `null`, which `syncDerivedOutputs` already treats safely.
|
|
210
|
+
*/
|
|
211
|
+
readonly hasDerivedOutputs: boolean;
|
|
49
212
|
/** Emit `_source`/`_sourceTs` provenance fields when a source is supplied. */
|
|
50
213
|
readonly provenance: boolean;
|
|
51
214
|
/** Declared tiers, or null when the feature is off. */
|
|
@@ -56,9 +219,108 @@ export interface TiersContext<T> {
|
|
|
56
219
|
getDEK(key: string): Promise<EnclaveKey>;
|
|
57
220
|
/** Fire a cross-tier access event (sink stays collection-resident). */
|
|
58
221
|
emitCrossTierEvent(event: CrossTierAccessEvent): void;
|
|
222
|
+
/**
|
|
223
|
+
* Register this record's ref in the encrypted `_subject_index` (#766).
|
|
224
|
+
* `putAtTier`'s raw `ctx.adapter.put` bypasses `Collection.put()`'s write-
|
|
225
|
+
* hook pipeline — the `onAfterWrite` hook that normally does this — so a
|
|
226
|
+
* record whose FIRST persistence is `putAtTier` (sensitive from birth, a
|
|
227
|
+
* documented legitimate use) would otherwise never enter the index and
|
|
228
|
+
* stay unreachable by `vault.forget()`. Idempotent (safe on every call,
|
|
229
|
+
* including a repeat write of an already-registered record) and a no-op
|
|
230
|
+
* when the collection declares no forget-subject field.
|
|
231
|
+
*/
|
|
232
|
+
addSubjectRef(id: string, record: T): Promise<void>;
|
|
59
233
|
}
|
|
60
234
|
export declare function assertTiersEnabled<T>(ctx: TiersContext<T>): void;
|
|
61
235
|
export declare function assertDeclaredTier<T>(ctx: TiersContext<T>, tier: number): void;
|
|
236
|
+
/**
|
|
237
|
+
* Tier-composition guard (#724 / Arc 7 of the tier-invisibility campaign).
|
|
238
|
+
*
|
|
239
|
+
* Refuses `tiers` declared together with a derived-artifact feature whose
|
|
240
|
+
* crypto has not yet been made tier-aware — i.e. a feature `elevate()` /
|
|
241
|
+
* `demote()` does not re-key when a record moves tiers, so an elevated
|
|
242
|
+
* record's data for that feature would stay readable at tier 0.
|
|
243
|
+
*
|
|
244
|
+
* **Status:** the original call site (`Collection` constructor, beside
|
|
245
|
+
* `buildUniqueConstraintSet`) was removed by Arc 10 Task 1 (#724) — the
|
|
246
|
+
* `tiers + blobFields` refusal below was superseded by a runtime read gate
|
|
247
|
+
* on `collection.blob(id)` (`with-shape/blobs/blob-set.ts`), so this
|
|
248
|
+
* function currently has no caller. Relocated here from
|
|
249
|
+
* `with-lookup/indexing/unique-constraints.ts` (#733) so the tier-domain
|
|
250
|
+
* guard lives in the tier domain, rather than an indexing file it only
|
|
251
|
+
* borrowed for a grandfathered import specifier.
|
|
252
|
+
*
|
|
253
|
+
* ## #724 verified: `tiers + blobFields` leaks
|
|
254
|
+
*
|
|
255
|
+
* `collection.blob(id)` (`Collection.blob()`) never checks the live
|
|
256
|
+
* record's tier before returning a `BlobSet` handle, and `BlobSet`'s crypto
|
|
257
|
+
* is entirely orthogonal to the tier ladder:
|
|
258
|
+
* - the slot map (`_blob_slots_{collection}/{id}`) is encrypted under the
|
|
259
|
+
* collection's TIER-0 DEK (`getDEK(name)` ≡ `dekKey(name, 0)` — see
|
|
260
|
+
* `dekKey` in `with-party/team/tiers.ts`), never a tier-N DEK;
|
|
261
|
+
* - chunk content (`_blob_index` / `_blob_chunks`) is encrypted under the
|
|
262
|
+
* vault-shared `_blob` DEK (`BLOB_COLLECTION`), which has no tier
|
|
263
|
+
* dimension at all.
|
|
264
|
+
* `elevate()`/`demote()` (this file) rewrap only the live record body,
|
|
265
|
+
* `_history` snapshots (#712), and index side-cars — blob slots and chunks
|
|
266
|
+
* are untouched. A caller whose keyring never held the record's elevated
|
|
267
|
+
* tier DEK can still open `collection.blob(id).get(slot)` and read full
|
|
268
|
+
* plaintext, even though `collection.get(id)` correctly reports the same
|
|
269
|
+
* record as invisible. See `__tests__/tier-composition-guard.test.ts` for
|
|
270
|
+
* the reproduction.
|
|
271
|
+
*
|
|
272
|
+
* ## Safe today — no check needed here
|
|
273
|
+
*
|
|
274
|
+
* Field indexes, search (`textIndexes`/`embeddings`), `withHistory`
|
|
275
|
+
* (snapshot keys are rewrapped by `elevate()`/`demote()`, #712), and the
|
|
276
|
+
* decoded-record cache (evicted on tier moves) are already tier-safe. They
|
|
277
|
+
* are not enumerated below; only known-unsafe features are refused, so any
|
|
278
|
+
* combination not named here passes silently by default.
|
|
279
|
+
*
|
|
280
|
+
* ## Deliberately NOT handled here
|
|
281
|
+
*
|
|
282
|
+
* - `ledger` — `withHistory` threads a ledger writer onto every tiered
|
|
283
|
+
* collection by default in shipped usage; refusing `tiers + ledger` would
|
|
284
|
+
* break that default. A ledger-specific tier-rekey handler (rewrap ledger
|
|
285
|
+
* entries, or scope ledger visibility to tier) is a separate arc.
|
|
286
|
+
* - materialized-view (MV) output — an MV's fanout spec lives on the
|
|
287
|
+
* SOURCE collection, not on the MV collection's own config, so it is not
|
|
288
|
+
* visible at `vault.collection()` registration time and this guard cannot
|
|
289
|
+
* detect it structurally.
|
|
290
|
+
*/
|
|
291
|
+
export declare function assertTierComposition(collectionName: string, cfg: {
|
|
292
|
+
readonly tiers: boolean;
|
|
293
|
+
readonly blobFields: BlobFieldsConfig | undefined;
|
|
294
|
+
}): void;
|
|
295
|
+
/**
|
|
296
|
+
* Structural surface {@link syncDerivedOutputs} needs from the owning
|
|
297
|
+
* collection — the SAME onDelete dispatchers `forgetDerivedFanout` already
|
|
298
|
+
* drives (`kernel/via/dispatch.ts`), reused as-is (#722). Narrower than
|
|
299
|
+
* `Collection<T>` (avoids an import cycle: collection.ts constructs
|
|
300
|
+
* `TiersContext` FROM `this`, which already satisfies this shape
|
|
301
|
+
* structurally — no cast needed at the `tiersContext()` call site).
|
|
302
|
+
*/
|
|
303
|
+
export interface DerivedOutputsHost<T> {
|
|
304
|
+
dispatchMaterializedViewsOnDelete(id: string): Promise<{
|
|
305
|
+
deleted: number;
|
|
306
|
+
residueUndecodable: string[];
|
|
307
|
+
residueDeclined: string[];
|
|
308
|
+
}>;
|
|
309
|
+
dispatchArrayDerivationsOnDelete(id: string, eraseRecordShapeToo?: boolean): Promise<number>;
|
|
310
|
+
dispatchRollupsOnDelete(id: string, deleted: T): Promise<unknown>;
|
|
311
|
+
/** Task 2 (#722) add-direction: the same local-write dispatchers an ordinary `put()` fires. */
|
|
312
|
+
dispatchMaterializedViews(id: string, record: T): Promise<void>;
|
|
313
|
+
dispatchDerivations(id: string, record: T, version: number): Promise<void>;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* The {@link TiersContext.syncDerived} implementation collection.ts's
|
|
317
|
+
* `tiersContext()` binds `this` into (#722). See that field's doc comment
|
|
318
|
+
* for the design; `host` is `this` — every dispatcher below is a public
|
|
319
|
+
* Collection method, already self-guarding (no-op) when the collection has
|
|
320
|
+
* no materialized-view/derivation source, so no separate fast-path check is
|
|
321
|
+
* needed here.
|
|
322
|
+
*/
|
|
323
|
+
export declare function syncDerivedOutputs<T>(host: DerivedOutputsHost<T>, id: string, record: T | null, elevated: boolean, version?: number): Promise<void>;
|
|
62
324
|
/**
|
|
63
325
|
* tier-aware put. Encrypts the record with the collection's tier-N DEK and
|
|
64
326
|
* stamps `_tier: N` on the envelope. The caller's keyring must hold the tier-N
|
|
@@ -78,7 +340,7 @@ export declare function putAtTier<T>(ctx: TiersContext<T>, id: string, record: T
|
|
|
78
340
|
};
|
|
79
341
|
source?: string;
|
|
80
342
|
sourceTs?: string;
|
|
81
|
-
}): Promise<
|
|
343
|
+
}): Promise<TierMoveResult>;
|
|
82
344
|
/**
|
|
83
345
|
* tier-aware get. When the stored record is at a tier the caller cannot
|
|
84
346
|
* decrypt:
|
|
@@ -100,18 +362,28 @@ export declare function listAtTier<T>(ctx: TiersContext<T>): Promise<Array<{
|
|
|
100
362
|
tier: number;
|
|
101
363
|
readable: boolean;
|
|
102
364
|
}>>;
|
|
365
|
+
/**
|
|
366
|
+
* Result of a completed `elevate()`/`demote()` (#764). The record move
|
|
367
|
+
* (put + indexes/cache/ledger/derived/history/blobs sync) always completes —
|
|
368
|
+
* `searchResidue: true` means only the search-index side (`_vec`/`_ftindex`)
|
|
369
|
+
* was left in a needs-retry state (a stuck `PersistedIndexCompensationError`),
|
|
370
|
+
* mirroring `forget()`'s `indexResidue` posture rather than aborting the move.
|
|
371
|
+
*/
|
|
372
|
+
export interface TierMoveResult {
|
|
373
|
+
readonly searchResidue: boolean;
|
|
374
|
+
}
|
|
103
375
|
/**
|
|
104
376
|
* elevate a record to a higher tier. Re-encrypts with the target tier's DEK.
|
|
105
377
|
* The caller must hold DEKs for both the current tier (to decrypt) and the
|
|
106
378
|
* target tier (to re-encrypt). Stamps `_elevatedBy` with the caller id so
|
|
107
379
|
* `demote()` can check the reverse operation.
|
|
108
380
|
*/
|
|
109
|
-
export declare function elevate<T>(ctx: TiersContext<T>, id: string, toTier: number): Promise<
|
|
381
|
+
export declare function elevate<T>(ctx: TiersContext<T>, id: string, toTier: number): Promise<TierMoveResult>;
|
|
110
382
|
/**
|
|
111
383
|
* demote a record to a lower tier. Allowed only for the user who performed the
|
|
112
384
|
* last elevation or an owner.
|
|
113
385
|
*/
|
|
114
|
-
export declare function demote<T>(ctx: TiersContext<T>, id: string, toTier: number): Promise<
|
|
386
|
+
export declare function demote<T>(ctx: TiersContext<T>, id: string, toTier: number): Promise<TierMoveResult>;
|
|
115
387
|
/**
|
|
116
388
|
* Classify a live envelope's `_sealed` slots for crypto-shred completeness
|
|
117
389
|
* (#M-1). Thin delegate to {@link RecordCodec.classifySealedShred}; surfaced
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
* @internal
|
|
9
9
|
*/
|
|
10
10
|
import type { GhostRecord } from '../../kernel/types.js';
|
|
11
|
-
import type { TiersContext } from './index.js';
|
|
11
|
+
import type { TiersContext, TierMoveResult } from './index.js';
|
|
12
|
+
export type { TierMoveResult };
|
|
12
13
|
export interface TiersStrategy {
|
|
13
14
|
putAtTier<T>(ctx: TiersContext<T>, id: string, record: T, tier: number, opts?: {
|
|
14
15
|
elevation?: {
|
|
@@ -17,15 +18,15 @@ export interface TiersStrategy {
|
|
|
17
18
|
};
|
|
18
19
|
source?: string;
|
|
19
20
|
sourceTs?: string;
|
|
20
|
-
}): Promise<
|
|
21
|
+
}): Promise<TierMoveResult>;
|
|
21
22
|
getAtTier<T>(ctx: TiersContext<T>, id: string): Promise<T | GhostRecord | null>;
|
|
22
23
|
listAtTier<T>(ctx: TiersContext<T>): Promise<Array<{
|
|
23
24
|
id: string;
|
|
24
25
|
tier: number;
|
|
25
26
|
readable: boolean;
|
|
26
27
|
}>>;
|
|
27
|
-
elevate<T>(ctx: TiersContext<T>, id: string, toTier: number): Promise<
|
|
28
|
-
demote<T>(ctx: TiersContext<T>, id: string, toTier: number): Promise<
|
|
28
|
+
elevate<T>(ctx: TiersContext<T>, id: string, toTier: number): Promise<TierMoveResult>;
|
|
29
|
+
demote<T>(ctx: TiersContext<T>, id: string, toTier: number): Promise<TierMoveResult>;
|
|
29
30
|
}
|
|
30
31
|
/**
|
|
31
32
|
* No-op stub — the floor default. Every capability method throws
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* @module
|
|
8
8
|
*/
|
|
9
9
|
import type { Vault } from '../kernel/vault.js';
|
|
10
|
-
import { type WalkClosureOptions } from './walk-closure.js';
|
|
10
|
+
import { type WalkClosureOptions, type DanglingRefNotice } from './walk-closure.js';
|
|
11
11
|
export interface ExtractionPreview {
|
|
12
12
|
readonly totalRecords: number;
|
|
13
13
|
/** Sum of serialized encrypted-envelope sizes (bytes). */
|
|
@@ -29,5 +29,13 @@ export interface ExtractionPreview {
|
|
|
29
29
|
readonly collection: string;
|
|
30
30
|
readonly id: string;
|
|
31
31
|
}>;
|
|
32
|
+
/**
|
|
33
|
+
* #772: outbound FK edges whose referenced parent was excluded from the
|
|
34
|
+
* closure (missing, or tier-elevated and therefore invisible) — mirrors
|
|
35
|
+
* `ExtractPartitionResult.danglingRefs` (#759) so a preview/extract pair
|
|
36
|
+
* gives the SAME signal. A parent excluded this way never appears in
|
|
37
|
+
* `byCollection` at all; this is the only preview-time indicator.
|
|
38
|
+
*/
|
|
39
|
+
readonly danglingRefs: ReadonlyArray<DanglingRefNotice>;
|
|
32
40
|
}
|
|
33
41
|
export declare function describeExtraction(vault: Vault, opts: WalkClosureOptions): Promise<ExtractionPreview>;
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
import type { Vault } from '../kernel/vault.js';
|
|
10
10
|
import type { EncryptedEnvelope } from '../kernel/types.js';
|
|
11
11
|
import { type EnclaveKey } from '../kernel/enclave/index.js';
|
|
12
|
-
import { type WalkClosureOptions } from './walk-closure.js';
|
|
12
|
+
import { type WalkClosureOptions, type DanglingRefNotice } from './walk-closure.js';
|
|
13
13
|
import { type TransferSealPayload } from '../with-pod/bundle.js';
|
|
14
14
|
/** Re-keyed collections snapshot + the fresh DEKs used. */
|
|
15
15
|
export interface ReKeyResult {
|
|
@@ -113,6 +113,14 @@ export interface ExtractPartitionResult {
|
|
|
113
113
|
/** Raw 32-byte transfer key — deliver out-of-band; required to adopt. */
|
|
114
114
|
readonly transferKey: Uint8Array;
|
|
115
115
|
readonly sealId: string;
|
|
116
|
+
/**
|
|
117
|
+
* #759: outbound FK edges whose referenced parent was excluded from the
|
|
118
|
+
* partition (missing, or tier-elevated and therefore invisible). The
|
|
119
|
+
* child record still carries its FK value; the parent did not travel —
|
|
120
|
+
* callers should surface this to the operator rather than assume
|
|
121
|
+
* referential completeness.
|
|
122
|
+
*/
|
|
123
|
+
readonly danglingRefs: ReadonlyArray<DanglingRefNotice>;
|
|
116
124
|
}
|
|
117
125
|
/**
|
|
118
126
|
* Extract a re-keyed, transfer-sealed partition. Owner-only
|
|
@@ -8,9 +8,10 @@
|
|
|
8
8
|
* 1. INBOUND expansion: from selected records, pull every record
|
|
9
9
|
* that references them (children travel with parents), to a
|
|
10
10
|
* fixed point.
|
|
11
|
-
* 2. OUTBOUND completion: pull every parent the selected set
|
|
12
|
-
* references
|
|
13
|
-
*
|
|
11
|
+
* 2. OUTBOUND completion: pull every VISIBLE parent the selected set
|
|
12
|
+
* references, transitively, WITHOUT re-expanding inbound from those
|
|
13
|
+
* parents (bounds the closure). A tier-elevated (or missing) parent is
|
|
14
|
+
* excluded rather than admitted — see `danglingRefs` on the result.
|
|
14
15
|
*
|
|
15
16
|
* The FK graph is auto-derived from the vault's existing RefRegistry
|
|
16
17
|
* (the `ref('target')` declarations on collections) — no hand-written
|
|
@@ -25,6 +26,32 @@ export interface WalkClosureOptions {
|
|
|
25
26
|
/** Max fixed-point iterations before throwing. Default 16. */
|
|
26
27
|
readonly maxDepth?: number;
|
|
27
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* #759: an outbound FK edge whose referenced parent was excluded from the
|
|
31
|
+
* closure — either because it doesn't exist, or because it is tier-elevated
|
|
32
|
+
* and therefore invisible (same "elevated ≡ missing" semantics as root
|
|
33
|
+
* selection / inbound expansion). The child keeps its FK value; the parent
|
|
34
|
+
* does not travel. Callers (extract-partition) surface this as a residue
|
|
35
|
+
* notice rather than silently dropping it.
|
|
36
|
+
*/
|
|
37
|
+
export interface DanglingRefNotice {
|
|
38
|
+
/** Collection of the child record that holds the dangling FK. */
|
|
39
|
+
readonly collection: string;
|
|
40
|
+
/** Id of the child record. */
|
|
41
|
+
readonly id: string;
|
|
42
|
+
/** FK field on the child that references the missing/elevated parent. */
|
|
43
|
+
readonly field: string;
|
|
44
|
+
/** Target collection the FK points at. */
|
|
45
|
+
readonly target: string;
|
|
46
|
+
/** Id of the missing/elevated parent. */
|
|
47
|
+
readonly targetId: string;
|
|
48
|
+
/**
|
|
49
|
+
* #772: distinguishes an intentional tier boundary (`'elevated'` — the
|
|
50
|
+
* parent exists but is above the caller's readable tier) from a genuine
|
|
51
|
+
* data-integrity gap (`'missing'` — no envelope for `targetId` at all).
|
|
52
|
+
*/
|
|
53
|
+
readonly reason: 'missing' | 'elevated';
|
|
54
|
+
}
|
|
28
55
|
export interface ClosureResult {
|
|
29
56
|
/** collection → set of record ids that travel together. */
|
|
30
57
|
readonly closure: Map<string, Set<string>>;
|
|
@@ -34,5 +61,7 @@ export interface ClosureResult {
|
|
|
34
61
|
/** True if an edge pointed back to an already-selected node. */
|
|
35
62
|
readonly cyclesDetected: boolean;
|
|
36
63
|
};
|
|
64
|
+
/** #759: outbound FK edges whose parent was excluded (missing or elevated). */
|
|
65
|
+
readonly danglingRefs: ReadonlyArray<DanglingRefNotice>;
|
|
37
66
|
}
|
|
38
67
|
export declare function walkClosure(vault: Vault, opts: WalkClosureOptions): Promise<ClosureResult>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { NoydbStore, EncryptedEnvelope, HistoryOptions, PruneOptions } from '../../kernel/types.js';
|
|
2
|
+
import { type EnclaveKey } from '../../kernel/enclave/index.js';
|
|
2
3
|
/** Save a history entry (a complete encrypted envelope snapshot). */
|
|
3
4
|
export declare function saveHistory(adapter: NoydbStore, vault: string, collection: string, recordId: string, envelope: EncryptedEnvelope): Promise<void>;
|
|
4
5
|
/** Get history entries for a record, sorted newest-first. */
|
|
@@ -25,3 +26,48 @@ export declare function clearHistory(adapter: NoydbStore, vault: string, collect
|
|
|
25
26
|
* Returns the number of history versions newly tombstoned.
|
|
26
27
|
*/
|
|
27
28
|
export declare function tombstoneHistory(adapter: NoydbStore, vault: string, collection: string, recordId: string, actor: string, encrypted: boolean): Promise<number>;
|
|
29
|
+
/**
|
|
30
|
+
* Re-key every `_history` snapshot of a record from `fromDek` to `toDek`.
|
|
31
|
+
* Mirrors what `rewrapBodyToDek` already does for a record's LIVE body on a
|
|
32
|
+
* tier move (elevate/demote/putAtTier) — each `_history` envelope also
|
|
33
|
+
* carries its own `_cek`, wrapped under the collection's tier-0 DEK at write
|
|
34
|
+
* time (`record-codec.ts`), so a tier move that rewraps only the live
|
|
35
|
+
* envelope leaves prior versions decryptable at rest under the tier the
|
|
36
|
+
* record left. This is defense-in-depth *beneath* the read-gate
|
|
37
|
+
* (`history()`/`getVersion()` already return empty for an elevated record;
|
|
38
|
+
* this protects the ciphertext even if that gate is bypassed).
|
|
39
|
+
*
|
|
40
|
+
* Rewraps content in place — unlike `tombstoneHistory`, it does NOT blank
|
|
41
|
+
* `_iv`/`_data`/`_cek` — so a subsequent `demote()` restores tier-0
|
|
42
|
+
* readability. Tombstone-shaped entries (a forgotten/shredded version —
|
|
43
|
+
* blanked `_data`, no `_cek`) are skipped: there is no key material left to
|
|
44
|
+
* rewrap.
|
|
45
|
+
*
|
|
46
|
+
* **Legacy fallback.** A snapshot written before this fix stays wrapped
|
|
47
|
+
* under the tier-0 DEK even after its live record has since moved tiers, so
|
|
48
|
+
* a rewrap attempted with a tier-N `fromDek` fails to unwrap/decrypt. When
|
|
49
|
+
* the caller supplies `tier0Dek`, a failed rewrap is retried once with
|
|
50
|
+
* `tier0Dek` as `fromDek` (the only other key a pre-fix snapshot can be
|
|
51
|
+
* wrapped under — history is written only by tier-0 `put()`). The output is
|
|
52
|
+
* always wrapped under `toDek` regardless of which `fromDek` succeeded. A
|
|
53
|
+
* rewrap that fails under BOTH keys re-throws — that is real corruption, not
|
|
54
|
+
* a tier mismatch, and must not be swallowed.
|
|
55
|
+
*
|
|
56
|
+
* **Crash-atomicity / idempotency (#712 whole-branch-fix-3).** This loop has
|
|
57
|
+
* no transaction around it: a crash after some entries have been rewritten
|
|
58
|
+
* under `toDek` but before the loop finishes leaves the record's history
|
|
59
|
+
* split across two keys. A retry of the SAME call must not re-fail on the
|
|
60
|
+
* entries that already made it — so each entry is probed with
|
|
61
|
+
* `isRewrappedUnder(env, toDek)` FIRST; a match means it's already at the
|
|
62
|
+
* target key and is skipped (put nothing). This makes same-target retries
|
|
63
|
+
* and demote-after-crash fully self-healing. It does NOT close every crash
|
|
64
|
+
* window: a crash that lands SOME entries under `toDek` while the record's
|
|
65
|
+
* NEXT move target differs from this call's `toDek` (an intermediate-tier
|
|
66
|
+
* crash — e.g. elevate 0→1 crashes mid-loop, then the record is moved 1→2)
|
|
67
|
+
* still finds those entries unreadable under either `fromDek` or the
|
|
68
|
+
* tier-0 fallback, since `toDek` is a third key the next call never probes
|
|
69
|
+
* for. That residual window is an accepted, fail-closed limitation (see
|
|
70
|
+
* `.changeset/history-at-rest.md` and the design doc) — availability is
|
|
71
|
+
* lost, never confidentiality.
|
|
72
|
+
*/
|
|
73
|
+
export declare function rewrapHistory(adapter: NoydbStore, vault: string, collection: string, recordId: string, fromDek: EnclaveKey, toDek: EnclaveKey, tier0Dek?: EnclaveKey): Promise<void>;
|