@noy-db/hub 0.5.0 → 0.6.0-pre.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api-67SBPMMH.js +20 -0
- package/dist/attestation/index.js +18 -18
- package/dist/{backup-ENTZYW37.js → backup-GAYWQAFN.js} +16 -11
- package/dist/backup-GAYWQAFN.js.map +1 -0
- package/dist/blobs/index.js +20 -20
- package/dist/broker/index.js +12 -12
- package/dist/bundle-handle-5OUAI7CV.js +36 -0
- package/dist/bundle-handle-5OUAI7CV.js.map +1 -0
- package/dist/cargo/index.js +36 -36
- package/dist/{chunk-V3EGXDFN.js → chunk-24UICKTB.js} +3 -3
- package/dist/{chunk-77AEMXFA.js → chunk-24ZLWWEO.js} +1 -1
- package/dist/chunk-24ZLWWEO.js.map +1 -0
- package/dist/{chunk-6PFST3FC.js → chunk-27TCYH6G.js} +5 -5
- package/dist/{chunk-PTSVGKSR.js → chunk-2KIV7BEK.js} +2 -2
- package/dist/{chunk-3LYMOSY7.js → chunk-2LGDCNFJ.js} +2 -2
- package/dist/{chunk-NWK6SVBM.js → chunk-35EBKWQU.js} +3 -3
- package/dist/{chunk-QMCWYN6O.js → chunk-3737A6EA.js} +3 -3
- package/dist/{chunk-5UKUOMO6.js → chunk-3CLZY46Y.js} +464 -237
- package/dist/chunk-3CLZY46Y.js.map +1 -0
- package/dist/{chunk-G7ZIMGPQ.js → chunk-3EO7RZLJ.js} +6 -6
- package/dist/{chunk-GYJRDALN.js → chunk-3FSX6LDG.js} +2 -2
- package/dist/{chunk-4SG5TOXK.js → chunk-3HYWYLXL.js} +2 -2
- package/dist/{chunk-653KOQ7A.js → chunk-3IIPWA75.js} +11 -11
- package/dist/{chunk-IQ423YMK.js → chunk-3UK6STWO.js} +3 -3
- package/dist/chunk-46V67XP5.js +117 -0
- package/dist/chunk-46V67XP5.js.map +1 -0
- package/dist/{chunk-F5UWVF6Z.js → chunk-4HDYQL3J.js} +2 -2
- package/dist/{chunk-J7YVY7TW.js → chunk-4MQDV3HZ.js} +2 -2
- package/dist/{chunk-UC5Y7OEJ.js → chunk-4UVDI4XE.js} +3 -3
- package/dist/{chunk-4DGBZEV6.js → chunk-4VCWI42L.js} +2 -2
- package/dist/{chunk-GIGLOQL7.js → chunk-747LRSOO.js} +2 -2
- package/dist/{chunk-W7C7MMIS.js → chunk-7F4DBNSP.js} +3 -3
- package/dist/{chunk-5EKL6BXI.js → chunk-7G6VDWXB.js} +3 -3
- package/dist/{chunk-PZRYKOKP.js → chunk-AHLJSVRL.js} +2 -2
- package/dist/{chunk-L67H6FAQ.js → chunk-AR2JDFAE.js} +2 -2
- package/dist/{chunk-TJOUKMWF.js → chunk-BPTZ4K5L.js} +11 -11
- package/dist/{chunk-MFW466PX.js → chunk-CCZJJ4I2.js} +4 -4
- package/dist/{chunk-OKBNFUUX.js → chunk-CJ73OLMW.js} +2 -2
- package/dist/{chunk-FHK6WWUE.js → chunk-CYQOUTMY.js} +3 -3
- package/dist/{chunk-LQVRK2XJ.js → chunk-DCMQR46R.js} +5 -5
- package/dist/{chunk-QTMZDMJ6.js → chunk-DG27IUVI.js} +2 -2
- package/dist/{chunk-XVK7TULT.js → chunk-DMQCLZ4Z.js} +8 -6
- package/dist/chunk-DMQCLZ4Z.js.map +1 -0
- package/dist/{chunk-IHYSIPEK.js → chunk-DPJTDNUF.js} +68 -34
- package/dist/chunk-DPJTDNUF.js.map +1 -0
- package/dist/{chunk-PKBONLCP.js → chunk-E6427JU2.js} +2 -2
- package/dist/{chunk-KDWBVCIX.js → chunk-EK7DT5BT.js} +220 -13
- package/dist/chunk-EK7DT5BT.js.map +1 -0
- package/dist/chunk-EPFF7LOX.js +14 -0
- package/dist/chunk-EPFF7LOX.js.map +1 -0
- package/dist/{chunk-XID22NOA.js → chunk-F3GVO44K.js} +6 -6
- package/dist/{chunk-U2ID5A2I.js → chunk-FAXZQ5UF.js} +2 -2
- package/dist/{chunk-P6UIVLZK.js → chunk-FNSMZQS4.js} +2 -2
- package/dist/{chunk-NIKQQXI2.js → chunk-FUHKW252.js} +2 -2
- package/dist/{chunk-623QEHDB.js → chunk-FY343IZR.js} +8 -8
- package/dist/{chunk-KPZS5QAQ.js → chunk-GQ3BX5EA.js} +9 -1
- package/dist/chunk-GQ3BX5EA.js.map +1 -0
- package/dist/{chunk-7P4LL3JH.js → chunk-GS5RT2KK.js} +4 -4
- package/dist/{chunk-IM2KST7E.js → chunk-HFKGIBMD.js} +3 -3
- package/dist/{chunk-AR5D76T2.js → chunk-HNGSV2YC.js} +129 -1
- package/dist/chunk-HNGSV2YC.js.map +1 -0
- package/dist/chunk-HNHCQ556.js +63 -0
- package/dist/chunk-HNHCQ556.js.map +1 -0
- package/dist/chunk-HS7HNYBD.js +91 -0
- package/dist/chunk-HS7HNYBD.js.map +1 -0
- package/dist/{chunk-FT5Y4VSP.js → chunk-HVQGCKY4.js} +2 -2
- package/dist/{chunk-MYSNNMJ3.js → chunk-HXGUIPQB.js} +3 -3
- package/dist/{chunk-GTQF32TP.js → chunk-JEM2IGS3.js} +9 -9
- package/dist/chunk-JH3OHQM4.js +260 -0
- package/dist/chunk-JH3OHQM4.js.map +1 -0
- package/dist/{chunk-ALUVACKT.js → chunk-JIUVJ4M7.js} +2 -2
- package/dist/{chunk-NJHQE4LT.js → chunk-JRCYZEHU.js} +2 -2
- package/dist/{chunk-G3ORJ3IQ.js → chunk-JSRU5W2M.js} +5 -5
- package/dist/{chunk-SBGXQK5I.js → chunk-JXIDGFKS.js} +2 -2
- package/dist/{chunk-VYYM3MEN.js → chunk-KHKKD62N.js} +16 -2
- package/dist/chunk-KHKKD62N.js.map +1 -0
- package/dist/{chunk-FQ5CHJR7.js → chunk-KUDZVJKQ.js} +21 -2
- package/dist/chunk-KUDZVJKQ.js.map +1 -0
- package/dist/{chunk-MGXUAID4.js → chunk-KZ3KMDN3.js} +2 -2
- package/dist/{chunk-HGDXJVK2.js → chunk-LBGPO5RL.js} +6 -6
- package/dist/{chunk-F2WWHKO7.js → chunk-LTU4FLHG.js} +57 -27
- package/dist/chunk-LTU4FLHG.js.map +1 -0
- package/dist/{chunk-CLE3TMIS.js → chunk-MC2LFTQM.js} +5 -2
- package/dist/{chunk-ECGDJU5R.js → chunk-MJWCLSQL.js} +17 -8
- package/dist/chunk-MJWCLSQL.js.map +1 -0
- package/dist/{chunk-EAN4TAPC.js → chunk-MSWYQLMQ.js} +2 -2
- package/dist/{chunk-WK7ULBTP.js → chunk-MVOWXQHN.js} +5 -3
- package/dist/chunk-MVOWXQHN.js.map +1 -0
- package/dist/{chunk-K5OFKXUG.js → chunk-MXZ5TSTR.js} +118 -4
- package/dist/chunk-MXZ5TSTR.js.map +1 -0
- package/dist/{chunk-OKRXXFZZ.js → chunk-MZ5ZFO2D.js} +3 -3
- package/dist/{chunk-RQILGK3N.js → chunk-NQCNSVGI.js} +5 -5
- package/dist/{chunk-EFJAAFBW.js → chunk-NQRJ5AJO.js} +2 -2
- package/dist/{chunk-Q2SEJMP2.js → chunk-NVU7ZMPN.js} +2 -2
- package/dist/{chunk-Y2PTKKIN.js → chunk-OF3L2SD6.js} +2 -2
- package/dist/{chunk-MDRCEA56.js → chunk-OMSAULZM.js} +11 -11
- package/dist/{chunk-SL3PLML2.js → chunk-OSFPNKY4.js} +3 -3
- package/dist/{chunk-XX7YB5BI.js → chunk-P7NGLLUF.js} +5 -5
- package/dist/{chunk-QITP2JGX.js → chunk-PGAPBZEK.js} +7 -7
- package/dist/{chunk-KJNMTE2W.js → chunk-PP5CO2PR.js} +6 -6
- package/dist/{chunk-FZAP4JNC.js → chunk-RLWY6Z44.js} +227 -41
- package/dist/chunk-RLWY6Z44.js.map +1 -0
- package/dist/{chunk-NG4AQIYJ.js → chunk-ROWL352P.js} +5 -5
- package/dist/{chunk-V4O6YZSP.js → chunk-RPXL6KSX.js} +4 -4
- package/dist/{chunk-ODCEOSJF.js → chunk-SKONR2OL.js} +3 -3
- package/dist/{chunk-RM4FIXY2.js → chunk-SRGJET2F.js} +16 -5
- package/dist/chunk-SRGJET2F.js.map +1 -0
- package/dist/{chunk-QQL6XPPG.js → chunk-T4GPR2IR.js} +2 -2
- package/dist/{chunk-WFYKIDCS.js → chunk-TFZ7LLOQ.js} +88 -30
- package/dist/chunk-TFZ7LLOQ.js.map +1 -0
- package/dist/{chunk-NMYH55MW.js → chunk-TLNNHG3A.js} +4 -4
- package/dist/{chunk-DDB626I7.js → chunk-UHXCLPGC.js} +2 -2
- package/dist/{chunk-Q6MXHDSE.js → chunk-V5C5NNBR.js} +4 -4
- package/dist/{chunk-ELJOLQIG.js → chunk-VBY6ZLJT.js} +7 -7
- package/dist/{chunk-RPWMDIGK.js → chunk-VCETL77O.js} +34 -16
- package/dist/chunk-VCETL77O.js.map +1 -0
- package/dist/{chunk-IJV56FWY.js → chunk-VJFMXYKP.js} +2 -2
- package/dist/{chunk-BFG7LD6Z.js → chunk-VMCCGUQB.js} +2 -2
- package/dist/{chunk-PWEMRXPO.js → chunk-W3TVWF6N.js} +2 -2
- package/dist/{chunk-4TXO442D.js → chunk-WLYIROCJ.js} +2 -2
- package/dist/{chunk-MPW6AHTC.js → chunk-XB7LUDKM.js} +4 -4
- package/dist/{chunk-YA7Y3EZP.js → chunk-XBLKM73C.js} +10 -10
- package/dist/{chunk-LXRVTJ5D.js → chunk-YAWK6AWF.js} +2 -2
- package/dist/{chunk-6RDTG6E5.js → chunk-ZGGVOADG.js} +5 -5
- package/dist/{chunk-JLBCK7XM.js → chunk-ZK4CO2KZ.js} +6 -6
- package/dist/{chunk-DSDXAKIP.js → chunk-ZVF37PKE.js} +34 -5
- package/dist/chunk-ZVF37PKE.js.map +1 -0
- package/dist/{chunk-NZEGQWQ5.js → chunk-ZWMO5GL5.js} +5 -5
- package/dist/{chunk-4MSNAB64.js → chunk-ZXJXDHNK.js} +4 -4
- package/dist/classified/index.js +5 -5
- package/dist/{classified-marker-ZALWKOBC.js → classified-marker-MH3ON5OL.js} +3 -3
- package/dist/collection-facade-AHT7FATG.js +45 -0
- package/dist/{computed-YOQCGUCS.js → computed-6G5M3UPH.js} +3 -3
- package/dist/consent/index.js +9 -9
- package/dist/cover/index.js +3 -3
- package/dist/custody/index.js +11 -11
- package/dist/{dead-filter-6DVWST6U.js → dead-filter-U575NGSH.js} +2 -2
- package/dist/debug/index.js +1 -1
- package/dist/{delegation-WMO3Q3O5.js → delegation-PDYL6RWT.js} +10 -10
- package/dist/derivations/index.js +12 -12
- package/dist/derive-AKT4KU36.js +22 -0
- package/dist/directory/index.js +10 -10
- package/dist/{dispatch-VNR3TLBX.js → dispatch-4XIJSFTT.js} +5 -5
- package/dist/{dispatch-TKV4UCKB.js → dispatch-N5HGVUGU.js} +18 -18
- package/dist/{enclave-YWP3QAIQ.js → enclave-OPK24QDR.js} +13 -9
- package/dist/executor-3JZ4POTW.js +28 -0
- package/dist/executor-CYJQLKKI.js +9 -0
- package/dist/executor-S4QIKEHW.js +9 -0
- package/dist/export-accessible-CPTP5STN.js +23 -0
- package/dist/extract-partition-TWXPHVU7.js +38 -0
- package/dist/{fanout-sidecar-WYXO6QQT.js → fanout-sidecar-T2ZGLQFE.js} +9 -9
- package/dist/find-RBBYKXI7.js +11 -0
- package/dist/forget/index.js +9 -9
- package/dist/guards/index.js +4 -4
- package/dist/history/index.js +15 -15
- package/dist/i18n/index.js +14 -14
- package/dist/index.d.ts +35 -7
- package/dist/index.js +276 -201
- package/dist/index.js.map +1 -1
- package/dist/indexing/index.js +3 -3
- package/dist/introspection/index.js +12 -12
- package/dist/issue-N74C55X6.js +19 -0
- package/dist/kernel/collection.d.ts +10 -2
- package/dist/kernel/cutover-transform.d.ts +64 -0
- package/dist/kernel/enclave/crypto.d.ts +24 -0
- package/dist/kernel/enclave/index.d.ts +2 -1
- package/dist/kernel/errors.d.ts +123 -0
- package/dist/kernel/noydb.d.ts +10 -1
- package/dist/kernel/secret-mode.d.ts +59 -0
- package/dist/kernel/types.d.ts +98 -7
- package/dist/kernel/validation.d.ts +33 -0
- package/dist/kernel/vault.d.ts +18 -6
- package/dist/{ledger-BLYDYRTQ.js → ledger-DONWFC5M.js} +11 -11
- package/dist/liberate-KICI7AJN.js +24 -0
- package/dist/{link-set-7F5ZPDEB.js → link-set-2TTP4VLO.js} +11 -11
- package/dist/managed-secret-EAOYWRYF.js +27 -0
- package/dist/materialized-views/index.js +24 -24
- package/dist/money/index.js +3 -3
- package/dist/noydb-6W2XGQCS.js +83 -0
- package/dist/overlay-views/index.js +6 -6
- package/dist/periods/index.js +16 -16
- package/dist/pod/index.js +121 -12
- package/dist/policy/index.js +4 -4
- package/dist/port/to/index.d.ts +3 -1
- package/dist/port/to/locator.d.ts +84 -0
- package/dist/port/with/device-seal-strategy.d.ts +16 -0
- package/dist/port/with/strategies.d.ts +2 -0
- package/dist/portability/index.js +8 -8
- package/dist/{post-register-PQSY544J.js → post-register-ORQOQJCS.js} +6 -6
- package/dist/query/index.js +4 -4
- package/dist/reduce/index.js +4 -4
- package/dist/register-LHETZRJM.js +32 -0
- package/dist/registry-AMAZ6QRZ.js +19 -0
- package/dist/registry-CZVINVQH.js +9 -0
- package/dist/registry-IKUR2MXD.js +9 -0
- package/dist/registry-JRIN447B.js +18 -0
- package/dist/request-withdrawal-2DN2RGCO.js +31 -0
- package/dist/{reveal-HY7DZST4.js → reveal-AG4SCHUQ.js} +6 -6
- package/dist/revoke-ZX4NM2CJ.js +24 -0
- package/dist/satellites/index.js +1 -1
- package/dist/schema-update/index.js +6 -6
- package/dist/sealed-record/index.js +12 -12
- package/dist/search/index.js +4 -4
- package/dist/{seed-ALU3BHFS.js → seed-IRCDGIRK.js} +11 -11
- package/dist/sequence/index.js +9 -9
- package/dist/session/index.js +9 -9
- package/dist/shadow/index.js +2 -2
- package/dist/signer-7KHD4OL2.js +25 -0
- package/dist/snapshots/index.js +10 -10
- package/dist/{stale-U3WO5MYN.js → stale-K734VACF.js} +10 -10
- package/dist/storage-4H2GF6RQ.js +23 -0
- package/dist/{store-coordination-provider-AHGFEMFA.js → store-coordination-provider-4SKLSFUG.js} +3 -3
- package/dist/sync/index.js +10 -10
- package/dist/team/index.js +27 -15
- package/dist/tiers/index.js +10 -10
- package/dist/to/index.js +28 -3
- package/dist/to/index.js.map +1 -1
- package/dist/transactions/index.js +3 -3
- package/dist/util/index.js +1 -1
- package/dist/{verify-JEIXSK5U.js → verify-RO5RTZOJ.js} +5 -5
- package/dist/walk-MQHYNDLZ.js +21 -0
- package/dist/with-audit/guards/registry.d.ts +8 -1
- package/dist/with-audit/guards/types.d.ts +5 -0
- package/dist/with-audit/periods/index.d.ts +1 -1
- package/dist/with-audit/periods/periods.d.ts +7 -0
- package/dist/with-formula/derivations/registry.d.ts +6 -0
- package/dist/with-formula/derivations/types.d.ts +5 -0
- package/dist/with-lookup/indexing/eager-indexes.d.ts +10 -0
- package/dist/with-party/team/device-seal.d.ts +25 -0
- package/dist/with-party/team/echo-ceremony.d.ts +74 -0
- package/dist/with-party/team/echo-secret.d.ts +56 -0
- package/dist/with-party/team/index.d.ts +8 -0
- package/dist/with-party/team/keyring.d.ts +71 -9
- package/dist/with-party/team/rotate-recover.d.ts +99 -5
- package/dist/with-pod/bundle-handle.d.ts +9 -0
- package/dist/with-pod/bundle.d.ts +100 -2
- package/dist/with-pod/format.d.ts +92 -1
- package/dist/with-pod/index.d.ts +22 -1
- package/dist/with-pod/open.d.ts +117 -0
- package/dist/with-pod/redirect.d.ts +78 -0
- package/dist/with-pod/signature.d.ts +13 -0
- package/dist/with-shape/introspection/behaviors.d.ts +100 -0
- package/dist/with-shape/introspection/derivation-key.d.ts +17 -0
- package/dist/with-shape/introspection/describe.d.ts +36 -0
- package/dist/with-shape/introspection/index.d.ts +1 -0
- package/dist/with-shape/introspection/subsystem-matrix.d.ts +22 -0
- package/dist/with-shape/introspection/types.d.ts +2 -1
- package/dist/with-shape/links/names.d.ts +14 -0
- package/dist/with-shape/manifest/derive.d.ts +86 -0
- package/dist/with-shape/manifest/reserved-collections.d.ts +27 -0
- package/dist/with-shape/manifest/storage.d.ts +62 -0
- package/dist/with-shape/manifest/sync.d.ts +135 -0
- package/dist/with-shape/manifest/types.d.ts +49 -0
- package/dist/with-shape/manifest/writer.d.ts +32 -0
- package/dist/with-shape/persisted-schemas/field-ids.d.ts +29 -0
- package/dist/with-shape/persisted-schemas/register.d.ts +3 -0
- package/dist/with-shape/persisted-schemas/types.d.ts +17 -0
- package/dist/with-shape/schema-update/fence-controller.d.ts +34 -0
- package/dist/with-shape/schema-update/fence.d.ts +9 -0
- package/dist/with-shape/schema-update/strategies.d.ts +18 -2
- package/dist/with-shape/schema-update/types.d.ts +11 -0
- package/dist/with-sync/engine.d.ts +4 -0
- package/dist/with-sync/presence.d.ts +31 -1
- package/dist/withdraw-accessible-JSDQHXHE.js +28 -0
- package/dist/withdraw-accessible-JSDQHXHE.js.map +1 -0
- package/package.json +3 -3
- package/dist/api-M7REIE7H.js +0 -20
- package/dist/backup-ENTZYW37.js.map +0 -1
- package/dist/chunk-5UKUOMO6.js.map +0 -1
- package/dist/chunk-77AEMXFA.js.map +0 -1
- package/dist/chunk-AJAOXFCF.js +0 -129
- package/dist/chunk-AJAOXFCF.js.map +0 -1
- package/dist/chunk-AR5D76T2.js.map +0 -1
- package/dist/chunk-DSDXAKIP.js.map +0 -1
- package/dist/chunk-EBETHILL.js +0 -41
- package/dist/chunk-EBETHILL.js.map +0 -1
- package/dist/chunk-ECGDJU5R.js.map +0 -1
- package/dist/chunk-F2WWHKO7.js.map +0 -1
- package/dist/chunk-FQ5CHJR7.js.map +0 -1
- package/dist/chunk-FUECZSRM.js +0 -23
- package/dist/chunk-FUECZSRM.js.map +0 -1
- package/dist/chunk-FZAP4JNC.js.map +0 -1
- package/dist/chunk-IHYSIPEK.js.map +0 -1
- package/dist/chunk-K5OFKXUG.js.map +0 -1
- package/dist/chunk-KDWBVCIX.js.map +0 -1
- package/dist/chunk-KPZS5QAQ.js.map +0 -1
- package/dist/chunk-RM4FIXY2.js.map +0 -1
- package/dist/chunk-RPWMDIGK.js.map +0 -1
- package/dist/chunk-US2AR4BI.js +0 -25
- package/dist/chunk-US2AR4BI.js.map +0 -1
- package/dist/chunk-VYYM3MEN.js.map +0 -1
- package/dist/chunk-WFYKIDCS.js.map +0 -1
- package/dist/chunk-WK7ULBTP.js.map +0 -1
- package/dist/chunk-XVK7TULT.js.map +0 -1
- package/dist/collection-facade-KI53O6QB.js +0 -45
- package/dist/derive-P2NXWUNB.js +0 -22
- package/dist/executor-M4ZZNX6S.js +0 -28
- package/dist/executor-TI64S4LE.js +0 -9
- package/dist/executor-YBK3I2OT.js +0 -9
- package/dist/export-accessible-GBLYLGW4.js +0 -23
- package/dist/extract-partition-SFV35U2R.js +0 -38
- package/dist/find-HUSSZRBR.js +0 -11
- package/dist/issue-6TIJYWKS.js +0 -19
- package/dist/liberate-TSOW7IG5.js +0 -24
- package/dist/noydb-KFN6M6UJ.js +0 -81
- package/dist/register-S3ECUZPV.js +0 -25
- package/dist/registry-BWD2ED52.js +0 -8
- package/dist/registry-FZOHKUME.js +0 -18
- package/dist/registry-RISV7IDZ.js +0 -19
- package/dist/registry-ZE35A7WC.js +0 -9
- package/dist/request-withdrawal-KXVTQKR5.js +0 -31
- package/dist/revoke-J473JJ22.js +0 -24
- package/dist/signer-XLUKCCH3.js +0 -25
- package/dist/storage-IQONEOYY.js +0 -23
- package/dist/walk-BF36V4SR.js +0 -21
- package/dist/withdraw-accessible-TYTA23XH.js +0 -28
- /package/dist/{api-M7REIE7H.js.map → api-67SBPMMH.js.map} +0 -0
- /package/dist/{chunk-V3EGXDFN.js.map → chunk-24UICKTB.js.map} +0 -0
- /package/dist/{chunk-6PFST3FC.js.map → chunk-27TCYH6G.js.map} +0 -0
- /package/dist/{chunk-PTSVGKSR.js.map → chunk-2KIV7BEK.js.map} +0 -0
- /package/dist/{chunk-3LYMOSY7.js.map → chunk-2LGDCNFJ.js.map} +0 -0
- /package/dist/{chunk-NWK6SVBM.js.map → chunk-35EBKWQU.js.map} +0 -0
- /package/dist/{chunk-QMCWYN6O.js.map → chunk-3737A6EA.js.map} +0 -0
- /package/dist/{chunk-G7ZIMGPQ.js.map → chunk-3EO7RZLJ.js.map} +0 -0
- /package/dist/{chunk-GYJRDALN.js.map → chunk-3FSX6LDG.js.map} +0 -0
- /package/dist/{chunk-4SG5TOXK.js.map → chunk-3HYWYLXL.js.map} +0 -0
- /package/dist/{chunk-653KOQ7A.js.map → chunk-3IIPWA75.js.map} +0 -0
- /package/dist/{chunk-IQ423YMK.js.map → chunk-3UK6STWO.js.map} +0 -0
- /package/dist/{chunk-F5UWVF6Z.js.map → chunk-4HDYQL3J.js.map} +0 -0
- /package/dist/{chunk-J7YVY7TW.js.map → chunk-4MQDV3HZ.js.map} +0 -0
- /package/dist/{chunk-UC5Y7OEJ.js.map → chunk-4UVDI4XE.js.map} +0 -0
- /package/dist/{chunk-4DGBZEV6.js.map → chunk-4VCWI42L.js.map} +0 -0
- /package/dist/{chunk-GIGLOQL7.js.map → chunk-747LRSOO.js.map} +0 -0
- /package/dist/{chunk-W7C7MMIS.js.map → chunk-7F4DBNSP.js.map} +0 -0
- /package/dist/{chunk-5EKL6BXI.js.map → chunk-7G6VDWXB.js.map} +0 -0
- /package/dist/{chunk-PZRYKOKP.js.map → chunk-AHLJSVRL.js.map} +0 -0
- /package/dist/{chunk-L67H6FAQ.js.map → chunk-AR2JDFAE.js.map} +0 -0
- /package/dist/{chunk-TJOUKMWF.js.map → chunk-BPTZ4K5L.js.map} +0 -0
- /package/dist/{chunk-MFW466PX.js.map → chunk-CCZJJ4I2.js.map} +0 -0
- /package/dist/{chunk-OKBNFUUX.js.map → chunk-CJ73OLMW.js.map} +0 -0
- /package/dist/{chunk-FHK6WWUE.js.map → chunk-CYQOUTMY.js.map} +0 -0
- /package/dist/{chunk-LQVRK2XJ.js.map → chunk-DCMQR46R.js.map} +0 -0
- /package/dist/{chunk-QTMZDMJ6.js.map → chunk-DG27IUVI.js.map} +0 -0
- /package/dist/{chunk-PKBONLCP.js.map → chunk-E6427JU2.js.map} +0 -0
- /package/dist/{chunk-XID22NOA.js.map → chunk-F3GVO44K.js.map} +0 -0
- /package/dist/{chunk-U2ID5A2I.js.map → chunk-FAXZQ5UF.js.map} +0 -0
- /package/dist/{chunk-P6UIVLZK.js.map → chunk-FNSMZQS4.js.map} +0 -0
- /package/dist/{chunk-NIKQQXI2.js.map → chunk-FUHKW252.js.map} +0 -0
- /package/dist/{chunk-623QEHDB.js.map → chunk-FY343IZR.js.map} +0 -0
- /package/dist/{chunk-7P4LL3JH.js.map → chunk-GS5RT2KK.js.map} +0 -0
- /package/dist/{chunk-IM2KST7E.js.map → chunk-HFKGIBMD.js.map} +0 -0
- /package/dist/{chunk-FT5Y4VSP.js.map → chunk-HVQGCKY4.js.map} +0 -0
- /package/dist/{chunk-MYSNNMJ3.js.map → chunk-HXGUIPQB.js.map} +0 -0
- /package/dist/{chunk-GTQF32TP.js.map → chunk-JEM2IGS3.js.map} +0 -0
- /package/dist/{chunk-ALUVACKT.js.map → chunk-JIUVJ4M7.js.map} +0 -0
- /package/dist/{chunk-NJHQE4LT.js.map → chunk-JRCYZEHU.js.map} +0 -0
- /package/dist/{chunk-G3ORJ3IQ.js.map → chunk-JSRU5W2M.js.map} +0 -0
- /package/dist/{chunk-SBGXQK5I.js.map → chunk-JXIDGFKS.js.map} +0 -0
- /package/dist/{chunk-MGXUAID4.js.map → chunk-KZ3KMDN3.js.map} +0 -0
- /package/dist/{chunk-HGDXJVK2.js.map → chunk-LBGPO5RL.js.map} +0 -0
- /package/dist/{chunk-CLE3TMIS.js.map → chunk-MC2LFTQM.js.map} +0 -0
- /package/dist/{chunk-EAN4TAPC.js.map → chunk-MSWYQLMQ.js.map} +0 -0
- /package/dist/{chunk-OKRXXFZZ.js.map → chunk-MZ5ZFO2D.js.map} +0 -0
- /package/dist/{chunk-RQILGK3N.js.map → chunk-NQCNSVGI.js.map} +0 -0
- /package/dist/{chunk-EFJAAFBW.js.map → chunk-NQRJ5AJO.js.map} +0 -0
- /package/dist/{chunk-Q2SEJMP2.js.map → chunk-NVU7ZMPN.js.map} +0 -0
- /package/dist/{chunk-Y2PTKKIN.js.map → chunk-OF3L2SD6.js.map} +0 -0
- /package/dist/{chunk-MDRCEA56.js.map → chunk-OMSAULZM.js.map} +0 -0
- /package/dist/{chunk-SL3PLML2.js.map → chunk-OSFPNKY4.js.map} +0 -0
- /package/dist/{chunk-XX7YB5BI.js.map → chunk-P7NGLLUF.js.map} +0 -0
- /package/dist/{chunk-QITP2JGX.js.map → chunk-PGAPBZEK.js.map} +0 -0
- /package/dist/{chunk-KJNMTE2W.js.map → chunk-PP5CO2PR.js.map} +0 -0
- /package/dist/{chunk-NG4AQIYJ.js.map → chunk-ROWL352P.js.map} +0 -0
- /package/dist/{chunk-V4O6YZSP.js.map → chunk-RPXL6KSX.js.map} +0 -0
- /package/dist/{chunk-ODCEOSJF.js.map → chunk-SKONR2OL.js.map} +0 -0
- /package/dist/{chunk-QQL6XPPG.js.map → chunk-T4GPR2IR.js.map} +0 -0
- /package/dist/{chunk-NMYH55MW.js.map → chunk-TLNNHG3A.js.map} +0 -0
- /package/dist/{chunk-DDB626I7.js.map → chunk-UHXCLPGC.js.map} +0 -0
- /package/dist/{chunk-Q6MXHDSE.js.map → chunk-V5C5NNBR.js.map} +0 -0
- /package/dist/{chunk-ELJOLQIG.js.map → chunk-VBY6ZLJT.js.map} +0 -0
- /package/dist/{chunk-IJV56FWY.js.map → chunk-VJFMXYKP.js.map} +0 -0
- /package/dist/{chunk-BFG7LD6Z.js.map → chunk-VMCCGUQB.js.map} +0 -0
- /package/dist/{chunk-PWEMRXPO.js.map → chunk-W3TVWF6N.js.map} +0 -0
- /package/dist/{chunk-4TXO442D.js.map → chunk-WLYIROCJ.js.map} +0 -0
- /package/dist/{chunk-MPW6AHTC.js.map → chunk-XB7LUDKM.js.map} +0 -0
- /package/dist/{chunk-YA7Y3EZP.js.map → chunk-XBLKM73C.js.map} +0 -0
- /package/dist/{chunk-LXRVTJ5D.js.map → chunk-YAWK6AWF.js.map} +0 -0
- /package/dist/{chunk-6RDTG6E5.js.map → chunk-ZGGVOADG.js.map} +0 -0
- /package/dist/{chunk-JLBCK7XM.js.map → chunk-ZK4CO2KZ.js.map} +0 -0
- /package/dist/{chunk-NZEGQWQ5.js.map → chunk-ZWMO5GL5.js.map} +0 -0
- /package/dist/{chunk-4MSNAB64.js.map → chunk-ZXJXDHNK.js.map} +0 -0
- /package/dist/{classified-marker-ZALWKOBC.js.map → classified-marker-MH3ON5OL.js.map} +0 -0
- /package/dist/{collection-facade-KI53O6QB.js.map → collection-facade-AHT7FATG.js.map} +0 -0
- /package/dist/{computed-YOQCGUCS.js.map → computed-6G5M3UPH.js.map} +0 -0
- /package/dist/{dead-filter-6DVWST6U.js.map → dead-filter-U575NGSH.js.map} +0 -0
- /package/dist/{delegation-WMO3Q3O5.js.map → delegation-PDYL6RWT.js.map} +0 -0
- /package/dist/{derive-P2NXWUNB.js.map → derive-AKT4KU36.js.map} +0 -0
- /package/dist/{dispatch-VNR3TLBX.js.map → dispatch-4XIJSFTT.js.map} +0 -0
- /package/dist/{dispatch-TKV4UCKB.js.map → dispatch-N5HGVUGU.js.map} +0 -0
- /package/dist/{enclave-YWP3QAIQ.js.map → enclave-OPK24QDR.js.map} +0 -0
- /package/dist/{executor-M4ZZNX6S.js.map → executor-3JZ4POTW.js.map} +0 -0
- /package/dist/{executor-TI64S4LE.js.map → executor-CYJQLKKI.js.map} +0 -0
- /package/dist/{executor-YBK3I2OT.js.map → executor-S4QIKEHW.js.map} +0 -0
- /package/dist/{export-accessible-GBLYLGW4.js.map → export-accessible-CPTP5STN.js.map} +0 -0
- /package/dist/{extract-partition-SFV35U2R.js.map → extract-partition-TWXPHVU7.js.map} +0 -0
- /package/dist/{fanout-sidecar-WYXO6QQT.js.map → fanout-sidecar-T2ZGLQFE.js.map} +0 -0
- /package/dist/{find-HUSSZRBR.js.map → find-RBBYKXI7.js.map} +0 -0
- /package/dist/{issue-6TIJYWKS.js.map → issue-N74C55X6.js.map} +0 -0
- /package/dist/{ledger-BLYDYRTQ.js.map → ledger-DONWFC5M.js.map} +0 -0
- /package/dist/{liberate-TSOW7IG5.js.map → liberate-KICI7AJN.js.map} +0 -0
- /package/dist/{link-set-7F5ZPDEB.js.map → link-set-2TTP4VLO.js.map} +0 -0
- /package/dist/{noydb-KFN6M6UJ.js.map → managed-secret-EAOYWRYF.js.map} +0 -0
- /package/dist/{register-S3ECUZPV.js.map → noydb-6W2XGQCS.js.map} +0 -0
- /package/dist/{post-register-PQSY544J.js.map → post-register-ORQOQJCS.js.map} +0 -0
- /package/dist/{registry-BWD2ED52.js.map → register-LHETZRJM.js.map} +0 -0
- /package/dist/{registry-FZOHKUME.js.map → registry-AMAZ6QRZ.js.map} +0 -0
- /package/dist/{registry-RISV7IDZ.js.map → registry-CZVINVQH.js.map} +0 -0
- /package/dist/{registry-ZE35A7WC.js.map → registry-IKUR2MXD.js.map} +0 -0
- /package/dist/{request-withdrawal-KXVTQKR5.js.map → registry-JRIN447B.js.map} +0 -0
- /package/dist/{revoke-J473JJ22.js.map → request-withdrawal-2DN2RGCO.js.map} +0 -0
- /package/dist/{reveal-HY7DZST4.js.map → reveal-AG4SCHUQ.js.map} +0 -0
- /package/dist/{signer-XLUKCCH3.js.map → revoke-ZX4NM2CJ.js.map} +0 -0
- /package/dist/{seed-ALU3BHFS.js.map → seed-IRCDGIRK.js.map} +0 -0
- /package/dist/{stale-U3WO5MYN.js.map → signer-7KHD4OL2.js.map} +0 -0
- /package/dist/{storage-IQONEOYY.js.map → stale-K734VACF.js.map} +0 -0
- /package/dist/{walk-BF36V4SR.js.map → storage-4H2GF6RQ.js.map} +0 -0
- /package/dist/{store-coordination-provider-AHGFEMFA.js.map → store-coordination-provider-4SKLSFUG.js.map} +0 -0
- /package/dist/{verify-JEIXSK5U.js.map → verify-RO5RTZOJ.js.map} +0 -0
- /package/dist/{withdraw-accessible-TYTA23XH.js.map → walk-MQHYNDLZ.js.map} +0 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keep the persisted `_manifest/schema` record in sync with the
|
|
3
|
+
* per-collection `_schemas/<collection>` source of truth (#941 Task 3).
|
|
4
|
+
*
|
|
5
|
+
* Called from `persisted-schemas/register.ts`'s `persistSchemaIfNeeded`
|
|
6
|
+
* right after a `_schemas/<collection>` write succeeds.
|
|
7
|
+
*
|
|
8
|
+
* ## Reconciling strict-CAS-refuse with the derived nature of the manifest
|
|
9
|
+
*
|
|
10
|
+
* `writer.ts`'s `writeSchemaManifest` is deliberately strict-CAS: a
|
|
11
|
+
* concurrent *direct* edit to the manifest is refused, never retried (AC
|
|
12
|
+
* #1). But this call site is not a direct edit — it is a re-derivation
|
|
13
|
+
* from the source of truth, triggered as a side effect of a `_schemas`
|
|
14
|
+
* write that has ALREADY succeeded. When N collections are declared
|
|
15
|
+
* together (one `openVault()` call registering several `persistJsonSchema:
|
|
16
|
+
* true` collections), their `persistSchemaIfNeeded` calls run CONCURRENTLY
|
|
17
|
+
* — each one's own `_schemas/<collection>` write lands independently, and
|
|
18
|
+
* each then calls this function. A single derive-then-write with no
|
|
19
|
+
* feedback loop is NOT enough here: a call whose `deriveSchemaManifest`
|
|
20
|
+
* snapshot ran before a sibling's `_schemas` write landed would persist a
|
|
21
|
+
* manifest that's missing that sibling forever (nothing re-triggers it) —
|
|
22
|
+
* this was a REAL bug (not a test-isolation artifact — reproduced with 0
|
|
23
|
+
* shared state, purely from concurrent `_schemas` writes racing the derive
|
|
24
|
+
* snapshot; see #941 flake fix commit). `syncSchemaManifest` therefore
|
|
25
|
+
* loops (bounded by {@link MAX_SYNC_ATTEMPTS}):
|
|
26
|
+
*
|
|
27
|
+
* 1. Derive fresh, compare to what's persisted. Already converged → done.
|
|
28
|
+
* 2. Write via strict-CAS. `ManifestConflictError` (another writer moved
|
|
29
|
+
* the manifest first) → loop: re-derive against the NEW state and
|
|
30
|
+
* retry, exactly like a normal optimistic-CAS retry.
|
|
31
|
+
* 3. On a successful write, derive ONE more time. If a sibling's
|
|
32
|
+
* `_schemas` write landed while we were deriving/writing, the state
|
|
33
|
+
* has already moved past what we just wrote — loop again to catch it
|
|
34
|
+
* up. If the re-derive matches what we wrote, we're the last writer
|
|
35
|
+
* and the manifest is provably converged: return.
|
|
36
|
+
*
|
|
37
|
+
* This guarantees that whichever collection's `_schemas` write is the LAST
|
|
38
|
+
* to land (in real wall-clock order — there is always exactly one, even
|
|
39
|
+
* though no single caller knows which) ends up running a sync whose own
|
|
40
|
+
* derive sees every sibling's write already committed, and whose
|
|
41
|
+
* recheck-after-write confirms nothing moved further — so it converges the
|
|
42
|
+
* manifest deterministically, regardless of interleaving. If attempts are
|
|
43
|
+
* exhausted under pathological contention, the loop gives up — with a
|
|
44
|
+
* `console.warn` (see cap-exhaustion note below), not silently — leaving
|
|
45
|
+
* the last successful write in place; the manifest is a derivable cache
|
|
46
|
+
* (not a correctness invariant), so a next schema write or `open()`'s
|
|
47
|
+
* re-derive still converges it, matching how `persistSchemaIfNeeded`
|
|
48
|
+
* already treats its own write failures.
|
|
49
|
+
* Any error OTHER than `ManifestConflictError` (store failure, DEK
|
|
50
|
+
* resolution failure, etc.) is NOT swallowed — it propagates to the
|
|
51
|
+
* caller immediately, matching how `persistSchemaIfNeeded` already treats
|
|
52
|
+
* its own write failures as a visible (not silently discarded) fingerprint
|
|
53
|
+
* failure.
|
|
54
|
+
*
|
|
55
|
+
* ## CRITICAL fix (#941 review): a scoped principal must never write a
|
|
56
|
+
* partial manifest
|
|
57
|
+
*
|
|
58
|
+
* `deriveSchemaManifest` returns `undecodableCollections` for any
|
|
59
|
+
* `_schemas/<collection>` entry this principal's `lookupDEK` couldn't
|
|
60
|
+
* resolve — e.g. a member `grant()`-scoped to one collection can decrypt
|
|
61
|
+
* `_manifest` itself (system-prefixed DEKs propagate to every role) but
|
|
62
|
+
* NOT a sibling data collection's `_schemas/<sibling>` entry. Before this
|
|
63
|
+
* fix, `deriveSchemaManifest` silently treated "can't decrypt" the same as
|
|
64
|
+
* "no derivable content" and omitted the sibling — so a scoped member's
|
|
65
|
+
* OWN schema declare would derive a manifest missing every collection they
|
|
66
|
+
* can't see, load the real (complete) persisted manifest as a valid CAS
|
|
67
|
+
* token, observe a hash mismatch, and OVERWRITE it — permanently dropping
|
|
68
|
+
* the siblings, silently, ledger-audited as a legitimate migration. The
|
|
69
|
+
* converging recheck loop above made this WORSE, not better: re-deriving
|
|
70
|
+
* from the same restricted view just re-confirms the same partial result
|
|
71
|
+
* and declares it "stable."
|
|
72
|
+
*
|
|
73
|
+
* Fix: if `undecodableCollections` is non-empty, `syncSchemaManifest`
|
|
74
|
+
* `SKIP`s entirely — no read-compare, no write, no audit, no loop. It does
|
|
75
|
+
* NOT try to merge-preserve the undecodable entries from what's currently
|
|
76
|
+
* persisted: an `aggregateHash` computed over entries this principal can't
|
|
77
|
+
* verify would be a hash asserting something it never actually checked,
|
|
78
|
+
* which is worse than not writing at all. This is safe because:
|
|
79
|
+
*
|
|
80
|
+
* - The source of truth, `_schemas/<their-collection>`, was ALREADY
|
|
81
|
+
* updated by their declare — nothing about their own change is lost.
|
|
82
|
+
* - The pod-wide `_manifest` cache simply isn't rewritten by a principal
|
|
83
|
+
* who'd corrupt it by omission — it stays whatever a full-visibility
|
|
84
|
+
* principal (owner/admin/custodian) last wrote.
|
|
85
|
+
* - `open()` re-derives from `_schemas` directly (not from the cached
|
|
86
|
+
* manifest) for whoever opens it, so a stale cache is never load-bearing.
|
|
87
|
+
* - The NEXT full-visibility principal's declare (or any subsequent sync
|
|
88
|
+
* by someone with complete access) naturally refreshes the cache,
|
|
89
|
+
* including the scoped member's own just-landed change.
|
|
90
|
+
*
|
|
91
|
+
* ## Ledger audit (AC #5)
|
|
92
|
+
*
|
|
93
|
+
* Schema-generation transitions are not ledger-audited anywhere else today
|
|
94
|
+
* (neither the `_schemas/<collection>` write in `register.ts` nor the fence
|
|
95
|
+
* bump in `schema-update/fence-controller.ts#runCutover`). This is the
|
|
96
|
+
* first ledger-audited signal for a schema change: every manifest write
|
|
97
|
+
* that actually happens (i.e. every time the derived manifest differs from
|
|
98
|
+
* what's stored) appends an `op: 'migration'` entry via the optional
|
|
99
|
+
* `getLedgerOrNull` callback — `null`/absent when the history strategy
|
|
100
|
+
* isn't opted in, matching every other optional-ledger call site
|
|
101
|
+
* (`vault._getLedgerOrNull()?.append(...)`, see `liberate.ts`,
|
|
102
|
+
* `with-audit/periods/vault-facade.ts`). No audit fires on the no-op path
|
|
103
|
+
* (derived manifest unchanged), on a swallowed conflict (the winning
|
|
104
|
+
* writer's own sync already audits its write), or on the scoped-principal
|
|
105
|
+
* SKIP path above (nothing was written).
|
|
106
|
+
*
|
|
107
|
+
* @module
|
|
108
|
+
*/
|
|
109
|
+
import type { LedgerStore } from '../../with-commit/history/ledger/store.js';
|
|
110
|
+
import type { NoydbStore } from '../../kernel/types.js';
|
|
111
|
+
import { type LookupDEK } from './derive.js';
|
|
112
|
+
import { type GetManifestDEK } from './storage.js';
|
|
113
|
+
export interface ManifestSyncDeps {
|
|
114
|
+
/** Resolver for `_manifest`'s OWN DEK — mints if absent (this principal's declare is about to write it). */
|
|
115
|
+
readonly getDEK: GetManifestDEK;
|
|
116
|
+
/**
|
|
117
|
+
* NON-MINTING lookup for every OTHER (sibling data) collection's DEK,
|
|
118
|
+
* used by `deriveSchemaManifest` to build the index — see `derive.ts`'s
|
|
119
|
+
* `LookupDEK` doc for why minting here would be actively harmful.
|
|
120
|
+
*/
|
|
121
|
+
readonly lookupDEK: LookupDEK;
|
|
122
|
+
/** Optional ledger handle — absent when the history strategy isn't opted in (no-op audit). */
|
|
123
|
+
readonly getLedgerOrNull?: () => LedgerStore | null;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Re-derive the schema manifest and write it if it changed, looping until
|
|
127
|
+
* the write is provably stable against concurrent sibling `_schemas`
|
|
128
|
+
* writes (see module doc). SKIPS entirely (no write, no audit) when this
|
|
129
|
+
* principal's view is incomplete (`undecodableCollections` non-empty) —
|
|
130
|
+
* see the module doc's CRITICAL fix section. Swallows a
|
|
131
|
+
* {@link ManifestConflictError} by retrying against the fresher state; any
|
|
132
|
+
* other error propagates. Ledger-audits (`op: 'migration'`) once per
|
|
133
|
+
* successful write.
|
|
134
|
+
*/
|
|
135
|
+
export declare function syncSchemaManifest(store: NoydbStore, vault: string, deps: ManifestSyncDeps): Promise<void>;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The pod-wide **schema manifest** record type (#941).
|
|
3
|
+
*
|
|
4
|
+
* This is an INDEX, not a full-inline manifest: `SchemaManifest.collections`
|
|
5
|
+
* carries per-collection *metadata* (generation / content hash / field ids),
|
|
6
|
+
* never the JSON Schema body itself. The JSON Schema stays the source of
|
|
7
|
+
* truth at `_schemas/<collection>`, encrypted under that collection's own
|
|
8
|
+
* DEK (see `with-shape/persisted-schemas`). Inlining full schemas into one
|
|
9
|
+
* pod-wide manifest record would either leak every collection's schema to a
|
|
10
|
+
* principal scoped to a single collection, or force the manifest itself
|
|
11
|
+
* onto a collection-DEK it has no business holding — the index preserves
|
|
12
|
+
* per-collection DEK isolation while still giving a single place to answer
|
|
13
|
+
* "what schema generation is this pod at, and does collection X's stored
|
|
14
|
+
* schema match its declared content hash."
|
|
15
|
+
*
|
|
16
|
+
* `aggregateHash` binds the whole per-collection index's content: it is
|
|
17
|
+
* `sha256Hex(canonicalJson(collections))`, so any change to any collection's
|
|
18
|
+
* entry (a new generation, a changed hash, added/renamed field ids) changes
|
|
19
|
+
* `aggregateHash` too. Canonical JSON (sorted object keys, no whitespace)
|
|
20
|
+
* makes the hash independent of the map's key insertion order.
|
|
21
|
+
*
|
|
22
|
+
* @module
|
|
23
|
+
*/
|
|
24
|
+
/** Per-collection entry inside a {@link SchemaManifest}'s `collections` index. */
|
|
25
|
+
export interface SchemaManifestEntry {
|
|
26
|
+
/** The vault-wide schema-fence generation this collection's schema was last written at. */
|
|
27
|
+
readonly generation: number;
|
|
28
|
+
/** SHA-256 (hex) of the collection's canonicalised JSON Schema (see `persisted-schemas/derive.ts`). */
|
|
29
|
+
readonly contentHash: string;
|
|
30
|
+
/** Stable per-field ids (#946), keyed by the field's current name. Absent when the collection has none. */
|
|
31
|
+
readonly fieldIds?: Record<string, string>;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The pod-wide schema manifest — one record per pod, stored at
|
|
35
|
+
* `_manifest/schema` (see `storage.ts`). An INDEX over the per-collection
|
|
36
|
+
* `_schemas/<collection>` entries, not the schemas themselves.
|
|
37
|
+
*/
|
|
38
|
+
export interface SchemaManifest {
|
|
39
|
+
readonly v: 1;
|
|
40
|
+
readonly kind: 'schema';
|
|
41
|
+
/** Pod-wide schema-fence generation (`FenceDoc.currentSchemaVersion`) as of this manifest's derivation. */
|
|
42
|
+
readonly generation: number;
|
|
43
|
+
/** Per-collection index: collection name → its manifest entry. */
|
|
44
|
+
readonly collections: Record<string, SchemaManifestEntry>;
|
|
45
|
+
/** `sha256Hex(canonicalJson(collections))` — the pod-wide content binding over the index. */
|
|
46
|
+
readonly aggregateHash: string;
|
|
47
|
+
}
|
|
48
|
+
/** The record id the schema manifest is stored under inside `_manifest`. */
|
|
49
|
+
export declare const MANIFEST_SCHEMA_RECORD_ID: "schema";
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Strict-CAS schema-manifest writer (#941, AC #1).
|
|
3
|
+
*
|
|
4
|
+
* Every other reserved-collection writer in the hub (`persisted-schemas`'s
|
|
5
|
+
* `savePersistedSchema` callers, the classified/satellite marker writers)
|
|
6
|
+
* retries on a CAS conflict: re-read, re-apply, try again. The schema
|
|
7
|
+
* manifest deliberately does NOT — two concurrent *direct* edits to the
|
|
8
|
+
* manifest must be refused and surfaced, never silently merged or
|
|
9
|
+
* retry-resolved, because a manifest write encodes a specific point-in-time
|
|
10
|
+
* claim about the pod's schema generation/content-hash set. A caller that
|
|
11
|
+
* lost the race must re-derive against the fresh state and decide what to
|
|
12
|
+
* do, not have its stale write quietly re-applied on top of someone else's.
|
|
13
|
+
*
|
|
14
|
+
* Ledger audit: this writer does not have a `LedgerStore` handle at this
|
|
15
|
+
* seam (mirroring `persisted-schemas`, whose `_schemas/<collection>` writes
|
|
16
|
+
* are likewise not ledger-audited today). Wiring `LedgerStore.append({ op:
|
|
17
|
+
* 'migration', ... })` around a manifest write belongs at the call site
|
|
18
|
+
* where a ledger handle is already in scope (the open/write integration —
|
|
19
|
+
* #941 Task 3/4), not here.
|
|
20
|
+
*
|
|
21
|
+
* @module
|
|
22
|
+
*/
|
|
23
|
+
import { type GetManifestDEK } from './storage.js';
|
|
24
|
+
import type { NoydbStore } from '../../kernel/types.js';
|
|
25
|
+
import type { SchemaManifest } from './types.js';
|
|
26
|
+
/**
|
|
27
|
+
* Write the schema manifest as a strict CAS: `expectedVersion` must match
|
|
28
|
+
* the stored envelope's `_v` (0 when no manifest exists yet). On a
|
|
29
|
+
* conflict, throws {@link ManifestConflictError} — this function never
|
|
30
|
+
* retries.
|
|
31
|
+
*/
|
|
32
|
+
export declare function writeSchemaManifest(store: NoydbStore, vault: string, manifest: SchemaManifest, expectedVersion: number, getDEK: GetManifestDEK): Promise<void>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stable field-identifier minting (#946).
|
|
3
|
+
*
|
|
4
|
+
* A field's `id` is opaque and permanent — minted once, from randomness
|
|
5
|
+
* only, with no timestamp and no name-derivation. A name-derived id would
|
|
6
|
+
* change when the field is renamed, defeating the whole point (identity
|
|
7
|
+
* must survive a rename). See `PersistedSchemaEnvelope.fieldIds`.
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Resolve the `fieldIds` map for a freshly-derived schema against the
|
|
13
|
+
* previously-stored envelope's map (if any). Existing ids are preserved by
|
|
14
|
+
* name — a field keeps its id across re-derivation as long as its name is
|
|
15
|
+
* unchanged; a genuinely new field name mints a fresh id. Returns
|
|
16
|
+
* `undefined` when the fresh schema has no derivable top-level field set
|
|
17
|
+
* (e.g. a stub envelope, or a non-object root schema).
|
|
18
|
+
*
|
|
19
|
+
* `renamed` (#946 Task 2) — unambiguous rename pairs from
|
|
20
|
+
* `computeSchemaDelta`'s `SchemaDelta.renamed`. When the fresh name is a
|
|
21
|
+
* rename target (`to`), the id is looked up under its OLD name (`from`)
|
|
22
|
+
* instead of the fresh name itself — the whole point of a stable field id
|
|
23
|
+
* is that it survives exactly this case; without it, a rename would mint a
|
|
24
|
+
* fresh id for the new name and silently drop the old one.
|
|
25
|
+
*/
|
|
26
|
+
export declare function resolveFieldIds(freshJsonSchema: object | null, priorFieldIds: Record<string, string> | undefined, renamed?: readonly {
|
|
27
|
+
readonly from: string;
|
|
28
|
+
readonly to: string;
|
|
29
|
+
}[]): Record<string, string> | undefined;
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
*
|
|
14
14
|
* @module
|
|
15
15
|
*/
|
|
16
|
+
import { type ManifestSyncDeps } from '../manifest/sync.js';
|
|
16
17
|
import type { SchemaUpdateStrategy, UpdateDecision } from '../schema-update/types.js';
|
|
17
18
|
import type { NoydbStore, ClassifiedMarker } from '../../kernel/types.js';
|
|
18
19
|
import type { PersistedSchemaEnvelope } from './types.js';
|
|
@@ -35,6 +36,8 @@ export declare function persistSchemaIfNeeded(opts: {
|
|
|
35
36
|
readonly validator: unknown;
|
|
36
37
|
readonly dek: EnclaveKey;
|
|
37
38
|
readonly strategies?: readonly SchemaUpdateStrategy[];
|
|
39
|
+
/** #941 Task 3: re-derive + sync the `_manifest/schema` INDEX after a write. Omitted → no sync (e.g. tests that don't care). */
|
|
40
|
+
readonly manifestSync?: ManifestSyncDeps;
|
|
38
41
|
}): Promise<PersistSchemaResult>;
|
|
39
42
|
/**
|
|
40
43
|
* Persist (or refresh) the C-A / R10 classified marker into the collection's
|
|
@@ -51,4 +51,21 @@ export interface PersistedSchemaEnvelope {
|
|
|
51
51
|
* the satellite-pair analogue of {@link classified}'s config-drift guard.
|
|
52
52
|
*/
|
|
53
53
|
readonly satellite?: PairingMarker;
|
|
54
|
+
/**
|
|
55
|
+
* Stable per-field identifiers (#946), keyed by the field's current name
|
|
56
|
+
* (top-level JSON Schema `properties` key) and mapping to an opaque,
|
|
57
|
+
* permanent id minted once via `mintFieldId()`. IDs are preserved by name
|
|
58
|
+
* across re-derivation (a field keeps its id as long as its name is
|
|
59
|
+
* unchanged) so a field's identity survives a rename — the name is a
|
|
60
|
+
* label, the id is the stable key. Absent on a legacy (pre-#946) envelope
|
|
61
|
+
* and on a stub envelope with no derivable field set (`jsonSchema === null`).
|
|
62
|
+
*/
|
|
63
|
+
readonly fieldIds?: Record<string, string>;
|
|
64
|
+
/**
|
|
65
|
+
* The vault-wide schema-fence generation (`FenceDoc.currentSchemaVersion`)
|
|
66
|
+
* as of this envelope's most recent write. Together with
|
|
67
|
+
* `FenceDoc.schemaHash`, answers "generation N = which schema content
|
|
68
|
+
* hash" (#946). Absent on a legacy (pre-#946) envelope.
|
|
69
|
+
*/
|
|
70
|
+
readonly generation?: number;
|
|
54
71
|
}
|
|
@@ -17,6 +17,37 @@ import type { TransformFn } from './types.js';
|
|
|
17
17
|
import { type CoordinationProvider } from '../../port/by/index.js';
|
|
18
18
|
/** Runs one collection's transform; supplied by the Vault (binds to a Collection). */
|
|
19
19
|
export type RunTransform = (collection: string, transform: TransformFn) => Promise<void>;
|
|
20
|
+
/** Structural (no static import — kernel-spine port-layering carve-out, same rationale as
|
|
21
|
+
* `kernel/via/dispatch.ts`'s `AuditLedgerLike`) shape of the with-history `LedgerStore.append`
|
|
22
|
+
* seam {@link schemaBumpAuditHook} needs. */
|
|
23
|
+
interface AuditLedgerLike {
|
|
24
|
+
append(input: {
|
|
25
|
+
readonly op: 'lifecycle';
|
|
26
|
+
readonly collection: string;
|
|
27
|
+
readonly id: string;
|
|
28
|
+
readonly version: number;
|
|
29
|
+
readonly actor: string;
|
|
30
|
+
readonly payloadHash: string;
|
|
31
|
+
readonly reason?: string;
|
|
32
|
+
}): Promise<unknown>;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* #965 — a bare `runCutover` generation bump (no re-declare, no per-record
|
|
36
|
+
* migrations) otherwise leaves zero ledger evidence: per-record `migration`
|
|
37
|
+
* entries only fire from `applyCutoverTransform` when records + a transform
|
|
38
|
+
* exist. Mirrors `ledgerAuditHook` (`kernel/via/dispatch.ts`): encoded as a
|
|
39
|
+
* `'lifecycle'` entry (no ciphertext to hash, `payloadHash: ''`), distinct
|
|
40
|
+
* from the per-record `op: 'migration'` entries via its
|
|
41
|
+
* `reason: 'schema:generation-bump=<n>'`. Fires once per successful bump,
|
|
42
|
+
* always — even when the same cutover also produced per-record entries —
|
|
43
|
+
* so "one bump entry per generation bump" stays a simple, unconditional
|
|
44
|
+
* invariant to audit against.
|
|
45
|
+
*
|
|
46
|
+
* `getLedger` is called lazily (at bump time, not at wiring time) — same
|
|
47
|
+
* lazy-init contract as `Vault.getLedgerOrNull`; calling it eagerly during
|
|
48
|
+
* `Vault` construction (before `this.strategies` is assigned) would throw.
|
|
49
|
+
*/
|
|
50
|
+
export declare function schemaBumpAuditHook(getLedger: () => AuditLedgerLike | null, actor: string): (generation: number) => Promise<void>;
|
|
20
51
|
export declare class SchemaFenceController {
|
|
21
52
|
#private;
|
|
22
53
|
constructor(opts: {
|
|
@@ -38,6 +69,8 @@ export declare class SchemaFenceController {
|
|
|
38
69
|
currentSchemaVersion: number;
|
|
39
70
|
fenceState: FenceState;
|
|
40
71
|
}) => void;
|
|
72
|
+
/** #965 — best-effort ledger audit for a bare (no-record) generation bump. See {@link schemaBumpAuditHook}. */
|
|
73
|
+
auditBump?: ((generation: number) => Promise<void>) | undefined;
|
|
41
74
|
});
|
|
42
75
|
/** Capture the generation snapshot at vault-open. */
|
|
43
76
|
init(): Promise<void>;
|
|
@@ -60,3 +93,4 @@ export declare class SchemaFenceController {
|
|
|
60
93
|
/** Recover a stuck drain: reset fenceState to normal at the current version (no bump). */
|
|
61
94
|
abort(): Promise<void>;
|
|
62
95
|
}
|
|
96
|
+
export {};
|
|
@@ -8,6 +8,15 @@ export type FenceState = 'normal' | 'draining' | 'migrating' | 'complete';
|
|
|
8
8
|
export interface FenceDoc {
|
|
9
9
|
readonly currentSchemaVersion: number;
|
|
10
10
|
readonly fenceState: FenceState;
|
|
11
|
+
/**
|
|
12
|
+
* Content hash (`PersistedSchemaEnvelope.hash`) of the schema most
|
|
13
|
+
* recently persisted while the vault sat at `currentSchemaVersion` —
|
|
14
|
+
* binds "generation N" to a concrete schema-content hash (#946), so
|
|
15
|
+
* "which schema is generation N" is answerable from `schemaFenceState()`
|
|
16
|
+
* alone. Optional: absent on a fresh vault (generation 0, nothing
|
|
17
|
+
* persisted yet) and on a fence document written before #946.
|
|
18
|
+
*/
|
|
19
|
+
readonly schemaHash?: string;
|
|
11
20
|
}
|
|
12
21
|
export declare const FENCE_RECORD_ID = "schema-fence";
|
|
13
22
|
export declare const DEFAULT_FENCE: FenceDoc;
|
|
@@ -1,11 +1,27 @@
|
|
|
1
1
|
import type { SchemaUpdateStrategy } from './types.js';
|
|
2
2
|
/** Allow any schema change. Explicit blind / back-compat. */
|
|
3
3
|
export declare function blindUpdate(): SchemaUpdateStrategy;
|
|
4
|
-
/**
|
|
4
|
+
/**
|
|
5
|
+
* Allow additive changes; reject non-additive ones. The safety backstop.
|
|
6
|
+
*
|
|
7
|
+
* #946: a `renamed` pair is NOT additive-safe *for this gate* — the delta
|
|
8
|
+
* itself carries no data migration, so an allowed rename would orphan
|
|
9
|
+
* existing record values under the old key. `computeSchemaDelta` classifies
|
|
10
|
+
* a pure rename as `kind: 'additive'` (it IS additive-safe as far as the
|
|
11
|
+
* name-change itself is concerned, and the id-carry through `SchemaDelta.
|
|
12
|
+
* renamed` is real), but a guard whose whole job is "don't admit anything
|
|
13
|
+
* that isn't a mechanical additive write" must still block it — the same as
|
|
14
|
+
* it blocks any other non-additive change — forcing a `coordinatedCutover()`
|
|
15
|
+
* (or `blindUpdate()`) to actually move the data.
|
|
16
|
+
*/
|
|
5
17
|
export declare function additiveOnly(): SchemaUpdateStrategy;
|
|
6
18
|
/**
|
|
7
19
|
* Reject schema changes. With `fields`, reject only when one of those
|
|
8
|
-
* fields is added/removed/changed; otherwise reject any non-`none`
|
|
20
|
+
* fields is added/removed/changed/renamed; otherwise reject any non-`none`
|
|
21
|
+
* delta. #946: a `renamed` pair's `from` AND `to` both count as touching a
|
|
22
|
+
* locked field — a rename away from a locked name (or onto one) still
|
|
23
|
+
* violates the lock, and a blanket `lockSchema()` (no `fields`) already
|
|
24
|
+
* blocks any rename since a pure rename's `kind` is never `'none'`.
|
|
9
25
|
*/
|
|
10
26
|
export declare function lockSchema(opts?: {
|
|
11
27
|
readonly fields?: readonly string[];
|
|
@@ -23,6 +23,17 @@ export interface SchemaDelta {
|
|
|
23
23
|
readonly removed: readonly string[];
|
|
24
24
|
/** Top-level properties present in both but altered. */
|
|
25
25
|
readonly changed: readonly FieldChange[];
|
|
26
|
+
/**
|
|
27
|
+
* Unambiguous rename pairs detected by shape-matching a removed name
|
|
28
|
+
* against an added name (#946) — same field, new label. Present only
|
|
29
|
+
* when at least one pairing was found; the paired names are excluded
|
|
30
|
+
* from `added`/`removed` (a pure rename is additive-safe, not a
|
|
31
|
+
* drop+add). See `computeSchemaDelta`'s doc comment for the pairing rule.
|
|
32
|
+
*/
|
|
33
|
+
readonly renamed?: readonly {
|
|
34
|
+
readonly from: string;
|
|
35
|
+
readonly to: string;
|
|
36
|
+
}[];
|
|
26
37
|
}
|
|
27
38
|
/** Context handed to a strategy alongside the delta. */
|
|
28
39
|
export interface UpdateContext {
|
|
@@ -19,6 +19,10 @@ export declare class SyncEngine {
|
|
|
19
19
|
private readonly vault;
|
|
20
20
|
readonly role: SyncTargetRole;
|
|
21
21
|
readonly label: string | undefined;
|
|
22
|
+
/** #948: the resolved policy this engine was constructed with, retained for
|
|
23
|
+
* introspection (`Noydb.listSyncTargets()`) — otherwise lost once consumed
|
|
24
|
+
* into the scheduler below. */
|
|
25
|
+
readonly policy: SyncPolicy | undefined;
|
|
22
26
|
private dirty;
|
|
23
27
|
private lastPush;
|
|
24
28
|
private lastPull;
|
|
@@ -26,7 +26,14 @@ export interface PresenceHandleOpts {
|
|
|
26
26
|
vault: string;
|
|
27
27
|
/** Collection name — used as HKDF `info` and channel suffix. */
|
|
28
28
|
collectionName: string;
|
|
29
|
-
/**
|
|
29
|
+
/**
|
|
30
|
+
* Calling user's ID. In encrypted mode it is encrypted inside the
|
|
31
|
+
* storage-poll record's `data` field — the record id is an
|
|
32
|
+
* adapter-opaque HMAC tag, not the userId, so the adapter never learns
|
|
33
|
+
* peer identities. Unencrypted vaults have no key to tag or encrypt
|
|
34
|
+
* with, so the userId is used as the record id in cleartext (dev posture
|
|
35
|
+
* only — identity privacy requires encryption).
|
|
36
|
+
*/
|
|
30
37
|
userId: string;
|
|
31
38
|
/** Whether encryption is active. When false, presence payloads are stored as JSON. */
|
|
32
39
|
encrypted: boolean;
|
|
@@ -51,6 +58,7 @@ export declare class PresenceHandle<P> {
|
|
|
51
58
|
private readonly channel;
|
|
52
59
|
private readonly storageCollection;
|
|
53
60
|
private presenceKey;
|
|
61
|
+
private presenceTagKey;
|
|
54
62
|
private subscribers;
|
|
55
63
|
private unsubscribePubSub;
|
|
56
64
|
private pollTimer;
|
|
@@ -71,6 +79,28 @@ export declare class PresenceHandle<P> {
|
|
|
71
79
|
/** Stop all listening and clear resources. */
|
|
72
80
|
stop(): void;
|
|
73
81
|
private getPresenceKey;
|
|
82
|
+
/**
|
|
83
|
+
* Derive (and cache) the presence-tag key — a non-extractable, sign-only
|
|
84
|
+
* HMAC-SHA256 key HKDF-derived from the collection DEK, domain-separated
|
|
85
|
+
* from the presence payload key by {@link PRESENCE_TAG_KEY_DOMAIN}.
|
|
86
|
+
* Mirrors `deriveClassifyIndexKey` (kernel/enclave/classify/bidx.ts). No
|
|
87
|
+
* PBKDF2 stretch — the adapter never holds this key, so a plain keyed HMAC
|
|
88
|
+
* tag is sufficient and deterministic. Returns `null` when unencrypted
|
|
89
|
+
* (no DEK to derive from).
|
|
90
|
+
*/
|
|
91
|
+
private getPresenceTagKey;
|
|
92
|
+
/**
|
|
93
|
+
* Deterministic, adapter-opaque tag for `userId` — used as the
|
|
94
|
+
* storage-poll record id in encrypted mode so the adapter never sees the
|
|
95
|
+
* userId. Falls back to the raw `userId` when unencrypted (no key exists
|
|
96
|
+
* to tag with — see {@link PresenceHandleOpts.userId}).
|
|
97
|
+
*
|
|
98
|
+
* Signs directly via `subtle.sign` (like `bidx.ts`'s `mintAt`) rather than
|
|
99
|
+
* the barrel's `hmacSha256Hex` helper: that helper re-exports its key
|
|
100
|
+
* argument's raw bytes internally, which only works for extractable keys
|
|
101
|
+
* (e.g. an AES-GCM DEK) — `presenceTagKey` is deliberately non-extractable.
|
|
102
|
+
*/
|
|
103
|
+
private presenceTag;
|
|
74
104
|
private getPubSubAdapter;
|
|
75
105
|
private startListening;
|
|
76
106
|
private stopListening;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FROZEN_SNAPSHOTS_COLLECTION,
|
|
3
|
+
freezeAndDeleteClosure,
|
|
4
|
+
freezeSnapshotOnly,
|
|
5
|
+
randomId,
|
|
6
|
+
withdrawAccessibleData
|
|
7
|
+
} from "./chunk-JSRU5W2M.js";
|
|
8
|
+
import "./chunk-4MQDV3HZ.js";
|
|
9
|
+
import "./chunk-EK7DT5BT.js";
|
|
10
|
+
import "./chunk-CYQOUTMY.js";
|
|
11
|
+
import "./chunk-FY343IZR.js";
|
|
12
|
+
import "./chunk-NQRJ5AJO.js";
|
|
13
|
+
import "./chunk-HXGUIPQB.js";
|
|
14
|
+
import "./chunk-AR2JDFAE.js";
|
|
15
|
+
import "./chunk-747LRSOO.js";
|
|
16
|
+
import "./chunk-LP7BEXCT.js";
|
|
17
|
+
import "./chunk-VCETL77O.js";
|
|
18
|
+
import "./chunk-24ZLWWEO.js";
|
|
19
|
+
import "./chunk-HNGSV2YC.js";
|
|
20
|
+
import "./chunk-PZ5AY32C.js";
|
|
21
|
+
export {
|
|
22
|
+
FROZEN_SNAPSHOTS_COLLECTION,
|
|
23
|
+
freezeAndDeleteClosure,
|
|
24
|
+
freezeSnapshotOnly,
|
|
25
|
+
randomId,
|
|
26
|
+
withdrawAccessibleData
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=withdraw-accessible-JSDQHXHE.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.6.0-pre.0",
|
|
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": "MIT",
|
|
6
6
|
"author": "vLannaAi <vicio@lanna.ai>",
|
|
@@ -208,14 +208,14 @@
|
|
|
208
208
|
"node": ">=22.0.0"
|
|
209
209
|
},
|
|
210
210
|
"dependencies": {
|
|
211
|
-
"@noy-db/attestation": "0.
|
|
211
|
+
"@noy-db/attestation": "0.6.0-pre.0"
|
|
212
212
|
},
|
|
213
213
|
"devDependencies": {
|
|
214
214
|
"@types/node": "^22.0.0",
|
|
215
215
|
"esbuild": "^0.25.0",
|
|
216
216
|
"zod": "^4.0.0",
|
|
217
217
|
"zod-to-json-schema": "^3.25.2",
|
|
218
|
-
"@noy-db/on-shamir": "0.
|
|
218
|
+
"@noy-db/on-shamir": "0.6.0-pre.0"
|
|
219
219
|
},
|
|
220
220
|
"peerDependencies": {
|
|
221
221
|
"zod-to-json-schema": "^3.25.0"
|
package/dist/api-M7REIE7H.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
UserApi,
|
|
3
|
-
createUserApi
|
|
4
|
-
} from "./chunk-SL3PLML2.js";
|
|
5
|
-
import "./chunk-6PFST3FC.js";
|
|
6
|
-
import "./chunk-623QEHDB.js";
|
|
7
|
-
import "./chunk-EFJAAFBW.js";
|
|
8
|
-
import "./chunk-MYSNNMJ3.js";
|
|
9
|
-
import "./chunk-L67H6FAQ.js";
|
|
10
|
-
import "./chunk-GIGLOQL7.js";
|
|
11
|
-
import "./chunk-LP7BEXCT.js";
|
|
12
|
-
import "./chunk-RPWMDIGK.js";
|
|
13
|
-
import "./chunk-77AEMXFA.js";
|
|
14
|
-
import "./chunk-AR5D76T2.js";
|
|
15
|
-
import "./chunk-PZ5AY32C.js";
|
|
16
|
-
export {
|
|
17
|
-
UserApi,
|
|
18
|
-
createUserApi
|
|
19
|
-
};
|
|
20
|
-
//# sourceMappingURL=api-M7REIE7H.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 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'\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 '_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 = {\n _noydb: 1 as const,\n _v: 1,\n _ts: new Date().toISOString(),\n _iv: '',\n _data: JSON.stringify(keyringFile),\n }\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. Legacy backups (no ledgerHead)\n // skip this with a one-line warning so existing consumers can\n // still read them while migrating.\n if (!backup.ledgerHead) {\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 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":"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","names":[]}
|