@noy-db/hub 0.4.0-pre.1 → 0.4.0-pre.11
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/README.md +3 -4
- package/dist/api-ZDKTWNBB.js +20 -0
- package/dist/attestation/index.js +18 -18
- package/dist/{backup-LU2DTZTI.js → backup-2UX7PRM5.js} +13 -13
- package/dist/blobs/index.js +30 -15
- package/dist/blobs/index.js.map +1 -1
- package/dist/broker/index.js +12 -12
- package/dist/broker/index.js.map +1 -1
- package/dist/cargo/index.js +53 -43
- package/dist/{chunk-YTGDPCPW.js → chunk-2J6UEN2V.js} +42 -18
- package/dist/chunk-2J6UEN2V.js.map +1 -0
- package/dist/{chunk-IY23KFNZ.js → chunk-35NMVJ7I.js} +3 -3
- package/dist/{chunk-S3BFKGET.js → chunk-3HUYRN24.js} +4 -4
- package/dist/chunk-3HUYRN24.js.map +1 -0
- package/dist/{walk-XS3PKM6I.js → chunk-3V3XR4S4.js} +4 -13
- package/dist/{walk-XS3PKM6I.js.map → chunk-3V3XR4S4.js.map} +1 -1
- package/dist/{chunk-RTEK4C4I.js → chunk-4JQK3L4V.js} +2 -2
- package/dist/{chunk-3ELCWU56.js → chunk-4ZKNC6A6.js} +2 -2
- package/dist/{chunk-VQNJ7UZL.js → chunk-55LKVALY.js} +106 -10
- package/dist/chunk-55LKVALY.js.map +1 -0
- package/dist/{chunk-VAIS3SOM.js → chunk-55LX6FSX.js} +2 -2
- package/dist/chunk-5D2ALSM5.js +19 -0
- package/dist/chunk-5D2ALSM5.js.map +1 -0
- package/dist/{chunk-6HPG2YNX.js → chunk-5DRROK5W.js} +2 -2
- package/dist/{chunk-S6Q37VGE.js → chunk-5GQEU4DN.js} +2 -2
- package/dist/chunk-5JOFWL4G.js +25 -0
- package/dist/chunk-5JOFWL4G.js.map +1 -0
- package/dist/{chunk-TOPYT5U5.js → chunk-63FE525P.js} +6 -6
- package/dist/chunk-6LJY7X5A.js +18 -0
- package/dist/chunk-6LJY7X5A.js.map +1 -0
- package/dist/{chunk-JVBO4SZL.js → chunk-6UBZ6I5Z.js} +2 -2
- package/dist/{chunk-BOKIKJJB.js → chunk-6ZNSB3H6.js} +5 -17
- package/dist/chunk-6ZNSB3H6.js.map +1 -0
- package/dist/{chunk-BMQWTQZ4.js → chunk-7YVBQJ7K.js} +13 -355
- package/dist/chunk-7YVBQJ7K.js.map +1 -0
- package/dist/{chunk-UFEVO57O.js → chunk-ABS7FMMD.js} +6 -6
- package/dist/chunk-AFHQATY4.js +47 -0
- package/dist/chunk-AFHQATY4.js.map +1 -0
- package/dist/{chunk-HOONYZY2.js → chunk-AKKRXT23.js} +7 -7
- package/dist/chunk-AKKRXT23.js.map +1 -0
- package/dist/{chunk-DDHM2TLX.js → chunk-AT2JJEKJ.js} +4 -4
- package/dist/chunk-AT2JJEKJ.js.map +1 -0
- package/dist/{chunk-M75ZZHSR.js → chunk-BLBAQRBM.js} +2 -2
- package/dist/{chunk-3SV2EPMN.js → chunk-BLCWSJLN.js} +88 -81
- package/dist/chunk-BLCWSJLN.js.map +1 -0
- package/dist/chunk-CADUYBQD.js +151 -0
- package/dist/chunk-CADUYBQD.js.map +1 -0
- package/dist/{chunk-G6EQYAL6.js → chunk-CI32CAFS.js} +5 -5
- package/dist/{chunk-FH52K7EG.js → chunk-CUZLNGD5.js} +2 -6
- package/dist/{chunk-FH52K7EG.js.map → chunk-CUZLNGD5.js.map} +1 -1
- package/dist/{chunk-2P7EGNKF.js → chunk-CXQW2NWO.js} +145 -3
- package/dist/chunk-CXQW2NWO.js.map +1 -0
- package/dist/{chunk-6B4DYGWO.js → chunk-DABACXEF.js} +3 -3
- package/dist/{chunk-F6T6L2UK.js → chunk-DMH3VZU5.js} +4 -4
- package/dist/chunk-DSDXAKIP.js +50 -0
- package/dist/chunk-DSDXAKIP.js.map +1 -0
- package/dist/{chunk-MQ6WOPSY.js → chunk-DZ2JXHWK.js} +5 -5
- package/dist/chunk-DZFQVICS.js +23 -0
- package/dist/chunk-DZFQVICS.js.map +1 -0
- package/dist/chunk-E23UGFVC.js +63 -0
- package/dist/chunk-E23UGFVC.js.map +1 -0
- package/dist/{chunk-UBNCR3YK.js → chunk-EE7UHLKH.js} +4 -4
- package/dist/chunk-EIPVYUEP.js +654 -0
- package/dist/chunk-EIPVYUEP.js.map +1 -0
- package/dist/{chunk-EGCRBCNA.js → chunk-EKRSCRNM.js} +3 -3
- package/dist/{chunk-YMUGBZN2.js → chunk-FQ5CHJR7.js} +1 -1
- package/dist/chunk-FQ5CHJR7.js.map +1 -0
- package/dist/{chunk-LB6OH6K2.js → chunk-FQZ6XTQ7.js} +17 -20
- package/dist/chunk-FQZ6XTQ7.js.map +1 -0
- package/dist/{chunk-IRQY7IR5.js → chunk-FRMPM7WG.js} +4 -4
- package/dist/{chunk-DVUZMT2W.js → chunk-G2JUIDFA.js} +9 -9
- package/dist/{chunk-DVUZMT2W.js.map → chunk-G2JUIDFA.js.map} +1 -1
- package/dist/{chunk-RND5ZPNP.js → chunk-G6WWZNJP.js} +13 -13
- package/dist/chunk-G6WWZNJP.js.map +1 -0
- package/dist/chunk-GJW4HX2O.js +1 -0
- package/dist/{chunk-T6GU5PPZ.js → chunk-GU3IP74F.js} +6 -6
- package/dist/{chunk-5OI6BR4H.js → chunk-GWWOGNBK.js} +308 -18
- package/dist/chunk-GWWOGNBK.js.map +1 -0
- package/dist/{chunk-UNCOC7QH.js → chunk-H2GPHUZD.js} +12 -13
- package/dist/chunk-H2GPHUZD.js.map +1 -0
- package/dist/{chunk-7CI6CP7Z.js → chunk-HMU5P6RL.js} +5 -5
- package/dist/chunk-HMU5P6RL.js.map +1 -0
- package/dist/{chunk-YJV2UZ7H.js → chunk-I5GEJX3R.js} +5 -5
- package/dist/chunk-I5GEJX3R.js.map +1 -0
- package/dist/{chunk-GWKAVKHI.js → chunk-IG6KUWBX.js} +2 -2
- package/dist/chunk-IG6KUWBX.js.map +1 -0
- package/dist/{chunk-MTQPRQHB.js → chunk-IPUG56GJ.js} +15 -5
- package/dist/{chunk-MTQPRQHB.js.map → chunk-IPUG56GJ.js.map} +1 -1
- package/dist/{chunk-SMIRGMS7.js → chunk-IXNCZTWA.js} +2 -2
- package/dist/{chunk-RM2XV574.js → chunk-IXTSNGYY.js} +3 -3
- package/dist/{chunk-KUPKLSX5.js → chunk-IYZISPGD.js} +7 -5
- package/dist/chunk-IYZISPGD.js.map +1 -0
- package/dist/{chunk-SMGEYW6G.js → chunk-JDOMW53O.js} +26 -16
- package/dist/chunk-JDOMW53O.js.map +1 -0
- package/dist/{chunk-PK6QCH2C.js → chunk-JJZGIE4U.js} +6 -5
- package/dist/{chunk-DRWBEDYO.js → chunk-JYJFGD2H.js} +2 -2
- package/dist/{chunk-TAGR72IR.js → chunk-KRCBZYTZ.js} +26 -177
- package/dist/chunk-KRCBZYTZ.js.map +1 -0
- package/dist/{chunk-HPUWOVR7.js → chunk-L2DGWBCT.js} +14 -14
- package/dist/chunk-L2DGWBCT.js.map +1 -0
- package/dist/{chunk-VEALDPHW.js → chunk-L3YYLT4E.js} +15 -2
- package/dist/chunk-L3YYLT4E.js.map +1 -0
- package/dist/{chunk-A7JJLVGH.js → chunk-LNPUSMZL.js} +29 -31
- package/dist/chunk-LNPUSMZL.js.map +1 -0
- package/dist/{chunk-KUIB4B5Q.js → chunk-LNZKOUJR.js} +2 -2
- package/dist/{chunk-IM3QVF53.js → chunk-MBKVNOJS.js} +6 -6
- package/dist/chunk-MCHBCNCE.js +367 -0
- package/dist/chunk-MCHBCNCE.js.map +1 -0
- package/dist/{chunk-VCBHAE4R.js → chunk-MHMLXJ3I.js} +2 -2
- package/dist/chunk-MHMLXJ3I.js.map +1 -0
- package/dist/{chunk-WNGGJWF7.js → chunk-MSMJJB4J.js} +2 -2
- package/dist/chunk-MSMJJB4J.js.map +1 -0
- package/dist/{chunk-T36RFODW.js → chunk-MXUT7FTE.js} +2 -2
- package/dist/chunk-MXUT7FTE.js.map +1 -0
- package/dist/{chunk-BGK233EA.js → chunk-N4BBNYIB.js} +11 -9
- package/dist/chunk-N4BBNYIB.js.map +1 -0
- package/dist/{chunk-3PF6CRDT.js → chunk-NFIBXF4V.js} +1082 -1583
- package/dist/chunk-NFIBXF4V.js.map +1 -0
- package/dist/{chunk-LOF2W3JU.js → chunk-NFNJLRY7.js} +368 -52
- package/dist/chunk-NFNJLRY7.js.map +1 -0
- package/dist/{chunk-N6WF5PKC.js → chunk-NFZGZ4AK.js} +2 -2
- package/dist/{chunk-JRBNCUNT.js → chunk-NGSJZFGL.js} +21 -4
- package/dist/chunk-NGSJZFGL.js.map +1 -0
- package/dist/chunk-NJ4DYYO5.js +81 -0
- package/dist/chunk-NJ4DYYO5.js.map +1 -0
- package/dist/{chunk-2IALOXZS.js → chunk-NM5UYF6Q.js} +2 -2
- package/dist/chunk-NM5UYF6Q.js.map +1 -0
- package/dist/{chunk-JBBSYJHP.js → chunk-NYEFP7DY.js} +4 -4
- package/dist/chunk-NYEFP7DY.js.map +1 -0
- package/dist/{chunk-CCOP5XDW.js → chunk-NZ24MX4J.js} +8 -46
- package/dist/chunk-NZ24MX4J.js.map +1 -0
- package/dist/{chunk-KWVJAOIN.js → chunk-OLEPKFTW.js} +4 -4
- package/dist/chunk-OLEPKFTW.js.map +1 -0
- package/dist/{chunk-OF75ACKS.js → chunk-PEATRIYJ.js} +9 -9
- package/dist/chunk-PEOZ34EM.js +13 -0
- package/dist/chunk-PEOZ34EM.js.map +1 -0
- package/dist/{chunk-UC2ETWF3.js → chunk-PTHKZWEH.js} +2 -14
- package/dist/{chunk-UC2ETWF3.js.map → chunk-PTHKZWEH.js.map} +1 -1
- package/dist/chunk-PVEWA2DU.js +23 -0
- package/dist/chunk-PVEWA2DU.js.map +1 -0
- package/dist/{chunk-LSASLXGC.js → chunk-QBAC3GXA.js} +1 -1
- package/dist/chunk-QBAC3GXA.js.map +1 -0
- package/dist/{chunk-RDXW3OBQ.js → chunk-QD46HPZG.js} +2 -2
- package/dist/chunk-QD46HPZG.js.map +1 -0
- package/dist/{chunk-N55W7KUL.js → chunk-QDIH2744.js} +2 -2
- package/dist/{chunk-6HY2X62D.js → chunk-QJNCB5SK.js} +2 -2
- package/dist/{chunk-4BRCIYFG.js → chunk-QX76XVQH.js} +6 -6
- package/dist/chunk-QX76XVQH.js.map +1 -0
- package/dist/{chunk-W2OG6JOL.js → chunk-QZWTRENR.js} +24 -7
- package/dist/chunk-QZWTRENR.js.map +1 -0
- package/dist/{chunk-6NQMXTYC.js → chunk-RO5NM6UI.js} +2 -2
- package/dist/chunk-RO5NM6UI.js.map +1 -0
- package/dist/chunk-SGDPRCC4.js +1075 -0
- package/dist/chunk-SGDPRCC4.js.map +1 -0
- package/dist/{chunk-2PCAVW2I.js → chunk-SHEEBRZ4.js} +2 -2
- package/dist/chunk-SMY5X46Z.js +14 -0
- package/dist/chunk-SMY5X46Z.js.map +1 -0
- package/dist/{chunk-ISMV2QVG.js → chunk-TG634KCO.js} +11 -2
- package/dist/chunk-TG634KCO.js.map +1 -0
- package/dist/{chunk-J6Q7UVQE.js → chunk-TUXQSFHZ.js} +4 -16
- package/dist/{chunk-J6Q7UVQE.js.map → chunk-TUXQSFHZ.js.map} +1 -1
- package/dist/{chunk-GULTLPFB.js → chunk-UADPR6F4.js} +3 -3
- package/dist/{chunk-GULTLPFB.js.map → chunk-UADPR6F4.js.map} +1 -1
- package/dist/{chunk-ZEQWCBCM.js → chunk-UDHBXYGG.js} +27 -5
- package/dist/chunk-UDHBXYGG.js.map +1 -0
- package/dist/{chunk-RA5VTXXG.js → chunk-V6UQZA2H.js} +2 -2
- package/dist/chunk-VG2ZSFYD.js +32 -0
- package/dist/chunk-VG2ZSFYD.js.map +1 -0
- package/dist/chunk-VKQCVU2Z.js +21 -0
- package/dist/chunk-VKQCVU2Z.js.map +1 -0
- package/dist/{chunk-QDPZWTN2.js → chunk-W3G5REIU.js} +2 -2
- package/dist/{chunk-WEYZTLXN.js → chunk-W3L64Y3J.js} +2 -2
- package/dist/{chunk-ONTBCHCP.js → chunk-W66AM5IB.js} +2 -2
- package/dist/chunk-W66AM5IB.js.map +1 -0
- package/dist/{chunk-A5BDDEXK.js → chunk-WBKZUO5V.js} +26 -43
- package/dist/chunk-WBKZUO5V.js.map +1 -0
- package/dist/{chunk-CBSY2N76.js → chunk-WLXMTYGO.js} +2 -2
- package/dist/{chunk-3U3FBR7O.js → chunk-X3F5YJG2.js} +2 -2
- package/dist/{chunk-GQNGCEP5.js → chunk-X45JYIAY.js} +3 -3
- package/dist/chunk-X45JYIAY.js.map +1 -0
- package/dist/{chunk-6XE5TMPR.js → chunk-X4MVWPHV.js} +3 -3
- package/dist/chunk-X4MVWPHV.js.map +1 -0
- package/dist/chunk-XZHEOSQ2.js +16 -0
- package/dist/chunk-XZHEOSQ2.js.map +1 -0
- package/dist/chunk-Y2NBBT6K.js +18 -0
- package/dist/chunk-Y2NBBT6K.js.map +1 -0
- package/dist/{chunk-DDATL6PU.js → chunk-Y2NJBNX3.js} +8 -8
- package/dist/{chunk-DDATL6PU.js.map → chunk-Y2NJBNX3.js.map} +1 -1
- package/dist/chunk-YMUFFJCO.js +23 -0
- package/dist/chunk-YMUFFJCO.js.map +1 -0
- package/dist/{chunk-O7WJ47EF.js → chunk-YWWQM7KP.js} +5 -14
- package/dist/chunk-YWWQM7KP.js.map +1 -0
- package/dist/{chunk-7O3AYBC7.js → chunk-YZJSJOUI.js} +235 -65
- package/dist/chunk-YZJSJOUI.js.map +1 -0
- package/dist/{chunk-5WZXVULX.js → chunk-ZTLOXFPB.js} +2 -2
- package/dist/chunk-ZTLOXFPB.js.map +1 -0
- package/dist/classified/index.js +5 -5
- package/dist/{classified-marker-WQVIJAW2.js → classified-marker-7PKJBFCG.js} +3 -3
- package/dist/collection-facade-6I5K5IOD.js +45 -0
- package/dist/{computed-DSMPXG2Y.js → computed-AB45PS4V.js} +3 -3
- package/dist/consent/index.js +13 -9
- package/dist/consent/index.js.map +1 -1
- package/dist/cover/index.js +37 -0
- package/dist/crdt/index.js +4 -0
- package/dist/crdt/index.js.map +1 -1
- package/dist/custody/index.js +26 -0
- package/dist/{dead-filter-2A7IAJ3D.js → dead-filter-FL3WIUZS.js} +2 -2
- package/dist/{chunk-GYYCX5K6.js → delegation-QXZ4MPPH.js} +12 -6
- package/dist/{chunk-GYYCX5K6.js.map → delegation-QXZ4MPPH.js.map} +1 -1
- package/dist/derivations/index.js +12 -12
- package/dist/derive-VGS7FKE3.js +22 -0
- package/dist/directory/index.js +46 -0
- package/dist/dispatch-EGGC7UD7.js +72 -0
- package/dist/dispatch-EGGC7UD7.js.map +1 -0
- package/dist/dispatch-GDSTUTVP.js +194 -0
- package/dist/dispatch-GDSTUTVP.js.map +1 -0
- package/dist/{enclave-7MW6ZGXW.js → enclave-SPEEDYZ4.js} +11 -11
- package/dist/executor-IEBLTBCW.js +9 -0
- package/dist/executor-OTF556PL.js +28 -0
- package/dist/executor-RM7XWQDU.js +9 -0
- package/dist/export-accessible-P42BQ4PB.js +23 -0
- package/dist/extract-partition-TCYXRWBN.js +38 -0
- package/dist/{fanout-sidecar-WDYQ77VB.js → fanout-sidecar-SSMRSC2L.js} +9 -9
- package/dist/find-OZMTRIK3.js +11 -0
- package/dist/forget/index.js +11 -11
- package/dist/forget/index.js.map +1 -1
- package/dist/guards/index.js +6 -6
- package/dist/history/index.js +16 -12
- package/dist/history/index.js.map +1 -1
- package/dist/i18n/index.js +16 -14
- package/dist/i18n/index.js.map +1 -1
- package/dist/index.d.ts +42 -42
- package/dist/index.js +330 -2106
- package/dist/index.js.map +1 -1
- package/dist/indexing/index.js +4 -2
- package/dist/indexing/index.js.map +1 -1
- package/dist/introspection/index.js +28 -0
- package/dist/issue-FCKN5O6C.js +19 -0
- package/dist/kernel/best-effort-revert.d.ts +9 -1
- package/dist/kernel/collection-config.d.ts +12 -70
- package/dist/kernel/collection.d.ts +11 -23
- package/dist/kernel/enclave/crypto.d.ts +8 -8
- package/dist/kernel/enclave/index.d.ts +3 -3
- package/dist/kernel/errors.d.ts +41 -22
- package/dist/kernel/lazy.d.ts +30 -0
- package/dist/kernel/noydb.d.ts +81 -124
- package/dist/kernel/query/builder.d.ts +10 -10
- package/dist/kernel/query/index.d.ts +0 -6
- package/dist/kernel/query/scan-builder.d.ts +4 -4
- package/dist/kernel/sync-policy.d.ts +76 -4
- package/dist/kernel/types.d.ts +146 -86
- package/dist/kernel/validation.d.ts +33 -33
- package/dist/kernel/vault.d.ts +41 -229
- package/dist/kernel/via/dispatch.d.ts +7 -0
- package/dist/{ledger-33BC4TR7.js → ledger-6XBEVWYP.js} +11 -11
- package/dist/liberate-CYUOS4NC.js +24 -0
- package/dist/{link-set-QK22TDEX.js → link-set-NK6L2A5S.js} +11 -11
- package/dist/materialized-views/index.js +22 -19
- package/dist/money/index.js +31 -0
- package/dist/noydb-FZZIMLCI.js +81 -0
- package/dist/overlay-views/index.js +4 -4
- package/dist/periods/index.js +15 -13
- package/dist/pod/index.js +26 -12
- package/dist/{policy-NAHB2TUT.js → policy/index.js} +6 -6
- package/dist/port/with/archive-strategy.d.ts +31 -0
- package/dist/port/with/blob-strategy.d.ts +15 -5
- package/dist/port/with/collection-options.d.ts +171 -0
- package/dist/port/with/collection-registries.d.ts +62 -0
- package/dist/port/with/strategies.d.ts +134 -0
- package/dist/port/with/team-strategy.d.ts +3 -2
- package/dist/portability/index.js +8 -8
- package/dist/{post-register-JVTMJ6OW.js → post-register-VFIYISUK.js} +6 -6
- package/dist/query/index.js +6 -46
- package/dist/{aggregate → reduce}/index.js +24 -17
- package/dist/reduce/index.js.map +1 -0
- package/dist/register-UKU2J6MN.js +25 -0
- package/dist/registry-2VCWVHZS.js +19 -0
- package/dist/registry-7Y5WF7GS.js +9 -0
- package/dist/{registry-VW6P6A3J.js → registry-BWD2ED52.js} +2 -2
- package/dist/registry-DTWRJLSF.js +18 -0
- package/dist/request-withdrawal-JYDZ5XY2.js +31 -0
- package/dist/{reveal-LGBOM2BO.js → reveal-CL2BCW6A.js} +6 -6
- package/dist/revoke-2TSAD2T4.js +24 -0
- package/dist/satellites/index.js +1 -1
- package/dist/schema-update/index.js +26 -0
- package/dist/sealed-record/index.js +12 -12
- package/dist/search/index.js +36 -0
- package/dist/{seed-PWK45HDF.js → seed-NUVJEL7T.js} +12 -12
- package/dist/seed-NUVJEL7T.js.map +1 -0
- package/dist/sequence/index.js +30 -0
- package/dist/session/index.js +13 -9
- package/dist/session/index.js.map +1 -1
- package/dist/shadow/index.js +6 -2
- package/dist/shadow/index.js.map +1 -1
- package/dist/signer-K7Z2EOMG.js +25 -0
- package/dist/snapshots/index.js +14 -10
- package/dist/snapshots/index.js.map +1 -1
- package/dist/{stale-FJED42DM.js → stale-A4J26OIC.js} +11 -10
- package/dist/storage-YVHZUISN.js +23 -0
- package/dist/store/index.js +22 -0
- package/dist/{store-coordination-provider-APODTV4W.js → store-coordination-provider-EWRZL7XF.js} +3 -3
- package/dist/sync/index.js +15 -12
- package/dist/sync/index.js.map +1 -1
- package/dist/team/index.js +33 -48
- package/dist/tiers/index.js +10 -10
- package/dist/to/index.js +1 -1
- package/dist/{tx → transactions}/index.js +7 -3
- package/dist/transactions/index.js.map +1 -0
- package/dist/util/index.js +1 -1
- package/dist/{verify-26Y5GNMK.js → verify-7XWHJWUN.js} +5 -5
- package/dist/via/blob/active.d.ts +23 -7
- package/dist/via/blob/binding.d.ts +1 -1
- package/dist/via/blob/index.d.ts +7 -1
- package/dist/via/i18n/core.d.ts +1 -1
- package/dist/via/i18n/index.d.ts +2 -0
- package/dist/via/money/money-reducer.d.ts +2 -2
- package/dist/walk-P5D6CF4V.js +21 -0
- package/dist/with-audit/consent/index.d.ts +2 -0
- package/dist/with-audit/forget/active.d.ts +3 -3
- package/dist/with-audit/forget/index.d.ts +6 -5
- package/dist/with-audit/forget/strategy.d.ts +3 -3
- package/dist/with-audit/guards/executor.d.ts +4 -4
- package/dist/with-audit/guards/immutable-guard.d.ts +3 -3
- package/dist/with-audit/guards/index.d.ts +1 -1
- package/dist/with-audit/guards/registry.d.ts +3 -3
- package/dist/with-audit/guards/transition-guard.d.ts +3 -3
- package/dist/with-audit/guards/types.d.ts +10 -10
- package/dist/with-audit/guards/with-guard.d.ts +2 -2
- package/dist/with-audit/periods/index.d.ts +2 -0
- package/dist/with-audit/periods/vault-facade.d.ts +6 -0
- package/dist/with-audit/portability/export-accessible.d.ts +4 -4
- package/dist/with-audit/portability/request-withdrawal.d.ts +3 -3
- package/dist/with-audit/portability/withdraw-accessible.d.ts +2 -2
- package/dist/with-audit/sealed-record/strategy.d.ts +1 -1
- package/dist/with-audit/tiers/index.d.ts +1 -0
- package/dist/with-cargo/adopt-partition.d.ts +7 -7
- package/dist/{legacy/kernel.d.ts → with-cargo/floor.d.ts} +4 -4
- package/dist/with-cargo/index.d.ts +9 -2
- package/dist/with-commit/crdt/index.d.ts +2 -0
- package/dist/with-commit/history/index.d.ts +2 -0
- package/dist/with-commit/history/time-machine.d.ts +2 -2
- package/dist/with-commit/numbering/descriptor.d.ts +16 -6
- package/dist/with-commit/tx/active.d.ts +5 -5
- package/dist/with-commit/tx/index.d.ts +2 -2
- package/dist/with-commit/tx/invariants.d.ts +1 -1
- package/dist/with-commit/tx/strategy.d.ts +3 -3
- package/dist/with-fork/shadow/index.d.ts +2 -0
- package/dist/with-fork/snapshots/active.d.ts +2 -2
- package/dist/with-fork/snapshots/index.d.ts +3 -1
- package/dist/with-fork/snapshots/noydb-facade.d.ts +3 -3
- package/dist/with-fork/snapshots/strategy.d.ts +2 -2
- package/dist/with-formula/derivations/dispatch.d.ts +98 -0
- package/dist/with-formula/derivations/executor.d.ts +2 -2
- package/dist/with-formula/derivations/index.d.ts +4 -1
- package/dist/with-formula/derivations/registry.d.ts +3 -3
- package/dist/with-formula/derivations/stale.d.ts +2 -2
- package/dist/with-formula/derivations/types.d.ts +3 -3
- package/dist/with-formula/derivations/with-derivation.d.ts +2 -2
- package/dist/with-formula/derivations/with-rollup.d.ts +15 -8
- package/dist/with-formula/materialized-views/dependency-analyzer.d.ts +3 -3
- package/dist/with-formula/materialized-views/dispatch.d.ts +75 -0
- package/dist/with-formula/materialized-views/index.d.ts +2 -1
- package/dist/with-formula/materialized-views/registry.d.ts +4 -4
- package/dist/with-formula/materialized-views/types.d.ts +11 -11
- package/dist/with-formula/materialized-views/with-materialized-view.d.ts +2 -2
- package/dist/with-formula/overlay-views/index.d.ts +1 -1
- package/dist/with-formula/overlay-views/registry.d.ts +4 -4
- package/dist/with-formula/overlay-views/types.d.ts +3 -3
- package/dist/with-formula/overlay-views/virtual-collection.d.ts +2 -2
- package/dist/with-formula/overlay-views/with-overlayed-view.d.ts +2 -2
- package/dist/with-lookup/indexing/active.d.ts +5 -5
- package/dist/with-lookup/indexing/index.d.ts +3 -1
- package/dist/with-lookup/indexing/strategy.d.ts +3 -3
- package/dist/with-lookup/{aggregate → reduce}/active.d.ts +8 -8
- package/dist/with-lookup/{aggregate → reduce}/groupby.d.ts +21 -21
- package/dist/with-lookup/reduce/index.d.ts +34 -0
- package/dist/with-lookup/{aggregate → reduce}/reducers.d.ts +11 -12
- package/dist/with-lookup/{aggregate/aggregation.d.ts → reduce/reduction.d.ts} +21 -21
- package/dist/with-lookup/{aggregate → reduce}/strategy.d.ts +15 -15
- package/dist/with-lookup/search/build-docs.d.ts +7 -2
- package/dist/with-lookup/search/index.d.ts +1 -1
- package/dist/with-party/broker/index.d.ts +1 -0
- package/dist/with-party/broker/seed.d.ts +1 -1
- package/dist/with-party/custody/liberate.d.ts +3 -3
- package/dist/with-party/directory/cover/index.d.ts +1 -5
- package/dist/with-party/directory/cover/schema.d.ts +0 -6
- package/dist/with-party/directory/cover/storage.d.ts +0 -8
- package/dist/with-party/directory/cover/types.d.ts +0 -21
- package/dist/with-party/directory/index.d.ts +2 -0
- package/dist/with-party/session/dev-unlock.d.ts +2 -2
- package/dist/with-party/session/index.d.ts +2 -0
- package/dist/with-party/session/session.d.ts +2 -2
- package/dist/with-party/team/deed.d.ts +8 -8
- package/dist/with-party/team/index.d.ts +4 -7
- package/dist/with-party/team/keyring.d.ts +83 -35
- package/dist/with-party/team/{managed-passphrase.d.ts → managed-secret.d.ts} +27 -27
- package/dist/with-party/team/noydb-facade.d.ts +43 -42
- package/dist/with-party/team/peer-recover.d.ts +13 -13
- package/dist/with-party/team/recovery.d.ts +5 -5
- package/dist/with-party/team/rotate-recover.d.ts +30 -30
- package/dist/with-pod/bundle.d.ts +30 -32
- package/dist/with-pod/format.d.ts +2 -2
- package/dist/with-pod/index.d.ts +2 -1
- package/dist/with-shape/blobs/blob-compaction.d.ts +43 -3
- package/dist/with-shape/blobs/blob-pinning.d.ts +112 -0
- package/dist/with-shape/blobs/blob-set.d.ts +86 -2
- package/dist/with-shape/introspection/index.d.ts +6 -0
- package/dist/with-shape/schema-update/index.d.ts +1 -0
- package/dist/with-store/index.d.ts +3 -2
- package/dist/with-store/route-store.d.ts +1 -1
- package/dist/{with-party/team/sync-active.d.ts → with-sync/active.d.ts} +1 -1
- package/dist/{with-party/team/sync-credentials.d.ts → with-sync/credentials.d.ts} +3 -3
- package/dist/{with-party/team/sync.d.ts → with-sync/engine.d.ts} +5 -5
- package/dist/{with-party/sync → with-sync}/index.d.ts +4 -2
- package/dist/{with-party/team/sync-period-scope.d.ts → with-sync/period-scope.d.ts} +2 -2
- package/dist/{with-party/team → with-sync}/presence.d.ts +2 -2
- package/dist/{with-party/team/sync-strategy.d.ts → with-sync/strategy.d.ts} +6 -6
- package/dist/{with-party/team/sync-transaction.d.ts → with-sync/transaction.d.ts} +3 -3
- package/dist/withdraw-accessible-A2PWF5MZ.js +28 -0
- package/package.json +45 -36
- package/dist/aggregate/index.js.map +0 -1
- package/dist/api-IQFZJSQO.js +0 -20
- package/dist/as/index.js +0 -30
- package/dist/at/index.js +0 -1
- package/dist/bundle/index.js +0 -105
- package/dist/by/index.js +0 -11
- package/dist/chunk-2IALOXZS.js.map +0 -1
- package/dist/chunk-2MUZ3LY6.js +0 -205
- package/dist/chunk-2MUZ3LY6.js.map +0 -1
- package/dist/chunk-2P7EGNKF.js.map +0 -1
- package/dist/chunk-3PF6CRDT.js.map +0 -1
- package/dist/chunk-3SV2EPMN.js.map +0 -1
- package/dist/chunk-4BRCIYFG.js.map +0 -1
- package/dist/chunk-5OI6BR4H.js.map +0 -1
- package/dist/chunk-5WZXVULX.js.map +0 -1
- package/dist/chunk-6NQMXTYC.js.map +0 -1
- package/dist/chunk-6XE5TMPR.js.map +0 -1
- package/dist/chunk-7CI6CP7Z.js.map +0 -1
- package/dist/chunk-7O3AYBC7.js.map +0 -1
- package/dist/chunk-A5BDDEXK.js.map +0 -1
- package/dist/chunk-A7JJLVGH.js.map +0 -1
- package/dist/chunk-BGK233EA.js.map +0 -1
- package/dist/chunk-BMQWTQZ4.js.map +0 -1
- package/dist/chunk-BOKIKJJB.js.map +0 -1
- package/dist/chunk-CCOP5XDW.js.map +0 -1
- package/dist/chunk-CHFZDSE4.js +0 -1
- package/dist/chunk-DDHM2TLX.js.map +0 -1
- package/dist/chunk-GQNGCEP5.js.map +0 -1
- package/dist/chunk-GVZQ4NAM.js +0 -14
- package/dist/chunk-GVZQ4NAM.js.map +0 -1
- package/dist/chunk-GWKAVKHI.js.map +0 -1
- package/dist/chunk-HOONYZY2.js.map +0 -1
- package/dist/chunk-HPUWOVR7.js.map +0 -1
- package/dist/chunk-ISMV2QVG.js.map +0 -1
- package/dist/chunk-JBBSYJHP.js.map +0 -1
- package/dist/chunk-JRBNCUNT.js.map +0 -1
- package/dist/chunk-JZWWLLVY.js +0 -99
- package/dist/chunk-JZWWLLVY.js.map +0 -1
- package/dist/chunk-KUPKLSX5.js.map +0 -1
- package/dist/chunk-KWVJAOIN.js.map +0 -1
- package/dist/chunk-LB6OH6K2.js.map +0 -1
- package/dist/chunk-LB7FD65R.js +0 -163
- package/dist/chunk-LB7FD65R.js.map +0 -1
- package/dist/chunk-LOF2W3JU.js.map +0 -1
- package/dist/chunk-LSASLXGC.js.map +0 -1
- package/dist/chunk-O7WJ47EF.js.map +0 -1
- package/dist/chunk-ONTBCHCP.js.map +0 -1
- package/dist/chunk-PT37L5DV.js +0 -255
- package/dist/chunk-PT37L5DV.js.map +0 -1
- package/dist/chunk-RDXW3OBQ.js.map +0 -1
- package/dist/chunk-RND5ZPNP.js.map +0 -1
- package/dist/chunk-S3BFKGET.js.map +0 -1
- package/dist/chunk-SMGEYW6G.js.map +0 -1
- package/dist/chunk-T36RFODW.js.map +0 -1
- package/dist/chunk-TAGR72IR.js.map +0 -1
- package/dist/chunk-UNCOC7QH.js.map +0 -1
- package/dist/chunk-VCBHAE4R.js.map +0 -1
- package/dist/chunk-VEALDPHW.js.map +0 -1
- package/dist/chunk-VQNJ7UZL.js.map +0 -1
- package/dist/chunk-W2OG6JOL.js.map +0 -1
- package/dist/chunk-WNGGJWF7.js.map +0 -1
- package/dist/chunk-YJV2UZ7H.js.map +0 -1
- package/dist/chunk-YMUGBZN2.js.map +0 -1
- package/dist/chunk-YTGDPCPW.js.map +0 -1
- package/dist/chunk-ZEQWCBCM.js.map +0 -1
- package/dist/collection-facade-MJXSC3Q6.js +0 -44
- package/dist/cover-B5SJDHR3.js +0 -52
- package/dist/delegation-A5A75KQO.js +0 -25
- package/dist/derive-HJSMH7RA.js +0 -21
- package/dist/executor-AXE4XMLT.js +0 -26
- package/dist/executor-KGNLJD6M.js +0 -9
- package/dist/executor-XGIS6CR7.js +0 -9
- package/dist/export-accessible-VVBJM3MM.js +0 -23
- package/dist/extract-partition-LGGBTQET.js +0 -38
- package/dist/find-YS6XWB46.js +0 -11
- package/dist/in/index.js +0 -1
- package/dist/issue-LSR5PS6H.js +0 -19
- package/dist/legacy/bundle.d.ts +0 -30
- package/dist/liberate-GBSAYLPJ.js +0 -24
- package/dist/noydb-MTUBMWFE.js +0 -70
- package/dist/on/index.js +0 -17
- package/dist/port/as/index.d.ts +0 -26
- package/dist/port/at/index.d.ts +0 -18
- package/dist/port/in/index.d.ts +0 -21
- package/dist/port/on/index.d.ts +0 -27
- package/dist/port/ui/index.d.ts +0 -21
- package/dist/port/with/index.d.ts +0 -18
- package/dist/register-X462DNDM.js +0 -23
- package/dist/registry-3XMCT7MQ.js +0 -18
- package/dist/registry-KHD2I3M2.js +0 -19
- package/dist/registry-NPOWJHC4.js +0 -9
- package/dist/request-withdrawal-U7K3JTMY.js +0 -31
- package/dist/revoke-OCWDSWRQ.js +0 -24
- package/dist/seed-PWK45HDF.js.map +0 -1
- package/dist/signer-3YFBLZRN.js +0 -25
- package/dist/storage-W3GURVFU.js +0 -23
- package/dist/tx/index.js.map +0 -1
- package/dist/ui/index.js +0 -1
- package/dist/with/index.js +0 -31
- package/dist/with-lookup/aggregate/index.d.ts +0 -23
- package/dist/withdraw-accessible-Y3B2535F.js +0 -28
- /package/dist/{api-IQFZJSQO.js.map → api-ZDKTWNBB.js.map} +0 -0
- /package/dist/{backup-LU2DTZTI.js.map → backup-2UX7PRM5.js.map} +0 -0
- /package/dist/{chunk-IY23KFNZ.js.map → chunk-35NMVJ7I.js.map} +0 -0
- /package/dist/{chunk-RTEK4C4I.js.map → chunk-4JQK3L4V.js.map} +0 -0
- /package/dist/{chunk-3ELCWU56.js.map → chunk-4ZKNC6A6.js.map} +0 -0
- /package/dist/{chunk-VAIS3SOM.js.map → chunk-55LX6FSX.js.map} +0 -0
- /package/dist/{chunk-6HPG2YNX.js.map → chunk-5DRROK5W.js.map} +0 -0
- /package/dist/{chunk-S6Q37VGE.js.map → chunk-5GQEU4DN.js.map} +0 -0
- /package/dist/{chunk-TOPYT5U5.js.map → chunk-63FE525P.js.map} +0 -0
- /package/dist/{chunk-JVBO4SZL.js.map → chunk-6UBZ6I5Z.js.map} +0 -0
- /package/dist/{chunk-UFEVO57O.js.map → chunk-ABS7FMMD.js.map} +0 -0
- /package/dist/{chunk-M75ZZHSR.js.map → chunk-BLBAQRBM.js.map} +0 -0
- /package/dist/{chunk-G6EQYAL6.js.map → chunk-CI32CAFS.js.map} +0 -0
- /package/dist/{chunk-6B4DYGWO.js.map → chunk-DABACXEF.js.map} +0 -0
- /package/dist/{chunk-F6T6L2UK.js.map → chunk-DMH3VZU5.js.map} +0 -0
- /package/dist/{chunk-MQ6WOPSY.js.map → chunk-DZ2JXHWK.js.map} +0 -0
- /package/dist/{chunk-UBNCR3YK.js.map → chunk-EE7UHLKH.js.map} +0 -0
- /package/dist/{chunk-EGCRBCNA.js.map → chunk-EKRSCRNM.js.map} +0 -0
- /package/dist/{chunk-IRQY7IR5.js.map → chunk-FRMPM7WG.js.map} +0 -0
- /package/dist/{as/index.js.map → chunk-GJW4HX2O.js.map} +0 -0
- /package/dist/{chunk-T6GU5PPZ.js.map → chunk-GU3IP74F.js.map} +0 -0
- /package/dist/{chunk-SMIRGMS7.js.map → chunk-IXNCZTWA.js.map} +0 -0
- /package/dist/{chunk-RM2XV574.js.map → chunk-IXTSNGYY.js.map} +0 -0
- /package/dist/{chunk-PK6QCH2C.js.map → chunk-JJZGIE4U.js.map} +0 -0
- /package/dist/{chunk-DRWBEDYO.js.map → chunk-JYJFGD2H.js.map} +0 -0
- /package/dist/{chunk-KUIB4B5Q.js.map → chunk-LNZKOUJR.js.map} +0 -0
- /package/dist/{chunk-IM3QVF53.js.map → chunk-MBKVNOJS.js.map} +0 -0
- /package/dist/{chunk-N6WF5PKC.js.map → chunk-NFZGZ4AK.js.map} +0 -0
- /package/dist/{chunk-OF75ACKS.js.map → chunk-PEATRIYJ.js.map} +0 -0
- /package/dist/{chunk-N55W7KUL.js.map → chunk-QDIH2744.js.map} +0 -0
- /package/dist/{chunk-6HY2X62D.js.map → chunk-QJNCB5SK.js.map} +0 -0
- /package/dist/{chunk-2PCAVW2I.js.map → chunk-SHEEBRZ4.js.map} +0 -0
- /package/dist/{chunk-RA5VTXXG.js.map → chunk-V6UQZA2H.js.map} +0 -0
- /package/dist/{chunk-QDPZWTN2.js.map → chunk-W3G5REIU.js.map} +0 -0
- /package/dist/{chunk-WEYZTLXN.js.map → chunk-W3L64Y3J.js.map} +0 -0
- /package/dist/{chunk-CBSY2N76.js.map → chunk-WLXMTYGO.js.map} +0 -0
- /package/dist/{chunk-3U3FBR7O.js.map → chunk-X3F5YJG2.js.map} +0 -0
- /package/dist/{classified-marker-WQVIJAW2.js.map → classified-marker-7PKJBFCG.js.map} +0 -0
- /package/dist/{at/index.js.map → collection-facade-6I5K5IOD.js.map} +0 -0
- /package/dist/{bundle/index.js.map → computed-AB45PS4V.js.map} +0 -0
- /package/dist/{by → cover}/index.js.map +0 -0
- /package/dist/{in → custody}/index.js.map +0 -0
- /package/dist/{dead-filter-2A7IAJ3D.js.map → dead-filter-FL3WIUZS.js.map} +0 -0
- /package/dist/{chunk-CHFZDSE4.js.map → derive-VGS7FKE3.js.map} +0 -0
- /package/dist/{on → directory}/index.js.map +0 -0
- /package/dist/{collection-facade-MJXSC3Q6.js.map → enclave-SPEEDYZ4.js.map} +0 -0
- /package/dist/{computed-DSMPXG2Y.js.map → executor-IEBLTBCW.js.map} +0 -0
- /package/dist/{cover-B5SJDHR3.js.map → executor-OTF556PL.js.map} +0 -0
- /package/dist/{delegation-A5A75KQO.js.map → executor-RM7XWQDU.js.map} +0 -0
- /package/dist/{derive-HJSMH7RA.js.map → export-accessible-P42BQ4PB.js.map} +0 -0
- /package/dist/{enclave-7MW6ZGXW.js.map → extract-partition-TCYXRWBN.js.map} +0 -0
- /package/dist/{fanout-sidecar-WDYQ77VB.js.map → fanout-sidecar-SSMRSC2L.js.map} +0 -0
- /package/dist/{executor-AXE4XMLT.js.map → find-OZMTRIK3.js.map} +0 -0
- /package/dist/{ui → introspection}/index.js.map +0 -0
- /package/dist/{executor-KGNLJD6M.js.map → issue-FCKN5O6C.js.map} +0 -0
- /package/dist/{executor-XGIS6CR7.js.map → ledger-6XBEVWYP.js.map} +0 -0
- /package/dist/{export-accessible-VVBJM3MM.js.map → liberate-CYUOS4NC.js.map} +0 -0
- /package/dist/{extract-partition-LGGBTQET.js.map → link-set-NK6L2A5S.js.map} +0 -0
- /package/dist/{with → money}/index.js.map +0 -0
- /package/dist/{find-YS6XWB46.js.map → noydb-FZZIMLCI.js.map} +0 -0
- /package/dist/{issue-LSR5PS6H.js.map → policy/index.js.map} +0 -0
- /package/dist/{post-register-JVTMJ6OW.js.map → post-register-VFIYISUK.js.map} +0 -0
- /package/dist/{ledger-33BC4TR7.js.map → register-UKU2J6MN.js.map} +0 -0
- /package/dist/{liberate-GBSAYLPJ.js.map → registry-2VCWVHZS.js.map} +0 -0
- /package/dist/{link-set-QK22TDEX.js.map → registry-7Y5WF7GS.js.map} +0 -0
- /package/dist/{noydb-MTUBMWFE.js.map → registry-BWD2ED52.js.map} +0 -0
- /package/dist/{policy-NAHB2TUT.js.map → registry-DTWRJLSF.js.map} +0 -0
- /package/dist/{register-X462DNDM.js.map → request-withdrawal-JYDZ5XY2.js.map} +0 -0
- /package/dist/{reveal-LGBOM2BO.js.map → reveal-CL2BCW6A.js.map} +0 -0
- /package/dist/{registry-3XMCT7MQ.js.map → revoke-2TSAD2T4.js.map} +0 -0
- /package/dist/{registry-KHD2I3M2.js.map → schema-update/index.js.map} +0 -0
- /package/dist/{registry-NPOWJHC4.js.map → search/index.js.map} +0 -0
- /package/dist/{registry-VW6P6A3J.js.map → sequence/index.js.map} +0 -0
- /package/dist/{request-withdrawal-U7K3JTMY.js.map → signer-K7Z2EOMG.js.map} +0 -0
- /package/dist/{revoke-OCWDSWRQ.js.map → stale-A4J26OIC.js.map} +0 -0
- /package/dist/{signer-3YFBLZRN.js.map → storage-YVHZUISN.js.map} +0 -0
- /package/dist/{stale-FJED42DM.js.map → store/index.js.map} +0 -0
- /package/dist/{store-coordination-provider-APODTV4W.js.map → store-coordination-provider-EWRZL7XF.js.map} +0 -0
- /package/dist/{verify-26Y5GNMK.js.map → verify-7XWHJWUN.js.map} +0 -0
- /package/dist/{storage-W3GURVFU.js.map → walk-P5D6CF4V.js.map} +0 -0
- /package/dist/with-lookup/{aggregate → reduce}/canonical-key.d.ts +0 -0
- /package/dist/{with-party → with-sync}/tab-coordination.d.ts +0 -0
- /package/dist/{with-party → with-sync}/tab-write-relay.d.ts +0 -0
- /package/dist/{withdraw-accessible-Y3B2535F.js.map → withdraw-accessible-A2PWF5MZ.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/with-lookup/indexing/strategy.ts","../src/with-lookup/indexing/persisted-indexes.ts","../src/with-lookup/indexing/lazy-builder.ts"],"sourcesContent":["/**\n * Strategy seam between core Collection and the optional indexing\n * service. Core imports `IndexingStrategy` and `IndexState` as\n * TYPE-ONLY symbols and `NO_INDEXING` as a tiny runtime stub.\n *\n * The heavy classes — `CollectionIndexes`, `PersistedCollectionIndex`,\n * `LazyQuery` — are only instantiated inside the `withIndexing()`\n * factory under `./active.ts`, which in turn is only reachable through\n * the `@noy-db/hub/indexing` subpath export. A consumer that never\n * imports the subpath ships none of those classes in their bundle\n * (ESM tree-shaking + hub's `\"sideEffects\": false`).\n *\n * @internal\n */\n\nimport type { CollectionIndexes, IndexDef } from './eager-indexes.js'\nimport type { PersistedCollectionIndex } from './persisted-indexes.js'\n\n/**\n * Per-collection container for whatever mirrors the active strategy\n * decided to materialize. Both accessors may return `null` — they do\n * for `NO_INDEXING`, and `getEagerIndexes` returns null in a\n * lazy-mode collection even when indexing is active (lazy uses the\n * persisted mirror instead).\n *\n * `isEnabled` is a cheap guard so collection code can short-circuit\n * the full indexing path without inspecting either mirror.\n *\n * @internal\n */\nexport interface IndexState {\n readonly isEnabled: boolean\n getEagerIndexes(): CollectionIndexes | null\n getPersistedIndexes(): PersistedCollectionIndex | null\n}\n\n/**\n * Factory that builds one `IndexState` per Collection. Called exactly\n * once inside each Collection constructor with the declared\n * `IndexDef[]` and the lazy-mode flag (so lazy collections get the\n * persisted mirror and eager collections get the in-memory one).\n *\n * @internal\n */\nexport interface IndexingStrategy {\n createState(args: {\n readonly defs: readonly IndexDef[]\n readonly lazy: boolean\n }): IndexState\n}\n\n/**\n * No-indexing stub. Every Collection defaults to this; it returns a\n * cheap `IndexState` whose mirrors are both `null`. Collection code\n * null-checks both accessors and short-circuits, so no indexing code\n * path runs and the heavy classes never arrive in the bundle.\n *\n * @internal\n */\nexport const NO_INDEXING: IndexingStrategy = {\n createState() {\n return DISABLED_STATE\n },\n}\n\nconst DISABLED_STATE: IndexState = {\n isEnabled: false,\n getEagerIndexes: () => null,\n getPersistedIndexes: () => null,\n}\n","/**\n * Persistent, encrypted secondary indexes for lazy-mode collections.\n *\n * Parallel to the in-memory `CollectionIndexes` used by eager mode (see\n * `packages/hub/src/query/indexes.ts`): same logical surface, but entries\n * are materialised as encrypted side-car records (`_idx/<field>/<recordId>`)\n * and bulk-loaded into an in-memory mirror on first query.\n *\n * This module only owns the id-namespace convention, the in-memory mirror,\n * and the typed errors. Write-path integration (PR 2 / ), query-planner\n * dispatch (PR 3 / , PR 4 / ), and the rebuild/reconcile utilities\n * (PR 5 / ) live in other files.\n *\n * See the design spec for the full architecture + threat model.\n */\n\n/**\n * Reserved id prefix for encrypted index side-car records.\n * Matches the existing `_keyring`, `_ledger_deltas/…`, `_meta/handle`\n * conventions inside a collection's id namespace.\n */\nexport const IDX_PREFIX = '_idx/' as const\n\n/**\n * Encode the side-car record id for a (field, recordId) pair.\n *\n * Format: `_idx/<field>/<recordId>` — no escaping. Field names may contain\n * dots (for dotted-path access consistent with eager-mode `readPath`);\n * record ids may contain slashes. The first two slash-separated segments\n * are `_idx` and the field; everything after the *second* slash is the\n * record id verbatim.\n */\nexport function encodeIdxId(field: string, recordId: string): string {\n return `${IDX_PREFIX}${field}/${recordId}`\n}\n\n/**\n * Decode a side-car id back into `{ field, recordId }`, or `null` if the\n * input is not a well-formed idx id. A well-formed id is:\n * - prefixed with `_idx/`\n * - contains a field segment (non-empty, no slashes)\n * - contains a record-id segment (non-empty, may contain slashes)\n */\nexport function decodeIdxId(id: string): { field: string; recordId: string } | null {\n if (!id.startsWith(IDX_PREFIX)) return null\n const rest = id.slice(IDX_PREFIX.length)\n const firstSlash = rest.indexOf('/')\n if (firstSlash <= 0) return null\n const field = rest.slice(0, firstSlash)\n const recordId = rest.slice(firstSlash + 1)\n if (recordId.length === 0) return null\n return { field, recordId }\n}\n\n/**\n * Fast-path predicate for discriminating side-car ids from regular record\n * ids and other reserved namespaces. Used by the hub to filter `list()`\n * results during bulk-load of the in-memory mirror.\n */\nexport function isIdxId(id: string): boolean {\n return decodeIdxId(id) !== null\n}\n\n/**\n * Sorted-value entry returned by `orderedBy()`. Mirrors the body shape\n * used by the write path — but `orderedBy` emits them already sorted by\n * `value` in the requested direction. Consumers (PR 4 / ) treat the\n * array as immutable and paginate via a numeric offset.\n *\n * **Note on `value`:** as of, this is the ORIGINAL TYPED\n * value (number, Date, boolean, etc.), not the stringified bucket key.\n * That's what lets range predicates and `orderedBy` compare numerically\n * instead of stumbling into `'10' < '2'` on `String(n)`.\n */\nexport interface OrderedEntry {\n readonly recordId: string\n readonly value: unknown\n}\n\n/**\n * Bulk-load row shape accepted by `ingest()`. The `value` field is the\n * decrypted index body's `value` field verbatim.\n */\nexport interface IngestRow {\n readonly recordId: string\n readonly value: unknown\n}\n\n/**\n * In-memory mirror of the persisted index side-car records for a single\n * collection. Populated by bulk-loading `_idx/<field>/*` ids on first\n * query and maintained incrementally by `Collection.put()` / `.delete()`\n * via `upsert()` / `remove()`.\n *\n * API surface is deliberately parallel to `CollectionIndexes` (eager mode)\n * so the query planner in PR 3/4 can dispatch to either polymorphically.\n *\n * Lifecycle:\n * - `declare(field)` — accept the field as indexable (idempotent)\n * - `ingest(field, rows[])` — bulk-load from decrypted index bodies\n * - `upsert(recordId, field, newValue, previousValue)` — incremental update\n * - `remove(recordId, field, value)` — incremental remove\n * - `lookupEqual(field, value)` / `lookupIn(field, values)` — equality reads\n * - `orderedBy(field, dir)` — sorted iteration for orderBy\n * - `clear()` — drop all buckets (invalidation / rotation)\n */\n/**\n * Per-field storage: the equality bucket map AND a parallel table of typed\n * values keyed by recordId. The typed table exists so range predicates\n * and `orderedBy` can compare on the original typed value rather\n * than the stringified bucket key — String(10) < String(2) is the classic\n * landmine `stringifyKey` introduces for numeric fields.\n */\ninterface PersistedFieldState {\n readonly buckets: Map<string, Set<string>>\n readonly values: Map<string, unknown>\n}\n\n/**\n * Structured index definition. Single-field indexes carry just a field\n * name; composite indexes carry the ordered list of fields and\n * the synthetic `key` (= fields joined by `COMPOSITE_DELIMITER`) used\n * as the bucket-map key and side-car envelope id segment.\n */\nexport type PersistedIndexDef =\n | { readonly kind: 'single'; readonly field: string; readonly key: string }\n | { readonly kind: 'composite'; readonly fields: readonly string[]; readonly key: string }\n\n/**\n * Delimiter used to synthesize a composite-index key from an ordered\n * field list. Intentionally a character that is extremely unusual in\n * JavaScript object keys (`|`) so collision with a literal field name\n * is vanishingly rare in practice. Composite declarations whose field\n * names contain `|` are rejected at declare-time with an explicit\n * error.\n */\nexport const COMPOSITE_DELIMITER = '|'\n\nexport function compositeKey(fields: readonly string[]): string {\n return fields.join(COMPOSITE_DELIMITER)\n}\n\nexport class PersistedCollectionIndex {\n private readonly indexes = new Map<string, PersistedFieldState>()\n private readonly defs = new Map<string, PersistedIndexDef>()\n\n /**\n * Per-field bucket-key canonicalizer (#677 — lazy twin of #672's\n * `CollectionIndexes.setCanonicalizer`), registered ONCE via\n * {@link setCanonicalizer} when the collection wires indexing up\n * (money-aware via `ViaPipeline.canonicalizeIndexKey`). Consulted by\n * EVERY bucket-mutation site — `ingest`/`upsert`/`remove` — so bucket\n * membership is symmetric: a legacy non-canonical stored value (e.g.\n * `'0100'`) and a canonical one (`'100'`) land in the SAME bucket,\n * mirroring `eager-indexes.ts`'s `addToIndex`/`removeFromIndex`.\n */\n private canonicalize?: (field: string, value: unknown) => string | undefined\n\n /**\n * Register the bucket-key canonicalizer. Called once, where the\n * collection constructs its indexing state — safe to call again (the\n * closure is simply replaced) but there is normally only one caller.\n */\n setCanonicalizer(fn: (field: string, value: unknown) => string | undefined): void {\n this.canonicalize = fn\n }\n\n /**\n * Declare a single-field index. Subsequent `upsert` / `ingest` calls\n * populate the in-memory mirror; calls before `declare` are no-ops\n * (tolerant bulk-load ordering). Idempotent.\n */\n declare(field: string): void {\n if (this.indexes.has(field)) return\n this.indexes.set(field, { buckets: new Map(), values: new Map() })\n this.defs.set(field, { kind: 'single', field, key: field })\n }\n\n /**\n * Declare a composite (multi-field) index. The synthetic\n * key is `fields.join('|')`; it doubles as the in-memory map key and\n * the `_idx/<key>/<recordId>` side-car field segment. Callers upsert\n * and lookup via the same `key` as single-field indexes, just with a\n * tuple value (JSON-stringified for bucketing).\n */\n declareComposite(fields: readonly string[]): void {\n if (fields.length === 0) {\n throw new Error('declareComposite: fields array must be non-empty')\n }\n for (const f of fields) {\n if (f.includes(COMPOSITE_DELIMITER)) {\n throw new Error(\n `declareComposite: field \"${f}\" contains the composite delimiter ` +\n `\"${COMPOSITE_DELIMITER}\" — pick a different field name or open an ` +\n `issue to add hash-based composite keys.`,\n )\n }\n }\n const key = compositeKey(fields)\n if (this.indexes.has(key)) return\n this.indexes.set(key, { buckets: new Map(), values: new Map() })\n this.defs.set(key, { kind: 'composite', fields: [...fields], key })\n }\n\n /**\n * Every declared index's structured definition. Collection walks this\n * when materialising side-cars on put/delete so it can extract a\n * single-field value or a composite tuple appropriately.\n */\n definitions(): PersistedIndexDef[] {\n return [...this.defs.values()]\n }\n\n /** True if `field` has been declared as indexable on this mirror. */\n has(field: string): boolean {\n return this.indexes.has(field)\n }\n\n /** All declared field names, in declaration order. */\n fields(): string[] {\n return [...this.indexes.keys()]\n }\n\n /**\n * Bulk-load the mirror from decrypted index bodies. Intended to be\n * called once per field after reading the collection's `_idx/<field>/*`\n * side-cars. Safe to call twice with the same rows — bucket Sets\n * deduplicate recordIds. If `field` is not declared, this is a no-op\n * (tolerates the case where bulk-load runs before `declare()` lands).\n */\n ingest(field: string, rows: readonly IngestRow[]): void {\n const state = this.indexes.get(field)\n if (!state) return\n for (const row of rows) {\n addToState(state, row.recordId, row.value, field, this.canonicalize)\n }\n }\n\n /**\n * Incrementally update a record's index entry for one field. Called by\n * `Collection.put()` after the main write succeeds. If\n * `previousValue` is non-null, the record is removed from the old\n * bucket first — this is the update path. Pass `null` for fresh adds.\n * No-op if the field is not declared.\n */\n upsert(recordId: string, field: string, newValue: unknown, previousValue: unknown): void {\n const state = this.indexes.get(field)\n if (!state) return\n if (previousValue !== null && previousValue !== undefined) {\n removeFromState(state, recordId, previousValue, field, this.canonicalize)\n }\n addToState(state, recordId, newValue, field, this.canonicalize)\n }\n\n /**\n * Remove a record from the index for one field. Called by\n * `Collection.delete()`. No-op if the field is not declared or\n * the record isn't in the bucket. Empty buckets are dropped to keep\n * the Map clean.\n */\n remove(recordId: string, field: string, value: unknown): void {\n const state = this.indexes.get(field)\n if (!state) return\n removeFromState(state, recordId, value, field, this.canonicalize)\n }\n\n /**\n * Drop all bucket data while preserving field declarations. Called on\n * invalidation (incoming sync changes, keyring rotation) — the next\n * query re-populates via `ingest`.\n */\n clear(): void {\n for (const state of this.indexes.values()) {\n state.buckets.clear()\n state.values.clear()\n }\n }\n\n /**\n * Equality lookup — return the set of record ids whose `field` matches\n * `value`. Returns `null` if the field is not declared (caller falls\n * back to scan or throws `IndexRequiredError`). Returns a shared empty\n * set if the field is declared but no record matches — that set MUST\n * NOT be mutated by the caller.\n *\n * `value` is bucketed via the plain {@link stringifyKey} — it is NOT\n * canonicalized here. Callers on a Via-covered field (money) canonicalize\n * `value` themselves BEFORE calling (see `lazy-builder.ts`'s\n * `resolveCandidateIds()`, #677) — the SAME caller-canonicalizes split\n * `eager-indexes.ts`'s `lookupEqual`/`lookupIn` use (see `kernel/query/\n * builder.ts`'s `candidateRecords()`), so probing here twice never\n * double-canonicalizes.\n */\n lookupEqual(field: string, value: unknown): ReadonlySet<string> | null {\n const state = this.indexes.get(field)\n if (!state) return null\n const key = stringifyKey(value)\n return state.buckets.get(key) ?? EMPTY_SET\n }\n\n /**\n * Set lookup — return the union of record ids whose `field` matches any\n * of `values`. Returns `null` if the field is not declared. Returns a\n * fresh (non-shared) Set — safe for the caller to mutate. Same\n * caller-canonicalizes contract as {@link lookupEqual} (#677).\n */\n lookupIn(field: string, values: readonly unknown[]): ReadonlySet<string> | null {\n const state = this.indexes.get(field)\n if (!state) return null\n const out = new Set<string>()\n for (const value of values) {\n const bucket = state.buckets.get(stringifyKey(value))\n if (bucket) for (const id of bucket) out.add(id)\n }\n return out\n }\n\n /**\n * Range lookup. Return record ids whose indexed value\n * satisfies the predicate. Comparison happens on the ORIGINAL TYPED\n * value carried in `state.values` — so numeric `<` sorts numerically,\n * not lexicographically on `String(n)`. Returns `null` if the field\n * is not declared.\n *\n * Supported ops: `'<'`, `'<='`, `'>'`, `'>='`, `'between'`. For\n * `'between'`, `value` is `[lo, hi]` and both bounds are inclusive\n * (matches the eager-mode operator contract in `predicate.ts`).\n *\n * NOT canonicalized (#677): this method compares `value` against the\n * ORIGINAL TYPED `state.values`, not a stringified bucket key, so a\n * `canonicalizeIndexKey`-shaped (`string | undefined`) result would not\n * even type-check as a bound here. This does NOT mirror eager mode the\n * way `lookupEqual`/`lookupIn` do: `moneyIndexProbe` (`via/money/\n * where.ts`) never emits a range probe, so EAGER mode's `candidateRecords`\n * never calls an index for a range clause and always scans.\n *\n * LAZY mode's `resolveCandidateIds()` (`lazy-builder.ts`) no longer\n * dispatches a Via-covered (e.g. money) range clause through THIS method\n * at all (#684) — it enumerates the field's indexed ids via `orderedBy()`\n * instead and leaves the raw/typed comparison here for the (now\n * Via-aware) post-filter to redo correctly in scaled-int space. A\n * NON-via range clause still dispatches through this method exactly as\n * before — the raw/typed comparison here is correct and sufficient for\n * fields with no decode-transforming Via binding.\n */\n lookupRange(\n field: string,\n op: '<' | '<=' | '>' | '>=' | 'between',\n value: unknown,\n ): ReadonlySet<string> | null {\n const state = this.indexes.get(field)\n if (!state) return null\n const out = new Set<string>()\n for (const [recordId, live] of state.values) {\n if (live === undefined || live === null) continue\n if (matchesRange(live, op, value)) out.add(recordId)\n }\n return out\n }\n\n /**\n * Sorted iteration — return every entry on `field` as an\n * `OrderedEntry[]`, sorted by the ORIGINAL TYPED value (no more\n * `'10' < '2'` surprises on numeric fields). Consumers paginate with\n * a numeric offset. `OrderedEntry.value` is the typed value.\n */\n orderedBy(field: string, dir: 'asc' | 'desc'): readonly OrderedEntry[] | null {\n const state = this.indexes.get(field)\n if (!state) return null\n const entries: OrderedEntry[] = []\n for (const [recordId, value] of state.values) {\n entries.push({ recordId, value })\n }\n entries.sort((a, b) => compareTyped(a.value, b.value))\n if (dir === 'desc') entries.reverse()\n return entries\n }\n}\n\nconst EMPTY_SET: ReadonlySet<string> = new Set()\n\n/**\n * Canonicalize a value into a bucket key. Deliberately identical to the\n * eager-mode `stringifyKey` in `query/indexes.ts` so semantics match. When\n * `query/indexes.ts` changes its coercion rules, update this in lockstep.\n *\n * null / undefined values are NOT indexed — callers who pass them to\n * `upsert` / `remove` short-circuit before reaching this function; the\n * sentinel here exists only to make `lookupEqual(field, null)` return\n * an empty bucket (rather than matching some arbitrary record).\n */\nfunction stringifyKey(value: unknown): string {\n if (value === null || value === undefined) return '\\0NULL\\0'\n if (typeof value === 'string') return value\n if (typeof value === 'number' || typeof value === 'boolean') return String(value)\n if (value instanceof Date) return value.toISOString()\n // composite index values are tuple arrays. JSON.stringify\n // gives a delimiter-safe, order-preserving canonical form so buckets\n // for `['c-A', '2026-Q1']` and `['c-A', '2026-Q2']` never collide.\n if (Array.isArray(value)) {\n const parts: string[] = []\n for (const el of value) parts.push(stringifyKey(el))\n return JSON.stringify(parts)\n }\n return '\\0OBJECT\\0'\n}\n\nfunction addToState(\n state: PersistedFieldState,\n recordId: string,\n value: unknown,\n field: string,\n canonicalize?: (field: string, value: unknown) => string | undefined,\n): void {\n if (value === null || value === undefined) return\n const key = canonicalize?.(field, value) ?? stringifyKey(value)\n let bucket = state.buckets.get(key)\n if (!bucket) {\n bucket = new Set()\n state.buckets.set(key, bucket)\n }\n bucket.add(recordId)\n state.values.set(recordId, value)\n}\n\nfunction removeFromState(\n state: PersistedFieldState,\n recordId: string,\n value: unknown,\n field: string,\n canonicalize?: (field: string, value: unknown) => string | undefined,\n): void {\n if (value === null || value === undefined) return\n const key = canonicalize?.(field, value) ?? stringifyKey(value)\n const bucket = state.buckets.get(key)\n if (bucket) {\n bucket.delete(recordId)\n if (bucket.size === 0) state.buckets.delete(key)\n }\n state.values.delete(recordId)\n}\n\n/**\n * Range-predicate comparator. Runs on the ORIGINAL TYPED value so numeric\n * fields sort numerically (not lexicographically on `String(n)`). ISO-8601\n * date strings already sort correctly lexicographically; Date instances\n * compare via `getTime()` before the string branch to keep the contract\n * honest regardless of which form survived serialization.\n */\nfunction matchesRange(\n live: unknown,\n op: '<' | '<=' | '>' | '>=' | 'between',\n bound: unknown,\n): boolean {\n if (op === 'between') {\n if (!Array.isArray(bound) || bound.length !== 2) return false\n return compareTyped(live, bound[0]) >= 0 && compareTyped(live, bound[1]) <= 0\n }\n const cmp = compareTyped(live, bound)\n switch (op) {\n case '<': return cmp < 0\n case '<=': return cmp <= 0\n case '>': return cmp > 0\n case '>=': return cmp >= 0\n }\n}\n\nfunction compareTyped(a: unknown, b: unknown): number {\n if (a === undefined || a === null) return b === undefined || b === null ? 0 : 1\n if (b === undefined || b === null) return -1\n if (typeof a === 'number' && typeof b === 'number') return a - b\n if (a instanceof Date && b instanceof Date) return a.getTime() - b.getTime()\n if (typeof a === 'string' && typeof b === 'string') return a < b ? -1 : a > b ? 1 : 0\n if (typeof a === 'boolean' && typeof b === 'boolean') {\n return a === b ? 0 : a ? 1 : -1\n }\n // Mixed/unsupported types: deliberately treat as equal so sort stays\n // stable. Matches the eager-mode `compareValues` contract in\n // builder.ts — we don't silently coerce arbitrary objects to strings\n // (which would be meaningless) nor throw (which would be hostile).\n return 0\n}\n","/**\n * Lazy-mode query builder.\n *\n * Companion to `Query<T>` in `builder.ts`, but built for collections in lazy\n * mode where `snapshot()` is unavailable — records live in the adapter and\n * are pulled on demand. Dispatches through `PersistedCollectionIndex` to\n * resolve a candidate record-id set, then decrypts only those records.\n *\n * Scope:\n * - `.where(field, '==' | 'in', value)` — dispatched through the index\n * - `.where(field, other-op, value)` — evaluated against the decrypted\n * candidate set (non-indexed ops still require the field to be indexed\n * — we need SOMETHING to scope the candidate set)\n * - `.orderBy(field, dir?)` — dispatched through `orderedBy` when no\n * `==`/`in` clause is present; otherwise applied as an in-memory sort\n * over the candidate set\n * - `.limit(n)` / `.offset(n)` — page slice after filtering\n * - `.toArray()` / `.first()` / `.count()` — terminals\n *\n * Every field referenced by a where or orderBy clause MUST be indexed;\n * otherwise `toArray()` throws `IndexRequiredError`. This is deliberate:\n * silent scan-fallback would hide the very performance cliff that lazy-mode\n * indexes exist to prevent (see `docs/architecture.md` §indexes).\n */\n\nimport type { Clause, FieldClause, Operator } from '../../kernel/query/predicate.js'\nimport { evaluateClause, readPath } from '../../kernel/query/predicate.js'\nimport type { PersistedCollectionIndex } from './persisted-indexes.js'\nimport { IndexRequiredError, FieldNotQueryableError } from '../../kernel/errors.js'\nimport type { QueryField } from '../../kernel/types.js'\nimport type { ViaPipeline } from '../../kernel/via/pipeline.js'\n\nexport interface LazyOrderBy {\n readonly field: string\n readonly direction: 'asc' | 'desc'\n}\n\n/**\n * Source abstraction the LazyQuery runs against. Collection implements it.\n * Kept minimal so the builder stays test-friendly.\n */\nexport interface LazyQuerySource<T> {\n readonly collectionName: string\n readonly persistedIndexes: PersistedCollectionIndex\n /**\n * Per-field bucket-key canonicalizer (#677 — lazy twin of the eager\n * `candidateRecords()` probe-resolution in `kernel/query/builder.ts`).\n * Consulted in `resolveCandidateIds()` for `==`/`in` clause values\n * BEFORE calling `lookupEqual`/`lookupIn`, so a mixed-era stored value\n * (money) probes the SAME canonical bucket the write path now\n * populates. A narrow closure — not the whole `ViaPipeline` — keeps\n * the with-lookup/kernel seam thin. `undefined` (no via, or no binding\n * covers the field) is the common case: falls back to the raw value,\n * unchanged from today.\n */\n canonicalizeIndexKey?(field: string, value: unknown): string | undefined\n /** Ensure `_idx/<field>/*` side-cars have been bulk-loaded into the mirror. */\n ensurePersistedIndexesLoaded(): Promise<void>\n /**\n * Decrypt one record by id in RAW (pre-`present()`, stored-form) shape,\n * or return null if it's gone (#684 — the raw-fetch seam). Used by the\n * post-filter (`toArray()`) so a `clause.via.evaluate` (e.g. money) sees\n * the same operand/actual-value space as eager's `filterRecords` — the\n * DECODED form (e.g. money's canonical decimal) is only materialized\n * for survivors, via {@link decodeRecord}.\n */\n getRawRecord(id: string): Promise<unknown>\n /**\n * Apply this collection's locale/virtual-field decode (`present()`) to a\n * RAW record already known to match — the output-side twin of\n * {@link getRawRecord}. Mirrors eager's `Query.decodeVia`.\n */\n decodeRecord(record: unknown): Promise<T>\n /**\n * This collection's compiled Via pipeline (money, i18n, …), read lazily\n * (a method, not a captured value) so a late `_setVia` (#666) is honored\n * — same closure discipline as {@link canonicalizeIndexKey}. `undefined`\n * when the collection has no Via-covered fields.\n */\n via(): ViaPipeline | undefined\n}\n\ninterface LazyPlan {\n readonly clauses: readonly FieldClause[]\n readonly orderBy: readonly LazyOrderBy[]\n readonly limit: number | undefined\n readonly offset: number\n}\n\nconst EMPTY_PLAN: LazyPlan = {\n clauses: [],\n orderBy: [],\n limit: undefined,\n offset: 0,\n}\n\nexport class LazyQuery<T, S extends keyof T = never, Q extends keyof T & string = never> {\n private readonly source: LazyQuerySource<T>\n private readonly plan: LazyPlan\n\n constructor(source: LazyQuerySource<T>, plan: LazyPlan = EMPTY_PLAN) {\n this.source = source\n this.plan = plan\n }\n\n where<V>(field: QueryField<T, S, Q>, op: Operator, value: V): LazyQuery<T, S, Q> {\n // A Via-covered field (e.g. money) compares in major units, BigInt-exact\n // in scaled space — same build-time operand rewrite + `clause.via`\n // attachment as `Query.where()` (`kernel/query/builder.ts`) and\n // `ScanBuilder.where()` (`kernel/query/scan-builder.ts`). Before #684\n // this method built a bare clause with no `clause.via` at all, so the\n // post-filter fell through to the generic (non-Via-aware) comparison —\n // see `toArray()` below for the raw-record post-filter this feeds.\n const via = this.source.via()\n // Consults the Via pipeline's posture BEFORE building a clause — same\n // gate as `Query.where()` (builder.ts) / `ScanBuilder.where()`\n // (scan-builder.ts): a field whose posture is `queryable: 'none'`\n // (e.g. a `blobFields` slot) throws `FieldNotQueryableError` here, at\n // the call site, instead of building a bare clause that later surfaces\n // as a deferred `IndexRequiredError` from `toArray()`.\n if (via?.postureFor(field)?.queryable === 'none') throw new FieldNotQueryableError(field)\n const viaClause = via?.buildClause(field, op, value)\n const clause: FieldClause = viaClause\n ? {\n type: 'field',\n field,\n op,\n value,\n via: {\n brand: viaClause.brand,\n payload: viaClause.payload,\n evaluate: (actual: unknown, evalOp: string) => via!.evaluateClause(viaClause, actual, evalOp),\n indexValue: via!.indexProbe(viaClause, op),\n },\n }\n : { type: 'field', field, op, value }\n return new LazyQuery<T, S, Q>(this.source, {\n ...this.plan,\n clauses: [...this.plan.clauses, clause],\n })\n }\n\n orderBy(field: QueryField<T, S>, direction: 'asc' | 'desc' = 'asc'): LazyQuery<T, S, Q> {\n return new LazyQuery<T, S, Q>(this.source, {\n ...this.plan,\n orderBy: [...this.plan.orderBy, { field, direction }],\n })\n }\n\n limit(n: number): LazyQuery<T, S, Q> {\n return new LazyQuery<T, S, Q>(this.source, { ...this.plan, limit: n })\n }\n\n offset(n: number): LazyQuery<T, S, Q> {\n return new LazyQuery<T, S, Q>(this.source, { ...this.plan, offset: n })\n }\n\n async toArray(): Promise<T[]> {\n await this.source.ensurePersistedIndexesLoaded()\n\n const touchedFields = collectTouchedFields(this.plan)\n const missingFields = touchedFields.filter(f => !isFieldIndexed(f, this.source.persistedIndexes))\n if (missingFields.length > 0) {\n throw new IndexRequiredError({\n collection: this.source.collectionName,\n touchedFields,\n missingFields,\n })\n }\n\n const candidateIds = this.resolveCandidateIds()\n if (candidateIds === null) {\n // No usable driver — every touched field is indexed but no clause\n // pins the candidate set. This happens when a query only uses\n // operators other than `==`/`in` and no `orderBy` clause is\n // present — we refuse to enumerate the whole index, because that\n // defeats the purpose of lazy mode.\n throw new IndexRequiredError({\n collection: this.source.collectionName,\n touchedFields,\n missingFields: touchedFields,\n })\n }\n\n // #684: post-filter the RAW record (mirrors eager's filterRecords on the\n // raw snapshot) so `clause.via.evaluate` sees the same stored-form\n // operand/actual-value space `buildClause` quantized into at where()\n // time. Survivors stay RAW here — #695 sorts them via-aware in that\n // same stored-form space (mirroring eager's `sortRecords(result, ...,\n // source.via, ...)` in `kernel/query/builder.ts`) before anything is\n // decoded (`present()`).\n const survivors: T[] = []\n for (const id of candidateIds) {\n const raw = await this.source.getRawRecord(id)\n if (raw === null) continue\n if (!matchesAll(raw, this.plan.clauses)) continue\n survivors.push(raw as T)\n }\n\n // #695: sort the RAW survivors via-aware — a money field's stored form\n // (scaled-integer string) sorts lexicographically wrong under the\n // generic comparator ('10.00' < '2.00' once decoded); `via.compareForOrder`\n // compares in the correct (BigInt-exact scaled) space, same as eager.\n const sorted = this.plan.orderBy.length > 0\n ? sortRecords(survivors, this.plan.orderBy, this.source.via())\n : survivors\n\n const offset = this.plan.offset > 0 ? this.plan.offset : 0\n const page = this.plan.limit === undefined\n ? sorted.slice(offset)\n : sorted.slice(offset, offset + this.plan.limit)\n\n // Decode only the final page — fewer decodes than the pre-#695 code,\n // which decoded every survivor before sorting/slicing.\n return Promise.all(page.map(r => this.source.decodeRecord(r)))\n }\n\n async first(): Promise<T | null> {\n const out = await this.limit(1).toArray()\n return out.length > 0 ? out[0]! : null\n }\n\n async count(): Promise<number> {\n const out = await this.toArray()\n return out.length\n }\n\n /**\n * Resolve the candidate record-id set to decrypt. Returns null when the\n * query has no usable driver — no `==`/`in` clause and no `orderBy`\n * clause that can scope the scan. Callers interpret null as\n * IndexRequiredError (see `toArray`).\n */\n private resolveCandidateIds(): readonly string[] | null {\n const idx = this.source.persistedIndexes\n\n // prefer a composite index when the query's `==`\n // clauses cover every field of one declared composite. The\n // composite mirror lookup is O(matches) vs single-field +\n // post-filter on the decrypted candidate set.\n const eqMap = new Map<string, unknown>()\n const viaFields = new Set<string>()\n for (const clause of this.plan.clauses) {\n if (clause.op === '==') {\n eqMap.set(clause.field, clause.value)\n // #696: the composite mirror buckets on `stringifyKey(tuple)` built\n // from the RAW clause values — the per-field money canonicalizer\n // (`canonicalizeIndexKey`) only ever keys off a single field name,\n // never the joined composite key, so a Via-covered field's tuple\n // slot never lands in the same bucket a canonical write produced.\n // Track which `==` fields are Via-covered so the composite branch\n // below can skip them and fall through to the single-field\n // Via-aware path (already correct for money) instead.\n if (clause.via) viaFields.add(clause.field)\n }\n }\n if (eqMap.size >= 2) {\n for (const def of idx.definitions()) {\n if (def.kind !== 'composite') continue\n if (def.fields.some(f => viaFields.has(f))) continue\n if (def.fields.every(f => eqMap.has(f))) {\n const tuple = def.fields.map(f => eqMap.get(f))\n const ids = idx.lookupEqual(def.key, tuple)\n if (ids) return [...ids]\n }\n }\n }\n\n for (const clause of this.plan.clauses) {\n if (clause.op === '==') {\n if (clause.via) {\n // #684: prefer `clause.via.indexValue` — the same STORED-form\n // probe operand eager's `candidateRecords()` resolves first\n // (`kernel/query/builder.ts`). `undefined` means the binding\n // declined to probe this op/payload (e.g. money multi-mode) — no\n // sound equality bucket exists. Eager's `candidateRecords()`\n // handles this by skipping the index-eligibility check for the\n // clause and falling back to a full scan (`builder.ts:1176`); the\n // lazy equivalent (#684 review-fix 2) is the same move the RANGE branch\n // below already makes — enumerate the field's full indexed id\n // set via `orderedBy` and let the (now via-aware) post-filter in\n // `toArray()` decide, instead of throwing `IndexRequiredError`.\n if (clause.via.indexValue === undefined) {\n const entries = idx.orderedBy(clause.field, 'asc')\n if (entries) return entries.map(e => e.recordId)\n continue\n }\n const ids = idx.lookupEqual(clause.field, clause.via.indexValue)\n if (ids) return [...ids]\n continue\n }\n // #677: canonicalize the probe value BEFORE the lookup — same\n // \"resolve before lookupEqual\" shape as eager's `candidateRecords()`,\n // but through the narrower `canonicalizeIndexKey` seam, used only on\n // this NON-via path. `undefined` (no via coverage) falls back to the\n // raw clause value, unchanged from today.\n const probe = this.source.canonicalizeIndexKey?.(clause.field, clause.value) ?? clause.value\n const ids = idx.lookupEqual(clause.field, probe)\n if (ids) return [...ids]\n } else if (clause.op === 'in' && Array.isArray(clause.value)) {\n if (clause.via) {\n // Same #684 review-fix 2 fallback as the `==` branch above — a via\n // payload that declines to probe (e.g. money multi-mode) still\n // has a sound candidate superset via `orderedBy`.\n if (clause.via.indexValue === undefined) {\n const entries = idx.orderedBy(clause.field, 'asc')\n if (entries) return entries.map(e => e.recordId)\n continue\n }\n if (!Array.isArray(clause.via.indexValue)) continue\n const ids = idx.lookupIn(clause.field, clause.via.indexValue)\n if (ids) return [...ids]\n continue\n }\n const probes = clause.value.map(v => this.source.canonicalizeIndexKey?.(clause.field, v) ?? v)\n const ids = idx.lookupIn(clause.field, probes)\n if (ids) return [...ids]\n } else if (isRangeOp(clause.op)) {\n if (clause.via) {\n // #684: a Via-covered range clause (e.g. money) cannot trust\n // `lookupRange` — it compares the ORIGINAL TYPED stored value,\n // wrong space for a binding whose stored form isn't directly\n // orderable that way (money: BigInt-exact scaled-int compare).\n // No binding emits a range `indexProbe` either (see\n // `moneyIndexProbe`), so there's no sound bucket lookup at all.\n // Enumerate the field's full indexed id set via `orderedBy` — the\n // same superset a scan would consider, just scoped to indexed ids\n // — and let the (now via-aware) post-filter in `toArray()` apply\n // the correct scaled-space comparison. Replaces the old\n // \"always trust lookupRange, no scan fallback\" gap.\n const entries = idx.orderedBy(clause.field, 'asc')\n if (entries) return entries.map(e => e.recordId)\n continue\n }\n // range predicates on a NON-via indexed field dispatch through\n // `lookupRange`, which compares on the original typed value (no\n // numeric-lexicographic landmines).\n const ids = idx.lookupRange(clause.field, clause.op, clause.value)\n if (ids) return [...ids]\n }\n }\n\n // No equality/range driver — try to scope via orderBy.\n if (this.plan.orderBy.length > 0) {\n const primary = this.plan.orderBy[0]!\n const entries = idx.orderedBy(primary.field, primary.direction)\n if (entries) return entries.map(e => e.recordId)\n }\n\n return null\n }\n}\n\n/**\n * True if the given field name is covered by either a single-field\n * index or appears as a component of a declared composite index.\n * Composite coverage is sufficient for the missing-field check because\n * composite writes also maintain the in-memory mirror — the range /\n * orderBy / single-equality lookup paths fall through to decrypted\n * candidates that still get post-filtered by the composite clause.\n */\nfunction isFieldIndexed(field: string, idx: PersistedCollectionIndex): boolean {\n if (idx.has(field)) return true\n for (const def of idx.definitions()) {\n if (def.kind === 'composite' && def.fields.includes(field)) return true\n }\n return false\n}\n\nfunction isRangeOp(op: Operator): op is '<' | '<=' | '>' | '>=' | 'between' {\n return op === '<' || op === '<=' || op === '>' || op === '>=' || op === 'between'\n}\n\nfunction collectTouchedFields(plan: LazyPlan): string[] {\n const seen = new Set<string>()\n for (const c of plan.clauses) seen.add(c.field)\n for (const o of plan.orderBy) seen.add(o.field)\n return [...seen]\n}\n\nfunction matchesAll(record: unknown, clauses: readonly Clause[]): boolean {\n for (const c of clauses) {\n if (!evaluateClause(record, c)) return false\n }\n return true\n}\n\nfunction sortRecords<T>(records: T[], orderBy: readonly LazyOrderBy[], via?: ViaPipeline): T[] {\n return [...records].sort((a, b) => {\n for (const { field, direction } of orderBy) {\n const av = readPath(a, field)\n const bv = readPath(b, field)\n // #695: a Via-covered field (e.g. money) may store a representation\n // the generic comparator would order wrong — ask the pipeline for an\n // exact ordering first, same as eager's `sortRecords` in\n // `kernel/query/builder.ts`. `undefined` (no via, or the field isn't\n // covered) falls back to the generic comparator, unchanged from today.\n const viaCmp = via?.compareForOrder(field, av, bv)\n const cmp = viaCmp !== undefined ? viaCmp : compareValues(av, bv)\n if (cmp !== 0) return direction === 'asc' ? cmp : -cmp\n }\n return 0\n })\n}\n\nfunction compareValues(a: unknown, b: unknown): number {\n if (a === undefined || a === null) return b === undefined || b === null ? 0 : 1\n if (b === undefined || b === null) return -1\n if (typeof a === 'number' && typeof b === 'number') return a - b\n if (typeof a === 'string' && typeof b === 'string') return a < b ? -1 : a > b ? 1 : 0\n if (a instanceof Date && b instanceof Date) return a.getTime() - b.getTime()\n return 0\n}\n"],"mappings":"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","names":["ids"]}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
pickLocale
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-TUXQSFHZ.js";
|
|
4
4
|
import {
|
|
5
5
|
sha256Hex
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-AKKRXT23.js";
|
|
7
7
|
import {
|
|
8
8
|
BundleIntegrityError,
|
|
9
9
|
BundleSealMismatchError,
|
|
10
10
|
ValidationError
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-QZWTRENR.js";
|
|
12
12
|
|
|
13
13
|
// src/with-pod/format.ts
|
|
14
14
|
var NOYDB_BUNDLE_MAGIC = new Uint8Array([78, 68, 66, 49]);
|
|
@@ -179,27 +179,27 @@ function hasNoydbBundleMagic(bytes) {
|
|
|
179
179
|
// src/with-pod/bundle.ts
|
|
180
180
|
function toAutoCredentials(m) {
|
|
181
181
|
return Object.fromEntries(
|
|
182
|
-
Object.entries(m).map(([u, value]) => [u, { kind: "
|
|
182
|
+
Object.entries(m).map(([u, value]) => [u, { kind: "secret", value }])
|
|
183
183
|
);
|
|
184
184
|
}
|
|
185
185
|
function normalizeAutoUnlock(opts) {
|
|
186
186
|
const set = [
|
|
187
187
|
opts.autoCredentials,
|
|
188
188
|
opts.sealedCredentials,
|
|
189
|
-
opts.
|
|
190
|
-
opts.
|
|
189
|
+
opts.autoSecrets,
|
|
190
|
+
opts.sealedSecrets
|
|
191
191
|
].filter((v) => v !== void 0).length;
|
|
192
192
|
if (set === 0) return null;
|
|
193
193
|
if (set > 1) {
|
|
194
194
|
throw new ValidationError(
|
|
195
|
-
"writePod: only one of autoCredentials / sealedCredentials /
|
|
195
|
+
"writePod: only one of autoCredentials / sealedCredentials / autoSecrets / sealedSecrets may be set."
|
|
196
196
|
);
|
|
197
197
|
}
|
|
198
198
|
if (opts.autoCredentials !== void 0) {
|
|
199
199
|
return { mode: "unsealed", perUser: opts.autoCredentials.perUser };
|
|
200
200
|
}
|
|
201
|
-
if (opts.
|
|
202
|
-
return { mode: "unsealed", perUser: toAutoCredentials(opts.
|
|
201
|
+
if (opts.autoSecrets !== void 0) {
|
|
202
|
+
return { mode: "unsealed", perUser: toAutoCredentials(opts.autoSecrets.perUser) };
|
|
203
203
|
}
|
|
204
204
|
if (opts.sealedCredentials !== void 0) {
|
|
205
205
|
if (opts.sealedCredentials.mode === "recipient-target") {
|
|
@@ -215,31 +215,31 @@ function normalizeAutoUnlock(opts) {
|
|
|
215
215
|
}
|
|
216
216
|
return {
|
|
217
217
|
mode: "sealed-self",
|
|
218
|
-
provider: opts.
|
|
219
|
-
perUser: toAutoCredentials(opts.
|
|
218
|
+
provider: opts.sealedSecrets.provider,
|
|
219
|
+
perUser: toAutoCredentials(opts.sealedSecrets.perUser)
|
|
220
220
|
};
|
|
221
221
|
}
|
|
222
222
|
function validateAutoUnlockOptions(opts, normalized) {
|
|
223
223
|
if (normalized === null) return null;
|
|
224
|
-
const VALID_KINDS = /* @__PURE__ */ new Set(["
|
|
224
|
+
const VALID_KINDS = /* @__PURE__ */ new Set(["secret", "password", "pin"]);
|
|
225
225
|
for (const [userId, cred] of Object.entries(normalized.perUser)) {
|
|
226
226
|
if (!VALID_KINDS.has(cred.kind)) {
|
|
227
227
|
throw new ValidationError(
|
|
228
|
-
`writePod: credential for user '${userId}' has unsupported kind '${cred.kind}'. auto-unlock supports
|
|
228
|
+
`writePod: credential for user '${userId}' has unsupported kind '${cred.kind}'. auto-unlock supports secret/password/pin only; WebAuthn is hardware-bound and cannot be bundled.`
|
|
229
229
|
);
|
|
230
230
|
}
|
|
231
231
|
}
|
|
232
232
|
if (normalized.mode === "unsealed") {
|
|
233
|
-
const policy = opts.autoCredentials?.policy ?? opts.
|
|
233
|
+
const policy = opts.autoCredentials?.policy ?? opts.autoSecrets?.policy;
|
|
234
234
|
if (policy !== "public-by-design") {
|
|
235
235
|
throw new ValidationError(
|
|
236
|
-
'writePod: `autoCredentials` (or `
|
|
236
|
+
'writePod: `autoCredentials` (or `autoSecrets`) requires `policy: "public-by-design"`. This is an explicit opt-in marker \u2014 bundling plaintext credentials is safe only when those credentials are intended to be public (demo data, sample vaults). For production credentials, use `sealedCredentials` instead.'
|
|
237
237
|
);
|
|
238
238
|
}
|
|
239
239
|
const userCount2 = Object.keys(normalized.perUser).length;
|
|
240
240
|
if (userCount2 === 0) {
|
|
241
241
|
throw new ValidationError(
|
|
242
|
-
"writePod: `autoCredentials.perUser` (or `
|
|
242
|
+
"writePod: `autoCredentials.perUser` (or `autoSecrets.perUser`) must have at least one entry."
|
|
243
243
|
);
|
|
244
244
|
}
|
|
245
245
|
return "unsealed";
|
|
@@ -286,21 +286,21 @@ function validateAutoUnlockOptions(opts, normalized) {
|
|
|
286
286
|
}
|
|
287
287
|
return "sealed";
|
|
288
288
|
}
|
|
289
|
-
const selfTargetMode = opts.sealedCredentials?.mode ?? opts.
|
|
289
|
+
const selfTargetMode = opts.sealedCredentials?.mode ?? opts.sealedSecrets?.mode;
|
|
290
290
|
if (selfTargetMode !== "self-target") {
|
|
291
291
|
throw new ValidationError(
|
|
292
|
-
`writePod: \`sealedCredentials.mode\` (or \`
|
|
292
|
+
`writePod: \`sealedCredentials.mode\` (or \`sealedSecrets.mode\`) must be 'self-target' or 'recipient-target' (got '${String(selfTargetMode)}').`
|
|
293
293
|
);
|
|
294
294
|
}
|
|
295
295
|
if (normalized.provider === void 0) {
|
|
296
296
|
throw new ValidationError(
|
|
297
|
-
"writePod: `sealedCredentials.provider` (or `
|
|
297
|
+
"writePod: `sealedCredentials.provider` (or `sealedSecrets.provider`) is required (a `SealingKeyProvider`)."
|
|
298
298
|
);
|
|
299
299
|
}
|
|
300
300
|
const userCount = Object.keys(normalized.perUser).length;
|
|
301
301
|
if (userCount === 0) {
|
|
302
302
|
throw new ValidationError(
|
|
303
|
-
"writePod: `sealedCredentials.perUser` (or `
|
|
303
|
+
"writePod: `sealedCredentials.perUser` (or `sealedSecrets.perUser`) must have at least one entry."
|
|
304
304
|
);
|
|
305
305
|
}
|
|
306
306
|
return "sealed";
|
|
@@ -430,7 +430,7 @@ function parseExtractedPartitionBody(bodyString) {
|
|
|
430
430
|
return { dump: obj["dump"], seal };
|
|
431
431
|
}
|
|
432
432
|
function coerceUnsealed(entry) {
|
|
433
|
-
if (typeof entry === "string") return { kind: "
|
|
433
|
+
if (typeof entry === "string") return { kind: "secret", value: entry };
|
|
434
434
|
return entry;
|
|
435
435
|
}
|
|
436
436
|
async function resolveAutoUnlock(blob, opts) {
|
|
@@ -444,7 +444,7 @@ async function resolveAutoUnlock(blob, opts) {
|
|
|
444
444
|
if (opts.sealingProviders === void 0 || opts.sealingProviders.length === 0) {
|
|
445
445
|
const passthrough = {};
|
|
446
446
|
for (const [userId, entry] of Object.entries(blob.perUser)) {
|
|
447
|
-
passthrough[userId] = { kind: entry.kind ?? "
|
|
447
|
+
passthrough[userId] = { kind: entry.kind ?? "secret", value: entry.sealed };
|
|
448
448
|
}
|
|
449
449
|
return { kind: "sealed", perUser: passthrough };
|
|
450
450
|
}
|
|
@@ -453,7 +453,7 @@ async function resolveAutoUnlock(blob, opts) {
|
|
|
453
453
|
const decoder = new TextDecoder();
|
|
454
454
|
const unsealedMap = {};
|
|
455
455
|
for (const [userId, entry] of Object.entries(blob.perUser)) {
|
|
456
|
-
const credKind = entry.kind ?? "
|
|
456
|
+
const credKind = entry.kind ?? "secret";
|
|
457
457
|
const provider = providersByPid.get(entry.pid);
|
|
458
458
|
if (provider === void 0) {
|
|
459
459
|
if (opts.attemptUnsealAcrossProviders === true) {
|
|
@@ -567,13 +567,13 @@ function concatBytes(parts) {
|
|
|
567
567
|
return out;
|
|
568
568
|
}
|
|
569
569
|
async function applyRecipientRewrap(vault, dumpJson, opts) {
|
|
570
|
-
if (opts.
|
|
570
|
+
if (opts.exportSecret === void 0 && opts.recipients === void 0) {
|
|
571
571
|
return dumpJson;
|
|
572
572
|
}
|
|
573
573
|
const recipients = opts.recipients ?? [
|
|
574
574
|
{
|
|
575
575
|
id: vault.userId,
|
|
576
|
-
|
|
576
|
+
secret: opts.exportSecret,
|
|
577
577
|
role: vault.role
|
|
578
578
|
}
|
|
579
579
|
];
|
|
@@ -613,7 +613,7 @@ async function applySatelliteLivenessFilter(vault, dumpJson) {
|
|
|
613
613
|
if (!backup.collections || typeof backup.collections !== "object") return dumpJson;
|
|
614
614
|
if (typeof vault._introspectState !== "function") return dumpJson;
|
|
615
615
|
const { adapter, name, getDEK } = vault._introspectState();
|
|
616
|
-
const { liveBaseIdSetsForBundle } = await import("./dead-filter-
|
|
616
|
+
const { liveBaseIdSetsForBundle } = await import("./dead-filter-FL3WIUZS.js");
|
|
617
617
|
const satLive = await liveBaseIdSetsForBundle(adapter, name, Object.keys(backup.collections), getDEK);
|
|
618
618
|
if (satLive.size === 0) return dumpJson;
|
|
619
619
|
const next = {};
|
|
@@ -689,9 +689,9 @@ async function assembleBundleContainer(opts) {
|
|
|
689
689
|
return concatBytes([prefix, headerBytes, body]);
|
|
690
690
|
}
|
|
691
691
|
async function writePod(vault, opts = {}) {
|
|
692
|
-
if (opts.
|
|
692
|
+
if (opts.exportSecret !== void 0 && opts.recipients !== void 0) {
|
|
693
693
|
throw new Error(
|
|
694
|
-
"writePod: pass either
|
|
694
|
+
"writePod: pass either exportSecret or recipients, not both"
|
|
695
695
|
);
|
|
696
696
|
}
|
|
697
697
|
const normalizedAutoUnlock = normalizeAutoUnlock(opts);
|
|
@@ -760,7 +760,6 @@ function readPodCover(bytes, opts = {}) {
|
|
|
760
760
|
...env.description !== void 0 ? { description: pickLocale(env.description, opts.locale, env.defaultLocale) } : {}
|
|
761
761
|
};
|
|
762
762
|
}
|
|
763
|
-
var readNoydbBundlePublicEnvelope = readPodCover;
|
|
764
763
|
async function readPod(bytes, opts = {}) {
|
|
765
764
|
const { header, bodyOffset, algo } = parsePrefixAndHeader(bytes);
|
|
766
765
|
const body = bytes.slice(bodyOffset);
|
|
@@ -819,8 +818,7 @@ export {
|
|
|
819
818
|
readPodHeader,
|
|
820
819
|
readNoydbBundleHeader,
|
|
821
820
|
readPodCover,
|
|
822
|
-
readNoydbBundlePublicEnvelope,
|
|
823
821
|
readPod,
|
|
824
822
|
readNoydbBundle
|
|
825
823
|
};
|
|
826
|
-
//# sourceMappingURL=chunk-
|
|
824
|
+
//# sourceMappingURL=chunk-LNPUSMZL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/with-pod/format.ts","../src/with-pod/bundle.ts"],"sourcesContent":["/**\n * `.noydb` container format — byte layout, header schema, validators.\n *\n *. Wraps a `vault.dump()` JSON string in a thin\n * binary container with a magic-byte prefix, a minimum-disclosure\n * unencrypted header, and a compressed body.\n *\n * **Byte layout** (read in order from offset 0):\n *\n * ```\n * +--------+--------+--------+--------+\n * | N=78 | D=68 | B=66 | 1=49 | Magic 'NDB1' (4 bytes)\n * +--------+--------+--------+--------+\n * | flags | compr | header_length (uint32 BE) |\n * +--------+--------+--------+--------+--------+--------+--------+\n * | header_length bytes of UTF-8 JSON header ...\n * +--------+--------+\n * | compressed body bytes ...\n * ```\n *\n * Total fixed prefix before the header JSON is **10 bytes**:\n * - 4 bytes magic\n * - 1 byte flags\n * - 1 byte compression algorithm\n * - 4 bytes header length (uint32 big-endian)\n *\n * **Why a binary container** at all? `vault.dump()` already\n * produces a JSON string with encrypted records inside. Wrapping it\n * again seems redundant — but the wrap is what makes the file safe\n * to drop into cloud storage (Drive, Dropbox, iCloud) without\n * leaking the vault name and exporter identity through the\n * cloud's metadata API. The minimum-disclosure header is the only\n * thing visible without downloading and decompressing the body.\n * The dump JSON inside the body still contains the original\n * metadata, but that's only readable by someone who already has the\n * file bytes — the same person who could read the encrypted records\n * with the right secret.\n *\n * **Why minimum disclosure** in the header? Because consumers will\n * inevitably store these in services where the filename, file size,\n * and any unencrypted metadata are indexed for search. A field like\n * `vault: \"Acme Corp\"` would let an attacker (or a curious\n * cloud admin) enumerate which compartments exist and who exported\n * them, even with zero access to the encrypted body. The header\n * carries only what's needed to identify the file as a NOYDB\n * bundle and verify its integrity — nothing about the contents.\n */\n\nimport type { Cover } from '../with-party/directory/cover/types.js'\n\n/** Magic bytes 'NDB1' (ASCII), identifying a NOYDB bundle. */\nexport const NOYDB_BUNDLE_MAGIC = new Uint8Array([0x4e, 0x44, 0x42, 0x31])\n\n/** Total fixed prefix before the header JSON: 4+1+1+4 bytes. */\nexport const NOYDB_BUNDLE_PREFIX_BYTES = 10\n\n/** Current bundle format version. Bumped on layout changes. */\nexport const NOYDB_BUNDLE_FORMAT_VERSION = 1\n\n/**\n * Bitfield interpretation of the flags byte.\n *\n * Bit 0 — body is compressed (0 = raw, 1 = compressed)\n * Bit 1 — header carries an integrity hash over the body bytes\n * Bits 2-7 — reserved, must be 0 in\n */\nexport const FLAG_COMPRESSED = 0b0000_0001\nexport const FLAG_HAS_INTEGRITY_HASH = 0b0000_0010\n\n/**\n * Compression algorithm encoding for the byte at offset 5.\n *\n * `none` is admitted for round-trip testing and for callers that\n * want to bundle without compression (e.g. when piping into a\n * separately compressed transport). `gzip` is the universally\n * available baseline (Node 18+, all modern browsers). `brotli` is\n * preferred when the runtime supports it — typically 30-50% smaller\n * for JSON payloads — but Node 22+ / Chrome 124+ / Firefox 122+\n * are required, so the writer feature-detects at runtime and falls\n * back to gzip. The reader must handle all three.\n */\nexport const COMPRESSION_NONE = 0\nexport const COMPRESSION_GZIP = 1\nexport const COMPRESSION_BROTLI = 2\n\nexport type CompressionAlgo = 0 | 1 | 2\n\n/**\n * The unencrypted header carried in every `.noydb` bundle.\n *\n * **Minimum-disclosure rules:** these are the ONLY allowed keys.\n * Any other key in a parsed header causes\n * `validateBundleHeader` to throw. The set is kept short to\n * minimize attack surface from cloud-storage metadata indexing —\n * see the file-level doc comment for the rationale.\n *\n * Forbidden in particular:\n * - `vault` / `_compartment` — would leak the tenant name\n * - `exporter` / `_exported_by` — would leak user identity\n * - `timestamp` / `_exported_at` — would leak activity timing\n * - `kdfParams` / salt fields — would leak crypto config that\n * could narrow brute-force search space\n * - any field starting with `_` (reserved by the dump format)\n */\nexport interface NoydbPodHeader {\n /** Bundle format version — bumped on layout changes. */\n readonly formatVersion: number\n /**\n * Opaque ULID identifier — generated once per vault and\n * stable across re-exports of the same vault. Does not\n * leak any information about contents (the timestamp prefix is\n * just monotonicity for sortability, not exporter activity —\n * see `bundle/ulid.ts` for the design notes).\n */\n readonly handle: string\n /** Compressed body length in bytes. Lets readers verify completeness without decompressing. */\n readonly bodyBytes: number\n /** SHA-256 of the compressed body bytes (lowercase hex). Lets readers verify integrity without decompressing. */\n readonly bodySha256: string\n /**\n * Owner-curated cover (`https://github.com/vLannaAi/noy-db-docs/blob/main/content/docs/services/public-envelope.md`).\n * Optional — present only when the source vault has a\n * `_meta/public-envelope` document AND the writer's hub is opted\n * into the feature. Treat as **untrusted hint**; the body's\n * encrypted contents remain the source of truth.\n *\n * The JSON key keeps its frozen wire name `publicEnvelope` (#799\n * renamed only the developer surface — existing bundles stay\n * readable byte-for-byte).\n *\n * The cover deliberately widens the minimum-disclosure rule\n * for explicit, owner-curated label fields (name, icon, …). Every\n * other unknown header key still rejects at parse time.\n */\n readonly publicEnvelope?: Cover\n /**\n * Auto-unlock material indicator. When present, the bundle\n * body wraps the dump JSON in a structure carrying per-user\n * secrets — either plaintext (`'unsealed'`, public-by-design)\n * or sealed under a `SealingKeyProvider` (`'sealed'`, requires\n * matching provider on the recipient side).\n *\n * Visible pre-decompression so cloud listing UIs can warn before\n * download: \"this bundle opens itself for anyone holding the file\"\n * (unsealed) or \"this bundle is sealed for a specific provider\"\n * (sealed).\n *\n * Absent → the body is a raw `vault.dump()` JSON string (the\n * the legacy shape; back-compatible).\n */\n readonly autoUnlock?: 'unsealed' | 'sealed'\n /**\n * Bundle's role in the source → destination lifecycle.\n * - omitted / 'snapshot' (default): backup/copy of an existing vault.\n * - 'extracted-partition': re-keyed projection awaiting adoption.\n */\n readonly bundleKind?: 'snapshot' | 'extracted-partition'\n /**\n * Transfer-seal INDICATOR — metadata only, no payload (the\n * sealed DEKs live in the body). Present iff\n * bundleKind === 'extracted-partition'.\n */\n readonly transferSeal?: {\n readonly v: 1\n readonly alg: 'aes-256-gcm-pre-shared'\n readonly sealId: string\n }\n}\n\n/** @deprecated Use `NoydbPodHeader`. */\nexport type NoydbBundleHeader = NoydbPodHeader\n\n/**\n * Allowlist of header keys. Any key not in this set is forbidden\n * and causes `validateBundleHeader` to throw. Kept as a Set for\n * O(1) lookup; the validator iterates over the parsed header and\n * checks each key against this set.\n */\nconst ALLOWED_HEADER_KEYS: ReadonlySet<string> = new Set([\n 'formatVersion',\n 'handle',\n 'bodyBytes',\n 'bodySha256',\n 'publicEnvelope',\n 'autoUnlock',\n 'bundleKind',\n 'transferSeal',\n])\n\n/**\n * Validate a parsed bundle header. Throws on any deviation from\n * the minimum-disclosure schema:\n *\n * - Missing required field\n * - Wrong type for any field\n * - Any extra key not in `ALLOWED_HEADER_KEYS`\n * - Unsupported `formatVersion`\n * - Negative or non-integer `bodyBytes`\n * - Malformed `handle` (must be 26-char Crockford base32)\n * - Malformed `bodySha256` (must be 64-char lowercase hex)\n *\n * The error messages name the offending field so consumers can\n * fix the producer rather than the reader.\n */\nexport function validateBundleHeader(\n parsed: unknown,\n): asserts parsed is NoydbPodHeader {\n if (parsed === null || typeof parsed !== 'object') {\n throw new Error(\n `.noydb bundle header must be a JSON object, got ${parsed === null ? 'null' : typeof parsed}`,\n )\n }\n // Disallow any unknown key — minimum disclosure means we reject\n // forward-compat extension keys at the format layer; new fields\n // require a format version bump and a new validator.\n for (const key of Object.keys(parsed)) {\n if (!ALLOWED_HEADER_KEYS.has(key)) {\n throw new Error(\n `.noydb bundle header contains forbidden key \"${key}\". ` +\n `Only minimum-disclosure fields are allowed: ` +\n `${[...ALLOWED_HEADER_KEYS].join(', ')}.`,\n )\n }\n }\n const h = parsed as Record<string, unknown>\n if (typeof h['formatVersion'] !== 'number' || h['formatVersion'] !== NOYDB_BUNDLE_FORMAT_VERSION) {\n throw new Error(\n `.noydb bundle header.formatVersion must be ${NOYDB_BUNDLE_FORMAT_VERSION}, ` +\n `got ${String(h['formatVersion'])}. The reader does not support ` +\n `forward-compat versions; upgrade the reader to handle newer bundles.`,\n )\n }\n if (typeof h['handle'] !== 'string' || !/^[0-9A-HJKMNP-TV-Z]{26}$/.test(h['handle'])) {\n throw new Error(\n `.noydb bundle header.handle must be a 26-character Crockford base32 ULID, ` +\n `got ${typeof h['handle'] === 'string' ? `\"${h['handle']}\"` : String(h['handle'])}.`,\n )\n }\n if (typeof h['bodyBytes'] !== 'number' || !Number.isInteger(h['bodyBytes']) || h['bodyBytes'] < 0) {\n throw new Error(\n `.noydb bundle header.bodyBytes must be a non-negative integer, ` +\n `got ${String(h['bodyBytes'])}.`,\n )\n }\n if (typeof h['bodySha256'] !== 'string' || !/^[0-9a-f]{64}$/.test(h['bodySha256'])) {\n throw new Error(\n `.noydb bundle header.bodySha256 must be a 64-character lowercase hex string, ` +\n `got ${typeof h['bodySha256'] === 'string' ? `\"${h['bodySha256']}\"` : String(h['bodySha256'])}.`,\n )\n }\n if (h['publicEnvelope'] !== undefined) {\n const env = h['publicEnvelope']\n if (env === null || typeof env !== 'object' || Array.isArray(env)) {\n throw new Error(\n `.noydb bundle header.publicEnvelope must be a JSON object when present, got ${typeof env}.`,\n )\n }\n const e = env as Record<string, unknown>\n if (e['_noydb_public'] !== 1) {\n throw new Error(\n `.noydb bundle header.publicEnvelope._noydb_public must be 1, got ${String(e['_noydb_public'])}.`,\n )\n }\n if (typeof e['version'] !== 'number' || !Number.isInteger(e['version']) || e['version'] < 1) {\n throw new Error(\n `.noydb bundle header.publicEnvelope.version must be a positive integer, got ${String(e['version'])}.`,\n )\n }\n }\n if (h['autoUnlock'] !== undefined) {\n if (h['autoUnlock'] !== 'unsealed' && h['autoUnlock'] !== 'sealed') {\n const got = typeof h['autoUnlock'] === 'string' ? `\"${h['autoUnlock']}\"` : typeof h['autoUnlock']\n throw new Error(\n `.noydb bundle header.autoUnlock must be 'unsealed' or 'sealed' when present, got ${got}.`,\n )\n }\n }\n if (h['bundleKind'] !== undefined) {\n if (h['bundleKind'] !== 'snapshot' && h['bundleKind'] !== 'extracted-partition') {\n const got = typeof h['bundleKind'] === 'string' ? `\"${h['bundleKind']}\"` : typeof h['bundleKind']\n throw new Error(\n `.noydb bundle header.bundleKind must be 'snapshot' or 'extracted-partition' when present, got ${got}.`,\n )\n }\n }\n if (h['transferSeal'] !== undefined) {\n const ts = h['transferSeal']\n if (ts === null || typeof ts !== 'object' || Array.isArray(ts)) {\n throw new Error(`.noydb bundle header.transferSeal must be a JSON object when present, got ${typeof ts}.`)\n }\n const t = ts as Record<string, unknown>\n if (t['v'] !== 1) {\n throw new Error(`.noydb bundle header.transferSeal.v must be 1, got ${String(t['v'])}.`)\n }\n if (t['alg'] !== 'aes-256-gcm-pre-shared') {\n throw new Error(`.noydb bundle header.transferSeal.alg must be 'aes-256-gcm-pre-shared', got ${String(t['alg'])}.`)\n }\n if (typeof t['sealId'] !== 'string' || t['sealId'].length === 0) {\n throw new Error(`.noydb bundle header.transferSeal.sealId must be a non-empty string, got ${String(t['sealId'])}.`)\n }\n }\n // Cross-field invariant: the seal indicator and the extracted-partition\n // kind imply each other. An extracted partition is unlocked via its\n // transfer seal; a seal without the kind is a malformed header.\n const isExtracted = h['bundleKind'] === 'extracted-partition'\n const hasSeal = h['transferSeal'] !== undefined\n if (hasSeal && !isExtracted) {\n throw new Error(\n `.noydb bundle header.transferSeal requires bundleKind === 'extracted-partition'.`,\n )\n }\n if (isExtracted && !hasSeal) {\n throw new Error(\n `.noydb bundle header with bundleKind === 'extracted-partition' must carry a transferSeal indicator.`,\n )\n }\n // An extracted partition's unlock path IS the transfer seal. A parallel\n // autoUnlock credential would create two unlock paths and weaken the\n // one-time-seal guarantee. Reject the combination.\n if (isExtracted && h['autoUnlock'] !== undefined) {\n throw new Error(\n `.noydb bundle header cannot carry both autoUnlock and bundleKind === 'extracted-partition' — `\n + `an extracted partition is unlocked via its transfer seal, not an auto-credential.`,\n )\n }\n}\n\n/**\n * Encode a header object to UTF-8 JSON bytes after validating\n * minimum disclosure. Used by the writer to serialize the header\n * region of the container.\n */\nexport function encodeBundleHeader(header: NoydbPodHeader): Uint8Array {\n validateBundleHeader(header)\n // Stable key ordering — JSON.stringify with no replacer uses\n // insertion order, which is fine here because we control the\n // object construction. Stable ordering means two bundles with\n // identical contents produce byte-identical headers.\n const json = JSON.stringify({\n formatVersion: header.formatVersion,\n handle: header.handle,\n bodyBytes: header.bodyBytes,\n bodySha256: header.bodySha256,\n ...(header.publicEnvelope !== undefined ? { publicEnvelope: header.publicEnvelope } : {}),\n ...(header.autoUnlock !== undefined ? { autoUnlock: header.autoUnlock } : {}),\n ...(header.bundleKind !== undefined ? { bundleKind: header.bundleKind } : {}),\n ...(header.transferSeal !== undefined ? { transferSeal: header.transferSeal } : {}),\n })\n return new TextEncoder().encode(json)\n}\n\n/**\n * Parse a bundle header from its UTF-8 JSON bytes. Throws on\n * invalid JSON or any minimum-disclosure violation.\n */\nexport function decodeBundleHeader(bytes: Uint8Array): NoydbPodHeader {\n const json = new TextDecoder('utf-8', { fatal: true }).decode(bytes)\n let parsed: unknown\n try {\n parsed = JSON.parse(json)\n } catch (err) {\n throw new Error(\n `.noydb bundle header is not valid JSON: ${(err as Error).message}`,\n )\n }\n validateBundleHeader(parsed)\n return parsed\n}\n\n/**\n * Read a uint32 from `bytes` at `offset` in big-endian byte order.\n * No bounds check — callers must guarantee `offset + 4 <= bytes.length`.\n * Used to decode the header length field; kept inline so the parser\n * doesn't depend on DataView allocation per call.\n */\nexport function readUint32BE(bytes: Uint8Array, offset: number): number {\n return (\n (bytes[offset]! << 24 >>> 0) +\n (bytes[offset + 1]! << 16) +\n (bytes[offset + 2]! << 8) +\n bytes[offset + 3]!\n )\n}\n\n/**\n * Write a uint32 to `bytes` at `offset` in big-endian byte order.\n * No bounds check — callers must guarantee `offset + 4 <= bytes.length`.\n */\nexport function writeUint32BE(bytes: Uint8Array, offset: number, value: number): void {\n bytes[offset] = (value >>> 24) & 0xff\n bytes[offset + 1] = (value >>> 16) & 0xff\n bytes[offset + 2] = (value >>> 8) & 0xff\n bytes[offset + 3] = value & 0xff\n}\n\n/**\n * Verify the magic prefix of a bundle. Returns true if the first\n * 4 bytes match `NDB1`. Used by readers as a fast file-type check\n * before any further parsing.\n */\nexport function hasNoydbBundleMagic(bytes: Uint8Array): boolean {\n if (bytes.length < NOYDB_BUNDLE_MAGIC.length) return false\n for (let i = 0; i < NOYDB_BUNDLE_MAGIC.length; i++) {\n if (bytes[i] !== NOYDB_BUNDLE_MAGIC[i]) return false\n }\n return true\n}\n","/**\n * `.noydb` container primitives — write, read, header-only read.\n *\n *. Wraps a `vault.dump()` JSON string in the\n * binary container described in `format.ts`.\n *\n * **Three primitives:**\n *\n * - `writePod(vault, opts?)` — produces the\n * full container bytes ready to write to disk or upload\n * - `readPodHeader(bytes)` — parses just the header\n * without decompressing the body, fast file-type and\n * metadata read for cloud listing UIs\n * - `readPod(bytes)` — full read: validates magic,\n * header, integrity hash, and decompresses the body to\n * return the original `dump()` JSON string for use with\n * `vault.load()`\n *\n * **Compression strategy:** brotli when available (Node 22+,\n * Chrome 124+, Firefox 122+), gzip fallback elsewhere. The\n * algorithm choice is encoded in the format byte at offset 5,\n * so readers handle either transparently. Brotli wins ~30-50%\n * on JSON payloads with repeated keys (which vault dumps\n * are).\n *\n * **Why split read/load?** `readPod` returns the\n * *unwrapped JSON string*, not a Vault object. The caller\n * is responsible for piping that JSON into\n * `vault.load(json, secret)`. Splitting the layers\n * keeps the bundle module free of any crypto/secret\n * concerns — it's purely a format layer. The same `readPod`\n * call can also feed verification tools, format inspectors, or\n * archive utilities that don't care about decryption.\n */\n\nimport {\n COMPRESSION_BROTLI,\n COMPRESSION_GZIP,\n COMPRESSION_NONE,\n FLAG_COMPRESSED,\n FLAG_HAS_INTEGRITY_HASH,\n NOYDB_BUNDLE_FORMAT_VERSION,\n NOYDB_BUNDLE_MAGIC,\n NOYDB_BUNDLE_PREFIX_BYTES,\n decodeBundleHeader,\n encodeBundleHeader,\n hasNoydbBundleMagic,\n readUint32BE,\n writeUint32BE,\n type CompressionAlgo,\n type NoydbPodHeader,\n} from './format.js'\nimport { sha256Hex as sha256HexBytes } from '../kernel/enclave/index.js'\nimport { BundleIntegrityError, BundleSealMismatchError, ValidationError } from '../kernel/errors.js'\nimport type { Vault } from '../kernel/vault.js'\nimport type { BundleRecipient } from '../with-party/team/keyring.js'\nimport { pickLocale } from '../with-party/directory/cover/storage.js'\nimport type { Cover } from '../with-party/directory/cover/types.js'\nimport type { SealingKeyProvider, RecipientSealer, RecipientHint } from '../with-party/team/managed-secret.js'\n\n// ─── Auto-credential types ────────────────────────────────────────────────────\n\n/**\n * The credential kinds that can be bundled for auto-unlock.\n * WebAuthn is intentionally excluded — it is hardware-bound and\n * cannot be embedded as a portable credential.\n */\nexport type AutoCredentialKind = 'secret' | 'password' | 'pin'\n\n/**\n * A typed credential for auto-unlock. Carries the credential `kind`\n * alongside the plaintext `value`, so consumers can dispatch the\n * correct login/prefill path rather than treating all credentials\n * as secrets.\n *\n * `bundle.ts` is a pure format layer — it carries the credential\n * without interpreting it. The consumer is responsible for\n * dispatching on `kind`.\n */\nexport interface AutoCredential {\n readonly kind: AutoCredentialKind\n readonly value: string\n}\n\n/**\n * Options accepted by `writePod`.\n *\n * - `compression: 'auto'` (default) — try brotli, fall back to gzip\n * - `compression: 'brotli'` — force brotli, throw if unsupported\n * - `compression: 'gzip'` — force gzip\n * - `compression: 'none'` — no compression (round-trip testing only)\n *\n * **Slice filtering:**\n * - `collections` — allowlist of collection names to include. Internal\n * collections (keyrings, ledger) and excluded user collections are\n * dropped from the bundle. Records inside included collections are\n * carried through verbatim.\n * - `since` — only records whose envelope `_ts` is on/after the given\n * instant survive. Operates on the unencrypted envelope timestamp,\n * so plaintext access to records is not required.\n *\n * Both filters intersect (AND). When neither is provided the bundle is\n * a whole-vault snapshot, identical to today's behaviour.\n */\nexport interface WritePodOptions {\n readonly compression?: 'auto' | 'brotli' | 'gzip' | 'none'\n /** Allowlist of user-collection names to include. */\n readonly collections?: readonly string[]\n /**\n * Drop records whose envelope `_ts` is strictly older than this\n * instant. Accepts a `Date` or any ISO-8601 string parseable by\n * `new Date()`.\n */\n readonly since?: Date | string\n /**\n * Plaintext-pipeline record predicate. Decrypts each record\n * with the vault's per-collection DEK, runs the predicate, and\n * keeps the original ciphertext for survivors (no re-encrypt —\n * preserves zero-knowledge cleanly). Records the predicate returns\n * `false` for are dropped from the bundle.\n *\n * Async predicates are supported. Mutating the record from inside\n * the predicate is undefined behaviour.\n */\n readonly where?: (\n record: unknown,\n ctx: { collection: string; id: string },\n ) => boolean | Promise<boolean>\n /**\n * Hierarchical-tier ceiling. Records whose envelope `_tier`\n * is strictly greater than this number are dropped. Operates on the\n * envelope `_tier` (no decryption needed) — vault.exportStream is\n * referenced in the issue body for symmetry, but the tier value\n * lives on the unencrypted envelope. Vault without tiers is a no-op.\n */\n readonly tierAtMost?: number\n /**\n * Single-recipient re-keying shorthand. When set, the\n * bundle's keyring is replaced with one freshly-derived entry sealed\n * with this secret. The recipient inherits the source keyring's\n * userId, role, and permissions. Mutually exclusive with `recipients`.\n */\n readonly exportSecret?: string\n /**\n * Multi-recipient re-keying. Replaces the bundle's keyring\n * map with one slot per recipient, each sealed with its own\n * secret. DEKs are unwrapped from the source keyring once and\n * re-wrapped per recipient — record ciphertext is unchanged.\n *\n * Mutually exclusive with `exportSecret`. When neither is set,\n * the bundle inherits the source keyring as-is (today's behaviour,\n * suited to personal backup-and-restore).\n */\n readonly recipients?: readonly BundleRecipient[]\n /**\n * Auto-unlock — unsealed per-user credentials.\n *\n * Generalises `autoSecrets` to support any bundleable credential\n * kind (`secret` | `password` | `pin`).\n *\n * Public-by-design: anyone holding the bundle bytes can read these\n * plaintext credentials. Use for demo data, sample vaults,\n * prospect onboarding.\n *\n * The `policy: 'public-by-design'` discriminant is mandatory. A\n * bare `{ perUser }` without it is rejected at write time — the\n * safety net against a careless call against a production vault.\n *\n * Mutually exclusive with `sealedCredentials`, `autoSecrets`,\n * and `sealedSecrets`.\n */\n readonly autoCredentials?: {\n readonly policy: 'public-by-design'\n readonly perUser: Record<string, AutoCredential>\n }\n /**\n * Auto-unlock — per-user credentials sealed under a\n * {@link SealingKeyProvider}.\n *\n * Generalises `sealedSecrets` to support any bundleable\n * credential kind (`secret` | `password` | `pin`).\n *\n * The hub seals each user's plaintext credential under `provider`\n * and embeds the resulting sealed envelopes in the bundle. The\n * recipient must hold a provider with a matching `pid` (i.e.,\n * `provider.id`) to auto-unseal on import.\n *\n * `mode: 'self-target'` — sender and recipient share the same\n * provider identity (same iCloud Keychain entry, same\n * MDM-provisioned bundle id, same KMS account, etc.).\n *\n * `mode: 'recipient-target'` — asymmetric sealing via a\n * {@link RecipientSealer}. Each user entry carries a\n * `credential` and a `hint` (the recipient's public material).\n * The bundle can only be unsealed by the holder of the matching\n * private key.\n *\n * Mutually exclusive with `autoCredentials`, `autoSecrets`,\n * and `sealedSecrets`.\n */\n readonly sealedCredentials?:\n | {\n readonly mode: 'self-target'\n readonly provider: SealingKeyProvider\n readonly perUser: Record<string, AutoCredential>\n }\n | {\n readonly mode: 'recipient-target'\n readonly provider: RecipientSealer\n readonly perUser: Record<string, { readonly credential: AutoCredential; readonly hint: RecipientHint }>\n }\n /**\n * @deprecated Use `autoCredentials` instead.\n *\n * Auto-unlock — unsealed per-user secrets.\n *\n * Public-by-design: anyone holding the bundle bytes can read these\n * plaintext credentials. Use for demo data, sample vaults,\n * prospect onboarding.\n *\n * The `policy: 'public-by-design'` discriminant is mandatory. A\n * bare `{ perUser }` without it is rejected at write time — the\n * safety net against a careless call against a production vault.\n *\n * Mutually exclusive with `autoCredentials`, `sealedCredentials`,\n * and `sealedSecrets`.\n */\n readonly autoSecrets?: {\n readonly policy: 'public-by-design'\n readonly perUser: Record<string, string>\n }\n /**\n * @deprecated Use `sealedCredentials` instead.\n *\n * Auto-unlock — per-user secrets sealed under a\n * {@link SealingKeyProvider} (self-target only).\n *\n * The hub seals each user's plaintext secret under `provider`\n * and embeds the resulting sealed envelopes in the bundle. The\n * recipient must hold a provider with a matching `pid` (i.e.,\n * `provider.id`) to auto-unseal on import.\n *\n * `mode: 'self-target'` is the only mode for `sealedSecrets` — sender\n * and recipient share the same provider identity (same iCloud Keychain\n * entry, same MDM-provisioned bundle id, same KMS account, etc.).\n * For recipient-target sealing via the `RecipientSealer` interface,\n * use `sealedCredentials` with `mode: 'recipient-target'` (§11.4).\n *\n * Mutually exclusive with `autoCredentials`, `sealedCredentials`,\n * and `autoSecrets`.\n */\n readonly sealedSecrets?: {\n readonly mode: 'self-target'\n readonly provider: SealingKeyProvider\n readonly perUser: Record<string, string>\n }\n}\n\n/** @deprecated Use `WritePodOptions`. */\nexport type WriteNoydbBundleOptions = WritePodOptions\n\n/**\n * Result returned by `readPod`. The caller is expected to\n * pass `dumpJson` into `vault.load(json, secret)` to\n * actually restore a vault. Splitting the layers keeps the\n * bundle module free of crypto concerns — see file-level docs.\n */\nexport interface NoydbBundleReadResult {\n readonly header: NoydbPodHeader\n readonly dumpJson: string\n /**\n * Auto-unlock material. Present only when\n * the header's `autoUnlock` flag is set AND the body's wrapped\n * structure survived parsing. Values are typed credentials — either\n * delivered plain (`kind: 'unsealed'`) or unsealed at read time\n * using one of the supplied `sealingProviders` (`kind: 'sealed'`).\n *\n * Consumers dispatch on `cred.kind` to choose the correct login /\n * prefill path. Pre-0.2 bundles (bare string entries) are coerced\n * to `{ kind: 'secret', value }` on read for back-compat.\n *\n * For `kind: 'sealed'` bundles read without `sealingProviders`, the\n * `value` field is the raw base64 sealed bytes — opaque to the\n * consumer until unsealed elsewhere.\n */\n readonly autoUnlock?: {\n readonly kind: 'unsealed' | 'sealed'\n readonly perUser: Record<string, AutoCredential>\n }\n}\n\n/**\n * Sealed credential entry as it appears in the bundle body's\n * `_autoUnlock.perUser` map when the bundle was written with\n * `sealedCredentials` (or the deprecated `sealedSecrets`).\n * Provider's sealed output is base64-encoded; the `pid` is the\n * dispatch key matched against recipient-supplied\n * `SealingKeyProvider.id`. The `kind` carries the plaintext-tier\n * metadata so the consumer can dispatch on credential type without\n * unsealing first.\n *\n * Back-compat: `kind` is absent in older bundles — readers must\n * default to `'secret'` when not present.\n */\ninterface SealedAutoUnlockEntry {\n readonly pid: string\n readonly sealed: string\n readonly alg: 'aes-256-gcm'\n readonly kind?: AutoCredentialKind\n /**\n * Recipient-target only: the RecipientHint the sender used to seal.\n * Carried for recipient verifiability (\"yes this was sealed against\n * my published hint\"). Self-target entries omit it. Pre-0.2 readers\n * ignore unknown fields, so this is back-compatible.\n */\n readonly hint?: RecipientHint\n}\n\n/**\n * Discriminated wrapper carried in the bundle body when the header's\n * `autoUnlock` flag is set. Without the flag, the body is the raw\n * `vault.dump()` JSON string.\n *\n * Back-compat: older bundles carry bare `string` values in the\n * unsealed `perUser` map. Readers must coerce those to\n * `{ kind: 'secret', value }`.\n */\ninterface AutoUnlockBody {\n readonly _noydb_bundle_body: 1\n readonly dump: string\n readonly _autoUnlock:\n | { readonly kind: 'unsealed'; readonly perUser: Record<string, AutoCredential | string> }\n | { readonly kind: 'sealed'; readonly perUser: Record<string, SealedAutoUnlockEntry> }\n}\n\n/**\n * Options accepted by {@link readPod} for the\n * auto-unlock paths. Without these the reader behaves exactly as before\n * (header parsed; body returned as `dumpJson`).\n */\nexport interface ReadNoydbBundleOptions {\n /**\n * Recipient-side sealing providers used to unseal entries from\n * `sealedSecrets`. The reader picks the one whose `.id`\n * matches each entry's `pid`. Multiple providers may be supplied\n * (different users may seal under different identities).\n *\n * When unset and the bundle carries sealed envelopes, the\n * `autoUnlock.perUser` map remains the SEALED entries unmodified\n * — callers can inspect them or unseal elsewhere.\n */\n readonly sealingProviders?: readonly SealingKeyProvider[]\n /**\n * Opt-in trial mode for unsealing — when an entry's `pid` doesn't\n * match a registered provider, try each provider whose alg\n * matches. Default `false` (strict-pid dispatch per foundation\n * §11.9.2). Surfaces extra credential prompts; use deliberately.\n */\n readonly attemptUnsealAcrossProviders?: boolean\n}\n\n// ─── Auto-unlock helpers ──────────────────────────────────────────────────────\n\n/**\n * Internal normalized form of the auto-unlock options, computed once\n * from the four public-facing fields (autoCredentials, sealedCredentials,\n * autoSecrets, sealedSecrets). Callers work against this shape\n * so the build + validate paths share a single normalizer.\n */\ninterface NormalizedAutoUnlock {\n readonly mode: 'unsealed' | 'sealed-self' | 'sealed-recipient'\n readonly provider?: SealingKeyProvider | RecipientSealer\n readonly perUser: Record<string, AutoCredential>\n /** Present only for `sealed-recipient`. Same key set as `perUser`. */\n readonly hints?: Record<string, RecipientHint>\n}\n\n/**\n * Coerce a `Record<string, string>` (legacy secret-only map) into\n * a `Record<string, AutoCredential>` by tagging each entry as\n * `kind: 'secret'`. Used by the normalizer to promote the deprecated\n * `autoSecrets`/`sealedSecrets` sugar.\n */\nfunction toAutoCredentials(m: Record<string, string>): Record<string, AutoCredential> {\n return Object.fromEntries(\n Object.entries(m).map(([u, value]) => [u, { kind: 'secret' as const, value }]),\n )\n}\n\n/**\n * Normalize the four auto-unlock option fields into a single\n * `NormalizedAutoUnlock` (or `null` when none is set). Enforces mutual\n * exclusion — exactly one of the four may be present. Promotes the\n * deprecated sugar fields to `AutoCredential` shape.\n *\n * Does NOT validate field-level constraints (policy marker, perUser\n * length, mode, provider presence, kind allowlist) — those are checked\n * in `validateAutoUnlockOptions` after normalization.\n */\nfunction normalizeAutoUnlock(opts: WritePodOptions): NormalizedAutoUnlock | null {\n const set = [\n opts.autoCredentials,\n opts.sealedCredentials,\n opts.autoSecrets,\n opts.sealedSecrets,\n ].filter(v => v !== undefined).length\n if (set === 0) return null\n if (set > 1) {\n throw new ValidationError(\n 'writePod: only one of autoCredentials / sealedCredentials / '\n + 'autoSecrets / sealedSecrets may be set.',\n )\n }\n if (opts.autoCredentials !== undefined) {\n return { mode: 'unsealed', perUser: opts.autoCredentials.perUser }\n }\n if (opts.autoSecrets !== undefined) {\n return { mode: 'unsealed', perUser: toAutoCredentials(opts.autoSecrets.perUser) }\n }\n if (opts.sealedCredentials !== undefined) {\n if (opts.sealedCredentials.mode === 'recipient-target') {\n const perUser: Record<string, AutoCredential> = {}\n const hints: Record<string, RecipientHint> = {}\n for (const [userId, entry] of Object.entries(opts.sealedCredentials.perUser)) {\n perUser[userId] = entry.credential\n hints[userId] = entry.hint\n }\n return { mode: 'sealed-recipient', provider: opts.sealedCredentials.provider, perUser, hints }\n }\n return { mode: 'sealed-self', provider: opts.sealedCredentials.provider, perUser: opts.sealedCredentials.perUser }\n }\n // sealedSecrets — only remaining option\n return {\n mode: 'sealed-self',\n provider: opts.sealedSecrets!.provider,\n perUser: toAutoCredentials(opts.sealedSecrets!.perUser),\n }\n}\n\n/**\n * Validate the auto-unlock options and return the resulting header\n * `autoUnlock` value (or null when no auto-unlock requested).\n *\n * Takes the pre-computed `NormalizedAutoUnlock` so the caller (i.e.\n * `writePod`) can pass the same object to `buildAutoUnlockWrapper`\n * without a second `normalizeAutoUnlock` call.\n *\n * Validation per spec (§3):\n * - (mutual exclusion already enforced by normalizeAutoUnlock)\n * - unsealed path: `policy: 'public-by-design'` marker required\n * - non-empty `perUser` maps\n * - sealed path: provider present; both `mode: 'self-target'` and `mode: 'recipient-target'` accepted; recipient-target requires a `RecipientSealer` provider and per-user `hint` (§11.4)\n * - every AutoCredential.kind ∈ {secret, password, pin}\n * (WebAuthn is hardware-bound and cannot be bundled)\n *\n * Throws {@link ValidationError} on any violation.\n */\nfunction validateAutoUnlockOptions(\n opts: WritePodOptions,\n normalized: NormalizedAutoUnlock | null,\n): 'unsealed' | 'sealed' | null {\n if (normalized === null) return null\n\n const VALID_KINDS: ReadonlySet<string> = new Set(['secret', 'password', 'pin'])\n\n // Validate every credential kind before any further checks.\n for (const [userId, cred] of Object.entries(normalized.perUser)) {\n if (!VALID_KINDS.has(cred.kind)) {\n throw new ValidationError(\n `writePod: credential for user '${userId}' has unsupported kind '${cred.kind}'. `\n + 'auto-unlock supports secret/password/pin only; WebAuthn is hardware-bound '\n + 'and cannot be bundled.',\n )\n }\n }\n\n if (normalized.mode === 'unsealed') {\n // Read the policy marker from whichever active option carries it.\n const policy = opts.autoCredentials?.policy ?? opts.autoSecrets?.policy\n if (policy !== 'public-by-design') {\n throw new ValidationError(\n 'writePod: `autoCredentials` (or `autoSecrets`) requires '\n + '`policy: \"public-by-design\"`. '\n + 'This is an explicit opt-in marker — bundling plaintext credentials is '\n + 'safe only when those credentials are intended to be public (demo data, '\n + 'sample vaults). For production credentials, use `sealedCredentials` instead.',\n )\n }\n const userCount = Object.keys(normalized.perUser).length\n if (userCount === 0) {\n throw new ValidationError(\n 'writePod: `autoCredentials.perUser` (or `autoSecrets.perUser`) '\n + 'must have at least one entry.',\n )\n }\n return 'unsealed'\n }\n\n // Sealed path — branch on mode.\n if (normalized.mode === 'sealed-recipient') {\n const provider = normalized.provider\n if (provider === undefined || typeof (provider as RecipientSealer).publishRecipientHint !== 'function'\n || typeof (provider as RecipientSealer).sealForRecipient !== 'function') {\n throw new ValidationError(\n 'writePod: `sealedCredentials.provider` for mode \\'recipient-target\\' must be a '\n + 'RecipientSealer (publishRecipientHint + sealForRecipient). Self-only providers '\n + '(MemorySealingKeyProvider, at-macos-keychain, etc.) do not satisfy this contract.',\n )\n }\n const hints = normalized.hints\n if (hints === undefined) {\n throw new Error('unreachable — sealed-recipient normalization must populate hints')\n }\n for (const userId of Object.keys(normalized.perUser)) {\n const hint = hints[userId]\n if (hint === undefined) {\n throw new ValidationError(\n `writePod: \\`sealedCredentials.perUser['${userId}']\\` missing required \\`hint\\` for mode 'recipient-target'.`,\n )\n }\n if (hint.v !== 1) {\n throw new ValidationError(\n `writePod: \\`sealedCredentials.perUser['${userId}'].hint.v\\` must be 1 (got ${String(hint.v)}).`,\n )\n }\n if (typeof hint.pid !== 'string' || hint.pid.length === 0) {\n throw new ValidationError(\n `writePod: \\`sealedCredentials.perUser['${userId}'].hint.pid\\` must be a non-empty string identifying the recipient.`,\n )\n }\n if (hint.alg !== 'rsa-oaep-sha256') {\n throw new ValidationError(\n `writePod: \\`sealedCredentials.perUser['${userId}'].hint.alg\\` must be 'rsa-oaep-sha256' in slice 1 (got '${String(hint.alg)}').`,\n )\n }\n // Note: hint.pid identifies the recipient, not the sender — no pid===sender.id check here.\n // The sender holds a RecipientSealer that calls sealForRecipient(plaintext, hint);\n // the hint's pid is the dispatch key on the reader side (matched against recipient providers).\n }\n const userCount = Object.keys(normalized.perUser).length\n if (userCount === 0) {\n throw new ValidationError(\n 'writePod: `sealedCredentials.perUser` must have at least one entry.',\n )\n }\n return 'sealed'\n }\n\n // mode === 'sealed-self'\n const selfTargetMode = opts.sealedCredentials?.mode ?? opts.sealedSecrets?.mode\n if (selfTargetMode !== 'self-target') {\n throw new ValidationError(\n `writePod: \\`sealedCredentials.mode\\` (or \\`sealedSecrets.mode\\`) must be `\n + `'self-target' or 'recipient-target' (got '${String(selfTargetMode)}').`,\n )\n }\n if (normalized.provider === undefined) {\n throw new ValidationError(\n 'writePod: `sealedCredentials.provider` (or `sealedSecrets.provider`) '\n + 'is required (a `SealingKeyProvider`).',\n )\n }\n const userCount = Object.keys(normalized.perUser).length\n if (userCount === 0) {\n throw new ValidationError(\n 'writePod: `sealedCredentials.perUser` (or `sealedSecrets.perUser`) '\n + 'must have at least one entry.',\n )\n }\n return 'sealed'\n}\n\n/**\n * Build the body wrapper carrying the dump + `_autoUnlock` blob.\n * Takes the pre-computed `NormalizedAutoUnlock` so both validate and\n * build work off the same normalized form (no double-normalize).\n */\nasync function buildAutoUnlockWrapper(\n dumpJson: string,\n normalized: NormalizedAutoUnlock,\n): Promise<AutoUnlockBody> {\n if (normalized.mode === 'unsealed') {\n return {\n _noydb_bundle_body: 1,\n dump: dumpJson,\n _autoUnlock: {\n kind: 'unsealed',\n perUser: { ...normalized.perUser },\n },\n }\n }\n // Sealed path — branch on mode.\n const provider = normalized.provider\n if (provider === undefined) {\n throw new Error('unreachable — validation should have caught this')\n }\n const sealedPerUser: Record<string, SealedAutoUnlockEntry> = {}\n const encoder = new TextEncoder()\n\n if (normalized.mode === 'sealed-recipient') {\n const recipientSealer = provider as RecipientSealer\n const hints = normalized.hints\n if (hints === undefined) {\n throw new Error('unreachable — sealed-recipient normalization must populate hints')\n }\n for (const [userId, cred] of Object.entries(normalized.perUser)) {\n const hint = hints[userId]!\n const sealed = await recipientSealer.sealForRecipient(encoder.encode(cred.value), hint)\n sealedPerUser[userId] = {\n pid: hint.pid, // use the recipient's pid, not the sender's\n sealed: bytesToBase64(sealed),\n alg: 'aes-256-gcm',\n kind: cred.kind,\n hint,\n }\n }\n } else {\n // mode === 'sealed-self'\n const selfSealer = provider as SealingKeyProvider\n for (const [userId, cred] of Object.entries(normalized.perUser)) {\n const sealed = await selfSealer.seal(encoder.encode(cred.value))\n sealedPerUser[userId] = {\n pid: selfSealer.id,\n sealed: bytesToBase64(sealed),\n alg: 'aes-256-gcm',\n kind: cred.kind,\n }\n }\n }\n\n return {\n _noydb_bundle_body: 1,\n dump: dumpJson,\n _autoUnlock: { kind: 'sealed', perUser: sealedPerUser },\n }\n}\n\n/**\n * Parse the body bytes when the header signaled an auto-unlock.\n * Returns the inner `dump` JSON string + the `_autoUnlock` blob;\n * throws if the wrapper structure is malformed.\n */\nfunction parseAutoUnlockBody(bodyString: string): { dump: string; blob: AutoUnlockBody['_autoUnlock'] } {\n let parsed: unknown\n try {\n parsed = JSON.parse(bodyString)\n } catch (err) {\n throw new BundleIntegrityError(\n 'header declared autoUnlock but body could not be parsed as JSON wrapper: '\n + (err instanceof Error ? err.message : String(err)),\n )\n }\n if (typeof parsed !== 'object' || parsed === null) {\n throw new BundleIntegrityError('autoUnlock body is not a JSON object')\n }\n const obj = parsed as Record<string, unknown>\n if (obj['_noydb_bundle_body'] !== 1) {\n throw new BundleIntegrityError(\n 'autoUnlock body missing `_noydb_bundle_body: 1` discriminator',\n )\n }\n if (typeof obj['dump'] !== 'string') {\n throw new BundleIntegrityError('autoUnlock body must carry a string `dump` field')\n }\n const blob = obj['_autoUnlock']\n if (typeof blob !== 'object' || blob === null) {\n throw new BundleIntegrityError('autoUnlock body missing `_autoUnlock` blob')\n }\n const blobObj = blob as Record<string, unknown>\n const kind = blobObj['kind']\n if (kind !== 'unsealed' && kind !== 'sealed') {\n throw new BundleIntegrityError(\n `autoUnlock blob has invalid kind ${String(kind)}; expected 'unsealed' or 'sealed'`,\n )\n }\n return {\n dump: obj['dump'],\n blob: blob as AutoUnlockBody['_autoUnlock'],\n }\n}\n\n/**\n * Transfer-seal payload. The destination DEKs, exported to raw\n * bytes and AES-256-GCM-sealed *as a set* under the one-time transfer\n * key. `adoptPartition` unseals this; `createOwnerOnAdoptedPartition`\n * re-wraps the raw DEKs under the recipient's KEK.\n */\nexport interface TransferSealPayload {\n readonly v: 1\n readonly alg: 'aes-256-gcm-pre-shared'\n readonly sealId: string\n /** base64(AES-256-GCM(transferKey, JSON of { collection: base64(rawDEK) })) — iv ‖ ct ‖ tag. */\n readonly payload: string\n}\n\n/**\n * Body wrapper for an extracted, transfer-sealed partition.\n * Sibling to {@link AutoUnlockBody}; selected by `header.bundleKind ===\n * 'extracted-partition'`. The inner `dump` is a re-keyed projection with\n * an empty `keyrings` map.\n */\nexport interface ExtractedPartitionBody {\n readonly _noydb_bundle_body: 1\n readonly dump: string\n readonly _transferSeal: TransferSealPayload\n}\n\nexport function buildExtractedPartitionWrapper(\n dumpJson: string,\n seal: TransferSealPayload,\n): ExtractedPartitionBody {\n return { _noydb_bundle_body: 1, dump: dumpJson, _transferSeal: seal }\n}\n\nexport function parseExtractedPartitionBody(\n bodyString: string,\n): { dump: string; seal: TransferSealPayload } {\n let parsed: unknown\n try {\n parsed = JSON.parse(bodyString)\n } catch (err) {\n throw new BundleIntegrityError(\n 'header declared extracted-partition but body could not be parsed as JSON wrapper: '\n + (err instanceof Error ? err.message : String(err)),\n )\n }\n if (typeof parsed !== 'object' || parsed === null) {\n throw new BundleIntegrityError('extracted-partition body is not a JSON object')\n }\n const obj = parsed as Record<string, unknown>\n if (obj['_noydb_bundle_body'] !== 1) {\n throw new BundleIntegrityError(\n 'extracted-partition body missing `_noydb_bundle_body: 1` discriminator',\n )\n }\n if (typeof obj['dump'] !== 'string') {\n throw new BundleIntegrityError('extracted-partition body must carry a string `dump` field')\n }\n const seal = obj['_transferSeal']\n if (typeof seal !== 'object' || seal === null) {\n throw new BundleIntegrityError('extracted-partition body missing `_transferSeal` blob')\n }\n const s = seal as Record<string, unknown>\n if (s['v'] !== 1 || s['alg'] !== 'aes-256-gcm-pre-shared'\n || typeof s['sealId'] !== 'string' || typeof s['payload'] !== 'string') {\n throw new BundleIntegrityError('extracted-partition `_transferSeal` blob is malformed')\n }\n return { dump: obj['dump'], seal: seal as TransferSealPayload }\n}\n\n/**\n * Coerce an unsealed perUser entry to `AutoCredential`. Older bundles\n * store bare strings; newer bundles store `{ kind, value }` objects.\n */\nfunction coerceUnsealed(entry: AutoCredential | string): AutoCredential {\n if (typeof entry === 'string') return { kind: 'secret', value: entry }\n return entry\n}\n\n/**\n * Resolve the `_autoUnlock` blob into a typed per-user credential map.\n *\n * - For `kind: 'unsealed'`: pass through, coercing pre-0.2 bare strings\n * to `{ kind: 'secret', value }`.\n * - For `kind: 'sealed'`: pick a `SealingKeyProvider` from\n * `opts.sealingProviders` whose `.id` matches each entry's `pid`;\n * unseal to `AutoCredential`. When no provider matches AND strict mode\n * (default), throw `BundleSealMismatchError`. With\n * `attemptUnsealAcrossProviders: true`, try each provider whose\n * `alg` matches the envelope.\n * Exception: if an unmatched entry carries a `hint` field (recipient-target\n * entries), it passes through as `{ kind, value: base64sealed }` rather than\n * throwing — multi-recipient bundles have N-1 unmatched entries from each\n * recipient's perspective, and the consumer is expected to ignore entries\n * not addressed to them.\n * - When `sealingProviders` is unset entirely on a `'sealed'` bundle,\n * pass through the SEALED entries as `{ kind, value: base64sealed }` —\n * the caller can inspect or unseal elsewhere.\n *\n * Pre-0.2 sealed entries missing `kind` default to `'secret'`.\n */\nasync function resolveAutoUnlock(\n blob: AutoUnlockBody['_autoUnlock'],\n opts: ReadNoydbBundleOptions,\n): Promise<{ kind: 'unsealed' | 'sealed'; perUser: Record<string, AutoCredential> }> {\n if (blob.kind === 'unsealed') {\n const resolved: Record<string, AutoCredential> = {}\n for (const [userId, entry] of Object.entries(blob.perUser)) {\n resolved[userId] = coerceUnsealed(entry)\n }\n return { kind: 'unsealed', perUser: resolved }\n }\n // Sealed path.\n if (opts.sealingProviders === undefined || opts.sealingProviders.length === 0) {\n // Inspection mode — pass the sealed payload through as a typed\n // credential whose `value` is the opaque base64 sealed bytes.\n // The caller is signalled by `kind: 'sealed'` on the outer result.\n const passthrough: Record<string, AutoCredential> = {}\n for (const [userId, entry] of Object.entries(blob.perUser)) {\n passthrough[userId] = { kind: entry.kind ?? 'secret', value: entry.sealed }\n }\n return { kind: 'sealed', perUser: passthrough }\n }\n const providersByPid = new Map<string, SealingKeyProvider>()\n for (const p of opts.sealingProviders) providersByPid.set(p.id, p)\n\n const decoder = new TextDecoder()\n const unsealedMap: Record<string, AutoCredential> = {}\n\n for (const [userId, entry] of Object.entries(blob.perUser)) {\n const credKind: AutoCredentialKind = entry.kind ?? 'secret'\n const provider = providersByPid.get(entry.pid)\n if (provider === undefined) {\n if (opts.attemptUnsealAcrossProviders === true) {\n // Try each provider; first that succeeds wins.\n let opened: string | null = null\n for (const candidate of opts.sealingProviders) {\n try {\n const plaintextBytes = await candidate.unseal(base64ToBytes(entry.sealed))\n opened = decoder.decode(plaintextBytes)\n break\n } catch {\n // try next\n }\n }\n if (opened === null) {\n if (entry.hint !== undefined) {\n // Recipient-target entry not addressed to any held key — pass through sealed.\n // Other recipients' entries in a multi-recipient bundle are opaque to us.\n unsealedMap[userId] = { kind: credKind, value: entry.sealed }\n continue\n }\n throw new BundleSealMismatchError(userId, entry.pid)\n }\n unsealedMap[userId] = { kind: credKind, value: opened }\n continue\n }\n if (entry.hint !== undefined) {\n // Recipient-target entry not addressed to any held key — pass through sealed.\n // Multi-recipient bundles deliberately seal each user's entry under their own\n // public key; a reader holding only alice's key will not match bob's pid.\n unsealedMap[userId] = { kind: credKind, value: entry.sealed }\n continue\n }\n throw new BundleSealMismatchError(userId, entry.pid)\n }\n const plaintextBytes = await provider.unseal(base64ToBytes(entry.sealed))\n unsealedMap[userId] = { kind: credKind, value: decoder.decode(plaintextBytes) }\n }\n return { kind: 'sealed', perUser: unsealedMap }\n}\n\nfunction bytesToBase64(bytes: Uint8Array): string {\n let binary = ''\n for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]!)\n return btoa(binary)\n}\n\nfunction base64ToBytes(b64: string): Uint8Array {\n const binary = atob(b64)\n const out = new Uint8Array(binary.length)\n for (let i = 0; i < binary.length; i++) out[i] = binary.charCodeAt(i)\n return out\n}\n\n/**\n * Detect whether the runtime's `CompressionStream` supports brotli.\n *\n * Brotli requires Node 22+ / Chrome 124+ / Firefox 122+. The\n * detection runs the `CompressionStream` constructor in a\n * try/catch — unsupported formats throw `TypeError` synchronously,\n * making this a safe one-shot check that we cache for the\n * lifetime of the process.\n */\nlet cachedBrotliSupport: boolean | null = null\nfunction supportsBrotliCompression(): boolean {\n if (cachedBrotliSupport !== null) return cachedBrotliSupport\n try {\n new CompressionStream('br' as CompressionFormat)\n cachedBrotliSupport = true\n } catch {\n cachedBrotliSupport = false\n }\n return cachedBrotliSupport\n}\n\n/** Test-only: reset the brotli detection cache between tests. */\nexport function resetBrotliSupportCache(): void {\n cachedBrotliSupport = null\n}\n\n/**\n * Pick the compression algorithm and the corresponding format byte\n * from a user option. Throws if the user explicitly requests brotli\n * on a runtime that doesn't support it — a silent fallback would\n * make the produced bundle smaller-than-expected and confuse\n * size-bound tests.\n */\nfunction selectCompression(option: WritePodOptions['compression']): {\n format: CompressionAlgo\n streamFormat: CompressionFormat | null\n} {\n const choice = option ?? 'auto'\n if (choice === 'none') return { format: COMPRESSION_NONE, streamFormat: null }\n if (choice === 'gzip') return { format: COMPRESSION_GZIP, streamFormat: 'gzip' }\n if (choice === 'brotli') {\n if (!supportsBrotliCompression()) {\n throw new Error(\n `writePod({ compression: 'brotli' }) is not supported on this ` +\n `runtime. Brotli requires Node 22+, Chrome 124+, or Firefox 122+. ` +\n `Use { compression: 'auto' } to fall back to gzip silently, or ` +\n `{ compression: 'gzip' } to be explicit.`,\n )\n }\n return { format: COMPRESSION_BROTLI, streamFormat: 'br' as CompressionFormat }\n }\n // 'auto' — prefer brotli, fall back to gzip\n if (supportsBrotliCompression()) {\n return { format: COMPRESSION_BROTLI, streamFormat: 'br' as CompressionFormat }\n }\n return { format: COMPRESSION_GZIP, streamFormat: 'gzip' }\n}\n\n/**\n * Pump a Uint8Array through a CompressionStream / DecompressionStream\n * and collect the output. Both APIs are universally available in\n * Node 18+ and modern browsers; the only variance is which\n * formats they support, handled by `selectCompression` above.\n *\n * Implementation: build a single-chunk ReadableStream from the\n * input, pipe through the transform, then drain the resulting\n * ReadableStream into a single concatenated Uint8Array. This is\n * O(N) memory in the input + output sizes, which is fine for the\n * dump-sized payloads (typically <50MB) targets.\n */\nasync function pumpThroughStream(\n input: Uint8Array,\n stream: CompressionStream | DecompressionStream,\n): Promise<Uint8Array> {\n const readable = new Blob([input as BlobPart]).stream().pipeThrough(stream)\n const reader = readable.getReader()\n const chunks: Uint8Array[] = []\n let total = 0\n for (;;) {\n const { value, done } = await reader.read()\n if (done) break\n if (value) {\n chunks.push(value as Uint8Array)\n total += value.length\n }\n }\n const out = new Uint8Array(total)\n let offset = 0\n for (const chunk of chunks) {\n out.set(chunk, offset)\n offset += chunk.length\n }\n return out\n}\n\n/**\n * SHA-256 hex digest of `bytes`. Used for the bundle integrity\n * hash carried in the header. Web Crypto API only — no Node\n * crypto module, no third-party hash library.\n *\n * The output format is lowercase hex (64 chars for SHA-256). The\n * format validator pins this — uppercase or mixed-case digests\n * are rejected, so the writer and reader agree on canonicalization.\n */\nasync function sha256Hex(bytes: Uint8Array): Promise<string> {\n // Copy into a fresh ArrayBuffer-backed Uint8Array. The\n // underlying buffer of `bytes` may be SharedArrayBuffer (e.g.\n // from a worker), which `subtle.digest` rejects via TypeScript's\n // BufferSource type. Allocating a fresh ArrayBuffer-backed view\n // sidesteps the type narrowing and is portable across all\n // runtimes — the copy cost is O(N) but bundle bodies are\n // typically <50MB, well below the threshold where the copy\n // matters.\n const copy = new Uint8Array(bytes.length)\n copy.set(bytes)\n return sha256HexBytes(copy)\n}\n\n/**\n * Concatenate any number of Uint8Arrays into a single new buffer.\n * Used to assemble the final bundle from its prefix + header +\n * body parts.\n */\nfunction concatBytes(parts: readonly Uint8Array[]): Uint8Array {\n let total = 0\n for (const p of parts) total += p.length\n const out = new Uint8Array(total)\n let offset = 0\n for (const p of parts) {\n out.set(p, offset)\n offset += p.length\n }\n return out\n}\n\n/**\n * Replace the bundle's keyrings with freshly built recipient slots,\n * one per supplied recipient. No-op when neither `exportSecret`\n * nor `recipients` is set — the source keyring is inherited as-is.\n *\n * The single-secret shorthand creates a one-recipient list whose\n * id, role, and permissions inherit from the source vault — useful\n * for \"back up to a different secret\" without changing role\n * semantics. The multi-recipient form wraps each slot independently\n * with its declared role + permissions.\n *\n * @internal\n */\nasync function applyRecipientRewrap(\n vault: Vault,\n dumpJson: string,\n opts: WritePodOptions,\n): Promise<string> {\n if (opts.exportSecret === undefined && opts.recipients === undefined) {\n return dumpJson\n }\n\n const recipients: readonly BundleRecipient[] =\n opts.recipients ?? [\n {\n id: vault.userId,\n secret: opts.exportSecret as string,\n role: vault.role,\n },\n ]\n\n const recipientKeyrings = await vault.buildBundleRecipientKeyrings(recipients)\n\n const backup = JSON.parse(dumpJson) as { keyrings: unknown; [k: string]: unknown }\n backup.keyrings = recipientKeyrings\n return JSON.stringify(backup)\n}\n\n/**\n * Apply opt-in slice filters to a vault dump JSON string. Filters that\n * narrow the bundle without crossing the encryption boundary — both\n * operate on metadata (collection name, envelope `_ts`) and never need\n * to decrypt records. When neither filter is set, the dump is returned\n * unchanged so the no-arg path stays a pure passthrough.\n *\n * Internal-collection filtering: when a `collections` allowlist is\n * provided, the bundle still carries `_internal` (ledger entries) and\n * the keyrings — they're necessary for the receiver to verify and\n * unlock the bundle. The allowlist applies to the user-collection\n * map only.\n *\n * @internal\n */\nfunction applySliceFilters(\n dumpJson: string,\n opts: WritePodOptions,\n): string {\n const collectionsFilter = opts.collections\n ? new Set(opts.collections)\n : null\n const sinceMs =\n opts.since !== undefined ? new Date(opts.since).getTime() : null\n if (collectionsFilter === null && sinceMs === null) return dumpJson\n\n // Parse, prune, re-serialize. The dump shape is stable\n // (VaultBackup) so this is a one-off allocation; for vaults beyond\n // the documented 1K–50K target a streaming variant would be a\n // follow-up, but the simple parse path keeps the slice path\n // type-safe and trivially auditable.\n const backup = JSON.parse(dumpJson) as {\n collections?: Record<string, Record<string, { _ts?: string }>>\n [k: string]: unknown\n }\n\n if (backup.collections && typeof backup.collections === 'object') {\n const next: Record<string, Record<string, unknown>> = {}\n for (const [name, records] of Object.entries(backup.collections)) {\n if (collectionsFilter && !collectionsFilter.has(name)) continue\n if (sinceMs === null) {\n next[name] = records\n continue\n }\n const kept: Record<string, unknown> = {}\n for (const [id, env] of Object.entries(records)) {\n const envTs = env._ts ? new Date(env._ts).getTime() : NaN\n if (Number.isFinite(envTs) && envTs >= sinceMs) {\n kept[id] = env\n }\n }\n next[name] = kept\n }\n backup.collections = next as typeof backup.collections\n }\n\n return JSON.stringify(backup)\n}\n\n/**\n * Unconditionally drop satellite-collection records whose base row is dead\n * (absent or tombstoned — existence.ts rule 1) from a vault dump. Unlike\n * `applySliceFilters` / `applyPlaintextFilters`, this isn't opt-in: a\n * satellite envelope that outlived its base is dead ciphertext (plus its\n * wrapped keys) that should never leave the vault in a `.noydb` backup\n * (#591 Task 10 — closes the last enumerated existence-authority surface).\n *\n * Pairing info comes from the persisted `_schemas/<name>` marker rather\n * than the in-memory `SatelliteRegistry` — that registry is private to\n * `Vault` and the bundle-export path only has `Vault._introspectState()`\n * (adapter + vault name + per-collection DEK accessor), so it reads the\n * marker instead of widening the kernel's surface. See\n * `with-shape/satellites/dead-filter.ts`.\n *\n * No-ops (returns `dumpJson` unchanged) when the vault has no detectable\n * satellite collections at all, so vaults that never use satellites pay\n * no extra parse/reserialize cost. Also no-ops when `vault` doesn't\n * implement `_introspectState()` at all — some call sites pass a minimal\n * duck-typed vault-like object for unit tests (e.g.\n * `snapshots.test.ts`'s `makeMockVault`, which implements only\n * `getBundleHandle`/`dump`/`load`/`getCover`); a real `Vault`\n * always implements it.\n *\n * @internal\n */\nasync function applySatelliteLivenessFilter(\n vault: Vault,\n dumpJson: string,\n): Promise<string> {\n const backup = JSON.parse(dumpJson) as {\n collections?: Record<string, Record<string, unknown>>\n [k: string]: unknown\n }\n if (!backup.collections || typeof backup.collections !== 'object') return dumpJson\n if (typeof vault._introspectState !== 'function') return dumpJson\n\n const { adapter, name, getDEK } = vault._introspectState()\n const { liveBaseIdSetsForBundle } = await import('../with-shape/satellites/dead-filter.js')\n const satLive = await liveBaseIdSetsForBundle(adapter, name, Object.keys(backup.collections), getDEK)\n if (satLive.size === 0) return dumpJson\n\n const next: Record<string, Record<string, unknown>> = {}\n for (const [collName, records] of Object.entries(backup.collections)) {\n const live = satLive.get(collName)\n if (!live) { next[collName] = records; continue }\n const kept: Record<string, unknown> = {}\n for (const [id, env] of Object.entries(records)) {\n if (live.has(id)) kept[id] = env\n }\n next[collName] = kept\n }\n backup.collections = next\n return JSON.stringify(backup)\n}\n\n/**\n * Apply opt-in plaintext-tier filters\n * to a vault dump. Operates BEFORE `applySliceFilters` so the metadata\n * pass sees the trimmed record set.\n *\n * The filter never re-encrypts: surviving records carry their original\n * envelope unchanged. Failing records are dropped from the\n * `collections` map. Internal collections (ledger, deltas) and the\n * keyrings map are untouched.\n *\n * @internal\n */\nasync function applyPlaintextFilters(\n vault: Vault,\n dumpJson: string,\n opts: WritePodOptions,\n): Promise<string> {\n if (opts.where === undefined && opts.tierAtMost === undefined) {\n return dumpJson\n }\n\n type Env = { _ts?: string; _tier?: number; _iv: string; _data: string }\n const backup = JSON.parse(dumpJson) as {\n collections?: Record<string, Record<string, Env>>\n [k: string]: unknown\n }\n if (!backup.collections || typeof backup.collections !== 'object') {\n return dumpJson\n }\n\n const tierCeiling = opts.tierAtMost\n const where = opts.where\n\n const next: Record<string, Record<string, Env>> = {}\n for (const [collName, records] of Object.entries(backup.collections)) {\n const kept: Record<string, Env> = {}\n for (const [id, env] of Object.entries(records)) {\n // Tier ceiling — runs FIRST so we don't waste a decrypt on\n // records about to be dropped anyway. Envelope tier defaults to\n // 0 when absent (matches Vault's tier-0 conventions).\n if (tierCeiling !== undefined) {\n const tier = env._tier ?? 0\n if (tier > tierCeiling) continue\n }\n // Plaintext predicate — decrypt, run, keep on truthy. Errors\n // from inside the predicate propagate (callers want to see why\n // their filter blew up rather than getting a silent passthrough).\n if (where !== undefined) {\n const record = await vault._decryptEnvelopeForBundleFilter(\n env as never,\n collName,\n )\n const ok = await where(record, { collection: collName, id })\n if (!ok) continue\n }\n kept[id] = env\n }\n next[collName] = kept\n }\n backup.collections = next\n return JSON.stringify(backup)\n}\n\n/**\n * Write a `.noydb` bundle for the given vault.\n *\n * Pipeline:\n * 1. Resolve or create the compartment's stable bundle handle\n * via `vault.getBundleHandle()` — same handle on\n * every export from the same vault instance, so cloud\n * adapters can use it as a primary key.\n * 2. `vault.dump()` → JSON string with encrypted records\n * inside.\n * 3. UTF-8 encode the dump string.\n * 4. Compress (brotli if available, gzip fallback by default).\n * 5. Compute SHA-256 of the compressed body for integrity.\n * 6. Build the minimum-disclosure header from format version,\n * handle, body length, body sha.\n * 7. Serialize: magic (4) + flags (1) + algo (1) + headerLen (4)\n * + header JSON (N) + compressed body (M).\n *\n * The output is a single `Uint8Array`. Consumers writing to disk\n * pass it to `fs.writeFile`; consumers uploading to cloud storage\n * pass it as the request body. The `@noy-db/file` adapter wraps\n * this with a `saveBundle(path, vault)` helper.\n */\n/**\n * Assemble the final `.noydb` container bytes from a body JSON string +\n * header extras. Shared by `writePod` and `extractPartition`\n * so both producers go through one compress/hash/prefix path.\n *\n * @internal\n */\nexport async function assembleBundleContainer(opts: {\n handle: string\n bodyJsonStr: string\n compression: WritePodOptions['compression']\n /** Header fields beyond the always-present four. */\n headerExtras?: Partial<Pick<NoydbPodHeader, 'publicEnvelope' | 'autoUnlock' | 'bundleKind' | 'transferSeal'>>\n}): Promise<Uint8Array> {\n const dumpBytes = new TextEncoder().encode(opts.bodyJsonStr)\n const { format, streamFormat } = selectCompression(opts.compression)\n const body = streamFormat === null\n ? dumpBytes\n : await pumpThroughStream(dumpBytes, new CompressionStream(streamFormat))\n const bodySha256 = await sha256Hex(body)\n\n const header: NoydbPodHeader = {\n formatVersion: NOYDB_BUNDLE_FORMAT_VERSION,\n handle: opts.handle,\n bodyBytes: body.length,\n bodySha256,\n ...(opts.headerExtras?.publicEnvelope !== undefined ? { publicEnvelope: opts.headerExtras.publicEnvelope } : {}),\n ...(opts.headerExtras?.autoUnlock !== undefined ? { autoUnlock: opts.headerExtras.autoUnlock } : {}),\n ...(opts.headerExtras?.bundleKind !== undefined ? { bundleKind: opts.headerExtras.bundleKind } : {}),\n ...(opts.headerExtras?.transferSeal !== undefined ? { transferSeal: opts.headerExtras.transferSeal } : {}),\n }\n const headerBytes = encodeBundleHeader(header)\n\n const prefix = new Uint8Array(NOYDB_BUNDLE_PREFIX_BYTES)\n prefix.set(NOYDB_BUNDLE_MAGIC, 0)\n prefix[4] = (streamFormat === null ? 0 : FLAG_COMPRESSED) | FLAG_HAS_INTEGRITY_HASH\n prefix[5] = format\n writeUint32BE(prefix, 6, headerBytes.length)\n\n return concatBytes([prefix, headerBytes, body])\n}\n\nexport async function writePod(\n vault: Vault,\n opts: WritePodOptions = {},\n): Promise<Uint8Array> {\n if (opts.exportSecret !== undefined && opts.recipients !== undefined) {\n throw new Error(\n 'writePod: pass either exportSecret or recipients, not both',\n )\n }\n\n // Auto-unlock: normalize once, validate + build from the\n // same NormalizedAutoUnlock object so there's no double-normalize call.\n const normalizedAutoUnlock = normalizeAutoUnlock(opts)\n const autoUnlockMode = validateAutoUnlockOptions(opts, normalizedAutoUnlock)\n\n const handle = await vault.getBundleHandle()\n const dumpJson = await vault.dump()\n\n // Satellite existence-authority filter (#591 Task 10) — unconditional,\n // runs before every other filter so dead-ciphertext satellite records\n // never reach recipient rewrap or the opt-in filters below.\n const satelliteFiltered = await applySatelliteLivenessFilter(vault, dumpJson)\n\n // Re-keying: when caller supplied recipients (or the single-recipient\n // shorthand), substitute the bundle's `keyrings` map with freshly\n // built recipient slots before slice filters run.\n const rekeyed = await applyRecipientRewrap(vault, satelliteFiltered, opts)\n // Plaintext-tier filters run BEFORE\n // the metadata-only slice — that way the metadata pass sees the\n // already-trimmed record set and the two filter chains compose\n // cleanly.\n const plainFiltered = await applyPlaintextFilters(vault, rekeyed, opts)\n const filtered = applySliceFilters(plainFiltered, opts)\n\n // If no auto-unlock requested, body remains the raw dump JSON.\n // Otherwise build the wrapped body containing the\n // dump + `_autoUnlock` blob and serialize.\n const bodyJsonStr = normalizedAutoUnlock === null\n ? filtered\n : JSON.stringify(await buildAutoUnlockWrapper(filtered, normalizedAutoUnlock))\n // Snapshot the source vault's cover into the header when one is\n // persisted. `Vault.getCover` tolerates a missing document and\n // returns undefined, which we propagate as \"no cover in the\n // header.\" Vaults without a `_meta/public-envelope` document\n // (the frozen wire name) produce minimum-disclosure headers\n // exactly like before, preserving back-compat.\n const cover = await vault.getCover()\n\n return assembleBundleContainer({\n handle,\n bodyJsonStr,\n compression: opts.compression,\n headerExtras: {\n // `publicEnvelope` is the frozen wire key for the cover (#799).\n ...(cover !== undefined ? { publicEnvelope: cover } : {}),\n ...(autoUnlockMode !== null ? { autoUnlock: autoUnlockMode } : {}),\n },\n })\n}\n\n/** @deprecated Use `writePod`. */\nexport const writeNoydbBundle = writePod\n\n/**\n * Internal helper shared by both readers — parses just the prefix\n * + header region of a bundle without touching the body. Returns\n * the parsed header plus the offset where the body starts and the\n * compression algorithm needed to decompress it.\n *\n * Throws on any format violation: missing/invalid magic, truncated\n * prefix, header length larger than the file, or unknown\n * compression algorithm.\n */\nfunction parsePrefixAndHeader(bytes: Uint8Array): {\n header: NoydbPodHeader\n bodyOffset: number\n algo: CompressionAlgo\n flags: number\n} {\n if (!hasNoydbBundleMagic(bytes)) {\n throw new Error(\n `Not a .noydb bundle: missing 'NDB1' magic prefix. The first 4 bytes ` +\n `are ${[...bytes.slice(0, 4)].map((b) => b.toString(16).padStart(2, '0')).join(' ')}.`,\n )\n }\n if (bytes.length < NOYDB_BUNDLE_PREFIX_BYTES) {\n throw new Error(\n `Truncated .noydb bundle: file is only ${bytes.length} bytes, ` +\n `which is less than the ${NOYDB_BUNDLE_PREFIX_BYTES}-byte fixed prefix.`,\n )\n }\n const flags = bytes[4]!\n const algo = bytes[5]!\n if (algo !== COMPRESSION_NONE && algo !== COMPRESSION_GZIP && algo !== COMPRESSION_BROTLI) {\n throw new Error(\n `.noydb bundle declares unknown compression algorithm ${algo}. ` +\n `Known values: 0 (none), 1 (gzip), 2 (brotli).`,\n )\n }\n const headerLength = readUint32BE(bytes, 6)\n const bodyOffset = NOYDB_BUNDLE_PREFIX_BYTES + headerLength\n if (bodyOffset > bytes.length) {\n throw new Error(\n `Truncated .noydb bundle: declared header length ${headerLength} ` +\n `would extend past end of file (${bytes.length} bytes).`,\n )\n }\n const headerBytes = bytes.slice(NOYDB_BUNDLE_PREFIX_BYTES, bodyOffset)\n const header = decodeBundleHeader(headerBytes)\n return { header, bodyOffset, algo: algo as CompressionAlgo, flags }\n}\n\n/**\n * Read just the bundle header — no body decompression, no\n * integrity verification. Intended for cloud-listing UIs that want\n * to show the handle and size before downloading the full body.\n *\n * Returns the same `NoydbPodHeader` shape as the writer, with\n * minimum-disclosure validation already applied.\n *\n * **Cost** — O(prefix + header bytes). The header is normally well\n * under 1 KB, but may grow to roughly 256 KB when a `publicEnvelope`\n * with an inline icon is present. Cloud-listing UIs that previously\n * assumed sub-KB header reads should account for this when sizing\n * range requests against bundles that may carry icons.\n */\nexport function readPodHeader(bytes: Uint8Array): NoydbPodHeader {\n return parsePrefixAndHeader(bytes).header\n}\n\n/** @deprecated Use `readPodHeader`. */\nexport const readNoydbBundleHeader = readPodHeader\n\n/**\n * Read just the bundle's cover (`https://github.com/vLannaAi/noy-db-docs/blob/main/content/docs/services/public-envelope.md`)\n * — without verifying the body or even parsing the dump JSON. Pass\n * the raw bundle bytes; receive the owner-curated metadata or\n * `undefined` if the bundle was written without one.\n *\n * Locale-resolves any `name` / `description` map fields when `locale`\n * is supplied. Omitting `locale` returns the raw cover.\n *\n * Same security caveat as the on-vault read path — the cover is an\n * **untrusted hint** in v1; the encrypted body remains\n * the source of truth for vault contents.\n */\nexport function readPodCover(\n bytes: Uint8Array,\n opts: { readonly locale?: string } = {},\n): Cover | undefined {\n const header = parsePrefixAndHeader(bytes).header\n const env = header.publicEnvelope\n if (!env) return undefined\n if (opts.locale === undefined) return env\n return {\n ...env,\n ...(env.name !== undefined ? { name: pickLocale(env.name, opts.locale, env.defaultLocale) } : {}),\n ...(env.description !== undefined ? { description: pickLocale(env.description, opts.locale, env.defaultLocale) } : {}),\n }\n}\n\n/**\n * Read a full `.noydb` bundle: validate magic + header, verify\n * integrity hash over the body bytes, decompress, and return the\n * original `vault.dump()` JSON string ready to pass to\n * `vault.load()`.\n *\n * Throws `BundleIntegrityError` if the body's actual SHA-256 does\n * not match the value declared in the header. Distinct from a\n * format error so consumers can pattern-match in catch blocks\n * (corrupted-in-transit vs malformed-by-producer).\n *\n * Note: this function does NOT take a secret. The dump JSON\n * inside the body still contains encrypted records — restoring\n * the vault requires `vault.load(dumpJson, secret)`\n * after this call. Splitting the layers keeps the bundle module\n * free of crypto concerns and lets the same code feed format\n * inspectors that never decrypt anything.\n */\nexport async function readPod(\n bytes: Uint8Array,\n opts: ReadNoydbBundleOptions = {},\n): Promise<NoydbBundleReadResult> {\n const { header, bodyOffset, algo } = parsePrefixAndHeader(bytes)\n const body = bytes.slice(bodyOffset)\n\n // Length check before hash check — a length mismatch is the\n // cheapest tamper signal and produces a more actionable error.\n if (body.length !== header.bodyBytes) {\n throw new BundleIntegrityError(\n `body length ${body.length} does not match header.bodyBytes ` +\n `${header.bodyBytes}. The bundle was truncated or padded ` +\n `between write and read.`,\n )\n }\n\n const actualSha = await sha256Hex(body)\n if (actualSha !== header.bodySha256) {\n throw new BundleIntegrityError(\n `body sha256 ${actualSha} does not match header.bodySha256 ` +\n `${header.bodySha256}. The bundle bytes were modified between ` +\n `write and read — refuse to decompress.`,\n )\n }\n\n let dumpBytes: Uint8Array\n if (algo === COMPRESSION_NONE) {\n dumpBytes = body\n } else {\n const streamFormat: CompressionFormat =\n algo === COMPRESSION_BROTLI ? ('br' as CompressionFormat) : 'gzip'\n try {\n dumpBytes = await pumpThroughStream(body, new DecompressionStream(streamFormat))\n } catch (err) {\n throw new BundleIntegrityError(\n `decompression failed: ${(err as Error).message}. The bundle ` +\n `passed the integrity hash but the body is not valid ` +\n `${streamFormat} data — likely a producer bug.`,\n )\n }\n }\n\n const bodyString = new TextDecoder('utf-8', { fatal: true }).decode(dumpBytes)\n\n // When the header signals auto-unlock, the body is a\n // JSON wrapper carrying the dump string + the auto-unlock blob.\n // When absent, the body IS the raw dump JSON.\n if (header.autoUnlock === undefined) {\n return { header, dumpJson: bodyString }\n }\n const { dump, blob } = parseAutoUnlockBody(bodyString)\n const autoUnlock = await resolveAutoUnlock(blob, opts)\n return { header, dumpJson: dump, autoUnlock }\n}\n\n/** @deprecated Use `readPod`. */\nexport const readNoydbBundle = readPod\n"],"mappings":"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","names":["userCount","plaintextBytes","sha256Hex"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
NOYDB_FORMAT_VERSION
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-QBAC3GXA.js";
|
|
4
4
|
|
|
5
5
|
// src/with-shape/schema-update/fence.ts
|
|
6
6
|
var FENCE_RECORD_ID = "schema-fence";
|
|
@@ -37,4 +37,4 @@ export {
|
|
|
37
37
|
loadFence,
|
|
38
38
|
saveFence
|
|
39
39
|
};
|
|
40
|
-
//# sourceMappingURL=chunk-
|
|
40
|
+
//# sourceMappingURL=chunk-LNZKOUJR.js.map
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import {
|
|
2
2
|
linkCollectionName,
|
|
3
3
|
linkRowKey
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-4JQK3L4V.js";
|
|
5
5
|
import {
|
|
6
6
|
openEnvelopeJson
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-G2JUIDFA.js";
|
|
8
8
|
import {
|
|
9
9
|
encrypt
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-AKKRXT23.js";
|
|
11
11
|
import {
|
|
12
12
|
NOYDB_FORMAT_VERSION
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-QBAC3GXA.js";
|
|
14
14
|
import {
|
|
15
15
|
NoydbError
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-QZWTRENR.js";
|
|
17
17
|
|
|
18
18
|
// src/with-shape/links/link-set.ts
|
|
19
19
|
var LinkSet = class {
|
|
@@ -127,4 +127,4 @@ export {
|
|
|
127
127
|
LinkSet,
|
|
128
128
|
LinkEndpointError
|
|
129
129
|
};
|
|
130
|
-
//# sourceMappingURL=chunk-
|
|
130
|
+
//# sourceMappingURL=chunk-MBKVNOJS.js.map
|