@noy-db/hub 0.9.0-pre.0 → 0.9.0-pre.2
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 +39 -0
- package/dist/api-H4B7ZQXP.js +18 -0
- package/dist/as/index.js +10 -10
- package/dist/at/index.js +8 -8
- package/dist/attestation/index.js +18 -18
- package/dist/{backup-7RKNZMQO.js → backup-E3GBMNDA.js} +92 -31
- package/dist/backup-E3GBMNDA.js.map +1 -0
- package/dist/blobs/index.js +12 -12
- package/dist/broker/index.js +13 -13
- package/dist/by/index.js +2 -2
- package/dist/capsule/contract.js +6 -6
- package/dist/capsule/enclave-aes/crypto.d.ts +18 -0
- package/dist/capsule/enclave-aes/index.d.ts +2 -2
- package/dist/capsule/enclave-aes/index.js +14 -8
- package/dist/capsule/enclave-aes/index.js.map +1 -1
- package/dist/capsule/index.d.ts +1 -1
- package/dist/{capsule-57BDK7LG.js → capsule-YQKQZPH7.js} +14 -8
- package/dist/cargo/index.js +35 -35
- package/dist/{chunk-AJFPAHMW.js → chunk-27NCEPKM.js} +3 -3
- package/dist/{chunk-PGC35KXE.js → chunk-2IASHJPS.js} +2 -2
- package/dist/{chunk-NYJBYVBG.js → chunk-2ODEFG6K.js} +4 -4
- package/dist/{chunk-7BMOS4JQ.js → chunk-2QH3I7QC.js} +11 -11
- package/dist/{chunk-VSUQI5Q6.js → chunk-2RH5SEY7.js} +16 -2
- package/dist/chunk-2RH5SEY7.js.map +1 -0
- package/dist/{chunk-IVMFIKNA.js → chunk-2T2TGRWE.js} +6 -6
- package/dist/{chunk-G66YXUTY.js → chunk-35CNOVQE.js} +3 -3
- package/dist/{chunk-OJU67C23.js → chunk-3EXQXOQ2.js} +4 -4
- package/dist/{chunk-BJH77UY2.js → chunk-4KYKRYRT.js} +2 -2
- package/dist/{chunk-RDOEOPOI.js → chunk-4N4OIVK3.js} +5 -5
- package/dist/{chunk-WHOKGHJ3.js → chunk-4WLI37WK.js} +7 -7
- package/dist/{chunk-RNACRT5H.js → chunk-52ZFNK46.js} +2 -2
- package/dist/{chunk-CB4467G3.js → chunk-5A3HOTP5.js} +33 -7
- package/dist/chunk-5A3HOTP5.js.map +1 -0
- package/dist/{chunk-QDHHHI5Q.js → chunk-5SMCBPJ2.js} +5 -5
- package/dist/{chunk-EMAWOGVH.js → chunk-654RE5YC.js} +3 -3
- package/dist/{chunk-FZXRLNJO.js → chunk-6BEBWHNL.js} +3 -3
- package/dist/{chunk-EUD3HQM4.js → chunk-6WEPFEMJ.js} +4 -4
- package/dist/{chunk-YFFMPZPY.js → chunk-6WIFF46H.js} +2 -2
- package/dist/{chunk-ZVSKSUGI.js → chunk-7C7OF26T.js} +5 -5
- package/dist/{chunk-QXJXG7DN.js → chunk-7IV7GVOS.js} +5 -5
- package/dist/{chunk-MQ7YWBQ5.js → chunk-7JRLCP2J.js} +2 -2
- package/dist/{chunk-QSHATAXJ.js → chunk-7ONMS7QI.js} +2 -2
- package/dist/{chunk-JBMMWYOH.js → chunk-7UHLO4ZN.js} +35 -2
- package/dist/chunk-7UHLO4ZN.js.map +1 -0
- package/dist/{chunk-6WS35E6X.js → chunk-A52BK5AY.js} +2 -2
- package/dist/{chunk-GOJQ5DZA.js → chunk-AI35LNWQ.js} +4 -4
- package/dist/chunk-AI35LNWQ.js.map +1 -0
- package/dist/{chunk-XXQ5XIYY.js → chunk-AMSSAOOB.js} +2 -2
- package/dist/{chunk-3V6LZHUO.js → chunk-AYOQZJDB.js} +2 -2
- package/dist/{chunk-DL6BZKP3.js → chunk-B3B6HV5S.js} +2 -2
- package/dist/{chunk-5XONHAFD.js → chunk-B6EWMGFX.js} +2 -2
- package/dist/{chunk-6Y5E4SJU.js → chunk-BMAXBTYH.js} +5 -5
- package/dist/{chunk-LGGIFKJP.js → chunk-BNYDOF2Q.js} +4 -4
- package/dist/{chunk-XXNWU5QZ.js → chunk-BQJ5ORU5.js} +2 -2
- package/dist/{chunk-Z3ZXVB2Y.js → chunk-BSEPI3HD.js} +12 -12
- package/dist/chunk-BSEPI3HD.js.map +1 -0
- package/dist/{chunk-BYHCKX73.js → chunk-CLOSXHR4.js} +3 -3
- package/dist/{chunk-5HNW4ZTA.js → chunk-CSAN22QG.js} +6 -6
- package/dist/{chunk-TZYTMZZY.js → chunk-DL4GCSTS.js} +10 -10
- package/dist/{chunk-EA4VDI5D.js → chunk-DYIR6RC3.js} +4 -4
- package/dist/{chunk-PUBI455O.js → chunk-EPPAEGH5.js} +2 -2
- package/dist/{chunk-2A56DSRI.js → chunk-EQ6C2ZPT.js} +17 -51
- package/dist/chunk-EQ6C2ZPT.js.map +1 -0
- package/dist/{chunk-BNFNQNEP.js → chunk-F7X7MPK4.js} +2 -2
- package/dist/{chunk-SNM7LSYG.js → chunk-FUHUGKDN.js} +4 -4
- package/dist/{chunk-72XBVN4J.js → chunk-FVKQ5QUC.js} +2 -2
- package/dist/chunk-FVKQ5QUC.js.map +1 -0
- package/dist/{chunk-D4V5JJAK.js → chunk-GHMINSER.js} +4 -4
- package/dist/{chunk-APFFJN5T.js → chunk-GLSCL74M.js} +31 -34
- package/dist/chunk-GLSCL74M.js.map +1 -0
- package/dist/{chunk-XKBTJGFP.js → chunk-GU6QXHPZ.js} +3 -3
- package/dist/chunk-GU6QXHPZ.js.map +1 -0
- package/dist/{chunk-QGFEBNHO.js → chunk-GZISWBCJ.js} +4 -4
- package/dist/{chunk-OM3SEDI4.js → chunk-HTRLQ4ZZ.js} +4 -4
- package/dist/{chunk-SWXLZ4HX.js → chunk-ICHHNI5E.js} +8 -8
- package/dist/{chunk-K673OO6B.js → chunk-ID4ZBC3X.js} +4 -4
- package/dist/{chunk-H3YM66EI.js → chunk-IF2M43G4.js} +2 -2
- package/dist/{chunk-QGSNJD3B.js → chunk-IFUYLIEY.js} +2 -2
- package/dist/{chunk-D5A3GCZ4.js → chunk-IPF5ORDI.js} +3 -3
- package/dist/{delegation-ONLM4JFI.js → chunk-JQMEXCUZ.js} +59 -16
- package/dist/chunk-JQMEXCUZ.js.map +1 -0
- package/dist/{chunk-TFWFPZRU.js → chunk-K5JNK63R.js} +11 -11
- package/dist/{chunk-TFWFPZRU.js.map → chunk-K5JNK63R.js.map} +1 -1
- package/dist/{chunk-BVF3SXD7.js → chunk-KBIS64X4.js} +5 -5
- package/dist/chunk-L4UL4IAR.js +55 -0
- package/dist/chunk-L4UL4IAR.js.map +1 -0
- package/dist/{chunk-RIZTZJX6.js → chunk-LJ744WXU.js} +2 -2
- package/dist/{chunk-XITHENBI.js → chunk-LMC5L3MM.js} +7 -7
- package/dist/{chunk-XITHENBI.js.map → chunk-LMC5L3MM.js.map} +1 -1
- package/dist/{chunk-L5A3KR7R.js → chunk-LUQBG637.js} +3 -3
- package/dist/{chunk-6QLCS7ET.js → chunk-LZN6DTFI.js} +2 -2
- package/dist/{chunk-NIXRB5BP.js → chunk-MMWX5OT5.js} +2 -2
- package/dist/{chunk-JA25QG5M.js → chunk-N6EWQ5VB.js} +622 -119
- package/dist/chunk-N6EWQ5VB.js.map +1 -0
- package/dist/{chunk-UOZOWN73.js → chunk-ND6S2DKC.js} +2 -2
- package/dist/{chunk-WFWFXDNS.js → chunk-NHEKQWFI.js} +2 -2
- package/dist/{chunk-2ZFD2UJC.js → chunk-NIUHKKMM.js} +9 -9
- package/dist/{chunk-XA34THLF.js → chunk-NK4LGBGQ.js} +4 -4
- package/dist/{chunk-JSWKVZCR.js → chunk-NUZ7ROUZ.js} +2 -2
- package/dist/{chunk-DHU2AQ6T.js → chunk-O3NGOHXQ.js} +2 -2
- package/dist/{chunk-ZBUAX4EF.js → chunk-O6VOR4NH.js} +2 -2
- package/dist/{chunk-JZ4EDEIP.js → chunk-ODBOHPZU.js} +3 -3
- package/dist/{chunk-5UUJE4FP.js → chunk-OK44MD3C.js} +2 -2
- package/dist/{chunk-ECGXA4LT.js → chunk-OR3OHKU6.js} +2 -2
- package/dist/{chunk-ZWF3EWZA.js → chunk-P6FATPXQ.js} +2 -2
- package/dist/{chunk-PCYPXLEX.js → chunk-PBEHTFUG.js} +6 -6
- package/dist/{chunk-7CT6SX4M.js → chunk-PFHDQY5L.js} +3 -3
- package/dist/{chunk-PTJY5R3O.js → chunk-PIO6NW7O.js} +2 -2
- package/dist/{chunk-TMIJAR2X.js → chunk-PREYKC76.js} +3 -3
- package/dist/{chunk-ZHQJAV6D.js → chunk-PU5ZEV65.js} +2 -2
- package/dist/{chunk-UNSQZSZP.js → chunk-PWAMX5KU.js} +2 -2
- package/dist/{chunk-GETUTTZU.js → chunk-PZN76MMV.js} +4 -4
- package/dist/{chunk-ABU6A4Z5.js → chunk-Q4DBU5RM.js} +2 -2
- package/dist/{chunk-2WJKJZSO.js → chunk-QHG7GQKM.js} +2 -2
- package/dist/{chunk-UAKY6E4N.js → chunk-QNOWNCZS.js} +2 -2
- package/dist/{chunk-JPSL5GIZ.js → chunk-QQLXKDGC.js} +3 -3
- package/dist/{chunk-45VHWE4C.js → chunk-QVUMKG3Z.js} +271 -69
- package/dist/chunk-QVUMKG3Z.js.map +1 -0
- package/dist/{chunk-OK57EATL.js → chunk-R4GLRJ55.js} +2 -2
- package/dist/{chunk-B65CC6Z6.js → chunk-RF5WDM25.js} +2 -2
- package/dist/{chunk-G46JSSVX.js → chunk-RKBCUP5D.js} +7 -7
- package/dist/{chunk-GCUMOKTN.js → chunk-S2ORTQGS.js} +3 -3
- package/dist/{chunk-MRJDLXI3.js → chunk-SVXFCCSX.js} +8 -8
- package/dist/{chunk-BUE7R3B5.js → chunk-SXPLIRQH.js} +2 -2
- package/dist/{chunk-5LMCVBMY.js → chunk-T5EXREMW.js} +5 -5
- package/dist/{chunk-PT2YCQVK.js → chunk-TBVDI3LY.js} +4 -4
- package/dist/{chunk-BMHQHH7Q.js → chunk-TLIFNRU5.js} +2 -2
- package/dist/{chunk-YKGJ44Z7.js → chunk-TU6ZJTYT.js} +3 -3
- package/dist/{chunk-FSQNGPHH.js → chunk-U277K5GR.js} +612 -175
- package/dist/chunk-U277K5GR.js.map +1 -0
- package/dist/{chunk-55P6OBB7.js → chunk-U43RSPPX.js} +2 -2
- package/dist/{chunk-K7RW7FI4.js → chunk-UADW5NOU.js} +5 -5
- package/dist/{chunk-GRS2HIV6.js → chunk-UMV5GBTJ.js} +2 -2
- package/dist/{chunk-4UIP3QNW.js → chunk-UNAMWK2Q.js} +2 -2
- package/dist/{chunk-J4KAPKBJ.js → chunk-UORWAG7K.js} +2 -2
- package/dist/{chunk-V55JASXO.js → chunk-UQRKAM2R.js} +3 -3
- package/dist/{chunk-2ELOCEXE.js → chunk-URGHKZPL.js} +1 -1
- package/dist/chunk-URGHKZPL.js.map +1 -0
- package/dist/{chunk-ZMVSKYTJ.js → chunk-VLRY2UH4.js} +10 -10
- package/dist/{chunk-SPPOUJLN.js → chunk-VZFTON37.js} +2 -2
- package/dist/{chunk-CAD7N6HQ.js → chunk-WIUH6EJ7.js} +10 -10
- package/dist/chunk-WIUH6EJ7.js.map +1 -0
- package/dist/{chunk-YQFBH5ZJ.js → chunk-WQUIJPN4.js} +3 -3
- package/dist/{chunk-4J3MNVVX.js → chunk-WRLWEYHY.js} +7 -1
- package/dist/{chunk-4J3MNVVX.js.map → chunk-WRLWEYHY.js.map} +1 -1
- package/dist/{chunk-NZULV7LK.js → chunk-WVQDY3UM.js} +4 -4
- package/dist/{chunk-3Y5JLSXS.js → chunk-X5RGG3ZW.js} +2 -2
- package/dist/{chunk-PFCTSXHU.js → chunk-X6Z2SIRF.js} +2 -2
- package/dist/{chunk-UHFGK6YA.js → chunk-XQGKS4OW.js} +3 -3
- package/dist/{chunk-L2F3CFCH.js → chunk-Y22JWHCP.js} +4 -4
- package/dist/{chunk-C53ER7AG.js → chunk-YVA6UPRN.js} +2 -2
- package/dist/{chunk-226V6XXJ.js → chunk-Z2KP6PNF.js} +6 -6
- package/dist/{chunk-G5EDYVSE.js → chunk-ZK2WT532.js} +5 -5
- package/dist/{chunk-SFCD6OU7.js → chunk-ZNVBCKMV.js} +2 -2
- package/dist/{chunk-BU2ABHFW.js → chunk-ZOFNZLAA.js} +4 -4
- package/dist/{chunk-X2RP4TO5.js → chunk-ZVJKHGE5.js} +7 -7
- package/dist/classified/index.js +5 -5
- package/dist/{classified-marker-KHDOYIJB.js → classified-marker-7HXDMYHI.js} +3 -3
- package/dist/collection-facade-V63BEBGU.js +41 -0
- package/dist/{computed-XMFTHAXV.js → computed-LZLSYOPG.js} +3 -3
- package/dist/consent/index.js +8 -8
- package/dist/cover/index.js +8 -8
- package/dist/custody/index.js +12 -12
- package/dist/{dead-filter-CXV5NS67.js → dead-filter-PZIJ4F4G.js} +10 -10
- package/dist/debug/index.js +7 -7
- package/dist/delegation-7SSGIETH.js +26 -0
- package/dist/derivations/index.js +22 -22
- package/dist/derive-IMI3BMDS.js +20 -0
- package/dist/directory/index.js +9 -9
- package/dist/{dispatch-2MQFMEGY.js → dispatch-4BUYPWMJ.js} +19 -19
- package/dist/{dispatch-OFDA4WQV.js → dispatch-KOPDDPEQ.js} +5 -5
- package/dist/executor-7SY3M6TZ.js +8 -0
- package/dist/executor-SNHW4ELF.js +35 -0
- package/dist/executor-Z3IKK7G3.js +8 -0
- package/dist/export-accessible-O7DIVFUO.js +22 -0
- package/dist/extract-partition-ELZEJKXM.js +35 -0
- package/dist/{fanout-sidecar-BO67PCPO.js → fanout-sidecar-FYDRL7F3.js} +8 -8
- package/dist/find-KWB2RYWJ.js +10 -0
- package/dist/forget/index.js +8 -8
- package/dist/guards/index.js +4 -4
- package/dist/history/index.js +15 -13
- package/dist/history/index.js.map +1 -1
- package/dist/i18n/index.js +13 -13
- package/dist/index.d.ts +3 -2
- package/dist/index.js +111 -107
- package/dist/index.js.map +1 -1
- package/dist/indexing/index.js +5 -5
- package/dist/introspection/index.js +10 -10
- package/dist/issue-5ZHXK4HJ.js +19 -0
- package/dist/kernel/collection.d.ts +85 -6
- package/dist/kernel/constants.d.ts +7 -0
- package/dist/kernel/errors.d.ts +9 -0
- package/dist/kernel/merge-authority.d.ts +5 -1
- package/dist/kernel/noydb.d.ts +116 -21
- package/dist/kernel/rejection-seal.d.ts +13 -0
- package/dist/kernel/sync-wiring.d.ts +55 -0
- package/dist/kernel/types.d.ts +366 -8
- package/dist/kernel/vault.d.ts +39 -5
- package/dist/{ledger-MSJGWKGW.js → ledger-UFJCB6T5.js} +10 -10
- package/dist/liberate-OEOSNNFH.js +25 -0
- package/dist/{link-set-QXXSPPHL.js → link-set-KMUBFN2L.js} +10 -10
- package/dist/{managed-secret-VSK7ANQI.js → managed-secret-H5WYSJ46.js} +9 -9
- package/dist/materialized-views/index.js +25 -25
- package/dist/{migrate-cek-GEBFYBDC.js → migrate-cek-SPESQAAO.js} +2 -2
- package/dist/money/index.js +5 -5
- package/dist/noydb-QDZ4QIKO.js +100 -0
- package/dist/on/index.js +12 -12
- package/dist/overlay-views/index.js +4 -4
- package/dist/periods/index.js +11 -11
- package/dist/pod/index.js +66 -64
- package/dist/{pod-handle-YE7CT66T.js → pod-handle-GJLCOUGK.js} +8 -8
- package/dist/policy/index.js +9 -9
- package/dist/port/at/index.d.ts +1 -1
- package/dist/port/by/index.d.ts +1 -1
- package/dist/port/on/index.d.ts +1 -1
- package/dist/port/with/admission-authority.d.ts +34 -0
- package/dist/port/with/broker-strategy.d.ts +10 -0
- package/dist/port/with/rejection-courier.d.ts +37 -0
- package/dist/port/with/restore-host.d.ts +33 -0
- package/dist/port/with/service-bus.d.ts +18 -0
- package/dist/port/with/team-strategy.d.ts +2 -2
- package/dist/port/with/write-hooks.d.ts +2 -0
- package/dist/portability/index.js +8 -8
- package/dist/{post-register-QC5TEAW3.js → post-register-2AC2STHC.js} +6 -6
- package/dist/query/all/index.js +15 -15
- package/dist/query/index.js +7 -7
- package/dist/query/live/index.js +7 -7
- package/dist/query/reduce/index.js +10 -10
- package/dist/query/relate/index.js +9 -9
- package/dist/reduce/index.js +8 -8
- package/dist/register-PIORIMMR.js +30 -0
- package/dist/registry-BIMICFUH.js +23 -0
- package/dist/registry-JGWLW53D.js +35 -0
- package/dist/registry-SELCBYEQ.js +8 -0
- package/dist/registry-W327UNYH.js +8 -0
- package/dist/request-withdrawal-K3SXXODI.js +28 -0
- package/dist/restore-to-OOPKLAPU.js +66 -0
- package/dist/restore-to-OOPKLAPU.js.map +1 -0
- package/dist/{reveal-YQTRNQFH.js → reveal-UAPBG743.js} +7 -7
- package/dist/revoke-6AFVXTWF.js +24 -0
- package/dist/satellites/index.js +1 -1
- package/dist/schema-update/index.js +2 -2
- package/dist/sealed-record/index.js +11 -11
- package/dist/search/index.js +4 -4
- package/dist/{seed-JMQTRKRE.js → seed-BVYDPVIW.js} +33 -18
- package/dist/seed-BVYDPVIW.js.map +1 -0
- package/dist/sequence/index.js +8 -8
- package/dist/session/index.js +8 -8
- package/dist/shadow/index.js +2 -2
- package/dist/signer-TW5MAQJP.js +23 -0
- package/dist/snapshots/index.js +9 -9
- package/dist/{stale-SKV33PBU.js → stale-CROGJBIJ.js} +9 -9
- package/dist/storage-SO2L2Z5J.js +21 -0
- package/dist/{store-coordination-provider-Z6HKPOGM.js → store-coordination-provider-2YD2PTTP.js} +9 -9
- package/dist/sync/index.js +16 -16
- package/dist/sync/index.js.map +1 -1
- package/dist/team/index.js +15 -15
- package/dist/tiers/index.js +10 -10
- package/dist/to/index.js +2 -2
- package/dist/transactions/index.js +3 -3
- package/dist/util/index.js +1 -1
- package/dist/vault-head/index.js +7 -7
- package/dist/{verify-KWQIWLGH.js → verify-QWO5UKD6.js} +7 -7
- package/dist/walk-3KEOL7BY.js +20 -0
- package/dist/with-audit/guards/types.d.ts +2 -0
- package/dist/with-audit/tiers/index.d.ts +5 -5
- package/dist/with-commit/history/history.d.ts +16 -0
- package/dist/with-commit/history/restore-to.d.ts +40 -0
- package/dist/with-party/broker/seed.d.ts +4 -0
- package/dist/with-party/custody/strategy.d.ts +2 -2
- package/dist/with-party/team/delegation.d.ts +41 -11
- package/dist/with-party/team/index.d.ts +2 -0
- package/dist/with-party/team/keyring.d.ts +133 -3
- package/dist/with-party/team/managed-secret.d.ts +1 -1
- package/dist/with-party/team/noydb-facade.d.ts +14 -2
- package/dist/with-party/team/roster-tag.d.ts +1 -1
- package/dist/with-pod/backup.d.ts +9 -17
- package/dist/with-sync/active.d.ts +28 -1
- package/dist/with-sync/engine.d.ts +59 -2
- package/dist/with-sync/index.d.ts +1 -0
- package/dist/with-sync/reserved-mirror.d.ts +27 -4
- package/dist/with-sync/strategy.d.ts +2 -0
- package/dist/withdraw-accessible-OZU525ND.js +25 -0
- package/dist/withdraw-accessible-OZU525ND.js.map +1 -0
- package/package.json +3 -3
- package/dist/api-MSJXVYQG.js +0 -18
- package/dist/backup-7RKNZMQO.js.map +0 -1
- package/dist/chunk-2A56DSRI.js.map +0 -1
- package/dist/chunk-2ELOCEXE.js.map +0 -1
- package/dist/chunk-45VHWE4C.js.map +0 -1
- package/dist/chunk-72XBVN4J.js.map +0 -1
- package/dist/chunk-APFFJN5T.js.map +0 -1
- package/dist/chunk-CAD7N6HQ.js.map +0 -1
- package/dist/chunk-CB4467G3.js.map +0 -1
- package/dist/chunk-FSQNGPHH.js.map +0 -1
- package/dist/chunk-GOJQ5DZA.js.map +0 -1
- package/dist/chunk-JA25QG5M.js.map +0 -1
- package/dist/chunk-JBMMWYOH.js.map +0 -1
- package/dist/chunk-VSUQI5Q6.js.map +0 -1
- package/dist/chunk-XKBTJGFP.js.map +0 -1
- package/dist/chunk-Z3ZXVB2Y.js.map +0 -1
- package/dist/collection-facade-LZIF7GWD.js +0 -41
- package/dist/delegation-ONLM4JFI.js.map +0 -1
- package/dist/derive-3YSIS36W.js +0 -20
- package/dist/executor-E6YDJ7YA.js +0 -8
- package/dist/executor-NJX3YQQ4.js +0 -35
- package/dist/executor-WWM3DD4P.js +0 -8
- package/dist/export-accessible-RLHU5G4W.js +0 -22
- package/dist/extract-partition-QII2EDCS.js +0 -35
- package/dist/find-6M7GYDUZ.js +0 -10
- package/dist/issue-LPEEEMPP.js +0 -19
- package/dist/liberate-LEKDYKTC.js +0 -25
- package/dist/noydb-F2AUF6KL.js +0 -98
- package/dist/register-SN72QALV.js +0 -30
- package/dist/registry-253FF7C6.js +0 -35
- package/dist/registry-3AZWQTDT.js +0 -23
- package/dist/registry-7UEBTHWG.js +0 -8
- package/dist/registry-IVJ67NFQ.js +0 -8
- package/dist/request-withdrawal-UKVJZKX2.js +0 -28
- package/dist/revoke-G2KXJQA5.js +0 -24
- package/dist/seed-JMQTRKRE.js.map +0 -1
- package/dist/signer-IUIYR3CX.js +0 -23
- package/dist/storage-NPBYP2SM.js +0 -21
- package/dist/walk-F4OLXI5H.js +0 -20
- package/dist/withdraw-accessible-ZKPLZ66E.js +0 -25
- /package/dist/{api-MSJXVYQG.js.map → api-H4B7ZQXP.js.map} +0 -0
- /package/dist/{capsule-57BDK7LG.js.map → capsule-YQKQZPH7.js.map} +0 -0
- /package/dist/{chunk-AJFPAHMW.js.map → chunk-27NCEPKM.js.map} +0 -0
- /package/dist/{chunk-PGC35KXE.js.map → chunk-2IASHJPS.js.map} +0 -0
- /package/dist/{chunk-NYJBYVBG.js.map → chunk-2ODEFG6K.js.map} +0 -0
- /package/dist/{chunk-7BMOS4JQ.js.map → chunk-2QH3I7QC.js.map} +0 -0
- /package/dist/{chunk-IVMFIKNA.js.map → chunk-2T2TGRWE.js.map} +0 -0
- /package/dist/{chunk-G66YXUTY.js.map → chunk-35CNOVQE.js.map} +0 -0
- /package/dist/{chunk-OJU67C23.js.map → chunk-3EXQXOQ2.js.map} +0 -0
- /package/dist/{chunk-BJH77UY2.js.map → chunk-4KYKRYRT.js.map} +0 -0
- /package/dist/{chunk-RDOEOPOI.js.map → chunk-4N4OIVK3.js.map} +0 -0
- /package/dist/{chunk-WHOKGHJ3.js.map → chunk-4WLI37WK.js.map} +0 -0
- /package/dist/{chunk-RNACRT5H.js.map → chunk-52ZFNK46.js.map} +0 -0
- /package/dist/{chunk-QDHHHI5Q.js.map → chunk-5SMCBPJ2.js.map} +0 -0
- /package/dist/{chunk-EMAWOGVH.js.map → chunk-654RE5YC.js.map} +0 -0
- /package/dist/{chunk-FZXRLNJO.js.map → chunk-6BEBWHNL.js.map} +0 -0
- /package/dist/{chunk-EUD3HQM4.js.map → chunk-6WEPFEMJ.js.map} +0 -0
- /package/dist/{chunk-YFFMPZPY.js.map → chunk-6WIFF46H.js.map} +0 -0
- /package/dist/{chunk-ZVSKSUGI.js.map → chunk-7C7OF26T.js.map} +0 -0
- /package/dist/{chunk-QXJXG7DN.js.map → chunk-7IV7GVOS.js.map} +0 -0
- /package/dist/{chunk-MQ7YWBQ5.js.map → chunk-7JRLCP2J.js.map} +0 -0
- /package/dist/{chunk-QSHATAXJ.js.map → chunk-7ONMS7QI.js.map} +0 -0
- /package/dist/{chunk-6WS35E6X.js.map → chunk-A52BK5AY.js.map} +0 -0
- /package/dist/{chunk-XXQ5XIYY.js.map → chunk-AMSSAOOB.js.map} +0 -0
- /package/dist/{chunk-3V6LZHUO.js.map → chunk-AYOQZJDB.js.map} +0 -0
- /package/dist/{chunk-DL6BZKP3.js.map → chunk-B3B6HV5S.js.map} +0 -0
- /package/dist/{chunk-5XONHAFD.js.map → chunk-B6EWMGFX.js.map} +0 -0
- /package/dist/{chunk-6Y5E4SJU.js.map → chunk-BMAXBTYH.js.map} +0 -0
- /package/dist/{chunk-LGGIFKJP.js.map → chunk-BNYDOF2Q.js.map} +0 -0
- /package/dist/{chunk-XXNWU5QZ.js.map → chunk-BQJ5ORU5.js.map} +0 -0
- /package/dist/{chunk-BYHCKX73.js.map → chunk-CLOSXHR4.js.map} +0 -0
- /package/dist/{chunk-5HNW4ZTA.js.map → chunk-CSAN22QG.js.map} +0 -0
- /package/dist/{chunk-TZYTMZZY.js.map → chunk-DL4GCSTS.js.map} +0 -0
- /package/dist/{chunk-EA4VDI5D.js.map → chunk-DYIR6RC3.js.map} +0 -0
- /package/dist/{chunk-PUBI455O.js.map → chunk-EPPAEGH5.js.map} +0 -0
- /package/dist/{chunk-BNFNQNEP.js.map → chunk-F7X7MPK4.js.map} +0 -0
- /package/dist/{chunk-SNM7LSYG.js.map → chunk-FUHUGKDN.js.map} +0 -0
- /package/dist/{chunk-D4V5JJAK.js.map → chunk-GHMINSER.js.map} +0 -0
- /package/dist/{chunk-QGFEBNHO.js.map → chunk-GZISWBCJ.js.map} +0 -0
- /package/dist/{chunk-OM3SEDI4.js.map → chunk-HTRLQ4ZZ.js.map} +0 -0
- /package/dist/{chunk-SWXLZ4HX.js.map → chunk-ICHHNI5E.js.map} +0 -0
- /package/dist/{chunk-K673OO6B.js.map → chunk-ID4ZBC3X.js.map} +0 -0
- /package/dist/{chunk-H3YM66EI.js.map → chunk-IF2M43G4.js.map} +0 -0
- /package/dist/{chunk-QGSNJD3B.js.map → chunk-IFUYLIEY.js.map} +0 -0
- /package/dist/{chunk-D5A3GCZ4.js.map → chunk-IPF5ORDI.js.map} +0 -0
- /package/dist/{chunk-BVF3SXD7.js.map → chunk-KBIS64X4.js.map} +0 -0
- /package/dist/{chunk-RIZTZJX6.js.map → chunk-LJ744WXU.js.map} +0 -0
- /package/dist/{chunk-L5A3KR7R.js.map → chunk-LUQBG637.js.map} +0 -0
- /package/dist/{chunk-6QLCS7ET.js.map → chunk-LZN6DTFI.js.map} +0 -0
- /package/dist/{chunk-NIXRB5BP.js.map → chunk-MMWX5OT5.js.map} +0 -0
- /package/dist/{chunk-UOZOWN73.js.map → chunk-ND6S2DKC.js.map} +0 -0
- /package/dist/{chunk-WFWFXDNS.js.map → chunk-NHEKQWFI.js.map} +0 -0
- /package/dist/{chunk-2ZFD2UJC.js.map → chunk-NIUHKKMM.js.map} +0 -0
- /package/dist/{chunk-XA34THLF.js.map → chunk-NK4LGBGQ.js.map} +0 -0
- /package/dist/{chunk-JSWKVZCR.js.map → chunk-NUZ7ROUZ.js.map} +0 -0
- /package/dist/{chunk-DHU2AQ6T.js.map → chunk-O3NGOHXQ.js.map} +0 -0
- /package/dist/{chunk-ZBUAX4EF.js.map → chunk-O6VOR4NH.js.map} +0 -0
- /package/dist/{chunk-JZ4EDEIP.js.map → chunk-ODBOHPZU.js.map} +0 -0
- /package/dist/{chunk-5UUJE4FP.js.map → chunk-OK44MD3C.js.map} +0 -0
- /package/dist/{chunk-ECGXA4LT.js.map → chunk-OR3OHKU6.js.map} +0 -0
- /package/dist/{chunk-ZWF3EWZA.js.map → chunk-P6FATPXQ.js.map} +0 -0
- /package/dist/{chunk-PCYPXLEX.js.map → chunk-PBEHTFUG.js.map} +0 -0
- /package/dist/{chunk-7CT6SX4M.js.map → chunk-PFHDQY5L.js.map} +0 -0
- /package/dist/{chunk-PTJY5R3O.js.map → chunk-PIO6NW7O.js.map} +0 -0
- /package/dist/{chunk-TMIJAR2X.js.map → chunk-PREYKC76.js.map} +0 -0
- /package/dist/{chunk-ZHQJAV6D.js.map → chunk-PU5ZEV65.js.map} +0 -0
- /package/dist/{chunk-UNSQZSZP.js.map → chunk-PWAMX5KU.js.map} +0 -0
- /package/dist/{chunk-GETUTTZU.js.map → chunk-PZN76MMV.js.map} +0 -0
- /package/dist/{chunk-ABU6A4Z5.js.map → chunk-Q4DBU5RM.js.map} +0 -0
- /package/dist/{chunk-2WJKJZSO.js.map → chunk-QHG7GQKM.js.map} +0 -0
- /package/dist/{chunk-UAKY6E4N.js.map → chunk-QNOWNCZS.js.map} +0 -0
- /package/dist/{chunk-JPSL5GIZ.js.map → chunk-QQLXKDGC.js.map} +0 -0
- /package/dist/{chunk-OK57EATL.js.map → chunk-R4GLRJ55.js.map} +0 -0
- /package/dist/{chunk-B65CC6Z6.js.map → chunk-RF5WDM25.js.map} +0 -0
- /package/dist/{chunk-G46JSSVX.js.map → chunk-RKBCUP5D.js.map} +0 -0
- /package/dist/{chunk-GCUMOKTN.js.map → chunk-S2ORTQGS.js.map} +0 -0
- /package/dist/{chunk-MRJDLXI3.js.map → chunk-SVXFCCSX.js.map} +0 -0
- /package/dist/{chunk-BUE7R3B5.js.map → chunk-SXPLIRQH.js.map} +0 -0
- /package/dist/{chunk-5LMCVBMY.js.map → chunk-T5EXREMW.js.map} +0 -0
- /package/dist/{chunk-PT2YCQVK.js.map → chunk-TBVDI3LY.js.map} +0 -0
- /package/dist/{chunk-BMHQHH7Q.js.map → chunk-TLIFNRU5.js.map} +0 -0
- /package/dist/{chunk-YKGJ44Z7.js.map → chunk-TU6ZJTYT.js.map} +0 -0
- /package/dist/{chunk-55P6OBB7.js.map → chunk-U43RSPPX.js.map} +0 -0
- /package/dist/{chunk-K7RW7FI4.js.map → chunk-UADW5NOU.js.map} +0 -0
- /package/dist/{chunk-GRS2HIV6.js.map → chunk-UMV5GBTJ.js.map} +0 -0
- /package/dist/{chunk-4UIP3QNW.js.map → chunk-UNAMWK2Q.js.map} +0 -0
- /package/dist/{chunk-J4KAPKBJ.js.map → chunk-UORWAG7K.js.map} +0 -0
- /package/dist/{chunk-V55JASXO.js.map → chunk-UQRKAM2R.js.map} +0 -0
- /package/dist/{chunk-ZMVSKYTJ.js.map → chunk-VLRY2UH4.js.map} +0 -0
- /package/dist/{chunk-SPPOUJLN.js.map → chunk-VZFTON37.js.map} +0 -0
- /package/dist/{chunk-YQFBH5ZJ.js.map → chunk-WQUIJPN4.js.map} +0 -0
- /package/dist/{chunk-NZULV7LK.js.map → chunk-WVQDY3UM.js.map} +0 -0
- /package/dist/{chunk-3Y5JLSXS.js.map → chunk-X5RGG3ZW.js.map} +0 -0
- /package/dist/{chunk-PFCTSXHU.js.map → chunk-X6Z2SIRF.js.map} +0 -0
- /package/dist/{chunk-UHFGK6YA.js.map → chunk-XQGKS4OW.js.map} +0 -0
- /package/dist/{chunk-L2F3CFCH.js.map → chunk-Y22JWHCP.js.map} +0 -0
- /package/dist/{chunk-C53ER7AG.js.map → chunk-YVA6UPRN.js.map} +0 -0
- /package/dist/{chunk-226V6XXJ.js.map → chunk-Z2KP6PNF.js.map} +0 -0
- /package/dist/{chunk-G5EDYVSE.js.map → chunk-ZK2WT532.js.map} +0 -0
- /package/dist/{chunk-SFCD6OU7.js.map → chunk-ZNVBCKMV.js.map} +0 -0
- /package/dist/{chunk-BU2ABHFW.js.map → chunk-ZOFNZLAA.js.map} +0 -0
- /package/dist/{chunk-X2RP4TO5.js.map → chunk-ZVJKHGE5.js.map} +0 -0
- /package/dist/{classified-marker-KHDOYIJB.js.map → classified-marker-7HXDMYHI.js.map} +0 -0
- /package/dist/{collection-facade-LZIF7GWD.js.map → collection-facade-V63BEBGU.js.map} +0 -0
- /package/dist/{computed-XMFTHAXV.js.map → computed-LZLSYOPG.js.map} +0 -0
- /package/dist/{dead-filter-CXV5NS67.js.map → dead-filter-PZIJ4F4G.js.map} +0 -0
- /package/dist/{derive-3YSIS36W.js.map → delegation-7SSGIETH.js.map} +0 -0
- /package/dist/{executor-E6YDJ7YA.js.map → derive-IMI3BMDS.js.map} +0 -0
- /package/dist/{dispatch-2MQFMEGY.js.map → dispatch-4BUYPWMJ.js.map} +0 -0
- /package/dist/{dispatch-OFDA4WQV.js.map → dispatch-KOPDDPEQ.js.map} +0 -0
- /package/dist/{executor-NJX3YQQ4.js.map → executor-7SY3M6TZ.js.map} +0 -0
- /package/dist/{executor-WWM3DD4P.js.map → executor-SNHW4ELF.js.map} +0 -0
- /package/dist/{export-accessible-RLHU5G4W.js.map → executor-Z3IKK7G3.js.map} +0 -0
- /package/dist/{extract-partition-QII2EDCS.js.map → export-accessible-O7DIVFUO.js.map} +0 -0
- /package/dist/{find-6M7GYDUZ.js.map → extract-partition-ELZEJKXM.js.map} +0 -0
- /package/dist/{fanout-sidecar-BO67PCPO.js.map → fanout-sidecar-FYDRL7F3.js.map} +0 -0
- /package/dist/{issue-LPEEEMPP.js.map → find-KWB2RYWJ.js.map} +0 -0
- /package/dist/{ledger-MSJGWKGW.js.map → issue-5ZHXK4HJ.js.map} +0 -0
- /package/dist/{liberate-LEKDYKTC.js.map → ledger-UFJCB6T5.js.map} +0 -0
- /package/dist/{link-set-QXXSPPHL.js.map → liberate-OEOSNNFH.js.map} +0 -0
- /package/dist/{managed-secret-VSK7ANQI.js.map → link-set-KMUBFN2L.js.map} +0 -0
- /package/dist/{noydb-F2AUF6KL.js.map → managed-secret-H5WYSJ46.js.map} +0 -0
- /package/dist/{migrate-cek-GEBFYBDC.js.map → migrate-cek-SPESQAAO.js.map} +0 -0
- /package/dist/{register-SN72QALV.js.map → noydb-QDZ4QIKO.js.map} +0 -0
- /package/dist/{pod-handle-YE7CT66T.js.map → pod-handle-GJLCOUGK.js.map} +0 -0
- /package/dist/{post-register-QC5TEAW3.js.map → post-register-2AC2STHC.js.map} +0 -0
- /package/dist/{registry-253FF7C6.js.map → register-PIORIMMR.js.map} +0 -0
- /package/dist/{registry-3AZWQTDT.js.map → registry-BIMICFUH.js.map} +0 -0
- /package/dist/{registry-7UEBTHWG.js.map → registry-JGWLW53D.js.map} +0 -0
- /package/dist/{registry-IVJ67NFQ.js.map → registry-SELCBYEQ.js.map} +0 -0
- /package/dist/{request-withdrawal-UKVJZKX2.js.map → registry-W327UNYH.js.map} +0 -0
- /package/dist/{revoke-G2KXJQA5.js.map → request-withdrawal-K3SXXODI.js.map} +0 -0
- /package/dist/{reveal-YQTRNQFH.js.map → reveal-UAPBG743.js.map} +0 -0
- /package/dist/{signer-IUIYR3CX.js.map → revoke-6AFVXTWF.js.map} +0 -0
- /package/dist/{stale-SKV33PBU.js.map → signer-TW5MAQJP.js.map} +0 -0
- /package/dist/{storage-NPBYP2SM.js.map → stale-CROGJBIJ.js.map} +0 -0
- /package/dist/{walk-F4OLXI5H.js.map → storage-SO2L2Z5J.js.map} +0 -0
- /package/dist/{store-coordination-provider-Z6HKPOGM.js.map → store-coordination-provider-2YD2PTTP.js.map} +0 -0
- /package/dist/{verify-KWQIWLGH.js.map → verify-QWO5UKD6.js.map} +0 -0
- /package/dist/{withdraw-accessible-ZKPLZ66E.js.map → walk-3KEOL7BY.js.map} +0 -0
|
@@ -1,34 +1,51 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {
|
|
2
|
+
openInboxKeyPair,
|
|
3
|
+
readKeyringFile
|
|
4
|
+
} from "./chunk-QVUMKG3Z.js";
|
|
2
5
|
import {
|
|
3
6
|
generateULID
|
|
4
7
|
} from "./chunk-4AOERLTV.js";
|
|
5
8
|
import {
|
|
6
9
|
dekKey
|
|
7
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-LJ744WXU.js";
|
|
8
11
|
import {
|
|
12
|
+
base64ToBuffer,
|
|
13
|
+
bufferToBase64,
|
|
9
14
|
buildRecordAad,
|
|
10
15
|
buildRecordEnvelope,
|
|
11
16
|
encrypt,
|
|
17
|
+
importRecipientPublicKeySpki,
|
|
18
|
+
importWrappingKey,
|
|
12
19
|
openEnvelopeJson,
|
|
20
|
+
recipientUnwrap,
|
|
21
|
+
recipientWrap,
|
|
13
22
|
unwrapKey,
|
|
14
23
|
wrapKey
|
|
15
|
-
} from "./chunk-
|
|
16
|
-
import "./chunk-ZBUAX4EF.js";
|
|
17
|
-
import "./chunk-SPPOUJLN.js";
|
|
18
|
-
import "./chunk-NH2UOV3B.js";
|
|
19
|
-
import "./chunk-OM3SEDI4.js";
|
|
20
|
-
import "./chunk-PUBI455O.js";
|
|
21
|
-
import "./chunk-2ELOCEXE.js";
|
|
24
|
+
} from "./chunk-WRLWEYHY.js";
|
|
22
25
|
import {
|
|
23
|
-
DelegationTargetMissingError
|
|
24
|
-
|
|
26
|
+
DelegationTargetMissingError,
|
|
27
|
+
INBOX_KEY_ID,
|
|
28
|
+
MemberInboxMissingError
|
|
29
|
+
} from "./chunk-2RH5SEY7.js";
|
|
25
30
|
|
|
26
31
|
// src/with-party/team/delegation.ts
|
|
27
32
|
var DELEGATIONS_COLLECTION = "_delegations";
|
|
28
|
-
async function issueDelegation(store, vault, grantor,
|
|
29
|
-
|
|
33
|
+
async function issueDelegation(store, vault, grantor, delegationsDek, opts) {
|
|
34
|
+
const targetFound = await readKeyringFile(store, vault, opts.toUser);
|
|
35
|
+
if (!targetFound) {
|
|
30
36
|
throw new DelegationTargetMissingError(opts.toUser);
|
|
31
37
|
}
|
|
38
|
+
const targetInbox = targetFound.file.inbox_key;
|
|
39
|
+
if (!targetInbox) {
|
|
40
|
+
throw new MemberInboxMissingError(
|
|
41
|
+
opts.toUser,
|
|
42
|
+
`Delegation target "${opts.toUser}" has a keyring with no inbox key pair \u2014 it predates core#96, so a delegated key cannot be sealed to them. Re-grant the user once (a fresh temporary secret they rotate on first open); the new keyring carries the pair.`
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
const cekBytes = globalThis.crypto.getRandomValues(new Uint8Array(32));
|
|
46
|
+
const targetKek = await importWrappingKey(cekBytes);
|
|
47
|
+
const sealedCek = bufferToBase64(await recipientWrap(await importRecipientPublicKeySpki(base64ToBuffer(targetInbox.pub)), cekBytes));
|
|
48
|
+
cekBytes.fill(0);
|
|
32
49
|
const tier = opts.tier;
|
|
33
50
|
const collectionName = opts.collection ?? null;
|
|
34
51
|
let wrappedDek;
|
|
@@ -67,6 +84,7 @@ async function issueDelegation(store, vault, grantor, targetKek, delegationsDek,
|
|
|
67
84
|
until,
|
|
68
85
|
...wrappedDek !== void 0 && { wrappedDek },
|
|
69
86
|
...wrappedDeks !== void 0 && { wrappedDeks },
|
|
87
|
+
sealedCek,
|
|
70
88
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
71
89
|
};
|
|
72
90
|
const plaintext = JSON.stringify(token);
|
|
@@ -83,6 +101,7 @@ async function loadActiveDelegations(store, vault, user, delegationsDek, now = /
|
|
|
83
101
|
const ids = await store.list(vault, DELEGATIONS_COLLECTION);
|
|
84
102
|
const merged = [];
|
|
85
103
|
const nowIso = now.toISOString();
|
|
104
|
+
let ownInbox;
|
|
86
105
|
for (const id of ids) {
|
|
87
106
|
const env = await store.get(vault, DELEGATIONS_COLLECTION, id);
|
|
88
107
|
if (!env) continue;
|
|
@@ -95,14 +114,37 @@ async function loadActiveDelegations(store, vault, user, delegationsDek, now = /
|
|
|
95
114
|
}
|
|
96
115
|
if (token.toUser !== user.userId) continue;
|
|
97
116
|
if (token.until <= nowIso) continue;
|
|
98
|
-
|
|
117
|
+
let wrapKeyForToken;
|
|
118
|
+
if (token.sealedCek !== void 0) {
|
|
119
|
+
const inboxKeyAes = user.deks.get(INBOX_KEY_ID);
|
|
120
|
+
if (!inboxKeyAes) continue;
|
|
121
|
+
if (ownInbox === void 0) {
|
|
122
|
+
const own = await readKeyringFile(store, vault, user.userId);
|
|
123
|
+
ownInbox = own?.file.inbox_key ?? null;
|
|
124
|
+
}
|
|
125
|
+
if (!ownInbox) continue;
|
|
126
|
+
try {
|
|
127
|
+
const pair = await openInboxKeyPair(ownInbox, inboxKeyAes);
|
|
128
|
+
const cekBytes = await recipientUnwrap(pair, base64ToBuffer(token.sealedCek));
|
|
129
|
+
try {
|
|
130
|
+
wrapKeyForToken = await importWrappingKey(cekBytes);
|
|
131
|
+
} finally {
|
|
132
|
+
cekBytes.fill(0);
|
|
133
|
+
}
|
|
134
|
+
} catch {
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
} else {
|
|
138
|
+
if (!user.kek) continue;
|
|
139
|
+
wrapKeyForToken = user.kek;
|
|
140
|
+
}
|
|
99
141
|
const wraps = token.collection ? token.wrappedDek ? { [dekKey(token.collection, token.tier)]: token.wrappedDek } : {} : { ...token.wrappedDeks ?? {} };
|
|
100
142
|
if (Object.keys(wraps).length === 0) continue;
|
|
101
143
|
let anyMerged = false;
|
|
102
144
|
for (const [slot, wrapped] of Object.entries(wraps)) {
|
|
103
145
|
let dek;
|
|
104
146
|
try {
|
|
105
|
-
dek = await unwrapKey(wrapped,
|
|
147
|
+
dek = await unwrapKey(wrapped, wrapKeyForToken);
|
|
106
148
|
} catch {
|
|
107
149
|
continue;
|
|
108
150
|
}
|
|
@@ -117,10 +159,11 @@ async function loadActiveDelegations(store, vault, user, delegationsDek, now = /
|
|
|
117
159
|
async function revokeDelegation(store, vault, id) {
|
|
118
160
|
await store.delete(vault, DELEGATIONS_COLLECTION, id);
|
|
119
161
|
}
|
|
162
|
+
|
|
120
163
|
export {
|
|
121
164
|
DELEGATIONS_COLLECTION,
|
|
122
165
|
issueDelegation,
|
|
123
166
|
loadActiveDelegations,
|
|
124
167
|
revokeDelegation
|
|
125
168
|
};
|
|
126
|
-
//# sourceMappingURL=
|
|
169
|
+
//# sourceMappingURL=chunk-JQMEXCUZ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/with-party/team/delegation.ts"],"sourcesContent":["/**\n * Time-boxed cross-tier delegation tokens.\n *\n * A higher-tier user can issue a delegation that grants another user\n * temporary access to records at a specified tier. The delegation is\n * persisted as an encrypted envelope in the reserved `_delegations`\n * collection. The target user's runtime scans this collection on every\n * open and, while `until` is still in the future, merges the\n * unwrapped tier DEKs into their in-memory DEK map.\n *\n * ## Token shape\n *\n * ```\n * {\n * id, // ULID, also the _delegations record id\n * toUser, // grantee user id\n * fromUser, // grantor user id (owner/admin/higher-tier principal)\n * tier, // tier being delegated\n * collection, // collection name OR null for \"every collection\"\n * record, // optional specific record id\n * until, // ISO timestamp — token expires at this instant\n * wrappedDek, // base64 AES-KW-wrapped tier DEK, under the token's content key\n * sealedCek, // that content key, RSA-OAEP-sealed to the target's inbox public half\n * createdAt, // ISO timestamp\n * }\n * ```\n *\n * ## Cross-user (core#65)\n *\n * The wrap key is a per-token CONTENT KEY, not anybody's KEK: the tier DEKs are\n * AES-KW-wrapped under it exactly as they used to be under a KEK, and the key\n * itself is RSA-OAEP-sealed to the target's INBOX PUBLIC HALF (core#96 mints\n * that pair for every grantee, private half sealed under a DEK only that\n * member's own KEK unwraps). So a grantor delegates to somebody whose secret it\n * does not know — the thing this module could not do — while the slot NAMES\n * stay readable to any member holding the `_delegations` DEK, which is what\n * makes an audit enumeration possible without making the keys usable.\n *\n * The ciphertext is stored as a normal noy-db envelope — the\n * `_delegations` collection has its own DEK shared across all vault\n * users, so an operator can enumerate active delegations for audit\n * without being able to *use* them (the `wrappedDek` inside is still\n * keyed to the target user's KEK).\n *\n * ## Revocation\n *\n * Delete the `_delegations/<id>` envelope. The target user's runtime\n * reloads the delegation list at each open and at periodic intervals\n * (tracked by the caller — this module is pure logic).\n *\n * @module\n */\n\nimport type { NoydbStore, KeyringFile } from '../../kernel/types.js'\nimport type { UnlockedKeyring } from './keyring.js'\nimport {\n buildRecordAad, buildRecordEnvelope, encrypt, openEnvelopeJson, wrapKey, unwrapKey,\n importWrappingKey, importRecipientPublicKeySpki, recipientWrap, recipientUnwrap,\n bufferToBase64, base64ToBuffer, type EnclaveKey,\n} from '../../capsule/index.js'\nimport { dekKey } from './tiers.js'\nimport { readKeyringFile, openInboxKeyPair } from './keyring.js'\nimport { INBOX_KEY_ID } from '../../kernel/constants.js'\nimport { DelegationTargetMissingError, MemberInboxMissingError } from '../../kernel/errors.js'\nimport { generateULID } from '../../with-pod/ulid.js'\n\nexport const DELEGATIONS_COLLECTION = '_delegations'\n\n/**\n * Durable payload of a delegation token. Encrypted under the vault's\n * `_delegations` DEK; the `wrappedDek` inside is additionally wrapped\n * under the target user's KEK.\n */\nexport interface DelegationToken {\n readonly id: string\n readonly toUser: string\n readonly fromUser: string\n readonly tier: number\n /**\n * Collection name, or `null` for a COLLECTION-WIDE token — see\n * {@link DelegationToken.wrappedDeks} for what that means and what it cannot\n * mean.\n */\n readonly collection: string | null\n /** Optional specific record id scope. */\n readonly record?: string\n readonly until: string\n /**\n * The delegated tier DEK for {@link DelegationToken.collection}, wrapped\n * under the target's KEK. Present on a per-collection token; absent on a\n * collection-wide one, which carries {@link DelegationToken.wrappedDeks}.\n */\n readonly wrappedDek?: string\n /**\n * A collection-wide token's payload: `<collection>#<tier>` → wrapped DEK, one\n * entry per collection the grantor held at that tier (core#56).\n *\n * ## ⛔ Why a MAP and not one key\n *\n * Every collection has its OWN tier DEK — measured, `docs#1` and `ledger#1`\n * are different keys. The original design tried to express \"every collection\"\n * as a single DEK under a wildcard slot `__any#<tier>`, which cannot work: one\n * key decrypts one collection. A wildcard accepted at the access gate would\n * have passed the check and then failed decryption — a gate that says yes\n * followed by a crypto error. `__any#` is gone; every entry here merges under\n * its REAL `<collection>#<tier>` key, so `assertTierAccess` needs no wildcard\n * and gains no new privilege surface.\n *\n * ## ⚠️ \"Every collection\" means \"every collection AS OF ISSUE TIME\"\n *\n * This is a SNAPSHOT. A collection created after the token was issued is not\n * in it and will not be granted by it — the grantor did not hold its DEK to\n * wrap. That is a real limit of the shape, not an oversight, and it is stated\n * here because a caller who reads \"all collections\" will otherwise assume\n * otherwise.\n */\n readonly wrappedDeks?: Readonly<Record<string, string>>\n /**\n * core#65 — the token's CONTENT KEY, RSA-OAEP-sealed to the target's inbox\n * public half. `wrappedDek` / `wrappedDeks` are AES-KW-wrapped under it, so\n * only the target can unwrap them, and only they can: the matching private\n * half is sealed in their keyring under a DEK their own KEK unwraps.\n *\n * Absent on a token written before core#65, whose wraps are under the\n * grantor's own KEK — those still load for a target that shares that KEK\n * (the only case that ever worked) and are skipped for anyone else, exactly\n * as before.\n */\n readonly sealedCek?: string\n readonly createdAt: string\n}\n\nexport interface IssueDelegationOptions {\n readonly toUser: string\n readonly tier: number\n readonly collection?: string\n readonly record?: string\n readonly until: Date | string\n}\n\n/**\n * Build and persist a delegation token. The caller must hold a tier-N DEK; the\n * target must have a keyring in this vault with an inbox key pair (core#96).\n *\n * core#65 — the wraps are keyed to a per-token content key sealed to that\n * pair, so the grantor needs nothing of the target's but their PUBLIC half.\n */\nexport async function issueDelegation(\n store: NoydbStore,\n vault: string,\n grantor: UnlockedKeyring,\n delegationsDek: EnclaveKey,\n opts: IssueDelegationOptions,\n): Promise<DelegationToken> {\n const targetFound = await readKeyringFile(store, vault, opts.toUser)\n if (!targetFound) {\n throw new DelegationTargetMissingError(opts.toUser)\n }\n const targetInbox = targetFound.file.inbox_key\n if (!targetInbox) {\n throw new MemberInboxMissingError(\n opts.toUser,\n `Delegation target \"${opts.toUser}\" has a keyring with no inbox key pair — it predates core#96, ` +\n 'so a delegated key cannot be sealed to them. Re-grant the user once (a fresh temporary secret ' +\n 'they rotate on first open); the new keyring carries the pair.',\n )\n }\n const cekBytes = globalThis.crypto.getRandomValues(new Uint8Array(32))\n const targetKek = await importWrappingKey(cekBytes)\n const sealedCek = bufferToBase64(await recipientWrap(await importRecipientPublicKeySpki(base64ToBuffer(targetInbox.pub)), cekBytes))\n cekBytes.fill(0)\n const tier = opts.tier\n const collectionName = opts.collection ?? null\n\n // Collection-wide: wrap EVERY tier DEK the grantor holds at this tier, each\n // under its own real slot key. See `wrappedDeks` for why this is a map and\n // for the as-of-issue-time limit it carries.\n let wrappedDek: string | undefined\n let wrappedDeks: Record<string, string> | undefined\n if (collectionName === null) {\n const suffix = `#${tier}`\n const entries: Record<string, string> = {}\n for (const [slot, dek] of grantor.deks) {\n if (slot.endsWith(suffix)) entries[slot] = await wrapKey(dek, targetKek)\n }\n if (Object.keys(entries).length === 0) {\n throw new DelegationTargetMissingError(\n opts.toUser,\n `grantor holds no tier-${tier} DEK for ANY collection, so a collection-wide ` +\n `delegation would grant nothing. Obtain a tier grant first, or name a ` +\n `\\`collection\\`.`,\n )\n }\n wrappedDeks = entries\n } else {\n const sourceDek = grantor.deks.get(dekKey(collectionName, tier))\n if (!sourceDek) {\n throw new DelegationTargetMissingError(\n opts.toUser,\n `grantor holds no tier-${tier} DEK for collection \"${collectionName}\", so there ` +\n `is nothing to delegate. Obtain the tier grant first.`,\n )\n }\n wrappedDek = await wrapKey(sourceDek, targetKek)\n }\n\n const until = typeof opts.until === 'string' ? opts.until : opts.until.toISOString()\n const token: DelegationToken = {\n id: generateULID(),\n toUser: opts.toUser,\n fromUser: grantor.userId,\n tier,\n collection: collectionName,\n ...(opts.record && { record: opts.record }),\n until,\n ...(wrappedDek !== undefined && { wrappedDek }),\n ...(wrappedDeks !== undefined && { wrappedDeks }),\n sealedCek,\n createdAt: new Date().toISOString(),\n }\n\n const plaintext = JSON.stringify(token)\n const identity = { collection: DELEGATIONS_COLLECTION, id: token.id, by: grantor.userId, version: 1 }\n const { iv, data } = await encrypt(plaintext, delegationsDek, buildRecordAad(identity))\n const envelope = buildRecordEnvelope(\n identity,\n { ts: token.createdAt, iv, data},\n )\n await store.put(vault, DELEGATIONS_COLLECTION, token.id, envelope)\n return token\n}\n\n/**\n * ## Why the vault calls this EXPLICITLY, and never from `openVault` (core#56)\n *\n * The module header above describes a runtime that scans on every open. Doing\n * that automatically would call `getDEK('_delegations')`, which MINTS a DEK when\n * absent and persists the keyring — so merely opening a vault would write to it.\n * Worse, on a vault whose shared `_delegations` DEK this user does not hold, it\n * would mint a WRONG one and then fail to decrypt every token under it.\n *\n * ⛔ A read path must not have that side effect. `Vault.refreshDelegations()`\n * therefore lists first, returns `[]` when nothing is written, and looks the DEK\n * up WITHOUT minting — which also makes the module header's \"at each open\"\n * cheap to honour, and its \"periodic intervals (tracked by the caller)\" is what\n * an explicit method is.\n *\n * ## Cross-user delegation (core#65) — and the one thing it still needs\n *\n * A token's wraps are keyed to a per-token content key sealed to the target's\n * INBOX PUBLIC HALF, so any member can be a target. Opening one therefore needs\n * that member's inbox PRIVATE half, which is sealed in their keyring file under\n * `deks[INBOX_KEY_ID]` — so this function reads the caller's own keyring file,\n * once, and only when a sealed token is actually addressed to them.\n *\n * ⚠️ A pre-core#65 token (no `sealedCek`) is wrapped under the GRANTOR's KEK and\n * still requires `user.kek`; it is skipped for anyone who does not share it,\n * which is the behaviour those tokens were written under.\n */\n\n/**\n * Enumerate every live (non-expired) delegation addressed to `toUser`\n * and merge the unwrapped tier DEKs into their keyring. Returns the\n * list of merged delegations so the caller can register per-access\n * audit context.\n */\nexport async function loadActiveDelegations(\n store: NoydbStore,\n vault: string,\n user: UnlockedKeyring,\n delegationsDek: EnclaveKey,\n now: Date = new Date(),\n): Promise<DelegationToken[]> {\n const ids = await store.list(vault, DELEGATIONS_COLLECTION)\n const merged: DelegationToken[] = []\n const nowIso = now.toISOString()\n /** This member's own inbox key pair material, read at most once per call. `null` = read, absent. */\n let ownInbox: NonNullable<KeyringFile['inbox_key']> | null | undefined\n for (const id of ids) {\n const env = await store.get(vault, DELEGATIONS_COLLECTION, id)\n if (!env) continue\n let token: DelegationToken\n try {\n const plaintext = await openEnvelopeJson({ collection: DELEGATIONS_COLLECTION, id }, env, delegationsDek)\n token = JSON.parse(plaintext) as DelegationToken\n } catch {\n continue\n }\n if (token.toUser !== user.userId) continue\n if (token.until <= nowIso) continue\n\n // core#65 — the wrap key. A sealed token carries its own content key,\n // opened with this member's inbox pair; a legacy token is under the\n // grantor's KEK and needs `user.kek`, absent on a tier-3 PIN resume, a\n // wrap-DEKs tier-2 unlock or a session restore (reached again at the next\n // tier-1 unlock). A sealed token has no such limit: the pair's private\n // half is sealed under a DEK the rebuilt set already carries.\n let wrapKeyForToken: EnclaveKey\n if (token.sealedCek !== undefined) {\n const inboxKeyAes = user.deks.get(INBOX_KEY_ID)\n if (!inboxKeyAes) continue\n if (ownInbox === undefined) {\n const own = await readKeyringFile(store, vault, user.userId)\n ownInbox = own?.file.inbox_key ?? null\n }\n if (!ownInbox) continue\n try {\n const pair = await openInboxKeyPair(ownInbox, inboxKeyAes)\n const cekBytes = await recipientUnwrap(pair, base64ToBuffer(token.sealedCek))\n try {\n wrapKeyForToken = await importWrappingKey(cekBytes)\n } finally {\n cekBytes.fill(0)\n }\n } catch {\n // Sealed to somebody else's pair, or this member's own pair was\n // replaced (a re-grant mints a fresh one). Not ours to open.\n continue\n }\n } else {\n if (!user.kek) continue\n wrapKeyForToken = user.kek\n }\n\n // ⭐ Every merged key lands under its REAL `<collection>#<tier>` slot, which\n // is exactly what `assertTierAccess` and `getDEK` already look up. There is\n // no wildcard slot and no lookup change anywhere — see `wrappedDeks`.\n const wraps: Record<string, string> = token.collection\n ? (token.wrappedDek ? { [dekKey(token.collection, token.tier)]: token.wrappedDek } : {})\n : { ...(token.wrappedDeks ?? {}) }\n if (Object.keys(wraps).length === 0) continue\n\n let anyMerged = false\n for (const [slot, wrapped] of Object.entries(wraps)) {\n let dek: EnclaveKey\n try {\n dek = await unwrapKey(wrapped, wrapKeyForToken)\n } catch {\n // One unusable entry must not discard the rest of a collection-wide\n // token — a revoked or re-wrapped collection is the expected case.\n continue\n }\n user.deks.set(slot, dek)\n anyMerged = true\n }\n if (!anyMerged) continue\n merged.push(token)\n }\n return merged\n}\n\n/**\n * Revoke a delegation by id — the caller resolves the envelope and\n * issues a `delete`. Provided as a stable helper so the naming is\n * symmetric to `issueDelegation`.\n */\nexport async function revokeDelegation(\n store: NoydbStore,\n vault: string,\n id: string,\n): Promise<void> {\n await store.delete(vault, DELEGATIONS_COLLECTION, id)\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
import {
|
|
2
2
|
walkClosure
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-ICHHNI5E.js";
|
|
4
4
|
import {
|
|
5
5
|
resolveManagedSecret
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-GU6QXHPZ.js";
|
|
7
7
|
import {
|
|
8
8
|
parseExtractedPartitionBody,
|
|
9
9
|
readPod,
|
|
10
10
|
readPodHeader
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-4N4OIVK3.js";
|
|
12
12
|
import {
|
|
13
13
|
createOwnerKeyring,
|
|
14
14
|
mintRosterTag,
|
|
15
15
|
requireRosterKey,
|
|
16
16
|
stampAuthority
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-QVUMKG3Z.js";
|
|
18
18
|
import {
|
|
19
19
|
LedgerStore
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-Y22JWHCP.js";
|
|
21
21
|
import {
|
|
22
22
|
LEDGER_COLLECTION
|
|
23
23
|
} from "./chunk-I7FD46FF.js";
|
|
@@ -30,18 +30,18 @@ import {
|
|
|
30
30
|
importTransferKey,
|
|
31
31
|
openEnvelopeJson,
|
|
32
32
|
wrapKey
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-WRLWEYHY.js";
|
|
34
34
|
import {
|
|
35
35
|
AdoptionStateError,
|
|
36
36
|
TransferSealError,
|
|
37
37
|
ValidationError
|
|
38
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-2RH5SEY7.js";
|
|
39
39
|
|
|
40
40
|
// src/with-cargo/active.ts
|
|
41
41
|
function withCargo() {
|
|
42
42
|
return {
|
|
43
43
|
async extractPartition(vault, opts) {
|
|
44
|
-
const { extractPartitionCore } = await import("./extract-partition-
|
|
44
|
+
const { extractPartitionCore } = await import("./extract-partition-ELZEJKXM.js");
|
|
45
45
|
return extractPartitionCore(vault, opts);
|
|
46
46
|
}
|
|
47
47
|
};
|
|
@@ -221,7 +221,7 @@ async function createOwnerOnAdoptedPartition(store, vaultName, opts) {
|
|
|
221
221
|
const withEpoch = stampAuthority(merged, keyringFile.roster_epoch);
|
|
222
222
|
const rosterKey = requireRosterKey(unlocked, "adoptPartition");
|
|
223
223
|
const mergedFile = { ...withEpoch, roster_tag: await mintRosterTag(withEpoch, rosterKey) };
|
|
224
|
-
await store.put(vaultName, "_keyring", userId, { ...env, _data: JSON.stringify(mergedFile) });
|
|
224
|
+
await store.put(vaultName, "_keyring", userId, { ...env, _v: env._v + 1, _data: JSON.stringify(mergedFile) }, env._v);
|
|
225
225
|
}
|
|
226
226
|
const ledgerDek = partitionDeks.get(LEDGER_COLLECTION);
|
|
227
227
|
if (ledgerDek) {
|
|
@@ -243,7 +243,7 @@ async function createOwnerOnAdoptedPartition(store, vaultName, opts) {
|
|
|
243
243
|
}
|
|
244
244
|
}
|
|
245
245
|
if (isManaged(opts)) {
|
|
246
|
-
const { createNoydb } = await import("./noydb-
|
|
246
|
+
const { createNoydb } = await import("./noydb-QDZ4QIKO.js");
|
|
247
247
|
const db = await createNoydb({
|
|
248
248
|
store,
|
|
249
249
|
user: userId,
|
|
@@ -298,4 +298,4 @@ export {
|
|
|
298
298
|
withCargo,
|
|
299
299
|
describeExtraction
|
|
300
300
|
};
|
|
301
|
-
//# sourceMappingURL=chunk-
|
|
301
|
+
//# sourceMappingURL=chunk-K5JNK63R.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/with-cargo/active.ts","../src/with-cargo/describe-extraction.ts","../src/with-cargo/adopt-partition.ts","../src/with-cargo/decrypt-partition.ts"],"sourcesContent":["/**\n * Enable the cargo (partition extraction) capability.\n * Pass to `createNoydb({ cargoStrategy: withCargo() })` to make the source-side\n * `extractPartition(vault, ...)` free function live. The extraction crypto\n * engine is dynamically imported here, so it stays out of the floor bundle\n * until opted in. The recipient-side `adoptPartition` /\n * `decryptExtractedPartition` free functions — and `diffVault` (shared\n * import/merge infra) — are ungated and unaffected.\n */\nimport type { CargoStrategy } from './strategy.js'\n\nexport function withCargo(): CargoStrategy {\n return {\n async extractPartition(vault, opts) {\n const { extractPartitionCore } = await import('./extract-partition.js')\n return extractPartitionCore(vault, opts)\n },\n }\n}\n","/**\n * Partition-extraction dry-run. Read-only preview of what an\n * `extractPartition` would move: record counts, byte totals, and the\n * timestamp span per collection — computed from raw encrypted\n * envelopes WITHOUT decrypting them. Writes nothing, mutates nothing.\n *\n * @module\n */\nimport type { Vault } from '../kernel/vault.js'\nimport { walkClosure, type WalkClosureOptions, type DanglingRefNotice } from './walk-closure.js'\n\nexport interface ExtractionPreview {\n readonly totalRecords: number\n /** Sum of serialized encrypted-envelope sizes (bytes). */\n readonly totalBytes: number\n readonly byCollection: ReadonlyArray<{\n readonly name: string\n readonly recordCount: number\n readonly bytes: number\n /** Earliest envelope `_ts` in this collection (lexicographic). */\n readonly oldestTs?: string\n readonly newestTs?: string\n }>\n readonly graph: { readonly depth: number; readonly cyclesDetected: boolean }\n /** Records the walk reached but whose envelope couldn't be read. */\n readonly inaccessible: ReadonlyArray<{ readonly collection: string; readonly id: string }>\n /**\n * #772: outbound FK edges whose referenced parent was excluded from the\n * closure (missing, or tier-elevated and therefore invisible) — mirrors\n * `ExtractPartitionResult.danglingRefs` (#759) so a preview/extract pair\n * gives the SAME signal. A parent excluded this way never appears in\n * `byCollection` at all; this is the only preview-time indicator.\n */\n readonly danglingRefs: ReadonlyArray<DanglingRefNotice>\n}\n\nexport async function describeExtraction(\n vault: Vault,\n opts: WalkClosureOptions,\n): Promise<ExtractionPreview> {\n const { closure, graph, danglingRefs } = await walkClosure(vault, opts)\n\n const { name: vaultName, adapter } = vault._introspectState()\n const encoder = new TextEncoder()\n\n const byCollection: Array<{\n name: string; recordCount: number; bytes: number; oldestTs?: string; newestTs?: string\n }> = []\n const inaccessible: Array<{ collection: string; id: string }> = []\n let totalBytes = 0\n let totalRecords = 0\n\n for (const [collectionName, ids] of closure) {\n let bytes = 0\n let oldestTs: string | undefined\n let newestTs: string | undefined\n let recordCount = 0\n\n for (const id of ids) {\n const env = await adapter.get(vaultName, collectionName, id)\n if (!env) {\n // Walk reached it (via decrypted list) but the raw store read\n // returned nothing — surface rather than miscount.\n inaccessible.push({ collection: collectionName, id })\n continue\n }\n recordCount++\n bytes += encoder.encode(JSON.stringify(env)).length\n const ts = env._ts\n if (oldestTs === undefined || ts < oldestTs) oldestTs = ts\n if (newestTs === undefined || ts > newestTs) newestTs = ts\n }\n\n byCollection.push({\n name: collectionName,\n recordCount,\n bytes,\n // Spread conditionally — exactOptionalPropertyTypes forbids an\n // explicit `undefined` on an optional property.\n ...(oldestTs !== undefined ? { oldestTs } : {}),\n ...(newestTs !== undefined ? { newestTs } : {}),\n })\n totalBytes += bytes\n totalRecords += recordCount\n }\n\n byCollection.sort((a, b) => a.name.localeCompare(b.name))\n\n return Object.freeze({\n totalRecords,\n totalBytes,\n byCollection,\n graph,\n inaccessible,\n danglingRefs,\n })\n}\n","/**\n * Partition adoption. Recipient side: verify an extracted bundle,\n * validate the transfer key, import the re-keyed collections into a\n * destination store, and record an `_meta/adoption` marker. The bundle\n * stays UNOWNED after adoption — `createOwnerOnAdoptedPartition`\n * mints the owner; the transfer seal is then destroyed.\n *\n * @module\n */\nimport {\n base64ToBuffer, bufferToBase64, wrapKey, importTransferKey, decryptBytes, importDekSet,\n type EnclaveKey,\n} from '../capsule/index.js'\nimport { TransferSealError, AdoptionStateError, ValidationError } from '../kernel/errors.js'\nimport type { NoydbStore, VaultSnapshot, KeyringFile } from '../kernel/types.js'\nimport { createOwnerKeyring, requireRosterKey } from '../with-party/team/keyring.js'\nimport { mintRosterTag } from '../with-party/team/roster-tag.js' // #1115\nimport { stampAuthority } from '../with-party/team/roster-tag.js'\nimport { resolveManagedSecret } from '../with-party/team/managed-secret.js'\nimport type { NoydbSealer } from '../with-party/team/managed-secret.js'\nimport type { NoydbShamir } from '../with-party/team/noydb-shamir.js'\nimport type { RecoveryEnrollmentInput } from '../with-party/team/rotate-recover.js'\nimport { LedgerStore } from '../with-commit/history/ledger/store.js'\nimport { LEDGER_COLLECTION } from '../with-commit/history/ledger/constants.js'\nimport type { TransferSealPayload } from '../with-pod/pod.js'\nimport { readPodHeader, readPod, parseExtractedPartitionBody } from '../with-pod/pod.js'\nimport { buildRecordEnvelope } from '../capsule/index.js'\n\n/**\n * Reverse of `sealDeks`. Imports the transfer key, decrypts the\n * sealed `{ collection: base64(rawDEK) }` map (layout iv(12)‖ct‖tag), and\n * re-imports each DEK as an AES-GCM key. Throws `TransferSealError` on a\n * wrong key (AES-GCM auth-tag failure) or malformed payload.\n */\nexport async function unsealDeks(\n seal: TransferSealPayload,\n transferKey: Uint8Array,\n): Promise<Map<string, EnclaveKey>> {\n if (transferKey.byteLength !== 32) {\n throw new TransferSealError(\n `transfer key must be 32 bytes, got ${transferKey.byteLength}.`,\n )\n }\n const key = await importTransferKey(transferKey)\n const raw = base64ToBuffer(seal.payload)\n let plaintext: Uint8Array\n try {\n plaintext = await decryptBytes(bufferToBase64(raw.slice(0, 12)), bufferToBase64(raw.slice(12)), key)\n } catch {\n throw new TransferSealError(\n 'transfer seal could not be opened — wrong transfer key (AES-GCM authentication failed).',\n )\n }\n let dekMap: Record<string, string>\n try {\n dekMap = JSON.parse(new TextDecoder().decode(plaintext)) as Record<string, string>\n } catch {\n throw new TransferSealError('transfer seal payload is not valid JSON after decryption.')\n }\n // Extractable: the recipient re-wraps these under their own KEK (AES-KW)\n // at owner-creation — importDekSet mints them the way generateDEK does.\n return importDekSet(dekMap)\n}\n\nexport interface AdoptPartitionOptions {\n readonly transferKey: Uint8Array\n readonly destinationStore: NoydbStore\n readonly vaultName: string\n}\n\nexport interface AdoptPartitionResult {\n readonly vaultName: string\n readonly needsOwner: true\n readonly sealId: string\n}\n\nexport async function adoptPartition(\n bundleBytes: Uint8Array,\n opts: AdoptPartitionOptions,\n): Promise<AdoptPartitionResult> {\n const { transferKey, destinationStore, vaultName } = opts\n\n const header = readPodHeader(bundleBytes)\n if (header.bundleKind !== 'extracted-partition' || header.transferSeal === undefined) {\n throw new ValidationError(\n 'adoptPartition requires an extracted-partition bundle with a transfer seal. '\n + 'For ordinary backups use readPod + vault.load.',\n )\n }\n\n const { dumpJson } = await readPod(bundleBytes)\n const { dump, seal } = parseExtractedPartitionBody(dumpJson)\n\n // Validate the transfer key by unsealing in memory; throws\n // TransferSealError on mismatch. DEKs are discarded here — they stay\n // sealed at rest (in _meta/adoption) until owner-creation wraps them under the\n // recipient's KEK.\n await unsealDeks(seal, transferKey)\n\n // Single-occupancy per vaultName: an `_meta/adoption` marker already present\n // means this slot holds a partition (adopted-and-unowned, or already owned).\n // saveAll below would overwrite its data and replace the marker, stranding the\n // prior adoption's transfer seal. Refuse regardless of sealId — re-adopting the\n // SAME bundle is a redundant call, and adopting a DIFFERENT bundle here would\n // clobber the existing partition. Either way, pick a fresh vaultName.\n const existing = await destinationStore.get(vaultName, '_meta', 'adoption')\n if (existing) {\n const prior = JSON.parse(existing._data ?? '') as { sealId?: string }\n if (prior.sealId === seal.sealId) {\n throw new AdoptionStateError(\n `partition (sealId ${seal.sealId}) is already adopted into vault \"${vaultName}\".`,\n )\n }\n throw new AdoptionStateError(\n `vault \"${vaultName}\" already holds an adopted partition (sealId ${prior.sealId}); `\n + `adopting a different partition (sealId ${seal.sealId}) here would overwrite it. `\n + `Adopt into a fresh vaultName instead.`,\n )\n }\n\n // The marker-only check above misses a worse case: a vaultName already in use\n // by an ORDINARY vault (createNoydb + openVault) carries no `_meta/adoption`,\n // yet `saveAll` below is destructive on SQL adapters (`DELETE FROM ... WHERE\n // vault = ?` followed by upsert) and would wipe the legitimate keyring +\n // data. Refuse adoption into ANY occupied slot — a fresh vaultName is the\n // documented precondition.\n const existingKeyring = await destinationStore.list(vaultName, '_keyring')\n if (existingKeyring.length > 0) {\n throw new AdoptionStateError(\n `vault \"${vaultName}\" already holds a keyring (an unrelated owner exists at this slot); `\n + `adoptPartition requires a fresh vaultName to avoid destructive saveAll on SQL adapters.`,\n )\n }\n\n const backup = JSON.parse(dump) as { collections: VaultSnapshot; _internal?: VaultSnapshot }\n await destinationStore.saveAll(vaultName, backup.collections)\n\n // Import carried internal collections (e.g. _schemas from carrySchemas).\n // saveAll only writes data collections; _internal is written per-record.\n if (backup._internal) {\n for (const [collection, records] of Object.entries(backup._internal)) {\n for (const [id, envelope] of Object.entries(records)) {\n await destinationStore.put(vaultName, collection, id, envelope)\n }\n }\n }\n\n const adoptedAt = new Date().toISOString()\n const adoption = { sealId: seal.sealId, adoptedAt, needsOwner: true as const, transferSeal: seal }\n await destinationStore.put(vaultName, '_meta', 'adoption',\n buildRecordEnvelope({ collection: '_meta', id: 'adoption', version: 1 },\n { ts: adoptedAt, iv: '', data: JSON.stringify(adoption) }))\n\n return { vaultName, needsOwner: true, sealId: seal.sealId }\n}\n\nexport interface CreateOwnerResult {\n readonly vaultName: string\n readonly userId: string\n}\n\n/** Standard-mode owner: recipient supplies the secret. */\nexport interface CreateOwnerStandardOptions {\n readonly userId: string\n readonly secret: string\n readonly transferKey: Uint8Array\n}\n\n/**\n * Managed-mode owner: the secret is minted + sealed under\n * a `NoydbSealer` (e.g. an `at-*` OS keychain) so the partition\n * auto-unlocks on the recipient's device. Managed mode mandates a strong\n * (Shamir) recovery profile at creation, which needs the\n * `shamirRecovery` provider injected.\n */\nexport interface CreateOwnerManagedOptions {\n readonly userId: string\n readonly secretMode: 'managed'\n readonly sealingKey: NoydbSealer\n readonly recovery: ReadonlyArray<RecoveryEnrollmentInput>\n readonly shamirRecovery: NoydbShamir\n readonly transferKey: Uint8Array\n}\n\nexport type CreateOwnerOptions = CreateOwnerStandardOptions | CreateOwnerManagedOptions\n\nfunction isManaged(o: CreateOwnerOptions): o is CreateOwnerManagedOptions {\n return 'secretMode' in o && o.secretMode === 'managed'\n}\n\n/**\n * Mint the first owner keyring on an adopted-but-unowned partition,\n * then destroy the transfer seal.\n *\n * Standard mode: the recipient supplies a secret. Managed mode: the\n * secret is minted + sealed under a `NoydbSealer` and a strong\n * (Shamir) recovery profile is enrolled — orchestrated via the existing\n * `openVaultAndEnrollRecovery` ceremony.\n *\n * Either way, reuses `createOwnerKeyring` to derive the KEK + write the base\n * keyring, then wraps the partition's DEKs (recovered from the seal) under that\n * KEK and re-persists the merged keyring file.\n *\n * Idempotent under retry: the seal is destroyed LAST (Stage D), after the\n * keyring (Stage A), the ledger transition (Stage B), and — in managed mode —\n * strong-recovery enrollment (Stage C). A failure in the fallible enrollment\n * step leaves the seal intact, and re-running with the same `userId` +\n * `transferKey` resumes from the first incomplete stage. (Multi-profile recovery\n * arrays may re-enroll an already-enrolled profile on retry; managed mode's\n * mandated single Shamir profile does not.)\n */\nexport async function createOwnerOnAdoptedPartition(\n store: NoydbStore,\n vaultName: string,\n opts: CreateOwnerOptions,\n): Promise<CreateOwnerResult> {\n const { userId, transferKey } = opts\n\n // Managed mode requires a strong (Shamir) recovery profile, validated BEFORE\n // any disk write — same gate as createNoydb.\n if (isManaged(opts) && !opts.recovery.some((r) => r.profile === 'shamir')) {\n throw new AdoptionStateError(\n 'managed-mode adoption requires at least one strong (shamir) recovery profile in '\n + '`recovery` — paper alone is not strong when there is no user secret to fall back on.',\n )\n }\n\n // 1. Verify adopted-unowned state.\n const adoptionEnv = await store.get(vaultName, '_meta', 'adoption')\n if (!adoptionEnv) {\n throw new AdoptionStateError(\n `vault \"${vaultName}\" is not an adopted partition (no _meta/adoption). `\n + `createOwnerOnAdoptedPartition only applies to vaults created via adoptPartition.`,\n )\n }\n const adoption = JSON.parse(adoptionEnv._data ?? '') as {\n sealId: string; adoptedAt: string; needsOwner?: boolean\n consumedAt?: string; transferSeal?: TransferSealPayload\n }\n if (adoption.consumedAt !== undefined || adoption.transferSeal === undefined) {\n throw new AdoptionStateError(\n `vault \"${vaultName}\" already has an owner (transfer seal consumed at ${adoption.consumedAt}).`,\n )\n }\n\n // 2. Recover the partition DEKs from the seal (throws on wrong key) BEFORE\n // writing any keyring, so a bad transfer key leaves no trace. Always\n // validated, including when resuming a partial prior call.\n const partitionDeks = await unsealDeks(adoption.transferSeal, transferKey)\n\n // The ceremony below is split into stages so a failure in the fallible\n // managed-enrollment step (network/provider outage) leaves the call RETRYABLE\n // — the seal is destroyed only once everything durable is in place. Each stage\n // detects its own prior completion rather than relying on a single resume bit.\n\n // A keyring present for a DIFFERENT user (with the seal still unconsumed) is a\n // genuine second-owner attempt — refuse it. A same-user keyring is a resumed\n // partial call and is handled by the stage checks below.\n const existingKeyring = await store.get(vaultName, '_keyring', userId)\n const otherOwners = (await store.list(vaultName, '_keyring')).filter((u) => u !== userId)\n if (otherOwners.length > 0) {\n throw new AdoptionStateError(\n `vault \"${vaultName}\" already has a keyring for a different owner; cannot create owner \"${userId}\".`,\n )\n }\n\n // Stage A — mint the owner keyring + merge the partition DEKs. Considered done\n // only when the keyring already holds every partition DEK. createOwnerKeyring\n // overwrites (fresh KEK + fresh _users DEK), so re-running is safe ONLY while\n // no recovery has been enrolled yet — guaranteed here because enrollment\n // (Stage C) runs strictly after Stage A completes.\n const partitionCollections = [...partitionDeks.keys()]\n const priorDeks = existingKeyring ? (JSON.parse(existingKeyring._data ?? '') as KeyringFile).deks : {}\n const ownerMinted = existingKeyring !== null && partitionCollections.every((c) => c in priorDeks)\n if (!ownerMinted) {\n // Resolve the owner secret. Managed mode mints a random secret, seals\n // it under the provider, and persists _meta/sealed-secret (so the\n // partition auto-unlocks on the recipient's device); standard mode uses the\n // caller's secret. Idempotent under retry — resolveManagedSecret's reopen\n // arm reuses an already-sealed secret.\n const secret = isManaged(opts)\n ? await resolveManagedSecret(store, vaultName, opts.sealingKey)\n : opts.secret\n\n // Mint the owner keyring (KEK + _users DEK + canary, written to disk).\n const unlocked = await createOwnerKeyring(store, vaultName, { userId: userId, secret: secret })\n\n // Merge the partition DEKs (wrapped under the new KEK) into the keyring.\n const env = await store.get(vaultName, '_keyring', userId)\n if (!env) throw new AdoptionStateError(`keyring write for \"${userId}\" did not persist`)\n const keyringFile = JSON.parse(env._data ?? '') as KeyringFile\n const kek = unlocked.kek\n if (!kek) throw new AdoptionStateError(`owner keyring for \"${userId}\" has no KEK to wrap partition DEKs under`)\n const mergedDeks: Record<string, string> = { ...keyringFile.deks }\n for (const [collection, dek] of partitionDeks) {\n mergedDeks[collection] = await wrapKey(dek, kek)\n }\n // #1115 — RESTAMP. The roster tag now covers the DEK key SET, and this merge\n // is precisely a change to that set: adoption joins the partition's\n // collections to a keyring `createOwnerKeyring` stamped moments earlier\n // without them. Writing the merged file under the old tag would leave every\n // adopted vault failing `roster-tag-mismatch` on its first open.\n //\n // The roster key is the one just minted for this NEW vault — unlike\n // `liberateVault`, which joins an EXISTING vault and must keep the\n // incumbent key so co-members can still verify each other.\n const merged: KeyringFile = { ...keyringFile, deks: mergedDeks }\n // #1097 — stamped BEFORE the tag is minted, so it lands inside the\n // authenticated canonical and a store can neither edit nor strip it.\n const withEpoch = stampAuthority(merged, keyringFile.roster_epoch)\n const rosterKey = requireRosterKey(unlocked, 'adoptPartition')\n const mergedFile: KeyringFile = { ...withEpoch, roster_tag: await mintRosterTag(withEpoch, rosterKey) }\n await store.put(vaultName, '_keyring', userId, { ...env, _data: JSON.stringify(mergedFile) })\n }\n\n // Stage B — record the ownership transition on the carried\n // audit chain (carryLedger sealed the _ledger DEK). No-op without that DEK.\n // Idempotent: appended only if the closing `transfer-seal-consumed` entry is\n // absent, so a retry does not duplicate the pair.\n const ledgerDek = partitionDeks.get(LEDGER_COLLECTION)\n if (ledgerDek) {\n const ledger = new LedgerStore({\n adapter: store,\n vault: vaultName,\n encrypted: true,\n getDEK: async () => ledgerDek,\n actor: userId,\n })\n const creationReason = `creation-of-new-owner:${userId}`\n const consumedReason = `transfer-seal-consumed:${adoption.sealId}`\n // Gate each append on its own presence — a crash or store error strictly\n // between the two adjacent puts would otherwise re-append the first one\n // on retry. The pair is the audit record, not a single transaction.\n const recordedReasons = new Set((await ledger.loadAllEntries()).map((e) => e.reason))\n if (!recordedReasons.has(creationReason)) {\n await ledger.append({ op: 'lifecycle', collection: '', id: '', version: 0, actor: '', payloadHash: '', reason: creationReason })\n }\n if (!recordedReasons.has(consumedReason)) {\n await ledger.append({ op: 'lifecycle', collection: '', id: '', version: 0, actor: '', payloadHash: '', reason: consumedReason })\n }\n }\n\n // Stage C — Managed mode: enroll the mandatory strong recovery\n // by orchestrating the existing public ceremony. The partition is\n // now a managed-mode vault on disk (sealed secret + keyring), so we\n // open it as a normal client and let openVaultAndEnrollRecovery do the\n // gate-bypass + enroll + re-assert. Dynamic import keeps the Noydb class\n // out of the @noy-db/hub/cargo static graph. Runs BEFORE seal destruction\n // so a failure here leaves the seal intact and the call retryable.\n if (isManaged(opts)) {\n const { createNoydb } = await import('../kernel/noydb.js')\n const db = await createNoydb({\n store,\n user: userId,\n secretMode: 'managed',\n sealingKey: opts.sealingKey,\n shamirRecovery: opts.shamirRecovery,\n })\n await db.team.openVaultAndEnrollRecovery(vaultName, { recovery: opts.recovery })\n }\n\n // Stage D — Destroy the transfer seal LAST — the commit point. Everything\n // above is either idempotent or resumable, so the seal is only consumed\n // once the owner keyring (and, in managed mode, strong recovery) is\n // durably in place. Retain sealId + consumedAt for audit.\n const consumed = { sealId: adoption.sealId, adoptedAt: adoption.adoptedAt, consumedAt: new Date().toISOString() }\n await store.put(vaultName, '_meta', 'adoption', { ...adoptionEnv, _data: JSON.stringify(consumed) })\n\n return { vaultName, userId }\n}\n","/**\n * Read-side counterpart to `extractPartition`: decrypt an\n * extracted-partition bundle's records to plaintext using its transfer\n * key, WITHOUT adopting it into a vault. Used by an outward\n * orchestration layer's reconcile/merge and field-authority flows to\n * compare incoming records against a receiver. The transfer key validates the bundle\n * (wrong key throws).\n * @module\n */\nimport type { EncryptedEnvelope } from '../kernel/types.js'\nimport { openEnvelopeJson } from '../capsule/index.js'\nimport { readPodHeader, readPod, parseExtractedPartitionBody } from '../with-pod/pod.js'\nimport { unsealDeks } from './adopt-partition.js'\n\n/** One decrypted record from an extracted-partition compartment. */\nexport interface DecryptedRecord {\n readonly id: string\n readonly record: Record<string, unknown>\n /** Source envelope write timestamp (ISO) — for last-write-wins merges. */\n readonly ts: string\n /** Source envelope version. */\n readonly version: number\n /** Provenance source id (FR-5). Present only when the source collection had provenance:true and a source was supplied on put. */\n readonly source?: string\n /** ISO-8601 timestamp the provenance source was recorded (FR-5). */\n readonly sourceTs?: string\n}\n\n/**\n * Decrypt every record of an extracted-partition bundle to plaintext,\n * grouped by collection. Throws if the bundle isn't an\n * extracted-partition or the transfer key is wrong.\n */\nexport async function decryptExtractedPartition(\n bundleBytes: Uint8Array,\n transferKey: Uint8Array,\n): Promise<Record<string, DecryptedRecord[]>> {\n const header = readPodHeader(bundleBytes)\n if (header.bundleKind !== 'extracted-partition' || header.transferSeal === undefined) {\n throw new Error('decryptExtractedPartition: bundle is not an extracted-partition.')\n }\n const { dumpJson } = await readPod(bundleBytes)\n const { dump, seal } = parseExtractedPartitionBody(dumpJson)\n const deks = await unsealDeks(seal, transferKey) // throws TransferSealError on wrong key\n const backup = JSON.parse(dump) as { collections: Record<string, Record<string, EncryptedEnvelope>> }\n const out: Record<string, DecryptedRecord[]> = {}\n for (const [collection, byId] of Object.entries(backup.collections)) {\n const dek = deks.get(collection)\n if (dek === undefined) continue // no DEK sealed for this collection — skip\n const recs: DecryptedRecord[] = []\n for (const [id, env] of Object.entries(byId)) {\n const plaintext = await openEnvelopeJson({ collection, id }, env, dek)\n const body = JSON.parse(plaintext) as Record<string, unknown>\n recs.push({\n id,\n record: { ...body, id },\n ts: env._ts,\n version: env._v,\n ...(env._source !== undefined ? { source: env._source } : {}),\n ...(env._sourceTs !== undefined ? { sourceTs: env._sourceTs } : {}),\n })\n }\n out[collection] = recs\n }\n return out\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/with-cargo/active.ts","../src/with-cargo/describe-extraction.ts","../src/with-cargo/adopt-partition.ts","../src/with-cargo/decrypt-partition.ts"],"sourcesContent":["/**\n * Enable the cargo (partition extraction) capability.\n * Pass to `createNoydb({ cargoStrategy: withCargo() })` to make the source-side\n * `extractPartition(vault, ...)` free function live. The extraction crypto\n * engine is dynamically imported here, so it stays out of the floor bundle\n * until opted in. The recipient-side `adoptPartition` /\n * `decryptExtractedPartition` free functions — and `diffVault` (shared\n * import/merge infra) — are ungated and unaffected.\n */\nimport type { CargoStrategy } from './strategy.js'\n\nexport function withCargo(): CargoStrategy {\n return {\n async extractPartition(vault, opts) {\n const { extractPartitionCore } = await import('./extract-partition.js')\n return extractPartitionCore(vault, opts)\n },\n }\n}\n","/**\n * Partition-extraction dry-run. Read-only preview of what an\n * `extractPartition` would move: record counts, byte totals, and the\n * timestamp span per collection — computed from raw encrypted\n * envelopes WITHOUT decrypting them. Writes nothing, mutates nothing.\n *\n * @module\n */\nimport type { Vault } from '../kernel/vault.js'\nimport { walkClosure, type WalkClosureOptions, type DanglingRefNotice } from './walk-closure.js'\n\nexport interface ExtractionPreview {\n readonly totalRecords: number\n /** Sum of serialized encrypted-envelope sizes (bytes). */\n readonly totalBytes: number\n readonly byCollection: ReadonlyArray<{\n readonly name: string\n readonly recordCount: number\n readonly bytes: number\n /** Earliest envelope `_ts` in this collection (lexicographic). */\n readonly oldestTs?: string\n readonly newestTs?: string\n }>\n readonly graph: { readonly depth: number; readonly cyclesDetected: boolean }\n /** Records the walk reached but whose envelope couldn't be read. */\n readonly inaccessible: ReadonlyArray<{ readonly collection: string; readonly id: string }>\n /**\n * #772: outbound FK edges whose referenced parent was excluded from the\n * closure (missing, or tier-elevated and therefore invisible) — mirrors\n * `ExtractPartitionResult.danglingRefs` (#759) so a preview/extract pair\n * gives the SAME signal. A parent excluded this way never appears in\n * `byCollection` at all; this is the only preview-time indicator.\n */\n readonly danglingRefs: ReadonlyArray<DanglingRefNotice>\n}\n\nexport async function describeExtraction(\n vault: Vault,\n opts: WalkClosureOptions,\n): Promise<ExtractionPreview> {\n const { closure, graph, danglingRefs } = await walkClosure(vault, opts)\n\n const { name: vaultName, adapter } = vault._introspectState()\n const encoder = new TextEncoder()\n\n const byCollection: Array<{\n name: string; recordCount: number; bytes: number; oldestTs?: string; newestTs?: string\n }> = []\n const inaccessible: Array<{ collection: string; id: string }> = []\n let totalBytes = 0\n let totalRecords = 0\n\n for (const [collectionName, ids] of closure) {\n let bytes = 0\n let oldestTs: string | undefined\n let newestTs: string | undefined\n let recordCount = 0\n\n for (const id of ids) {\n const env = await adapter.get(vaultName, collectionName, id)\n if (!env) {\n // Walk reached it (via decrypted list) but the raw store read\n // returned nothing — surface rather than miscount.\n inaccessible.push({ collection: collectionName, id })\n continue\n }\n recordCount++\n bytes += encoder.encode(JSON.stringify(env)).length\n const ts = env._ts\n if (oldestTs === undefined || ts < oldestTs) oldestTs = ts\n if (newestTs === undefined || ts > newestTs) newestTs = ts\n }\n\n byCollection.push({\n name: collectionName,\n recordCount,\n bytes,\n // Spread conditionally — exactOptionalPropertyTypes forbids an\n // explicit `undefined` on an optional property.\n ...(oldestTs !== undefined ? { oldestTs } : {}),\n ...(newestTs !== undefined ? { newestTs } : {}),\n })\n totalBytes += bytes\n totalRecords += recordCount\n }\n\n byCollection.sort((a, b) => a.name.localeCompare(b.name))\n\n return Object.freeze({\n totalRecords,\n totalBytes,\n byCollection,\n graph,\n inaccessible,\n danglingRefs,\n })\n}\n","/**\n * Partition adoption. Recipient side: verify an extracted bundle,\n * validate the transfer key, import the re-keyed collections into a\n * destination store, and record an `_meta/adoption` marker. The bundle\n * stays UNOWNED after adoption — `createOwnerOnAdoptedPartition`\n * mints the owner; the transfer seal is then destroyed.\n *\n * @module\n */\nimport {\n base64ToBuffer, bufferToBase64, wrapKey, importTransferKey, decryptBytes, importDekSet,\n type EnclaveKey,\n} from '../capsule/index.js'\nimport { TransferSealError, AdoptionStateError, ValidationError } from '../kernel/errors.js'\nimport type { NoydbStore, VaultSnapshot, KeyringFile } from '../kernel/types.js'\nimport { createOwnerKeyring, requireRosterKey } from '../with-party/team/keyring.js'\nimport { mintRosterTag } from '../with-party/team/roster-tag.js' // #1115\nimport { stampAuthority } from '../with-party/team/roster-tag.js'\nimport { resolveManagedSecret } from '../with-party/team/managed-secret.js'\nimport type { NoydbSealer } from '../with-party/team/managed-secret.js'\nimport type { NoydbShamir } from '../with-party/team/noydb-shamir.js'\nimport type { RecoveryEnrollmentInput } from '../with-party/team/rotate-recover.js'\nimport { LedgerStore } from '../with-commit/history/ledger/store.js'\nimport { LEDGER_COLLECTION } from '../with-commit/history/ledger/constants.js'\nimport type { TransferSealPayload } from '../with-pod/pod.js'\nimport { readPodHeader, readPod, parseExtractedPartitionBody } from '../with-pod/pod.js'\nimport { buildRecordEnvelope } from '../capsule/index.js'\n\n/**\n * Reverse of `sealDeks`. Imports the transfer key, decrypts the\n * sealed `{ collection: base64(rawDEK) }` map (layout iv(12)‖ct‖tag), and\n * re-imports each DEK as an AES-GCM key. Throws `TransferSealError` on a\n * wrong key (AES-GCM auth-tag failure) or malformed payload.\n */\nexport async function unsealDeks(\n seal: TransferSealPayload,\n transferKey: Uint8Array,\n): Promise<Map<string, EnclaveKey>> {\n if (transferKey.byteLength !== 32) {\n throw new TransferSealError(\n `transfer key must be 32 bytes, got ${transferKey.byteLength}.`,\n )\n }\n const key = await importTransferKey(transferKey)\n const raw = base64ToBuffer(seal.payload)\n let plaintext: Uint8Array\n try {\n plaintext = await decryptBytes(bufferToBase64(raw.slice(0, 12)), bufferToBase64(raw.slice(12)), key)\n } catch {\n throw new TransferSealError(\n 'transfer seal could not be opened — wrong transfer key (AES-GCM authentication failed).',\n )\n }\n let dekMap: Record<string, string>\n try {\n dekMap = JSON.parse(new TextDecoder().decode(plaintext)) as Record<string, string>\n } catch {\n throw new TransferSealError('transfer seal payload is not valid JSON after decryption.')\n }\n // Extractable: the recipient re-wraps these under their own KEK (AES-KW)\n // at owner-creation — importDekSet mints them the way generateDEK does.\n return importDekSet(dekMap)\n}\n\nexport interface AdoptPartitionOptions {\n readonly transferKey: Uint8Array\n readonly destinationStore: NoydbStore\n readonly vaultName: string\n}\n\nexport interface AdoptPartitionResult {\n readonly vaultName: string\n readonly needsOwner: true\n readonly sealId: string\n}\n\nexport async function adoptPartition(\n bundleBytes: Uint8Array,\n opts: AdoptPartitionOptions,\n): Promise<AdoptPartitionResult> {\n const { transferKey, destinationStore, vaultName } = opts\n\n const header = readPodHeader(bundleBytes)\n if (header.bundleKind !== 'extracted-partition' || header.transferSeal === undefined) {\n throw new ValidationError(\n 'adoptPartition requires an extracted-partition bundle with a transfer seal. '\n + 'For ordinary backups use readPod + vault.load.',\n )\n }\n\n const { dumpJson } = await readPod(bundleBytes)\n const { dump, seal } = parseExtractedPartitionBody(dumpJson)\n\n // Validate the transfer key by unsealing in memory; throws\n // TransferSealError on mismatch. DEKs are discarded here — they stay\n // sealed at rest (in _meta/adoption) until owner-creation wraps them under the\n // recipient's KEK.\n await unsealDeks(seal, transferKey)\n\n // Single-occupancy per vaultName: an `_meta/adoption` marker already present\n // means this slot holds a partition (adopted-and-unowned, or already owned).\n // saveAll below would overwrite its data and replace the marker, stranding the\n // prior adoption's transfer seal. Refuse regardless of sealId — re-adopting the\n // SAME bundle is a redundant call, and adopting a DIFFERENT bundle here would\n // clobber the existing partition. Either way, pick a fresh vaultName.\n const existing = await destinationStore.get(vaultName, '_meta', 'adoption')\n if (existing) {\n const prior = JSON.parse(existing._data ?? '') as { sealId?: string }\n if (prior.sealId === seal.sealId) {\n throw new AdoptionStateError(\n `partition (sealId ${seal.sealId}) is already adopted into vault \"${vaultName}\".`,\n )\n }\n throw new AdoptionStateError(\n `vault \"${vaultName}\" already holds an adopted partition (sealId ${prior.sealId}); `\n + `adopting a different partition (sealId ${seal.sealId}) here would overwrite it. `\n + `Adopt into a fresh vaultName instead.`,\n )\n }\n\n // The marker-only check above misses a worse case: a vaultName already in use\n // by an ORDINARY vault (createNoydb + openVault) carries no `_meta/adoption`,\n // yet `saveAll` below is destructive on SQL adapters (`DELETE FROM ... WHERE\n // vault = ?` followed by upsert) and would wipe the legitimate keyring +\n // data. Refuse adoption into ANY occupied slot — a fresh vaultName is the\n // documented precondition.\n const existingKeyring = await destinationStore.list(vaultName, '_keyring')\n if (existingKeyring.length > 0) {\n throw new AdoptionStateError(\n `vault \"${vaultName}\" already holds a keyring (an unrelated owner exists at this slot); `\n + `adoptPartition requires a fresh vaultName to avoid destructive saveAll on SQL adapters.`,\n )\n }\n\n const backup = JSON.parse(dump) as { collections: VaultSnapshot; _internal?: VaultSnapshot }\n await destinationStore.saveAll(vaultName, backup.collections)\n\n // Import carried internal collections (e.g. _schemas from carrySchemas).\n // saveAll only writes data collections; _internal is written per-record.\n if (backup._internal) {\n for (const [collection, records] of Object.entries(backup._internal)) {\n for (const [id, envelope] of Object.entries(records)) {\n await destinationStore.put(vaultName, collection, id, envelope)\n }\n }\n }\n\n const adoptedAt = new Date().toISOString()\n const adoption = { sealId: seal.sealId, adoptedAt, needsOwner: true as const, transferSeal: seal }\n await destinationStore.put(vaultName, '_meta', 'adoption',\n buildRecordEnvelope({ collection: '_meta', id: 'adoption', version: 1 },\n { ts: adoptedAt, iv: '', data: JSON.stringify(adoption) }))\n\n return { vaultName, needsOwner: true, sealId: seal.sealId }\n}\n\nexport interface CreateOwnerResult {\n readonly vaultName: string\n readonly userId: string\n}\n\n/** Standard-mode owner: recipient supplies the secret. */\nexport interface CreateOwnerStandardOptions {\n readonly userId: string\n readonly secret: string\n readonly transferKey: Uint8Array\n}\n\n/**\n * Managed-mode owner: the secret is minted + sealed under\n * a `NoydbSealer` (e.g. an `at-*` OS keychain) so the partition\n * auto-unlocks on the recipient's device. Managed mode mandates a strong\n * (Shamir) recovery profile at creation, which needs the\n * `shamirRecovery` provider injected.\n */\nexport interface CreateOwnerManagedOptions {\n readonly userId: string\n readonly secretMode: 'managed'\n readonly sealingKey: NoydbSealer\n readonly recovery: ReadonlyArray<RecoveryEnrollmentInput>\n readonly shamirRecovery: NoydbShamir\n readonly transferKey: Uint8Array\n}\n\nexport type CreateOwnerOptions = CreateOwnerStandardOptions | CreateOwnerManagedOptions\n\nfunction isManaged(o: CreateOwnerOptions): o is CreateOwnerManagedOptions {\n return 'secretMode' in o && o.secretMode === 'managed'\n}\n\n/**\n * Mint the first owner keyring on an adopted-but-unowned partition,\n * then destroy the transfer seal.\n *\n * Standard mode: the recipient supplies a secret. Managed mode: the\n * secret is minted + sealed under a `NoydbSealer` and a strong\n * (Shamir) recovery profile is enrolled — orchestrated via the existing\n * `openVaultAndEnrollRecovery` ceremony.\n *\n * Either way, reuses `createOwnerKeyring` to derive the KEK + write the base\n * keyring, then wraps the partition's DEKs (recovered from the seal) under that\n * KEK and re-persists the merged keyring file.\n *\n * Idempotent under retry: the seal is destroyed LAST (Stage D), after the\n * keyring (Stage A), the ledger transition (Stage B), and — in managed mode —\n * strong-recovery enrollment (Stage C). A failure in the fallible enrollment\n * step leaves the seal intact, and re-running with the same `userId` +\n * `transferKey` resumes from the first incomplete stage. (Multi-profile recovery\n * arrays may re-enroll an already-enrolled profile on retry; managed mode's\n * mandated single Shamir profile does not.)\n */\nexport async function createOwnerOnAdoptedPartition(\n store: NoydbStore,\n vaultName: string,\n opts: CreateOwnerOptions,\n): Promise<CreateOwnerResult> {\n const { userId, transferKey } = opts\n\n // Managed mode requires a strong (Shamir) recovery profile, validated BEFORE\n // any disk write — same gate as createNoydb.\n if (isManaged(opts) && !opts.recovery.some((r) => r.profile === 'shamir')) {\n throw new AdoptionStateError(\n 'managed-mode adoption requires at least one strong (shamir) recovery profile in '\n + '`recovery` — paper alone is not strong when there is no user secret to fall back on.',\n )\n }\n\n // 1. Verify adopted-unowned state.\n const adoptionEnv = await store.get(vaultName, '_meta', 'adoption')\n if (!adoptionEnv) {\n throw new AdoptionStateError(\n `vault \"${vaultName}\" is not an adopted partition (no _meta/adoption). `\n + `createOwnerOnAdoptedPartition only applies to vaults created via adoptPartition.`,\n )\n }\n const adoption = JSON.parse(adoptionEnv._data ?? '') as {\n sealId: string; adoptedAt: string; needsOwner?: boolean\n consumedAt?: string; transferSeal?: TransferSealPayload\n }\n if (adoption.consumedAt !== undefined || adoption.transferSeal === undefined) {\n throw new AdoptionStateError(\n `vault \"${vaultName}\" already has an owner (transfer seal consumed at ${adoption.consumedAt}).`,\n )\n }\n\n // 2. Recover the partition DEKs from the seal (throws on wrong key) BEFORE\n // writing any keyring, so a bad transfer key leaves no trace. Always\n // validated, including when resuming a partial prior call.\n const partitionDeks = await unsealDeks(adoption.transferSeal, transferKey)\n\n // The ceremony below is split into stages so a failure in the fallible\n // managed-enrollment step (network/provider outage) leaves the call RETRYABLE\n // — the seal is destroyed only once everything durable is in place. Each stage\n // detects its own prior completion rather than relying on a single resume bit.\n\n // A keyring present for a DIFFERENT user (with the seal still unconsumed) is a\n // genuine second-owner attempt — refuse it. A same-user keyring is a resumed\n // partial call and is handled by the stage checks below.\n const existingKeyring = await store.get(vaultName, '_keyring', userId)\n const otherOwners = (await store.list(vaultName, '_keyring')).filter((u) => u !== userId)\n if (otherOwners.length > 0) {\n throw new AdoptionStateError(\n `vault \"${vaultName}\" already has a keyring for a different owner; cannot create owner \"${userId}\".`,\n )\n }\n\n // Stage A — mint the owner keyring + merge the partition DEKs. Considered done\n // only when the keyring already holds every partition DEK. createOwnerKeyring\n // overwrites (fresh KEK + fresh _users DEK), so re-running is safe ONLY while\n // no recovery has been enrolled yet — guaranteed here because enrollment\n // (Stage C) runs strictly after Stage A completes.\n const partitionCollections = [...partitionDeks.keys()]\n const priorDeks = existingKeyring ? (JSON.parse(existingKeyring._data ?? '') as KeyringFile).deks : {}\n const ownerMinted = existingKeyring !== null && partitionCollections.every((c) => c in priorDeks)\n if (!ownerMinted) {\n // Resolve the owner secret. Managed mode mints a random secret, seals\n // it under the provider, and persists _meta/sealed-secret (so the\n // partition auto-unlocks on the recipient's device); standard mode uses the\n // caller's secret. Idempotent under retry — resolveManagedSecret's reopen\n // arm reuses an already-sealed secret.\n const secret = isManaged(opts)\n ? await resolveManagedSecret(store, vaultName, opts.sealingKey)\n : opts.secret\n\n // Mint the owner keyring (KEK + _users DEK + canary, written to disk).\n const unlocked = await createOwnerKeyring(store, vaultName, { userId: userId, secret: secret })\n\n // Merge the partition DEKs (wrapped under the new KEK) into the keyring.\n const env = await store.get(vaultName, '_keyring', userId)\n if (!env) throw new AdoptionStateError(`keyring write for \"${userId}\" did not persist`)\n const keyringFile = JSON.parse(env._data ?? '') as KeyringFile\n const kek = unlocked.kek\n if (!kek) throw new AdoptionStateError(`owner keyring for \"${userId}\" has no KEK to wrap partition DEKs under`)\n const mergedDeks: Record<string, string> = { ...keyringFile.deks }\n for (const [collection, dek] of partitionDeks) {\n mergedDeks[collection] = await wrapKey(dek, kek)\n }\n // #1115 — RESTAMP. The roster tag now covers the DEK key SET, and this merge\n // is precisely a change to that set: adoption joins the partition's\n // collections to a keyring `createOwnerKeyring` stamped moments earlier\n // without them. Writing the merged file under the old tag would leave every\n // adopted vault failing `roster-tag-mismatch` on its first open.\n //\n // The roster key is the one just minted for this NEW vault — unlike\n // `liberateVault`, which joins an EXISTING vault and must keep the\n // incumbent key so co-members can still verify each other.\n const merged: KeyringFile = { ...keyringFile, deks: mergedDeks }\n // #1097 — stamped BEFORE the tag is minted, so it lands inside the\n // authenticated canonical and a store can neither edit nor strip it.\n const withEpoch = stampAuthority(merged, keyringFile.roster_epoch)\n const rosterKey = requireRosterKey(unlocked, 'adoptPartition')\n const mergedFile: KeyringFile = { ...withEpoch, roster_tag: await mintRosterTag(withEpoch, rosterKey) }\n // core#132 — CAS on the envelope this merge was computed from; see liberate.ts.\n await store.put(vaultName, '_keyring', userId, { ...env, _v: env._v + 1, _data: JSON.stringify(mergedFile) }, env._v)\n }\n\n // Stage B — record the ownership transition on the carried\n // audit chain (carryLedger sealed the _ledger DEK). No-op without that DEK.\n // Idempotent: appended only if the closing `transfer-seal-consumed` entry is\n // absent, so a retry does not duplicate the pair.\n const ledgerDek = partitionDeks.get(LEDGER_COLLECTION)\n if (ledgerDek) {\n const ledger = new LedgerStore({\n adapter: store,\n vault: vaultName,\n encrypted: true,\n getDEK: async () => ledgerDek,\n actor: userId,\n })\n const creationReason = `creation-of-new-owner:${userId}`\n const consumedReason = `transfer-seal-consumed:${adoption.sealId}`\n // Gate each append on its own presence — a crash or store error strictly\n // between the two adjacent puts would otherwise re-append the first one\n // on retry. The pair is the audit record, not a single transaction.\n const recordedReasons = new Set((await ledger.loadAllEntries()).map((e) => e.reason))\n if (!recordedReasons.has(creationReason)) {\n await ledger.append({ op: 'lifecycle', collection: '', id: '', version: 0, actor: '', payloadHash: '', reason: creationReason })\n }\n if (!recordedReasons.has(consumedReason)) {\n await ledger.append({ op: 'lifecycle', collection: '', id: '', version: 0, actor: '', payloadHash: '', reason: consumedReason })\n }\n }\n\n // Stage C — Managed mode: enroll the mandatory strong recovery\n // by orchestrating the existing public ceremony. The partition is\n // now a managed-mode vault on disk (sealed secret + keyring), so we\n // open it as a normal client and let openVaultAndEnrollRecovery do the\n // gate-bypass + enroll + re-assert. Dynamic import keeps the Noydb class\n // out of the @noy-db/hub/cargo static graph. Runs BEFORE seal destruction\n // so a failure here leaves the seal intact and the call retryable.\n if (isManaged(opts)) {\n const { createNoydb } = await import('../kernel/noydb.js')\n const db = await createNoydb({\n store,\n user: userId,\n secretMode: 'managed',\n sealingKey: opts.sealingKey,\n shamirRecovery: opts.shamirRecovery,\n })\n await db.team.openVaultAndEnrollRecovery(vaultName, { recovery: opts.recovery })\n }\n\n // Stage D — Destroy the transfer seal LAST — the commit point. Everything\n // above is either idempotent or resumable, so the seal is only consumed\n // once the owner keyring (and, in managed mode, strong recovery) is\n // durably in place. Retain sealId + consumedAt for audit.\n const consumed = { sealId: adoption.sealId, adoptedAt: adoption.adoptedAt, consumedAt: new Date().toISOString() }\n await store.put(vaultName, '_meta', 'adoption', { ...adoptionEnv, _data: JSON.stringify(consumed) })\n\n return { vaultName, userId }\n}\n","/**\n * Read-side counterpart to `extractPartition`: decrypt an\n * extracted-partition bundle's records to plaintext using its transfer\n * key, WITHOUT adopting it into a vault. Used by an outward\n * orchestration layer's reconcile/merge and field-authority flows to\n * compare incoming records against a receiver. The transfer key validates the bundle\n * (wrong key throws).\n * @module\n */\nimport type { EncryptedEnvelope } from '../kernel/types.js'\nimport { openEnvelopeJson } from '../capsule/index.js'\nimport { readPodHeader, readPod, parseExtractedPartitionBody } from '../with-pod/pod.js'\nimport { unsealDeks } from './adopt-partition.js'\n\n/** One decrypted record from an extracted-partition compartment. */\nexport interface DecryptedRecord {\n readonly id: string\n readonly record: Record<string, unknown>\n /** Source envelope write timestamp (ISO) — for last-write-wins merges. */\n readonly ts: string\n /** Source envelope version. */\n readonly version: number\n /** Provenance source id (FR-5). Present only when the source collection had provenance:true and a source was supplied on put. */\n readonly source?: string\n /** ISO-8601 timestamp the provenance source was recorded (FR-5). */\n readonly sourceTs?: string\n}\n\n/**\n * Decrypt every record of an extracted-partition bundle to plaintext,\n * grouped by collection. Throws if the bundle isn't an\n * extracted-partition or the transfer key is wrong.\n */\nexport async function decryptExtractedPartition(\n bundleBytes: Uint8Array,\n transferKey: Uint8Array,\n): Promise<Record<string, DecryptedRecord[]>> {\n const header = readPodHeader(bundleBytes)\n if (header.bundleKind !== 'extracted-partition' || header.transferSeal === undefined) {\n throw new Error('decryptExtractedPartition: bundle is not an extracted-partition.')\n }\n const { dumpJson } = await readPod(bundleBytes)\n const { dump, seal } = parseExtractedPartitionBody(dumpJson)\n const deks = await unsealDeks(seal, transferKey) // throws TransferSealError on wrong key\n const backup = JSON.parse(dump) as { collections: Record<string, Record<string, EncryptedEnvelope>> }\n const out: Record<string, DecryptedRecord[]> = {}\n for (const [collection, byId] of Object.entries(backup.collections)) {\n const dek = deks.get(collection)\n if (dek === undefined) continue // no DEK sealed for this collection — skip\n const recs: DecryptedRecord[] = []\n for (const [id, env] of Object.entries(byId)) {\n const plaintext = await openEnvelopeJson({ collection, id }, env, dek)\n const body = JSON.parse(plaintext) as Record<string, unknown>\n recs.push({\n id,\n record: { ...body, id },\n ts: env._ts,\n version: env._v,\n ...(env._source !== undefined ? { source: env._source } : {}),\n ...(env._sourceTs !== undefined ? { sourceTs: env._sourceTs } : {}),\n })\n }\n out[collection] = recs\n }\n return out\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getHistory,
|
|
3
3
|
historyIdentity
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-EQ6C2ZPT.js";
|
|
5
5
|
import {
|
|
6
6
|
liveRecordIsElevated
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-LJ744WXU.js";
|
|
8
8
|
import {
|
|
9
9
|
openEnvelopeJson
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-WRLWEYHY.js";
|
|
11
11
|
import {
|
|
12
12
|
ReadOnlyAtInstantError
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-2RH5SEY7.js";
|
|
14
14
|
|
|
15
15
|
// src/with-commit/history/time-machine.ts
|
|
16
16
|
var VaultInstant = class {
|
|
@@ -208,4 +208,4 @@ export {
|
|
|
208
208
|
VaultInstant,
|
|
209
209
|
CollectionInstant
|
|
210
210
|
};
|
|
211
|
-
//# sourceMappingURL=chunk-
|
|
211
|
+
//# sourceMappingURL=chunk-KBIS64X4.js.map
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import {
|
|
2
|
+
historyIdentity
|
|
3
|
+
} from "./chunk-EQ6C2ZPT.js";
|
|
4
|
+
|
|
5
|
+
// src/with-commit/history/strategy.ts
|
|
6
|
+
function notEnabled(op) {
|
|
7
|
+
return new Error(
|
|
8
|
+
`${op} requires the history strategy. Import \`{ withHistory }\` from "@noy-db/hub/history" and pass it to \`createNoydb({ historyStrategy: withHistory() })\`.`
|
|
9
|
+
);
|
|
10
|
+
}
|
|
11
|
+
var NO_HISTORY = {
|
|
12
|
+
async saveHistory() {
|
|
13
|
+
},
|
|
14
|
+
// Unreachable in practice — `saveHistory` above is a no-op, so nothing is
|
|
15
|
+
// ever sealed. Returns the real layout rather than a sentinel so a future
|
|
16
|
+
// caller that reads it without writing cannot be misled.
|
|
17
|
+
historyIdentity: (collection, recordId, version) => historyIdentity(collection, recordId, version),
|
|
18
|
+
async getHistoryEntries() {
|
|
19
|
+
throw notEnabled("collection.history()");
|
|
20
|
+
},
|
|
21
|
+
async getVersionEnvelope() {
|
|
22
|
+
throw notEnabled("collection.getVersion()");
|
|
23
|
+
},
|
|
24
|
+
async pruneHistory() {
|
|
25
|
+
return 0;
|
|
26
|
+
},
|
|
27
|
+
async clearHistory() {
|
|
28
|
+
return 0;
|
|
29
|
+
},
|
|
30
|
+
async tombstoneHistory() {
|
|
31
|
+
return 0;
|
|
32
|
+
},
|
|
33
|
+
async rewrapHistory() {
|
|
34
|
+
},
|
|
35
|
+
async envelopePayloadHash() {
|
|
36
|
+
return "";
|
|
37
|
+
},
|
|
38
|
+
computePatch() {
|
|
39
|
+
return [];
|
|
40
|
+
},
|
|
41
|
+
diff() {
|
|
42
|
+
throw notEnabled("collection.diff()");
|
|
43
|
+
},
|
|
44
|
+
buildLedger() {
|
|
45
|
+
return null;
|
|
46
|
+
},
|
|
47
|
+
buildVaultInstant() {
|
|
48
|
+
throw notEnabled("vault.at() / vault.timeMachine()");
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export {
|
|
53
|
+
NO_HISTORY
|
|
54
|
+
};
|
|
55
|
+
//# sourceMappingURL=chunk-L4UL4IAR.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/with-commit/history/strategy.ts"],"sourcesContent":["/**\n * Strategy seam for the optional history + ledger + time-machine\n * service. Core imports `HistoryStrategy` type-only + `NO_HISTORY`\n * stub; real implementations of `saveHistory`, `LedgerStore`,\n * `VaultInstant`, `computePatch`, `diff` etc. are only reachable via\n * `withHistory()` in `./active.ts`.\n *\n * Applications that don't track per-record versioning, don't need the\n * hash-chained audit ledger, and don't restore to past instants ship\n * none of the ~1,880 LOC behind this seam.\n *\n * Strategy contract:\n *\n * - **saveHistory / pruneHistory / clearHistory** — no-ops under\n * NO_HISTORY. Writes still succeed; no snapshot is captured.\n * - **getHistoryEntries / getVersionEnvelope / diff** — throw under\n * NO_HISTORY. These are read APIs the consumer would only call\n * after explicitly asking for history; the throw guides them to\n * `@noy-db/hub/history`.\n * - **envelopePayloadHash / computePatch** — return empty / `[]`\n * under NO_HISTORY. These are only used inside the\n * `if (this.ledger)` branch, which is itself gated by\n * `buildLedger()` returning null.\n * - **buildLedger** — returns `null` under NO_HISTORY. The Vault's\n * public `vault.ledger()` accessor throws when null.\n * - **buildVaultInstant** — throws under NO_HISTORY. `vault.at()`\n * propagates the throw.\n *\n * @internal\n */\n\nimport type {\n EncryptedEnvelope,\n NoydbStore,\n HistoryOptions,\n PruneOptions,\n} from '../../kernel/types.js'\nimport type { LedgerStore } from './ledger/store.js'\nimport type { JsonPatch } from './ledger/patch.js'\nimport type { DiffEntry } from './diff.js'\nimport type { VaultInstant, VaultEngine } from './time-machine.js'\nimport type { EnclaveKey, RecordIdentity } from '../../capsule/index.js'\nimport { historyIdentity } from './history.js'\n\n/**\n * Options accepted by `HistoryStrategy.buildLedger`. Mirrors the\n * `LedgerStore` constructor verbatim — kept in this file so `core`\n * code never imports the LedgerStore module at runtime.\n *\n * @internal\n */\nexport interface BuildLedgerOptions {\n adapter: NoydbStore\n vault: string\n encrypted: boolean\n getDEK: (collectionName: string) => Promise<EnclaveKey>\n actor: string\n}\n\n/**\n * @internal\n */\nexport interface HistoryStrategy {\n /**\n * Persist a full encrypted envelope snapshot of the prior version\n * under `_history/{collection}:{id}:{paddedVersion}`. No-op under\n * `NO_HISTORY`.\n */\n saveHistory(\n adapter: NoydbStore,\n vault: string,\n collection: string,\n recordId: string,\n envelope: EncryptedEnvelope,\n ): Promise<void>\n\n /**\n * The identity a snapshot of `collection/recordId@version` must be **sealed\n * against** — its `_history` storage location (#1041).\n *\n * On the port because the kernel writes history snapshots but must not import\n * `with-commit` to learn its layout. Exposing it here keeps the derivation in\n * the module that owns the layout, and `saveHistory` uses the same function,\n * so the sealed identity and the put location cannot drift.\n */\n historyIdentity(collection: string, recordId: string, version: number): RecordIdentity\n\n /**\n * List history envelopes for a record, newest first. Throws under\n * `NO_HISTORY` — callers reach this via `collection.history()` /\n * `collection.getVersion()` / `collection.diff()`, which only work\n * with the strategy enabled.\n */\n getHistoryEntries(\n adapter: NoydbStore,\n vault: string,\n collection: string,\n recordId: string,\n options?: HistoryOptions,\n ): Promise<EncryptedEnvelope[]>\n\n /**\n * Fetch a specific version's envelope. Throws under `NO_HISTORY`.\n */\n getVersionEnvelope(\n adapter: NoydbStore,\n vault: string,\n collection: string,\n recordId: string,\n version: number,\n ): Promise<EncryptedEnvelope | null>\n\n /**\n * Prune history entries by retention rule. Returns `0` under\n * `NO_HISTORY`.\n */\n pruneHistory(\n adapter: NoydbStore,\n vault: string,\n collection: string,\n recordId: string | undefined,\n options: PruneOptions,\n ): Promise<number>\n\n /**\n * Clear all history for vault/collection/record. Returns `0` under\n * `NO_HISTORY`.\n */\n clearHistory(\n adapter: NoydbStore,\n vault: string,\n collection?: string,\n recordId?: string,\n ): Promise<number>\n\n /**\n * Crypto-shred (overwrite-to-tombstone) every `_history` version of a\n * record for GDPR erasure. Returns the number of versions newly\n * tombstoned, or `0` under `NO_HISTORY` (no history = nothing to shred).\n */\n tombstoneHistory(\n adapter: NoydbStore,\n vault: string,\n collection: string,\n recordId: string,\n actor: string,\n encrypted: boolean,\n ): Promise<number>\n\n /**\n * Re-key every `_history` snapshot of a record from `fromDek` to `toDek`\n * on a tier move (elevate/demote/putAtTier), mirroring the live-body\n * rewrap so prior versions are not left decryptable at rest under a tier\n * the record has moved away from. Optional `tier0Dek` enables the legacy\n * fallback for snapshots written before this rewrap existed (see\n * `history.ts` for the full contract). No-op under `NO_HISTORY` (no\n * history = nothing to rewrap).\n */\n rewrapHistory(\n adapter: NoydbStore,\n vault: string,\n collection: string,\n recordId: string,\n fromDek: EnclaveKey,\n toDek: EnclaveKey,\n tier0Dek?: EnclaveKey,\n ): Promise<void>\n\n /**\n * Compute the SHA-256 hash of an envelope's encrypted payload, used\n * by `LedgerStore.append` to track tamper-evidence. Returns the\n * empty string under `NO_HISTORY` (the call site is gated by\n * `if (this.ledger)`, so the value is never observed).\n */\n envelopePayloadHash(envelope: EncryptedEnvelope | null): Promise<string>\n\n /**\n * Compute the JSON patch from `from` → `to`. Returns `[]` under\n * `NO_HISTORY`.\n */\n computePatch(from: unknown, to: unknown): JsonPatch\n\n /**\n * Compute the typed diff between two records. Throws under\n * `NO_HISTORY` — `collection.diff()` is a history-read API.\n */\n diff(recordA: unknown, recordB: unknown): DiffEntry[]\n\n /**\n * Construct (or return null) a `LedgerStore` for the vault. Returns\n * `null` under `NO_HISTORY`; the Vault treats null as \"no ledger\n * attached\" — collection write paths skip the append branch and the\n * public `vault.ledger()` accessor throws.\n */\n buildLedger(opts: BuildLedgerOptions): LedgerStore | null\n\n /**\n * Construct a `VaultInstant` for time-machine reads. Throws under\n * `NO_HISTORY`.\n */\n buildVaultInstant(engine: VaultEngine, timestamp: string): VaultInstant\n}\n\n/**\n * Error thrown when the consumer reaches a history-gated surface\n * without opting into the strategy. The message names the offending\n * operation and points to the subpath import.\n *\n * @internal\n */\nfunction notEnabled(op: string): Error {\n return new Error(\n `${op} requires the history strategy. Import ` +\n '`{ withHistory }` from \"@noy-db/hub/history\" and pass it to ' +\n '`createNoydb({ historyStrategy: withHistory() })`.',\n )\n}\n\n/**\n * No-history stub. Snapshots and prune/clear are no-ops; reads and\n * time-machine throw with an actionable message; ledger construction\n * returns null so the write-path's `if (this.ledger)` branch is dead\n * code in the bundle.\n *\n * @internal\n */\nexport const NO_HISTORY: HistoryStrategy = {\n async saveHistory() {},\n // Unreachable in practice — `saveHistory` above is a no-op, so nothing is\n // ever sealed. Returns the real layout rather than a sentinel so a future\n // caller that reads it without writing cannot be misled.\n historyIdentity: (collection, recordId, version) => historyIdentity(collection, recordId, version),\n async getHistoryEntries() { throw notEnabled('collection.history()') },\n async getVersionEnvelope() { throw notEnabled('collection.getVersion()') },\n async pruneHistory() { return 0 },\n async clearHistory() { return 0 },\n async tombstoneHistory() { return 0 },\n async rewrapHistory() {},\n async envelopePayloadHash() { return '' },\n computePatch() { return [] },\n diff() { throw notEnabled('collection.diff()') },\n buildLedger() { return null },\n buildVaultInstant() { throw notEnabled('vault.at() / vault.timeMachine()') },\n}\n"],"mappings":";;;;;AAkNA,SAAS,WAAW,IAAmB;AACrC,SAAO,IAAI;AAAA,IACT,GAAG,EAAE;AAAA,EAGP;AACF;AAUO,IAAM,aAA8B;AAAA,EACzC,MAAM,cAAc;AAAA,EAAC;AAAA;AAAA;AAAA;AAAA,EAIrB,iBAAiB,CAAC,YAAY,UAAU,YAAY,gBAAgB,YAAY,UAAU,OAAO;AAAA,EACjG,MAAM,oBAAoB;AAAE,UAAM,WAAW,sBAAsB;AAAA,EAAE;AAAA,EACrE,MAAM,qBAAqB;AAAE,UAAM,WAAW,yBAAyB;AAAA,EAAE;AAAA,EACzE,MAAM,eAAe;AAAE,WAAO;AAAA,EAAE;AAAA,EAChC,MAAM,eAAe;AAAE,WAAO;AAAA,EAAE;AAAA,EAChC,MAAM,mBAAmB;AAAE,WAAO;AAAA,EAAE;AAAA,EACpC,MAAM,gBAAgB;AAAA,EAAC;AAAA,EACvB,MAAM,sBAAsB;AAAE,WAAO;AAAA,EAAG;AAAA,EACxC,eAAe;AAAE,WAAO,CAAC;AAAA,EAAE;AAAA,EAC3B,OAAO;AAAE,UAAM,WAAW,mBAAmB;AAAA,EAAE;AAAA,EAC/C,cAAc;AAAE,WAAO;AAAA,EAAK;AAAA,EAC5B,oBAAoB;AAAE,UAAM,WAAW,kCAAkC;AAAA,EAAE;AAC7E;","names":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
TierWriteRefusedError
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-2RH5SEY7.js";
|
|
4
4
|
|
|
5
5
|
// src/kernel/tier-visibility.ts
|
|
6
6
|
async function peekLiveTier(adapter, vault, name, id) {
|
|
@@ -49,4 +49,4 @@ export {
|
|
|
49
49
|
dekKey,
|
|
50
50
|
parseDekKey
|
|
51
51
|
};
|
|
52
|
-
//# sourceMappingURL=chunk-
|
|
52
|
+
//# sourceMappingURL=chunk-LJ744WXU.js.map
|
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
import {
|
|
2
2
|
freezeSnapshotOnly
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-FUHUGKDN.js";
|
|
4
4
|
import {
|
|
5
5
|
resolveManagedSecret
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-GU6QXHPZ.js";
|
|
7
7
|
import {
|
|
8
8
|
assertRosterTagValid,
|
|
9
9
|
createOwnerKeyring,
|
|
10
10
|
mintRosterTag,
|
|
11
11
|
requireRosterKey,
|
|
12
12
|
stampAuthority
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-QVUMKG3Z.js";
|
|
14
14
|
import {
|
|
15
15
|
buildRecordEnvelope,
|
|
16
16
|
wrapKey
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-WRLWEYHY.js";
|
|
18
18
|
import {
|
|
19
19
|
PermissionDeniedError
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-2RH5SEY7.js";
|
|
21
21
|
|
|
22
22
|
// src/with-party/team/deed.ts
|
|
23
23
|
var DEED_RECORD_ID = "deed";
|
|
@@ -108,7 +108,7 @@ async function liberateVault(vault, opts) {
|
|
|
108
108
|
const merged = { ...keyringFile, deks: mergedDeks };
|
|
109
109
|
const withEpoch = stampAuthority(merged, keyringFile.roster_epoch);
|
|
110
110
|
const mergedFile = { ...withEpoch, roster_tag: await mintRosterTag(withEpoch, rosterKey) };
|
|
111
|
-
await adapter.put(vaultName, "_keyring", opts.newOwnerId, { ...env, _data: JSON.stringify(mergedFile) });
|
|
111
|
+
await adapter.put(vaultName, "_keyring", opts.newOwnerId, { ...env, _v: env._v + 1, _data: JSON.stringify(mergedFile) }, env._v);
|
|
112
112
|
await vault._getLedgerOrNull()?.append({
|
|
113
113
|
op: "lifecycle",
|
|
114
114
|
collection: "",
|
|
@@ -135,4 +135,4 @@ export {
|
|
|
135
135
|
isDeedVault,
|
|
136
136
|
liberateVault
|
|
137
137
|
};
|
|
138
|
-
//# sourceMappingURL=chunk-
|
|
138
|
+
//# sourceMappingURL=chunk-LMC5L3MM.js.map
|