@noy-db/hub 0.8.0 → 0.9.0-pre.1
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 +49 -0
- package/README.md +8 -8
- package/codemods/0.4.0-pre.json +1 -1
- package/codemods/0.8.0-pre.json +1 -1
- package/dist/api-6EFD43KN.js +18 -0
- package/dist/as/index.js +33 -23
- package/dist/as/index.js.map +1 -1
- package/dist/at/index.js +8 -8
- package/dist/attestation/index.js +18 -18
- package/dist/{backup-YE2VQ26S.js → backup-RJBFQSHE.js} +92 -31
- package/dist/backup-RJBFQSHE.js.map +1 -0
- package/dist/blobs/index.js +12 -12
- package/dist/broker/index.js +19 -11
- package/dist/broker/index.js.map +1 -1
- package/dist/by/index.js +2 -2
- package/dist/capsule/contract.d.ts +1 -1
- package/dist/capsule/contract.js +6 -6
- package/dist/capsule/enclave-aes/broker/proof.d.ts +12 -3
- package/dist/capsule/enclave-aes/crypto.d.ts +18 -0
- package/dist/capsule/enclave-aes/index.d.ts +3 -3
- package/dist/capsule/enclave-aes/index.js +46 -14
- package/dist/capsule/enclave-aes/index.js.map +1 -1
- package/dist/capsule/index.d.ts +2 -2
- package/dist/capsule/plumbing/record-codec.d.ts +7 -0
- package/dist/{capsule-VOLX3QRQ.js → capsule-6LJAVQNM.js} +14 -8
- package/dist/cargo/index.js +35 -35
- package/dist/{chunk-GZT3NQRA.js → chunk-25FXU6WS.js} +8 -2
- package/dist/chunk-25FXU6WS.js.map +1 -0
- package/dist/{chunk-OYW3I5M4.js → chunk-2DOCDOPL.js} +6 -6
- package/dist/chunk-2DX4JCRI.js +1 -0
- package/dist/{chunk-FLPCETP6.js → chunk-2LBS62AC.js} +2 -2
- package/dist/{chunk-WXE4W2U6.js → chunk-2ST3WA3C.js} +4 -4
- package/dist/{chunk-DQESF6RP.js → chunk-3G3GOGZZ.js} +50 -40
- package/dist/chunk-3G3GOGZZ.js.map +1 -0
- package/dist/{chunk-O2IMQSNA.js → chunk-3YBIVLTC.js} +2 -2
- package/dist/{chunk-LGNDFRYC.js → chunk-4CFHL5RY.js} +1 -1
- package/dist/chunk-4CFHL5RY.js.map +1 -0
- package/dist/{chunk-DIZLQVAA.js → chunk-4CHM2TRS.js} +2 -2
- package/dist/{chunk-V7ADQF5O.js → chunk-4CUJLEOA.js} +4 -4
- package/dist/{chunk-3EWS67C7.js → chunk-4TG2ITRW.js} +2 -2
- package/dist/{chunk-HS554XAF.js → chunk-5HQFROZS.js} +2 -2
- package/dist/{chunk-IUBMZPHM.js → chunk-5ZVE3N5C.js} +5 -6
- package/dist/chunk-5ZVE3N5C.js.map +1 -0
- package/dist/{chunk-PP3K67AJ.js → chunk-654RE5YC.js} +3 -3
- package/dist/{chunk-FOEDQATO.js → chunk-66GD7XXU.js} +2 -2
- package/dist/{chunk-BNWA3WG5.js → chunk-72FQ46VW.js} +3 -3
- package/dist/{chunk-EYG2CY2X.js → chunk-7JPA3LIH.js} +11 -11
- package/dist/chunk-7JPA3LIH.js.map +1 -0
- package/dist/{chunk-JQYKPKG6.js → chunk-7K42TSCY.js} +4 -4
- package/dist/{chunk-BPWYQ25R.js → chunk-7Q6IU3R7.js} +4 -4
- package/dist/{chunk-BPWYQ25R.js.map → chunk-7Q6IU3R7.js.map} +1 -1
- package/dist/{chunk-T7IR4N2S.js → chunk-7UHLO4ZN.js} +37 -2
- package/dist/chunk-7UHLO4ZN.js.map +1 -0
- package/dist/{chunk-UEFOQH74.js → chunk-ADCXTW7L.js} +2 -2
- package/dist/{chunk-MBMTND6D.js → chunk-AGGPT4UE.js} +2 -2
- package/dist/{chunk-RB4DOPGZ.js → chunk-AKIEBFIJ.js} +10 -10
- package/dist/{chunk-VHBKYN2J.js → chunk-B3B6HV5S.js} +2 -2
- package/dist/{chunk-JWWYRR4Q.js → chunk-B6EWMGFX.js} +2 -2
- package/dist/{chunk-H7JBY4P7.js → chunk-B7Y2BRQA.js} +14 -14
- package/dist/chunk-B7Y2BRQA.js.map +1 -0
- package/dist/{chunk-4CIQDWRB.js → chunk-BFJE2GPP.js} +14 -8
- package/dist/{chunk-4CIQDWRB.js.map → chunk-BFJE2GPP.js.map} +1 -1
- package/dist/{chunk-WPOYWFSE.js → chunk-BJRKXNFP.js} +7 -7
- package/dist/{chunk-H427H63K.js → chunk-BPQ5CRJF.js} +2 -2
- package/dist/{chunk-VFHCKG5M.js → chunk-BVRJYMFZ.js} +3 -3
- package/dist/{chunk-244QBK7Z.js → chunk-C4XV3PSJ.js} +4 -4
- package/dist/{chunk-244QBK7Z.js.map → chunk-C4XV3PSJ.js.map} +1 -1
- package/dist/{chunk-SMV2HRDU.js → chunk-DFC4WTJW.js} +2 -2
- package/dist/{chunk-5A4345TG.js → chunk-DMIEKD24.js} +3 -3
- package/dist/{chunk-TKVUE4JF.js → chunk-DQAXA2GK.js} +9 -9
- package/dist/{chunk-AL6ML4LA.js → chunk-DWCFGF2K.js} +5 -5
- package/dist/{chunk-Y3LPTBG7.js → chunk-E2C6FFSI.js} +6 -9
- package/dist/chunk-E2C6FFSI.js.map +1 -0
- package/dist/{chunk-LNSVGRHO.js → chunk-EQ6C2ZPT.js} +17 -51
- package/dist/chunk-EQ6C2ZPT.js.map +1 -0
- package/dist/chunk-EZOFTI4K.js +60 -0
- package/dist/chunk-EZOFTI4K.js.map +1 -0
- package/dist/{chunk-PD64727P.js → chunk-FMINS2B6.js} +2 -2
- package/dist/chunk-FMINS2B6.js.map +1 -0
- package/dist/{chunk-QBLT6POL.js → chunk-FPF5HRBE.js} +2 -2
- package/dist/{chunk-UA372JHH.js → chunk-FZVCZEVI.js} +3 -3
- package/dist/chunk-FZVCZEVI.js.map +1 -0
- package/dist/{chunk-FFWI7UH7.js → chunk-GAGT3YZN.js} +1 -1
- package/dist/chunk-GAGT3YZN.js.map +1 -0
- package/dist/{chunk-5WWDGFOS.js → chunk-GIQJGXV7.js} +2 -2
- package/dist/{chunk-V3RWOOSO.js → chunk-GYZICGRU.js} +4 -4
- package/dist/chunk-GYZICGRU.js.map +1 -0
- package/dist/{chunk-BVCUTXE3.js → chunk-H334G6KU.js} +2 -2
- package/dist/{chunk-AEQGFRU4.js → chunk-HE7EAHGS.js} +3 -3
- package/dist/chunk-HKB4HZDU.js +74 -0
- package/dist/chunk-HKB4HZDU.js.map +1 -0
- package/dist/{chunk-4V3Q35WG.js → chunk-ICF3TIGY.js} +3 -3
- package/dist/{chunk-3L2NBKDR.js → chunk-IF2M43G4.js} +2 -2
- package/dist/{chunk-37EPTBBR.js → chunk-IKPQ2GGB.js} +46 -4
- package/dist/chunk-IKPQ2GGB.js.map +1 -0
- package/dist/{chunk-DHHGL42E.js → chunk-IKS2CPAG.js} +27 -11
- package/dist/chunk-IKS2CPAG.js.map +1 -0
- package/dist/{chunk-3A5DUZ56.js → chunk-IMIQAGR7.js} +6 -6
- package/dist/{chunk-3A5DUZ56.js.map → chunk-IMIQAGR7.js.map} +1 -1
- package/dist/{chunk-A4XMIZT3.js → chunk-IQAJ4OR6.js} +41 -6
- package/dist/chunk-IQAJ4OR6.js.map +1 -0
- package/dist/{chunk-IUT3GWP3.js → chunk-IUD7WU67.js} +17 -93
- package/dist/chunk-IUD7WU67.js.map +1 -0
- package/dist/{chunk-AUKKUPVB.js → chunk-IVLRPRXM.js} +2 -2
- package/dist/{chunk-GUZET4SG.js → chunk-JAQHWHUN.js} +4 -4
- package/dist/chunk-JAQHWHUN.js.map +1 -0
- package/dist/{chunk-Y2RKVFKR.js → chunk-K4JSTGXT.js} +2 -2
- package/dist/{chunk-EJLV62NI.js → chunk-KN4LUMH6.js} +2 -2
- package/dist/{chunk-23D6M6VM.js → chunk-KZA3DITX.js} +4 -4
- package/dist/{chunk-E2N2T5ZO.js → chunk-L2VM64HK.js} +2 -2
- package/dist/chunk-L4UL4IAR.js +55 -0
- package/dist/chunk-L4UL4IAR.js.map +1 -0
- package/dist/{chunk-UIYESRD6.js → chunk-LUCQY3OM.js} +10 -10
- package/dist/{chunk-UIYESRD6.js.map → chunk-LUCQY3OM.js.map} +1 -1
- package/dist/{chunk-O46CHQT7.js → chunk-MAQBYBUX.js} +4 -4
- package/dist/{chunk-EZOAKKTB.js → chunk-MBPZMZVB.js} +2 -2
- package/dist/{chunk-XQRFSKYM.js → chunk-MCNNZBG7.js} +2 -2
- package/dist/{chunk-YRXFFWG4.js → chunk-MLVPMDOZ.js} +2 -2
- package/dist/{chunk-5FE75J4S.js → chunk-MMCN7TLK.js} +5 -5
- package/dist/{chunk-MXOQ5JCG.js → chunk-MRCR7ZMC.js} +686 -202
- package/dist/chunk-MRCR7ZMC.js.map +1 -0
- package/dist/{chunk-SYNY3VB5.js → chunk-NCTN2FW4.js} +2 -2
- package/dist/{chunk-4T3SE27M.js → chunk-ND6S2DKC.js} +2 -2
- package/dist/{chunk-3XJQBBZD.js → chunk-NTVKHQ3L.js} +2 -2
- package/dist/{chunk-RHVMZSUU.js → chunk-NV4OESHC.js} +1 -1
- package/dist/chunk-NV4OESHC.js.map +1 -0
- package/dist/chunk-NXQEOC3X.js +40 -0
- package/dist/chunk-NXQEOC3X.js.map +1 -0
- package/dist/{chunk-Q4UHJ5SN.js → chunk-O2VQ3K36.js} +2 -2
- package/dist/{chunk-HW7CMKUG.js → chunk-OFD2HD6F.js} +1 -1
- package/dist/{chunk-HW7CMKUG.js.map → chunk-OFD2HD6F.js.map} +1 -1
- package/dist/{chunk-2GHDLTPE.js → chunk-OGKMRIIJ.js} +2 -2
- package/dist/{chunk-N7EVQD5S.js → chunk-ONZ3B5EW.js} +4 -4
- package/dist/{chunk-VKI2EB3N.js → chunk-OOPSMQX5.js} +3 -3
- package/dist/{chunk-VMV5SBE4.js → chunk-OYEBSWLE.js} +5 -5
- package/dist/{chunk-JDEYF3PJ.js → chunk-P6FATPXQ.js} +2 -2
- package/dist/chunk-P6FATPXQ.js.map +1 -0
- package/dist/{chunk-VVOLDVIR.js → chunk-PLTIJDQN.js} +2 -2
- package/dist/{chunk-OKSTSITU.js → chunk-PR7ILCIH.js} +3 -3
- package/dist/{chunk-7R2Q7CPL.js → chunk-QE3TLZ6Z.js} +7 -7
- package/dist/{chunk-G2MVBDFP.js → chunk-QFW4MYGN.js} +39 -9
- package/dist/chunk-QFW4MYGN.js.map +1 -0
- package/dist/{chunk-6QVKPHBF.js → chunk-QHG7GQKM.js} +2 -2
- package/dist/chunk-QJNAHPVT.js +91 -0
- package/dist/chunk-QJNAHPVT.js.map +1 -0
- package/dist/{chunk-LIOVX5TJ.js → chunk-QT5ITL25.js} +3 -3
- package/dist/{chunk-IMQKWR46.js → chunk-R2ZULFXU.js} +4 -5
- package/dist/chunk-R2ZULFXU.js.map +1 -0
- package/dist/{chunk-Q2XRFWOI.js → chunk-RRTQAQ3N.js} +2 -2
- package/dist/{chunk-H23XHRTT.js → chunk-RUE6TCES.js} +809 -101
- package/dist/chunk-RUE6TCES.js.map +1 -0
- package/dist/chunk-RWFQVNXR.js +24 -0
- package/dist/chunk-RWFQVNXR.js.map +1 -0
- package/dist/{chunk-2PVXF5CS.js → chunk-SALY3LIJ.js} +3 -3
- package/dist/{chunk-JOSPH3E5.js → chunk-SBAR5JQ6.js} +2 -2
- package/dist/{chunk-N7UDP5VU.js → chunk-SCH2F7R2.js} +7 -7
- package/dist/{chunk-MXKI4ABF.js → chunk-SOOAW6HK.js} +3 -3
- package/dist/{chunk-VQDZYB2B.js → chunk-T4VTRKCY.js} +3 -3
- package/dist/{chunk-VQDZYB2B.js.map → chunk-T4VTRKCY.js.map} +1 -1
- package/dist/{chunk-TEHHROZL.js → chunk-T5EXREMW.js} +5 -5
- package/dist/{chunk-M5B2W6YY.js → chunk-TDJVQTXD.js} +3 -3
- package/dist/{chunk-QMWY2FDS.js → chunk-THQ3BHLM.js} +2 -2
- package/dist/{chunk-VAORSCSU.js → chunk-TLIFNRU5.js} +2 -2
- package/dist/chunk-TLIFNRU5.js.map +1 -0
- package/dist/{chunk-FVH5QYY2.js → chunk-TRHUNPXP.js} +2 -2
- package/dist/{chunk-EGVJ7TM4.js → chunk-UL6MTRMJ.js} +8 -9
- package/dist/chunk-UL6MTRMJ.js.map +1 -0
- package/dist/chunk-UNL6YGL5.js +169 -0
- package/dist/chunk-UNL6YGL5.js.map +1 -0
- package/dist/{chunk-747G6CT3.js → chunk-UORWAG7K.js} +2 -2
- package/dist/{chunk-XSPFDUDG.js → chunk-V7AKGAXY.js} +314 -77
- package/dist/chunk-V7AKGAXY.js.map +1 -0
- package/dist/{chunk-TZZBXPZK.js → chunk-VLQ6KT7F.js} +2 -2
- package/dist/{chunk-NCO25JZO.js → chunk-VP37VUKQ.js} +4 -4
- package/dist/{chunk-52MGURXO.js → chunk-WBUHHMLN.js} +2 -2
- package/dist/{chunk-EZGV6F47.js → chunk-WRLWEYHY.js} +7 -1
- package/dist/chunk-WRLWEYHY.js.map +1 -0
- package/dist/{chunk-2MG3SW7Q.js → chunk-X6Z2SIRF.js} +2 -2
- package/dist/{chunk-U2FZNEWJ.js → chunk-XLKWF3L4.js} +8 -6
- package/dist/{chunk-U2FZNEWJ.js.map → chunk-XLKWF3L4.js.map} +1 -1
- package/dist/{chunk-5UMK7GRI.js → chunk-XPNJH7GN.js} +5 -5
- package/dist/{chunk-KZXDLBY6.js → chunk-XPW7T2GN.js} +5 -5
- package/dist/{chunk-SV2PM2OY.js → chunk-XX4R7TUB.js} +1 -1
- package/dist/chunk-XX4R7TUB.js.map +1 -0
- package/dist/{chunk-NBQ3KK6X.js → chunk-Y55XHMQB.js} +4 -4
- package/dist/chunk-Y55XHMQB.js.map +1 -0
- package/dist/{chunk-5KC7QYEC.js → chunk-YH4OUOSI.js} +33 -7
- package/dist/chunk-YH4OUOSI.js.map +1 -0
- package/dist/{chunk-FFJFE4T7.js → chunk-YJGKOSQD.js} +2 -2
- package/dist/{chunk-2AFX33YA.js → chunk-Z3STG43F.js} +3 -3
- package/dist/chunk-Z3STG43F.js.map +1 -0
- package/dist/{chunk-OIEO4WDL.js → chunk-ZD7WFMV2.js} +2 -2
- package/dist/chunk-ZD7WFMV2.js.map +1 -0
- package/dist/{chunk-42ALPZ2B.js → chunk-ZF6JECDT.js} +4 -4
- package/dist/{chunk-42ALPZ2B.js.map → chunk-ZF6JECDT.js.map} +1 -1
- package/dist/{chunk-4JPMZTJY.js → chunk-ZF7KNSLU.js} +2 -2
- package/dist/{chunk-2ODVB6LZ.js → chunk-ZGKODRGB.js} +2 -2
- package/dist/{chunk-JIBUPZHA.js → chunk-ZNEKQFGF.js} +4 -4
- package/dist/{chunk-DLD5LGDS.js → chunk-ZUTUNVFD.js} +3 -3
- package/dist/{chunk-JSMTXZR3.js → chunk-ZWMOHANW.js} +8 -6
- package/dist/chunk-ZWMOHANW.js.map +1 -0
- package/dist/{chunk-MILI22XQ.js → chunk-ZZZ4VCY2.js} +10 -10
- package/dist/chunk-ZZZ4VCY2.js.map +1 -0
- package/dist/classified/index.js +5 -5
- package/dist/{classified-marker-SIYKUU5L.js → classified-marker-WKP33U2R.js} +3 -3
- package/dist/collection-facade-COSGZKLC.js +41 -0
- package/dist/{computed-FAD7SED4.js → computed-WN6V53ZV.js} +3 -3
- package/dist/consent/index.js +8 -8
- package/dist/cover/index.js +8 -8
- package/dist/coverage/index.js +1 -1
- package/dist/custody/index.js +12 -11
- package/dist/{dead-filter-4F3LWYKH.js → dead-filter-43WL3Y5H.js} +10 -10
- package/dist/debug/index.js +7 -7
- package/dist/delegation-5UWT4JGT.js +26 -0
- package/dist/derivations/index.js +24 -23
- package/dist/derive-IL5JNLEE.js +20 -0
- package/dist/directory/index.js +9 -9
- package/dist/{dispatch-JDZNGEB3.js → dispatch-LOQQD5JK.js} +20 -20
- package/dist/{dispatch-H4HV32AM.js → dispatch-SHKTG57L.js} +5 -5
- package/dist/executor-6PQ7WAGV.js +35 -0
- package/dist/executor-6ZPQA6HS.js +8 -0
- package/dist/executor-OXRA64TY.js +8 -0
- package/dist/export-accessible-XG3FKJWW.js +22 -0
- package/dist/extract-partition-33747NY5.js +35 -0
- package/dist/{fanout-sidecar-L7NHPIOC.js → fanout-sidecar-NEB6IYV7.js} +8 -8
- package/dist/find-VW543G3J.js +10 -0
- package/dist/forget/index.js +25 -8
- package/dist/forget/index.js.map +1 -1
- 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 +9 -6
- package/dist/index.js +126 -110
- package/dist/index.js.map +1 -1
- package/dist/indexing/index.js +6 -6
- package/dist/introspection/index.js +15 -11
- package/dist/issue-4ZPSY44M.js +19 -0
- package/dist/kernel/cache/index.d.ts +1 -1
- package/dist/kernel/collection.d.ts +86 -6
- package/dist/kernel/constants.d.ts +7 -0
- package/dist/kernel/errors.d.ts +42 -4
- package/dist/kernel/export-scope.d.ts +40 -0
- package/dist/kernel/merge-authority.d.ts +5 -1
- package/dist/kernel/noydb.d.ts +118 -21
- package/dist/kernel/put-many-atomic.d.ts +1 -1
- package/dist/kernel/query/live/live.d.ts +2 -1
- package/dist/kernel/query/sort-key.d.ts +0 -2
- package/dist/kernel/rejection-seal.d.ts +13 -0
- package/dist/kernel/sync-wiring.d.ts +55 -0
- package/dist/kernel/tx-write-gate.d.ts +2 -4
- package/dist/kernel/types.d.ts +463 -14
- package/dist/kernel/validation.d.ts +0 -10
- package/dist/kernel/vault.d.ts +42 -4
- package/dist/kernel/via/reconcile.d.ts +1 -42
- package/dist/{ledger-5ZMGE44K.js → ledger-MZ25UFT2.js} +10 -10
- package/dist/liberate-OJIP2ZFX.js +25 -0
- package/dist/{link-set-MFXC24VK.js → link-set-4FRRAVTH.js} +10 -10
- package/dist/{managed-secret-MFTFT22X.js → managed-secret-SQWO2EUR.js} +9 -9
- package/dist/materialized-views/index.js +26 -26
- package/dist/{migrate-cek-DZRFFOHW.js → migrate-cek-JWEM4RP6.js} +2 -2
- package/dist/money/index.js +5 -5
- package/dist/noydb-U62OVKXB.js +100 -0
- package/dist/on/index.js +25 -0
- package/dist/overlay-views/index.js +4 -4
- package/dist/periods/index.js +11 -11
- package/dist/pod/index.js +71 -67
- package/dist/{pod-handle-A3LET7NO.js → pod-handle-R6Y4MILX.js} +8 -8
- package/dist/policy/index.js +9 -9
- package/dist/port/as/active.d.ts +4 -0
- package/dist/port/as/index.d.ts +1 -0
- package/dist/port/by/index.d.ts +14 -5
- package/dist/port/on/index.d.ts +26 -0
- package/dist/port/to/index.d.ts +1 -1
- package/dist/port/with/admission-authority.d.ts +34 -0
- package/dist/port/with/broker-strategy.d.ts +24 -0
- package/dist/port/with/coverage-strategy.d.ts +17 -1
- package/dist/port/with/formats-strategy.d.ts +34 -1
- package/dist/port/with/lookup-strategy.d.ts +85 -4
- 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 +20 -1
- 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-7ND27CF2.js → post-register-GRVQHBOH.js} +6 -6
- package/dist/query/all/index.js +16 -16
- package/dist/query/index.js +8 -8
- package/dist/query/live/index.js +7 -7
- package/dist/query/reduce/index.js +10 -10
- package/dist/query/relate/index.js +10 -10
- package/dist/reduce/index.js +8 -8
- package/dist/register-YJ5YLQ36.js +30 -0
- package/dist/registry-ICOHBQFD.js +8 -0
- package/dist/registry-MJ7MWCSW.js +35 -0
- package/dist/registry-MVEKKGWL.js +23 -0
- package/dist/registry-XP744FAP.js +8 -0
- package/dist/request-withdrawal-LSU4G6W3.js +28 -0
- package/dist/restore-to-DVBHAQAA.js +66 -0
- package/dist/restore-to-DVBHAQAA.js.map +1 -0
- package/dist/{reveal-B2TLP4JQ.js → reveal-AIHOIK2N.js} +7 -7
- package/dist/revoke-QUT7WWG3.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-XNSE4U3S.js → seed-GFLA4FCK.js} +136 -27
- package/dist/seed-GFLA4FCK.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-NYR4I3FO.js +23 -0
- package/dist/snapshots/index.js +9 -9
- package/dist/{stale-6GCFMOOR.js → stale-PIJPAL5T.js} +9 -9
- package/dist/storage-VH6SPXHC.js +21 -0
- package/dist/{store-coordination-provider-C4BPT5XF.js → store-coordination-provider-2KSHCOPU.js} +9 -9
- package/dist/sync/index.js +19 -13
- package/dist/sync/index.js.map +1 -1
- package/dist/team/index.js +17 -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 +8 -8
- package/dist/{verify-UKALW7C2.js → verify-PCFS4PNS.js} +7 -7
- package/dist/via/classified/presets.d.ts +29 -0
- package/dist/via/classified/resolve.d.ts +7 -0
- package/dist/via/geo/binding.d.ts +0 -4
- package/dist/via/lookup/index.d.ts +32 -0
- package/dist/via/money/binding.d.ts +0 -9
- package/dist/walk-OZCN6LJS.js +20 -0
- package/dist/with-audit/attestation/strategy.d.ts +2 -1
- package/dist/with-audit/attestation/vault-facade.d.ts +7 -0
- package/dist/with-audit/forget/completeness.d.ts +66 -0
- package/dist/with-audit/forget/index.d.ts +2 -0
- package/dist/with-audit/forget/strategy.d.ts +65 -0
- package/dist/with-audit/guards/types.d.ts +2 -0
- package/dist/with-audit/periods/periods.d.ts +0 -9
- package/dist/with-audit/periods/reserved-collections.d.ts +7 -0
- package/dist/with-audit/portability/request-withdrawal.d.ts +0 -1
- package/dist/with-audit/portability/withdraw-accessible.d.ts +0 -1
- package/dist/with-audit/tiers/index.d.ts +6 -6
- package/dist/with-audit/tiers/strategy.d.ts +19 -0
- package/dist/with-cargo/extract-partition.d.ts +0 -46
- package/dist/with-commit/history/history.d.ts +16 -0
- package/dist/with-commit/history/restore-to.d.ts +40 -0
- package/dist/with-commit/numbering/index.d.ts +0 -2
- package/dist/with-commit/tx/transaction.d.ts +2 -24
- package/dist/with-commit/vault-head/strategy.d.ts +7 -0
- package/dist/with-fork/snapshots/noydb-facade.d.ts +7 -0
- package/dist/with-formula/derivations/trigger-match.d.ts +8 -5
- package/dist/with-formula/materialized-views/emit-memo.d.ts +0 -2
- package/dist/with-lookup/embeddings/index.d.ts +1 -2
- package/dist/with-lookup/indexing/collection-facade.d.ts +1 -15
- package/dist/with-lookup/indexing/eager-indexes.d.ts +2 -1
- package/dist/with-lookup/search/collection-facade.d.ts +0 -12
- package/dist/with-party/broker/index.d.ts +2 -2
- package/dist/with-party/broker/seed.d.ts +29 -10
- package/dist/with-party/custody/strategy.d.ts +2 -2
- package/dist/with-party/policy/noydb-facade.d.ts +1 -31
- package/dist/with-party/team/delegation.d.ts +93 -7
- package/dist/with-party/team/echo-secret.d.ts +0 -2
- package/dist/with-party/team/index.d.ts +2 -0
- package/dist/with-party/team/keyring.d.ts +133 -24
- package/dist/with-party/team/magic-link-grant.d.ts +11 -1
- package/dist/with-party/team/noydb-facade.d.ts +19 -2
- package/dist/with-party/team/reserved-secret-collections.d.ts +10 -8
- package/dist/with-party/team/roster-tag.d.ts +42 -1
- package/dist/with-party/team/tiers.d.ts +36 -5
- package/dist/with-pod/backup.d.ts +9 -17
- package/dist/with-shape/blobs/blob-set.d.ts +23 -0
- package/dist/with-shape/blobs/legacy-sweep.d.ts +16 -0
- package/dist/with-shape/introspection/describe.d.ts +1 -2
- package/dist/with-shape/introspection/index.d.ts +1 -0
- package/dist/with-shape/introspection/types.d.ts +2 -1
- package/dist/with-shape/schema-update/fence.d.ts +7 -0
- package/dist/with-sync/active.d.ts +28 -1
- package/dist/with-sync/engine.d.ts +88 -2
- package/dist/with-sync/index.d.ts +1 -0
- package/dist/with-sync/reserved-mirror.d.ts +112 -0
- package/dist/with-sync/strategy.d.ts +9 -0
- package/dist/with-sync/tab-write-relay.d.ts +0 -10
- package/dist/withdraw-accessible-MTFP7OIB.js +25 -0
- package/dist/withdraw-accessible-MTFP7OIB.js.map +1 -0
- package/package.json +3 -3
- package/dist/api-OS747DS4.js +0 -18
- package/dist/backup-YE2VQ26S.js.map +0 -1
- package/dist/chunk-2AFX33YA.js.map +0 -1
- package/dist/chunk-2RH777HH.js +0 -126
- package/dist/chunk-2RH777HH.js.map +0 -1
- package/dist/chunk-37EPTBBR.js.map +0 -1
- package/dist/chunk-5KC7QYEC.js.map +0 -1
- package/dist/chunk-7XMHMVTS.js +0 -20
- package/dist/chunk-7XMHMVTS.js.map +0 -1
- package/dist/chunk-A4XMIZT3.js.map +0 -1
- package/dist/chunk-DHHGL42E.js.map +0 -1
- package/dist/chunk-DQESF6RP.js.map +0 -1
- package/dist/chunk-EGVJ7TM4.js.map +0 -1
- package/dist/chunk-EYG2CY2X.js.map +0 -1
- package/dist/chunk-EZGV6F47.js.map +0 -1
- package/dist/chunk-FFWI7UH7.js.map +0 -1
- package/dist/chunk-G2MVBDFP.js.map +0 -1
- package/dist/chunk-GUZET4SG.js.map +0 -1
- package/dist/chunk-GZT3NQRA.js.map +0 -1
- package/dist/chunk-H23XHRTT.js.map +0 -1
- package/dist/chunk-H7JBY4P7.js.map +0 -1
- package/dist/chunk-IMQKWR46.js.map +0 -1
- package/dist/chunk-IUBMZPHM.js.map +0 -1
- package/dist/chunk-IUT3GWP3.js.map +0 -1
- package/dist/chunk-JDEYF3PJ.js.map +0 -1
- package/dist/chunk-JSMTXZR3.js.map +0 -1
- package/dist/chunk-LGNDFRYC.js.map +0 -1
- package/dist/chunk-LNSVGRHO.js.map +0 -1
- package/dist/chunk-MILI22XQ.js.map +0 -1
- package/dist/chunk-MXOQ5JCG.js.map +0 -1
- package/dist/chunk-NBQ3KK6X.js.map +0 -1
- package/dist/chunk-OIEO4WDL.js.map +0 -1
- package/dist/chunk-PD64727P.js.map +0 -1
- package/dist/chunk-RHVMZSUU.js.map +0 -1
- package/dist/chunk-SV2PM2OY.js.map +0 -1
- package/dist/chunk-T7IR4N2S.js.map +0 -1
- package/dist/chunk-UA372JHH.js.map +0 -1
- package/dist/chunk-UBSFPGVJ.js +0 -1
- package/dist/chunk-V3RWOOSO.js.map +0 -1
- package/dist/chunk-VAORSCSU.js.map +0 -1
- package/dist/chunk-XSPFDUDG.js.map +0 -1
- package/dist/chunk-Y3LPTBG7.js.map +0 -1
- package/dist/collection-facade-CS7CA2XO.js +0 -47
- package/dist/delegation-NANZDG4N.js +0 -102
- package/dist/delegation-NANZDG4N.js.map +0 -1
- package/dist/derive-XLOJVXPU.js +0 -20
- package/dist/executor-FMPVN6DT.js +0 -35
- package/dist/executor-LBBBRTN5.js +0 -8
- package/dist/executor-OSRZST2U.js +0 -8
- package/dist/export-accessible-RAOJAAU5.js +0 -22
- package/dist/extract-partition-JD5CUSTG.js +0 -37
- package/dist/find-JRN4RNQ5.js +0 -10
- package/dist/issue-YIVBZUTH.js +0 -19
- package/dist/liberate-WZSZM2W6.js +0 -24
- package/dist/noydb-ITIGNKUF.js +0 -96
- package/dist/register-DT5HZ2LZ.js +0 -30
- package/dist/registry-BHRZGZHF.js +0 -8
- package/dist/registry-ET6ZFFWA.js +0 -34
- package/dist/registry-HXFGLGTG.js +0 -8
- package/dist/registry-THCPDEOD.js +0 -23
- package/dist/request-withdrawal-AV2MJJKY.js +0 -30
- package/dist/revoke-6DWIEOCV.js +0 -24
- package/dist/seed-XNSE4U3S.js.map +0 -1
- package/dist/signer-MHGW3OIL.js +0 -23
- package/dist/storage-BYN5LO6Z.js +0 -21
- package/dist/walk-4VPK7AS4.js +0 -20
- package/dist/withdraw-accessible-HL7GACUE.js +0 -27
- /package/dist/{api-OS747DS4.js.map → api-6EFD43KN.js.map} +0 -0
- /package/dist/{capsule-VOLX3QRQ.js.map → capsule-6LJAVQNM.js.map} +0 -0
- /package/dist/{chunk-OYW3I5M4.js.map → chunk-2DOCDOPL.js.map} +0 -0
- /package/dist/{chunk-UBSFPGVJ.js.map → chunk-2DX4JCRI.js.map} +0 -0
- /package/dist/{chunk-FLPCETP6.js.map → chunk-2LBS62AC.js.map} +0 -0
- /package/dist/{chunk-WXE4W2U6.js.map → chunk-2ST3WA3C.js.map} +0 -0
- /package/dist/{chunk-O2IMQSNA.js.map → chunk-3YBIVLTC.js.map} +0 -0
- /package/dist/{chunk-DIZLQVAA.js.map → chunk-4CHM2TRS.js.map} +0 -0
- /package/dist/{chunk-V7ADQF5O.js.map → chunk-4CUJLEOA.js.map} +0 -0
- /package/dist/{chunk-3EWS67C7.js.map → chunk-4TG2ITRW.js.map} +0 -0
- /package/dist/{chunk-HS554XAF.js.map → chunk-5HQFROZS.js.map} +0 -0
- /package/dist/{chunk-PP3K67AJ.js.map → chunk-654RE5YC.js.map} +0 -0
- /package/dist/{chunk-FOEDQATO.js.map → chunk-66GD7XXU.js.map} +0 -0
- /package/dist/{chunk-BNWA3WG5.js.map → chunk-72FQ46VW.js.map} +0 -0
- /package/dist/{chunk-JQYKPKG6.js.map → chunk-7K42TSCY.js.map} +0 -0
- /package/dist/{chunk-UEFOQH74.js.map → chunk-ADCXTW7L.js.map} +0 -0
- /package/dist/{chunk-MBMTND6D.js.map → chunk-AGGPT4UE.js.map} +0 -0
- /package/dist/{chunk-RB4DOPGZ.js.map → chunk-AKIEBFIJ.js.map} +0 -0
- /package/dist/{chunk-VHBKYN2J.js.map → chunk-B3B6HV5S.js.map} +0 -0
- /package/dist/{chunk-JWWYRR4Q.js.map → chunk-B6EWMGFX.js.map} +0 -0
- /package/dist/{chunk-WPOYWFSE.js.map → chunk-BJRKXNFP.js.map} +0 -0
- /package/dist/{chunk-H427H63K.js.map → chunk-BPQ5CRJF.js.map} +0 -0
- /package/dist/{chunk-VFHCKG5M.js.map → chunk-BVRJYMFZ.js.map} +0 -0
- /package/dist/{chunk-SMV2HRDU.js.map → chunk-DFC4WTJW.js.map} +0 -0
- /package/dist/{chunk-5A4345TG.js.map → chunk-DMIEKD24.js.map} +0 -0
- /package/dist/{chunk-TKVUE4JF.js.map → chunk-DQAXA2GK.js.map} +0 -0
- /package/dist/{chunk-AL6ML4LA.js.map → chunk-DWCFGF2K.js.map} +0 -0
- /package/dist/{chunk-QBLT6POL.js.map → chunk-FPF5HRBE.js.map} +0 -0
- /package/dist/{chunk-5WWDGFOS.js.map → chunk-GIQJGXV7.js.map} +0 -0
- /package/dist/{chunk-BVCUTXE3.js.map → chunk-H334G6KU.js.map} +0 -0
- /package/dist/{chunk-AEQGFRU4.js.map → chunk-HE7EAHGS.js.map} +0 -0
- /package/dist/{chunk-4V3Q35WG.js.map → chunk-ICF3TIGY.js.map} +0 -0
- /package/dist/{chunk-3L2NBKDR.js.map → chunk-IF2M43G4.js.map} +0 -0
- /package/dist/{chunk-AUKKUPVB.js.map → chunk-IVLRPRXM.js.map} +0 -0
- /package/dist/{chunk-Y2RKVFKR.js.map → chunk-K4JSTGXT.js.map} +0 -0
- /package/dist/{chunk-EJLV62NI.js.map → chunk-KN4LUMH6.js.map} +0 -0
- /package/dist/{chunk-23D6M6VM.js.map → chunk-KZA3DITX.js.map} +0 -0
- /package/dist/{chunk-E2N2T5ZO.js.map → chunk-L2VM64HK.js.map} +0 -0
- /package/dist/{chunk-O46CHQT7.js.map → chunk-MAQBYBUX.js.map} +0 -0
- /package/dist/{chunk-EZOAKKTB.js.map → chunk-MBPZMZVB.js.map} +0 -0
- /package/dist/{chunk-XQRFSKYM.js.map → chunk-MCNNZBG7.js.map} +0 -0
- /package/dist/{chunk-YRXFFWG4.js.map → chunk-MLVPMDOZ.js.map} +0 -0
- /package/dist/{chunk-5FE75J4S.js.map → chunk-MMCN7TLK.js.map} +0 -0
- /package/dist/{chunk-SYNY3VB5.js.map → chunk-NCTN2FW4.js.map} +0 -0
- /package/dist/{chunk-4T3SE27M.js.map → chunk-ND6S2DKC.js.map} +0 -0
- /package/dist/{chunk-3XJQBBZD.js.map → chunk-NTVKHQ3L.js.map} +0 -0
- /package/dist/{chunk-Q4UHJ5SN.js.map → chunk-O2VQ3K36.js.map} +0 -0
- /package/dist/{chunk-2GHDLTPE.js.map → chunk-OGKMRIIJ.js.map} +0 -0
- /package/dist/{chunk-N7EVQD5S.js.map → chunk-ONZ3B5EW.js.map} +0 -0
- /package/dist/{chunk-VKI2EB3N.js.map → chunk-OOPSMQX5.js.map} +0 -0
- /package/dist/{chunk-VMV5SBE4.js.map → chunk-OYEBSWLE.js.map} +0 -0
- /package/dist/{chunk-VVOLDVIR.js.map → chunk-PLTIJDQN.js.map} +0 -0
- /package/dist/{chunk-OKSTSITU.js.map → chunk-PR7ILCIH.js.map} +0 -0
- /package/dist/{chunk-7R2Q7CPL.js.map → chunk-QE3TLZ6Z.js.map} +0 -0
- /package/dist/{chunk-6QVKPHBF.js.map → chunk-QHG7GQKM.js.map} +0 -0
- /package/dist/{chunk-LIOVX5TJ.js.map → chunk-QT5ITL25.js.map} +0 -0
- /package/dist/{chunk-Q2XRFWOI.js.map → chunk-RRTQAQ3N.js.map} +0 -0
- /package/dist/{chunk-2PVXF5CS.js.map → chunk-SALY3LIJ.js.map} +0 -0
- /package/dist/{chunk-JOSPH3E5.js.map → chunk-SBAR5JQ6.js.map} +0 -0
- /package/dist/{chunk-N7UDP5VU.js.map → chunk-SCH2F7R2.js.map} +0 -0
- /package/dist/{chunk-MXKI4ABF.js.map → chunk-SOOAW6HK.js.map} +0 -0
- /package/dist/{chunk-TEHHROZL.js.map → chunk-T5EXREMW.js.map} +0 -0
- /package/dist/{chunk-M5B2W6YY.js.map → chunk-TDJVQTXD.js.map} +0 -0
- /package/dist/{chunk-QMWY2FDS.js.map → chunk-THQ3BHLM.js.map} +0 -0
- /package/dist/{chunk-FVH5QYY2.js.map → chunk-TRHUNPXP.js.map} +0 -0
- /package/dist/{chunk-747G6CT3.js.map → chunk-UORWAG7K.js.map} +0 -0
- /package/dist/{chunk-TZZBXPZK.js.map → chunk-VLQ6KT7F.js.map} +0 -0
- /package/dist/{chunk-NCO25JZO.js.map → chunk-VP37VUKQ.js.map} +0 -0
- /package/dist/{chunk-52MGURXO.js.map → chunk-WBUHHMLN.js.map} +0 -0
- /package/dist/{chunk-2MG3SW7Q.js.map → chunk-X6Z2SIRF.js.map} +0 -0
- /package/dist/{chunk-5UMK7GRI.js.map → chunk-XPNJH7GN.js.map} +0 -0
- /package/dist/{chunk-KZXDLBY6.js.map → chunk-XPW7T2GN.js.map} +0 -0
- /package/dist/{chunk-FFJFE4T7.js.map → chunk-YJGKOSQD.js.map} +0 -0
- /package/dist/{chunk-4JPMZTJY.js.map → chunk-ZF7KNSLU.js.map} +0 -0
- /package/dist/{chunk-2ODVB6LZ.js.map → chunk-ZGKODRGB.js.map} +0 -0
- /package/dist/{chunk-JIBUPZHA.js.map → chunk-ZNEKQFGF.js.map} +0 -0
- /package/dist/{chunk-DLD5LGDS.js.map → chunk-ZUTUNVFD.js.map} +0 -0
- /package/dist/{classified-marker-SIYKUU5L.js.map → classified-marker-WKP33U2R.js.map} +0 -0
- /package/dist/{collection-facade-CS7CA2XO.js.map → collection-facade-COSGZKLC.js.map} +0 -0
- /package/dist/{computed-FAD7SED4.js.map → computed-WN6V53ZV.js.map} +0 -0
- /package/dist/{dead-filter-4F3LWYKH.js.map → dead-filter-43WL3Y5H.js.map} +0 -0
- /package/dist/{derive-XLOJVXPU.js.map → delegation-5UWT4JGT.js.map} +0 -0
- /package/dist/{executor-FMPVN6DT.js.map → derive-IL5JNLEE.js.map} +0 -0
- /package/dist/{dispatch-JDZNGEB3.js.map → dispatch-LOQQD5JK.js.map} +0 -0
- /package/dist/{dispatch-H4HV32AM.js.map → dispatch-SHKTG57L.js.map} +0 -0
- /package/dist/{executor-LBBBRTN5.js.map → executor-6PQ7WAGV.js.map} +0 -0
- /package/dist/{executor-OSRZST2U.js.map → executor-6ZPQA6HS.js.map} +0 -0
- /package/dist/{export-accessible-RAOJAAU5.js.map → executor-OXRA64TY.js.map} +0 -0
- /package/dist/{extract-partition-JD5CUSTG.js.map → export-accessible-XG3FKJWW.js.map} +0 -0
- /package/dist/{find-JRN4RNQ5.js.map → extract-partition-33747NY5.js.map} +0 -0
- /package/dist/{fanout-sidecar-L7NHPIOC.js.map → fanout-sidecar-NEB6IYV7.js.map} +0 -0
- /package/dist/{issue-YIVBZUTH.js.map → find-VW543G3J.js.map} +0 -0
- /package/dist/{ledger-5ZMGE44K.js.map → issue-4ZPSY44M.js.map} +0 -0
- /package/dist/{liberate-WZSZM2W6.js.map → ledger-MZ25UFT2.js.map} +0 -0
- /package/dist/{link-set-MFXC24VK.js.map → liberate-OJIP2ZFX.js.map} +0 -0
- /package/dist/{managed-secret-MFTFT22X.js.map → link-set-4FRRAVTH.js.map} +0 -0
- /package/dist/{noydb-ITIGNKUF.js.map → managed-secret-SQWO2EUR.js.map} +0 -0
- /package/dist/{migrate-cek-DZRFFOHW.js.map → migrate-cek-JWEM4RP6.js.map} +0 -0
- /package/dist/{register-DT5HZ2LZ.js.map → noydb-U62OVKXB.js.map} +0 -0
- /package/dist/{pod-handle-A3LET7NO.js.map → pod-handle-R6Y4MILX.js.map} +0 -0
- /package/dist/{post-register-7ND27CF2.js.map → post-register-GRVQHBOH.js.map} +0 -0
- /package/dist/{registry-BHRZGZHF.js.map → register-YJ5YLQ36.js.map} +0 -0
- /package/dist/{registry-ET6ZFFWA.js.map → registry-ICOHBQFD.js.map} +0 -0
- /package/dist/{registry-HXFGLGTG.js.map → registry-MJ7MWCSW.js.map} +0 -0
- /package/dist/{registry-THCPDEOD.js.map → registry-MVEKKGWL.js.map} +0 -0
- /package/dist/{request-withdrawal-AV2MJJKY.js.map → registry-XP744FAP.js.map} +0 -0
- /package/dist/{revoke-6DWIEOCV.js.map → request-withdrawal-LSU4G6W3.js.map} +0 -0
- /package/dist/{reveal-B2TLP4JQ.js.map → reveal-AIHOIK2N.js.map} +0 -0
- /package/dist/{signer-MHGW3OIL.js.map → revoke-QUT7WWG3.js.map} +0 -0
- /package/dist/{stale-6GCFMOOR.js.map → signer-NYR4I3FO.js.map} +0 -0
- /package/dist/{storage-BYN5LO6Z.js.map → stale-PIJPAL5T.js.map} +0 -0
- /package/dist/{walk-4VPK7AS4.js.map → storage-VH6SPXHC.js.map} +0 -0
- /package/dist/{store-coordination-provider-C4BPT5XF.js.map → store-coordination-provider-2KSHCOPU.js.map} +0 -0
- /package/dist/{verify-UKALW7C2.js.map → verify-PCFS4PNS.js.map} +0 -0
- /package/dist/{withdraw-accessible-HL7GACUE.js.map → walk-OZCN6LJS.js.map} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { NoydbStore, EncryptedEnvelope, ExportStreamOptions, ExportChunk } from '../kernel/types.js';
|
|
1
|
+
import type { NoydbStore, EncryptedEnvelope, LoadPodOptions, LoadPodResult, ExportStreamOptions, ExportChunk } from '../kernel/types.js';
|
|
2
2
|
import type { LedgerStore } from '../with-commit/history/ledger/store.js';
|
|
3
3
|
/** Everything the moving backup methods touched on the vault's `this.*`. */
|
|
4
4
|
export interface BackupContext {
|
|
@@ -18,6 +18,13 @@ export interface BackupContext {
|
|
|
18
18
|
* callback (plaintext vaults / test constructions).
|
|
19
19
|
*/
|
|
20
20
|
reloadKeyringAndRebuildDEK(): Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* core#71 — reset every sync engine attached to the vault after a restore:
|
|
23
|
+
* the dirty log, the watermarks, the adopted epoch. A restore is a new base;
|
|
24
|
+
* the pre-restore dirty entries refer to records the load just replaced.
|
|
25
|
+
* Absent on test constructions without sync.
|
|
26
|
+
*/
|
|
27
|
+
resetSync?(): Promise<void>;
|
|
21
28
|
/** Clear the vault's collection cache (post-load). */
|
|
22
29
|
clearCollectionCache(): void;
|
|
23
30
|
/** Reset the ledger store so the next `ledger()` rebuilds its head cache. */
|
|
@@ -42,23 +49,8 @@ export type VerifyBackupResult = {
|
|
|
42
49
|
readonly id: string;
|
|
43
50
|
readonly message: string;
|
|
44
51
|
};
|
|
45
|
-
/**
|
|
46
|
-
* Dump vault as a verifiable encrypted JSON backup string.
|
|
47
|
-
*
|
|
48
|
-
* backups embed the current ledger head and the full `_ledger` +
|
|
49
|
-
* `_ledger_deltas` internal collections so the receiver can run
|
|
50
|
-
* `verifyBackupIntegrity()` after `load()` and detect any tampering between
|
|
51
|
-
* dump and restore. Backups produced without a ledger skip the integrity check
|
|
52
|
-
* with a warning — both modes round-trip cleanly.
|
|
53
|
-
*/
|
|
54
52
|
export declare function dumpVault(ctx: BackupContext): Promise<string>;
|
|
55
|
-
|
|
56
|
-
* Restore a vault from a verifiable backup. After loading, runs
|
|
57
|
-
* `verifyBackupIntegrity()` to confirm the hash chain, the embedded head, and
|
|
58
|
-
* every data envelope's payload hash. Legacy backups (no `ledgerHead`) load
|
|
59
|
-
* with a console warning and skip the integrity check.
|
|
60
|
-
*/
|
|
61
|
-
export declare function loadVault(ctx: BackupContext, backupJson: string): Promise<void>;
|
|
53
|
+
export declare function loadVault(ctx: BackupContext, backupJson: string, options?: LoadPodOptions): Promise<LoadPodResult>;
|
|
62
54
|
/**
|
|
63
55
|
* End-to-end backup integrity check: `ledger.verify()` (hash chain) plus a data
|
|
64
56
|
* envelope cross-check (every current record's `_data` hash must match the
|
|
@@ -608,6 +608,8 @@ export declare class BlobSet {
|
|
|
608
608
|
shredded: string[];
|
|
609
609
|
retainedShared: string[];
|
|
610
610
|
residue: string[];
|
|
611
|
+
/** #28 — the eTag half of `residue` alone: the join key to `compact()`'s sweep. */
|
|
612
|
+
residueETags: string[];
|
|
611
613
|
}>;
|
|
612
614
|
/**
|
|
613
615
|
* Resolve a SHRED `BlobIntent` for this record, or `null` when the entry
|
|
@@ -1294,6 +1296,27 @@ export declare class BlobSet {
|
|
|
1294
1296
|
* and "its attachments are released" are one operation. Ungated: the record
|
|
1295
1297
|
* delete itself already passed the gate bus. Ref-counted like any release —
|
|
1296
1298
|
* content another record still holds survives.
|
|
1299
|
+
*
|
|
1300
|
+
* ⛔ RELEASE IS NOT ERASURE, AND THE API CANNOT TELL YOU WHICH YOU GOT
|
|
1301
|
+
* (noy-db/core#28). Releasing the slot is unconditional; when the BYTES
|
|
1302
|
+
* leave the store depends on the collection's key mode:
|
|
1303
|
+
*
|
|
1304
|
+
* - `perRecordKeys: true` — crypto-shredded on the spot at refCount 0.
|
|
1305
|
+
* - legacy (shared DEK) — chunks RETAINED under the collection DEK until
|
|
1306
|
+
* `vault.compact({ reclaimLegacyBlobs: true })` runs (#1453).
|
|
1307
|
+
*
|
|
1308
|
+
* Both give the caller the same `null` from `blob(id).get(slot)`, and the
|
|
1309
|
+
* record, the slot list and the store listing all agree it is gone — so
|
|
1310
|
+
* every signal a consumer has says "erased" while the ciphertext is still
|
|
1311
|
+
* on disk, recoverable by anyone holding the DEK. pilot-1 measured exactly
|
|
1312
|
+
* this (chunks 2 → 2 on delete) and reasonably read the deferral as a
|
|
1313
|
+
* broken cascade.
|
|
1314
|
+
*
|
|
1315
|
+
* ⭐ So: if a delete is meant to ERASE — a subject-access request, a
|
|
1316
|
+
* retention policy — either put the blobs on a `perRecordKeys` collection
|
|
1317
|
+
* or run the reclaim pass, and assert on `compact()`'s
|
|
1318
|
+
* `unreferencedLegacyBlobs.reclaimed`, never on the null read. The seam is
|
|
1319
|
+
* pinned in `__tests__/1451-delete-releases-blobs.test.ts`.
|
|
1297
1320
|
*/
|
|
1298
1321
|
releaseAll(): Promise<void>;
|
|
1299
1322
|
/** The body of {@link delete}, minus the owner gate. */
|
|
@@ -26,6 +26,22 @@ export interface UnreferencedLegacyBlobReport {
|
|
|
26
26
|
readonly chunks: number;
|
|
27
27
|
/** How many of those blobs this run deleted (chunks first, then the index row). */
|
|
28
28
|
readonly reclaimed: number;
|
|
29
|
+
/**
|
|
30
|
+
* #28 — the eTags this run actually deleted, so a deferred erasure set can be
|
|
31
|
+
* reconciled against the reclaim that finished it:
|
|
32
|
+
*
|
|
33
|
+
* ```ts
|
|
34
|
+
* const still = before.blobResidueETags.filter((e) => !report.reclaimedETags.includes(e))
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* ⛔ DO NOT PERSIST. An eTag is a content hash — see
|
|
38
|
+
* `ForgetResult.blobResidueETags` for why a stored receipt of them is a
|
|
39
|
+
* re-identification oracle. Reconcile in memory, persist the verdict.
|
|
40
|
+
*
|
|
41
|
+
* Empty on a `dryRun` (nothing was deleted), even though `blobs`/`chunks`
|
|
42
|
+
* still count what WOULD be.
|
|
43
|
+
*/
|
|
44
|
+
readonly reclaimedETags: readonly string[];
|
|
29
45
|
}
|
|
30
46
|
export declare function sweepUnreferencedLegacyBlobs(ctx: {
|
|
31
47
|
adapter: NoydbStore;
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* @module
|
|
12
12
|
*/
|
|
13
13
|
import type { FieldMeta } from './field-meta.js';
|
|
14
|
-
import {
|
|
14
|
+
import { schemaFieldKeys } from './field-meta.js';
|
|
15
15
|
export { schemaFieldKeys };
|
|
16
16
|
import type { CollectionMeta } from './meta.js';
|
|
17
17
|
import type { ViaDescriptor, ViaPosture } from '../../kernel/via/index.js';
|
|
@@ -275,7 +275,6 @@ export interface BuildDescriptionInput {
|
|
|
275
275
|
*/
|
|
276
276
|
readonly fieldIds?: Record<string, string> | undefined;
|
|
277
277
|
}
|
|
278
|
-
export { FieldMetaUnknownFieldError };
|
|
279
278
|
/**
|
|
280
279
|
* Pure assembler: no I/O, no side effects.
|
|
281
280
|
* Builds a {@link CollectionDescription} from the collection's in-memory config.
|
|
@@ -13,6 +13,7 @@ export type { VaultIntrospectState } from './walk.js';
|
|
|
13
13
|
export { jsonSchemaToFields } from './fields.js';
|
|
14
14
|
export type { SchemaIntrospection } from './types.js';
|
|
15
15
|
export type { FieldMeta, SemanticType } from './field-meta.js';
|
|
16
|
+
export { FieldMetaUnknownFieldError } from './field-meta.js';
|
|
16
17
|
export type { CollectionDescription, DescribedField, DescribeOptions } from './describe.js';
|
|
17
18
|
export type { StandardSchemaV1Issue } from '../../kernel/schema.js';
|
|
18
19
|
export { applyListProjection } from './projection.js';
|
|
@@ -174,7 +174,7 @@ export interface InternalCollectionStats {
|
|
|
174
174
|
* documentation gate switching to the live report passes VACUOUSLY on a hub
|
|
175
175
|
* too old to answer. Measured by a consumer attempting that adoption.
|
|
176
176
|
*/
|
|
177
|
-
|
|
177
|
+
type SnapshotReport = 'via' | 'stats';
|
|
178
178
|
export interface VaultSchemaSnapshot {
|
|
179
179
|
readonly _noydb_snapshot: 2;
|
|
180
180
|
/**
|
|
@@ -209,3 +209,4 @@ export interface DumpSchemaOptions {
|
|
|
209
209
|
/** Sample N records per collection lacking a persisted/live schema. Default 50. `0` disables sampling. */
|
|
210
210
|
readonly sampleSize?: number;
|
|
211
211
|
}
|
|
212
|
+
export {};
|
|
@@ -18,6 +18,13 @@ export interface FenceDoc {
|
|
|
18
18
|
*/
|
|
19
19
|
readonly schemaHash?: string;
|
|
20
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* `FENCE_RECORD_ID` — PUBLISHED API, reachable from @noy-db/hub, @noy-db/hub/cover. Flagged as unused because
|
|
23
|
+
* nothing inside hub imports it from this module; a consumer does. Do not narrow
|
|
24
|
+
* or delete without a seam change (#55).
|
|
25
|
+
*
|
|
26
|
+
* @public
|
|
27
|
+
*/
|
|
21
28
|
export declare const FENCE_RECORD_ID = "schema-fence";
|
|
22
29
|
export declare const DEFAULT_FENCE: FenceDoc;
|
|
23
30
|
export declare function loadFence(store: NoydbStore, vault: string): Promise<FenceDoc>;
|
|
@@ -30,4 +30,31 @@
|
|
|
30
30
|
* @public
|
|
31
31
|
*/
|
|
32
32
|
import type { SyncStrategy } from './strategy.js';
|
|
33
|
-
|
|
33
|
+
/**
|
|
34
|
+
* core#107 — `arbiter: true` makes this device the vault's ARBITER: its
|
|
35
|
+
* admission refusals are replicated so the writer finds out, instead of
|
|
36
|
+
* staying local to the device that judged them.
|
|
37
|
+
*
|
|
38
|
+
* ⚠️ One arbiter, named by configuration on the device that is to be it
|
|
39
|
+
* (the admin host, or the daemon) — ruled over a quorum because the failure
|
|
40
|
+
* mode is legible: no arbiter configured means no replication, which is
|
|
41
|
+
* exactly the pre-core#107 behaviour. It is NOT an authority proof: nothing
|
|
42
|
+
* stops a member hand-writing `_sync_rejections`, and the reason that is
|
|
43
|
+
* tolerable is the report-only ruling — a replicated refusal never deletes,
|
|
44
|
+
* tombstones or retracts anything, so the worst a forged one does is show
|
|
45
|
+
* somebody a notice about their own record.
|
|
46
|
+
*
|
|
47
|
+
* ⚠️ THE CONDITION THAT WOULD MAKE THAT NON-BOUNDARY A REAL ONE, named by
|
|
48
|
+
* pilot-1 when they accepted it: every member is currently staff of the same
|
|
49
|
+
* firm, and a forged refusal is sealed under the refused record's own
|
|
50
|
+
* collection DEK — so a forger can only show a notice about a record they
|
|
51
|
+
* could already read. ⛔ If EXTERNAL `client`-role users ever hold
|
|
52
|
+
* collections of their own, "who may write `_sync_rejections`" stops being
|
|
53
|
+
* cosmetic and this needs an authority design, not a flag. Do not read the
|
|
54
|
+
* paragraph above as a general safety argument; it is an argument about one
|
|
55
|
+
* topology, and this is the trigger to re-open it.
|
|
56
|
+
*/
|
|
57
|
+
export interface WithSyncOptions {
|
|
58
|
+
readonly arbiter?: boolean;
|
|
59
|
+
}
|
|
60
|
+
export declare function withSync(options?: WithSyncOptions): SyncStrategy;
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
import type { NoydbStore, DirtyEntry, ConflictStrategy, CollectionConflictResolver, PushOptions, PullOptions, PushResult, PullResult, SyncStatus, SyncTargetRole } from '../kernel/types.js';
|
|
1
|
+
import type { NoydbStore, DirtyEntry, ConflictStrategy, CollectionConflictResolver, PushOptions, PullOptions, PushResult, PullResult, SyncStatus, SyncTargetRole, RealignResult, SyncRejectedApi, ReplaceRemoteResult } from '../kernel/types.js';
|
|
2
|
+
/** core#74 — where a device parks the records its admission gate refused. Local-only: never mirrored, never full-pushed. */
|
|
3
|
+
export declare const REJECTED_COLLECTION = "_sync_rejected";
|
|
2
4
|
import type { MergeAuthority } from '../port/with/merge-authority.js';
|
|
5
|
+
import type { AdmissionAuthority } from '../port/with/admission-authority.js';
|
|
6
|
+
import type { RejectionCourier } from '../port/with/rejection-courier.js';
|
|
3
7
|
import { type PeriodPullSource } from './period-scope.js';
|
|
4
8
|
import type { NoydbEventEmitter } from '../kernel/events.js';
|
|
5
9
|
import type { SyncPolicy } from '../kernel/sync-policy.js';
|
|
@@ -13,7 +17,14 @@ export interface ReservedLookupSource {
|
|
|
13
17
|
}
|
|
14
18
|
/** Sync engine: dirty tracking, push, pull, conflict resolution, scheduling. */
|
|
15
19
|
export declare class SyncEngine {
|
|
20
|
+
#private;
|
|
16
21
|
private readonly mergeAuthority;
|
|
22
|
+
/** core#74 — the vault's admission gate for incoming records; wired at open like the other vault seams. */
|
|
23
|
+
private admission;
|
|
24
|
+
/** core#107 — the vault's sealing capability for replicated refusals; wired at open like `admission`. */
|
|
25
|
+
private courier;
|
|
26
|
+
/** core#107 — this device's refusals replicate. Configuration, not an authority proof — see `withSync`. */
|
|
27
|
+
private readonly arbiter;
|
|
17
28
|
private readonly local;
|
|
18
29
|
private readonly remote;
|
|
19
30
|
private readonly strategy;
|
|
@@ -29,6 +40,8 @@ export declare class SyncEngine {
|
|
|
29
40
|
/** #1036 — last SUCCESSFUL push/pull. Never advanced by a failed attempt. */
|
|
30
41
|
private lastPush;
|
|
31
42
|
private lastPull;
|
|
43
|
+
/** core#72 — the target's restore epoch this device adopted; null before any. */
|
|
44
|
+
private epoch;
|
|
32
45
|
/**
|
|
33
46
|
* #1036 — the failure that ended the most recent attempt, cleared by the next
|
|
34
47
|
* success. Live state only: deliberately NOT persisted in `_sync/meta`, since a
|
|
@@ -89,11 +102,55 @@ export declare class SyncEngine {
|
|
|
89
102
|
private periodPullSource?;
|
|
90
103
|
/** Wire the period-window source (#807). Same injection pattern as `setReservedLookupSource`. */
|
|
91
104
|
setPeriodPullSource(source: PeriodPullSource): void;
|
|
105
|
+
/** core#81 — the collections this keyring names; the walk set for a paged pull. Wired by the vault at open. */
|
|
106
|
+
private collectionNames?;
|
|
107
|
+
/** Wire the paged-pull walk set (core#81). Same injection pattern as `setCacheInvalidator`. */
|
|
108
|
+
setCollectionNames(fn: () => readonly string[]): void;
|
|
109
|
+
/**
|
|
110
|
+
* core#81 — one chunk per page of one collection, for `pull({ paged: true })`.
|
|
111
|
+
* `listPage` when the store offers it (200 per page), else `list` + `get` in
|
|
112
|
+
* batches of the same size. Never more than one page in memory.
|
|
113
|
+
*/
|
|
114
|
+
private pagedChunks;
|
|
115
|
+
/** core#82 — when a pull replaces the caller's OWN keyring file, the vault reloads it in place. */
|
|
116
|
+
private rosterReload?;
|
|
117
|
+
/** Wire the roster-reload seam (core#82). Same injection pattern as `setCacheInvalidator`. */
|
|
118
|
+
/** core#107 — wire the vault's rejection sealing capability. */
|
|
119
|
+
setRejectionCourier(c: RejectionCourier): void;
|
|
120
|
+
/** core#74 — wire the vault's admission gate. */
|
|
121
|
+
setAdmission(a: AdmissionAuthority): void;
|
|
122
|
+
/** core#71 — after `vault.load()`: a new base. Drops the dirty log, the watermarks and the adopted epoch. */
|
|
123
|
+
resetAfterRestore(): Promise<void>;
|
|
124
|
+
/**
|
|
125
|
+
* core#72 — make the LOCAL vault authoritative on this target. Every local
|
|
126
|
+
* record goes up unconditionally, re-sealed above the target's version where
|
|
127
|
+
* the target moved on (so every peer's copy is superseded); every id the
|
|
128
|
+
* target holds that the local vault lacks gets a delete marker at
|
|
129
|
+
* `remote._v + 1` (so every peer removes it); the reserved collections are
|
|
130
|
+
* mirrored; then a new epoch is written at `_sync/epoch`. The dirty log is
|
|
131
|
+
* cleared: the target IS the local state now.
|
|
132
|
+
*/
|
|
133
|
+
replaceRemote(): Promise<ReplaceRemoteResult>;
|
|
134
|
+
/** core#74 — the parked refusals on this device, and their two fates. */
|
|
135
|
+
rejected(): SyncRejectedApi;
|
|
136
|
+
setRosterReload(seam: {
|
|
137
|
+
userId: string;
|
|
138
|
+
reload: () => Promise<void>;
|
|
139
|
+
}): void;
|
|
140
|
+
/** core#81 — the running sync's latest progress sample; `null` when idle. Read by `status()`. */
|
|
141
|
+
private inFlight;
|
|
142
|
+
private progressLastEmit;
|
|
143
|
+
private progressLastRecords;
|
|
144
|
+
/** Emit `sync:progress` no more than every 25 records or ~250 ms; `force` for the final sample. */
|
|
145
|
+
private progress;
|
|
146
|
+
private progressDone;
|
|
92
147
|
/** #807: KPI accumulator `applyRemote` feeds during a period-scoped `pull()` — pointed at the
|
|
93
148
|
* active phase's counters (summaries → records) and cleared before pull returns. Approximate
|
|
94
149
|
* by design: a push interleaved mid-pull on the same engine would attribute its converge
|
|
95
150
|
* applies to the open phase; the counters are a download-budget KPI, not an audit source. */
|
|
96
151
|
private pullByteSink;
|
|
152
|
+
/** core#81 — ciphertext bytes applied by the running pull, for `sync:progress`. */
|
|
153
|
+
private pullBytes;
|
|
97
154
|
constructor(opts: {
|
|
98
155
|
local: NoydbStore;
|
|
99
156
|
remote: NoydbStore;
|
|
@@ -112,6 +169,8 @@ export declare class SyncEngine {
|
|
|
112
169
|
* bound to the keys rather than the engine reaching for them.
|
|
113
170
|
*/
|
|
114
171
|
mergeAuthority?: MergeAuthority;
|
|
172
|
+
/** core#107 — this device is the vault's arbiter: its refusals replicate. */
|
|
173
|
+
arbiter?: boolean;
|
|
115
174
|
});
|
|
116
175
|
/** Start the sync scheduler. Called after vault is fully opened. */
|
|
117
176
|
startScheduler(): void;
|
|
@@ -147,9 +206,16 @@ export declare class SyncEngine {
|
|
|
147
206
|
*/
|
|
148
207
|
remirrorPairResolvers(names: readonly string[]): void;
|
|
149
208
|
/** Record a local change for later push. */
|
|
150
|
-
trackChange(collection: string, id: string, action: '
|
|
209
|
+
trackChange(collection: string, id: string, action: DirtyEntry['action'], version: number): Promise<void>;
|
|
151
210
|
/** Remove a dirty entry (satellite fan-out revert cleanup — spec #591). */
|
|
152
211
|
removeDirty(collection: string, id: string): Promise<void>;
|
|
212
|
+
/**
|
|
213
|
+
* core#92 — mark every user-collection record in the local store dirty at its
|
|
214
|
+
* current version, so the next push sends it (CAS against `_v - 1`, so a
|
|
215
|
+
* remote that already holds a newer copy resolves through the conflict path
|
|
216
|
+
* instead of being overwritten). Records already dirty keep their entry.
|
|
217
|
+
*/
|
|
218
|
+
markAllDirty(): Promise<void>;
|
|
153
219
|
/** Push dirty records to remote adapter. Accepts optional `PushOptions` for partial sync. */
|
|
154
220
|
push(options?: PushOptions): Promise<PushResult>;
|
|
155
221
|
/** Pull remote records to local adapter. Accepts optional `PullOptions` for partial sync. */
|
|
@@ -181,6 +247,26 @@ export declare class SyncEngine {
|
|
|
181
247
|
*/
|
|
182
248
|
private recordOutcome;
|
|
183
249
|
/** Get current sync status. */
|
|
250
|
+
/**
|
|
251
|
+
* core#82 — re-align a CORRUPTED local from the target. An ordinary pull
|
|
252
|
+
* cannot repair a damaged local envelope: it keeps its `_v`, so it wins
|
|
253
|
+
* (or ties) against the target's healthy copy. Here every local
|
|
254
|
+
* user-collection envelope is verified with the same `MergeAuthority`
|
|
255
|
+
* check pull runs on remote envelopes; one that fails is replaced by the
|
|
256
|
+
* target's copy when THAT verifies, and the dirty log is dropped (a dirty
|
|
257
|
+
* entry over a damaged record would push the damage). Records at a tier
|
|
258
|
+
* the caller holds no key for pass unverified, as in pull — this repairs
|
|
259
|
+
* what the caller can read. Requires a `MergeAuthority` (a vault-attached
|
|
260
|
+
* engine on an encrypted vault).
|
|
261
|
+
*/
|
|
262
|
+
/**
|
|
263
|
+
* core#96 (pilot-1, finding B) — bring one member's keyring file down from
|
|
264
|
+
* this target if the target's copy supersedes ours. Called by the kernel
|
|
265
|
+
* before an authority edit; reloads the caller's own keyring in place when
|
|
266
|
+
* it is the one refreshed (core#82).
|
|
267
|
+
*/
|
|
268
|
+
refreshKeyring(userId: string): Promise<boolean>;
|
|
269
|
+
realign(): Promise<RealignResult>;
|
|
184
270
|
status(): SyncStatus;
|
|
185
271
|
/** Start auto-sync: listen for online/offline events, optional periodic sync. */
|
|
186
272
|
startAutoSync(intervalMs?: number): void;
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
* directly. This subpath is the clean LTS factory entry point.
|
|
29
29
|
*/
|
|
30
30
|
export { withSync } from './active.js';
|
|
31
|
+
export type { WithSyncOptions } from './active.js';
|
|
31
32
|
export type { SyncStrategy } from './strategy.js';
|
|
32
33
|
/** The un-opted-in stub for this service — exported so callers can compare against it (#844). */
|
|
33
34
|
export { NO_SYNC } from './strategy.js';
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reserved-record replication between two stores (core#75, core#83, core#82).
|
|
3
|
+
*
|
|
4
|
+
* `loadAll()` skips every `_`-prefixed collection, so nothing reserved
|
|
5
|
+
* travels through a sync target unless it is named here. `_keyring` was the
|
|
6
|
+
* first (core#75): a target was never a full replica — a device that lost
|
|
7
|
+
* its local store re-opened by MINTING a new owner keyring whose DEKs open
|
|
8
|
+
* nothing, and a granted member could not open on their own device at all.
|
|
9
|
+
* The invite audit doc was the second (core#83): `acceptInvite` refuses
|
|
10
|
+
* without it, by design, so magic-link onboarding onto a fresh sync-peer
|
|
11
|
+
* device was closed.
|
|
12
|
+
*
|
|
13
|
+
* ## Declared, never blanket
|
|
14
|
+
*
|
|
15
|
+
* `_meta` mixes VAULT state (deed, adoption, recovery docs, invite audit
|
|
16
|
+
* docs) with DEVICE/SESSION state (`schema-fence`, the pod `handle`) that
|
|
17
|
+
* must never reach another device — a replicated fence would break every
|
|
18
|
+
* other device's cutover. So replication is a declared set of
|
|
19
|
+
* `(collection, id prefix)` rules, each with its own ordering, and a
|
|
20
|
+
* reserved record travels only when a rule names it. The decision per
|
|
21
|
+
* collection, written down (core#82):
|
|
22
|
+
*
|
|
23
|
+
* | collection | rule | why |
|
|
24
|
+
* |---|---|---|
|
|
25
|
+
* | `_keyring` | higher `roster_epoch` wins | the roster; replay-anchored by #1097 |
|
|
26
|
+
* | `_meta/invite-audit-*` | higher `_v` wins | single-use evidence for magic links (core#83) |
|
|
27
|
+
* | `_users` | higher `_v` wins | the directory's user envelopes; a member app renders these |
|
|
28
|
+
* | `_delegations` | higher `_v` wins | delegation tokens; revocation is a delete |
|
|
29
|
+
* | `_broker`, `_broker_member` | higher `_v` wins | broker seeds (core#91) — sealed under DEKs only their holder has; a fresh device mints from them |
|
|
30
|
+
* | `_history`, `_ledger` | NOT replicated | per-device evidence: the ledger is a hash chain per writer, two devices appending would fork it; `vault.at(T)` runs where history lives |
|
|
31
|
+
* | `_sync_rejections` | higher `_v` wins | core#107 — the arbiter's refusals, sealed under the refused record's own collection DEK |
|
|
32
|
+
* | `_sync` | NOT replicated | this device's dirty log and watermarks |
|
|
33
|
+
* | `_meta/schema-fence`, `_meta/handle`, other `_meta` | NOT replicated | session and instance state; the rest of `_meta` is decided one id at a time |
|
|
34
|
+
*
|
|
35
|
+
* DEK-free by construction: every rule compares a field the mover can read
|
|
36
|
+
* without a key — `roster_epoch` (plaintext JSON on purpose, #1097, read
|
|
37
|
+
* through `team/keyring.ts`'s parser) or the envelope's `_v`.
|
|
38
|
+
*
|
|
39
|
+
* ## The one rule, both directions
|
|
40
|
+
*
|
|
41
|
+
* **The candidate wins when it supersedes; the absent side receives; equal
|
|
42
|
+
* is a no-op.** For `_keyring`, a file with no epoch (pre-#1097) never
|
|
43
|
+
* overwrites one that has an epoch. Why an ordering and not bytes: a device
|
|
44
|
+
* holding a STALE copy (epoch 3, or `_v` 1) must not push it over the newer
|
|
45
|
+
* one (epoch 4, `_v` 2) — byte-difference alone would re-introduce exactly
|
|
46
|
+
* the replay the ordering exists to anchor.
|
|
47
|
+
*
|
|
48
|
+
* ## Deletion
|
|
49
|
+
*
|
|
50
|
+
* A revocation (keyring, delegation, user envelope) deletes the record on
|
|
51
|
+
* the acting device and is pushed through the dirty log as
|
|
52
|
+
* `(collection, id, 'delete')`. On PULL, a record the remote lacks and the
|
|
53
|
+
* local holds is deleted locally only when (a) the remote carries at least
|
|
54
|
+
* one KEYRING file — a target never pushed to is not evidence of revocation,
|
|
55
|
+
* but a collection that emptied by revocation is exactly what must propagate
|
|
56
|
+
* (core#91) — and (b) no dirty entry protects it (a grant made offline, not
|
|
57
|
+
* yet pushed). Invite audit docs are never deleted; revocation is a
|
|
58
|
+
* field update, which the `_v` rule carries.
|
|
59
|
+
*/
|
|
60
|
+
import type { NoydbStore, EncryptedEnvelope } from '../kernel/types.js';
|
|
61
|
+
export interface ReservedMirrorResult {
|
|
62
|
+
/** Records written to `to`. */
|
|
63
|
+
readonly copied: number;
|
|
64
|
+
/** Records deleted from `to` (pull-side revocation propagation only). */
|
|
65
|
+
readonly deleted: number;
|
|
66
|
+
/** Ids of `_keyring` files copied — the roster reload seam reads this for the caller's own file. */
|
|
67
|
+
readonly keyringsCopied: readonly string[];
|
|
68
|
+
/**
|
|
69
|
+
* core#96 (pilot-1, finding B) — push only: local `_keyring` files the epoch
|
|
70
|
+
* rule did not write and whose content differs from the remote's (the remote
|
|
71
|
+
* is ahead, or the two diverged at one epoch). The local edit LOST; the
|
|
72
|
+
* engine reports each as a `Conflict` so an authority edit made on a stale
|
|
73
|
+
* copy is never silently dropped.
|
|
74
|
+
*/
|
|
75
|
+
readonly staleKeyrings?: readonly {
|
|
76
|
+
readonly id: string;
|
|
77
|
+
readonly local: EncryptedEnvelope;
|
|
78
|
+
readonly remote: EncryptedEnvelope;
|
|
79
|
+
}[];
|
|
80
|
+
}
|
|
81
|
+
/** The push half: mirror every declared rule from `local` to `remote`. Never deletes. */
|
|
82
|
+
export declare function pushReserved(local: NoydbStore, remote: NoydbStore, vault: string): Promise<ReservedMirrorResult>;
|
|
83
|
+
/**
|
|
84
|
+
* core#96 (pilot-1, finding B) — bring ONE member's keyring file down from the
|
|
85
|
+
* target if the target's copy supersedes the local one. The kernel calls it
|
|
86
|
+
* before every authority edit (`grant` on an existing user, `updateUser`,
|
|
87
|
+
* `revoke`, `recoverUser`), so the edit is made on the current file and its
|
|
88
|
+
* push wins instead of being discarded by the epoch rule. One GET.
|
|
89
|
+
*/
|
|
90
|
+
export declare function pullKeyringFile(remote: NoydbStore, local: NoydbStore, vault: string, userId: string): Promise<boolean>;
|
|
91
|
+
/**
|
|
92
|
+
* The pull half: mirror every declared rule from `remote` into `local`, then
|
|
93
|
+
* propagate revocations under the two guards in the module doc.
|
|
94
|
+
* `protectedIds` maps a collection to the ids a pending local dirty entry
|
|
95
|
+
* protects.
|
|
96
|
+
*
|
|
97
|
+
* Costs one `list()` per rule per pull, and nothing at all for a vault with
|
|
98
|
+
* no local keyring: an encrypted vault always holds the caller's own file
|
|
99
|
+
* after open (bootstrapped or minted), so "no local keyring" means
|
|
100
|
+
* `encrypt: false` — nothing reserved to mirror, nothing to ask.
|
|
101
|
+
*/
|
|
102
|
+
export declare function pullReserved(remote: NoydbStore, local: NoydbStore, vault: string, protectedIds: ReadonlyMap<string, ReadonlySet<string>>): Promise<ReservedMirrorResult>;
|
|
103
|
+
/**
|
|
104
|
+
* Open-path bootstrap: an EMPTY local store is not evidence of a new vault
|
|
105
|
+
* when a `sync-peer` already carries the roster. Mirror its keyring files in
|
|
106
|
+
* first; `assertKeyringOpenAllowed` then decides — own file → open, other
|
|
107
|
+
* principals only → refuse, still nothing → genuinely new. Backups are
|
|
108
|
+
* never consulted (never pulled from, #616). No-op when the local already
|
|
109
|
+
* holds any keyring. Only the roster: the rest of the declared set arrives
|
|
110
|
+
* on the first `pull()`.
|
|
111
|
+
*/
|
|
112
|
+
export declare function bootstrapKeyrings(local: NoydbStore, peer: NoydbStore | undefined, vault: string): Promise<void>;
|
|
@@ -50,12 +50,21 @@ export interface BuildSyncEngineOptions {
|
|
|
50
50
|
label?: string;
|
|
51
51
|
/** #1042 — the merge's verify/re-stamp capability, bound to the keys by the caller. */
|
|
52
52
|
mergeAuthority?: MergeAuthority;
|
|
53
|
+
/** core#107 — this device is the vault's arbiter: its admission refusals replicate. */
|
|
54
|
+
arbiter?: boolean;
|
|
53
55
|
}
|
|
54
56
|
/**
|
|
55
57
|
* @internal
|
|
56
58
|
*/
|
|
57
59
|
export interface SyncStrategy {
|
|
58
60
|
buildSyncEngine(opts: BuildSyncEngineOptions): SyncEngine;
|
|
61
|
+
/**
|
|
62
|
+
* core#75 — open-path roster bootstrap: an EMPTY local store is not a new
|
|
63
|
+
* vault when a `sync-peer` already carries the roster. Runs inside keyring
|
|
64
|
+
* resolution, BEFORE any engine exists; the un-opted-in stub is a no-op
|
|
65
|
+
* (no sync ⇒ no target to bootstrap from).
|
|
66
|
+
*/
|
|
67
|
+
bootstrapKeyrings(local: NoydbStore, peer: NoydbStore | undefined, vault: string): Promise<void>;
|
|
59
68
|
buildSyncTransaction(vault: Vault, engine: SyncEngine): SyncTransaction;
|
|
60
69
|
buildPresence<P>(opts: PresenceHandleOpts): PresenceHandle<P>;
|
|
61
70
|
}
|
|
@@ -7,16 +7,6 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import type { TabChannel, Unsubscribe } from './tab-coordination.js';
|
|
9
9
|
import type { WriteEvent } from '../port/with/write-hooks.js';
|
|
10
|
-
export interface TabWriteMsg {
|
|
11
|
-
readonly kind: 'tab-write';
|
|
12
|
-
readonly writerId: string;
|
|
13
|
-
readonly vault: string;
|
|
14
|
-
readonly collection: string;
|
|
15
|
-
readonly docId: string;
|
|
16
|
-
readonly action: 'put' | 'delete';
|
|
17
|
-
readonly baseV: number;
|
|
18
|
-
readonly v: number;
|
|
19
|
-
}
|
|
20
10
|
export interface CrossTabWriteRelayOptions {
|
|
21
11
|
/** The broadcast channel (its own — distinct from the presence channel). */
|
|
22
12
|
readonly channel: TabChannel;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import {
|
|
2
|
+
freezeAndDeleteClosure,
|
|
3
|
+
freezeSnapshotOnly,
|
|
4
|
+
randomId,
|
|
5
|
+
withdrawAccessibleData
|
|
6
|
+
} from "./chunk-R2ZULFXU.js";
|
|
7
|
+
import "./chunk-KN4LUMH6.js";
|
|
8
|
+
import "./chunk-XPW7T2GN.js";
|
|
9
|
+
import "./chunk-DMIEKD24.js";
|
|
10
|
+
import "./chunk-GMKGGY7V.js";
|
|
11
|
+
import "./chunk-WRLWEYHY.js";
|
|
12
|
+
import "./chunk-ZD7WFMV2.js";
|
|
13
|
+
import "./chunk-RRTQAQ3N.js";
|
|
14
|
+
import "./chunk-NH2UOV3B.js";
|
|
15
|
+
import "./chunk-ZF6JECDT.js";
|
|
16
|
+
import "./chunk-THQ3BHLM.js";
|
|
17
|
+
import "./chunk-XX4R7TUB.js";
|
|
18
|
+
import "./chunk-IKPQ2GGB.js";
|
|
19
|
+
export {
|
|
20
|
+
freezeAndDeleteClosure,
|
|
21
|
+
freezeSnapshotOnly,
|
|
22
|
+
randomId,
|
|
23
|
+
withdrawAccessibleData
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=withdraw-accessible-MTFP7OIB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@noy-db/hub",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0-pre.1",
|
|
4
4
|
"description": "Zero-knowledge, offline-first, encrypted document store — core library with AES-256-GCM, PBKDF2, multi-user keyring, and sync engine",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "vLannaAi <vicio@lanna.ai>",
|
|
@@ -276,8 +276,8 @@
|
|
|
276
276
|
"happy-dom": "^18.0.0",
|
|
277
277
|
"zod": "^4.0.0",
|
|
278
278
|
"zod-to-json-schema": "^3.25.2",
|
|
279
|
-
"@noy-db/attestation": "0.
|
|
280
|
-
"@noy-db/shamir": "0.
|
|
279
|
+
"@noy-db/attestation": "0.9.0-pre.1",
|
|
280
|
+
"@noy-db/shamir": "0.9.0-pre.1"
|
|
281
281
|
},
|
|
282
282
|
"peerDependencies": {
|
|
283
283
|
"zod": "^3.0.0 || ^4.0.0",
|
package/dist/api-OS747DS4.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
UserApi,
|
|
3
|
-
createUserApi
|
|
4
|
-
} from "./chunk-AEQGFRU4.js";
|
|
5
|
-
import "./chunk-LIOVX5TJ.js";
|
|
6
|
-
import "./chunk-EZGV6F47.js";
|
|
7
|
-
import "./chunk-OIEO4WDL.js";
|
|
8
|
-
import "./chunk-Q2XRFWOI.js";
|
|
9
|
-
import "./chunk-NH2UOV3B.js";
|
|
10
|
-
import "./chunk-42ALPZ2B.js";
|
|
11
|
-
import "./chunk-QMWY2FDS.js";
|
|
12
|
-
import "./chunk-SV2PM2OY.js";
|
|
13
|
-
import "./chunk-37EPTBBR.js";
|
|
14
|
-
export {
|
|
15
|
-
UserApi,
|
|
16
|
-
createUserApi
|
|
17
|
-
};
|
|
18
|
-
//# sourceMappingURL=api-OS747DS4.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/with-pod/backup.ts"],"sourcesContent":["/**\n * Vault backup / restore / integrity.\n *\n * Holds `dump()` (verifiable encrypted JSON backup, including the blob\n * collections so blob \"covers\" travel in the bundle), `load()` (restore +\n * post-load integrity gate), `verifyBackupIntegrity()` (chain + data-envelope\n * cross-check), and `exportJSON()` (plaintext per-collection export, built on\n * the vault's `exportStream`). Behaviour is byte-identical to the inline\n * `Vault` methods these functions replaced — every dependency the moving code\n * touched on `this.*` arrives via {@link BackupContext}. `Vault` keeps the\n * public methods as thin delegators.\n *\n * Internal — reached through `vault.dump()` / `vault.load()` / etc.\n */\nimport { NOYDB_BACKUP_VERSION } from '../kernel/types.js'\nimport { BackupLedgerError, BackupCorruptedError } from '../kernel/errors.js'\nimport { LEDGER_COLLECTION, LEDGER_DELTAS_COLLECTION } from '../with-commit/history/ledger/constants.js'\nimport { SCHEMAS_COLLECTION } from '../with-shape/persisted-schemas/storage.js'\nimport { SEQUENCE_COLLECTION } from '../with-commit/sequence/index.js'\nimport { MANIFEST_COLLECTION } from '../with-shape/manifest/reserved-collections.js'\n// #1025 — imported from the dependency-light `window.ts`, not `periods.ts`: that\n// module exists precisely so a consumer can name the period collections without\n// dragging the ledger hash-chain machinery (`sha256Hex`/`canonicalJson`) into a\n// bundle that opted out of the periods service. Same reason the sync engine's\n// period-scoped pull imports it.\nimport {\n PERIODS_COLLECTION,\n PERIOD_FREEZES_COLLECTION,\n PERIOD_ARCHIVES_COLLECTION,\n PERIOD_TARGET_PURGES_COLLECTION,\n PERIOD_REOPENS_COLLECTION,\n} from '../with-audit/periods/window.js'\nimport type {\n NoydbStore,\n EncryptedEnvelope,\n VaultBackup,\n VaultSnapshot,\n ExportStreamOptions,\n ExportChunk,\n} from '../kernel/types.js'\nimport type { LedgerStore } from '../with-commit/history/ledger/store.js'\nimport { buildRecordEnvelope } from '../capsule/index.js'\n\n/** Everything the moving backup methods touched on the vault's `this.*`. */\nexport interface BackupContext {\n /** The ciphertext store. */\n readonly adapter: NoydbStore\n /** Vault namespace name. */\n readonly vault: string\n /** The invoking keyring's user id (read fresh per call). */\n userId(): string\n /** The vault's ledger store, or null when history is off. */\n getLedgerOrNull(): LedgerStore | null\n /** Recompute an envelope's `payloadHash` (bound `historyStrategy.envelopePayloadHash`). */\n envelopePayloadHash(envelope: EncryptedEnvelope): Promise<string>\n /**\n * Refresh the in-memory keyring from the freshly-loaded keyring file and\n * rebuild the DEK resolver. No-op when the vault has no `reloadKeyring`\n * callback (plaintext vaults / test constructions).\n */\n reloadKeyringAndRebuildDEK(): Promise<void>\n /** Clear the vault's collection cache (post-load). */\n clearCollectionCache(): void\n /** Reset the ledger store so the next `ledger()` rebuilds its head cache. */\n resetLedgerStore(): void\n /** The vault's decrypt+ACL export stream (used by `exportJSON`). */\n exportStream(opts: ExportStreamOptions): AsyncIterableIterator<ExportChunk>\n}\n\n/** Result of {@link verifyBackupIntegrity}. */\nexport type VerifyBackupResult =\n | { readonly ok: true; readonly head: string; readonly length: number }\n | {\n readonly ok: false\n readonly kind: 'chain'\n readonly divergedAt: number\n readonly message: string\n }\n | {\n readonly ok: false\n readonly kind: 'data'\n readonly collection: string\n readonly id: string\n readonly message: string\n }\n\n/**\n * Dump vault as a verifiable encrypted JSON backup string.\n *\n * backups embed the current ledger head and the full `_ledger` +\n * `_ledger_deltas` internal collections so the receiver can run\n * `verifyBackupIntegrity()` after `load()` and detect any tampering between\n * dump and restore. Backups produced without a ledger skip the integrity check\n * with a warning — both modes round-trip cleanly.\n */\nexport async function dumpVault(ctx: BackupContext): Promise<string> {\n const snapshot = await ctx.adapter.loadAll(ctx.vault)\n\n // Load keyrings (separate path because loadAll filters them out\n // along with all other underscore-prefixed internal collections).\n const keyringIds = await ctx.adapter.list(ctx.vault, '_keyring')\n const keyrings: Record<string, unknown> = {}\n for (const keyringId of keyringIds) {\n const envelope = await ctx.adapter.get(ctx.vault, '_keyring', keyringId)\n if (envelope) {\n keyrings[keyringId] = JSON.parse(envelope._data ?? '')\n }\n }\n\n // Load the ledger entries + deltas so the receiver can replay\n // the chain after restore. Without this, `load()` would have an\n // empty ledger and `verifyBackupIntegrity()` would have nothing\n // to compare against.\n //\n // Also enumerate the blob collections so blob content (\"covers\")\n // travels in the bundle (the blob DEK already travels in `_keyring`).\n // Literals are inlined (not imported from blobs/blob-set.ts) to keep\n // the blob runtime out of this kernel hot path — they mirror\n // BLOB_INDEX/CHUNKS/EVICTION_AUDIT_COLLECTION and SLOTS/VERSIONS_PREFIX.\n // The collect-loop skips empty ids, so this no-ops without blobs.\n const internalSnapshot: VaultSnapshot = {}\n const internalNames = [\n LEDGER_COLLECTION, LEDGER_DELTAS_COLLECTION, SCHEMAS_COLLECTION, SEQUENCE_COLLECTION,\n MANIFEST_COLLECTION, // #941: the pod's manifest-set record(s) travel in the bundle too\n // #1025: the accounting-period close state + its companions. The bundle is\n // the backup/restore path, so without these a restore discarded the\n // hash-chained evidence that a month was ever closed — the artifact\n // `closePeriod` exists to produce — and dropped the write gate with it, so\n // the restored vault silently accepted back-dated writes into a sealed\n // month. The companions matter as much as the close: a bounded reopen\n // window (`reopenPeriod({ until })`) is state a restore must not lose.\n PERIODS_COLLECTION,\n PERIOD_REOPENS_COLLECTION,\n PERIOD_FREEZES_COLLECTION,\n PERIOD_ARCHIVES_COLLECTION,\n PERIOD_TARGET_PURGES_COLLECTION,\n '_history', // full-snapshot version history — so history()/getVersion()/diff() survive the bundle\n '_blob_index', '_blob_chunks', '_blob_eviction_audit',\n // #753 spec §7 Q3: `_blob_intent` markers travel too — restoring mid-op\n // state (a blob row without its marker) would reproduce the ambiguity\n // the journal exists to prevent. Note: `_mv_stale` does NOT travel\n // today (a pre-existing, separate gap) — observed here, tracked on\n // #761, not fixed in this pass.\n '_blob_intent',\n // #769: `_blob_slots_<c>` envelopes travel verbatim (raw ciphertext,\n // same DEK, same vault) — including any `SlotRecord.pendingRelease`\n // resume breadcrumb they carry. This is INTENTIONALLY the opposite of\n // `extract-partition`'s `reKeyBlobs`, which STRIPS `pendingRelease`:\n // a full-vault backup restores into the SAME vault it was taken from,\n // so a breadcrumb taken mid-rehome (together with its `_blob_intent`\n // marker, carried above) is resumable on restore — carry-and-resume is\n // correct here. A partition extraction crosses vaults: the breadcrumb's\n // old eTag may not exist in the destination, so it must be stripped\n // there instead. Asymmetry: backup = same-vault-resumable = carry;\n // partition = cross-vault = strip-breadcrumb-carry-marker.\n ...Object.keys(snapshot).flatMap((c) => [`_blob_slots_${c}`, `_blob_versions_${c}`]),\n ]\n for (const internalName of internalNames) {\n const ids = await ctx.adapter.list(ctx.vault, internalName)\n if (ids.length === 0) continue\n const records: Record<string, EncryptedEnvelope> = {}\n for (const id of ids) {\n const envelope = await ctx.adapter.get(ctx.vault, internalName, id)\n if (envelope) records[id] = envelope\n }\n internalSnapshot[internalName] = records\n }\n\n // Embed the ledger head if there's a chain. An empty ledger\n // (fresh vault) leaves `ledgerHead` undefined, which\n // load() treats the same as a legacy backup (no integrity\n // check, console warning). If history is not opted in,\n // `getLedgerOrNull` returns null and we skip embedding entirely\n // — the backup is still valid, just without the integrity head.\n const ledgerForHead = ctx.getLedgerOrNull()\n const head = ledgerForHead ? await ledgerForHead.head() : null\n const backup: VaultBackup = {\n _noydb_backup: NOYDB_BACKUP_VERSION,\n _compartment: ctx.vault,\n _exported_at: new Date().toISOString(),\n _exported_by: ctx.userId(),\n keyrings: keyrings as VaultBackup['keyrings'],\n collections: snapshot,\n ...(Object.keys(internalSnapshot).length > 0\n ? { _internal: internalSnapshot }\n : {}),\n ...(head\n ? {\n ledgerHead: {\n hash: head.hash,\n index: head.entry.index,\n ts: head.entry.ts,\n },\n }\n : {}),\n }\n\n return JSON.stringify(backup)\n}\n\n/**\n * Restore a vault from a verifiable backup. After loading, runs\n * `verifyBackupIntegrity()` to confirm the hash chain, the embedded head, and\n * every data envelope's payload hash. Legacy backups (no `ledgerHead`) load\n * with a console warning and skip the integrity check.\n */\nexport async function loadVault(ctx: BackupContext, backupJson: string): Promise<void> {\n const backup = JSON.parse(backupJson) as VaultBackup\n\n // 1. Restore data collections.\n await ctx.adapter.saveAll(ctx.vault, backup.collections)\n\n // 2. Restore keyrings.\n for (const [userId, keyringFile] of Object.entries(backup.keyrings)) {\n const envelope = buildRecordEnvelope({ collection: '_keyring', id: userId, version: 1 },\n { iv: '', data: JSON.stringify(keyringFile) })\n await ctx.adapter.put(ctx.vault, '_keyring', userId, envelope)\n }\n\n // 3. Restore internal collections (`_ledger`, `_ledger_deltas`).\n // Required so verifyBackupIntegrity has the chain to walk.\n if (backup._internal) {\n for (const [internalName, records] of Object.entries(backup._internal)) {\n for (const [id, envelope] of Object.entries(records)) {\n await ctx.adapter.put(ctx.vault, internalName, id, envelope)\n }\n }\n }\n\n // 4. Refresh the in-memory keyring from the freshly-loaded\n // keyring file. Without this, the Vault's getDEK\n // closure still holds the OLD session's DEKs, and every\n // decrypt of a loaded ledger entry / data envelope fails\n // with TamperedError because the DEK doesn't match the\n // ciphertext that was encrypted with the SOURCE user's DEK.\n // Skipped for plaintext vaults and for tests that\n // construct Vault without a reloadKeyring callback.\n await ctx.reloadKeyringAndRebuildDEK()\n\n // 5. Clear collection cache + reset the ledger store so the\n // next ledger() call rebuilds its head cache from the\n // freshly-loaded entries.\n ctx.clearCollectionCache()\n ctx.resetLedgerStore()\n\n // 5. Run the verification gate. A backup with no ledgerHead cannot be\n // integrity-checked, and skipping silently would collapse\n // *unverifiable* into *clean* — so it always warns. But the REMEDY\n // depends on the reader, not the pod (#1303): the pod cannot say\n // whether its exporter predates the ledger or never enabled it, and\n // the reader knows its own configuration.\n //\n // - Reader HAS the ledger: the pod is behind it. \"Re-export\" is\n // actionable; keep the migration wording.\n // - Reader has NO ledger: nothing is stale and nothing is migrating —\n // the consumer priced the ledger (#1248 measured ~2.4x) and declined.\n // Prescribing a re-export is advice they should not take, and\n // repeating it on every read trains people to filter the one line\n // that also fires on a genuinely stale pod. State the consequence,\n // name the discriminator, prescribe nothing.\n if (!backup.ledgerHead) {\n if (ctx.getLedgerOrNull()) {\n console.warn(\n `[noy-db] Loaded a legacy backup with no ledgerHead — ` +\n `verifiable-backup integrity check skipped. ` +\n `Re-export with a ledger-aware build to get tamper detection.`,\n )\n } else {\n console.warn(\n `[noy-db] Loaded a backup with no ledgerHead — this pod is not integrity-checked. ` +\n `This reader has no ledger enabled (withHistory() is not configured), so nothing is stale: ` +\n `enable the ledger on both the exporter and this reader if tamper detection is wanted.`,\n )\n }\n return\n }\n\n const result = await verifyBackupIntegrity(ctx)\n if (!result.ok) {\n // Surface the most specific error class we can. The result\n // shape carries enough info for callers to inspect.\n if (result.kind === 'data') {\n throw new BackupCorruptedError(\n result.collection,\n result.id,\n result.message,\n )\n }\n throw new BackupLedgerError(result.message, result.divergedAt)\n }\n\n // 6. Cross-check: the freshly-verified head must match the\n // value embedded at dump time. A mismatch means someone\n // truncated or extended the chain after dump.\n if (result.head !== backup.ledgerHead.hash) {\n throw new BackupLedgerError(\n `Backup ledger head mismatch: embedded \"${backup.ledgerHead.hash}\" ` +\n `but reconstructed \"${result.head}\".`,\n )\n }\n}\n\n/**\n * End-to-end backup integrity check: `ledger.verify()` (hash chain) plus a data\n * envelope cross-check (every current record's `_data` hash must match the\n * latest `put` entry's `payloadHash`). Returns a discriminated union so callers\n * can distinguish chain vs data failures.\n */\nexport async function verifyBackupIntegrity(ctx: BackupContext): Promise<VerifyBackupResult> {\n // Step 1: chain verification. Without the history strategy there\n // is no ledger; an unaudited backup verifies trivially as `ok`\n // because there's nothing to diverge from.\n const ledgerForVerify = ctx.getLedgerOrNull()\n if (!ledgerForVerify) {\n return { ok: true, head: '', length: 0 }\n }\n const chainResult = await ledgerForVerify.verify()\n if (!chainResult.ok) {\n return {\n ok: false,\n kind: 'chain',\n divergedAt: chainResult.divergedAt,\n message:\n `Ledger chain diverged at index ${chainResult.divergedAt}: ` +\n `expected prevHash \"${chainResult.expected}\" but found \"${chainResult.actual}\".`,\n }\n }\n\n // Step 2: data envelope cross-check. Walk every entry in the\n // ledger and, for the LATEST `put` per (collection, id), recompute\n // the data envelope's payloadHash and compare. Earlier puts of the\n // same id are skipped because the data collection only holds the\n // current version — historical envelopes live in the deltas\n // collection (which is itself protected by the chain).\n // Reuse the ledger we already resolved in step 1.\n const allEntries = await ledgerForVerify.loadAllEntries()\n\n // Find the latest non-delete entry per (collection, id). Walk\n // the entries in reverse so we hit the latest first; mark each\n // (collection, id) as seen and skip subsequent entries.\n const seen = new Set<string>()\n const latest = new Map<\n string,\n { collection: string; id: string; expectedHash: string }\n >()\n for (let i = allEntries.length - 1; i >= 0; i--) {\n const entry = allEntries[i]\n if (!entry) continue\n // Amendment entries are multi-record audit entries whose\n // `collection` and `id` are empty strings — building a `\"/\"`\n // key here would mark that synthetic slot as seen and falsely\n // trip the data check on a record that never existed. Skip\n // them BEFORE the key/seen bookkeeping so they neither\n // tombstone real entries nor enter the latest map.\n if (entry.op === 'amendment' || entry.op === 'lifecycle') continue\n const key = `${entry.collection}/${entry.id}`\n if (seen.has(key)) continue\n seen.add(key)\n // For deletes the data collection should NOT have the record,\n // so we skip — there's nothing to cross-check. Marking the key\n // as seen above ensures any earlier `put` of the same id is\n // also skipped (the record was subsequently deleted).\n if (entry.op === 'delete') continue\n latest.set(key, {\n collection: entry.collection,\n id: entry.id,\n expectedHash: entry.payloadHash,\n })\n }\n\n for (const { collection, id, expectedHash } of latest.values()) {\n const envelope = await ctx.adapter.get(ctx.vault, collection, id)\n if (!envelope) {\n return {\n ok: false,\n kind: 'data',\n collection,\n id,\n message:\n `Ledger expects data record \"${collection}/${id}\" to exist, ` +\n `but the adapter has no envelope for it.`,\n }\n }\n const actualHash = await ctx.envelopePayloadHash(envelope)\n if (actualHash !== expectedHash) {\n return {\n ok: false,\n kind: 'data',\n collection,\n id,\n message:\n `Data envelope \"${collection}/${id}\" has been tampered with: ` +\n `expected payloadHash \"${expectedHash}\", got \"${actualHash}\".`,\n }\n }\n }\n\n return {\n ok: true,\n head: chainResult.head,\n length: chainResult.length,\n }\n}\n\n/**\n * Plaintext per-collection export, built on the vault's `exportStream`. Forces\n * collection granularity (record-by-record output makes no sense in a single\n * string) and merges dictionary snapshots across collections.\n */\nexport async function exportVaultJSON(ctx: BackupContext, opts: ExportStreamOptions = {}): Promise<string> {\n // Force per-collection granularity regardless of caller setting:\n // record-by-record output doesn't make sense in a single string.\n const collections: Record<\n string,\n {\n schema: null\n refs: Record<string, { target: string; mode: 'strict' | 'warn' | 'cascade' }>\n records: unknown[]\n }\n > = {}\n let ledgerHead: ExportChunk['ledgerHead'] | undefined\n // Merged dictionary snapshot across all collections.\n // Only populated when `resolveLabels` is not set.\n const allDictionaries: Record<\n string, // collection name\n Record<string, Record<string, Record<string, string>>>\n > = {}\n\n for await (const chunk of ctx.exportStream({\n granularity: 'collection',\n withLedgerHead: opts.withLedgerHead === true,\n // Thread the export locale so records are read at the\n // `export` layer (i18nText collapsed + dictKey/staticDict labels resolved).\n ...(opts.resolveLabels !== undefined ? { resolveLabels: opts.resolveLabels } : {}),\n })) {\n collections[chunk.collection] = {\n schema: null, // Standard Schema validators are not JSON-serializable\n refs: chunk.refs,\n records: chunk.records,\n }\n if (chunk.ledgerHead) ledgerHead = chunk.ledgerHead\n // Collect dictionary snapshots unless resolveLabels is set\n if (!opts.resolveLabels && chunk.dictionaries) {\n allDictionaries[chunk.collection] = chunk.dictionaries\n }\n }\n\n const hasDictionaries = Object.keys(allDictionaries).length > 0\n return JSON.stringify({\n _noydb_export: 1,\n _compartment: ctx.vault,\n _exported_at: new Date().toISOString(),\n _exported_by: ctx.userId(),\n collections,\n ...(hasDictionaries ? { _dictionaries: allDictionaries } : {}),\n ...(ledgerHead ? { ledgerHead } : {}),\n })\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+FA,eAAsB,UAAU,KAAqC;AACnE,QAAM,WAAW,MAAM,IAAI,QAAQ,QAAQ,IAAI,KAAK;AAIpD,QAAM,aAAa,MAAM,IAAI,QAAQ,KAAK,IAAI,OAAO,UAAU;AAC/D,QAAM,WAAoC,CAAC;AAC3C,aAAW,aAAa,YAAY;AAClC,UAAM,WAAW,MAAM,IAAI,QAAQ,IAAI,IAAI,OAAO,YAAY,SAAS;AACvE,QAAI,UAAU;AACZ,eAAS,SAAS,IAAI,KAAK,MAAM,SAAS,SAAS,EAAE;AAAA,IACvD;AAAA,EACF;AAaA,QAAM,mBAAkC,CAAC;AACzC,QAAM,gBAAgB;AAAA,IACpB;AAAA,IAAmB;AAAA,IAA0B;AAAA,IAAoB;AAAA,IACjE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAQA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA,IACA;AAAA,IAAe;AAAA,IAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAM/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAYA,GAAG,OAAO,KAAK,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,kBAAkB,CAAC,EAAE,CAAC;AAAA,EACrF;AACA,aAAW,gBAAgB,eAAe;AACxC,UAAM,MAAM,MAAM,IAAI,QAAQ,KAAK,IAAI,OAAO,YAAY;AAC1D,QAAI,IAAI,WAAW,EAAG;AACtB,UAAM,UAA6C,CAAC;AACpD,eAAW,MAAM,KAAK;AACpB,YAAM,WAAW,MAAM,IAAI,QAAQ,IAAI,IAAI,OAAO,cAAc,EAAE;AAClE,UAAI,SAAU,SAAQ,EAAE,IAAI;AAAA,IAC9B;AACA,qBAAiB,YAAY,IAAI;AAAA,EACnC;AAQA,QAAM,gBAAgB,IAAI,gBAAgB;AAC1C,QAAM,OAAO,gBAAgB,MAAM,cAAc,KAAK,IAAI;AAC1D,QAAM,SAAsB;AAAA,IAC1B,eAAe;AAAA,IACf,cAAc,IAAI;AAAA,IAClB,eAAc,oBAAI,KAAK,GAAE,YAAY;AAAA,IACrC,cAAc,IAAI,OAAO;AAAA,IACzB;AAAA,IACA,aAAa;AAAA,IACb,GAAI,OAAO,KAAK,gBAAgB,EAAE,SAAS,IACvC,EAAE,WAAW,iBAAiB,IAC9B,CAAC;AAAA,IACL,GAAI,OACA;AAAA,MACE,YAAY;AAAA,QACV,MAAM,KAAK;AAAA,QACX,OAAO,KAAK,MAAM;AAAA,QAClB,IAAI,KAAK,MAAM;AAAA,MACjB;AAAA,IACF,IACA,CAAC;AAAA,EACP;AAEA,SAAO,KAAK,UAAU,MAAM;AAC9B;AAQA,eAAsB,UAAU,KAAoB,YAAmC;AACrF,QAAM,SAAS,KAAK,MAAM,UAAU;AAGpC,QAAM,IAAI,QAAQ,QAAQ,IAAI,OAAO,OAAO,WAAW;AAGvD,aAAW,CAAC,QAAQ,WAAW,KAAK,OAAO,QAAQ,OAAO,QAAQ,GAAG;AACnE,UAAM,WAAW;AAAA,MAAoB,EAAE,YAAY,YAAY,IAAI,QAAQ,SAAS,EAAE;AAAA,MACpF,EAAE,IAAI,IAAI,MAAM,KAAK,UAAU,WAAW,EAAE;AAAA,IAAC;AAC/C,UAAM,IAAI,QAAQ,IAAI,IAAI,OAAO,YAAY,QAAQ,QAAQ;AAAA,EAC/D;AAIA,MAAI,OAAO,WAAW;AACpB,eAAW,CAAC,cAAc,OAAO,KAAK,OAAO,QAAQ,OAAO,SAAS,GAAG;AACtE,iBAAW,CAAC,IAAI,QAAQ,KAAK,OAAO,QAAQ,OAAO,GAAG;AACpD,cAAM,IAAI,QAAQ,IAAI,IAAI,OAAO,cAAc,IAAI,QAAQ;AAAA,MAC7D;AAAA,IACF;AAAA,EACF;AAUA,QAAM,IAAI,2BAA2B;AAKrC,MAAI,qBAAqB;AACzB,MAAI,iBAAiB;AAiBrB,MAAI,CAAC,OAAO,YAAY;AACtB,QAAI,IAAI,gBAAgB,GAAG;AACzB,cAAQ;AAAA,QACN;AAAA,MAGF;AAAA,IACF,OAAO;AACL,cAAQ;AAAA,QACN;AAAA,MAGF;AAAA,IACF;AACA;AAAA,EACF;AAEA,QAAM,SAAS,MAAM,sBAAsB,GAAG;AAC9C,MAAI,CAAC,OAAO,IAAI;AAGd,QAAI,OAAO,SAAS,QAAQ;AAC1B,YAAM,IAAI;AAAA,QACR,OAAO;AAAA,QACP,OAAO;AAAA,QACP,OAAO;AAAA,MACT;AAAA,IACF;AACA,UAAM,IAAI,kBAAkB,OAAO,SAAS,OAAO,UAAU;AAAA,EAC/D;AAKA,MAAI,OAAO,SAAS,OAAO,WAAW,MAAM;AAC1C,UAAM,IAAI;AAAA,MACR,0CAA0C,OAAO,WAAW,IAAI,wBAC1C,OAAO,IAAI;AAAA,IACnC;AAAA,EACF;AACF;AAQA,eAAsB,sBAAsB,KAAiD;AAI3F,QAAM,kBAAkB,IAAI,gBAAgB;AAC5C,MAAI,CAAC,iBAAiB;AACpB,WAAO,EAAE,IAAI,MAAM,MAAM,IAAI,QAAQ,EAAE;AAAA,EACzC;AACA,QAAM,cAAc,MAAM,gBAAgB,OAAO;AACjD,MAAI,CAAC,YAAY,IAAI;AACnB,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,MAAM;AAAA,MACN,YAAY,YAAY;AAAA,MACxB,SACE,kCAAkC,YAAY,UAAU,wBAClC,YAAY,QAAQ,gBAAgB,YAAY,MAAM;AAAA,IAChF;AAAA,EACF;AASA,QAAM,aAAa,MAAM,gBAAgB,eAAe;AAKxD,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,SAAS,oBAAI,IAGjB;AACF,WAAS,IAAI,WAAW,SAAS,GAAG,KAAK,GAAG,KAAK;AAC/C,UAAM,QAAQ,WAAW,CAAC;AAC1B,QAAI,CAAC,MAAO;AAOZ,QAAI,MAAM,OAAO,eAAe,MAAM,OAAO,YAAa;AAC1D,UAAM,MAAM,GAAG,MAAM,UAAU,IAAI,MAAM,EAAE;AAC3C,QAAI,KAAK,IAAI,GAAG,EAAG;AACnB,SAAK,IAAI,GAAG;AAKZ,QAAI,MAAM,OAAO,SAAU;AAC3B,WAAO,IAAI,KAAK;AAAA,MACd,YAAY,MAAM;AAAA,MAClB,IAAI,MAAM;AAAA,MACV,cAAc,MAAM;AAAA,IACtB,CAAC;AAAA,EACH;AAEA,aAAW,EAAE,YAAY,IAAI,aAAa,KAAK,OAAO,OAAO,GAAG;AAC9D,UAAM,WAAW,MAAM,IAAI,QAAQ,IAAI,IAAI,OAAO,YAAY,EAAE;AAChE,QAAI,CAAC,UAAU;AACb,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,MAAM;AAAA,QACN;AAAA,QACA;AAAA,QACA,SACE,+BAA+B,UAAU,IAAI,EAAE;AAAA,MAEnD;AAAA,IACF;AACA,UAAM,aAAa,MAAM,IAAI,oBAAoB,QAAQ;AACzD,QAAI,eAAe,cAAc;AAC/B,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,MAAM;AAAA,QACN;AAAA,QACA;AAAA,QACA,SACE,kBAAkB,UAAU,IAAI,EAAE,mDACT,YAAY,WAAW,UAAU;AAAA,MAC9D;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,MAAM,YAAY;AAAA,IAClB,QAAQ,YAAY;AAAA,EACtB;AACF;AAOA,eAAsB,gBAAgB,KAAoB,OAA4B,CAAC,GAAoB;AAGzG,QAAM,cAOF,CAAC;AACL,MAAI;AAGJ,QAAM,kBAGF,CAAC;AAEL,mBAAiB,SAAS,IAAI,aAAa;AAAA,IACzC,aAAa;AAAA,IACb,gBAAgB,KAAK,mBAAmB;AAAA;AAAA;AAAA,IAGxC,GAAI,KAAK,kBAAkB,SAAY,EAAE,eAAe,KAAK,cAAc,IAAI,CAAC;AAAA,EAClF,CAAC,GAAG;AACF,gBAAY,MAAM,UAAU,IAAI;AAAA,MAC9B,QAAQ;AAAA;AAAA,MACR,MAAM,MAAM;AAAA,MACZ,SAAS,MAAM;AAAA,IACjB;AACA,QAAI,MAAM,WAAY,cAAa,MAAM;AAEzC,QAAI,CAAC,KAAK,iBAAiB,MAAM,cAAc;AAC7C,sBAAgB,MAAM,UAAU,IAAI,MAAM;AAAA,IAC5C;AAAA,EACF;AAEA,QAAM,kBAAkB,OAAO,KAAK,eAAe,EAAE,SAAS;AAC9D,SAAO,KAAK,UAAU;AAAA,IACpB,eAAe;AAAA,IACf,cAAc,IAAI;AAAA,IAClB,eAAc,oBAAI,KAAK,GAAE,YAAY;AAAA,IACrC,cAAc,IAAI,OAAO;AAAA,IACzB;AAAA,IACA,GAAI,kBAAkB,EAAE,eAAe,gBAAgB,IAAI,CAAC;AAAA,IAC5D,GAAI,aAAa,EAAE,WAAW,IAAI,CAAC;AAAA,EACrC,CAAC;AACH;","names":[]}
|