@noy-db/hub 0.6.0-pre.2 → 0.6.0-pre.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5234 -0
- package/codemods/0.4.0-pre.json +699 -0
- package/codemods/0.6.0-pre.json +211 -0
- package/dist/api-EYNT6KGS.js +20 -0
- package/dist/attestation/index.js +19 -19
- package/dist/{backup-YYBE5RPC.js → backup-FSC36VWC.js} +36 -18
- package/dist/backup-FSC36VWC.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-35EBKWQU.js → chunk-2LFOMUEA.js} +4 -4
- package/dist/{chunk-OF3L2SD6.js → chunk-32B7VCKU.js} +2 -2
- package/dist/{chunk-MSWYQLMQ.js → chunk-3B6S6RSI.js} +2 -2
- package/dist/{chunk-PJNTR2NV.js → chunk-3ENNPCIW.js} +7 -10
- package/dist/chunk-3ENNPCIW.js.map +1 -0
- package/dist/{chunk-7F4DBNSP.js → chunk-3O72ZD2E.js} +3 -3
- package/dist/{chunk-FNSMZQS4.js → chunk-3PMFMUFX.js} +2 -2
- package/dist/{chunk-WQDTCJ6W.js → chunk-45YHJ3GV.js} +11 -3
- package/dist/{chunk-WQDTCJ6W.js.map → chunk-45YHJ3GV.js.map} +1 -1
- package/dist/{chunk-NIVEDYJZ.js → chunk-4A34KWOU.js} +31 -49
- package/dist/chunk-4A34KWOU.js.map +1 -0
- package/dist/{chunk-ZJADGNYF.js → chunk-4AOERLTV.js} +1 -1
- package/dist/chunk-4AOERLTV.js.map +1 -0
- package/dist/{chunk-EDXAQ6JI.js → chunk-4N5Q23KV.js} +87 -34
- package/dist/chunk-4N5Q23KV.js.map +1 -0
- package/dist/{chunk-VV4NSB7P.js → chunk-4OQZNXQG.js} +15 -24
- package/dist/chunk-4OQZNXQG.js.map +1 -0
- package/dist/{chunk-FAXZQ5UF.js → chunk-4RAS6HN6.js} +2 -2
- package/dist/{chunk-C2OOEM57.js → chunk-4YL2LMXK.js} +92 -35
- package/dist/chunk-4YL2LMXK.js.map +1 -0
- package/dist/{chunk-EP7VPR7Y.js → chunk-5Q7AJ7DN.js} +11 -8
- package/dist/chunk-5Q7AJ7DN.js.map +1 -0
- package/dist/{chunk-VMCCGUQB.js → chunk-6JPGVL7X.js} +2 -2
- package/dist/{chunk-PRDRGL73.js → chunk-6KTVJ5ZZ.js} +17 -14
- package/dist/chunk-6KTVJ5ZZ.js.map +1 -0
- package/dist/{chunk-4MC5JRRX.js → chunk-6WO62AJW.js} +14 -15
- package/dist/chunk-6WO62AJW.js.map +1 -0
- package/dist/{chunk-WLYIROCJ.js → chunk-6YD5SYQS.js} +2 -2
- package/dist/{chunk-YAWK6AWF.js → chunk-7KAE7CQ2.js} +2 -2
- package/dist/{chunk-MWKDOHEF.js → chunk-7LNE2N2V.js} +17 -10
- package/dist/chunk-7LNE2N2V.js.map +1 -0
- package/dist/{chunk-5PR33AC4.js → chunk-7PJ3BKHS.js} +20 -17
- package/dist/chunk-7PJ3BKHS.js.map +1 -0
- package/dist/{chunk-JXIDGFKS.js → chunk-A4TOGAUW.js} +4 -2
- package/dist/chunk-A4TOGAUW.js.map +1 -0
- package/dist/{chunk-VCETL77O.js → chunk-AU3AUJIZ.js} +27 -7
- package/dist/chunk-AU3AUJIZ.js.map +1 -0
- package/dist/{chunk-NKH7GSIH.js → chunk-AUPSEJ7O.js} +4 -4
- package/dist/{chunk-CCZJJ4I2.js → chunk-B6IYATME.js} +4 -4
- package/dist/{chunk-WYZ5MYUA.js → chunk-BAHOV5I5.js} +44 -42
- package/dist/chunk-BAHOV5I5.js.map +1 -0
- package/dist/{chunk-G5APARUV.js → chunk-BEZDLIDG.js} +13 -15
- package/dist/chunk-BEZDLIDG.js.map +1 -0
- package/dist/{chunk-ERB6NDDW.js → chunk-CAGI4LLJ.js} +427 -72
- package/dist/chunk-CAGI4LLJ.js.map +1 -0
- package/dist/{chunk-4UVDI4XE.js → chunk-CLAHBPOI.js} +4 -4
- package/dist/{chunk-HNGSV2YC.js → chunk-CWM4GQD2.js} +39 -10
- package/dist/chunk-CWM4GQD2.js.map +1 -0
- package/dist/{chunk-HVQGCKY4.js → chunk-D3R7Q4QK.js} +2 -2
- package/dist/{chunk-I4F6PKUK.js → chunk-DIZ6HM7Q.js} +16 -17
- package/dist/chunk-DIZ6HM7Q.js.map +1 -0
- package/dist/{chunk-ZNACADFG.js → chunk-DVRZYAGT.js} +4 -4
- package/dist/chunk-DVRZYAGT.js.map +1 -0
- package/dist/{chunk-P7OG2ETF.js → chunk-DXKLLKME.js} +3 -3
- package/dist/{chunk-TDJPS3T2.js → chunk-E5SC6ENM.js} +24 -19
- package/dist/chunk-E5SC6ENM.js.map +1 -0
- package/dist/{chunk-26JMGSSC.js → chunk-EES37S2V.js} +4 -4
- package/dist/chunk-EES37S2V.js.map +1 -0
- package/dist/{chunk-JIUVJ4M7.js → chunk-EKEIEJL6.js} +2 -2
- package/dist/{chunk-GASWQ3XG.js → chunk-ESKIAXO2.js} +15 -16
- package/dist/chunk-ESKIAXO2.js.map +1 -0
- package/dist/{chunk-TOAIYQJR.js → chunk-FFSQFH6D.js} +7 -10
- package/dist/chunk-FFSQFH6D.js.map +1 -0
- package/dist/{chunk-DG27IUVI.js → chunk-FS7NTGCJ.js} +2 -2
- package/dist/{chunk-V5KYPBUR.js → chunk-FW7NGYLT.js} +11 -14
- package/dist/chunk-FW7NGYLT.js.map +1 -0
- package/dist/{chunk-52QYGZHH.js → chunk-GBBDFE6C.js} +2 -2
- package/dist/chunk-GBBDFE6C.js.map +1 -0
- package/dist/{chunk-HXGUIPQB.js → chunk-GQXFOAYZ.js} +3 -3
- package/dist/{chunk-BTVYJWSN.js → chunk-GTHVPVAR.js} +10 -10
- package/dist/{chunk-DMQCLZ4Z.js → chunk-GWO2IDAB.js} +2 -2
- package/dist/{chunk-6HFM7EIT.js → chunk-H3G4I3PN.js} +2 -2
- package/dist/chunk-HK67PX4J.js +27 -0
- package/dist/chunk-HK67PX4J.js.map +1 -0
- package/dist/{chunk-E7OBCBXS.js → chunk-HQSPF5IY.js} +22 -18
- package/dist/chunk-HQSPF5IY.js.map +1 -0
- package/dist/{chunk-VJFMXYKP.js → chunk-HR5R5JOM.js} +2 -2
- package/dist/{chunk-FDX7OWWI.js → chunk-HYYVT2KZ.js} +2 -2
- package/dist/{chunk-JRCYZEHU.js → chunk-I6QKB7MT.js} +2 -2
- package/dist/{chunk-MZ5ZFO2D.js → chunk-ICDHUUMQ.js} +84 -112
- package/dist/chunk-ICDHUUMQ.js.map +1 -0
- package/dist/{chunk-W5W6KHN2.js → chunk-IGNJOJEP.js} +1 -1
- package/dist/chunk-IGNJOJEP.js.map +1 -0
- package/dist/{chunk-KUDZVJKQ.js → chunk-IJ46VCWD.js} +2 -2
- package/dist/{chunk-4HDYQL3J.js → chunk-INMHEMXX.js} +2 -2
- package/dist/{chunk-66W5OOCX.js → chunk-JLYQQNY4.js} +52 -65
- package/dist/chunk-JLYQQNY4.js.map +1 -0
- package/dist/{chunk-UHXCLPGC.js → chunk-JNMTN5D5.js} +2 -2
- package/dist/chunk-JNMTN5D5.js.map +1 -0
- package/dist/{chunk-I4ZAO7F7.js → chunk-JWMBG5S3.js} +7 -11
- package/dist/chunk-JWMBG5S3.js.map +1 -0
- package/dist/chunk-KRVS7YWY.js +123 -0
- package/dist/chunk-KRVS7YWY.js.map +1 -0
- package/dist/{chunk-AR2JDFAE.js → chunk-KV6JM2IA.js} +2 -2
- package/dist/{chunk-PVU7LW5L.js → chunk-KX57HODD.js} +6 -6
- package/dist/{chunk-PY7CI6L5.js → chunk-LGFTOU27.js} +553 -275
- package/dist/chunk-LGFTOU27.js.map +1 -0
- package/dist/chunk-LN7P6MZB.js +190 -0
- package/dist/chunk-LN7P6MZB.js.map +1 -0
- package/dist/{chunk-UIBGXRDD.js → chunk-LX46B56Q.js} +25 -31
- package/dist/chunk-LX46B56Q.js.map +1 -0
- package/dist/{chunk-CEJWMBXO.js → chunk-LXECF2ZR.js} +2 -2
- package/dist/{chunk-7VHY5E3X.js → chunk-MSLPDFK2.js} +7 -7
- package/dist/{chunk-I6SDX7WX.js → chunk-MZTUTEHP.js} +16 -22
- package/dist/chunk-MZTUTEHP.js.map +1 -0
- package/dist/{chunk-VRA4Q7DA.js → chunk-NCCEDL2K.js} +55 -48
- package/dist/chunk-NCCEDL2K.js.map +1 -0
- package/dist/{chunk-HNHCQ556.js → chunk-NR2SUJ3H.js} +2 -2
- package/dist/{chunk-AHLJSVRL.js → chunk-NW4TY6VC.js} +5 -7
- package/dist/chunk-NW4TY6VC.js.map +1 -0
- package/dist/{chunk-RKKORO4M.js → chunk-O742QBZZ.js} +10 -10
- package/dist/chunk-O742QBZZ.js.map +1 -0
- package/dist/{chunk-VN45YLWM.js → chunk-OHOKBMTM.js} +343 -132
- package/dist/chunk-OHOKBMTM.js.map +1 -0
- package/dist/{chunk-W3TVWF6N.js → chunk-OIBEJN5H.js} +2 -2
- package/dist/{chunk-QD724WDJ.js → chunk-OMYCSTXL.js} +4 -4
- package/dist/{chunk-Z45YRGFO.js → chunk-ONVD6GBY.js} +2 -2
- package/dist/{chunk-TAGFGKHP.js → chunk-OTHHO3KI.js} +7 -10
- package/dist/chunk-OTHHO3KI.js.map +1 -0
- package/dist/{chunk-3737A6EA.js → chunk-P2MR5UNE.js} +75 -18
- package/dist/chunk-P2MR5UNE.js.map +1 -0
- package/dist/chunk-PENPHA45.js +66 -0
- package/dist/chunk-PENPHA45.js.map +1 -0
- package/dist/{chunk-3FSX6LDG.js → chunk-PPCOKVFA.js} +8 -3
- package/dist/{chunk-3FSX6LDG.js.map → chunk-PPCOKVFA.js.map} +1 -1
- package/dist/{chunk-VOQW5LAM.js → chunk-QSIEL6TL.js} +102 -71
- package/dist/chunk-QSIEL6TL.js.map +1 -0
- package/dist/chunk-RFO4UXKQ.js +201 -0
- package/dist/chunk-RFO4UXKQ.js.map +1 -0
- package/dist/{chunk-KCQX65FU.js → chunk-RKCRPPNB.js} +3 -3
- package/dist/{chunk-7TSYBD3E.js → chunk-RSXQNFGO.js} +2 -2
- package/dist/{chunk-SZ2K3MHL.js → chunk-S56VYR4Q.js} +8 -11
- package/dist/{chunk-SZ2K3MHL.js.map → chunk-S56VYR4Q.js.map} +1 -1
- package/dist/{chunk-7NXHMW6Y.js → chunk-SYS46BL7.js} +2 -2
- package/dist/{chunk-55LKVALY.js → chunk-T7IR4N2S.js} +1 -3
- package/dist/chunk-T7IR4N2S.js.map +1 -0
- package/dist/{chunk-A67356IR.js → chunk-T7JGWTES.js} +33 -8
- package/dist/chunk-T7JGWTES.js.map +1 -0
- package/dist/{chunk-WHJKIZS7.js → chunk-TDSN2O2V.js} +27 -149
- package/dist/chunk-TDSN2O2V.js.map +1 -0
- package/dist/{chunk-747LRSOO.js → chunk-TMBSPLUG.js} +2 -2
- package/dist/{chunk-LWSJG3LI.js → chunk-TQPASLY4.js} +7 -3
- package/dist/chunk-TQPASLY4.js.map +1 -0
- package/dist/{chunk-WKPJXWKR.js → chunk-TX5MKAHA.js} +3 -3
- package/dist/{chunk-HFQ6LGIO.js → chunk-U27Y4DJZ.js} +12 -10
- package/dist/{chunk-HFQ6LGIO.js.map → chunk-U27Y4DJZ.js.map} +1 -1
- package/dist/{chunk-E6427JU2.js → chunk-VVSOPRUE.js} +18 -2
- package/dist/chunk-VVSOPRUE.js.map +1 -0
- package/dist/{chunk-7G6VDWXB.js → chunk-WVE6YKMX.js} +3 -3
- package/dist/chunk-WVE6YKMX.js.map +1 -0
- package/dist/{chunk-GLKDWWNO.js → chunk-YALD3SST.js} +16 -14
- package/dist/chunk-YALD3SST.js.map +1 -0
- package/dist/{chunk-NJDQ4YSV.js → chunk-YKXZHUOW.js} +4 -4
- package/dist/{chunk-VW6ZZGCG.js → chunk-ZLHHE5XZ.js} +3 -3
- package/dist/{chunk-FUHKW252.js → chunk-ZZXLB6AS.js} +2 -2
- package/dist/classified/index.js +5 -5
- package/dist/{classified-marker-FTOX7Q5L.js → classified-marker-NA6HUV33.js} +3 -3
- package/dist/collection-facade-VBM35WAH.js +45 -0
- package/dist/{computed-6G5M3UPH.js → computed-GSTLWSY5.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-UALP5DJX.js} +2 -2
- package/dist/debug/index.js +1 -1
- package/dist/{delegation-SSEPLXXO.js → delegation-JLNXM7KH.js} +24 -23
- package/dist/delegation-JLNXM7KH.js.map +1 -0
- package/dist/derivations/index.js +12 -12
- package/dist/derive-YUO3TQYN.js +22 -0
- package/dist/directory/index.js +10 -10
- package/dist/{dispatch-RE74SH6L.js → dispatch-4ZHLSFZQ.js} +5 -5
- package/dist/{dispatch-BDVGYC6X.js → dispatch-77CB75KB.js} +18 -18
- package/dist/{enclave-52VUXNRL.js → enclave-O4NOROCJ.js} +27 -9
- package/dist/executor-CZDXBXKE.js +29 -0
- package/dist/executor-DVJAWN3B.js +9 -0
- package/dist/executor-VRLG4TQJ.js +9 -0
- package/dist/export-accessible-UXSMG7AB.js +23 -0
- package/dist/extract-partition-TVY7AMKH.js +38 -0
- package/dist/{fanout-sidecar-DTBIDOWF.js → fanout-sidecar-NLQ7QAYW.js} +18 -27
- package/dist/fanout-sidecar-NLQ7QAYW.js.map +1 -0
- package/dist/find-WSARMJBW.js +11 -0
- package/dist/forget/index.js +9 -9
- package/dist/guards/index.js +7 -7
- package/dist/history/index.js +23 -20
- package/dist/history/index.js.map +1 -1
- package/dist/i18n/index.js +14 -14
- package/dist/index.d.ts +33 -15
- package/dist/index.js +187 -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-3JNJNPT3.js +19 -0
- package/dist/kernel/constants.d.ts +18 -0
- package/dist/kernel/enclave/crypto.d.ts +24 -4
- package/dist/kernel/enclave/index.d.ts +9 -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-blob.d.ts +88 -0
- 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 +71 -12
- package/dist/kernel/merge-authority.d.ts +25 -0
- package/dist/kernel/noydb.d.ts +27 -4
- package/dist/kernel/query/builder.d.ts +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 +145 -12
- package/dist/kernel/vault.d.ts +22 -18
- package/dist/kernel/via/index.d.ts +11 -2
- package/dist/{ledger-4WJL66BW.js → ledger-MVPNG5OS.js} +11 -11
- package/dist/liberate-4LOJOLDT.js +24 -0
- package/dist/{link-set-N4ZPV6E6.js → link-set-3POMQR3I.js} +11 -11
- package/dist/{managed-secret-OTHS64IF.js → managed-secret-IARIJJ7Q.js} +11 -3
- package/dist/materialized-views/index.js +22 -21
- package/dist/migrate-cek-XM2ETTZW.js +19 -0
- package/dist/migrate-cek-XM2ETTZW.js.map +1 -0
- package/dist/money/index.js +12 -8
- package/dist/noydb-IRILUDED.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-MELERCKU.js +41 -0
- package/dist/pod-handle-MELERCKU.js.map +1 -0
- package/dist/policy/index.js +11 -4
- package/dist/port/to/index.d.ts +4 -4
- package/dist/port/to/locator.d.ts +54 -8
- package/dist/port/with/i18n-strategy.d.ts +4 -1
- package/dist/port/with/lookup-strategy.d.ts +4 -1
- package/dist/port/with/merge-authority.d.ts +52 -0
- package/dist/port/with/service-bus.d.ts +0 -4
- package/dist/port/with/strategies.d.ts +2 -0
- package/dist/port/with/team-strategy.d.ts +5 -1
- package/dist/portability/index.js +8 -8
- package/dist/{post-register-ZAG2CAIY.js → post-register-Z5T7FY45.js} +6 -6
- package/dist/query/index.js +3 -3
- package/dist/reduce/index.js +4 -4
- package/dist/register-UZ37QPDB.js +32 -0
- package/dist/registry-ETJNA7PO.js +9 -0
- package/dist/registry-F7U6KSLX.js +9 -0
- package/dist/registry-L4ELKX6C.js +18 -0
- package/dist/registry-SDT5LIGO.js +19 -0
- package/dist/request-withdrawal-PVFEYX57.js +31 -0
- package/dist/{reveal-CMOJY4VO.js → reveal-DQ2E3QAZ.js} +6 -6
- package/dist/revoke-YXY6SHUH.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-DZ4ORU5N.js} +19 -22
- package/dist/seed-DZ4ORU5N.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-Q7XQBMPA.js +25 -0
- package/dist/snapshots/index.js +10 -10
- package/dist/snapshots/index.js.map +1 -1
- package/dist/{stale-ZWXSOWJI.js → stale-NI7SAXAZ.js} +10 -10
- package/dist/storage-3VNGSHXS.js +23 -0
- package/dist/{store-coordination-provider-PB6QZ57W.js → store-coordination-provider-TYKNR3OU.js} +18 -12
- package/dist/store-coordination-provider-TYKNR3OU.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-6J2YLKSO.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-WRA7RAPY.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 +149 -3
- package/dist/with-party/team/noydb-facade.d.ts +5 -1
- package/dist/with-party/team/roster-tag.d.ts +101 -0
- package/dist/with-party/team/tiers.d.ts +2 -1
- package/dist/with-pod/format.d.ts +10 -12
- package/dist/with-pod/index.d.ts +10 -10
- package/dist/with-pod/open.d.ts +2 -2
- package/dist/with-pod/pod-handle.d.ts +19 -0
- package/dist/with-pod/pod-store.d.ts +0 -8
- package/dist/with-pod/{bundle.d.ts → pod.d.ts} +26 -19
- package/dist/with-pod/ulid.d.ts +1 -1
- package/dist/with-shape/blobs/blob-set.d.ts +2 -2
- 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-4JTDFRFZ.js +28 -0
- package/package.json +13 -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-EYNT6KGS.js.map} +0 -0
- /package/dist/{chunk-35EBKWQU.js.map → chunk-2LFOMUEA.js.map} +0 -0
- /package/dist/{chunk-OF3L2SD6.js.map → chunk-32B7VCKU.js.map} +0 -0
- /package/dist/{chunk-MSWYQLMQ.js.map → chunk-3B6S6RSI.js.map} +0 -0
- /package/dist/{chunk-7F4DBNSP.js.map → chunk-3O72ZD2E.js.map} +0 -0
- /package/dist/{chunk-FNSMZQS4.js.map → chunk-3PMFMUFX.js.map} +0 -0
- /package/dist/{chunk-FAXZQ5UF.js.map → chunk-4RAS6HN6.js.map} +0 -0
- /package/dist/{chunk-VMCCGUQB.js.map → chunk-6JPGVL7X.js.map} +0 -0
- /package/dist/{chunk-WLYIROCJ.js.map → chunk-6YD5SYQS.js.map} +0 -0
- /package/dist/{chunk-YAWK6AWF.js.map → chunk-7KAE7CQ2.js.map} +0 -0
- /package/dist/{chunk-NKH7GSIH.js.map → chunk-AUPSEJ7O.js.map} +0 -0
- /package/dist/{chunk-CCZJJ4I2.js.map → chunk-B6IYATME.js.map} +0 -0
- /package/dist/{chunk-4UVDI4XE.js.map → chunk-CLAHBPOI.js.map} +0 -0
- /package/dist/{chunk-HVQGCKY4.js.map → chunk-D3R7Q4QK.js.map} +0 -0
- /package/dist/{chunk-P7OG2ETF.js.map → chunk-DXKLLKME.js.map} +0 -0
- /package/dist/{chunk-JIUVJ4M7.js.map → chunk-EKEIEJL6.js.map} +0 -0
- /package/dist/{chunk-DG27IUVI.js.map → chunk-FS7NTGCJ.js.map} +0 -0
- /package/dist/{chunk-HXGUIPQB.js.map → chunk-GQXFOAYZ.js.map} +0 -0
- /package/dist/{chunk-BTVYJWSN.js.map → chunk-GTHVPVAR.js.map} +0 -0
- /package/dist/{chunk-DMQCLZ4Z.js.map → chunk-GWO2IDAB.js.map} +0 -0
- /package/dist/{chunk-6HFM7EIT.js.map → chunk-H3G4I3PN.js.map} +0 -0
- /package/dist/{chunk-VJFMXYKP.js.map → chunk-HR5R5JOM.js.map} +0 -0
- /package/dist/{chunk-FDX7OWWI.js.map → chunk-HYYVT2KZ.js.map} +0 -0
- /package/dist/{chunk-JRCYZEHU.js.map → chunk-I6QKB7MT.js.map} +0 -0
- /package/dist/{chunk-KUDZVJKQ.js.map → chunk-IJ46VCWD.js.map} +0 -0
- /package/dist/{chunk-4HDYQL3J.js.map → chunk-INMHEMXX.js.map} +0 -0
- /package/dist/{chunk-AR2JDFAE.js.map → chunk-KV6JM2IA.js.map} +0 -0
- /package/dist/{chunk-PVU7LW5L.js.map → chunk-KX57HODD.js.map} +0 -0
- /package/dist/{chunk-CEJWMBXO.js.map → chunk-LXECF2ZR.js.map} +0 -0
- /package/dist/{chunk-7VHY5E3X.js.map → chunk-MSLPDFK2.js.map} +0 -0
- /package/dist/{chunk-HNHCQ556.js.map → chunk-NR2SUJ3H.js.map} +0 -0
- /package/dist/{chunk-W3TVWF6N.js.map → chunk-OIBEJN5H.js.map} +0 -0
- /package/dist/{chunk-QD724WDJ.js.map → chunk-OMYCSTXL.js.map} +0 -0
- /package/dist/{chunk-Z45YRGFO.js.map → chunk-ONVD6GBY.js.map} +0 -0
- /package/dist/{chunk-KCQX65FU.js.map → chunk-RKCRPPNB.js.map} +0 -0
- /package/dist/{chunk-7TSYBD3E.js.map → chunk-RSXQNFGO.js.map} +0 -0
- /package/dist/{chunk-7NXHMW6Y.js.map → chunk-SYS46BL7.js.map} +0 -0
- /package/dist/{chunk-747LRSOO.js.map → chunk-TMBSPLUG.js.map} +0 -0
- /package/dist/{chunk-WKPJXWKR.js.map → chunk-TX5MKAHA.js.map} +0 -0
- /package/dist/{chunk-NJDQ4YSV.js.map → chunk-YKXZHUOW.js.map} +0 -0
- /package/dist/{chunk-VW6ZZGCG.js.map → chunk-ZLHHE5XZ.js.map} +0 -0
- /package/dist/{chunk-FUHKW252.js.map → chunk-ZZXLB6AS.js.map} +0 -0
- /package/dist/{classified-marker-FTOX7Q5L.js.map → classified-marker-NA6HUV33.js.map} +0 -0
- /package/dist/{collection-facade-QN5ULWYC.js.map → collection-facade-VBM35WAH.js.map} +0 -0
- /package/dist/{computed-6G5M3UPH.js.map → computed-GSTLWSY5.js.map} +0 -0
- /package/dist/{dead-filter-ENRIOQIE.js.map → dead-filter-UALP5DJX.js.map} +0 -0
- /package/dist/{derive-6V3PIZF7.js.map → derive-YUO3TQYN.js.map} +0 -0
- /package/dist/{dispatch-RE74SH6L.js.map → dispatch-4ZHLSFZQ.js.map} +0 -0
- /package/dist/{dispatch-BDVGYC6X.js.map → dispatch-77CB75KB.js.map} +0 -0
- /package/dist/{enclave-52VUXNRL.js.map → enclave-O4NOROCJ.js.map} +0 -0
- /package/dist/{executor-CYJQLKKI.js.map → executor-CZDXBXKE.js.map} +0 -0
- /package/dist/{executor-FHHLXO4Y.js.map → executor-DVJAWN3B.js.map} +0 -0
- /package/dist/{executor-S4QIKEHW.js.map → executor-VRLG4TQJ.js.map} +0 -0
- /package/dist/{export-accessible-PE5AYKZR.js.map → export-accessible-UXSMG7AB.js.map} +0 -0
- /package/dist/{extract-partition-X2L26O6A.js.map → extract-partition-TVY7AMKH.js.map} +0 -0
- /package/dist/{find-RBBYKXI7.js.map → find-WSARMJBW.js.map} +0 -0
- /package/dist/{issue-RNU55YOF.js.map → issue-3JNJNPT3.js.map} +0 -0
- /package/dist/{ledger-4WJL66BW.js.map → ledger-MVPNG5OS.js.map} +0 -0
- /package/dist/{liberate-PX4CAT5V.js.map → liberate-4LOJOLDT.js.map} +0 -0
- /package/dist/{link-set-N4ZPV6E6.js.map → link-set-3POMQR3I.js.map} +0 -0
- /package/dist/{managed-secret-OTHS64IF.js.map → managed-secret-IARIJJ7Q.js.map} +0 -0
- /package/dist/{noydb-YPSEGK32.js.map → noydb-IRILUDED.js.map} +0 -0
- /package/dist/{post-register-ZAG2CAIY.js.map → post-register-Z5T7FY45.js.map} +0 -0
- /package/dist/{register-TMD6YRCX.js.map → register-UZ37QPDB.js.map} +0 -0
- /package/dist/{registry-CZVINVQH.js.map → registry-ETJNA7PO.js.map} +0 -0
- /package/dist/{registry-FVLDWQKT.js.map → registry-F7U6KSLX.js.map} +0 -0
- /package/dist/{registry-IKUR2MXD.js.map → registry-L4ELKX6C.js.map} +0 -0
- /package/dist/{registry-JET4HBLY.js.map → registry-SDT5LIGO.js.map} +0 -0
- /package/dist/{request-withdrawal-RH55LNZL.js.map → request-withdrawal-PVFEYX57.js.map} +0 -0
- /package/dist/{reveal-CMOJY4VO.js.map → reveal-DQ2E3QAZ.js.map} +0 -0
- /package/dist/{revoke-R5TBYVA6.js.map → revoke-YXY6SHUH.js.map} +0 -0
- /package/dist/{signer-AGALOXOO.js.map → signer-Q7XQBMPA.js.map} +0 -0
- /package/dist/{stale-ZWXSOWJI.js.map → stale-NI7SAXAZ.js.map} +0 -0
- /package/dist/{storage-N7LB275C.js.map → storage-3VNGSHXS.js.map} +0 -0
- /package/dist/{ulid-PTAIMDG4.js.map → ulid-VQW6ERQN.js.map} +0 -0
- /package/dist/{verify-RO5RTZOJ.js.map → verify-6J2YLKSO.js.map} +0 -0
- /package/dist/{walk-OCUHCYJ6.js.map → walk-WRA7RAPY.js.map} +0 -0
- /package/dist/{withdraw-accessible-QQNWM5BO.js.map → withdraw-accessible-4JTDFRFZ.js.map} +0 -0
|
@@ -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>;
|
|
@@ -4,6 +4,7 @@ import type { ReduceSpec, Reduction } from '../../with-lookup/reduce/reduction.j
|
|
|
4
4
|
import type { GroupedReduction } from '../../with-lookup/reduce/groupby.js';
|
|
5
5
|
import type { JoinStrategy } from '../../kernel/query/join.js';
|
|
6
6
|
import type { MoneyDescriptor } from '../../via/money/descriptor.js';
|
|
7
|
+
import type { ExactMath } from '../../via/money/exact.js';
|
|
7
8
|
import type { I18nTextDescriptor } from '../../via/i18n/core.js';
|
|
8
9
|
/**
|
|
9
10
|
* Minimal vault-shaped accessor passed to the MV `query()` callback.
|
|
@@ -269,6 +270,57 @@ export interface MaterializedViewSpec<TRow extends Record<string, unknown>> {
|
|
|
269
270
|
* UNION-mode only. Ignored if {@link query} is set.
|
|
270
271
|
*/
|
|
271
272
|
aggregate?: ReduceSpec;
|
|
273
|
+
/**
|
|
274
|
+
* Post-aggregate projection over ONE finished row (#1007).
|
|
275
|
+
*
|
|
276
|
+
* `aggregate` accepts reducers only, so a row can carry every input a
|
|
277
|
+
* derived value needs and still not express it — `max(0, netTotal - paid)`
|
|
278
|
+
* is not a reduction. `derive` closes that gap: it receives the row the
|
|
279
|
+
* grouping/aggregation pipeline just produced and returns a patch merged
|
|
280
|
+
* onto it, immediately before materialisation.
|
|
281
|
+
*
|
|
282
|
+
* ```ts
|
|
283
|
+
* aggregate: { paid: sum('paid'), netTotal: sum('netTotal') },
|
|
284
|
+
* derive: (row) => ({ toPay: Math.max(0, row.netTotal - row.paid) }),
|
|
285
|
+
* ```
|
|
286
|
+
*
|
|
287
|
+
* Deliberately narrow, and the narrowness is what keeps it safe under
|
|
288
|
+
* incremental recompute: **pure, single-row, no cross-row access, no second
|
|
289
|
+
* aggregation pass.** It only ever sees the row the reducer just produced,
|
|
290
|
+
* so a refresh triggered by one source write recomputes it correctly without
|
|
291
|
+
* the engine needing to know anything about the function.
|
|
292
|
+
*
|
|
293
|
+
* Returning `null` / `undefined` leaves the row unchanged. Returned keys
|
|
294
|
+
* that collide with a {@link groupBy} field throw
|
|
295
|
+
* `MaterializedViewConfigError` — a group key is the row's identity and
|
|
296
|
+
* feeds {@link rowKey}, so rewriting it would silently re-home the row.
|
|
297
|
+
*
|
|
298
|
+
* **Money:** money leaves a reducer as an exact decimal string, and
|
|
299
|
+
* `Number(a) - Number(b)` would put it straight back through binary floating
|
|
300
|
+
* point — `10.05 - 0.10` becomes `9.950000000000001`, which the money
|
|
301
|
+
* quantiser then refuses rather than storing drift. So `derive` receives
|
|
302
|
+
* {@link ExactMath} as its second argument; it works in scaled BigInt and
|
|
303
|
+
* cannot introduce a representation error:
|
|
304
|
+
*
|
|
305
|
+
* ```ts
|
|
306
|
+
* moneyFields: { netTotal: THB, paid: THB, toPay: THB },
|
|
307
|
+
* derive: (row, exact) => ({ toPay: exact.max(0, exact.sub(row.netTotal, row.paid)) }),
|
|
308
|
+
* ```
|
|
309
|
+
*
|
|
310
|
+
* Declare the derived field in {@link moneyFields} and the result is
|
|
311
|
+
* quantised through that descriptor before storage, exact at its scale.
|
|
312
|
+
*
|
|
313
|
+
* Note the one place `TRow` under-describes what arrives: a field declared
|
|
314
|
+
* in {@link moneyFields} reaches `derive` DECODED — the decimal string a
|
|
315
|
+
* reader would see, not the scaled integer the reducer left behind — even
|
|
316
|
+
* where `TRow` types it as `number` (which is what the arms' `map` emits).
|
|
317
|
+
* `ExactMath` accepts both, which is why its operations are the right tool
|
|
318
|
+
* here and why no cast is needed.
|
|
319
|
+
*
|
|
320
|
+
* Applies to every MV form (union, projection, and query), always as the
|
|
321
|
+
* last step before rows are materialised.
|
|
322
|
+
*/
|
|
323
|
+
derive?: (row: TRow, exact: ExactMath) => Record<string, unknown> | null | undefined;
|
|
272
324
|
/**
|
|
273
325
|
* Money descriptors for the UNION-mode aggregate, keyed by the
|
|
274
326
|
* OUTPUT/intermediate field name as it appears in the mapped row and
|
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Persistence helpers for `_meta/public-envelope` — the cover's
|
|
3
|
-
* frozen wire location. Mirrors the bypass-AES pattern used by
|
|
4
|
-
* `_meta/handle` and `_meta/policy` — the document is plaintext
|
|
5
|
-
* JSON, the envelope's `_iv` field is left empty.
|
|
6
|
-
*
|
|
7
|
-
* @module
|
|
8
|
-
*/
|
|
9
1
|
import type { NoydbStore } from '../../../kernel/types.js';
|
|
10
2
|
import type { Cover } from './types.js';
|
|
11
3
|
/**
|
|
@@ -1,14 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Persistence helpers for the vault-level user-directory toggle
|
|
3
|
-
* (`_meta/directory`). Mirrors the bypass-AES pattern used by
|
|
4
|
-
* `_meta/policy` — the directory document is plain JSON, the
|
|
5
|
-
* envelope's `_iv` field is left empty.
|
|
6
|
-
*
|
|
7
|
-
* @see https://github.com/vLannaAi/noy-db-docs/blob/main/content/docs/services/user-envelope.md → Directory visibility
|
|
8
|
-
* @see https://github.com/vLannaAi/noy-db-docs/blob/main/content/docs/services/plaintext-bypass.md — every `_iv: ''` write site
|
|
9
|
-
*
|
|
10
|
-
* @module
|
|
11
|
-
*/
|
|
12
1
|
import type { NoydbStore } from '../../kernel/types.js';
|
|
13
2
|
import type { DirectoryConfig } from './types.js';
|
|
14
3
|
/** Reserved collection name for vault-level metadata documents. */
|
|
@@ -1,24 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Persistence helpers for the per-user visibility flag
|
|
3
|
-
* (`_meta/visibility/<keyringId>`). Mirrors the bypass-AES pattern used
|
|
4
|
-
* by `_meta/policy` — the visibility document is plain JSON, the
|
|
5
|
-
* envelope's `_iv` field is left empty.
|
|
6
|
-
*
|
|
7
|
-
* Stored alongside the keyring file rather than inside the encrypted
|
|
8
|
-
* user envelope (`_users/<keyringId>`) because:
|
|
9
|
-
*
|
|
10
|
-
* - `UserEnvelope<T>.data` is opaque-to-hub by contract — hub does not
|
|
11
|
-
* introspect or reserve any keys inside it. Adding `hidden` there
|
|
12
|
-
* would violate that contract.
|
|
13
|
-
* - `listUsersWithEnvelopes` filters by the flag, and the filter must
|
|
14
|
-
* work even when decryption fails (legacy keyrings predating the
|
|
15
|
-
* envelope feature, or a corrupted envelope).
|
|
16
|
-
*
|
|
17
|
-
* @see https://github.com/vLannaAi/noy-db-docs/blob/main/content/docs/services/user-envelope.md → Directory visibility
|
|
18
|
-
* @see https://github.com/vLannaAi/noy-db-docs/blob/main/content/docs/services/plaintext-bypass.md — every `_iv: ''` write site
|
|
19
|
-
*
|
|
20
|
-
* @module
|
|
21
|
-
*/
|
|
22
1
|
import type { NoydbStore } from '../../kernel/types.js';
|
|
23
2
|
import type { UserVisibility } from './types.js';
|
|
24
3
|
/** Prefix for per-user visibility records inside `_meta`. */
|
|
@@ -1,13 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Persistence helpers for the vault-level policy document
|
|
3
|
-
* (`_meta/policy`). Mirrors the bypass-AES pattern used by
|
|
4
|
-
* `_meta/handle` — the policy document is plain JSON, the envelope's
|
|
5
|
-
* `_iv` field is left empty.
|
|
6
|
-
*
|
|
7
|
-
* @see https://github.com/vLannaAi/noy-db-docs/blob/main/content/docs/services/session-tiers.md → Storage location
|
|
8
|
-
*
|
|
9
|
-
* @module
|
|
10
|
-
*/
|
|
11
1
|
import type { NoydbStore, VaultPolicy } from '../../kernel/types.js';
|
|
12
2
|
/** Reserved collection name for vault-level metadata documents. */
|
|
13
3
|
export declare const META_COLLECTION = "_meta";
|
|
@@ -17,7 +17,7 @@ export { NO_TEAM, type TeamStrategy } from './strategy.js';
|
|
|
17
17
|
export { TeamNotEnabledError } from '../../kernel/errors.js';
|
|
18
18
|
export type { UnlockedKeyring } from './keyring.js';
|
|
19
19
|
export { loadKeyring, createOwnerKeyring, grant, revoke, changeSecret, listUsers, listUsersWithEnvelopes, ensureCollectionDEK, persistKeyring, updateKeyringIdentity, buildRecipientKeyringFile, } from './keyring.js';
|
|
20
|
-
export type {
|
|
20
|
+
export type { PodRecipient, ListUsersOptions } from './keyring.js';
|
|
21
21
|
export type { LoadKeyringOptions, CreateOwnerKeyringOptions, RotateKeysOptions, ChangeSecretOptions, } from './keyring.js';
|
|
22
22
|
export { enrollAuthenticator, removeAuthenticator, updateAuthenticator, findAuthenticator, } from './authenticators.js';
|
|
23
23
|
export type { EnrollAuthenticatorOptions, EnrollAuthenticatorWrappingKEKOptions, EnrollAuthenticatorWrappingDEKsOptions, UpdateAuthenticatorOptions, } from './authenticators.js';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { NoydbStore, KeyringFile, KeyringAuthenticator, Role, Permissions, GrantOptions, RevokeOptions, UpdateUserOptions, UserInfo, EncryptedEnvelope, ExportCapability, ExportFormat, ImportCapability, VaultPolicyOnDisk, UserEnvelope } from '../../kernel/types.js';
|
|
2
2
|
import { type EnclaveKey, type EchoSecretParts } from '../../kernel/enclave/index.js';
|
|
3
|
+
import type { KeyringTamperedReason } from '../../kernel/errors.js';
|
|
3
4
|
import { type SecretPolicy, type EchoSecretPolicy } from '../../kernel/validation.js';
|
|
4
5
|
import type { DeviceSealProvider } from './device-seal.js';
|
|
5
6
|
/** In-memory representation of an unlocked keyring. */
|
|
@@ -9,6 +10,11 @@ export interface UnlockedKeyring {
|
|
|
9
10
|
readonly role: Role;
|
|
10
11
|
readonly permissions: Permissions;
|
|
11
12
|
readonly deks: Map<string, EnclaveKey>;
|
|
13
|
+
/**
|
|
14
|
+
* Unwrapped counterpart of {@link KeyringFile.pending_deks} — an
|
|
15
|
+
* uncommitted rotation (#1074). Empty in the normal state.
|
|
16
|
+
*/
|
|
17
|
+
readonly pendingDeks?: Map<string, EnclaveKey> | undefined;
|
|
12
18
|
/**
|
|
13
19
|
* The KEK, when this keyring was unlocked via tier 1 (secret) or
|
|
14
20
|
* a wrap-KEK tier-2 method (WebAuthn / OIDC). `null` when the
|
|
@@ -72,6 +78,23 @@ export interface UnlockedKeyring {
|
|
|
72
78
|
}
|
|
73
79
|
/** Mint a fresh wrapped-canary string. Deterministic for a given KEK. */
|
|
74
80
|
export declare function mintKeyringCanary(kek: EnclaveKey): Promise<string>;
|
|
81
|
+
/**
|
|
82
|
+
* The vault roster key held by this keyring, or `null` when the keyring
|
|
83
|
+
* carries none.
|
|
84
|
+
*
|
|
85
|
+
* Null is expected on the resume-style paths (`kek: null` sessions, tier-3
|
|
86
|
+
* PIN resume, plaintext mode) — none of which may write a keyring file.
|
|
87
|
+
* Every stamping site null-guards this exactly as it guards `kek`: minting a
|
|
88
|
+
* file without a verifiable `roster_tag` would be worse than refusing, since
|
|
89
|
+
* it is indistinguishable on the next load from a store having stripped it.
|
|
90
|
+
*/
|
|
91
|
+
export declare function rosterKeyOf(keyring: UnlockedKeyring): EnclaveKey | null;
|
|
92
|
+
/**
|
|
93
|
+
* Shared wording for the stamping-site guards — mirrors the `kek` guard's shape.
|
|
94
|
+
* Exported so every roster-stamping site in the hub raises ONE error with one
|
|
95
|
+
* wording, rather than each hand-copying it (`peer-recover`, `liberate`).
|
|
96
|
+
*/
|
|
97
|
+
export declare function requireRosterKey(keyring: UnlockedKeyring, fn: string): EnclaveKey;
|
|
75
98
|
/** Options for {@link loadKeyring} (#846b). */
|
|
76
99
|
export interface LoadKeyringOptions {
|
|
77
100
|
/** The user whose keyring to unlock. */
|
|
@@ -168,6 +191,100 @@ export declare function createOwnerKeyring(store: NoydbStore, vault: string, opt
|
|
|
168
191
|
export declare function grant(store: NoydbStore, vault: string, callerKeyring: UnlockedKeyring, options: GrantOptions): Promise<void>;
|
|
169
192
|
/** Revoke a user's access. Optionally rotate keys for affected collections. */
|
|
170
193
|
export declare function revoke(store: NoydbStore, vault: string, callerKeyring: UnlockedKeyring, options: RevokeOptions): Promise<void>;
|
|
194
|
+
/** What {@link verifyRoster} found. */
|
|
195
|
+
export interface RosterVerifyResult {
|
|
196
|
+
/**
|
|
197
|
+
* How many `_keyring` files were examined.
|
|
198
|
+
*
|
|
199
|
+
* Reported first, and deliberately: "nothing unverified" is equally true of a
|
|
200
|
+
* sweep that examined nothing, and a roster check that silently covered zero
|
|
201
|
+
* members would look identical to a healthy vault. Same lesson as the vault
|
|
202
|
+
* head's `no-expectations` verdict (#1101).
|
|
203
|
+
*/
|
|
204
|
+
readonly checked: number;
|
|
205
|
+
/** The files that failed authentication, and why. */
|
|
206
|
+
readonly unverified: ReadonlyArray<{
|
|
207
|
+
readonly userId: string;
|
|
208
|
+
readonly reason: KeyringTamperedReason;
|
|
209
|
+
}>;
|
|
210
|
+
}
|
|
211
|
+
export declare function verifyRoster(store: NoydbStore, vault: string, callerKeyring: UnlockedKeyring): Promise<RosterVerifyResult>;
|
|
212
|
+
/** What {@link quarantineKeyring} did. */
|
|
213
|
+
export interface QuarantineResult {
|
|
214
|
+
readonly userId: string;
|
|
215
|
+
/** Why the file could not be authenticated — the justification for removing it. */
|
|
216
|
+
readonly reason: KeyringTamperedReason;
|
|
217
|
+
/** Collections re-keyed as part of the removal. */
|
|
218
|
+
readonly rotated: readonly string[];
|
|
219
|
+
/**
|
|
220
|
+
* (member, collection) pairs whose access the rotation dropped — the OTHER
|
|
221
|
+
* members, who must be re-granted.
|
|
222
|
+
*
|
|
223
|
+
* Passed through from `rotateKeys` rather than discarded, because a
|
|
224
|
+
* quarantine rotates broadly (see the scope note on the function) and so
|
|
225
|
+
* de-provisions more people than the one being removed. An operator who is
|
|
226
|
+
* not told this discovers it as unrelated `NoAccessError`s later.
|
|
227
|
+
*/
|
|
228
|
+
readonly needsRegrant: RotateResult['needsRegrant'];
|
|
229
|
+
/**
|
|
230
|
+
* OTHER members whose own files also failed authentication, found while
|
|
231
|
+
* rotating. One forged file is rarely the only one, and the operator is
|
|
232
|
+
* already holding the tool for them.
|
|
233
|
+
*/
|
|
234
|
+
readonly alsoUnverified: RotateResult['unverified'];
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Remove a `_keyring` file that cannot be authenticated, and re-key behind it
|
|
238
|
+
* (#1121).
|
|
239
|
+
*
|
|
240
|
+
* ## Why this is not a flag on `revoke`
|
|
241
|
+
*
|
|
242
|
+
* `revoke` reads the target's own `role` to decide whether the caller may
|
|
243
|
+
* revoke them, so it cannot act on a file it will not trust — which left a
|
|
244
|
+
* forged file removable only by editing the store by hand. Relaxing `revoke`
|
|
245
|
+
* conditionally would grow the safe path a parameter that turns it into the
|
|
246
|
+
* dangerous one; ADR 0003's standing rule is that if the implementation needs
|
|
247
|
+
* to weaken a guard, the design is wrong. This is a separate operation with its
|
|
248
|
+
* own contract, so `revoke`'s invariant stays absolute and the dangerous act is
|
|
249
|
+
* named at the call site rather than hidden in an option bag.
|
|
250
|
+
*
|
|
251
|
+
* ## The two properties that keep it from being a backdoor
|
|
252
|
+
*
|
|
253
|
+
* 1. **It refuses a file that verifies.** Otherwise it would delete any keyring
|
|
254
|
+
* while ignoring `canRevoke` — including an owner's, which `revoke` protects
|
|
255
|
+
* unconditionally.
|
|
256
|
+
* 2. **Because of (1) it can safely ignore the claimed `role` — and it must.**
|
|
257
|
+
* `canRevoke` refuses any target whose role reads `owner`, so a store that
|
|
258
|
+
* forged `"role":"owner"` onto its victim would otherwise make them
|
|
259
|
+
* permanently unremovable. Consulting the forged field is exactly the
|
|
260
|
+
* mistake this operation exists to avoid.
|
|
261
|
+
*
|
|
262
|
+
* Owner-only: the narrowest role that can always act, and quarantine
|
|
263
|
+
* deliberately consumes NO field of the file it is removing.
|
|
264
|
+
*
|
|
265
|
+
* ## Why it rotates, and why the scope comes from the CALLER
|
|
266
|
+
*
|
|
267
|
+
* Deleting the file is not a revocation — the store may decline the delete, and
|
|
268
|
+
* the member may already hold unwrapped DEKs. So this rotates, exactly as
|
|
269
|
+
* `revoke` does. The scope is every collection the CALLER holds, not the
|
|
270
|
+
* target's DEK map: that map is unauthenticated (#1115), so deriving the scope
|
|
271
|
+
* from it would let the store choose which collections survive a quarantine.
|
|
272
|
+
*
|
|
273
|
+
* ⚠️ **That is the security-correct scope, and it is NOT free.** An earlier
|
|
274
|
+
* draft of this comment called over-rotating "the safe direction"; a review
|
|
275
|
+
* probe disproved it. Rotation re-keys `store.list(vault, <name>)` plus the
|
|
276
|
+
* derived refs `rotateKeys` knows about, so a DEK slot whose ciphertext lives
|
|
277
|
+
* under a *different* collection name — `_blob`, whose data sits in
|
|
278
|
+
* `_blob_index`/`_blob_chunks`, and the `collection#tier` slots — is re-keyed
|
|
279
|
+
* without its data being re-encrypted, and that data then fails to open. That
|
|
280
|
+
* gap belongs to `rotateKeys` (it is reachable through an ordinary `revoke` of
|
|
281
|
+
* a whole-vault grantee, with no quarantine involved) and is filed as #1122,
|
|
282
|
+
* but a quarantine takes the maximal scope *unconditionally*, so it meets the
|
|
283
|
+
* gap every time rather than occasionally. Until that is fixed, treat a
|
|
284
|
+
* quarantine as an emergency operation with a real blast radius, and read
|
|
285
|
+
* `needsRegrant` afterwards.
|
|
286
|
+
*/
|
|
287
|
+
export declare function quarantineKeyring(store: NoydbStore, vault: string, callerKeyring: UnlockedKeyring, userId: string): Promise<QuarantineResult>;
|
|
171
288
|
/**
|
|
172
289
|
* Mutate `role`, `displayName`, and/or `permissions` on an existing
|
|
173
290
|
* keyring. Pure plaintext-header rewrite — no DEK rewrap, no KEK
|
|
@@ -217,6 +334,26 @@ export interface RotateResult {
|
|
|
217
334
|
readonly userId: string;
|
|
218
335
|
readonly collection: string;
|
|
219
336
|
}>;
|
|
337
|
+
/**
|
|
338
|
+
* Members skipped because their `_keyring` file failed roster verification
|
|
339
|
+
* (#1114).
|
|
340
|
+
*
|
|
341
|
+
* Rotation hands a member re-wrapped DEKs, so skipping one gives them
|
|
342
|
+
* **less**, never more: the file is left untouched and its wrappings for the
|
|
343
|
+
* rotated collections go stale. That is the same fail-closed end state as
|
|
344
|
+
* `needsRegrant`, but it needs a different remedy and so gets a different
|
|
345
|
+
* field — a `needsRegrant` entry is fixed by `grant()`, whereas one of these
|
|
346
|
+
* is a file that no longer authenticates and cannot be repaired by granting
|
|
347
|
+
* over it.
|
|
348
|
+
*
|
|
349
|
+
* Before this existed, one such file threw and took `revoke` and
|
|
350
|
+
* `rotateKeys` down vault-wide — the two operations most needed when a
|
|
351
|
+
* roster is suspect.
|
|
352
|
+
*/
|
|
353
|
+
readonly unverified: ReadonlyArray<{
|
|
354
|
+
readonly userId: string;
|
|
355
|
+
readonly reason: KeyringTamperedReason;
|
|
356
|
+
}>;
|
|
220
357
|
}
|
|
221
358
|
/** Options for {@link rotateKeys} (#846b — was a bare `string[]`). */
|
|
222
359
|
export interface RotateKeysOptions {
|
|
@@ -261,7 +398,7 @@ export interface EchoRecipientSecret extends EchoSecretParts {
|
|
|
261
398
|
*
|
|
262
399
|
* @public
|
|
263
400
|
*/
|
|
264
|
-
export interface
|
|
401
|
+
export interface PodRecipient {
|
|
265
402
|
/** User id stamped onto the keyring file in the bundle. */
|
|
266
403
|
readonly id: string;
|
|
267
404
|
/** Optional display name. Defaults to `id`. */
|
|
@@ -312,7 +449,7 @@ export interface BundleRecipient {
|
|
|
312
449
|
*
|
|
313
450
|
* @internal
|
|
314
451
|
*/
|
|
315
|
-
export declare function buildRecipientKeyringFile(callerKeyring: UnlockedKeyring, recipient:
|
|
452
|
+
export declare function buildRecipientKeyringFile(callerKeyring: UnlockedKeyring, recipient: PodRecipient): Promise<KeyringFile>;
|
|
316
453
|
/** List all users with access to a vault. */
|
|
317
454
|
export declare function listUsers(store: NoydbStore, vault: string): Promise<UserInfo[]>;
|
|
318
455
|
/**
|
|
@@ -368,8 +505,17 @@ export declare function listUsersWithEnvelopes<T = unknown>(store: NoydbStore, v
|
|
|
368
505
|
user: UserInfo;
|
|
369
506
|
envelope: UserEnvelope<T> | null;
|
|
370
507
|
}>>;
|
|
371
|
-
/** Ensure a DEK exists for a collection. Generates one if new. */
|
|
372
508
|
export declare function ensureCollectionDEK(store: NoydbStore, vault: string, keyring: UnlockedKeyring): Promise<(collectionName: string) => Promise<EnclaveKey>>;
|
|
509
|
+
/**
|
|
510
|
+
* The `Permissions` catch-all key (#1010). `Permissions` has always documented
|
|
511
|
+
* `'*'` as "the wildcard collection matching all collections in the vault", but
|
|
512
|
+
* nothing expanded it — a grantee handed the documented catch-all got no keys
|
|
513
|
+
* at all. It is honoured in three places, and they must agree: the DEK wrapping
|
|
514
|
+
* in `grant()`, and both permission checks below.
|
|
515
|
+
*/
|
|
516
|
+
export declare const PERMISSION_WILDCARD = "*";
|
|
517
|
+
/** Does this permission map hand over the whole vault? */
|
|
518
|
+
export declare function permissionsAreWildcard(permissions: Permissions | undefined): boolean;
|
|
373
519
|
/** Check if a user has write permission for a collection. */
|
|
374
520
|
export declare function hasWritePermission(keyring: UnlockedKeyring, collectionName: string): boolean;
|
|
375
521
|
/** Check if a user has any access to a collection. */
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* Internal service — reached through `noydb.team.rotateSecret(...)` etc.
|
|
20
20
|
*/
|
|
21
21
|
import type { NoydbOptions, NoydbStore, KeyringAuthenticator } from '../../kernel/types.js';
|
|
22
|
-
import type { RotateResult, RotateKeysOptions } from './keyring.js';
|
|
22
|
+
import type { RotateResult, RotateKeysOptions, RosterVerifyResult, QuarantineResult } from './keyring.js';
|
|
23
23
|
import { type RotateSecretInput, type RecoverSecretInput, type RecoverSecretResult, type RotateRecoveryOptions, type RotateRecoveryResult, type EnrollRecoveryResult, type RecoveryEnrollmentInput, type RecoveryProof } from './rotate-recover.js';
|
|
24
24
|
import { type RecoverUserOptions } from './peer-recover.js';
|
|
25
25
|
import { type PaperRecoveryEntry, type ShamirRecoveryEntry } from './recovery.js';
|
|
@@ -74,6 +74,10 @@ export declare class TeamFacade {
|
|
|
74
74
|
runRevoke(engine: (adapter: NoydbStore, vault: string, callerKeyring: UnlockedKeyring, options: RevokeOptions) => Promise<void>, vault: string, options: RevokeOptions, factors?: FactorProofBundle): Promise<void>;
|
|
75
75
|
/** Gate + run a `rotateKeys` engine. See `Noydb.rotate` for the public contract. */
|
|
76
76
|
runRotate(engine: (store: NoydbStore, vault: string, callerKeyring: UnlockedKeyring, opts: RotateKeysOptions) => Promise<RotateResult>, vault: string, collections: string[]): Promise<RotateResult>;
|
|
77
|
+
/** Gate + run the `verifyRoster` engine (#1121). See `Noydb.verifyRoster`. */
|
|
78
|
+
runVerifyRoster(engine: (store: NoydbStore, vault: string, callerKeyring: UnlockedKeyring) => Promise<RosterVerifyResult>, vault: string): Promise<RosterVerifyResult>;
|
|
79
|
+
/** Gate + run the `quarantineKeyring` engine (#1121). See `Noydb.quarantineKeyring`. */
|
|
80
|
+
runQuarantine(engine: (store: NoydbStore, vault: string, callerKeyring: UnlockedKeyring, userId: string) => Promise<QuarantineResult>, vault: string, userId: string, factors?: FactorProofBundle): Promise<QuarantineResult>;
|
|
77
81
|
/**
|
|
78
82
|
* Add a tier-2 authenticator slot to the calling user's keyring.
|
|
79
83
|
* Each slot independently wraps the SAME KEK under a method-specific
|