@noy-db/hub 0.4.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-X7F3TCFV.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-DQZXPGGZ.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-2BET5QTS.js → chunk-27TCYH6G.js} +5 -5
- package/dist/{chunk-MSMJJB4J.js → chunk-2KIV7BEK.js} +2 -2
- package/dist/{chunk-6ZNSB3H6.js → chunk-2LGDCNFJ.js} +2 -2
- package/dist/{chunk-GTYFIVIZ.js → chunk-35EBKWQU.js} +5 -5
- package/dist/chunk-35EBKWQU.js.map +1 -0
- package/dist/{chunk-WBKZUO5V.js → chunk-3737A6EA.js} +3 -3
- package/dist/{chunk-ZBYFMI6D.js → chunk-3CLZY46Y.js} +638 -300
- package/dist/chunk-3CLZY46Y.js.map +1 -0
- package/dist/{chunk-HLKXPJ4V.js → chunk-3EO7RZLJ.js} +6 -6
- package/dist/{chunk-JYJFGD2H.js → chunk-3FSX6LDG.js} +2 -2
- package/dist/{chunk-MXUT7FTE.js → chunk-3HYWYLXL.js} +2 -2
- package/dist/{chunk-IVYQAVWO.js → chunk-3IIPWA75.js} +11 -11
- package/dist/{chunk-7H3WWH6J.js → chunk-3UK6STWO.js} +3 -3
- package/dist/chunk-46V67XP5.js +117 -0
- package/dist/chunk-46V67XP5.js.map +1 -0
- package/dist/{chunk-NJ4DYYO5.js → chunk-4HDYQL3J.js} +2 -2
- package/dist/{chunk-P4JO3H6R.js → chunk-4MQDV3HZ.js} +2 -2
- package/dist/{chunk-X4MVWPHV.js → chunk-4UVDI4XE.js} +3 -3
- package/dist/{chunk-LXRTP3AQ.js → chunk-4VCWI42L.js} +2 -2
- package/dist/{chunk-QJNCB5SK.js → chunk-747LRSOO.js} +2 -2
- package/dist/{chunk-3HUYRN24.js → chunk-7F4DBNSP.js} +3 -3
- package/dist/{chunk-UADPR6F4.js → chunk-7G6VDWXB.js} +3 -3
- package/dist/{chunk-PTHKZWEH.js → chunk-AHLJSVRL.js} +2 -2
- package/dist/{chunk-NFZGZ4AK.js → chunk-AR2JDFAE.js} +2 -2
- package/dist/{chunk-3ECU57YH.js → chunk-BPTZ4K5L.js} +11 -11
- package/dist/{chunk-KRCBZYTZ.js → chunk-CCZJJ4I2.js} +4 -4
- package/dist/{chunk-NYEFP7DY.js → chunk-CJ73OLMW.js} +2 -2
- package/dist/{chunk-Q36YXK77.js → chunk-CYQOUTMY.js} +3 -3
- package/dist/{chunk-RBTVFPHF.js → chunk-DCMQR46R.js} +5 -5
- package/dist/{chunk-TG634KCO.js → chunk-DG27IUVI.js} +2 -2
- package/dist/{chunk-E23UGFVC.js → chunk-DMQCLZ4Z.js} +8 -6
- package/dist/chunk-DMQCLZ4Z.js.map +1 -0
- package/dist/{chunk-ZNWSG7XC.js → chunk-DPJTDNUF.js} +68 -34
- package/dist/chunk-DPJTDNUF.js.map +1 -0
- package/dist/{chunk-V6UQZA2H.js → chunk-E6427JU2.js} +2 -2
- package/dist/{chunk-JEI6JJNI.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-TWPK7KUJ.js → chunk-F3GVO44K.js} +6 -6
- package/dist/{chunk-QD46HPZG.js → chunk-FAXZQ5UF.js} +2 -2
- package/dist/{chunk-IG6KUWBX.js → chunk-FNSMZQS4.js} +2 -2
- package/dist/{chunk-BLBAQRBM.js → chunk-FUHKW252.js} +2 -2
- package/dist/{chunk-SU6SGWXM.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-DAFBJS4Y.js → chunk-GS5RT2KK.js} +4 -4
- package/dist/{chunk-5UQ7Y6SQ.js → chunk-HFKGIBMD.js} +3 -3
- package/dist/{chunk-QZWTRENR.js → chunk-HNGSV2YC.js} +133 -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-SHEEBRZ4.js → chunk-HVQGCKY4.js} +2 -2
- package/dist/{chunk-35NMVJ7I.js → chunk-HXGUIPQB.js} +3 -3
- package/dist/{chunk-ERGECZEI.js → chunk-JEM2IGS3.js} +9 -9
- package/dist/chunk-JH3OHQM4.js +260 -0
- package/dist/chunk-JH3OHQM4.js.map +1 -0
- package/dist/{chunk-L3YYLT4E.js → chunk-JIUVJ4M7.js} +2 -2
- package/dist/{chunk-55LX6FSX.js → chunk-JRCYZEHU.js} +2 -2
- package/dist/{chunk-SFBYQMZM.js → chunk-JSRU5W2M.js} +5 -5
- package/dist/{chunk-NM5UYF6Q.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-RO5NM6UI.js → chunk-KZ3KMDN3.js} +2 -2
- package/dist/{chunk-HZZP2ZIG.js → chunk-LBGPO5RL.js} +6 -6
- package/dist/{chunk-ZFG5EBI3.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-467SWYT5.js → chunk-MJWCLSQL.js} +17 -8
- package/dist/chunk-MJWCLSQL.js.map +1 -0
- package/dist/{chunk-W3G5REIU.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-2J6UEN2V.js → chunk-MXZ5TSTR.js} +118 -4
- package/dist/chunk-MXZ5TSTR.js.map +1 -0
- package/dist/{chunk-SGDPRCC4.js → chunk-MZ5ZFO2D.js} +3 -3
- package/dist/{chunk-NBXFCQX4.js → chunk-NQCNSVGI.js} +9 -9
- package/dist/chunk-NQCNSVGI.js.map +1 -0
- package/dist/{chunk-EFJAAFBW.js → chunk-NQRJ5AJO.js} +2 -2
- package/dist/{chunk-Q2SEJMP2.js → chunk-NVU7ZMPN.js} +2 -2
- package/dist/{chunk-ZTLOXFPB.js → chunk-OF3L2SD6.js} +2 -2
- package/dist/{chunk-LLYIMSQQ.js → chunk-OMSAULZM.js} +11 -11
- package/dist/{chunk-SF2ZIRD6.js → chunk-OSFPNKY4.js} +3 -3
- package/dist/{chunk-WUHEP3HH.js → chunk-P7NGLLUF.js} +5 -5
- package/dist/{chunk-RQ4ZI4ZI.js → chunk-PGAPBZEK.js} +7 -7
- package/dist/{chunk-T2MOJF76.js → chunk-PP5CO2PR.js} +6 -6
- package/dist/{chunk-Q5YJCVJY.js → chunk-RLWY6Z44.js} +227 -41
- package/dist/chunk-RLWY6Z44.js.map +1 -0
- package/dist/{chunk-QGIBI6GL.js → chunk-ROWL352P.js} +5 -5
- package/dist/{chunk-ZHDSUZQU.js → chunk-RPXL6KSX.js} +4 -4
- package/dist/{chunk-DTFA5DO4.js → chunk-SKONR2OL.js} +3 -3
- package/dist/{chunk-AT2JJEKJ.js → chunk-SRGJET2F.js} +16 -5
- package/dist/chunk-SRGJET2F.js.map +1 -0
- package/dist/{chunk-4ZKNC6A6.js → chunk-T4GPR2IR.js} +2 -2
- package/dist/{chunk-NLYALJMY.js → chunk-TFZ7LLOQ.js} +113 -36
- package/dist/chunk-TFZ7LLOQ.js.map +1 -0
- package/dist/{chunk-TS5XLBZR.js → chunk-TLNNHG3A.js} +4 -4
- package/dist/{chunk-6UBZ6I5Z.js → chunk-UHXCLPGC.js} +2 -2
- package/dist/{chunk-KD4HGBJV.js → chunk-V5C5NNBR.js} +4 -4
- package/dist/{chunk-WYUAEZSC.js → chunk-VBY6ZLJT.js} +15 -14
- package/dist/chunk-VBY6ZLJT.js.map +1 -0
- package/dist/{chunk-AKKRXT23.js → chunk-VCETL77O.js} +34 -16
- package/dist/chunk-VCETL77O.js.map +1 -0
- package/dist/{chunk-5GQEU4DN.js → chunk-VJFMXYKP.js} +2 -2
- package/dist/{chunk-5DRROK5W.js → chunk-VMCCGUQB.js} +2 -2
- package/dist/{chunk-IXNCZTWA.js → chunk-W3TVWF6N.js} +2 -2
- package/dist/{chunk-W66AM5IB.js → chunk-WLYIROCJ.js} +2 -2
- package/dist/{chunk-OWHP3H5C.js → chunk-XB7LUDKM.js} +4 -4
- package/dist/{chunk-KYRDJI5O.js → chunk-XBLKM73C.js} +10 -10
- package/dist/{chunk-MHMLXJ3I.js → chunk-YAWK6AWF.js} +2 -2
- package/dist/{chunk-PWPYO73B.js → chunk-ZGGVOADG.js} +5 -5
- package/dist/{chunk-YGK2HMLR.js → chunk-ZK4CO2KZ.js} +9 -9
- package/dist/chunk-ZK4CO2KZ.js.map +1 -0
- package/dist/{chunk-DSDXAKIP.js → chunk-ZVF37PKE.js} +34 -5
- package/dist/chunk-ZVF37PKE.js.map +1 -0
- package/dist/{chunk-IFOH7RBI.js → chunk-ZWMO5GL5.js} +5 -5
- package/dist/{chunk-LRRX57UA.js → chunk-ZXJXDHNK.js} +4 -4
- package/dist/classified/index.js +5 -5
- package/dist/{classified-marker-LE54HWSX.js → classified-marker-MH3ON5OL.js} +3 -3
- package/dist/collection-facade-AHT7FATG.js +45 -0
- package/dist/{computed-AB45PS4V.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-V3LVWYEJ.js → dead-filter-U575NGSH.js} +2 -2
- package/dist/debug/index.js +1 -1
- package/dist/{delegation-JDUMAF6L.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-6TV3DGO6.js → dispatch-4XIJSFTT.js} +5 -5
- package/dist/{dispatch-W7NWQ637.js → dispatch-N5HGVUGU.js} +18 -18
- package/dist/{enclave-YFCLPIDR.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-273RDMYS.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 +6 -6
- 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 +279 -202
- 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-config.d.ts +4 -0
- package/dist/kernel/collection.d.ts +34 -8
- 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 +138 -0
- package/dist/kernel/noydb.d.ts +10 -1
- package/dist/kernel/put-many-atomic.d.ts +45 -0
- 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 +32 -6
- package/dist/{ledger-XE7JF2I2.js → ledger-DONWFC5M.js} +11 -11
- package/dist/liberate-KICI7AJN.js +24 -0
- package/dist/{link-set-CGYC3OH5.js → link-set-2TTP4VLO.js} +11 -11
- package/dist/managed-secret-EAOYWRYF.js +27 -0
- package/dist/materialized-views/index.js +19 -19
- 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/port/with/write-hooks.d.ts +6 -0
- package/dist/portability/index.js +8 -8
- package/dist/{post-register-LY35EDTJ.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-T34ADTPY.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-JOV54PB3.js → seed-IRCDGIRK.js} +15 -15
- package/dist/seed-IRCDGIRK.js.map +1 -0
- 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-T3V7XEOB.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-7XWHJWUN.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-commit/tx/atomic-eligibility.d.ts +13 -11
- 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 +17 -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-SI2IVBQO.js +0 -20
- package/dist/backup-X7F3TCFV.js.map +0 -1
- package/dist/chunk-2J6UEN2V.js.map +0 -1
- package/dist/chunk-467SWYT5.js.map +0 -1
- package/dist/chunk-4JQK3L4V.js +0 -41
- package/dist/chunk-4JQK3L4V.js.map +0 -1
- package/dist/chunk-77AEMXFA.js.map +0 -1
- package/dist/chunk-AKKRXT23.js.map +0 -1
- package/dist/chunk-AT2JJEKJ.js.map +0 -1
- package/dist/chunk-DSDXAKIP.js.map +0 -1
- package/dist/chunk-E23UGFVC.js.map +0 -1
- package/dist/chunk-FQ5CHJR7.js.map +0 -1
- package/dist/chunk-GTYFIVIZ.js.map +0 -1
- package/dist/chunk-JEI6JJNI.js.map +0 -1
- package/dist/chunk-JQ2AX4T5.js +0 -23
- package/dist/chunk-JQ2AX4T5.js.map +0 -1
- package/dist/chunk-KPZS5QAQ.js.map +0 -1
- package/dist/chunk-NBXFCQX4.js.map +0 -1
- package/dist/chunk-NLYALJMY.js.map +0 -1
- package/dist/chunk-Q5YJCVJY.js.map +0 -1
- package/dist/chunk-QZWTRENR.js.map +0 -1
- package/dist/chunk-S7GIXBXV.js +0 -129
- package/dist/chunk-S7GIXBXV.js.map +0 -1
- package/dist/chunk-SBHN6QUT.js +0 -25
- package/dist/chunk-SBHN6QUT.js.map +0 -1
- package/dist/chunk-VYYM3MEN.js.map +0 -1
- package/dist/chunk-WK7ULBTP.js.map +0 -1
- package/dist/chunk-WYUAEZSC.js.map +0 -1
- package/dist/chunk-YGK2HMLR.js.map +0 -1
- package/dist/chunk-ZBYFMI6D.js.map +0 -1
- package/dist/chunk-ZFG5EBI3.js.map +0 -1
- package/dist/chunk-ZNWSG7XC.js.map +0 -1
- package/dist/collection-facade-DO2AABZT.js +0 -45
- package/dist/derive-ZPGVLE2Q.js +0 -22
- package/dist/executor-FPHKWDWT.js +0 -28
- package/dist/executor-IEBLTBCW.js +0 -9
- package/dist/executor-RM7XWQDU.js +0 -9
- package/dist/export-accessible-EKM3HGB2.js +0 -23
- package/dist/extract-partition-LS4ET5A6.js +0 -38
- package/dist/find-OZMTRIK3.js +0 -11
- package/dist/issue-LIA7FXBJ.js +0 -19
- package/dist/liberate-WZ3RHVKW.js +0 -24
- package/dist/noydb-ZLPVCDES.js +0 -81
- package/dist/register-6RIBIT3I.js +0 -25
- package/dist/registry-7Y5WF7GS.js +0 -9
- package/dist/registry-BWD2ED52.js +0 -8
- package/dist/registry-MUSL4AW6.js +0 -19
- package/dist/registry-RON4WHAP.js +0 -18
- package/dist/request-withdrawal-FT3ORAWN.js +0 -31
- package/dist/revoke-HC7WG3HE.js +0 -24
- package/dist/seed-JOV54PB3.js.map +0 -1
- package/dist/signer-CTWOH6KT.js +0 -25
- package/dist/storage-LLNLPWWB.js +0 -23
- package/dist/walk-G3NFEP5L.js +0 -21
- package/dist/withdraw-accessible-ANSVG6XG.js +0 -28
- /package/dist/{api-SI2IVBQO.js.map → api-67SBPMMH.js.map} +0 -0
- /package/dist/{chunk-DQZXPGGZ.js.map → chunk-24UICKTB.js.map} +0 -0
- /package/dist/{chunk-2BET5QTS.js.map → chunk-27TCYH6G.js.map} +0 -0
- /package/dist/{chunk-MSMJJB4J.js.map → chunk-2KIV7BEK.js.map} +0 -0
- /package/dist/{chunk-6ZNSB3H6.js.map → chunk-2LGDCNFJ.js.map} +0 -0
- /package/dist/{chunk-WBKZUO5V.js.map → chunk-3737A6EA.js.map} +0 -0
- /package/dist/{chunk-HLKXPJ4V.js.map → chunk-3EO7RZLJ.js.map} +0 -0
- /package/dist/{chunk-JYJFGD2H.js.map → chunk-3FSX6LDG.js.map} +0 -0
- /package/dist/{chunk-MXUT7FTE.js.map → chunk-3HYWYLXL.js.map} +0 -0
- /package/dist/{chunk-IVYQAVWO.js.map → chunk-3IIPWA75.js.map} +0 -0
- /package/dist/{chunk-7H3WWH6J.js.map → chunk-3UK6STWO.js.map} +0 -0
- /package/dist/{chunk-NJ4DYYO5.js.map → chunk-4HDYQL3J.js.map} +0 -0
- /package/dist/{chunk-P4JO3H6R.js.map → chunk-4MQDV3HZ.js.map} +0 -0
- /package/dist/{chunk-X4MVWPHV.js.map → chunk-4UVDI4XE.js.map} +0 -0
- /package/dist/{chunk-LXRTP3AQ.js.map → chunk-4VCWI42L.js.map} +0 -0
- /package/dist/{chunk-QJNCB5SK.js.map → chunk-747LRSOO.js.map} +0 -0
- /package/dist/{chunk-3HUYRN24.js.map → chunk-7F4DBNSP.js.map} +0 -0
- /package/dist/{chunk-UADPR6F4.js.map → chunk-7G6VDWXB.js.map} +0 -0
- /package/dist/{chunk-PTHKZWEH.js.map → chunk-AHLJSVRL.js.map} +0 -0
- /package/dist/{chunk-NFZGZ4AK.js.map → chunk-AR2JDFAE.js.map} +0 -0
- /package/dist/{chunk-3ECU57YH.js.map → chunk-BPTZ4K5L.js.map} +0 -0
- /package/dist/{chunk-KRCBZYTZ.js.map → chunk-CCZJJ4I2.js.map} +0 -0
- /package/dist/{chunk-NYEFP7DY.js.map → chunk-CJ73OLMW.js.map} +0 -0
- /package/dist/{chunk-Q36YXK77.js.map → chunk-CYQOUTMY.js.map} +0 -0
- /package/dist/{chunk-RBTVFPHF.js.map → chunk-DCMQR46R.js.map} +0 -0
- /package/dist/{chunk-TG634KCO.js.map → chunk-DG27IUVI.js.map} +0 -0
- /package/dist/{chunk-V6UQZA2H.js.map → chunk-E6427JU2.js.map} +0 -0
- /package/dist/{chunk-TWPK7KUJ.js.map → chunk-F3GVO44K.js.map} +0 -0
- /package/dist/{chunk-QD46HPZG.js.map → chunk-FAXZQ5UF.js.map} +0 -0
- /package/dist/{chunk-IG6KUWBX.js.map → chunk-FNSMZQS4.js.map} +0 -0
- /package/dist/{chunk-BLBAQRBM.js.map → chunk-FUHKW252.js.map} +0 -0
- /package/dist/{chunk-SU6SGWXM.js.map → chunk-FY343IZR.js.map} +0 -0
- /package/dist/{chunk-DAFBJS4Y.js.map → chunk-GS5RT2KK.js.map} +0 -0
- /package/dist/{chunk-5UQ7Y6SQ.js.map → chunk-HFKGIBMD.js.map} +0 -0
- /package/dist/{chunk-SHEEBRZ4.js.map → chunk-HVQGCKY4.js.map} +0 -0
- /package/dist/{chunk-35NMVJ7I.js.map → chunk-HXGUIPQB.js.map} +0 -0
- /package/dist/{chunk-ERGECZEI.js.map → chunk-JEM2IGS3.js.map} +0 -0
- /package/dist/{chunk-L3YYLT4E.js.map → chunk-JIUVJ4M7.js.map} +0 -0
- /package/dist/{chunk-55LX6FSX.js.map → chunk-JRCYZEHU.js.map} +0 -0
- /package/dist/{chunk-SFBYQMZM.js.map → chunk-JSRU5W2M.js.map} +0 -0
- /package/dist/{chunk-NM5UYF6Q.js.map → chunk-JXIDGFKS.js.map} +0 -0
- /package/dist/{chunk-RO5NM6UI.js.map → chunk-KZ3KMDN3.js.map} +0 -0
- /package/dist/{chunk-HZZP2ZIG.js.map → chunk-LBGPO5RL.js.map} +0 -0
- /package/dist/{chunk-CLE3TMIS.js.map → chunk-MC2LFTQM.js.map} +0 -0
- /package/dist/{chunk-W3G5REIU.js.map → chunk-MSWYQLMQ.js.map} +0 -0
- /package/dist/{chunk-SGDPRCC4.js.map → chunk-MZ5ZFO2D.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-ZTLOXFPB.js.map → chunk-OF3L2SD6.js.map} +0 -0
- /package/dist/{chunk-LLYIMSQQ.js.map → chunk-OMSAULZM.js.map} +0 -0
- /package/dist/{chunk-SF2ZIRD6.js.map → chunk-OSFPNKY4.js.map} +0 -0
- /package/dist/{chunk-WUHEP3HH.js.map → chunk-P7NGLLUF.js.map} +0 -0
- /package/dist/{chunk-RQ4ZI4ZI.js.map → chunk-PGAPBZEK.js.map} +0 -0
- /package/dist/{chunk-T2MOJF76.js.map → chunk-PP5CO2PR.js.map} +0 -0
- /package/dist/{chunk-QGIBI6GL.js.map → chunk-ROWL352P.js.map} +0 -0
- /package/dist/{chunk-ZHDSUZQU.js.map → chunk-RPXL6KSX.js.map} +0 -0
- /package/dist/{chunk-DTFA5DO4.js.map → chunk-SKONR2OL.js.map} +0 -0
- /package/dist/{chunk-4ZKNC6A6.js.map → chunk-T4GPR2IR.js.map} +0 -0
- /package/dist/{chunk-TS5XLBZR.js.map → chunk-TLNNHG3A.js.map} +0 -0
- /package/dist/{chunk-6UBZ6I5Z.js.map → chunk-UHXCLPGC.js.map} +0 -0
- /package/dist/{chunk-KD4HGBJV.js.map → chunk-V5C5NNBR.js.map} +0 -0
- /package/dist/{chunk-5GQEU4DN.js.map → chunk-VJFMXYKP.js.map} +0 -0
- /package/dist/{chunk-5DRROK5W.js.map → chunk-VMCCGUQB.js.map} +0 -0
- /package/dist/{chunk-IXNCZTWA.js.map → chunk-W3TVWF6N.js.map} +0 -0
- /package/dist/{chunk-W66AM5IB.js.map → chunk-WLYIROCJ.js.map} +0 -0
- /package/dist/{chunk-OWHP3H5C.js.map → chunk-XB7LUDKM.js.map} +0 -0
- /package/dist/{chunk-KYRDJI5O.js.map → chunk-XBLKM73C.js.map} +0 -0
- /package/dist/{chunk-MHMLXJ3I.js.map → chunk-YAWK6AWF.js.map} +0 -0
- /package/dist/{chunk-PWPYO73B.js.map → chunk-ZGGVOADG.js.map} +0 -0
- /package/dist/{chunk-IFOH7RBI.js.map → chunk-ZWMO5GL5.js.map} +0 -0
- /package/dist/{chunk-LRRX57UA.js.map → chunk-ZXJXDHNK.js.map} +0 -0
- /package/dist/{classified-marker-LE54HWSX.js.map → classified-marker-MH3ON5OL.js.map} +0 -0
- /package/dist/{collection-facade-DO2AABZT.js.map → collection-facade-AHT7FATG.js.map} +0 -0
- /package/dist/{computed-AB45PS4V.js.map → computed-6G5M3UPH.js.map} +0 -0
- /package/dist/{dead-filter-V3LVWYEJ.js.map → dead-filter-U575NGSH.js.map} +0 -0
- /package/dist/{delegation-JDUMAF6L.js.map → delegation-PDYL6RWT.js.map} +0 -0
- /package/dist/{derive-ZPGVLE2Q.js.map → derive-AKT4KU36.js.map} +0 -0
- /package/dist/{dispatch-6TV3DGO6.js.map → dispatch-4XIJSFTT.js.map} +0 -0
- /package/dist/{dispatch-W7NWQ637.js.map → dispatch-N5HGVUGU.js.map} +0 -0
- /package/dist/{enclave-YFCLPIDR.js.map → enclave-OPK24QDR.js.map} +0 -0
- /package/dist/{executor-FPHKWDWT.js.map → executor-3JZ4POTW.js.map} +0 -0
- /package/dist/{executor-IEBLTBCW.js.map → executor-CYJQLKKI.js.map} +0 -0
- /package/dist/{executor-RM7XWQDU.js.map → executor-S4QIKEHW.js.map} +0 -0
- /package/dist/{export-accessible-EKM3HGB2.js.map → export-accessible-CPTP5STN.js.map} +0 -0
- /package/dist/{extract-partition-LS4ET5A6.js.map → extract-partition-TWXPHVU7.js.map} +0 -0
- /package/dist/{fanout-sidecar-273RDMYS.js.map → fanout-sidecar-T2ZGLQFE.js.map} +0 -0
- /package/dist/{find-OZMTRIK3.js.map → find-RBBYKXI7.js.map} +0 -0
- /package/dist/{issue-LIA7FXBJ.js.map → issue-N74C55X6.js.map} +0 -0
- /package/dist/{ledger-XE7JF2I2.js.map → ledger-DONWFC5M.js.map} +0 -0
- /package/dist/{liberate-WZ3RHVKW.js.map → liberate-KICI7AJN.js.map} +0 -0
- /package/dist/{link-set-CGYC3OH5.js.map → link-set-2TTP4VLO.js.map} +0 -0
- /package/dist/{noydb-ZLPVCDES.js.map → managed-secret-EAOYWRYF.js.map} +0 -0
- /package/dist/{register-6RIBIT3I.js.map → noydb-6W2XGQCS.js.map} +0 -0
- /package/dist/{post-register-LY35EDTJ.js.map → post-register-ORQOQJCS.js.map} +0 -0
- /package/dist/{registry-7Y5WF7GS.js.map → register-LHETZRJM.js.map} +0 -0
- /package/dist/{registry-BWD2ED52.js.map → registry-AMAZ6QRZ.js.map} +0 -0
- /package/dist/{registry-MUSL4AW6.js.map → registry-CZVINVQH.js.map} +0 -0
- /package/dist/{registry-RON4WHAP.js.map → registry-IKUR2MXD.js.map} +0 -0
- /package/dist/{request-withdrawal-FT3ORAWN.js.map → registry-JRIN447B.js.map} +0 -0
- /package/dist/{revoke-HC7WG3HE.js.map → request-withdrawal-2DN2RGCO.js.map} +0 -0
- /package/dist/{reveal-T34ADTPY.js.map → reveal-AG4SCHUQ.js.map} +0 -0
- /package/dist/{signer-CTWOH6KT.js.map → revoke-ZX4NM2CJ.js.map} +0 -0
- /package/dist/{stale-T3V7XEOB.js.map → signer-7KHD4OL2.js.map} +0 -0
- /package/dist/{storage-LLNLPWWB.js.map → stale-K734VACF.js.map} +0 -0
- /package/dist/{walk-G3NFEP5L.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-7XWHJWUN.js.map → verify-RO5RTZOJ.js.map} +0 -0
- /package/dist/{withdraw-accessible-ANSVG6XG.js.map → walk-MQHYNDLZ.js.map} +0 -0
|
@@ -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":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/with-pod/pod-store.ts"],"sourcesContent":["import type { NoydbStore, NoydbPodStore, VaultSnapshot, EncryptedEnvelope } from '../kernel/types.js'\nimport { ConflictError, PodVersionConflictError } from '../kernel/errors.js'\n\n// ─── Bundle format ─────────────────────────────────────────────────────\n\nconst BUNDLE_STORE_VERSION = 1 as const\n\n/**\n * Wire format written by `wrapPodStore`. A JSON-serialised object that\n * contains the entire `VaultSnapshot` (all encrypted envelopes) plus a small\n * header for integrity checking. The envelopes inside are already AES-GCM\n * encrypted by core — the bundle bytes themselves are not additionally\n * encrypted, but they are safe to store on untrusted blob hosts because\n * every record inside is already ciphertext.\n *\n * @internal\n */\ninterface BundleStoreData {\n readonly _noydb_bundle_store: typeof BUNDLE_STORE_VERSION\n readonly vault: string\n readonly ts: string\n readonly data: VaultSnapshot\n}\n\n// ─── Options ───────────────────────────────────────────────────────────\n\nexport interface WrapPodStoreOptions {\n /**\n * When `true` (default), every `put()` and `delete()` flushes the full\n * vault snapshot to the bundle backend. Set to `false` for bulk operations\n * and call `store.flush(vaultId)` manually.\n */\n autoFlush?: boolean\n}\n\n// ─── Extended NoydbStore with flush/batch ───────────────────────────────\n\nexport interface WrappedPodNoydbStore extends NoydbStore {\n /** Manually flush the in-memory snapshot to the bundle backend. */\n flush(vaultId: string): Promise<void>\n /**\n * Run a batch of mutations without flushing until the callback completes.\n * A single flush is performed at the end.\n */\n batch(vaultId: string, fn: () => Promise<void>): Promise<void>\n}\n\n// ─── wrapPodStore ───────────────────────────────────────────────────\n\nconst MAX_CONFLICT_RETRIES = 3\n\n/**\n * Convert a `NoydbPodStore` (blob-oriented read/write with OCC) into the\n * standard six-method `NoydbStore` interface expected by `createNoydb({ store })`.\n *\n * Bundle stores operate on the entire vault as a single serialised unit —\n * ideal for backends like Google Drive, WebDAV, or iCloud Drive that work\n * best with whole-file I/O rather than per-record KV operations.\n *\n * ## Optimistic concurrency\n *\n * The wrapper tracks the `version` token from the last `readBundle` and\n * passes it as `expectedVersion` on every flush. On\n * `PodVersionConflictError`, it re-reads, merges the remote snapshot\n * (last-write-wins per record key), and retries (max 3 attempts).\n *\n * ## Flush modes\n *\n * By default, flushes on every mutation (O(vault size) per write). Options:\n * - `autoFlush: false` + explicit `store.flush(vaultId)` calls\n * - `store.batch(vaultId, async () => { ... })` — defers flush until end\n * - Pair with `syncPolicy: { push: { mode: 'debounce' } }` from \n */\nexport function wrapPodStore(\n bundle: NoydbPodStore,\n options?: WrapPodStoreOptions,\n): WrappedPodNoydbStore {\n const autoFlush = options?.autoFlush !== false\n\n // Per-vault state\n const snapshots = new Map<string, VaultSnapshot>()\n const versions = new Map<string, string | null>()\n const loaded = new Set<string>()\n\n // Batch mode: when > 0, suppress auto-flush\n let batchDepth = 0\n\n // #908 — in-flight loads, keyed by vault. Without this, every concurrent\n // caller issued its own `readBundle` and then REPLACED `snapshots` with a\n // freshly parsed object — orphaning the mutations earlier callers had\n // already made to the object they were handed. 100 racing puts kept 1.\n const loading = new Map<string, Promise<VaultSnapshot>>()\n\n async function load(vault: string): Promise<VaultSnapshot> {\n if (loaded.has(vault)) return snapshots.get(vault)!\n\n const inFlight = loading.get(vault)\n if (inFlight) return inFlight\n\n const pending = (async () => {\n const result = await bundle.readBundle(vault)\n if (result) {\n const text = new TextDecoder().decode(result.bytes)\n const format = JSON.parse(text) as BundleStoreData\n snapshots.set(vault, format.data)\n versions.set(vault, result.version)\n } else {\n snapshots.set(vault, {})\n versions.set(vault, null)\n }\n\n loaded.add(vault)\n return snapshots.get(vault)!\n })()\n\n loading.set(vault, pending)\n try {\n return await pending\n } finally {\n // Clear on failure too, so a transient read error does not poison\n // every later load of this vault with a rejected promise.\n loading.delete(vault)\n }\n }\n\n async function flush(vault: string): Promise<void> {\n const snapshot = snapshots.get(vault) ?? {}\n const format: BundleStoreData = {\n _noydb_bundle_store: BUNDLE_STORE_VERSION,\n vault,\n ts: new Date().toISOString(),\n data: snapshot,\n }\n const bytes = new TextEncoder().encode(JSON.stringify(format))\n const expectedVersion = versions.get(vault) ?? null\n\n for (let attempt = 0; attempt < MAX_CONFLICT_RETRIES; attempt++) {\n try {\n const { version: newVersion } = await bundle.writeBundle(vault, bytes, expectedVersion)\n versions.set(vault, newVersion)\n return\n } catch (err) {\n if (err instanceof PodVersionConflictError && attempt < MAX_CONFLICT_RETRIES - 1) {\n // Pull remote, merge (last-write-wins by record key), retry\n const remote = await bundle.readBundle(vault)\n if (remote) {\n const remoteText = new TextDecoder().decode(remote.bytes)\n const remoteFormat = JSON.parse(remoteText) as BundleStoreData\n const localSnap = snapshots.get(vault) ?? {}\n const mergedSnap = mergeSnapshots(remoteFormat.data, localSnap)\n snapshots.set(vault, mergedSnap)\n versions.set(vault, remote.version)\n }\n // Re-encode with merged data for the retry\n continue\n }\n throw err\n }\n }\n }\n\n // #908 — one flush at a time per vault. `flush` reads and writes the vault's\n // version token, so concurrent flushes race: each sends the same\n // `expectedVersion`, the losers take the conflict/merge path, and with enough\n // of them the retry budget is exhausted and the error surfaces to a caller\n // whose write was perfectly valid. Serialising makes every flush see the\n // token its predecessor produced.\n const flushChain = new Map<string, Promise<void>>()\n\n function serialFlush(vault: string): Promise<void> {\n const prev = flushChain.get(vault) ?? Promise.resolve()\n // Chain past a rejection as well — one failed flush must not wedge every\n // subsequent write to this vault.\n const next = prev.then(() => flush(vault), () => flush(vault))\n flushChain.set(vault, next)\n return next\n }\n\n async function maybeFlush(vault: string): Promise<void> {\n if (autoFlush && batchDepth === 0) {\n await serialFlush(vault)\n }\n }\n\n const store: WrappedPodNoydbStore = {\n name: bundle.name ?? 'bundle',\n\n async flush(vaultId: string): Promise<void> {\n await serialFlush(vaultId)\n },\n\n async batch(vaultId: string, fn: () => Promise<void>): Promise<void> {\n await load(vaultId) // ensure loaded before batch\n batchDepth++\n try {\n await fn()\n } finally {\n batchDepth--\n }\n await serialFlush(vaultId)\n },\n\n async get(vault: string, collection: string, id: string): Promise<EncryptedEnvelope | null> {\n const snap = await load(vault)\n return snap[collection]?.[id] ?? null\n },\n\n async put(\n vault: string,\n collection: string,\n id: string,\n envelope: EncryptedEnvelope,\n expectedVersion?: number,\n ): Promise<void> {\n const snap = await load(vault)\n\n if (expectedVersion !== undefined) {\n const current = snap[collection]?.[id]\n const currentVersion = current?._v ?? 0\n if (currentVersion !== expectedVersion) {\n throw new ConflictError(\n currentVersion,\n `Expected version ${expectedVersion} but found ${currentVersion} on ${collection}/${id}`,\n )\n }\n }\n\n snap[collection] ??= {}\n snap[collection][id] = envelope\n await maybeFlush(vault)\n },\n\n async delete(vault: string, collection: string, id: string): Promise<void> {\n const snap = await load(vault)\n if (snap[collection]) {\n delete snap[collection][id]\n await maybeFlush(vault)\n }\n },\n\n async list(vault: string, collection: string): Promise<string[]> {\n const snap = await load(vault)\n return Object.keys(snap[collection] ?? {})\n },\n\n async loadAll(vault: string): Promise<VaultSnapshot> {\n const snap = await load(vault)\n // #908 — two contract fixes in one place:\n // 1. internal collections (`_keyring`, `_sync`) are the vault's own\n // bookkeeping and must not appear in a snapshot — `@noy-db/to-file`\n // sets the reference behaviour with this same `_`-prefix rule;\n // 2. copy rather than hand out the live cache, which let a caller\n // mutating the result silently rewrite the wrapper's own state.\n // `get()`/`list()` still serve internal collections; this is about what\n // a *snapshot* claims, not about hiding data.\n const out: VaultSnapshot = {}\n for (const [collection, records] of Object.entries(snap)) {\n if (collection.startsWith('_')) continue\n out[collection] = { ...records }\n }\n return out\n },\n\n async saveAll(vault: string, data: VaultSnapshot): Promise<void> {\n snapshots.set(vault, data)\n loaded.add(vault)\n await serialFlush(vault)\n },\n }\n\n return store\n}\n\n// ─── Snapshot merge (last-write-wins per record) ────────────────────────\n\nfunction mergeSnapshots(remote: VaultSnapshot, local: VaultSnapshot): VaultSnapshot {\n const merged: VaultSnapshot = {}\n\n // Start with all remote collections\n for (const [coll, records] of Object.entries(remote)) {\n merged[coll] = { ...records }\n }\n\n // Overlay local collections — LWW by _ts per record\n for (const [coll, records] of Object.entries(local)) {\n if (!merged[coll]) {\n merged[coll] = { ...records }\n continue\n }\n for (const [id, envelope] of Object.entries(records)) {\n const existing = merged[coll][id]\n if (!existing || envelope._ts >= existing._ts) {\n merged[coll][id] = envelope\n }\n }\n }\n\n return merged\n}\n\n// ─── Factory helper ─────────────────────────────────────────────────────\n\n/**\n * Type-safe factory helper for `NoydbPodStore` implementations,\n * analogous to `createStore` for KV stores.\n */\nexport function createPodStore<TOptions>(\n factory: (options: TOptions) => NoydbPodStore,\n): (options: TOptions) => NoydbPodStore {\n return factory\n}\n\n// ─── Deprecated aliases (pre-rename compatibility) ──────────────────────\n\n/** @deprecated Use wrapPodStore. */\nexport const wrapBundleStore = wrapPodStore\n/** @deprecated Use createPodStore. */\nexport const createBundleStore = createPodStore\n/** @deprecated Use WrappedPodNoydbStore. */\nexport type WrappedBundleNoydbStore = WrappedPodNoydbStore\n/** @deprecated Use WrapPodStoreOptions. */\nexport type WrapBundleStoreOptions = WrapPodStoreOptions\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/with-shape/introspection/walk.ts"],"sourcesContent":["/**\n * Orchestrate the structural walk of a Vault, producing a\n * {@link VaultSchemaSnapshot}. Called from `Vault.dumpSchema()`.\n *\n * @module\n */\n\nimport { derivePersistedSchema } from '../persisted-schemas/derive.js'\nimport { loadPersistedSchema } from '../persisted-schemas/storage.js'\nimport { jsonSchemaToFields } from './fields.js'\nimport type {\n CollectionConfig,\n CollectionDescriptor,\n CollectionStats,\n DumpSchemaOptions,\n FieldDescriptor,\n InternalCollectionStats,\n MaterializedViewDescriptor,\n OverlayViewDescriptor,\n DerivationDescriptor,\n VaultSchemaSnapshot,\n} from './types.js'\nimport type { Collection } from '../../kernel/collection.js'\nimport type { NoydbStore } from '../../kernel/types.js'\nimport type { UnlockedKeyring } from '../../with-party/team/keyring.js'\nimport type { RefRegistry } from '../../kernel/refs.js'\nimport type { VaultMeta } from './meta.js'\nimport type { EnclaveKey } from '../../kernel/enclave/index.js'\n\n/**\n * The minimal slice of Vault internal state the walker needs.\n * Exposed via `vault._introspectState()` to keep the public Vault\n * surface narrow.\n *\n * @internal\n */\nexport interface VaultIntrospectState {\n readonly name: string\n readonly adapter: NoydbStore\n readonly collectionCache: Map<string, Collection<unknown>>\n readonly refRegistry: RefRegistry\n readonly getDEK: (collectionName: string) => Promise<EnclaveKey>\n /** The active unlocked keyring — role/permissions/userId for access-scoped ops. */\n readonly keyring: UnlockedKeyring\n readonly subsystems: Record<string, boolean>\n /** Vault-level descriptive metadata, when set via `openVault({meta})`. */\n readonly vaultMeta?: VaultMeta\n // Typed loosely on purpose — these are private service registries\n // accessed only for \"is anything registered\" enumeration.\n readonly mvRegistry: unknown\n readonly overlayRegistry: unknown\n readonly derivationRegistry: unknown\n /**\n * Returns the registered schema-update strategy names for a collection,\n * or `undefined` when none are registered. Populated from\n * `vault.#schemaUpdateNames` in `_introspectState()`.\n */\n readonly getCollectionSchemaUpdateNames?: (col: string) => readonly string[] | undefined\n /**\n * Returns `true` when the collection has an archive policy registered\n * in `vault.archiveRegistry`, `false` otherwise. Populated from\n * `vault.archiveRegistry` in `_introspectState()`.\n */\n readonly hasCollectionArchive?: (col: string) => boolean\n}\n\nconst INTERNAL_PREFIX = '_'\n\n/** Reserved internal collections always present in any real vault. */\nconst KNOWN_INTERNAL_NAMES = ['_keyring', '_ledger', '_meta', '_schemas', '_deltas']\n\nexport async function dumpVaultSchema(\n vault: { _introspectState(): VaultIntrospectState },\n opts: DumpSchemaOptions,\n): Promise<VaultSchemaSnapshot> {\n const state = vault._introspectState()\n const sampleSize = opts.sampleSize ?? 50\n const withStats = opts.withStats === true\n\n // 1. User-facing collections — alphabetical for diff stability\n const cacheNames = [...state.collectionCache.keys()]\n const storageNames = (await safeListAllCollections(state.adapter, state.name))\n .filter((n) => !n.startsWith(INTERNAL_PREFIX))\n const allNames = Array.from(new Set([...cacheNames, ...storageNames])).sort()\n\n const collections: Record<string, CollectionDescriptor> = {}\n for (const name of allNames) {\n collections[name] = await describeCollection(state, name, sampleSize, withStats)\n }\n\n // 2. Materialized views (placeholder — real walk in MV slice 2 follow-up)\n const materializedViews = describeMVs(state.mvRegistry)\n // 3. Overlay views\n const overlayViews = describeOverlays(state.overlayRegistry)\n // 4. Derivations\n const derivations = describeDerivations(state.derivationRegistry)\n\n // 5. Internal collections — only with stats\n let internal: Record<string, InternalCollectionStats> | undefined\n if (withStats) {\n internal = {}\n for (const name of KNOWN_INTERNAL_NAMES) {\n const stats = await statsForCollection(state.adapter, state.name, name)\n if (stats.records > 0) {\n internal[name] = { records: stats.records, bytes: stats.bytes }\n }\n }\n }\n\n const snap: VaultSchemaSnapshot = {\n _noydb_snapshot: 1,\n vault: state.name,\n emittedAt: new Date().toISOString(),\n subsystems: state.subsystems,\n ...(state.vaultMeta !== undefined ? { meta: state.vaultMeta } : {}),\n collections,\n materializedViews,\n overlayViews,\n derivations,\n ...(internal !== undefined ? { internal } : {}),\n }\n return snap\n}\n\nasync function safeListAllCollections(adapter: NoydbStore, vault: string): Promise<string[]> {\n try {\n const snap = await adapter.loadAll(vault)\n return Object.keys(snap)\n } catch {\n return []\n }\n}\n\nasync function describeCollection(\n state: VaultIntrospectState,\n collectionName: string,\n sampleSize: number,\n withStats: boolean,\n): Promise<CollectionDescriptor> {\n let fields: Record<string, FieldDescriptor> = {}\n let validator: CollectionDescriptor['validator']\n\n const refsRaw = state.refRegistry.getOutbound(collectionName)\n const refs: CollectionDescriptor['refs'] = {}\n for (const [name, desc] of Object.entries(refsRaw)) {\n refs[name] = { target: desc.target, mode: desc.mode }\n }\n\n // 1. Try the persisted Route B envelope first.\n try {\n const dek = await state.getDEK(collectionName)\n const persisted = await loadPersistedSchema(state.adapter, state.name, collectionName, dek)\n if (persisted) {\n validator = { kind: persisted.kind, source: 'persisted' }\n if (persisted.jsonSchema) {\n fields = jsonSchemaToFields(persisted.jsonSchema, 'persisted', refsRaw)\n }\n }\n } catch {\n // No DEK or decrypt failure — fall through to live-validator\n }\n\n const liveColl = state.collectionCache.get(collectionName)\n\n // 2. Try the live in-process validator (when no persisted envelope).\n if (!validator) {\n const schema = liveColl?.getSchema()\n if (schema) {\n try {\n const derived = await derivePersistedSchema(schema)\n validator = { kind: derived.kind, source: 'live-validator' }\n if (derived.jsonSchema) {\n fields = jsonSchemaToFields(derived.jsonSchema, 'live-validator', refsRaw)\n }\n } catch {\n // Derivation failed (e.g. missing peer-dep) — silently leave fields empty\n }\n }\n }\n\n // 3. Sampling fallback — deferred to a follow-up. For now: empty when no schema.\n if (Object.keys(fields).length === 0 && sampleSize > 0) {\n // Sampling path not implemented in baseline slice 2; reserved for follow-up.\n }\n\n // Populate collection-level meta and config from the live collection when available.\n const collMeta = liveColl?.getMeta()\n const collConfig = liveColl?.getConfig()\n\n // Thread vault-level config (archive + schemaUpdate) that the Collection cannot see.\n const archivePresent = state.hasCollectionArchive?.(collectionName) === true\n const schemaUpdateNames = state.getCollectionSchemaUpdateNames?.(collectionName)\n const hasSchemaUpdate = schemaUpdateNames !== undefined && schemaUpdateNames.length > 0\n\n // Merge Collection-level config with vault-level fields. Omit config entirely\n // when all sources are empty.\n let mergedConfig: CollectionConfig | undefined\n if (collConfig !== undefined || archivePresent || hasSchemaUpdate) {\n mergedConfig = {\n ...(collConfig ?? {}),\n ...(archivePresent ? { archive: true as const } : {}),\n ...(hasSchemaUpdate ? { schemaUpdate: schemaUpdateNames } : {}),\n }\n }\n\n const descriptor: CollectionDescriptor = {\n fields,\n indexes: [],\n refs,\n ...(validator ? { validator } : {}),\n ...(collMeta !== undefined ? { meta: collMeta } : {}),\n ...(mergedConfig !== undefined ? { config: mergedConfig } : {}),\n }\n if (withStats) {\n const stats = await statsForCollection(state.adapter, state.name, collectionName)\n ;(descriptor as { stats?: CollectionStats }).stats = stats\n }\n return descriptor\n}\n\nasync function statsForCollection(\n adapter: NoydbStore,\n vault: string,\n collection: string,\n): Promise<CollectionStats> {\n const ids = await adapter.list(vault, collection)\n if (ids.length === 0) {\n return { records: 0, bytes: 0, bytesAvg: 0, bytesMin: 0, bytesMax: 0, oldest: '', newest: '' }\n }\n let total = 0\n let min = Number.POSITIVE_INFINITY\n let max = 0\n let oldest = ''\n let newest = ''\n for (const id of ids) {\n const env = await adapter.get(vault, collection, id)\n if (!env) continue\n const size = env._data.length\n total += size\n if (size < min) min = size\n if (size > max) max = size\n if (env._ts < oldest) oldest = env._ts\n if (env._ts > newest) newest = env._ts\n }\n return {\n records: ids.length,\n bytes: total,\n bytesAvg: Math.round(total / ids.length),\n bytesMin: min === Number.POSITIVE_INFINITY ? 0 : min,\n bytesMax: max,\n oldest: oldest === '' ? '' : oldest,\n newest,\n }\n}\n\nfunction describeMVs(registry: unknown): Record<string, MaterializedViewDescriptor> {\n if (!registry || typeof registry !== 'object') return {}\n const items = listFromRegistry(registry as Record<string, unknown>)\n const out: Record<string, MaterializedViewDescriptor> = {}\n // Each item is RegisteredMV { spec, dependencies, outputCollection, ... }\n for (const item of items) {\n const reg = item as {\n spec?: {\n name?: string\n unionSources?: ReadonlyArray<{ collection: string }>\n groupBy?: string | ReadonlyArray<string>\n aggregate?: Record<string, unknown>\n refresh?: string\n }\n dependencies?: ReadonlySet<string>\n }\n const spec = reg.spec\n if (!spec?.name) continue\n const sources = spec.unionSources\n ? spec.unionSources.map((u) => u.collection)\n : (reg.dependencies ? [...reg.dependencies].sort() : [])\n const groupBy = spec.groupBy\n ? Array.isArray(spec.groupBy) ? [...spec.groupBy] : [spec.groupBy]\n : undefined\n const aggregate = spec.aggregate ? Object.fromEntries(\n Object.entries(spec.aggregate).map(([k, v]) => [k, summariseAggregateOp(v)]),\n ) : undefined\n out[spec.name] = {\n sources,\n ...(groupBy ? { groupBy } : {}),\n ...(aggregate ? { aggregate } : {}),\n refresh: spec.refresh ?? 'eager',\n }\n }\n return out\n}\n\nfunction describeOverlays(registry: unknown): Record<string, OverlayViewDescriptor> {\n if (!registry || typeof registry !== 'object') return {}\n const specs = listFromRegistry(registry as Record<string, unknown>)\n const out: Record<string, OverlayViewDescriptor> = {}\n for (const spec of specs) {\n const s = spec as { name?: string; base?: string; overlay?: string }\n if (!s.name || !s.base || !s.overlay) continue\n out[s.name] = { base: s.base, overlay: s.overlay }\n }\n return out\n}\n\nfunction describeDerivations(registry: unknown): Record<string, DerivationDescriptor> {\n if (!registry || typeof registry !== 'object') return {}\n const items = listFromRegistry(registry as Record<string, unknown>)\n const out: Record<string, DerivationDescriptor> = {}\n for (const item of items) {\n // `all()` on DerivationRegistry returns RegisteredStrategy objects:\n // { spec: DerivationSpec, strategyHash }. Read `spec` and fall\n // back to the item itself for forward-compat with other registries.\n const reg = item as { spec?: { source?: string; outputs?: Record<string, { collection: string }> }; source?: string; outputs?: Record<string, { collection: string }> }\n const s = reg.spec ?? reg\n if (!s.source) continue\n const outputCollections = s.outputs\n ? Object.values(s.outputs).map((o) => (o as { collection: string }).collection)\n : []\n // Key by sorted output-collection names so co-sourced derivations don't\n // collide. A single-output derivation keys as just that collection name\n // (e.g. 'billSummary'); multi-output keys as sorted join (e.g. 'a+b').\n // Falls back to source when no outputs are declared (defensive).\n const key = outputCollections.length > 0\n ? [...outputCollections].sort().join('+')\n : s.source\n out[key] = {\n source: s.source,\n outputs: outputCollections,\n }\n }\n return out\n}\n\nfunction listFromRegistry(reg: Record<string, unknown>): readonly unknown[] {\n // Registries expose different accessor methods; try the common ones.\n for (const method of ['all', 'list', 'specs', 'values']) {\n const fn = reg[method]\n if (typeof fn === 'function') {\n try {\n const out = (fn as () => unknown).call(reg)\n if (Array.isArray(out)) return out\n if (out && typeof (out as { values?: () => unknown }).values === 'function') {\n return [...(out as { values: () => Iterable<unknown> }).values()]\n }\n } catch {\n continue\n }\n }\n }\n return []\n}\n\nfunction summariseAggregateOp(value: unknown): string {\n if (value && typeof value === 'object') {\n const op = (value as { op?: string; kind?: string; field?: string }).op\n ?? (value as { kind?: string }).kind\n const field = (value as { field?: string }).field\n if (op && field) return `${op}(${field})`\n if (op) return op\n }\n return String(value)\n}\n"],"mappings":"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","names":[]}
|
package/dist/chunk-4JQK3L4V.js
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
NoydbError
|
|
3
|
-
} from "./chunk-QZWTRENR.js";
|
|
4
|
-
|
|
5
|
-
// src/with-shape/links/names.ts
|
|
6
|
-
var LINK_COLLECTION_PREFIX = "_links_";
|
|
7
|
-
function linkCollectionName(name) {
|
|
8
|
-
return `${LINK_COLLECTION_PREFIX}${name}`;
|
|
9
|
-
}
|
|
10
|
-
function isLinkCollectionName(name) {
|
|
11
|
-
return name.startsWith(LINK_COLLECTION_PREFIX);
|
|
12
|
-
}
|
|
13
|
-
function linkRowKey(aId, bId) {
|
|
14
|
-
return `${encodeURIComponent(aId)}|${encodeURIComponent(bId)}`;
|
|
15
|
-
}
|
|
16
|
-
var LinkIntegrityError = class extends NoydbError {
|
|
17
|
-
link;
|
|
18
|
-
endpoint;
|
|
19
|
-
id;
|
|
20
|
-
count;
|
|
21
|
-
constructor(link, endpoint, id, count) {
|
|
22
|
-
super(
|
|
23
|
-
"LINK_INTEGRITY",
|
|
24
|
-
`Cannot delete "${endpoint}"/"${id}": ${count} link(s) in "${link}" still reference it (onDelete: 'strict').`
|
|
25
|
-
);
|
|
26
|
-
this.name = "LinkIntegrityError";
|
|
27
|
-
this.link = link;
|
|
28
|
-
this.endpoint = endpoint;
|
|
29
|
-
this.id = id;
|
|
30
|
-
this.count = count;
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
export {
|
|
35
|
-
LINK_COLLECTION_PREFIX,
|
|
36
|
-
linkCollectionName,
|
|
37
|
-
isLinkCollectionName,
|
|
38
|
-
linkRowKey,
|
|
39
|
-
LinkIntegrityError
|
|
40
|
-
};
|
|
41
|
-
//# sourceMappingURL=chunk-4JQK3L4V.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/with-shape/links/names.ts"],"sourcesContent":["/**\n * Link-set naming helpers, declaration types, and errors — the tiny,\n * always-loadable slice of the links feature (#553).\n *\n * Split out of `link-set.ts` so the kernel floor (reserved-name guard in\n * `vault.collection()`, the lazy `vault.links()` handle) and the ref/link\n * enforcement facade can bind these few lines WITHOUT statically pulling\n * the `LinkSet` storage engine; that class now loads via dynamic import\n * on first link I/O. `link-set.ts` re-exports everything here, so import\n * paths and class identities are unchanged for existing consumers.\n */\n\nimport { NoydbError } from '../../kernel/errors.js'\n\nexport const LINK_COLLECTION_PREFIX = '_links_'\n\n/** Storage collection name for a logical link set. */\nexport function linkCollectionName(name: string): string {\n return `${LINK_COLLECTION_PREFIX}${name}`\n}\n\n/** True for any reserved link-collection name. */\nexport function isLinkCollectionName(name: string): boolean {\n return name.startsWith(LINK_COLLECTION_PREFIX)\n}\n\n/** What happens to a link's rows when one of its endpoint records is deleted. */\nexport type LinkOnDelete = 'cascade' | 'strict' | 'warn'\n\n/**\n * Declaration for a link set, passed to `vault.link(name, spec)`. `a` and\n * `b` are the endpoint collection names (slot-typed). `onDelete` governs\n * what happens to link rows when an endpoint record is deleted:\n * `'cascade'` (default) removes the touching link rows, `'strict'` blocks\n * the endpoint delete while links exist, `'warn'` leaves orphan rows\n * (surfaced by `vault.checkIntegrity()`).\n */\nexport interface LinkSpec {\n readonly a: string\n readonly b: string\n readonly onDelete?: LinkOnDelete\n}\n\n/** One link tuple as returned by `of()` / `list()`. */\nexport interface LinkRow {\n readonly a: string\n readonly b: string\n readonly meta?: Record<string, unknown>\n}\n\n/**\n * Compose the row key for an ordered `(a, b)` pair. Each id is\n * URI-encoded and joined with `|` — encodeURIComponent escapes `|`, so the\n * key is unambiguous regardless of id contents.\n */\nexport function linkRowKey(aId: string, bId: string): string {\n return `${encodeURIComponent(aId)}|${encodeURIComponent(bId)}`\n}\n\n/** Public handle returned by `vault.links(name)`. */\nexport interface LinkSetHandle {\n /** Create (or overwrite the metadata of) the link `(aId, bId)`. Validates both endpoints exist. */\n connect(aId: string, bId: string, meta?: Record<string, unknown>): Promise<void>\n /** Remove the link `(aId, bId)`. Idempotent — a no-op if it doesn't exist. */\n disconnect(aId: string, bId: string): Promise<void>\n /** Whether the link `(aId, bId)` exists. */\n has(aId: string, bId: string): Promise<boolean>\n /** All links touching `id` on EITHER endpoint. */\n of(id: string): Promise<LinkRow[]>\n /** All links in the set. */\n list(): Promise<LinkRow[]>\n}\n\n/** Thrown when a `strict` link blocks deletion of an endpoint that still has links. */\nexport class LinkIntegrityError extends NoydbError {\n readonly link: string\n readonly endpoint: string\n readonly id: string\n readonly count: number\n constructor(link: string, endpoint: string, id: string, count: number) {\n super(\n 'LINK_INTEGRITY',\n `Cannot delete \"${endpoint}\"/\"${id}\": ${count} link(s) in \"${link}\" still reference it (onDelete: 'strict').`,\n )\n this.name = 'LinkIntegrityError'\n this.link = link\n this.endpoint = endpoint\n this.id = id\n this.count = count\n }\n}\n"],"mappings":";;;;;AAcO,IAAM,yBAAyB;AAG/B,SAAS,mBAAmB,MAAsB;AACvD,SAAO,GAAG,sBAAsB,GAAG,IAAI;AACzC;AAGO,SAAS,qBAAqB,MAAuB;AAC1D,SAAO,KAAK,WAAW,sBAAsB;AAC/C;AA+BO,SAAS,WAAW,KAAa,KAAqB;AAC3D,SAAO,GAAG,mBAAmB,GAAG,CAAC,IAAI,mBAAmB,GAAG,CAAC;AAC9D;AAiBO,IAAM,qBAAN,cAAiC,WAAW;AAAA,EACxC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACT,YAAY,MAAc,UAAkB,IAAY,OAAe;AACrE;AAAA,MACE;AAAA,MACA,kBAAkB,QAAQ,MAAM,EAAE,MAAM,KAAK,gBAAgB,IAAI;AAAA,IACnE;AACA,SAAK,OAAO;AACZ,SAAK,OAAO;AACZ,SAAK,WAAW;AAChB,SAAK,KAAK;AACV,SAAK,QAAQ;AAAA,EACf;AACF;","names":[]}
|