@noy-db/hub 0.6.0-pre.2 → 0.6.0-pre.20
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/codemods/0.4.0-pre.json +699 -0
- package/codemods/0.6.0-pre.json +211 -0
- package/dist/api-Z5VHH24A.js +20 -0
- package/dist/attestation/index.js +19 -19
- package/dist/{backup-YYBE5RPC.js → backup-K62BFMYK.js} +36 -18
- package/dist/backup-K62BFMYK.js.map +1 -0
- package/dist/blobs/index.js +13 -13
- package/dist/broker/index.js +12 -12
- package/dist/cargo/index.js +33 -33
- package/dist/{chunk-FDX7OWWI.js → chunk-2E2MKBMI.js} +2 -2
- package/dist/{chunk-VOQW5LAM.js → chunk-2IK6AC6A.js} +102 -71
- package/dist/chunk-2IK6AC6A.js.map +1 -0
- package/dist/{chunk-EDXAQ6JI.js → chunk-32O2N2CH.js} +87 -34
- package/dist/chunk-32O2N2CH.js.map +1 -0
- package/dist/{chunk-W5W6KHN2.js → chunk-3Y4OFWQJ.js} +1 -1
- package/dist/chunk-3Y4OFWQJ.js.map +1 -0
- package/dist/{chunk-7G6VDWXB.js → chunk-437FDIHO.js} +3 -3
- package/dist/chunk-437FDIHO.js.map +1 -0
- package/dist/{chunk-3FSX6LDG.js → chunk-47ZFULEZ.js} +8 -3
- package/dist/{chunk-3FSX6LDG.js.map → chunk-47ZFULEZ.js.map} +1 -1
- package/dist/{chunk-ZJADGNYF.js → chunk-4AOERLTV.js} +1 -1
- package/dist/chunk-4AOERLTV.js.map +1 -0
- package/dist/{chunk-MWKDOHEF.js → chunk-4HVTRHSA.js} +17 -10
- package/dist/chunk-4HVTRHSA.js.map +1 -0
- package/dist/{chunk-V5KYPBUR.js → chunk-5BS6IQZZ.js} +11 -14
- package/dist/chunk-5BS6IQZZ.js.map +1 -0
- package/dist/{chunk-LWSJG3LI.js → chunk-5EJQNA26.js} +7 -3
- package/dist/chunk-5EJQNA26.js.map +1 -0
- package/dist/{chunk-7F4DBNSP.js → chunk-5J5TTSGW.js} +3 -3
- package/dist/{chunk-BTVYJWSN.js → chunk-5JT4Y5UE.js} +10 -10
- package/dist/{chunk-C2OOEM57.js → chunk-6S466CMQ.js} +92 -35
- package/dist/chunk-6S466CMQ.js.map +1 -0
- package/dist/{chunk-PY7CI6L5.js → chunk-6TXUVKPG.js} +516 -263
- package/dist/chunk-6TXUVKPG.js.map +1 -0
- package/dist/{chunk-7NXHMW6Y.js → chunk-7RCZ436O.js} +2 -2
- package/dist/{chunk-DG27IUVI.js → chunk-A3NTKHDB.js} +2 -2
- package/dist/{chunk-CCZJJ4I2.js → chunk-A4K5GLE6.js} +4 -4
- package/dist/{chunk-CEJWMBXO.js → chunk-APV42WPR.js} +2 -2
- package/dist/{chunk-4HDYQL3J.js → chunk-AQF7JSQR.js} +2 -2
- package/dist/{chunk-KUDZVJKQ.js → chunk-BP4I7IBK.js} +2 -2
- package/dist/{chunk-4UVDI4XE.js → chunk-BTNKPDZM.js} +4 -4
- package/dist/{chunk-HVQGCKY4.js → chunk-C7WJNVJG.js} +2 -2
- package/dist/{chunk-WYZ5MYUA.js → chunk-CV7WXCZD.js} +44 -42
- package/dist/chunk-CV7WXCZD.js.map +1 -0
- package/dist/{chunk-KCQX65FU.js → chunk-CVYXIN5B.js} +3 -3
- package/dist/{chunk-VN45YLWM.js → chunk-D5UDZANO.js} +255 -132
- package/dist/chunk-D5UDZANO.js.map +1 -0
- package/dist/{chunk-AR2JDFAE.js → chunk-DJ23QZIN.js} +2 -2
- package/dist/{chunk-PJNTR2NV.js → chunk-DKYEVHZH.js} +7 -10
- package/dist/chunk-DKYEVHZH.js.map +1 -0
- package/dist/{chunk-SZ2K3MHL.js → chunk-DYASJSKI.js} +8 -11
- package/dist/{chunk-SZ2K3MHL.js.map → chunk-DYASJSKI.js.map} +1 -1
- package/dist/{chunk-G5APARUV.js → chunk-E6VDPBE3.js} +13 -15
- package/dist/chunk-E6VDPBE3.js.map +1 -0
- package/dist/{chunk-A67356IR.js → chunk-EG6AQBYW.js} +33 -8
- package/dist/chunk-EG6AQBYW.js.map +1 -0
- package/dist/{chunk-PVU7LW5L.js → chunk-EJIVFOOQ.js} +6 -6
- package/dist/{chunk-VRA4Q7DA.js → chunk-F5AJZC3U.js} +35 -47
- package/dist/chunk-F5AJZC3U.js.map +1 -0
- package/dist/{chunk-VMCCGUQB.js → chunk-GDGTIWB4.js} +2 -2
- package/dist/{chunk-FUHKW252.js → chunk-GILI76SU.js} +2 -2
- package/dist/{chunk-35EBKWQU.js → chunk-GT72D4FO.js} +4 -4
- package/dist/{chunk-PRDRGL73.js → chunk-GYUCRDAU.js} +17 -14
- package/dist/chunk-GYUCRDAU.js.map +1 -0
- package/dist/{chunk-JRCYZEHU.js → chunk-HGJC7I5F.js} +2 -2
- package/dist/{chunk-TOAIYQJR.js → chunk-HJRTFXAA.js} +7 -10
- package/dist/chunk-HJRTFXAA.js.map +1 -0
- package/dist/chunk-HK67PX4J.js +27 -0
- package/dist/chunk-HK67PX4J.js.map +1 -0
- package/dist/{chunk-JXIDGFKS.js → chunk-HTHRCGWP.js} +4 -2
- package/dist/chunk-HTHRCGWP.js.map +1 -0
- package/dist/{chunk-AHLJSVRL.js → chunk-HTMQBBF3.js} +5 -7
- package/dist/chunk-HTMQBBF3.js.map +1 -0
- package/dist/{chunk-ZNACADFG.js → chunk-ICCRAPWD.js} +4 -4
- package/dist/chunk-ICCRAPWD.js.map +1 -0
- package/dist/{chunk-66W5OOCX.js → chunk-IOURTXTM.js} +52 -65
- package/dist/chunk-IOURTXTM.js.map +1 -0
- package/dist/{chunk-MZ5ZFO2D.js → chunk-IPDS2TYW.js} +84 -112
- package/dist/chunk-IPDS2TYW.js.map +1 -0
- package/dist/{chunk-UIBGXRDD.js → chunk-JHO6FGZX.js} +25 -31
- package/dist/chunk-JHO6FGZX.js.map +1 -0
- package/dist/{chunk-YAWK6AWF.js → chunk-JIF3IBRK.js} +2 -2
- package/dist/{chunk-HNHCQ556.js → chunk-KBOPY6W2.js} +2 -2
- package/dist/{chunk-UHXCLPGC.js → chunk-KDX6VEYV.js} +2 -2
- package/dist/chunk-KDX6VEYV.js.map +1 -0
- package/dist/{chunk-W3TVWF6N.js → chunk-KM6YR5XF.js} +2 -2
- package/dist/{chunk-3737A6EA.js → chunk-KUXTWVAR.js} +75 -18
- package/dist/chunk-KUXTWVAR.js.map +1 -0
- package/dist/chunk-L2XQ776M.js +123 -0
- package/dist/chunk-L2XQ776M.js.map +1 -0
- package/dist/{chunk-E6427JU2.js → chunk-L6FSZFG7.js} +18 -2
- package/dist/chunk-L6FSZFG7.js.map +1 -0
- package/dist/{chunk-5PR33AC4.js → chunk-M4IKEOJS.js} +20 -17
- package/dist/chunk-M4IKEOJS.js.map +1 -0
- package/dist/{chunk-6HFM7EIT.js → chunk-MNMYHZVU.js} +2 -2
- package/dist/{chunk-NIVEDYJZ.js → chunk-MNUTPZRQ.js} +31 -49
- package/dist/chunk-MNUTPZRQ.js.map +1 -0
- package/dist/{chunk-VV4NSB7P.js → chunk-MQXYR65M.js} +15 -24
- package/dist/chunk-MQXYR65M.js.map +1 -0
- package/dist/{chunk-QD724WDJ.js → chunk-N2HKBESK.js} +4 -4
- package/dist/{chunk-Z45YRGFO.js → chunk-N7YAQKAO.js} +2 -2
- package/dist/{chunk-DMQCLZ4Z.js → chunk-NH2MST6J.js} +2 -2
- package/dist/{chunk-TAGFGKHP.js → chunk-NRNTXBHT.js} +7 -10
- package/dist/chunk-NRNTXBHT.js.map +1 -0
- package/dist/{chunk-I6SDX7WX.js → chunk-NYSD43OE.js} +16 -22
- package/dist/chunk-NYSD43OE.js.map +1 -0
- package/dist/{chunk-I4F6PKUK.js → chunk-ODVIFBAQ.js} +16 -17
- package/dist/chunk-ODVIFBAQ.js.map +1 -0
- package/dist/{chunk-26JMGSSC.js → chunk-OIIAXFKM.js} +4 -4
- package/dist/chunk-OIIAXFKM.js.map +1 -0
- package/dist/{chunk-HXGUIPQB.js → chunk-OQLYMBJI.js} +3 -3
- package/dist/{chunk-RKKORO4M.js → chunk-OWGEHDT2.js} +10 -10
- package/dist/chunk-OWGEHDT2.js.map +1 -0
- package/dist/{chunk-HNGSV2YC.js → chunk-P7L3OQLL.js} +25 -10
- package/dist/chunk-P7L3OQLL.js.map +1 -0
- package/dist/{chunk-MSWYQLMQ.js → chunk-PG6PFMDC.js} +2 -2
- package/dist/{chunk-E7OBCBXS.js → chunk-PNAIDIP7.js} +13 -16
- package/dist/chunk-PNAIDIP7.js.map +1 -0
- package/dist/{chunk-GLKDWWNO.js → chunk-PZSS7MUM.js} +16 -14
- package/dist/chunk-PZSS7MUM.js.map +1 -0
- package/dist/{chunk-WKPJXWKR.js → chunk-QPIUFRUC.js} +3 -3
- package/dist/{chunk-JIUVJ4M7.js → chunk-REL4OLWW.js} +2 -2
- package/dist/{chunk-ERB6NDDW.js → chunk-RKDH6L53.js} +134 -33
- package/dist/chunk-RKDH6L53.js.map +1 -0
- package/dist/{chunk-VW6ZZGCG.js → chunk-RNSC2ARR.js} +3 -3
- package/dist/{chunk-WLYIROCJ.js → chunk-RORE2GX2.js} +2 -2
- package/dist/{chunk-TDJPS3T2.js → chunk-RQY5UWEL.js} +24 -19
- package/dist/chunk-RQY5UWEL.js.map +1 -0
- package/dist/{chunk-7TSYBD3E.js → chunk-RSFG7XHM.js} +2 -2
- package/dist/{chunk-FAXZQ5UF.js → chunk-S55DBWRC.js} +2 -2
- package/dist/{chunk-WHJKIZS7.js → chunk-SA77BQ7F.js} +27 -149
- package/dist/chunk-SA77BQ7F.js.map +1 -0
- package/dist/{chunk-747LRSOO.js → chunk-SFD2LL7G.js} +2 -2
- package/dist/{chunk-P7OG2ETF.js → chunk-SG3OQCRG.js} +3 -3
- package/dist/{chunk-55LKVALY.js → chunk-T7IR4N2S.js} +1 -3
- package/dist/chunk-T7IR4N2S.js.map +1 -0
- package/dist/{chunk-EP7VPR7Y.js → chunk-TC6MBEGH.js} +11 -8
- package/dist/chunk-TC6MBEGH.js.map +1 -0
- package/dist/{chunk-HFQ6LGIO.js → chunk-TENLCGYD.js} +12 -10
- package/dist/{chunk-HFQ6LGIO.js.map → chunk-TENLCGYD.js.map} +1 -1
- package/dist/{chunk-WQDTCJ6W.js → chunk-VEX2BQVX.js} +3 -3
- package/dist/{chunk-7VHY5E3X.js → chunk-VH2W6BOG.js} +7 -7
- package/dist/chunk-VHVMJWM6.js +201 -0
- package/dist/chunk-VHVMJWM6.js.map +1 -0
- package/dist/{chunk-VCETL77O.js → chunk-VJ4B3ZXY.js} +27 -7
- package/dist/chunk-VJ4B3ZXY.js.map +1 -0
- package/dist/{chunk-OF3L2SD6.js → chunk-W6NFONOV.js} +2 -2
- package/dist/{chunk-NJDQ4YSV.js → chunk-WBNXZU42.js} +4 -4
- package/dist/{chunk-FNSMZQS4.js → chunk-WKD5ESK4.js} +2 -2
- package/dist/{chunk-NKH7GSIH.js → chunk-XGQGWZ6D.js} +4 -4
- package/dist/chunk-YOT7D63X.js +190 -0
- package/dist/chunk-YOT7D63X.js.map +1 -0
- package/dist/{chunk-4MC5JRRX.js → chunk-YVTADFTC.js} +14 -15
- package/dist/chunk-YVTADFTC.js.map +1 -0
- package/dist/{chunk-GASWQ3XG.js → chunk-ZBDWKPBW.js} +15 -16
- package/dist/chunk-ZBDWKPBW.js.map +1 -0
- package/dist/{chunk-52QYGZHH.js → chunk-ZPMXYPBR.js} +2 -2
- package/dist/chunk-ZPMXYPBR.js.map +1 -0
- package/dist/chunk-ZVAFJQZB.js +66 -0
- package/dist/chunk-ZVAFJQZB.js.map +1 -0
- package/dist/{chunk-VJFMXYKP.js → chunk-ZWKF3CD3.js} +2 -2
- package/dist/{chunk-I4ZAO7F7.js → chunk-ZXW3X3DQ.js} +7 -11
- package/dist/chunk-ZXW3X3DQ.js.map +1 -0
- package/dist/classified/index.js +5 -5
- package/dist/{classified-marker-FTOX7Q5L.js → classified-marker-PMDG3O36.js} +3 -3
- package/dist/collection-facade-ZJK5EB33.js +45 -0
- package/dist/{computed-6G5M3UPH.js → computed-UHCBRILW.js} +3 -3
- package/dist/consent/index.js +10 -10
- package/dist/cover/index.js +10 -3
- package/dist/custody/index.js +11 -11
- package/dist/{dead-filter-ENRIOQIE.js → dead-filter-777VWDER.js} +2 -2
- package/dist/debug/index.js +1 -1
- package/dist/{delegation-SSEPLXXO.js → delegation-4R5DU23X.js} +24 -23
- package/dist/delegation-4R5DU23X.js.map +1 -0
- package/dist/derivations/index.js +12 -12
- package/dist/derive-3WAS2G5T.js +22 -0
- package/dist/directory/index.js +10 -10
- package/dist/{dispatch-BDVGYC6X.js → dispatch-3EN6YCCS.js} +18 -18
- package/dist/{dispatch-RE74SH6L.js → dispatch-ASL257KG.js} +5 -5
- package/dist/{enclave-52VUXNRL.js → enclave-ZJS5R5RH.js} +25 -9
- package/dist/executor-GPM6DNWV.js +9 -0
- package/dist/executor-LJSMZ4IB.js +9 -0
- package/dist/executor-SHUVRZUJ.js +29 -0
- package/dist/export-accessible-GNY6DC6U.js +23 -0
- package/dist/extract-partition-BG3AF4NZ.js +38 -0
- package/dist/{fanout-sidecar-DTBIDOWF.js → fanout-sidecar-TFPWDOME.js} +18 -27
- package/dist/fanout-sidecar-TFPWDOME.js.map +1 -0
- package/dist/find-KX6OKHDP.js +11 -0
- package/dist/forget/index.js +9 -9
- package/dist/guards/index.js +4 -4
- 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 +32 -15
- package/dist/index.js +183 -191
- package/dist/index.js.map +1 -1
- package/dist/indexing/index.js +2 -2
- package/dist/introspection/index.js +11 -11
- package/dist/issue-PAUM7NCX.js +19 -0
- package/dist/kernel/enclave/crypto.d.ts +24 -4
- package/dist/kernel/enclave/index.d.ts +8 -2
- 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.d.ts +68 -0
- package/dist/kernel/enclave/record-keys/tombstone.d.ts +3 -2
- package/dist/kernel/errors.d.ts +23 -11
- package/dist/kernel/merge-authority.d.ts +25 -0
- package/dist/kernel/noydb.d.ts +9 -3
- package/dist/kernel/query/builder.d.ts +15 -2
- package/dist/kernel/query/join.d.ts +27 -0
- package/dist/kernel/sync-policy.d.ts +0 -2
- package/dist/kernel/tier-visibility.d.ts +15 -0
- package/dist/kernel/types.d.ts +125 -6
- package/dist/kernel/vault.d.ts +21 -17
- package/dist/kernel/via/index.d.ts +11 -2
- package/dist/{ledger-4WJL66BW.js → ledger-62CEPRPX.js} +11 -11
- package/dist/liberate-I6AOLWXW.js +24 -0
- package/dist/{link-set-N4ZPV6E6.js → link-set-ZRYNUHN3.js} +11 -11
- package/dist/{managed-secret-OTHS64IF.js → managed-secret-T2WB4O47.js} +11 -3
- package/dist/materialized-views/index.js +22 -21
- package/dist/money/index.js +12 -8
- package/dist/noydb-SS6EN7TK.js +84 -0
- package/dist/overlay-views/index.js +4 -4
- package/dist/periods/index.js +22 -12
- package/dist/pod/index.js +75 -86
- package/dist/pod-handle-UPLXOGIK.js +41 -0
- package/dist/pod-handle-UPLXOGIK.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/portability/index.js +8 -8
- package/dist/{post-register-ZAG2CAIY.js → post-register-J4DEVNXK.js} +6 -6
- package/dist/query/index.js +3 -3
- package/dist/reduce/index.js +4 -4
- package/dist/register-UPD4GKBC.js +32 -0
- package/dist/registry-7KX2HWFS.js +18 -0
- package/dist/registry-PKYYEHEW.js +9 -0
- package/dist/registry-XHCYMD34.js +19 -0
- package/dist/registry-XIRTZHPC.js +9 -0
- package/dist/request-withdrawal-XZSESWZV.js +31 -0
- package/dist/{reveal-CMOJY4VO.js → reveal-525XWQU2.js} +6 -6
- package/dist/revoke-QI7YHQ2B.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-UK4QRIUN.js → seed-SGIF3EN4.js} +19 -22
- package/dist/seed-SGIF3EN4.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-BZWDPGGN.js +25 -0
- package/dist/snapshots/index.js +10 -10
- package/dist/snapshots/index.js.map +1 -1
- package/dist/{stale-ZWXSOWJI.js → stale-PQYPVCER.js} +10 -10
- package/dist/storage-MJHKNQRO.js +23 -0
- package/dist/{store-coordination-provider-PB6QZ57W.js → store-coordination-provider-TFHZLKHG.js} +18 -12
- package/dist/store-coordination-provider-TFHZLKHG.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-J6DEOXP3.js} +5 -5
- package/dist/via/lookup/handle.d.ts +4 -1
- package/dist/via/money/exact.d.ts +44 -0
- package/dist/via/money/index.d.ts +2 -0
- package/dist/via/money/normalize.d.ts +20 -0
- package/dist/walk-BX4NSB5L.js +21 -0
- package/dist/with-audit/guards/immutable-guard.d.ts +14 -0
- package/dist/with-audit/periods/active.d.ts +28 -1
- package/dist/with-audit/periods/index.d.ts +4 -2
- package/dist/with-audit/periods/periods.d.ts +161 -6
- package/dist/with-audit/periods/strategy.d.ts +14 -5
- package/dist/with-audit/periods/vault-facade.d.ts +89 -10
- 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 +2 -2
- 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/types.d.ts +52 -0
- 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 +17 -3
- 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} +26 -19
- package/dist/with-pod/ulid.d.ts +1 -1
- 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-K4CPMH4C.js +28 -0
- package/package.json +12 -5
- package/dist/api-WVY3H3YH.js +0 -20
- package/dist/backup-YYBE5RPC.js.map +0 -1
- package/dist/bundle-handle-JEUWU2SJ.js +0 -36
- package/dist/bundle-handle-JEUWU2SJ.js.map +0 -1
- package/dist/chunk-26JMGSSC.js.map +0 -1
- package/dist/chunk-3737A6EA.js.map +0 -1
- package/dist/chunk-4MC5JRRX.js.map +0 -1
- package/dist/chunk-52QYGZHH.js.map +0 -1
- package/dist/chunk-55LKVALY.js.map +0 -1
- package/dist/chunk-5PR33AC4.js.map +0 -1
- package/dist/chunk-66W5OOCX.js.map +0 -1
- package/dist/chunk-7G6VDWXB.js.map +0 -1
- package/dist/chunk-A67356IR.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-C2OOEM57.js.map +0 -1
- package/dist/chunk-DIMKRG2E.js +0 -131
- package/dist/chunk-DIMKRG2E.js.map +0 -1
- package/dist/chunk-E6427JU2.js.map +0 -1
- package/dist/chunk-E7OBCBXS.js.map +0 -1
- package/dist/chunk-EDXAQ6JI.js.map +0 -1
- package/dist/chunk-EP7VPR7Y.js.map +0 -1
- package/dist/chunk-ERB6NDDW.js.map +0 -1
- package/dist/chunk-G5APARUV.js.map +0 -1
- package/dist/chunk-GASWQ3XG.js.map +0 -1
- package/dist/chunk-GLKDWWNO.js.map +0 -1
- package/dist/chunk-HNGSV2YC.js.map +0 -1
- package/dist/chunk-I4F6PKUK.js.map +0 -1
- package/dist/chunk-I4ZAO7F7.js.map +0 -1
- package/dist/chunk-I6SDX7WX.js.map +0 -1
- package/dist/chunk-JXIDGFKS.js.map +0 -1
- package/dist/chunk-LWSJG3LI.js.map +0 -1
- package/dist/chunk-MWKDOHEF.js.map +0 -1
- package/dist/chunk-MZ5ZFO2D.js.map +0 -1
- package/dist/chunk-NIVEDYJZ.js.map +0 -1
- package/dist/chunk-NWCGDAV6.js +0 -45
- package/dist/chunk-NWCGDAV6.js.map +0 -1
- package/dist/chunk-PJNTR2NV.js.map +0 -1
- package/dist/chunk-PRDRGL73.js.map +0 -1
- package/dist/chunk-PY7CI6L5.js.map +0 -1
- package/dist/chunk-RKKORO4M.js.map +0 -1
- package/dist/chunk-TAGFGKHP.js.map +0 -1
- package/dist/chunk-TDJPS3T2.js.map +0 -1
- package/dist/chunk-TOAIYQJR.js.map +0 -1
- package/dist/chunk-UHXCLPGC.js.map +0 -1
- package/dist/chunk-UIBGXRDD.js.map +0 -1
- package/dist/chunk-V5KYPBUR.js.map +0 -1
- package/dist/chunk-VCETL77O.js.map +0 -1
- package/dist/chunk-VN45YLWM.js.map +0 -1
- package/dist/chunk-VOQW5LAM.js.map +0 -1
- package/dist/chunk-VRA4Q7DA.js.map +0 -1
- package/dist/chunk-VV4NSB7P.js.map +0 -1
- package/dist/chunk-W5W6KHN2.js.map +0 -1
- package/dist/chunk-WHJKIZS7.js.map +0 -1
- package/dist/chunk-WYZ5MYUA.js.map +0 -1
- package/dist/chunk-ZJADGNYF.js.map +0 -1
- package/dist/chunk-ZNACADFG.js.map +0 -1
- package/dist/collection-facade-QN5ULWYC.js +0 -45
- package/dist/delegation-SSEPLXXO.js.map +0 -1
- package/dist/derive-6V3PIZF7.js +0 -22
- package/dist/executor-CYJQLKKI.js +0 -9
- package/dist/executor-FHHLXO4Y.js +0 -28
- package/dist/executor-S4QIKEHW.js +0 -9
- package/dist/export-accessible-PE5AYKZR.js +0 -23
- package/dist/extract-partition-X2L26O6A.js +0 -38
- package/dist/fanout-sidecar-DTBIDOWF.js.map +0 -1
- package/dist/find-RBBYKXI7.js +0 -11
- package/dist/issue-RNU55YOF.js +0 -19
- package/dist/liberate-PX4CAT5V.js +0 -24
- package/dist/noydb-YPSEGK32.js +0 -83
- package/dist/register-TMD6YRCX.js +0 -32
- package/dist/registry-CZVINVQH.js +0 -9
- package/dist/registry-FVLDWQKT.js +0 -18
- package/dist/registry-IKUR2MXD.js +0 -9
- package/dist/registry-JET4HBLY.js +0 -19
- package/dist/request-withdrawal-RH55LNZL.js +0 -31
- package/dist/revoke-R5TBYVA6.js +0 -24
- package/dist/seed-UK4QRIUN.js.map +0 -1
- package/dist/signer-AGALOXOO.js +0 -25
- package/dist/storage-N7LB275C.js +0 -23
- package/dist/store-coordination-provider-PB6QZ57W.js.map +0 -1
- package/dist/walk-OCUHCYJ6.js +0 -21
- package/dist/with-pod/bundle-handle.d.ts +0 -9
- package/dist/withdraw-accessible-QQNWM5BO.js +0 -28
- /package/dist/{api-WVY3H3YH.js.map → api-Z5VHH24A.js.map} +0 -0
- /package/dist/{chunk-FDX7OWWI.js.map → chunk-2E2MKBMI.js.map} +0 -0
- /package/dist/{chunk-7F4DBNSP.js.map → chunk-5J5TTSGW.js.map} +0 -0
- /package/dist/{chunk-BTVYJWSN.js.map → chunk-5JT4Y5UE.js.map} +0 -0
- /package/dist/{chunk-7NXHMW6Y.js.map → chunk-7RCZ436O.js.map} +0 -0
- /package/dist/{chunk-DG27IUVI.js.map → chunk-A3NTKHDB.js.map} +0 -0
- /package/dist/{chunk-CCZJJ4I2.js.map → chunk-A4K5GLE6.js.map} +0 -0
- /package/dist/{chunk-CEJWMBXO.js.map → chunk-APV42WPR.js.map} +0 -0
- /package/dist/{chunk-4HDYQL3J.js.map → chunk-AQF7JSQR.js.map} +0 -0
- /package/dist/{chunk-KUDZVJKQ.js.map → chunk-BP4I7IBK.js.map} +0 -0
- /package/dist/{chunk-4UVDI4XE.js.map → chunk-BTNKPDZM.js.map} +0 -0
- /package/dist/{chunk-HVQGCKY4.js.map → chunk-C7WJNVJG.js.map} +0 -0
- /package/dist/{chunk-KCQX65FU.js.map → chunk-CVYXIN5B.js.map} +0 -0
- /package/dist/{chunk-AR2JDFAE.js.map → chunk-DJ23QZIN.js.map} +0 -0
- /package/dist/{chunk-PVU7LW5L.js.map → chunk-EJIVFOOQ.js.map} +0 -0
- /package/dist/{chunk-VMCCGUQB.js.map → chunk-GDGTIWB4.js.map} +0 -0
- /package/dist/{chunk-FUHKW252.js.map → chunk-GILI76SU.js.map} +0 -0
- /package/dist/{chunk-35EBKWQU.js.map → chunk-GT72D4FO.js.map} +0 -0
- /package/dist/{chunk-JRCYZEHU.js.map → chunk-HGJC7I5F.js.map} +0 -0
- /package/dist/{chunk-YAWK6AWF.js.map → chunk-JIF3IBRK.js.map} +0 -0
- /package/dist/{chunk-HNHCQ556.js.map → chunk-KBOPY6W2.js.map} +0 -0
- /package/dist/{chunk-W3TVWF6N.js.map → chunk-KM6YR5XF.js.map} +0 -0
- /package/dist/{chunk-6HFM7EIT.js.map → chunk-MNMYHZVU.js.map} +0 -0
- /package/dist/{chunk-QD724WDJ.js.map → chunk-N2HKBESK.js.map} +0 -0
- /package/dist/{chunk-Z45YRGFO.js.map → chunk-N7YAQKAO.js.map} +0 -0
- /package/dist/{chunk-DMQCLZ4Z.js.map → chunk-NH2MST6J.js.map} +0 -0
- /package/dist/{chunk-HXGUIPQB.js.map → chunk-OQLYMBJI.js.map} +0 -0
- /package/dist/{chunk-MSWYQLMQ.js.map → chunk-PG6PFMDC.js.map} +0 -0
- /package/dist/{chunk-WKPJXWKR.js.map → chunk-QPIUFRUC.js.map} +0 -0
- /package/dist/{chunk-JIUVJ4M7.js.map → chunk-REL4OLWW.js.map} +0 -0
- /package/dist/{chunk-VW6ZZGCG.js.map → chunk-RNSC2ARR.js.map} +0 -0
- /package/dist/{chunk-WLYIROCJ.js.map → chunk-RORE2GX2.js.map} +0 -0
- /package/dist/{chunk-7TSYBD3E.js.map → chunk-RSFG7XHM.js.map} +0 -0
- /package/dist/{chunk-FAXZQ5UF.js.map → chunk-S55DBWRC.js.map} +0 -0
- /package/dist/{chunk-747LRSOO.js.map → chunk-SFD2LL7G.js.map} +0 -0
- /package/dist/{chunk-P7OG2ETF.js.map → chunk-SG3OQCRG.js.map} +0 -0
- /package/dist/{chunk-WQDTCJ6W.js.map → chunk-VEX2BQVX.js.map} +0 -0
- /package/dist/{chunk-7VHY5E3X.js.map → chunk-VH2W6BOG.js.map} +0 -0
- /package/dist/{chunk-OF3L2SD6.js.map → chunk-W6NFONOV.js.map} +0 -0
- /package/dist/{chunk-NJDQ4YSV.js.map → chunk-WBNXZU42.js.map} +0 -0
- /package/dist/{chunk-FNSMZQS4.js.map → chunk-WKD5ESK4.js.map} +0 -0
- /package/dist/{chunk-NKH7GSIH.js.map → chunk-XGQGWZ6D.js.map} +0 -0
- /package/dist/{chunk-VJFMXYKP.js.map → chunk-ZWKF3CD3.js.map} +0 -0
- /package/dist/{classified-marker-FTOX7Q5L.js.map → classified-marker-PMDG3O36.js.map} +0 -0
- /package/dist/{collection-facade-QN5ULWYC.js.map → collection-facade-ZJK5EB33.js.map} +0 -0
- /package/dist/{computed-6G5M3UPH.js.map → computed-UHCBRILW.js.map} +0 -0
- /package/dist/{dead-filter-ENRIOQIE.js.map → dead-filter-777VWDER.js.map} +0 -0
- /package/dist/{derive-6V3PIZF7.js.map → derive-3WAS2G5T.js.map} +0 -0
- /package/dist/{dispatch-BDVGYC6X.js.map → dispatch-3EN6YCCS.js.map} +0 -0
- /package/dist/{dispatch-RE74SH6L.js.map → dispatch-ASL257KG.js.map} +0 -0
- /package/dist/{enclave-52VUXNRL.js.map → enclave-ZJS5R5RH.js.map} +0 -0
- /package/dist/{executor-CYJQLKKI.js.map → executor-GPM6DNWV.js.map} +0 -0
- /package/dist/{executor-FHHLXO4Y.js.map → executor-LJSMZ4IB.js.map} +0 -0
- /package/dist/{executor-S4QIKEHW.js.map → executor-SHUVRZUJ.js.map} +0 -0
- /package/dist/{export-accessible-PE5AYKZR.js.map → export-accessible-GNY6DC6U.js.map} +0 -0
- /package/dist/{extract-partition-X2L26O6A.js.map → extract-partition-BG3AF4NZ.js.map} +0 -0
- /package/dist/{find-RBBYKXI7.js.map → find-KX6OKHDP.js.map} +0 -0
- /package/dist/{issue-RNU55YOF.js.map → issue-PAUM7NCX.js.map} +0 -0
- /package/dist/{ledger-4WJL66BW.js.map → ledger-62CEPRPX.js.map} +0 -0
- /package/dist/{liberate-PX4CAT5V.js.map → liberate-I6AOLWXW.js.map} +0 -0
- /package/dist/{link-set-N4ZPV6E6.js.map → link-set-ZRYNUHN3.js.map} +0 -0
- /package/dist/{managed-secret-OTHS64IF.js.map → managed-secret-T2WB4O47.js.map} +0 -0
- /package/dist/{noydb-YPSEGK32.js.map → noydb-SS6EN7TK.js.map} +0 -0
- /package/dist/{post-register-ZAG2CAIY.js.map → post-register-J4DEVNXK.js.map} +0 -0
- /package/dist/{register-TMD6YRCX.js.map → register-UPD4GKBC.js.map} +0 -0
- /package/dist/{registry-CZVINVQH.js.map → registry-7KX2HWFS.js.map} +0 -0
- /package/dist/{registry-FVLDWQKT.js.map → registry-PKYYEHEW.js.map} +0 -0
- /package/dist/{registry-IKUR2MXD.js.map → registry-XHCYMD34.js.map} +0 -0
- /package/dist/{registry-JET4HBLY.js.map → registry-XIRTZHPC.js.map} +0 -0
- /package/dist/{request-withdrawal-RH55LNZL.js.map → request-withdrawal-XZSESWZV.js.map} +0 -0
- /package/dist/{reveal-CMOJY4VO.js.map → reveal-525XWQU2.js.map} +0 -0
- /package/dist/{revoke-R5TBYVA6.js.map → revoke-QI7YHQ2B.js.map} +0 -0
- /package/dist/{signer-AGALOXOO.js.map → signer-BZWDPGGN.js.map} +0 -0
- /package/dist/{stale-ZWXSOWJI.js.map → stale-PQYPVCER.js.map} +0 -0
- /package/dist/{storage-N7LB275C.js.map → storage-MJHKNQRO.js.map} +0 -0
- /package/dist/{ulid-PTAIMDG4.js.map → ulid-VQW6ERQN.js.map} +0 -0
- /package/dist/{verify-RO5RTZOJ.js.map → verify-J6DEOXP3.js.map} +0 -0
- /package/dist/{walk-OCUHCYJ6.js.map → walk-BX4NSB5L.js.map} +0 -0
- /package/dist/{withdraw-accessible-QQNWM5BO.js.map → withdraw-accessible-K4CPMH4C.js.map} +0 -0
|
@@ -12,21 +12,30 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import type { EncryptedEnvelope, NoydbStore } from '../../kernel/types.js';
|
|
14
14
|
import type { LedgerStore } from '../../with-commit/history/ledger/store.js';
|
|
15
|
-
import type { PeriodRecord } from './periods.js';
|
|
15
|
+
import type { PeriodRecord, PeriodPartition, PartitionResolver } from './periods.js';
|
|
16
16
|
/**
|
|
17
17
|
* @internal
|
|
18
18
|
*/
|
|
19
19
|
export interface PeriodsStrategy {
|
|
20
|
-
loadPeriods(adapter: NoydbStore, vault: string, decrypt: (envelope: EncryptedEnvelope) => Promise<PeriodRecord>): Promise<PeriodRecord[]>;
|
|
21
|
-
chainAnchor(records: readonly PeriodRecord[]): Promise<{
|
|
20
|
+
loadPeriods(adapter: NoydbStore, vault: string, decrypt: (id: string, envelope: EncryptedEnvelope) => Promise<PeriodRecord>): Promise<PeriodRecord[]>;
|
|
21
|
+
chainAnchor(records: readonly PeriodRecord[], partition?: PeriodPartition): Promise<{
|
|
22
22
|
priorPeriodName?: string;
|
|
23
23
|
priorPeriodHash: string;
|
|
24
24
|
}>;
|
|
25
25
|
assertTsWritable(existing: {
|
|
26
26
|
ts: string | null;
|
|
27
27
|
record: Record<string, unknown> | null;
|
|
28
|
-
} | null, incoming: Record<string, unknown> | null, periods: readonly PeriodRecord[]
|
|
29
|
-
|
|
28
|
+
} | null, incoming: Record<string, unknown> | null, periods: readonly PeriodRecord[], scope?: {
|
|
29
|
+
collection: string;
|
|
30
|
+
resolve?: PartitionResolver;
|
|
31
|
+
}): void;
|
|
32
|
+
validatePeriodName(name: string, existing: readonly PeriodRecord[], partition?: PeriodPartition): void;
|
|
33
|
+
/**
|
|
34
|
+
* Record → timeline resolver built from `withPeriods({ subjects })` (#1005).
|
|
35
|
+
* `undefined` when the caller configured no subjects, which keeps every
|
|
36
|
+
* record on the vault-wide timeline.
|
|
37
|
+
*/
|
|
38
|
+
readonly partitionOf?: PartitionResolver;
|
|
30
39
|
appendPeriodLedgerEntry(ledger: LedgerStore | null, actor: string, envelope: EncryptedEnvelope, periodName: string, collection?: string): Promise<void>;
|
|
31
40
|
}
|
|
32
41
|
export declare const NO_PERIODS: PeriodsStrategy;
|
|
@@ -3,7 +3,31 @@ import type { NoydbStore } from '../../kernel/types.js';
|
|
|
3
3
|
import type { LedgerStore } from '../../with-commit/history/ledger/store.js';
|
|
4
4
|
import type { Collection } from '../../kernel/collection.js';
|
|
5
5
|
import type { PeriodsStrategy } from './strategy.js';
|
|
6
|
-
import { type PeriodRecord, type TargetPurgeCount, type ClosePeriodOptions, type OpenPeriodOptions } from './periods.js';
|
|
6
|
+
import { type PeriodRecord, type TargetPurgeCount, type ClosePeriodOptions, type OpenPeriodOptions, type PeriodPartition, type PeriodReopenEvent } from './periods.js';
|
|
7
|
+
/** Selects one period timeline. Omit — or pass an empty tuple — for the vault-wide one (#1005). */
|
|
8
|
+
export interface PeriodScope {
|
|
9
|
+
readonly partition?: PeriodPartition;
|
|
10
|
+
}
|
|
11
|
+
/** A scoped operation that also records a free-text justification in the audit trail. */
|
|
12
|
+
export interface PeriodScopeWithReason extends PeriodScope {
|
|
13
|
+
readonly reason?: string;
|
|
14
|
+
}
|
|
15
|
+
/** Options for `vault.reopenPeriod()` (#1022). */
|
|
16
|
+
export interface ReopenPeriodOptions extends PeriodScopeWithReason {
|
|
17
|
+
/**
|
|
18
|
+
* ISO instant after which the period re-seals BY ITSELF, with nobody acting.
|
|
19
|
+
* Omit for a window that stays open until an explicit `reclosePeriod()`.
|
|
20
|
+
*
|
|
21
|
+
* Expiry is evaluated against the clock on every write check, so a lapsed
|
|
22
|
+
* window needs no sweep, no timer and no cache invalidation to take effect.
|
|
23
|
+
*/
|
|
24
|
+
readonly until?: string;
|
|
25
|
+
}
|
|
26
|
+
/** The persisted side of a write, as the period write-guard sees it. */
|
|
27
|
+
export interface PeriodGuardPrior {
|
|
28
|
+
readonly ts: string | null;
|
|
29
|
+
readonly record: Record<string, unknown> | null;
|
|
30
|
+
}
|
|
7
31
|
/** Everything the moving period methods touched on the vault's `this.*`. */
|
|
8
32
|
export interface VaultPeriodsDeps {
|
|
9
33
|
/** Resolved periods strategy (NO_PERIODS when not configured). */
|
|
@@ -56,7 +80,7 @@ export declare class VaultPeriods {
|
|
|
56
80
|
* read only. Idempotent: a second call is a no-op that returns the
|
|
57
81
|
* same merged record without re-purging or re-appending a ledger entry.
|
|
58
82
|
*/
|
|
59
|
-
freezePeriod(name: string): Promise<PeriodRecord>;
|
|
83
|
+
freezePeriod(name: string, options?: PeriodScope): Promise<PeriodRecord>;
|
|
60
84
|
/**
|
|
61
85
|
* Archive a closed period (#613): physically relocates its in-window
|
|
62
86
|
* records (those with `_ts < periodExclusiveUpperBound(endDate)`) from the
|
|
@@ -66,7 +90,7 @@ export declare class VaultPeriods {
|
|
|
66
90
|
* through to cold) and idempotent: a second call is a no-op returning the
|
|
67
91
|
* same merged record.
|
|
68
92
|
*/
|
|
69
|
-
archivePeriod(name: string): Promise<PeriodRecord>;
|
|
93
|
+
archivePeriod(name: string, options?: PeriodScope): Promise<PeriodRecord>;
|
|
70
94
|
/**
|
|
71
95
|
* Target-purge a closed period (#615): sweeps delete markers off the vault's
|
|
72
96
|
* PUSH-ONLY sync targets (`backup`/`archive`) via `purgeTargets`, recording a
|
|
@@ -76,22 +100,77 @@ export declare class VaultPeriods {
|
|
|
76
100
|
* Idempotent once run; with no push-only targets it writes no companion and
|
|
77
101
|
* is re-runnable.
|
|
78
102
|
*/
|
|
79
|
-
purgePeriodTargets(name: string): Promise<PeriodRecord>;
|
|
103
|
+
purgePeriodTargets(name: string, options?: PeriodScope): Promise<PeriodRecord>;
|
|
80
104
|
/** Merge target-purge companion fields into a fresh `PeriodRecord` copy — never mutates `periodCache`. */
|
|
81
105
|
private mergeTargetPurge;
|
|
82
106
|
/** Merge archive companion fields into a fresh `PeriodRecord` copy — never mutates `periodCache`. */
|
|
83
107
|
private mergeArchive;
|
|
84
108
|
/** Merge freeze companion fields into a fresh `PeriodRecord` copy — never mutates `periodCache`. */
|
|
85
109
|
private mergeFreeze;
|
|
86
|
-
/**
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
110
|
+
/**
|
|
111
|
+
* Return every closed / opened period in `closedAt` order, merged with any
|
|
112
|
+
* freeze + archive companions.
|
|
113
|
+
*
|
|
114
|
+
* With no argument this spans EVERY timeline — the pre-#1005 behaviour, and
|
|
115
|
+
* the right default for an audit sweep. Pass `{ partition }` to scope to one
|
|
116
|
+
* timeline; `{ partition: [] }` (or omitting it) means the vault-wide one.
|
|
117
|
+
*/
|
|
118
|
+
listPeriods(options?: PeriodScope): Promise<readonly PeriodRecord[]>;
|
|
119
|
+
/**
|
|
120
|
+
* Look up a single period by name within one timeline, merged with its
|
|
121
|
+
* freeze + archive + target-purge companions if any. Returns `null` if not
|
|
122
|
+
* found.
|
|
123
|
+
*
|
|
124
|
+
* Names are only unique per partition (#1005), so this resolves against the
|
|
125
|
+
* VAULT-WIDE timeline unless `{ partition }` says otherwise — matching how
|
|
126
|
+
* every pre-partition period is stored.
|
|
127
|
+
*/
|
|
128
|
+
getPeriod(name: string, options?: PeriodScope): Promise<PeriodRecord | null>;
|
|
129
|
+
/**
|
|
130
|
+
* The full append-only reopen/reclose log for one period (#1022) — the record
|
|
131
|
+
* an audit actually asks for, in order. `[]` when never reopened.
|
|
132
|
+
*/
|
|
133
|
+
listPeriodReopens(name: string, options?: PeriodScope): Promise<readonly PeriodReopenEvent[]>;
|
|
134
|
+
/**
|
|
135
|
+
* Return a closed period to a writable state (#1022).
|
|
136
|
+
*
|
|
137
|
+
* Close is a three-state lifecycle in practice — open / closed / reopened —
|
|
138
|
+
* because a month gets closed and then a missing invoice arrives, or a filing
|
|
139
|
+
* is rejected and must be amended. That is routine, and it is supposed to
|
|
140
|
+
* leave a trail.
|
|
141
|
+
*
|
|
142
|
+
* The `_periods/<key>` record is NOT touched: the reopen is appended to a
|
|
143
|
+
* companion log, so the inter-period hash chain that proves the close
|
|
144
|
+
* happened survives the reopen intact. The chain reads *closed at T1,
|
|
145
|
+
* reopened at T2 by U, reclosed at T3*.
|
|
146
|
+
*
|
|
147
|
+
* A reopen withdraws the PERIOD's veto and nothing else. Record-level rules —
|
|
148
|
+
* an `immutableGuard` on a sent receipt, a frozen field — are separate gate
|
|
149
|
+
* handlers registered ahead of the period gate, so a reopened month cannot
|
|
150
|
+
* resurrect a document that is independently locked. Period state can only
|
|
151
|
+
* ever widen what the record-level rule already permits.
|
|
152
|
+
*
|
|
153
|
+
* Reopening an already-open window is allowed and appends another event: that
|
|
154
|
+
* is how a window gets extended, and the log keeps both.
|
|
155
|
+
*/
|
|
156
|
+
reopenPeriod(name: string, options?: ReopenPeriodOptions): Promise<PeriodRecord>;
|
|
157
|
+
/**
|
|
158
|
+
* Seal a reopened period again (#1022), ending the window explicitly rather
|
|
159
|
+
* than waiting for an `until` to lapse. Appends to the same log, so the
|
|
160
|
+
* close → reopen → reclose sequence is recoverable in order.
|
|
161
|
+
*/
|
|
162
|
+
reclosePeriod(name: string, options?: PeriodScopeWithReason): Promise<PeriodRecord>;
|
|
163
|
+
/** Append one entry to a period's reopen log, ledger it, and invalidate the guard's view. */
|
|
164
|
+
private appendReopenEvent;
|
|
165
|
+
/** Merge each period's reopen log onto it. One adapter listing, not one per period. */
|
|
166
|
+
private mergeReopenState;
|
|
167
|
+
/** Resolve one period within the timeline named by `options` (vault-wide when absent). */
|
|
168
|
+
private findPeriod;
|
|
169
|
+
/** Called by the gate bus before put/delete. `collection` selects the subject mapping (#1005). */
|
|
91
170
|
assertTsWritable(existing: {
|
|
92
171
|
ts: string | null;
|
|
93
172
|
record: Record<string, unknown> | null;
|
|
94
|
-
} | null, incoming: Record<string, unknown> | null): Promise<void>;
|
|
173
|
+
} | null, incoming: Record<string, unknown> | null, collection?: string): Promise<void>;
|
|
95
174
|
private loadPeriodsCache;
|
|
96
175
|
/** Generic reserved-collection writer — serves `_periods` and `_period_freezes` alike. */
|
|
97
176
|
private writeReserved;
|
|
@@ -6,6 +6,16 @@ export declare const PERIOD_FREEZES_COLLECTION = "_period_freezes";
|
|
|
6
6
|
export declare const PERIOD_ARCHIVES_COLLECTION = "_period_archives";
|
|
7
7
|
/** Sibling of {@link PERIODS_COLLECTION} holding target-purge companions (#615). */
|
|
8
8
|
export declare const PERIOD_TARGET_PURGES_COLLECTION = "_period_target_purges";
|
|
9
|
+
/**
|
|
10
|
+
* Sibling of {@link PERIODS_COLLECTION} holding reopen/reclose companions (#1022).
|
|
11
|
+
*
|
|
12
|
+
* Unlike the freeze / archive / target-purge companions — each a single,
|
|
13
|
+
* idempotent, once-only record — this one holds an APPEND-ONLY EVENT LIST,
|
|
14
|
+
* because reopening is a repeating cycle: a month can be closed, reopened,
|
|
15
|
+
* reclosed, and reopened again. The audit value is the sequence, not the
|
|
16
|
+
* latest state.
|
|
17
|
+
*/
|
|
18
|
+
export declare const PERIOD_REOPENS_COLLECTION = "_period_reopens";
|
|
9
19
|
/**
|
|
10
20
|
* Exclusive upper bound for a period's delete-marker purge window (#604).
|
|
11
21
|
* Markers carry no business date (empty body), only write-time `_ts`, so freeze
|
|
@@ -46,10 +46,23 @@ export { SealedRecordNotEnabledError } from '../../kernel/errors.js';
|
|
|
46
46
|
* @param expectedCollection Collection the caller believes `recordEnvelope` is in.
|
|
47
47
|
* @param expectedId Record id the caller believes `recordEnvelope` is.
|
|
48
48
|
* @returns The decrypted record body as a JSON string.
|
|
49
|
+
*
|
|
50
|
+
* ⚠️ **`recordEnvelope` must carry `_tier` and `_by`, not just the body**
|
|
51
|
+
* (#1041). They are plaintext metadata rather than secrets, but they are bound
|
|
52
|
+
* into the record's AAD, so a host handed only `{_iv, _data}` cannot
|
|
53
|
+
* reconstruct the identity the body was sealed against.
|
|
54
|
+
*
|
|
55
|
+
* That is a feature, not a tax: it means a host cannot be fed a body with its
|
|
56
|
+
* tags stripped or rewritten — a re-tiered or re-authored envelope no longer
|
|
57
|
+
* opens, even with a valid sealed CEK.
|
|
49
58
|
*/
|
|
50
59
|
export declare function openSealedRecord(sealedCekEnvelope: SealedCekDeliveryEnvelope, recordEnvelope: {
|
|
51
60
|
readonly _iv: string;
|
|
52
61
|
readonly _data: string;
|
|
62
|
+
/** Bound into the AAD since #1093 — a rewound body no longer opens. */
|
|
63
|
+
readonly _v: number;
|
|
64
|
+
readonly _tier?: number | undefined;
|
|
65
|
+
readonly _by?: string | undefined;
|
|
53
66
|
}, recipientSealer: {
|
|
54
67
|
unseal(bytes: Uint8Array): Promise<Uint8Array>;
|
|
55
68
|
}, expectedCollection: string, expectedId: string): Promise<string>;
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
export { withTiers } from './active.js';
|
|
24
24
|
export { NO_TIERS, type TiersStrategy } from './strategy.js';
|
|
25
25
|
export { TiersNotEnabledError } from '../../kernel/errors.js';
|
|
26
|
-
import { type RecordCodec, type EnclaveKey, type SealedShredSlot } from '../../kernel/enclave/index.js';
|
|
26
|
+
import { type RecordIdentity, 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
29
|
import type { BlobFieldsConfig } from '../../with-shape/blobs/blob-compaction.js';
|
|
@@ -123,7 +123,22 @@ export interface TiersContext<T> {
|
|
|
123
123
|
* pre-move body whenever `fromTier > 0`. No-op when history is disabled
|
|
124
124
|
* (folds the `historyConfig.enabled` gate so `tiers/index.ts` stays simple).
|
|
125
125
|
*/
|
|
126
|
-
|
|
126
|
+
/**
|
|
127
|
+
* Persist a `_history` snapshot of `version`, sealed against the address it
|
|
128
|
+
* will be STORED at (#1041).
|
|
129
|
+
*
|
|
130
|
+
* Takes a **sealer**, not a finished envelope, because the destination
|
|
131
|
+
* identity is not knowable here: only the history strategy owns the
|
|
132
|
+
* `_history` layout. It hands the address in; the caller seals to it.
|
|
133
|
+
*
|
|
134
|
+
* ⚠️ The identity passed to `rewrapBodyToDek` must be what a READER will
|
|
135
|
+
* recompute — `recordAadFor(address, finalEnvelope)`. A tier-move snapshot
|
|
136
|
+
* strips `_tier`/`_elevatedBy` but KEEPS `_by`, so the destination is
|
|
137
|
+
* `{...address, by: envelope._by}` with no tier. Sealing against the bare
|
|
138
|
+
* address would produce history nothing can open, and the failure would
|
|
139
|
+
* surface only when someone reads it.
|
|
140
|
+
*/
|
|
141
|
+
saveHistorySnapshot(id: string, version: number, seal: (address: RecordIdentity) => Promise<EncryptedEnvelope>): Promise<void>;
|
|
127
142
|
/**
|
|
128
143
|
* `true` iff a real history strategy is wired (not `NO_HISTORY`) AND not
|
|
129
144
|
* explicitly disabled via `historyConfig.enabled`. `putAtTier` checks this
|
|
@@ -12,7 +12,7 @@ import type { NoydbStore } from '../kernel/types.js';
|
|
|
12
12
|
import type { SealingKeyProvider } from '../with-party/team/managed-secret.js';
|
|
13
13
|
import type { ShamirRecoveryProvider } from '../with-party/team/shamir-recovery-provider.js';
|
|
14
14
|
import type { RecoveryEnrollmentInput } from '../with-party/team/rotate-recover.js';
|
|
15
|
-
import type { TransferSealPayload } from '../with-pod/
|
|
15
|
+
import type { TransferSealPayload } from '../with-pod/pod.js';
|
|
16
16
|
/**
|
|
17
17
|
* Reverse of `sealDeks`. Imports the transfer key, decrypts the
|
|
18
18
|
* sealed `{ collection: base64(rawDEK) }` map (layout iv(12)‖ct‖tag), and
|
|
@@ -10,7 +10,7 @@ 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
12
|
import { type WalkClosureOptions, type DanglingRefNotice } from './walk-closure.js';
|
|
13
|
-
import { type TransferSealPayload } from '../with-pod/
|
|
13
|
+
import { type TransferSealPayload } from '../with-pod/pod.js';
|
|
14
14
|
/** Re-keyed collections snapshot + the fresh DEKs used. */
|
|
15
15
|
export interface ReKeyResult {
|
|
16
16
|
readonly collections: Record<string, Record<string, EncryptedEnvelope>>;
|
|
@@ -37,10 +37,10 @@ export type { ExtractPartitionResult } from './extract-partition.js';
|
|
|
37
37
|
export { adoptPartition, unsealDeks, createOwnerOnAdoptedPartition } from './adopt-partition.js';
|
|
38
38
|
export type { AdoptPartitionOptions, AdoptPartitionResult, CreateOwnerResult, CreateOwnerOptions, CreateOwnerStandardOptions, CreateOwnerManagedOptions, } from './adopt-partition.js';
|
|
39
39
|
export { TransferSealError, AdoptionStateError, PartitionExtractionError } from '../kernel/errors.js';
|
|
40
|
-
export type { WriteHook } from '../port/with/write-hooks.js';
|
|
40
|
+
export type { WriteHook, WriteEvent } from '../port/with/write-hooks.js';
|
|
41
41
|
export type { WriteQueue } from '../kernel/write-queue.js';
|
|
42
42
|
export type { WriteConflict } from '../kernel/types.js';
|
|
43
43
|
export type { AccessibleVault } from '../kernel/types.js';
|
|
44
44
|
export type { Unsubscribe } from '../kernel/types.js';
|
|
45
45
|
export type { ExtractPartitionOptions } from './extract-partition.js';
|
|
46
|
-
export type { TransferSealPayload } from '../with-pod/
|
|
46
|
+
export type { TransferSealPayload } from '../with-pod/pod.js';
|
|
@@ -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>;
|