@noy-db/hub 0.4.0-pre.0 → 0.4.0-pre.10
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-YPUEKIJC.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 +58 -29
- 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-IPLXE36W.js → chunk-3V3XR4S4.js} +4 -13
- package/dist/{walk-IPLXE36W.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-ZXEZCY6F.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-IK43HLDQ.js → chunk-7YVBQJ7K.js} +13 -355
- package/dist/chunk-7YVBQJ7K.js.map +1 -0
- package/dist/{chunk-VRBTNCM4.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-554KLAAN.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-WOM2HTML.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-U6JMEH2P.js → chunk-CXQW2NWO.js} +145 -3
- package/dist/chunk-CXQW2NWO.js.map +1 -0
- package/dist/{chunk-EO43ANYJ.js → chunk-DABACXEF.js} +3 -3
- package/dist/{chunk-CJ5KKU6X.js → chunk-DMH3VZU5.js} +4 -4
- package/dist/chunk-DSDXAKIP.js +50 -0
- package/dist/chunk-DSDXAKIP.js.map +1 -0
- package/dist/{chunk-WZSHL6DQ.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-Z4PD65VQ.js → chunk-EE7UHLKH.js} +4 -4
- package/dist/chunk-EIPVYUEP.js +654 -0
- package/dist/chunk-EIPVYUEP.js.map +1 -0
- package/dist/{chunk-RNG4VRP4.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-RFI7GGFO.js → chunk-FQZ6XTQ7.js} +17 -20
- package/dist/chunk-FQZ6XTQ7.js.map +1 -0
- package/dist/{chunk-MT62YSPZ.js → chunk-FRMPM7WG.js} +4 -4
- package/dist/{chunk-W4TCUGQR.js → chunk-G2JUIDFA.js} +13 -9
- package/dist/{chunk-W4TCUGQR.js.map → chunk-G2JUIDFA.js.map} +1 -1
- package/dist/{chunk-T3GY65MA.js → chunk-G6WWZNJP.js} +13 -13
- package/dist/chunk-G6WWZNJP.js.map +1 -0
- package/dist/chunk-GJW4HX2O.js +1 -0
- package/dist/{chunk-KS6SAVCZ.js → chunk-GU3IP74F.js} +6 -6
- package/dist/{chunk-UHNGNKLV.js → chunk-GWWOGNBK.js} +308 -18
- package/dist/chunk-GWWOGNBK.js.map +1 -0
- package/dist/{chunk-5PFOMHTB.js → chunk-H2GPHUZD.js} +12 -13
- package/dist/chunk-H2GPHUZD.js.map +1 -0
- package/dist/{chunk-H2KSZMIX.js → chunk-HMU5P6RL.js} +5 -5
- package/dist/chunk-HMU5P6RL.js.map +1 -0
- package/dist/{chunk-JFCV5QIK.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-LVGTA624.js → chunk-IPUG56GJ.js} +15 -5
- package/dist/{chunk-LVGTA624.js.map → chunk-IPUG56GJ.js.map} +1 -1
- package/dist/{chunk-SMIRGMS7.js → chunk-IXNCZTWA.js} +2 -2
- package/dist/{chunk-WQIYTNJV.js → chunk-IXTSNGYY.js} +3 -3
- package/dist/{chunk-WHXXI3W5.js → chunk-IYZISPGD.js} +7 -5
- package/dist/chunk-IYZISPGD.js.map +1 -0
- package/dist/{chunk-HQBM64EE.js → chunk-JDOMW53O.js} +145 -16
- package/dist/chunk-JDOMW53O.js.map +1 -0
- package/dist/{chunk-NCCBLYEB.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-DSBQODMZ.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-FXZDAV62.js → chunk-LNPUSMZL.js} +29 -31
- package/dist/chunk-LNPUSMZL.js.map +1 -0
- package/dist/{chunk-XJMBYYQK.js → chunk-LNZKOUJR.js} +2 -2
- package/dist/{chunk-R3BLCFD2.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-WG4QBZDN.js → chunk-N4BBNYIB.js} +11 -9
- package/dist/chunk-N4BBNYIB.js.map +1 -0
- package/dist/{chunk-PK6JIDQ4.js → chunk-NFIBXF4V.js} +1084 -1583
- package/dist/chunk-NFIBXF4V.js.map +1 -0
- package/dist/{chunk-VKCADNMR.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-NM5UYF6Q.js +24 -0
- 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-GDG5VVYG.js → chunk-NZ24MX4J.js} +8 -46
- package/dist/chunk-NZ24MX4J.js.map +1 -0
- package/dist/{chunk-IFJTPAQQ.js → chunk-OLEPKFTW.js} +4 -4
- package/dist/chunk-OLEPKFTW.js.map +1 -0
- package/dist/{chunk-THVIPWRF.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-VCTXU4AT.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-YZQOGE2L.js → chunk-QDIH2744.js} +2 -2
- package/dist/{chunk-6HY2X62D.js → chunk-QJNCB5SK.js} +2 -2
- package/dist/{chunk-IAO54J4R.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-XUW3PXHU.js → chunk-TUXQSFHZ.js} +4 -16
- package/dist/{chunk-XUW3PXHU.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-XTHCN77N.js → chunk-UDHBXYGG.js} +29 -19
- 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-A4FXFAKF.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-XDIAFPUM.js → chunk-WLXMTYGO.js} +2 -2
- package/dist/{chunk-RJ6K6K5M.js → chunk-X3F5YJG2.js} +2 -2
- package/dist/{chunk-WKGF2TJR.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-CZTLE22N.js → chunk-Y2NJBNX3.js} +8 -8
- package/dist/{chunk-CZTLE22N.js.map → chunk-Y2NJBNX3.js.map} +1 -1
- package/dist/{chunk-YTGDPCPW.js → chunk-Y6B6HVKC.js} +2 -2
- package/dist/chunk-YMUFFJCO.js +23 -0
- package/dist/chunk-YMUFFJCO.js.map +1 -0
- package/dist/{chunk-SV6EAJEP.js → chunk-YWWQM7KP.js} +5 -14
- package/dist/chunk-YWWQM7KP.js.map +1 -0
- package/dist/{chunk-UDSR4X4L.js → chunk-YZJSJOUI.js} +239 -16
- 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-QWMASIT7.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-66VGI6JV.js → dead-filter-FL3WIUZS.js} +2 -2
- package/dist/{chunk-OCVM6KDH.js → delegation-QXZ4MPPH.js} +12 -6
- package/dist/{chunk-OCVM6KDH.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-TKPN2G2U.js → enclave-SPEEDYZ4.js} +13 -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-B5LVUMQX.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 +4 -4
- 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 +332 -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 +4 -4
- package/dist/kernel/enclave/record-keys/envelope-body.d.ts +8 -0
- 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 +187 -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-PTK7XZYT.js → ledger-6XBEVWYP.js} +11 -11
- package/dist/liberate-CYUOS4NC.js +24 -0
- package/dist/{link-set-SLJHDNRB.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 +21 -17
- package/dist/pod/index.js +26 -12
- package/dist/{policy-YDLCOX4P.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-2YHSADFI.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-HWO4YMTJ.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-3ZMF5EQA.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/share-link/index.d.ts +19 -0
- package/dist/share-link/index.js +201 -0
- package/dist/share-link/index.js.map +1 -0
- package/dist/share-link/share-link.d.ts +123 -0
- 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-VZL4OGUB.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-FKX3F6TQ.js → store-coordination-provider-EWRZL7XF.js} +3 -3
- package/dist/sync/index.js +15 -11
- package/dist/sync/index.js.map +1 -1
- package/dist/team/index.js +33 -47
- 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/periods.d.ts +1 -16
- package/dist/with-audit/periods/vault-facade.d.ts +6 -0
- package/dist/with-audit/periods/window.d.ts +16 -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 +15 -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} +17 -4
- package/dist/{with-party/sync → with-sync}/index.d.ts +4 -2
- package/dist/with-sync/period-scope.d.ts +78 -0
- 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/dist/withdraw-accessible-A2PWF5MZ.js.map +1 -0
- package/package.json +49 -36
- package/dist/aggregate/index.js.map +0 -1
- package/dist/api-3A3S4SHH.js +0 -20
- package/dist/as/index.js +0 -30
- package/dist/at/index.js +0 -1
- package/dist/bundle/index.js +0 -153
- package/dist/bundle/index.js.map +0 -1
- package/dist/by/index.js +0 -11
- package/dist/chunk-554KLAAN.js.map +0 -1
- package/dist/chunk-5PFOMHTB.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-A5BDDEXK.js.map +0 -1
- package/dist/chunk-ANATMTOA.js +0 -205
- package/dist/chunk-ANATMTOA.js.map +0 -1
- package/dist/chunk-BOKIKJJB.js.map +0 -1
- package/dist/chunk-CHFZDSE4.js +0 -1
- package/dist/chunk-DDHM2TLX.js.map +0 -1
- package/dist/chunk-DSBQODMZ.js.map +0 -1
- package/dist/chunk-EWPOHMN2.js +0 -255
- package/dist/chunk-EWPOHMN2.js.map +0 -1
- package/dist/chunk-FXZDAV62.js.map +0 -1
- package/dist/chunk-GDG5VVYG.js.map +0 -1
- package/dist/chunk-GWKAVKHI.js.map +0 -1
- package/dist/chunk-H2KSZMIX.js.map +0 -1
- package/dist/chunk-HOONYZY2.js.map +0 -1
- package/dist/chunk-HQBM64EE.js.map +0 -1
- package/dist/chunk-IAO54J4R.js.map +0 -1
- package/dist/chunk-IFJTPAQQ.js.map +0 -1
- package/dist/chunk-IK43HLDQ.js.map +0 -1
- package/dist/chunk-ISMV2QVG.js.map +0 -1
- package/dist/chunk-JBBSYJHP.js.map +0 -1
- package/dist/chunk-JFCV5QIK.js.map +0 -1
- package/dist/chunk-JRBNCUNT.js.map +0 -1
- package/dist/chunk-LB7FD65R.js +0 -163
- package/dist/chunk-LB7FD65R.js.map +0 -1
- package/dist/chunk-ONTBCHCP.js.map +0 -1
- package/dist/chunk-PK6JIDQ4.js.map +0 -1
- package/dist/chunk-RDXW3OBQ.js.map +0 -1
- package/dist/chunk-RFI7GGFO.js.map +0 -1
- package/dist/chunk-S3BFKGET.js.map +0 -1
- package/dist/chunk-SV6EAJEP.js.map +0 -1
- package/dist/chunk-T36RFODW.js.map +0 -1
- package/dist/chunk-T3GY65MA.js.map +0 -1
- package/dist/chunk-TAGR72IR.js.map +0 -1
- package/dist/chunk-TIGPQDYP.js +0 -14
- package/dist/chunk-TIGPQDYP.js.map +0 -1
- package/dist/chunk-U6JMEH2P.js.map +0 -1
- package/dist/chunk-UDSR4X4L.js.map +0 -1
- package/dist/chunk-UHNGNKLV.js.map +0 -1
- package/dist/chunk-VCBHAE4R.js.map +0 -1
- package/dist/chunk-VCTXU4AT.js.map +0 -1
- package/dist/chunk-VEALDPHW.js.map +0 -1
- package/dist/chunk-VKCADNMR.js.map +0 -1
- package/dist/chunk-VQNJ7UZL.js.map +0 -1
- package/dist/chunk-W2OG6JOL.js.map +0 -1
- package/dist/chunk-WG4QBZDN.js.map +0 -1
- package/dist/chunk-WHXXI3W5.js.map +0 -1
- package/dist/chunk-WKGF2TJR.js.map +0 -1
- package/dist/chunk-WNGGJWF7.js.map +0 -1
- package/dist/chunk-XTHCN77N.js.map +0 -1
- package/dist/chunk-YCH5GBN6.js +0 -99
- package/dist/chunk-YCH5GBN6.js.map +0 -1
- package/dist/chunk-YMUGBZN2.js.map +0 -1
- package/dist/collection-facade-KMBWNCYP.js +0 -44
- package/dist/cover-QJRXINN5.js +0 -52
- package/dist/delegation-SU6CV3W7.js +0 -25
- package/dist/derive-6RWU4EOA.js +0 -21
- package/dist/executor-KGNLJD6M.js +0 -9
- package/dist/executor-UX4FASYZ.js +0 -26
- package/dist/executor-XGIS6CR7.js +0 -9
- package/dist/export-accessible-LKW3QV22.js +0 -23
- package/dist/extract-partition-UP2ARO75.js +0 -38
- package/dist/find-YS6XWB46.js +0 -11
- package/dist/in/index.js +0 -1
- package/dist/issue-3ACYX7LO.js +0 -19
- package/dist/legacy/bundle.d.ts +0 -30
- package/dist/liberate-MQQXBUCY.js +0 -24
- package/dist/noydb-ANIW5FLE.js +0 -69
- 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-PAM3ASRZ.js +0 -23
- package/dist/registry-4S2U2TR4.js +0 -19
- package/dist/registry-NPOWJHC4.js +0 -9
- package/dist/registry-VZ3CCI2R.js +0 -18
- package/dist/request-withdrawal-DI3H5WUI.js +0 -31
- package/dist/revoke-R5CZSVUT.js +0 -24
- package/dist/seed-3ZMF5EQA.js.map +0 -1
- package/dist/signer-MBVHW4WE.js +0 -25
- package/dist/storage-3MEJUENZ.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-TZDATQVR.js +0 -28
- /package/dist/{api-3A3S4SHH.js.map → api-ZDKTWNBB.js.map} +0 -0
- /package/dist/{backup-YPUEKIJC.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-ZXEZCY6F.js.map → chunk-63FE525P.js.map} +0 -0
- /package/dist/{chunk-JVBO4SZL.js.map → chunk-6UBZ6I5Z.js.map} +0 -0
- /package/dist/{chunk-VRBTNCM4.js.map → chunk-ABS7FMMD.js.map} +0 -0
- /package/dist/{chunk-M75ZZHSR.js.map → chunk-BLBAQRBM.js.map} +0 -0
- /package/dist/{chunk-WOM2HTML.js.map → chunk-CI32CAFS.js.map} +0 -0
- /package/dist/{chunk-EO43ANYJ.js.map → chunk-DABACXEF.js.map} +0 -0
- /package/dist/{chunk-CJ5KKU6X.js.map → chunk-DMH3VZU5.js.map} +0 -0
- /package/dist/{chunk-WZSHL6DQ.js.map → chunk-DZ2JXHWK.js.map} +0 -0
- /package/dist/{chunk-Z4PD65VQ.js.map → chunk-EE7UHLKH.js.map} +0 -0
- /package/dist/{chunk-RNG4VRP4.js.map → chunk-EKRSCRNM.js.map} +0 -0
- /package/dist/{chunk-MT62YSPZ.js.map → chunk-FRMPM7WG.js.map} +0 -0
- /package/dist/{as/index.js.map → chunk-GJW4HX2O.js.map} +0 -0
- /package/dist/{chunk-KS6SAVCZ.js.map → chunk-GU3IP74F.js.map} +0 -0
- /package/dist/{chunk-SMIRGMS7.js.map → chunk-IXNCZTWA.js.map} +0 -0
- /package/dist/{chunk-WQIYTNJV.js.map → chunk-IXTSNGYY.js.map} +0 -0
- /package/dist/{chunk-NCCBLYEB.js.map → chunk-JJZGIE4U.js.map} +0 -0
- /package/dist/{chunk-DRWBEDYO.js.map → chunk-JYJFGD2H.js.map} +0 -0
- /package/dist/{chunk-XJMBYYQK.js.map → chunk-LNZKOUJR.js.map} +0 -0
- /package/dist/{chunk-R3BLCFD2.js.map → chunk-MBKVNOJS.js.map} +0 -0
- /package/dist/{chunk-N6WF5PKC.js.map → chunk-NFZGZ4AK.js.map} +0 -0
- /package/dist/{chunk-THVIPWRF.js.map → chunk-PEATRIYJ.js.map} +0 -0
- /package/dist/{chunk-YZQOGE2L.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-A4FXFAKF.js.map → chunk-W3L64Y3J.js.map} +0 -0
- /package/dist/{chunk-XDIAFPUM.js.map → chunk-WLXMTYGO.js.map} +0 -0
- /package/dist/{chunk-RJ6K6K5M.js.map → chunk-X3F5YJG2.js.map} +0 -0
- /package/dist/{chunk-YTGDPCPW.js.map → chunk-Y6B6HVKC.js.map} +0 -0
- /package/dist/{classified-marker-QWMASIT7.js.map → classified-marker-7PKJBFCG.js.map} +0 -0
- /package/dist/{at/index.js.map → collection-facade-6I5K5IOD.js.map} +0 -0
- /package/dist/{by/index.js.map → computed-AB45PS4V.js.map} +0 -0
- /package/dist/{in → cover}/index.js.map +0 -0
- /package/dist/{on → custody}/index.js.map +0 -0
- /package/dist/{dead-filter-66VGI6JV.js.map → dead-filter-FL3WIUZS.js.map} +0 -0
- /package/dist/{chunk-CHFZDSE4.js.map → derive-VGS7FKE3.js.map} +0 -0
- /package/dist/{ui → directory}/index.js.map +0 -0
- /package/dist/{collection-facade-KMBWNCYP.js.map → enclave-SPEEDYZ4.js.map} +0 -0
- /package/dist/{computed-DSMPXG2Y.js.map → executor-IEBLTBCW.js.map} +0 -0
- /package/dist/{cover-QJRXINN5.js.map → executor-OTF556PL.js.map} +0 -0
- /package/dist/{delegation-SU6CV3W7.js.map → executor-RM7XWQDU.js.map} +0 -0
- /package/dist/{derive-6RWU4EOA.js.map → export-accessible-P42BQ4PB.js.map} +0 -0
- /package/dist/{enclave-TKPN2G2U.js.map → extract-partition-TCYXRWBN.js.map} +0 -0
- /package/dist/{fanout-sidecar-B5LVUMQX.js.map → fanout-sidecar-SSMRSC2L.js.map} +0 -0
- /package/dist/{executor-KGNLJD6M.js.map → find-OZMTRIK3.js.map} +0 -0
- /package/dist/{with → introspection}/index.js.map +0 -0
- /package/dist/{executor-UX4FASYZ.js.map → issue-FCKN5O6C.js.map} +0 -0
- /package/dist/{executor-XGIS6CR7.js.map → ledger-6XBEVWYP.js.map} +0 -0
- /package/dist/{export-accessible-LKW3QV22.js.map → liberate-CYUOS4NC.js.map} +0 -0
- /package/dist/{extract-partition-UP2ARO75.js.map → link-set-NK6L2A5S.js.map} +0 -0
- /package/dist/{find-YS6XWB46.js.map → money/index.js.map} +0 -0
- /package/dist/{issue-3ACYX7LO.js.map → noydb-FZZIMLCI.js.map} +0 -0
- /package/dist/{ledger-PTK7XZYT.js.map → policy/index.js.map} +0 -0
- /package/dist/{post-register-2YHSADFI.js.map → post-register-VFIYISUK.js.map} +0 -0
- /package/dist/{liberate-MQQXBUCY.js.map → register-UKU2J6MN.js.map} +0 -0
- /package/dist/{link-set-SLJHDNRB.js.map → registry-2VCWVHZS.js.map} +0 -0
- /package/dist/{noydb-ANIW5FLE.js.map → registry-7Y5WF7GS.js.map} +0 -0
- /package/dist/{policy-YDLCOX4P.js.map → registry-BWD2ED52.js.map} +0 -0
- /package/dist/{register-PAM3ASRZ.js.map → registry-DTWRJLSF.js.map} +0 -0
- /package/dist/{registry-4S2U2TR4.js.map → request-withdrawal-JYDZ5XY2.js.map} +0 -0
- /package/dist/{reveal-HWO4YMTJ.js.map → reveal-CL2BCW6A.js.map} +0 -0
- /package/dist/{registry-NPOWJHC4.js.map → revoke-2TSAD2T4.js.map} +0 -0
- /package/dist/{registry-VW6P6A3J.js.map → schema-update/index.js.map} +0 -0
- /package/dist/{registry-VZ3CCI2R.js.map → search/index.js.map} +0 -0
- /package/dist/{request-withdrawal-DI3H5WUI.js.map → sequence/index.js.map} +0 -0
- /package/dist/{revoke-R5CZSVUT.js.map → signer-K7Z2EOMG.js.map} +0 -0
- /package/dist/{signer-MBVHW4WE.js.map → stale-A4J26OIC.js.map} +0 -0
- /package/dist/{stale-VZL4OGUB.js.map → storage-YVHZUISN.js.map} +0 -0
- /package/dist/{storage-3MEJUENZ.js.map → store/index.js.map} +0 -0
- /package/dist/{store-coordination-provider-FKX3F6TQ.js.map → store-coordination-provider-EWRZL7XF.js.map} +0 -0
- /package/dist/{verify-26Y5GNMK.js.map → verify-7XWHJWUN.js.map} +0 -0
- /package/dist/{withdraw-accessible-TZDATQVR.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
|
@@ -1,96 +1,59 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import {
|
|
5
|
-
NO_SEQUENCE,
|
|
6
|
-
SEQUENCE_COLLECTION,
|
|
7
|
-
compileSequenceFormat,
|
|
8
|
-
resolveSequenceKey
|
|
9
|
-
} from "./chunk-DSBQODMZ.js";
|
|
10
|
-
import {
|
|
11
|
-
loadVaultPolicy
|
|
12
|
-
} from "./chunk-XDIAFPUM.js";
|
|
2
|
+
resolveStaleOnRead
|
|
3
|
+
} from "./chunk-NJ4DYYO5.js";
|
|
13
4
|
import {
|
|
14
5
|
LinkIntegrityError,
|
|
15
6
|
isLinkCollectionName,
|
|
16
7
|
linkCollectionName,
|
|
17
8
|
linkRowKey
|
|
18
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-4JQK3L4V.js";
|
|
19
10
|
import {
|
|
20
11
|
hashFields,
|
|
21
12
|
validateSatelliteDeclaration
|
|
22
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-SHEEBRZ4.js";
|
|
23
14
|
import {
|
|
24
15
|
loadFence
|
|
25
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-LNZKOUJR.js";
|
|
26
17
|
import {
|
|
27
|
-
InvertedIndex,
|
|
28
|
-
MemoryIndexStore,
|
|
29
|
-
NO_SEARCH,
|
|
30
18
|
VectorSet,
|
|
31
19
|
buildPersistedIndexCallbacks,
|
|
32
20
|
encodeVecId,
|
|
33
21
|
syncTierSearch
|
|
34
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-7YVBQJ7K.js";
|
|
35
23
|
import {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
} from "./chunk-BOKIKJJB.js";
|
|
24
|
+
SchemaUpdateGate
|
|
25
|
+
} from "./chunk-6LJY7X5A.js";
|
|
39
26
|
import {
|
|
40
27
|
isBaseLive,
|
|
41
28
|
liveBaseIdSet
|
|
42
29
|
} from "./chunk-GYGLAVCX.js";
|
|
43
|
-
import {
|
|
44
|
-
CustodyApi,
|
|
45
|
-
NO_CARGO,
|
|
46
|
-
NO_CUSTODY
|
|
47
|
-
} from "./chunk-SV6EAJEP.js";
|
|
48
|
-
import {
|
|
49
|
-
ServiceBus,
|
|
50
|
-
WriteHookRegistry,
|
|
51
|
-
assertCanExport,
|
|
52
|
-
assertCanImport,
|
|
53
|
-
canExport,
|
|
54
|
-
canImport
|
|
55
|
-
} from "./chunk-EWPOHMN2.js";
|
|
56
|
-
import {
|
|
57
|
-
runDrainBarrier
|
|
58
|
-
} from "./chunk-ISMV2QVG.js";
|
|
59
|
-
import {
|
|
60
|
-
OverlayedCollection
|
|
61
|
-
} from "./chunk-5WZXVULX.js";
|
|
62
|
-
import {
|
|
63
|
-
NO_ATTESTATION
|
|
64
|
-
} from "./chunk-S6Q37VGE.js";
|
|
65
|
-
import {
|
|
66
|
-
NO_CLASSIFIED,
|
|
67
|
-
guardClassifiedCompat,
|
|
68
|
-
resolveClassifiedFields
|
|
69
|
-
} from "./chunk-Z4PD65VQ.js";
|
|
70
30
|
import {
|
|
71
31
|
NO_TIERS,
|
|
72
32
|
classifySealedShred,
|
|
73
33
|
syncDerivedOutputs
|
|
74
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-Y2NJBNX3.js";
|
|
75
35
|
import {
|
|
76
36
|
NO_PORTABILITY
|
|
77
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-BLBAQRBM.js";
|
|
78
38
|
import {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
PERIOD_TARGET_PURGES_COLLECTION,
|
|
83
|
-
periodExclusiveUpperBound
|
|
84
|
-
} from "./chunk-XTHCN77N.js";
|
|
39
|
+
NO_CARGO,
|
|
40
|
+
runDrainBarrier
|
|
41
|
+
} from "./chunk-TG634KCO.js";
|
|
85
42
|
import {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
43
|
+
resolveManagedSecret,
|
|
44
|
+
saveSealedSecret
|
|
45
|
+
} from "./chunk-FQZ6XTQ7.js";
|
|
46
|
+
import {
|
|
47
|
+
jsonSchemaToFields
|
|
48
|
+
} from "./chunk-VYYM3MEN.js";
|
|
49
|
+
import {
|
|
50
|
+
derivePersistedSchema,
|
|
51
|
+
isZod4Schema
|
|
52
|
+
} from "./chunk-6ZNSB3H6.js";
|
|
90
53
|
import {
|
|
91
54
|
DEFAULT_POSTURE,
|
|
92
55
|
ViaGraph
|
|
93
|
-
} from "./chunk-
|
|
56
|
+
} from "./chunk-4ZKNC6A6.js";
|
|
94
57
|
import {
|
|
95
58
|
buildLookupAltIndex,
|
|
96
59
|
buildLookupSnapshotRows,
|
|
@@ -111,24 +74,80 @@ import {
|
|
|
111
74
|
resolveLabelFromMap,
|
|
112
75
|
resolveRollupDeleteIntents,
|
|
113
76
|
runGraphDispatchWave,
|
|
77
|
+
selfWriteFieldEqual,
|
|
114
78
|
touchFor,
|
|
115
79
|
updateReferencingRecords
|
|
116
|
-
} from "./chunk-
|
|
80
|
+
} from "./chunk-IPUG56GJ.js";
|
|
81
|
+
import {
|
|
82
|
+
OverlayedCollection
|
|
83
|
+
} from "./chunk-ZTLOXFPB.js";
|
|
84
|
+
import {
|
|
85
|
+
INDEXED_STORE_POLICY,
|
|
86
|
+
NO_SYNC
|
|
87
|
+
} from "./chunk-55LKVALY.js";
|
|
88
|
+
import {
|
|
89
|
+
NO_ATTESTATION
|
|
90
|
+
} from "./chunk-5GQEU4DN.js";
|
|
91
|
+
import {
|
|
92
|
+
NO_CLASSIFIED,
|
|
93
|
+
guardClassifiedCompat,
|
|
94
|
+
resolveClassifiedFields
|
|
95
|
+
} from "./chunk-EE7UHLKH.js";
|
|
96
|
+
import {
|
|
97
|
+
NO_PERIODS
|
|
98
|
+
} from "./chunk-UDHBXYGG.js";
|
|
99
|
+
import {
|
|
100
|
+
PERIODS_COLLECTION,
|
|
101
|
+
PERIOD_ARCHIVES_COLLECTION,
|
|
102
|
+
PERIOD_FREEZES_COLLECTION,
|
|
103
|
+
PERIOD_TARGET_PURGES_COLLECTION,
|
|
104
|
+
periodExclusiveUpperBound
|
|
105
|
+
} from "./chunk-NM5UYF6Q.js";
|
|
106
|
+
import {
|
|
107
|
+
NO_SHADOW
|
|
108
|
+
} from "./chunk-SMY5X46Z.js";
|
|
109
|
+
import {
|
|
110
|
+
NO_SNAPSHOTS
|
|
111
|
+
} from "./chunk-DZFQVICS.js";
|
|
112
|
+
import {
|
|
113
|
+
TxContext,
|
|
114
|
+
bestEffortRevert,
|
|
115
|
+
revertExecuted
|
|
116
|
+
} from "./chunk-NGSJZFGL.js";
|
|
117
|
+
import {
|
|
118
|
+
lazy
|
|
119
|
+
} from "./chunk-5D2ALSM5.js";
|
|
120
|
+
import {
|
|
121
|
+
InvertedIndex,
|
|
122
|
+
MemoryIndexStore,
|
|
123
|
+
NO_SEARCH
|
|
124
|
+
} from "./chunk-MCHBCNCE.js";
|
|
125
|
+
import {
|
|
126
|
+
NO_SEQUENCE,
|
|
127
|
+
SEQUENCE_COLLECTION,
|
|
128
|
+
compileSequenceFormat,
|
|
129
|
+
resolveSequenceKey
|
|
130
|
+
} from "./chunk-L2DGWBCT.js";
|
|
131
|
+
import {
|
|
132
|
+
CustodyApi,
|
|
133
|
+
NO_CUSTODY
|
|
134
|
+
} from "./chunk-YWWQM7KP.js";
|
|
117
135
|
import {
|
|
118
|
-
NO_AGGREGATE,
|
|
119
136
|
Query,
|
|
120
137
|
ScanBuilder
|
|
121
|
-
} from "./chunk-
|
|
138
|
+
} from "./chunk-WBKZUO5V.js";
|
|
122
139
|
import {
|
|
123
140
|
EXPORT_AUDIT_COLLECTION,
|
|
141
|
+
NO_BLOBS,
|
|
124
142
|
createExportBlobsHandle,
|
|
125
143
|
runCompaction
|
|
126
|
-
} from "./chunk-
|
|
144
|
+
} from "./chunk-CXQW2NWO.js";
|
|
127
145
|
import {
|
|
128
146
|
LazyQuery,
|
|
147
|
+
NO_INDEXING,
|
|
129
148
|
decodeIdxId,
|
|
130
149
|
encodeIdxId
|
|
131
|
-
} from "./chunk-
|
|
150
|
+
} from "./chunk-L3YYLT4E.js";
|
|
132
151
|
import {
|
|
133
152
|
IMPLICIT_LAZY,
|
|
134
153
|
Lru,
|
|
@@ -136,17 +155,22 @@ import {
|
|
|
136
155
|
} from "./chunk-NO272T7Q.js";
|
|
137
156
|
import {
|
|
138
157
|
canonicalGroupKey
|
|
139
|
-
} from "./chunk-
|
|
158
|
+
} from "./chunk-XZHEOSQ2.js";
|
|
159
|
+
import {
|
|
160
|
+
NO_REDUCE
|
|
161
|
+
} from "./chunk-YMUFFJCO.js";
|
|
140
162
|
import {
|
|
141
163
|
readPath
|
|
142
164
|
} from "./chunk-IGJCYUT5.js";
|
|
143
165
|
import {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
166
|
+
NO_CRDT
|
|
167
|
+
} from "./chunk-PVEWA2DU.js";
|
|
168
|
+
import {
|
|
169
|
+
NO_CONSENT
|
|
170
|
+
} from "./chunk-PEOZ34EM.js";
|
|
147
171
|
import {
|
|
148
172
|
dictCollectionName
|
|
149
|
-
} from "./chunk-
|
|
173
|
+
} from "./chunk-FRMPM7WG.js";
|
|
150
174
|
import {
|
|
151
175
|
NO_I18N,
|
|
152
176
|
getAtPath,
|
|
@@ -154,36 +178,34 @@ import {
|
|
|
154
178
|
isDictKeyDescriptor,
|
|
155
179
|
isI18nTextDescriptor,
|
|
156
180
|
isStaticDictDescriptor
|
|
157
|
-
} from "./chunk-
|
|
181
|
+
} from "./chunk-UADPR6F4.js";
|
|
158
182
|
import {
|
|
159
|
-
installViaBinder,
|
|
160
183
|
isViaInstalled,
|
|
161
184
|
viaBinder
|
|
162
|
-
} from "./chunk-
|
|
185
|
+
} from "./chunk-6UBZ6I5Z.js";
|
|
163
186
|
import {
|
|
164
187
|
NO_TEAM,
|
|
188
|
+
describeAllUsersAuth,
|
|
189
|
+
describeAuthConfig,
|
|
190
|
+
describeUserAuth,
|
|
191
|
+
diagramAuthConfig,
|
|
165
192
|
enrollAuthenticator,
|
|
166
193
|
findAuthenticator,
|
|
167
|
-
recoverPassphrase,
|
|
168
|
-
recoverUser,
|
|
169
|
-
removeAuthenticator,
|
|
170
|
-
rotatePassphrase,
|
|
171
|
-
updateAuthenticator,
|
|
172
|
-
writeMagicLinkGrant
|
|
173
|
-
} from "./chunk-VKCADNMR.js";
|
|
174
|
-
import {
|
|
175
194
|
hasRecoveryEnrolled,
|
|
176
195
|
hasStrongRecoveryEnrolled,
|
|
177
196
|
loadPaperRecoveryEntries,
|
|
178
197
|
loadShamirRecoveryEntries,
|
|
179
198
|
mintPaperRecoveryEntry,
|
|
180
199
|
mintShamirRecoveryEntry,
|
|
200
|
+
recoverSecret,
|
|
201
|
+
recoverUser,
|
|
202
|
+
removeAuthenticator,
|
|
203
|
+
rotateSecret,
|
|
181
204
|
savePaperRecoveryEntries,
|
|
182
|
-
saveShamirRecoveryEntries
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
} from "./chunk-VQNJ7UZL.js";
|
|
205
|
+
saveShamirRecoveryEntries,
|
|
206
|
+
updateAuthenticator,
|
|
207
|
+
writeMagicLinkGrant
|
|
208
|
+
} from "./chunk-NFNJLRY7.js";
|
|
187
209
|
import {
|
|
188
210
|
assertKeyringOpenAllowed,
|
|
189
211
|
buildRecipientKeyringFile,
|
|
@@ -191,31 +213,39 @@ import {
|
|
|
191
213
|
createOwnerKeyring,
|
|
192
214
|
ensureCollectionDEK,
|
|
193
215
|
hasAccess,
|
|
216
|
+
hasExportCapability,
|
|
217
|
+
hasImportCapability,
|
|
194
218
|
hasWritePermission,
|
|
195
219
|
isSecretBearingReservedCollection,
|
|
196
220
|
listUsers,
|
|
197
221
|
loadKeyring,
|
|
198
222
|
updateKeyringIdentity
|
|
199
|
-
} from "./chunk-
|
|
223
|
+
} from "./chunk-BLCWSJLN.js";
|
|
200
224
|
import {
|
|
201
225
|
persistDirectoryConfig,
|
|
202
226
|
readDirectoryConfig
|
|
203
|
-
} from "./chunk-
|
|
227
|
+
} from "./chunk-JJZGIE4U.js";
|
|
204
228
|
import {
|
|
205
229
|
NO_BROKER,
|
|
206
230
|
buildCredentialBrokerHandle
|
|
207
|
-
} from "./chunk-
|
|
231
|
+
} from "./chunk-IXNCZTWA.js";
|
|
232
|
+
import {
|
|
233
|
+
NO_SESSION
|
|
234
|
+
} from "./chunk-VKQCVU2Z.js";
|
|
208
235
|
import {
|
|
209
236
|
generateULID
|
|
210
237
|
} from "./chunk-ZJADGNYF.js";
|
|
238
|
+
import {
|
|
239
|
+
NO_HISTORY
|
|
240
|
+
} from "./chunk-AFHQATY4.js";
|
|
211
241
|
import {
|
|
212
242
|
assertCutoverTierSafe,
|
|
213
243
|
assertTierWritable,
|
|
214
244
|
liveRecordIsElevated
|
|
215
|
-
} from "./chunk-
|
|
245
|
+
} from "./chunk-JYJFGD2H.js";
|
|
216
246
|
import {
|
|
217
247
|
sha256Hex
|
|
218
|
-
} from "./chunk-
|
|
248
|
+
} from "./chunk-IXTSNGYY.js";
|
|
219
249
|
import {
|
|
220
250
|
NO_FORGET,
|
|
221
251
|
addSubjectRef,
|
|
@@ -224,10 +254,10 @@ import {
|
|
|
224
254
|
readDottedPath,
|
|
225
255
|
rebuildSubjectIndex,
|
|
226
256
|
removeSubjectRef
|
|
227
|
-
} from "./chunk-
|
|
257
|
+
} from "./chunk-OLEPKFTW.js";
|
|
228
258
|
import {
|
|
229
259
|
NO_SEALED_RECORD
|
|
230
|
-
} from "./chunk-
|
|
260
|
+
} from "./chunk-QD46HPZG.js";
|
|
231
261
|
import {
|
|
232
262
|
RecordCodec,
|
|
233
263
|
SEALED_CEK_NS,
|
|
@@ -238,20 +268,20 @@ import {
|
|
|
238
268
|
queryByDet,
|
|
239
269
|
resolveStableCek,
|
|
240
270
|
validateSchemaInput
|
|
241
|
-
} from "./chunk-
|
|
271
|
+
} from "./chunk-G2JUIDFA.js";
|
|
242
272
|
import {
|
|
243
273
|
buildDeleteMarker,
|
|
244
274
|
buildTombstone,
|
|
245
275
|
isDeleteMarker,
|
|
246
276
|
isTombstone
|
|
247
|
-
} from "./chunk-
|
|
277
|
+
} from "./chunk-W3L64Y3J.js";
|
|
248
278
|
import {
|
|
249
279
|
encrypt
|
|
250
|
-
} from "./chunk-
|
|
280
|
+
} from "./chunk-AKKRXT23.js";
|
|
251
281
|
import {
|
|
252
282
|
NOYDB_FORMAT_VERSION,
|
|
253
283
|
SealedHandle
|
|
254
|
-
} from "./chunk-
|
|
284
|
+
} from "./chunk-QBAC3GXA.js";
|
|
255
285
|
import {
|
|
256
286
|
AlreadyElevatedError,
|
|
257
287
|
AttestationError,
|
|
@@ -260,11 +290,12 @@ import {
|
|
|
260
290
|
ClassifiedVerifyError,
|
|
261
291
|
ConflictError,
|
|
262
292
|
DebugPlaintextError,
|
|
263
|
-
DerivationCapExceededError,
|
|
264
293
|
DictKeyInUseError,
|
|
265
294
|
ElevationExpiredError,
|
|
295
|
+
ExportCapabilityError,
|
|
266
296
|
FieldNotQueryableError,
|
|
267
297
|
ForgetStrategyNotConfiguredError,
|
|
298
|
+
ImportCapabilityError,
|
|
268
299
|
IndexWriteFailureError,
|
|
269
300
|
InvalidKeyError,
|
|
270
301
|
KeyringCorruptError,
|
|
@@ -291,14 +322,127 @@ import {
|
|
|
291
322
|
UnsupportedIndexOptionError,
|
|
292
323
|
UnsupportedTierCompositionError,
|
|
293
324
|
ValidationError
|
|
294
|
-
} from "./chunk-
|
|
325
|
+
} from "./chunk-QZWTRENR.js";
|
|
326
|
+
|
|
327
|
+
// src/with-commit/tx/strategy.ts
|
|
328
|
+
var NOT_ENABLED = new Error(
|
|
329
|
+
'Multi-record transactions require the tx strategy. Import `{ withTransactions }` from "@noy-db/hub/transactions" and pass it to `createNoydb({ transactionsStrategy: withTransactions() })`.'
|
|
330
|
+
);
|
|
331
|
+
var NO_TRANSACTIONS = {
|
|
332
|
+
async runTransaction(_db, _fn, _options, _txInvariants) {
|
|
333
|
+
throw NOT_ENABLED;
|
|
334
|
+
},
|
|
335
|
+
async runDryRun() {
|
|
336
|
+
throw NOT_ENABLED;
|
|
337
|
+
}
|
|
338
|
+
};
|
|
339
|
+
|
|
340
|
+
// src/port/with/archive-strategy.ts
|
|
341
|
+
var ARCHIVE_NOT_ENABLED = "vault.archive/restore/listArchived require `archiveStrategy: withArchive({ store })` in createNoydb";
|
|
342
|
+
var NO_ARCHIVE = {
|
|
343
|
+
get store() {
|
|
344
|
+
throw new Error(ARCHIVE_NOT_ENABLED);
|
|
345
|
+
}
|
|
346
|
+
};
|
|
347
|
+
|
|
348
|
+
// src/port/with/strategies.ts
|
|
349
|
+
var STRATEGY_DEFAULTS = {
|
|
350
|
+
reduce: NO_REDUCE,
|
|
351
|
+
archive: NO_ARCHIVE,
|
|
352
|
+
attestation: NO_ATTESTATION,
|
|
353
|
+
blobs: NO_BLOBS,
|
|
354
|
+
broker: NO_BROKER,
|
|
355
|
+
cargo: NO_CARGO,
|
|
356
|
+
classified: NO_CLASSIFIED,
|
|
357
|
+
consent: NO_CONSENT,
|
|
358
|
+
crdt: NO_CRDT,
|
|
359
|
+
custody: NO_CUSTODY,
|
|
360
|
+
forget: NO_FORGET,
|
|
361
|
+
history: NO_HISTORY,
|
|
362
|
+
i18n: NO_I18N,
|
|
363
|
+
indexing: NO_INDEXING,
|
|
364
|
+
lazy: IMPLICIT_LAZY,
|
|
365
|
+
periods: NO_PERIODS,
|
|
366
|
+
portability: NO_PORTABILITY,
|
|
367
|
+
sealedRecord: NO_SEALED_RECORD,
|
|
368
|
+
search: NO_SEARCH,
|
|
369
|
+
sequence: NO_SEQUENCE,
|
|
370
|
+
session: NO_SESSION,
|
|
371
|
+
shadow: NO_SHADOW,
|
|
372
|
+
snapshots: NO_SNAPSHOTS,
|
|
373
|
+
sync: NO_SYNC,
|
|
374
|
+
team: NO_TEAM,
|
|
375
|
+
tiers: NO_TIERS,
|
|
376
|
+
transactions: NO_TRANSACTIONS
|
|
377
|
+
};
|
|
378
|
+
var STRATEGY_KEYS = Object.keys(STRATEGY_DEFAULTS);
|
|
379
|
+
function resolveStrategies(options) {
|
|
380
|
+
const provided = options;
|
|
381
|
+
const resolved = { ...STRATEGY_DEFAULTS };
|
|
382
|
+
for (const key of STRATEGY_KEYS) {
|
|
383
|
+
const value = provided[`${key}Strategy`];
|
|
384
|
+
if (value !== void 0) resolved[key] = value;
|
|
385
|
+
}
|
|
386
|
+
return resolved;
|
|
387
|
+
}
|
|
295
388
|
|
|
296
389
|
// src/port/by/default-provider.ts
|
|
297
390
|
async function createDefaultCoordinationProvider(store) {
|
|
298
|
-
const { StoreCoordinationProvider } = await import("./store-coordination-provider-
|
|
391
|
+
const { StoreCoordinationProvider } = await import("./store-coordination-provider-EWRZL7XF.js");
|
|
299
392
|
return new StoreCoordinationProvider(store);
|
|
300
393
|
}
|
|
301
394
|
|
|
395
|
+
// src/port/with/collection-registries.ts
|
|
396
|
+
function populateCollectionRegistries(r, collectionName, options, effectiveViaFields) {
|
|
397
|
+
if (options?.refs) {
|
|
398
|
+
r.refRegistry.register(collectionName, options.refs);
|
|
399
|
+
}
|
|
400
|
+
if (effectiveViaFields.i18nFields) {
|
|
401
|
+
r.i18nFieldRegistry.set(collectionName, effectiveViaFields.i18nFields);
|
|
402
|
+
}
|
|
403
|
+
if (options?.blobFields) {
|
|
404
|
+
r.blobFieldsRegistry.set(collectionName, options.blobFields);
|
|
405
|
+
}
|
|
406
|
+
if (options?.archive) {
|
|
407
|
+
r.archiveRegistry.set(collectionName, options.archive);
|
|
408
|
+
}
|
|
409
|
+
if (options?.attestation !== void 0) {
|
|
410
|
+
r.attestation.register(collectionName, options.attestation);
|
|
411
|
+
}
|
|
412
|
+
if (effectiveViaFields.dictKeyFields || effectiveViaFields.lookupFields) {
|
|
413
|
+
const dictFieldMap = {};
|
|
414
|
+
const staticFieldMap = {};
|
|
415
|
+
for (const [field, desc] of Object.entries(effectiveViaFields.dictKeyFields ?? {})) {
|
|
416
|
+
if (isStaticDictDescriptor(desc)) {
|
|
417
|
+
staticFieldMap[field] = desc;
|
|
418
|
+
r.staticDictNames.add(desc.name);
|
|
419
|
+
r.staticByName.set(desc.name, desc);
|
|
420
|
+
} else {
|
|
421
|
+
dictFieldMap[field] = desc.name;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
const lookupCompat = collectLookupDictCompat(effectiveViaFields.lookupFields);
|
|
425
|
+
Object.assign(dictFieldMap, lookupCompat.dictFieldMap);
|
|
426
|
+
for (const [field, desc] of lookupCompat.staticEntries) {
|
|
427
|
+
staticFieldMap[field] = desc;
|
|
428
|
+
r.staticDictNames.add(desc.name);
|
|
429
|
+
r.staticByName.set(desc.name, desc);
|
|
430
|
+
}
|
|
431
|
+
if (Object.keys(dictFieldMap).length > 0) {
|
|
432
|
+
r.dictKeyFieldRegistry.set(collectionName, dictFieldMap);
|
|
433
|
+
for (const dictName of new Set(Object.values(dictFieldMap))) {
|
|
434
|
+
r.reservedLookupCollections.set(dictCollectionName(dictName), dictName);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
if (Object.keys(staticFieldMap).length > 0) {
|
|
438
|
+
r.staticDescriptorByField.set(collectionName, staticFieldMap);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
if ((options?.schemaUpdate?.length ?? 0) > 0) {
|
|
442
|
+
r.schemaUpdateNames.set(collectionName, (options.schemaUpdate ?? []).map((s) => s.name));
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
302
446
|
// src/kernel/via/pipeline.ts
|
|
303
447
|
var ViaPipeline = class _ViaPipeline {
|
|
304
448
|
constructor(bindings, taint) {
|
|
@@ -792,7 +936,7 @@ async function reconcileIndex(ctx, field, opts = {}) {
|
|
|
792
936
|
const persisted = ctx.persistedIndexes;
|
|
793
937
|
if (!persisted) {
|
|
794
938
|
throw new Error(
|
|
795
|
-
`Collection "${ctx.name}": indexing is disabled on this Noydb instance. Pass \`withIndexing()\` from "@noy-db/hub/indexing" to \`createNoydb({
|
|
939
|
+
`Collection "${ctx.name}": indexing is disabled on this Noydb instance. Pass \`withIndexing()\` from "@noy-db/hub/indexing" to \`createNoydb({ indexingStrategy })\`.`
|
|
796
940
|
);
|
|
797
941
|
}
|
|
798
942
|
if (!persisted.has(field)) {
|
|
@@ -964,61 +1108,6 @@ async function resolveTierSyncPrior(ctx, id, priorEnvelope) {
|
|
|
964
1108
|
return await ctx.codec.decryptRecord(priorEnvelope, { skipValidation: true, id });
|
|
965
1109
|
}
|
|
966
1110
|
|
|
967
|
-
// src/with-commit/history/strategy.ts
|
|
968
|
-
function notEnabled(op) {
|
|
969
|
-
return new Error(
|
|
970
|
-
`${op} requires the history strategy. Import \`{ withHistory }\` from "@noy-db/hub/history" and pass it to \`createNoydb({ historyStrategy: withHistory() })\`.`
|
|
971
|
-
);
|
|
972
|
-
}
|
|
973
|
-
var NO_HISTORY = {
|
|
974
|
-
async saveHistory() {
|
|
975
|
-
},
|
|
976
|
-
async getHistoryEntries() {
|
|
977
|
-
throw notEnabled("collection.history()");
|
|
978
|
-
},
|
|
979
|
-
async getVersionEnvelope() {
|
|
980
|
-
throw notEnabled("collection.getVersion()");
|
|
981
|
-
},
|
|
982
|
-
async pruneHistory() {
|
|
983
|
-
return 0;
|
|
984
|
-
},
|
|
985
|
-
async clearHistory() {
|
|
986
|
-
return 0;
|
|
987
|
-
},
|
|
988
|
-
async tombstoneHistory() {
|
|
989
|
-
return 0;
|
|
990
|
-
},
|
|
991
|
-
async rewrapHistory() {
|
|
992
|
-
},
|
|
993
|
-
async envelopePayloadHash() {
|
|
994
|
-
return "";
|
|
995
|
-
},
|
|
996
|
-
computePatch() {
|
|
997
|
-
return [];
|
|
998
|
-
},
|
|
999
|
-
diff() {
|
|
1000
|
-
throw notEnabled("collection.diff()");
|
|
1001
|
-
},
|
|
1002
|
-
buildLedger() {
|
|
1003
|
-
return null;
|
|
1004
|
-
},
|
|
1005
|
-
buildVaultInstant() {
|
|
1006
|
-
throw notEnabled("vault.at() / vault.timeMachine()");
|
|
1007
|
-
}
|
|
1008
|
-
};
|
|
1009
|
-
|
|
1010
|
-
// src/with-lookup/indexing/strategy.ts
|
|
1011
|
-
var NO_INDEXING = {
|
|
1012
|
-
createState() {
|
|
1013
|
-
return DISABLED_STATE;
|
|
1014
|
-
}
|
|
1015
|
-
};
|
|
1016
|
-
var DISABLED_STATE = {
|
|
1017
|
-
isEnabled: false,
|
|
1018
|
-
getEagerIndexes: () => null,
|
|
1019
|
-
getPersistedIndexes: () => null
|
|
1020
|
-
};
|
|
1021
|
-
|
|
1022
1111
|
// src/with-lookup/search/serialize.ts
|
|
1023
1112
|
function serializeIndex(idx) {
|
|
1024
1113
|
return JSON.stringify(idx.toSnapshot());
|
|
@@ -1621,164 +1710,6 @@ function buildDescription(input) {
|
|
|
1621
1710
|
};
|
|
1622
1711
|
}
|
|
1623
1712
|
|
|
1624
|
-
// src/via/blob/binding.ts
|
|
1625
|
-
async function eraseBlobs(ctx, cfg) {
|
|
1626
|
-
if (cfg.purgeBlobsForRecord) return cfg.purgeBlobsForRecord(ctx.id);
|
|
1627
|
-
return { shredded: 0, residue: [] };
|
|
1628
|
-
}
|
|
1629
|
-
function buildBlobDescribeFragment(fields) {
|
|
1630
|
-
return {
|
|
1631
|
-
blobFields: Object.fromEntries(
|
|
1632
|
-
Object.entries(fields).map(([field, p]) => [field, {
|
|
1633
|
-
...p.retainDays !== void 0 ? { retainDays: p.retainDays } : {},
|
|
1634
|
-
...p.evictWhen !== void 0 ? { evictWhen: true } : {},
|
|
1635
|
-
...p.legalHold !== void 0 ? { legalHold: true } : {},
|
|
1636
|
-
...p.retainUntil !== void 0 ? { retainUntil: true } : {},
|
|
1637
|
-
...p.external === true ? { external: true } : {},
|
|
1638
|
-
...p.public === true ? { public: true } : {},
|
|
1639
|
-
...p.backlink !== void 0 ? { backlink: p.backlink } : {}
|
|
1640
|
-
}])
|
|
1641
|
-
)
|
|
1642
|
-
};
|
|
1643
|
-
}
|
|
1644
|
-
function blobBinding(cfg) {
|
|
1645
|
-
return {
|
|
1646
|
-
brand: "blob",
|
|
1647
|
-
// encryptedAtRest: 'envelope' — blob chunks are AEAD-encrypted envelopes
|
|
1648
|
-
// in `_blob_chunks` (service-side), not sealed record fields; queryable:
|
|
1649
|
-
// 'none' — nothing indexes blob content; exportable — vault.exportBlobs()
|
|
1650
|
-
// is a first-class door; forgettable — shredAllForRecord participates in
|
|
1651
|
-
// vault.forget().
|
|
1652
|
-
posture: { encryptedAtRest: "envelope", queryable: "none", exportable: true, forgettable: true },
|
|
1653
|
-
covers: (field) => field in cfg.fields,
|
|
1654
|
-
erase: (ctx) => eraseBlobs(ctx, cfg),
|
|
1655
|
-
describeFragment: () => buildBlobDescribeFragment(cfg.fields)
|
|
1656
|
-
};
|
|
1657
|
-
}
|
|
1658
|
-
function linkBlobVia() {
|
|
1659
|
-
installViaBinder("blob", (c) => blobBinding(c));
|
|
1660
|
-
}
|
|
1661
|
-
|
|
1662
|
-
// src/port/with/blob-strategy.ts
|
|
1663
|
-
linkBlobVia();
|
|
1664
|
-
var NO_BLOBS = {
|
|
1665
|
-
openSlot() {
|
|
1666
|
-
throw new Error(
|
|
1667
|
-
'Blob storage is not enabled on this Noydb instance. Import `{ withBlobs }` from "@noy-db/hub/blobs" and pass `withBlobs()` to `createNoydb({ blobStrategy: withBlobs() })`.'
|
|
1668
|
-
);
|
|
1669
|
-
}
|
|
1670
|
-
};
|
|
1671
|
-
|
|
1672
|
-
// src/with-formula/derivations/stale.ts
|
|
1673
|
-
var _staleByRegistry = /* @__PURE__ */ new WeakMap();
|
|
1674
|
-
var keyFor = (source, sourceId) => `${source}/${sourceId}`;
|
|
1675
|
-
async function markStale(registry, strategy, sourceId) {
|
|
1676
|
-
let map = _staleByRegistry.get(registry);
|
|
1677
|
-
if (!map) {
|
|
1678
|
-
map = /* @__PURE__ */ new Map();
|
|
1679
|
-
_staleByRegistry.set(registry, map);
|
|
1680
|
-
}
|
|
1681
|
-
const k = keyFor(strategy.source, sourceId);
|
|
1682
|
-
let set = map.get(k);
|
|
1683
|
-
if (!set) {
|
|
1684
|
-
set = /* @__PURE__ */ new Set();
|
|
1685
|
-
map.set(k, set);
|
|
1686
|
-
}
|
|
1687
|
-
set.add(strategy);
|
|
1688
|
-
}
|
|
1689
|
-
async function resolveStaleOnRead(accessor, outputCollection, id) {
|
|
1690
|
-
const registry = accessor.registry();
|
|
1691
|
-
const producers = registry.strategiesProducingOutput(outputCollection);
|
|
1692
|
-
if (producers.length === 0) return;
|
|
1693
|
-
const map = _staleByRegistry.get(registry);
|
|
1694
|
-
if (!map) return;
|
|
1695
|
-
let DerivationExecutor = null;
|
|
1696
|
-
for (const { spec, strategyHash } of producers) {
|
|
1697
|
-
const k = keyFor(spec.source, id);
|
|
1698
|
-
const pending = map.get(k);
|
|
1699
|
-
if (!pending || !pending.has(spec)) continue;
|
|
1700
|
-
const sourceColl = accessor.getCollection(spec.source);
|
|
1701
|
-
const source = await sourceColl.get(id);
|
|
1702
|
-
if (!source) {
|
|
1703
|
-
pending.delete(spec);
|
|
1704
|
-
continue;
|
|
1705
|
-
}
|
|
1706
|
-
const sourceWithId = { ...source, id };
|
|
1707
|
-
if (DerivationExecutor === null) {
|
|
1708
|
-
({ DerivationExecutor } = await import("./executor-XGIS6CR7.js"));
|
|
1709
|
-
}
|
|
1710
|
-
const ctx = { vault: accessor.getReadOnlyFacade() };
|
|
1711
|
-
const result = await DerivationExecutor.run(spec, sourceWithId, 0, strategyHash, ctx);
|
|
1712
|
-
for (const key of Object.keys(spec.outputs)) {
|
|
1713
|
-
const out = result.outputs[key];
|
|
1714
|
-
if (!out) continue;
|
|
1715
|
-
if (out.kind === "failed") {
|
|
1716
|
-
const err = out.error;
|
|
1717
|
-
if (spec.strict) {
|
|
1718
|
-
throw err;
|
|
1719
|
-
}
|
|
1720
|
-
console.warn(
|
|
1721
|
-
`[derivation] lazy output "${key}" for source "${spec.source}" id="${id}" failed:`,
|
|
1722
|
-
err
|
|
1723
|
-
);
|
|
1724
|
-
continue;
|
|
1725
|
-
}
|
|
1726
|
-
if (out.kind === "array") {
|
|
1727
|
-
console.warn(
|
|
1728
|
-
`[derivation] unexpected array-shape output "${key}" in lazy resolve path; array-shape derivations require lifecycle: "eager".`
|
|
1729
|
-
);
|
|
1730
|
-
continue;
|
|
1731
|
-
}
|
|
1732
|
-
const outSpec = spec.outputs[key];
|
|
1733
|
-
if (!outSpec) continue;
|
|
1734
|
-
const outputColl = accessor.getCollection(outSpec.collection);
|
|
1735
|
-
if (out.skipped === true) {
|
|
1736
|
-
await outputColl._internalDelete(id, accessor.getActiveTxContext());
|
|
1737
|
-
continue;
|
|
1738
|
-
}
|
|
1739
|
-
await outputColl.put(id, out.value);
|
|
1740
|
-
}
|
|
1741
|
-
pending.delete(spec);
|
|
1742
|
-
}
|
|
1743
|
-
}
|
|
1744
|
-
|
|
1745
|
-
// src/with-commit/crdt/strategy.ts
|
|
1746
|
-
var NOT_ENABLED = new Error(
|
|
1747
|
-
'CRDT mode requires the CRDT strategy. Import `{ withCrdt }` from "@noy-db/hub/crdt" and pass it to `createNoydb({ crdtStrategy: withCrdt() })`.'
|
|
1748
|
-
);
|
|
1749
|
-
var NO_CRDT = {
|
|
1750
|
-
buildLwwMapState() {
|
|
1751
|
-
throw NOT_ENABLED;
|
|
1752
|
-
},
|
|
1753
|
-
buildRgaState() {
|
|
1754
|
-
throw NOT_ENABLED;
|
|
1755
|
-
},
|
|
1756
|
-
mergeCrdtStates() {
|
|
1757
|
-
throw NOT_ENABLED;
|
|
1758
|
-
},
|
|
1759
|
-
resolveCrdtSnapshot() {
|
|
1760
|
-
throw NOT_ENABLED;
|
|
1761
|
-
}
|
|
1762
|
-
};
|
|
1763
|
-
|
|
1764
|
-
// src/with-party/team/sync-strategy.ts
|
|
1765
|
-
function notEnabled2(op) {
|
|
1766
|
-
return new Error(
|
|
1767
|
-
`${op} requires the sync strategy. Import \`{ withSync }\` from "@noy-db/hub/sync" and pass it to \`createNoydb({ syncStrategy: withSync() })\`.`
|
|
1768
|
-
);
|
|
1769
|
-
}
|
|
1770
|
-
var NO_SYNC = {
|
|
1771
|
-
buildSyncEngine() {
|
|
1772
|
-
throw notEnabled2("SyncEngine");
|
|
1773
|
-
},
|
|
1774
|
-
buildSyncTransaction() {
|
|
1775
|
-
throw notEnabled2("SyncTransaction");
|
|
1776
|
-
},
|
|
1777
|
-
buildPresence() {
|
|
1778
|
-
throw notEnabled2("collection.presence()");
|
|
1779
|
-
}
|
|
1780
|
-
};
|
|
1781
|
-
|
|
1782
1713
|
// src/kernel/via/compose.ts
|
|
1783
1714
|
function via(...descriptors) {
|
|
1784
1715
|
if (descriptors.length === 0) {
|
|
@@ -1942,7 +1873,7 @@ function compileViaBindings(opts, classifiedGuardCtx, eraseCfgOut) {
|
|
|
1942
1873
|
...i18nFields !== void 0 ? { i18nFields } : {},
|
|
1943
1874
|
...dictKeyFields !== void 0 ? { dictKeyFields } : {},
|
|
1944
1875
|
...i18nDensifyFields !== void 0 ? { i18nDensifyFields } : {},
|
|
1945
|
-
strategy: opts.
|
|
1876
|
+
strategy: opts.strategies.i18n,
|
|
1946
1877
|
...opts.defaultLocale !== void 0 ? { defaultLocale: opts.defaultLocale } : {},
|
|
1947
1878
|
...opts.autoTranslateHook !== void 0 ? { autoTranslateHook: opts.autoTranslateHook } : {},
|
|
1948
1879
|
...opts.dictLabelResolver !== void 0 ? { dictLabelResolver: opts.dictLabelResolver } : {},
|
|
@@ -2056,6 +1987,11 @@ function resolveCollectionConfig(opts) {
|
|
|
2056
1987
|
`Collection "${opts.name}": embeddings are not supported on CRDT collections (L2). Use a non-CRDT collection for semantic search.`
|
|
2057
1988
|
);
|
|
2058
1989
|
}
|
|
1990
|
+
if (opts.sensitive && opts.sensitive.length > 0 && opts.crdt) {
|
|
1991
|
+
throw new Error(
|
|
1992
|
+
`Collection "${opts.name}": sensitive (structural group-encryption) is not supported on CRDT collections \u2014 the CRDT write path bypasses per-field sealing, so the fields would be stored in the ordinary encrypted body with no \`_sealed\` slot and no per-field key. Use a non-CRDT collection for sealed fields.`
|
|
1993
|
+
);
|
|
1994
|
+
}
|
|
2059
1995
|
if (opts.tiers && opts.tiers.length > 0 && opts.blobFields !== void 0 && Object.keys(opts.blobFields).length > 0 && opts.perRecordKeys !== true) {
|
|
2060
1996
|
throw new UnsupportedTierCompositionError(
|
|
2061
1997
|
"blobs",
|
|
@@ -2172,14 +2108,9 @@ function resolveCollectionConfig(opts) {
|
|
|
2172
2108
|
writeHooks: opts.writeHooks,
|
|
2173
2109
|
subsystemBus: opts.subsystemBus,
|
|
2174
2110
|
activeTxId: opts.activeTxId,
|
|
2175
|
-
|
|
2111
|
+
strategies: opts.strategies,
|
|
2176
2112
|
objectStore: opts.objectStore,
|
|
2177
2113
|
blobFields: opts.blobFields,
|
|
2178
|
-
aggregateStrategy: opts.aggregateStrategy ?? NO_AGGREGATE,
|
|
2179
|
-
crdtStrategy: opts.crdtStrategy ?? NO_CRDT,
|
|
2180
|
-
historyStrategy: opts.historyStrategy ?? NO_HISTORY,
|
|
2181
|
-
i18nStrategy: opts.i18nStrategy ?? NO_I18N,
|
|
2182
|
-
syncStrategy: opts.syncStrategy ?? NO_SYNC,
|
|
2183
2114
|
reconcileOnOpen: opts.reconcileOnOpen ?? "off",
|
|
2184
2115
|
getDEK: opts.getDEK,
|
|
2185
2116
|
onDirty: opts.onDirty,
|
|
@@ -2208,7 +2139,6 @@ function resolveCollectionConfig(opts) {
|
|
|
2208
2139
|
moneyFields: effectiveViaFields.moneyFields,
|
|
2209
2140
|
classified: resolvedClassified,
|
|
2210
2141
|
classifiedGuardCtx,
|
|
2211
|
-
classifiedStrategy: opts.classifiedStrategy ?? NO_CLASSIFIED,
|
|
2212
2142
|
computed: mergedComputed,
|
|
2213
2143
|
computedEdges,
|
|
2214
2144
|
viaDepsEdges,
|
|
@@ -2230,8 +2160,6 @@ function resolveCollectionConfig(opts) {
|
|
|
2230
2160
|
materializedViewSource: opts.materializedViewSource,
|
|
2231
2161
|
graphDispatch: opts.graphDispatch,
|
|
2232
2162
|
tiers: opts.tiers && opts.tiers.length > 0 ? new Set(opts.tiers) : null,
|
|
2233
|
-
tiersStrategy: opts.tiersStrategy ?? NO_TIERS,
|
|
2234
|
-
searchStrategy: opts.searchStrategy ?? NO_SEARCH,
|
|
2235
2163
|
tierMode: opts.tierMode ?? "invisibility",
|
|
2236
2164
|
blobTierPolicy: opts.blobTierPolicy ?? "isolate",
|
|
2237
2165
|
onCrossTierAccess: opts.onCrossTierAccess,
|
|
@@ -2246,22 +2174,12 @@ function resolveCollectionConfig(opts) {
|
|
|
2246
2174
|
}
|
|
2247
2175
|
|
|
2248
2176
|
// src/with-formula/computed/lazy.ts
|
|
2249
|
-
var
|
|
2177
|
+
var loadComputed = lazy(() => import("./computed-AB45PS4V.js"));
|
|
2250
2178
|
async function loadEvalComputedFields() {
|
|
2251
|
-
|
|
2252
|
-
return fn;
|
|
2179
|
+
return (await loadComputed()).evalComputedFields;
|
|
2253
2180
|
}
|
|
2254
2181
|
|
|
2255
2182
|
// src/kernel/collection.ts
|
|
2256
|
-
function selfWriteFieldEqual(a, b) {
|
|
2257
|
-
if (a === b) return true;
|
|
2258
|
-
if (a === null || b === null || typeof a !== "object" || typeof b !== "object") return false;
|
|
2259
|
-
try {
|
|
2260
|
-
return JSON.stringify(a) === JSON.stringify(b);
|
|
2261
|
-
} catch {
|
|
2262
|
-
return false;
|
|
2263
|
-
}
|
|
2264
|
-
}
|
|
2265
2183
|
var fallbackWarned = /* @__PURE__ */ new Set();
|
|
2266
2184
|
function warnOnceFallback(adapterName) {
|
|
2267
2185
|
if (fallbackWarned.has(adapterName)) return;
|
|
@@ -2293,25 +2211,20 @@ var Collection = class {
|
|
|
2293
2211
|
/** True when the caller explicitly provided a `historyConfig` option (vs. inheriting the vault default). */
|
|
2294
2212
|
historyConfigExplicit;
|
|
2295
2213
|
/**
|
|
2296
|
-
*
|
|
2297
|
-
*
|
|
2298
|
-
*
|
|
2299
|
-
*
|
|
2300
|
-
*
|
|
2301
|
-
*
|
|
2302
|
-
* reaches the bundle
|
|
2214
|
+
* Every opt-in service, resolved once by `createNoydb` (#838) and shared by
|
|
2215
|
+
* reference with the owning `Vault` and `Noydb`.
|
|
2216
|
+
*
|
|
2217
|
+
* Each entry is a tree-shake seam. An un-opted-in service resolves to its
|
|
2218
|
+
* `NO_*` stub — a tiny module that throws with an actionable message —
|
|
2219
|
+
* so, for example, none of the BlobSet / chunk / MIME-magic machinery
|
|
2220
|
+
* reaches the bundle unless the consumer imports `@noy-db/hub/blobs` and
|
|
2221
|
+
* passes `blobsStrategy: blobs()` to `createNoydb`.
|
|
2303
2222
|
*/
|
|
2304
|
-
|
|
2223
|
+
strategies;
|
|
2305
2224
|
objectStore;
|
|
2306
2225
|
blobFields;
|
|
2307
2226
|
blobTierPolicy;
|
|
2308
2227
|
// #724 T2/T3
|
|
2309
|
-
aggregateStrategy;
|
|
2310
|
-
crdtStrategy;
|
|
2311
|
-
tiersStrategy;
|
|
2312
|
-
searchStrategy;
|
|
2313
|
-
historyStrategy;
|
|
2314
|
-
syncStrategy;
|
|
2315
2228
|
// In-memory cache of decrypted records (eager mode only). Lazy mode
|
|
2316
2229
|
// uses `lru` instead. Both fields exist so a single Collection instance
|
|
2317
2230
|
// doesn't need a runtime branch on every cache access.
|
|
@@ -2347,7 +2260,7 @@ var Collection = class {
|
|
|
2347
2260
|
lru;
|
|
2348
2261
|
/**
|
|
2349
2262
|
* tree-shake seam — per-Collection indexing state. Owned by the
|
|
2350
|
-
* `
|
|
2263
|
+
* `IndexingStrategy` passed through from `createNoydb({ indexingStrategy })`.
|
|
2351
2264
|
* Defaults to a disabled state (both accessors return null) so the
|
|
2352
2265
|
* `CollectionIndexes` / `PersistedCollectionIndex` / `LazyQuery`
|
|
2353
2266
|
* classes never reach the bundle when indexing is unused.
|
|
@@ -2481,12 +2394,6 @@ var Collection = class {
|
|
|
2481
2394
|
/** C-A/R10 memoization: marker declared-set lookup (undefined=unresolved) + classified-handle persist-once flag. */
|
|
2482
2395
|
_markerDigestOnlyCache = void 0;
|
|
2483
2396
|
_markerPersisted = false;
|
|
2484
|
-
/**
|
|
2485
|
-
* Tree-shake seam for `reveal()` — defaults to `NO_CLASSIFIED`, which
|
|
2486
|
-
* throws `ClassifiedNotEnabledError`. Set via the `classifiedStrategy`
|
|
2487
|
-
* `createNoydb()` option (opt in with `withClassified()`).
|
|
2488
|
-
*/
|
|
2489
|
-
classifiedStrategy;
|
|
2490
2397
|
/** Async callback provided by the Vault to open a dynamic dictionary handle (for label-map pre-computation in the search index). Only used in `resolveDictLabelMaps()`; static dicts bypass this entirely. Mutable, assign-once — see {@link _reconcileReadState} (#671 item 1). */
|
|
2491
2398
|
getDictionary;
|
|
2492
2399
|
/**
|
|
@@ -2635,16 +2542,10 @@ var Collection = class {
|
|
|
2635
2542
|
this.writeHooks = cfg.writeHooks;
|
|
2636
2543
|
this.subsystemBus = cfg.subsystemBus;
|
|
2637
2544
|
this.activeTxId = cfg.activeTxId;
|
|
2638
|
-
this.
|
|
2545
|
+
this.strategies = cfg.strategies;
|
|
2639
2546
|
this.objectStore = cfg.objectStore;
|
|
2640
2547
|
this.blobFields = cfg.blobFields;
|
|
2641
2548
|
this.blobTierPolicy = cfg.blobTierPolicy ?? "isolate";
|
|
2642
|
-
this.aggregateStrategy = cfg.aggregateStrategy;
|
|
2643
|
-
this.crdtStrategy = cfg.crdtStrategy;
|
|
2644
|
-
this.tiersStrategy = cfg.tiersStrategy;
|
|
2645
|
-
this.searchStrategy = cfg.searchStrategy;
|
|
2646
|
-
this.historyStrategy = cfg.historyStrategy;
|
|
2647
|
-
this.syncStrategy = cfg.syncStrategy;
|
|
2648
2549
|
this.reconcileOnOpen = cfg.reconcileOnOpen;
|
|
2649
2550
|
this.getDEK = cfg.getDEK;
|
|
2650
2551
|
this.onDirty = cfg.onDirty;
|
|
@@ -2671,7 +2572,6 @@ var Collection = class {
|
|
|
2671
2572
|
this.classified = cfg.classified;
|
|
2672
2573
|
this.classifiedGuardCtx = cfg.classifiedGuardCtx;
|
|
2673
2574
|
this.vdigFields = cfg.vdigFields;
|
|
2674
|
-
this.classifiedStrategy = cfg.classifiedStrategy;
|
|
2675
2575
|
this.computed = cfg.computed;
|
|
2676
2576
|
this.getDictionary = cfg.getDictionary;
|
|
2677
2577
|
this.defaultLocale = cfg.defaultLocale;
|
|
@@ -2719,7 +2619,7 @@ var Collection = class {
|
|
|
2719
2619
|
deterministicFields: this.deterministicFields,
|
|
2720
2620
|
vdigFields: this.vdigFields,
|
|
2721
2621
|
crdtMode: this.crdtMode,
|
|
2722
|
-
crdtStrategy: this.
|
|
2622
|
+
crdtStrategy: this.strategies.crdt,
|
|
2723
2623
|
schema: this.schema,
|
|
2724
2624
|
getDEK: (collection) => this.getDEK(collection ?? this.name),
|
|
2725
2625
|
cekCache: this.cekCache,
|
|
@@ -2737,7 +2637,7 @@ var Collection = class {
|
|
|
2737
2637
|
const remoteJson = await this.codec.decryptJsonString(remote, id);
|
|
2738
2638
|
if (localJson === null) return local;
|
|
2739
2639
|
if (remoteJson === null) return remote;
|
|
2740
|
-
const merged = this.
|
|
2640
|
+
const merged = this.strategies.crdt.mergeCrdtStates(JSON.parse(localJson), JSON.parse(remoteJson));
|
|
2741
2641
|
const mergedVersion = Math.max(local._v, remote._v) + 1;
|
|
2742
2642
|
const cek = this.perRecordCek ? await this.resolveRecordCek(id) : void 0;
|
|
2743
2643
|
return this.codec.encryptJsonString(JSON.stringify(merged), mergedVersion, cek);
|
|
@@ -2795,12 +2695,12 @@ var Collection = class {
|
|
|
2795
2695
|
}
|
|
2796
2696
|
this.lazy = opts.prefetch === false;
|
|
2797
2697
|
if (this.lazy) {
|
|
2798
|
-
this.lru =
|
|
2698
|
+
this.lru = opts.strategies.lazy.createCache(this.name, opts.cache);
|
|
2799
2699
|
this.hydrated = true;
|
|
2800
2700
|
} else {
|
|
2801
2701
|
this.lru = null;
|
|
2802
2702
|
}
|
|
2803
|
-
const strategy = opts.
|
|
2703
|
+
const strategy = opts.strategies.indexing;
|
|
2804
2704
|
this.indexState = strategy.createState({
|
|
2805
2705
|
defs: opts.indexes ?? [],
|
|
2806
2706
|
lazy: this.lazy
|
|
@@ -2955,7 +2855,7 @@ var Collection = class {
|
|
|
2955
2855
|
if (spec.storage === "digest-only") {
|
|
2956
2856
|
throw new ClassifiedRevealError(this.name, field, `storage:'digest-only' \u2014 verify-only; nothing recoverable to reveal`);
|
|
2957
2857
|
}
|
|
2958
|
-
return this.
|
|
2858
|
+
return this.strategies.classified.reveal({
|
|
2959
2859
|
collection: this.name,
|
|
2960
2860
|
spec,
|
|
2961
2861
|
encrypted: this.storeCiphertext,
|
|
@@ -2975,7 +2875,7 @@ var Collection = class {
|
|
|
2975
2875
|
throw new ClassifiedVerifyError(this.name, field, `storage:'never' \u2014 nothing is stored to verify against`);
|
|
2976
2876
|
}
|
|
2977
2877
|
const ctx = this._classifiedVerifyCtx(spec);
|
|
2978
|
-
return spec.storage === "digest-only" ? this.
|
|
2878
|
+
return spec.storage === "digest-only" ? this.strategies.classified.verify(ctx, id, field, candidate) : this.strategies.classified.verifyText(ctx, id, field, candidate);
|
|
2979
2879
|
}
|
|
2980
2880
|
/** k-of-n challenge over the collection's secretAnswer members. Requires withClassified(). */
|
|
2981
2881
|
async verifyGroup(id, answers, opts) {
|
|
@@ -2984,7 +2884,7 @@ var Collection = class {
|
|
|
2984
2884
|
throw new ClassifiedVerifyError(this.name, "*", "no groupable digest-only (secretAnswer) fields declared");
|
|
2985
2885
|
}
|
|
2986
2886
|
const ctx = { ...this._classifiedVerifyCtx(members[0].spec), groupMembers: members };
|
|
2987
|
-
return this.
|
|
2887
|
+
return this.strategies.classified.matchGroup(ctx, id, answers, opts);
|
|
2988
2888
|
}
|
|
2989
2889
|
_classifiedVerifyCtx(spec) {
|
|
2990
2890
|
return {
|
|
@@ -3039,7 +2939,7 @@ var Collection = class {
|
|
|
3039
2939
|
if (typeof candidate !== "string") {
|
|
3040
2940
|
throw new ClassifiedVerifyError(this.name, "*", "candidate must be a string");
|
|
3041
2941
|
}
|
|
3042
|
-
const target = await this.
|
|
2942
|
+
const target = await this.strategies.classified.computeTarget(this._classifiedVerifyCtx(spec), field, candidate);
|
|
3043
2943
|
const ids = await this.adapter.list(this.vault, this.name);
|
|
3044
2944
|
const hits = [];
|
|
3045
2945
|
const hitMap = /* @__PURE__ */ new Map();
|
|
@@ -3052,7 +2952,7 @@ var Collection = class {
|
|
|
3052
2952
|
}
|
|
3053
2953
|
await this.onAccess?.("find", "*");
|
|
3054
2954
|
if (hits.length === 0) return [];
|
|
3055
|
-
const { verifyDigestField } = await import("./verify-
|
|
2955
|
+
const { verifyDigestField } = await import("./verify-7XWHJWUN.js");
|
|
3056
2956
|
const policy = {
|
|
3057
2957
|
normalize: spec.verifyNormalize ?? "password",
|
|
3058
2958
|
notLastN: spec.notLastN ?? 0,
|
|
@@ -3126,7 +3026,7 @@ var Collection = class {
|
|
|
3126
3026
|
id,
|
|
3127
3027
|
version: scrubbed._v,
|
|
3128
3028
|
actor: this.keyring.userId,
|
|
3129
|
-
payloadHash: await this.
|
|
3029
|
+
payloadHash: await this.strategies.history.envelopePayloadHash(scrubbed),
|
|
3130
3030
|
reason: "classified:scrub-equatable-tags"
|
|
3131
3031
|
});
|
|
3132
3032
|
}
|
|
@@ -3258,7 +3158,7 @@ var Collection = class {
|
|
|
3258
3158
|
}
|
|
3259
3159
|
}
|
|
3260
3160
|
if (this.materializedViewSource !== void 0) {
|
|
3261
|
-
const { resolveStaleMVOnRead } = await import("./stale-
|
|
3161
|
+
const { resolveStaleMVOnRead } = await import("./stale-A4J26OIC.js");
|
|
3262
3162
|
await resolveStaleMVOnRead(this.materializedViewSource, this.name, this.#dispatchCtx({ collection: this.name, id: "resolve-on-read" }));
|
|
3263
3163
|
}
|
|
3264
3164
|
let record;
|
|
@@ -3352,7 +3252,7 @@ var Collection = class {
|
|
|
3352
3252
|
if (this.syncAdapter !== void 0) presenceOpts.syncAdapter = this.syncAdapter;
|
|
3353
3253
|
if (opts?.staleMs !== void 0) presenceOpts.staleMs = opts.staleMs;
|
|
3354
3254
|
if (opts?.pollIntervalMs !== void 0) presenceOpts.pollIntervalMs = opts.pollIntervalMs;
|
|
3355
|
-
return this.
|
|
3255
|
+
return this.strategies.sync.buildPresence(presenceOpts);
|
|
3356
3256
|
}
|
|
3357
3257
|
/**
|
|
3358
3258
|
* Create or update a record. Runs inside the hub's write-queue tracker
|
|
@@ -3514,6 +3414,103 @@ var Collection = class {
|
|
|
3514
3414
|
return clone;
|
|
3515
3415
|
}
|
|
3516
3416
|
/** @internal Untracked put body — call {@link put}, not this. */
|
|
3417
|
+
/**
|
|
3418
|
+
* Decode a prior envelope's CRDT state, or `undefined` when there is no
|
|
3419
|
+
* usable prior: no envelope, a shredded body decrypting to `null`, or a
|
|
3420
|
+
* payload that is not a CRDT state. The `lww-map` and `rga` branches each
|
|
3421
|
+
* carried a copy, byte-identical apart from the cast (#842).
|
|
3422
|
+
*/
|
|
3423
|
+
async #decodePriorCrdtState(envelope) {
|
|
3424
|
+
if (!envelope) return void 0;
|
|
3425
|
+
const prevJson = await this.codec.decryptJsonString(envelope);
|
|
3426
|
+
if (prevJson === null) return void 0;
|
|
3427
|
+
const prevParsed = JSON.parse(prevJson);
|
|
3428
|
+
if (prevParsed === null || typeof prevParsed !== "object" || !("_crdt" in prevParsed)) {
|
|
3429
|
+
return void 0;
|
|
3430
|
+
}
|
|
3431
|
+
return prevParsed;
|
|
3432
|
+
}
|
|
3433
|
+
/**
|
|
3434
|
+
* Record a write on the active transaction so a mid-batch failure rolls it
|
|
3435
|
+
* back. Four sites in the derivation/MV dispatch hand-built this literal (#842).
|
|
3436
|
+
*/
|
|
3437
|
+
#trackPut(txCtx, collectionName, id, priorEnvelope) {
|
|
3438
|
+
txCtx._executed.push({
|
|
3439
|
+
op: { type: "put", vaultName: this.vault, collectionName, id },
|
|
3440
|
+
priorEnvelope
|
|
3441
|
+
});
|
|
3442
|
+
}
|
|
3443
|
+
/**
|
|
3444
|
+
* Snapshot the PRIOR version into history, emit, and prune.
|
|
3445
|
+
*
|
|
3446
|
+
* Deliberately does NOT carry `source` from the current write — a history
|
|
3447
|
+
* entry describes the version being replaced, not the one replacing it.
|
|
3448
|
+
*
|
|
3449
|
+
* Kept OUT of {@link #commitWriteTail} because the two paths call it at
|
|
3450
|
+
* different points: the normal path snapshots BEFORE `adapter.put` (so a
|
|
3451
|
+
* history failure leaves no write behind), while the CRDT path must merge
|
|
3452
|
+
* and persist first to resolve the prior record at all. Folding it into the
|
|
3453
|
+
* tail would silently reorder one of them (#842).
|
|
3454
|
+
*/
|
|
3455
|
+
async #savePriorHistory(id, prior, cek, vdigCtx) {
|
|
3456
|
+
if (this.historyConfig.enabled === false) return;
|
|
3457
|
+
await this.strategies.history.saveHistory(
|
|
3458
|
+
this.adapter,
|
|
3459
|
+
this.vault,
|
|
3460
|
+
this.name,
|
|
3461
|
+
id,
|
|
3462
|
+
await this.codec.encryptRecord(prior.record, prior.version, cek, void 0, void 0, vdigCtx, id)
|
|
3463
|
+
);
|
|
3464
|
+
this.emitter.emit("history:save", { vault: this.vault, collection: this.name, id, version: prior.version });
|
|
3465
|
+
if (this.historyConfig.maxVersions) {
|
|
3466
|
+
await this.strategies.history.pruneHistory(this.adapter, this.vault, this.name, id, { keepVersions: this.historyConfig.maxVersions });
|
|
3467
|
+
}
|
|
3468
|
+
}
|
|
3469
|
+
/**
|
|
3470
|
+
* Everything both write paths do once the envelope is on the adapter:
|
|
3471
|
+
* classified marker, embedding sidecar, ledger append, cache/index
|
|
3472
|
+
* maintenance, and the mutation event that drives derivation dispatch.
|
|
3473
|
+
*
|
|
3474
|
+
* The CRDT branch used to re-implement all of it, and in doing so skipped
|
|
3475
|
+
* `_ensureClassifiedMarker`, the unique-constraint upsert and
|
|
3476
|
+
* `_toCacheableRecord` (#835). All three were unreachable — each blocked by
|
|
3477
|
+
* a config-time refusal on CRDT collections — but only by accident of what
|
|
3478
|
+
* that copy happened to omit. One tail makes the divergence unrepresentable
|
|
3479
|
+
* rather than merely unreachable; on a CRDT collection the extra steps are
|
|
3480
|
+
* provably no-ops (classified/unique + crdt are refused at construction, and
|
|
3481
|
+
* a CRDT body never produces a `_sealed` slot, so `_toCacheableRecord` is
|
|
3482
|
+
* the identity).
|
|
3483
|
+
*/
|
|
3484
|
+
async #commitWriteTail(args) {
|
|
3485
|
+
const { id, envelope, version, indexed, event, prior, reason } = args;
|
|
3486
|
+
await this._ensureClassifiedMarker();
|
|
3487
|
+
if (this.embeddings) {
|
|
3488
|
+
await this.strategies.search.embedOnWrite(this.searchContext(), id, indexed, version);
|
|
3489
|
+
}
|
|
3490
|
+
if (this.ledger) {
|
|
3491
|
+
const appendInput = {
|
|
3492
|
+
op: "put",
|
|
3493
|
+
collection: this.name,
|
|
3494
|
+
id,
|
|
3495
|
+
version,
|
|
3496
|
+
actor: this.keyring.userId,
|
|
3497
|
+
payloadHash: await this.strategies.history.envelopePayloadHash(envelope)
|
|
3498
|
+
};
|
|
3499
|
+
if (prior) appendInput.delta = this.strategies.history.computePatch(indexed, prior.record);
|
|
3500
|
+
if (reason !== void 0) appendInput.reason = reason;
|
|
3501
|
+
await this.ledger.append(appendInput);
|
|
3502
|
+
}
|
|
3503
|
+
const cacheable = await this._toCacheableRecord(indexed, envelope, id);
|
|
3504
|
+
if (this.lazy && this.lru) {
|
|
3505
|
+
this.lru.set(id, { record: cacheable, version }, estimateRecordBytes(indexed));
|
|
3506
|
+
await this.maintainPersistedIndexesOnPut(id, indexed, prior ? prior.record : null, version);
|
|
3507
|
+
} else {
|
|
3508
|
+
this.cache.set(id, { record: cacheable, version });
|
|
3509
|
+
this.indexes?.upsert(id, indexed, prior ? prior.record : null);
|
|
3510
|
+
this.uniqueConstraints?.upsert(id, indexed, prior?.record);
|
|
3511
|
+
}
|
|
3512
|
+
await this._onRecordMutated(id, "put", "local-write", { record: event, version });
|
|
3513
|
+
}
|
|
3517
3514
|
async _putInternal(id, record, options) {
|
|
3518
3515
|
if (!hasWritePermission(this.keyring, this.name)) {
|
|
3519
3516
|
throw new ReadOnlyError();
|
|
@@ -3562,29 +3559,11 @@ var Collection = class {
|
|
|
3562
3559
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3563
3560
|
let crdtState;
|
|
3564
3561
|
if (this.crdtMode === "lww-map") {
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
const prevJson = await this.codec.decryptJsonString(existingEnvelope);
|
|
3568
|
-
if (prevJson !== null) {
|
|
3569
|
-
const prevParsed = JSON.parse(prevJson);
|
|
3570
|
-
if (prevParsed !== null && typeof prevParsed === "object" && "_crdt" in prevParsed) {
|
|
3571
|
-
existingState = prevParsed;
|
|
3572
|
-
}
|
|
3573
|
-
}
|
|
3574
|
-
}
|
|
3575
|
-
crdtState = this.crdtStrategy.buildLwwMapState(record, existingState, now);
|
|
3562
|
+
const existingState = await this.#decodePriorCrdtState(existingEnvelope);
|
|
3563
|
+
crdtState = this.strategies.crdt.buildLwwMapState(record, existingState, now);
|
|
3576
3564
|
} else if (this.crdtMode === "rga") {
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
const prevJson = await this.codec.decryptJsonString(existingEnvelope);
|
|
3580
|
-
if (prevJson !== null) {
|
|
3581
|
-
const prevParsed = JSON.parse(prevJson);
|
|
3582
|
-
if (prevParsed !== null && typeof prevParsed === "object" && "_crdt" in prevParsed) {
|
|
3583
|
-
existingState = prevParsed;
|
|
3584
|
-
}
|
|
3585
|
-
}
|
|
3586
|
-
}
|
|
3587
|
-
crdtState = this.crdtStrategy.buildRgaState(Array.isArray(record) ? record : [record], existingState, generateULID);
|
|
3565
|
+
const existingState = await this.#decodePriorCrdtState(existingEnvelope);
|
|
3566
|
+
crdtState = this.strategies.crdt.buildRgaState(Array.isArray(record) ? record : [record], existingState, generateULID);
|
|
3588
3567
|
} else {
|
|
3589
3568
|
crdtState = { _crdt: "yjs", update: record };
|
|
3590
3569
|
}
|
|
@@ -3592,42 +3571,21 @@ var Collection = class {
|
|
|
3592
3571
|
const cek2 = this.perRecordCek ? await this.resolveRecordCek(id) : void 0;
|
|
3593
3572
|
const envelope2 = await this.codec.encryptJsonString(JSON.stringify(crdtState), version2, cek2, options?.source, options?.sourceTs);
|
|
3594
3573
|
await this.adapter.put(this.vault, this.name, id, envelope2);
|
|
3595
|
-
const resolvedRecord = this.
|
|
3574
|
+
const resolvedRecord = this.strategies.crdt.resolveCrdtSnapshot(crdtState);
|
|
3596
3575
|
const existingResolvedRecord = existingEnvelope ? await this.codec.decryptRecord(existingEnvelope, { skipValidation: true }) : null;
|
|
3597
3576
|
const existingResolved = existingResolvedRecord !== null ? { record: existingResolvedRecord, version: existingVersion } : void 0;
|
|
3598
|
-
if (existingResolved
|
|
3599
|
-
await this
|
|
3600
|
-
this.emitter.emit("history:save", { vault: this.vault, collection: this.name, id, version: existingResolved.version });
|
|
3601
|
-
if (this.historyConfig.maxVersions) {
|
|
3602
|
-
await this.historyStrategy.pruneHistory(this.adapter, this.vault, this.name, id, { keepVersions: this.historyConfig.maxVersions });
|
|
3603
|
-
}
|
|
3577
|
+
if (existingResolved) {
|
|
3578
|
+
await this.#savePriorHistory(id, existingResolved, cek2, this.vdigFields !== null ? { id, prev: existingEnvelope } : void 0);
|
|
3604
3579
|
}
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
if (existingResolved) appendInput.delta = this.historyStrategy.computePatch(resolvedRecord, existingResolved.record);
|
|
3615
|
-
if (options?.reason !== void 0) appendInput.reason = options.reason;
|
|
3616
|
-
await this.ledger.append(appendInput);
|
|
3617
|
-
}
|
|
3618
|
-
if (this.lazy && this.lru) {
|
|
3619
|
-
this.lru.set(id, { record: resolvedRecord, version: version2 }, estimateRecordBytes(resolvedRecord));
|
|
3620
|
-
await this.maintainPersistedIndexesOnPut(
|
|
3621
|
-
id,
|
|
3622
|
-
resolvedRecord,
|
|
3623
|
-
existingResolved ? existingResolved.record : null,
|
|
3624
|
-
version2
|
|
3625
|
-
);
|
|
3626
|
-
} else {
|
|
3627
|
-
this.cache.set(id, { record: resolvedRecord, version: version2 });
|
|
3628
|
-
this.indexes?.upsert(id, resolvedRecord, existingResolved ? existingResolved.record : null);
|
|
3629
|
-
}
|
|
3630
|
-
await this._onRecordMutated(id, "put", "local-write", { record, version: version2 });
|
|
3580
|
+
await this.#commitWriteTail({
|
|
3581
|
+
id,
|
|
3582
|
+
envelope: envelope2,
|
|
3583
|
+
version: version2,
|
|
3584
|
+
indexed: resolvedRecord,
|
|
3585
|
+
event: record,
|
|
3586
|
+
prior: existingResolved,
|
|
3587
|
+
reason: options?.reason
|
|
3588
|
+
});
|
|
3631
3589
|
return;
|
|
3632
3590
|
}
|
|
3633
3591
|
let existing;
|
|
@@ -3657,47 +3615,19 @@ var Collection = class {
|
|
|
3657
3615
|
this.uniqueConstraints?.check(id, record);
|
|
3658
3616
|
const cek = this.perRecordCek ? await this.resolveRecordCek(id) : void 0;
|
|
3659
3617
|
const vdigCtx = this.vdigFields !== null ? { id, prev: await this.adapter.get(this.vault, this.name, id) } : void 0;
|
|
3660
|
-
if (existing
|
|
3661
|
-
await this.historyStrategy.saveHistory(this.adapter, this.vault, this.name, id, await this.codec.encryptRecord(existing.record, existing.version, cek, void 0, void 0, vdigCtx, id));
|
|
3662
|
-
this.emitter.emit("history:save", {
|
|
3663
|
-
vault: this.vault,
|
|
3664
|
-
collection: this.name,
|
|
3665
|
-
id,
|
|
3666
|
-
version: existing.version
|
|
3667
|
-
});
|
|
3668
|
-
if (this.historyConfig.maxVersions) await this.historyStrategy.pruneHistory(this.adapter, this.vault, this.name, id, { keepVersions: this.historyConfig.maxVersions });
|
|
3669
|
-
}
|
|
3618
|
+
if (existing) await this.#savePriorHistory(id, existing, cek, vdigCtx);
|
|
3670
3619
|
const envelope = await this.codec.encryptRecord(record, version, cek, options?.source, options?.sourceTs, vdigCtx, id);
|
|
3671
3620
|
await this.adapter.put(this.vault, this.name, id, envelope);
|
|
3672
3621
|
this.markerIds.delete(id);
|
|
3673
|
-
await this
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
version,
|
|
3683
|
-
actor: this.keyring.userId,
|
|
3684
|
-
payloadHash: await this.historyStrategy.envelopePayloadHash(envelope)
|
|
3685
|
-
};
|
|
3686
|
-
if (existing) {
|
|
3687
|
-
appendInput.delta = this.historyStrategy.computePatch(record, existing.record);
|
|
3688
|
-
}
|
|
3689
|
-
if (options?.reason !== void 0) appendInput.reason = options.reason;
|
|
3690
|
-
await this.ledger.append(appendInput);
|
|
3691
|
-
}
|
|
3692
|
-
if (this.lazy && this.lru) {
|
|
3693
|
-
this.lru.set(id, { record: await this._toCacheableRecord(record, envelope, id), version }, estimateRecordBytes(record));
|
|
3694
|
-
await this.maintainPersistedIndexesOnPut(id, record, existing ? existing.record : null, version);
|
|
3695
|
-
} else {
|
|
3696
|
-
this.cache.set(id, { record: await this._toCacheableRecord(record, envelope, id), version });
|
|
3697
|
-
this.indexes?.upsert(id, record, existing ? existing.record : null);
|
|
3698
|
-
this.uniqueConstraints?.upsert(id, record, existing?.record);
|
|
3699
|
-
}
|
|
3700
|
-
await this._onRecordMutated(id, "put", "local-write", { record, version });
|
|
3622
|
+
await this.#commitWriteTail({
|
|
3623
|
+
id,
|
|
3624
|
+
envelope,
|
|
3625
|
+
version,
|
|
3626
|
+
indexed: record,
|
|
3627
|
+
event: record,
|
|
3628
|
+
prior: existing,
|
|
3629
|
+
reason: options?.reason
|
|
3630
|
+
});
|
|
3701
3631
|
}
|
|
3702
3632
|
/**
|
|
3703
3633
|
* Fire registered MV strategies whose dependency set includes this
|
|
@@ -3714,34 +3644,8 @@ var Collection = class {
|
|
|
3714
3644
|
*/
|
|
3715
3645
|
async dispatchMaterializedViews(id, record, wave) {
|
|
3716
3646
|
if (this.materializedViewSource === void 0) return;
|
|
3717
|
-
const
|
|
3718
|
-
|
|
3719
|
-
const registry = this.materializedViewSource.registry();
|
|
3720
|
-
const mvs = registry.mvsForSource(this.name);
|
|
3721
|
-
if (mvs.length === 0) return;
|
|
3722
|
-
let executor = null;
|
|
3723
|
-
let staleHelpers = null;
|
|
3724
|
-
for (const reg of mvs) {
|
|
3725
|
-
const mode = reg.spec.refresh;
|
|
3726
|
-
if (mode === "eager") {
|
|
3727
|
-
if (wave?.seen(`mv\0${reg.spec.name}`)) continue;
|
|
3728
|
-
if (executor === null) {
|
|
3729
|
-
;
|
|
3730
|
-
({ MaterializedViewExecutor: executor } = await import("./executor-UX4FASYZ.js"));
|
|
3731
|
-
}
|
|
3732
|
-
await executor.refresh(reg, {
|
|
3733
|
-
getCollection: (name) => this.materializedViewSource.getCollection(name),
|
|
3734
|
-
getActiveTxContext: () => this.materializedViewSource.getActiveTxContext(),
|
|
3735
|
-
getQueryContext: () => this.materializedViewSource.getQueryContext(),
|
|
3736
|
-
dispatchCtx: this.#dispatchCtx({ collection: this.name, id })
|
|
3737
|
-
});
|
|
3738
|
-
} else if (mode === "lazy") {
|
|
3739
|
-
if (staleHelpers === null) {
|
|
3740
|
-
staleHelpers = await import("./stale-VZL4OGUB.js");
|
|
3741
|
-
}
|
|
3742
|
-
staleHelpers.markMVStale(registry, reg.spec.name);
|
|
3743
|
-
}
|
|
3744
|
-
}
|
|
3647
|
+
const { dispatchMaterializedViews } = await import("./dispatch-EGGC7UD7.js");
|
|
3648
|
+
return dispatchMaterializedViews(this.#mvDispatchCtx(this.materializedViewSource), id, record, wave);
|
|
3745
3649
|
}
|
|
3746
3650
|
/**
|
|
3747
3651
|
* Fire registered derivation strategies for this source collection.
|
|
@@ -3829,6 +3733,32 @@ var Collection = class {
|
|
|
3829
3733
|
return out;
|
|
3830
3734
|
}
|
|
3831
3735
|
/** @internal — ctx for `putDerivedOutput`'s frozen-period skip+audit (#638 Task 5). */
|
|
3736
|
+
/** What `with-formula/materialized-views/dispatch.ts` needs from this collection (#842). */
|
|
3737
|
+
#mvDispatchCtx(materializedViewSource) {
|
|
3738
|
+
return {
|
|
3739
|
+
materializedViewSource,
|
|
3740
|
+
collectionName: this.name,
|
|
3741
|
+
dispatchCtx: (source) => this.#dispatchCtx(source)
|
|
3742
|
+
};
|
|
3743
|
+
}
|
|
3744
|
+
/**
|
|
3745
|
+
* What `with-formula/derivations/dispatch.ts` needs from this collection (#842).
|
|
3746
|
+
*
|
|
3747
|
+
* The return type is inferred, not annotated: importing `DerivationDeleteCtx`
|
|
3748
|
+
* would be a STATIC spine→service import, which `port-layering` rejects even
|
|
3749
|
+
* when it is type-only — the guard scans import statements, not their
|
|
3750
|
+
* erasure. The dynamic `import()` at the call site still types the argument.
|
|
3751
|
+
*/
|
|
3752
|
+
#derivationDeleteCtx(derivationSource) {
|
|
3753
|
+
return {
|
|
3754
|
+
derivationSource,
|
|
3755
|
+
collectionName: this.name,
|
|
3756
|
+
adapter: this.adapter,
|
|
3757
|
+
vault: this.vault,
|
|
3758
|
+
getDEK: this.getDEK,
|
|
3759
|
+
storeCiphertext: this.storeCiphertext
|
|
3760
|
+
};
|
|
3761
|
+
}
|
|
3832
3762
|
#dispatchCtx(source) {
|
|
3833
3763
|
return { emit: (e, p) => this.emitter.emit(e, p), source, audit: ledgerAuditHook(this.ledger, this.keyring.userId) };
|
|
3834
3764
|
}
|
|
@@ -3854,11 +3784,7 @@ var Collection = class {
|
|
|
3854
3784
|
const patched = { ...base, [field]: newValue };
|
|
3855
3785
|
const txCtx = this.derivationSource.getActiveTxContext();
|
|
3856
3786
|
if (txCtx !== null) {
|
|
3857
|
-
|
|
3858
|
-
txCtx._executed.push({
|
|
3859
|
-
op: { type: "put", vaultName: this.vault, collectionName: into, id: parentId },
|
|
3860
|
-
priorEnvelope: prior
|
|
3861
|
-
});
|
|
3787
|
+
this.#trackPut(txCtx, into, parentId, await this.adapter.get(this.vault, into, parentId));
|
|
3862
3788
|
}
|
|
3863
3789
|
return putDerivedOutput(intoColl, parentId, patched, this.#dispatchCtx(source));
|
|
3864
3790
|
}
|
|
@@ -3891,150 +3817,14 @@ var Collection = class {
|
|
|
3891
3817
|
* dispatch wave's per-target dedup; `undefined` on the local-write path (byte-identical). */
|
|
3892
3818
|
async dispatchDerivations(id, record, version, wave) {
|
|
3893
3819
|
if (this.derivationSource === void 0) return;
|
|
3894
|
-
const
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
|
|
3902
|
-
if (spec.rollup) {
|
|
3903
|
-
if (mode !== "eager") continue;
|
|
3904
|
-
let parentId;
|
|
3905
|
-
if (this.name === spec.rollup.from) {
|
|
3906
|
-
const kv = incoming[spec.rollup.key];
|
|
3907
|
-
parentId = typeof kv === "string" || typeof kv === "number" ? String(kv) : null;
|
|
3908
|
-
} else {
|
|
3909
|
-
parentId = id;
|
|
3910
|
-
}
|
|
3911
|
-
if (parentId !== null) await this.recomputeRollup(spec, parentId, { collection: this.name, id }, wave);
|
|
3912
|
-
continue;
|
|
3913
|
-
}
|
|
3914
|
-
const isSource = spec.source === this.name;
|
|
3915
|
-
const isSibling = !isSource && (spec.sources?.includes(this.name) ?? false);
|
|
3916
|
-
const trigger = !isSource && !isSibling ? spec.triggerBy?.find((t) => t.collection === this.name) : void 0;
|
|
3917
|
-
const runs = [];
|
|
3918
|
-
if (isSource) {
|
|
3919
|
-
runs.push({ input: { ...incoming, id }, base: incoming, runId: id, version });
|
|
3920
|
-
} else if (isSibling) {
|
|
3921
|
-
const p = await this.derivationSource.getCollection(spec.source).get(id);
|
|
3922
|
-
if (p !== null && p !== void 0) {
|
|
3923
|
-
const raw = await this.derivationSource.getCollection(spec.source)._getStoredRecord(id);
|
|
3924
|
-
runs.push({ input: { ...p, id }, base: raw ?? p, runId: id, version: 0 });
|
|
3925
|
-
}
|
|
3926
|
-
} else if (trigger) {
|
|
3927
|
-
const srcColl = this.derivationSource.getCollection(spec.source);
|
|
3928
|
-
const ids = await srcColl._findMatchingIds(trigger.on, id);
|
|
3929
|
-
if (trigger.maxFanout !== void 0 && ids.length > trigger.maxFanout) {
|
|
3930
|
-
throw new DerivationCapExceededError(`triggerBy ${this.name}\u2192${spec.source}`, ids.length, trigger.maxFanout);
|
|
3931
|
-
}
|
|
3932
|
-
for (const sid of ids) {
|
|
3933
|
-
const raw = await srcColl._getStoredRecord(sid);
|
|
3934
|
-
if (raw === null) continue;
|
|
3935
|
-
runs.push({ input: { ...raw, id: sid }, base: raw, runId: sid, version: 0 });
|
|
3936
|
-
}
|
|
3937
|
-
}
|
|
3938
|
-
if (runs.length === 0) continue;
|
|
3939
|
-
if (mode !== "eager") {
|
|
3940
|
-
for (const run of runs) await markStale(registry, spec, run.runId);
|
|
3941
|
-
continue;
|
|
3942
|
-
}
|
|
3943
|
-
if (DerivationExecutor === null) {
|
|
3944
|
-
({ DerivationExecutor } = await import("./executor-XGIS6CR7.js"));
|
|
3945
|
-
}
|
|
3946
|
-
for (const run of runs) {
|
|
3947
|
-
const ctx = { vault: this.derivationSource.getReadOnlyFacade() };
|
|
3948
|
-
const outCtx = this.#dispatchCtx({ collection: spec.source, id: run.runId });
|
|
3949
|
-
const result = await DerivationExecutor.run(spec, run.input, run.version, strategyHash, ctx);
|
|
3950
|
-
for (const key of Object.keys(spec.outputs)) {
|
|
3951
|
-
const out = result.outputs[key];
|
|
3952
|
-
if (!out) continue;
|
|
3953
|
-
if (out.kind === "failed") {
|
|
3954
|
-
const err = out.error;
|
|
3955
|
-
if (spec.strict) throw err;
|
|
3956
|
-
console.warn(`[derivation] output "${key}" for source "${spec.source}" id="${run.runId}" failed:`, err);
|
|
3957
|
-
continue;
|
|
3958
|
-
}
|
|
3959
|
-
const outSpec = spec.outputs[key];
|
|
3960
|
-
if (!outSpec) continue;
|
|
3961
|
-
const outputCollection = this.derivationSource.getCollection(outSpec.collection);
|
|
3962
|
-
const txCtx = this.derivationSource.getActiveTxContext();
|
|
3963
|
-
if (out.kind === "array") {
|
|
3964
|
-
const { loadFanoutSidecar, saveFanoutSidecar } = await import("./fanout-sidecar-B5LVUMQX.js");
|
|
3965
|
-
const prior = await loadFanoutSidecar(this.adapter, this.vault, spec.source, run.runId, key, this.getDEK, this.storeCiphertext);
|
|
3966
|
-
const prevKeys = new Set(prior?.keys ?? []);
|
|
3967
|
-
const newKeysList = out.entries.map((e) => e.key);
|
|
3968
|
-
const newKeysSet = new Set(newKeysList);
|
|
3969
|
-
for (const k of prevKeys) {
|
|
3970
|
-
if (newKeysSet.has(k)) continue;
|
|
3971
|
-
await outputCollection._internalDelete(k, txCtx);
|
|
3972
|
-
}
|
|
3973
|
-
for (const entry of out.entries) {
|
|
3974
|
-
if (txCtx !== null) {
|
|
3975
|
-
const priorEnvelope = await this.adapter.get(this.vault, outSpec.collection, entry.key);
|
|
3976
|
-
txCtx._executed.push({
|
|
3977
|
-
op: {
|
|
3978
|
-
type: "put",
|
|
3979
|
-
vaultName: this.vault,
|
|
3980
|
-
collectionName: outSpec.collection,
|
|
3981
|
-
id: entry.key
|
|
3982
|
-
},
|
|
3983
|
-
priorEnvelope
|
|
3984
|
-
});
|
|
3985
|
-
}
|
|
3986
|
-
await putDerivedOutput(outputCollection, entry.key, entry.value, outCtx, { source: "derived" });
|
|
3987
|
-
}
|
|
3988
|
-
await saveFanoutSidecar(this.adapter, this.vault, {
|
|
3989
|
-
source: spec.source,
|
|
3990
|
-
sourceId: run.runId,
|
|
3991
|
-
outputKey: key,
|
|
3992
|
-
outputCollection: outSpec.collection,
|
|
3993
|
-
keys: newKeysList
|
|
3994
|
-
}, this.getDEK, this.storeCiphertext);
|
|
3995
|
-
continue;
|
|
3996
|
-
}
|
|
3997
|
-
if (out.skipped === true) {
|
|
3998
|
-
await outputCollection._internalDelete(run.runId, txCtx);
|
|
3999
|
-
continue;
|
|
4000
|
-
}
|
|
4001
|
-
if (outSpec.shape === "record" && outSpec.denorm !== void 0 && outSpec.collection === spec.source) {
|
|
4002
|
-
const value = out.value;
|
|
4003
|
-
const patched = { ...run.base };
|
|
4004
|
-
let changed = false;
|
|
4005
|
-
for (const f of outSpec.denorm) {
|
|
4006
|
-
if (!selfWriteFieldEqual(run.base[f], value[f])) {
|
|
4007
|
-
patched[f] = value[f];
|
|
4008
|
-
changed = true;
|
|
4009
|
-
}
|
|
4010
|
-
}
|
|
4011
|
-
if (!changed) continue;
|
|
4012
|
-
if (txCtx !== null) {
|
|
4013
|
-
const prior = await this.adapter.get(this.vault, outSpec.collection, run.runId);
|
|
4014
|
-
txCtx._executed.push({
|
|
4015
|
-
op: { type: "put", vaultName: this.vault, collectionName: outSpec.collection, id: run.runId },
|
|
4016
|
-
priorEnvelope: prior
|
|
4017
|
-
});
|
|
4018
|
-
}
|
|
4019
|
-
await putDerivedOutput(outputCollection, run.runId, patched, outCtx, { source: "derived" });
|
|
4020
|
-
continue;
|
|
4021
|
-
}
|
|
4022
|
-
if (txCtx !== null) {
|
|
4023
|
-
const prior = await this.adapter.get(this.vault, outSpec.collection, run.runId);
|
|
4024
|
-
txCtx._executed.push({
|
|
4025
|
-
op: {
|
|
4026
|
-
type: "put",
|
|
4027
|
-
vaultName: this.vault,
|
|
4028
|
-
collectionName: outSpec.collection,
|
|
4029
|
-
id: run.runId
|
|
4030
|
-
},
|
|
4031
|
-
priorEnvelope: prior
|
|
4032
|
-
});
|
|
4033
|
-
}
|
|
4034
|
-
await putDerivedOutput(outputCollection, run.runId, out.value, outCtx, { source: "derived" });
|
|
4035
|
-
}
|
|
4036
|
-
}
|
|
4037
|
-
}
|
|
3820
|
+
const { dispatchDerivations } = await import("./dispatch-GDSTUTVP.js");
|
|
3821
|
+
return dispatchDerivations({
|
|
3822
|
+
...this.#derivationDeleteCtx(this.derivationSource),
|
|
3823
|
+
via: this.via,
|
|
3824
|
+
recomputeRollup: (spec, parentId, source, w) => this.recomputeRollup(spec, parentId, source, w),
|
|
3825
|
+
dispatchCtx: (source) => this.#dispatchCtx(source),
|
|
3826
|
+
trackPut: (txCtx, collectionName, rid, prior) => this.#trackPut(txCtx, collectionName, rid, prior)
|
|
3827
|
+
}, id, record, version, wave);
|
|
4038
3828
|
}
|
|
4039
3829
|
/**
|
|
4040
3830
|
* Delete a record by ID. Runs inside the hub's write-queue tracker
|
|
@@ -4203,10 +3993,10 @@ var Collection = class {
|
|
|
4203
3993
|
if (existing && this.historyConfig.enabled !== false) {
|
|
4204
3994
|
const cek = this.perRecordCek ? await this.resolveRecordCek(id) : void 0;
|
|
4205
3995
|
const prevForVdig = this.vdigFields !== null ? await this.adapter.get(this.vault, this.name, id) : null;
|
|
4206
|
-
await this.
|
|
3996
|
+
await this.strategies.history.saveHistory(this.adapter, this.vault, this.name, id, await this.codec.encryptRecord(existing.record, existing.version, cek, void 0, void 0, this.vdigFields !== null ? { id, prev: prevForVdig } : void 0, id));
|
|
4207
3997
|
}
|
|
4208
3998
|
const previousEnvelope = await this.adapter.get(this.vault, this.name, id);
|
|
4209
|
-
const previousPayloadHash = await this.
|
|
3999
|
+
const previousPayloadHash = await this.strategies.history.envelopePayloadHash(previousEnvelope);
|
|
4210
4000
|
let markerVersion;
|
|
4211
4001
|
if (this.onDirty) {
|
|
4212
4002
|
const live = previousEnvelope;
|
|
@@ -4304,33 +4094,8 @@ var Collection = class {
|
|
|
4304
4094
|
*/
|
|
4305
4095
|
async dispatchArrayDerivationsOnDelete(id, eraseRecordShapeToo = false) {
|
|
4306
4096
|
if (this.derivationSource === void 0) return 0;
|
|
4307
|
-
const
|
|
4308
|
-
|
|
4309
|
-
if (strategies.length === 0) return 0;
|
|
4310
|
-
let helpers = null;
|
|
4311
|
-
const txCtx = this.derivationSource.getActiveTxContext();
|
|
4312
|
-
let erased = 0;
|
|
4313
|
-
for (const { spec } of strategies) {
|
|
4314
|
-
for (const [outputKey, outSpec] of Object.entries(spec.outputs)) {
|
|
4315
|
-
if (outSpec.shape === "record") {
|
|
4316
|
-
if (eraseRecordShapeToo && spec.source === this.name && outSpec.collection !== this.name) {
|
|
4317
|
-
if (await this.derivationSource.getCollection(outSpec.collection)._internalDelete(id, txCtx)) erased += 1;
|
|
4318
|
-
}
|
|
4319
|
-
continue;
|
|
4320
|
-
}
|
|
4321
|
-
if (helpers === null) {
|
|
4322
|
-
helpers = await import("./fanout-sidecar-B5LVUMQX.js");
|
|
4323
|
-
}
|
|
4324
|
-
const sidecar = await helpers.loadFanoutSidecar(this.adapter, this.vault, spec.source, id, outputKey, this.getDEK, this.storeCiphertext);
|
|
4325
|
-
if (!sidecar) continue;
|
|
4326
|
-
const outputCollection = this.derivationSource.getCollection(outSpec.collection);
|
|
4327
|
-
for (const derivedId of sidecar.keys) {
|
|
4328
|
-
if (await outputCollection._internalDelete(derivedId, txCtx)) erased += 1;
|
|
4329
|
-
}
|
|
4330
|
-
await helpers.deleteFanoutSidecar(this.adapter, this.vault, spec.source, id, outputKey);
|
|
4331
|
-
}
|
|
4332
|
-
}
|
|
4333
|
-
return erased;
|
|
4097
|
+
const { dispatchArrayDerivationsOnDelete } = await import("./dispatch-GDSTUTVP.js");
|
|
4098
|
+
return dispatchArrayDerivationsOnDelete(this.#derivationDeleteCtx(this.derivationSource), id, eraseRecordShapeToo);
|
|
4334
4099
|
}
|
|
4335
4100
|
/**
|
|
4336
4101
|
* Mirror of {@link dispatchMaterializedViews} for the delete/forget path — no `_materializedFrom`
|
|
@@ -4343,41 +4108,8 @@ var Collection = class {
|
|
|
4343
4108
|
*/
|
|
4344
4109
|
async dispatchMaterializedViewsOnDelete(id) {
|
|
4345
4110
|
if (this.materializedViewSource === void 0) return { deleted: 0, residueUndecodable: [], residueDeclined: [] };
|
|
4346
|
-
const
|
|
4347
|
-
|
|
4348
|
-
if (mvs.length === 0) return { deleted: 0, residueUndecodable: [], residueDeclined: [] };
|
|
4349
|
-
let executor = null;
|
|
4350
|
-
let staleHelpers = null;
|
|
4351
|
-
let deleted = 0;
|
|
4352
|
-
const residueUndecodable = [];
|
|
4353
|
-
const residueDeclined = [];
|
|
4354
|
-
for (const reg of mvs) {
|
|
4355
|
-
const mode = reg.spec.refresh;
|
|
4356
|
-
if (mode === "eager") {
|
|
4357
|
-
if (executor === null) {
|
|
4358
|
-
;
|
|
4359
|
-
({ MaterializedViewExecutor: executor } = await import("./executor-UX4FASYZ.js"));
|
|
4360
|
-
}
|
|
4361
|
-
const rr = await executor.refresh(reg, {
|
|
4362
|
-
getCollection: (name) => this.materializedViewSource.getCollection(name),
|
|
4363
|
-
getActiveTxContext: () => this.materializedViewSource.getActiveTxContext(),
|
|
4364
|
-
getQueryContext: () => this.materializedViewSource.getQueryContext(),
|
|
4365
|
-
dispatchCtx: this.#dispatchCtx({ collection: this.name, id })
|
|
4366
|
-
});
|
|
4367
|
-
deleted += rr.deleted;
|
|
4368
|
-
residueUndecodable.push(...rr.residueUndecodable);
|
|
4369
|
-
residueDeclined.push(...rr.residueDeclined);
|
|
4370
|
-
} else {
|
|
4371
|
-
if (staleHelpers === null) {
|
|
4372
|
-
staleHelpers = await import("./stale-VZL4OGUB.js");
|
|
4373
|
-
}
|
|
4374
|
-
const inv = await staleHelpers.invalidateMVAtRest(this.materializedViewSource, reg, mode);
|
|
4375
|
-
deleted += inv.deleted;
|
|
4376
|
-
residueUndecodable.push(...inv.residueUndecodable.map((rid) => `${reg.outputCollection}:${rid}`));
|
|
4377
|
-
residueDeclined.push(...inv.residueDeclined.map((rid) => `${reg.outputCollection}:${rid}`));
|
|
4378
|
-
}
|
|
4379
|
-
}
|
|
4380
|
-
return { deleted, residueUndecodable, residueDeclined };
|
|
4111
|
+
const { dispatchMaterializedViewsOnDelete } = await import("./dispatch-EGGC7UD7.js");
|
|
4112
|
+
return dispatchMaterializedViewsOnDelete(this.#mvDispatchCtx(this.materializedViewSource), id);
|
|
4381
4113
|
}
|
|
4382
4114
|
/**
|
|
4383
4115
|
* List all records in the collection.
|
|
@@ -4396,7 +4128,7 @@ var Collection = class {
|
|
|
4396
4128
|
);
|
|
4397
4129
|
}
|
|
4398
4130
|
if (this.materializedViewSource !== void 0) {
|
|
4399
|
-
const { resolveStaleMVOnRead } = await import("./stale-
|
|
4131
|
+
const { resolveStaleMVOnRead } = await import("./stale-A4J26OIC.js");
|
|
4400
4132
|
await resolveStaleMVOnRead(this.materializedViewSource, this.name, this.#dispatchCtx({ collection: this.name, id: "resolve-on-read" }));
|
|
4401
4133
|
}
|
|
4402
4134
|
await this.ensureHydrated();
|
|
@@ -4417,28 +4149,28 @@ var Collection = class {
|
|
|
4417
4149
|
* see `src/search/tokenize.ts` for the Thai/CJK caveat.
|
|
4418
4150
|
*/
|
|
4419
4151
|
search(field, query, opts = {}) {
|
|
4420
|
-
return this.
|
|
4152
|
+
return this.strategies.search.search(this.searchContext(), field, query, opts);
|
|
4421
4153
|
}
|
|
4422
4154
|
/** Force-persist the lexical index now — gated behind `searchStrategy: withSearch()`. */
|
|
4423
4155
|
flushIndex() {
|
|
4424
|
-
return this.
|
|
4156
|
+
return this.strategies.search.flushIndex(this.searchContext());
|
|
4425
4157
|
}
|
|
4426
4158
|
/** Pre-build the lexical index — gated behind `searchStrategy: withSearch()`. */
|
|
4427
4159
|
warmIndex() {
|
|
4428
|
-
return this.
|
|
4160
|
+
return this.strategies.search.warmIndex(this.searchContext());
|
|
4429
4161
|
}
|
|
4430
4162
|
/** Retrieval (lexical | semantic | hybrid) — gated behind `searchStrategy: withSearch()`. */
|
|
4431
4163
|
retrieve(query, opts = {}) {
|
|
4432
|
-
return this.
|
|
4164
|
+
return this.strategies.search.retrieve(this.searchContext(), query, opts);
|
|
4433
4165
|
}
|
|
4434
4166
|
/** Raw-vector kNN — gated behind `searchStrategy: withSearch()`. */
|
|
4435
4167
|
similarTo(vector, opts = {}) {
|
|
4436
|
-
return this.
|
|
4168
|
+
return this.strategies.search.similarTo(this.searchContext(), vector, opts);
|
|
4437
4169
|
}
|
|
4438
4170
|
/** Opt-in bulk `_vec` re-derive (#788) — a plain collection has nothing to rebuild; gated behind `searchStrategy: withSearch()` otherwise. */
|
|
4439
4171
|
rebuildEmbeddings() {
|
|
4440
4172
|
if (!this.embeddings) return Promise.resolve({ rebuilt: 0, skipped: 0 });
|
|
4441
|
-
return this.
|
|
4173
|
+
return this.strategies.search.rebuildEmbeddings(this.searchContext());
|
|
4442
4174
|
}
|
|
4443
4175
|
/**
|
|
4444
4176
|
* Bind the {@link SearchContext} the search/retrieval surface needs. The
|
|
@@ -4648,7 +4380,7 @@ var Collection = class {
|
|
|
4648
4380
|
...this.defaultLocale !== void 0 ? { defaultLocale: this.defaultLocale } : {},
|
|
4649
4381
|
...resolver.resolveDictSource ? { resolveDictSource: (field) => resolver.resolveDictSource(leftCollection, field) } : {}
|
|
4650
4382
|
} : void 0;
|
|
4651
|
-
return new Query(source, void 0, joinContext, this.
|
|
4383
|
+
return new Query(source, void 0, joinContext, this.strategies.reduce);
|
|
4652
4384
|
}
|
|
4653
4385
|
/**
|
|
4654
4386
|
* Subscribe to every put/delete on this collection. Returns an
|
|
@@ -4762,7 +4494,7 @@ var Collection = class {
|
|
|
4762
4494
|
// ─── History Methods ────────────────────────────────────────────
|
|
4763
4495
|
/** Get version history for a record, newest first. */
|
|
4764
4496
|
async history(id, options) {
|
|
4765
|
-
const envelopes = await this.
|
|
4497
|
+
const envelopes = await this.strategies.history.getHistoryEntries(
|
|
4766
4498
|
this.adapter,
|
|
4767
4499
|
this.vault,
|
|
4768
4500
|
this.name,
|
|
@@ -4794,7 +4526,7 @@ var Collection = class {
|
|
|
4794
4526
|
* and re-put the records through the normal `put()` path.
|
|
4795
4527
|
*/
|
|
4796
4528
|
async getVersion(id, version) {
|
|
4797
|
-
const envelope = await this.
|
|
4529
|
+
const envelope = await this.strategies.history.getVersionEnvelope(
|
|
4798
4530
|
this.adapter,
|
|
4799
4531
|
this.vault,
|
|
4800
4532
|
this.name,
|
|
@@ -4819,7 +4551,7 @@ var Collection = class {
|
|
|
4819
4551
|
*/
|
|
4820
4552
|
async diff(id, versionA, versionB) {
|
|
4821
4553
|
const recordA = versionA === 0 ? null : await this.resolveVersion(id, versionA);
|
|
4822
|
-
return this.
|
|
4554
|
+
return this.strategies.history.diff(recordA, versionB === void 0 || versionB === 0 ? versionB === 0 ? null : await this.resolveCurrentOrVersion(id) : await this.resolveVersion(id, versionB));
|
|
4823
4555
|
}
|
|
4824
4556
|
/** Resolve a version: try history first, then check if it's the current version. */
|
|
4825
4557
|
async resolveVersion(id, version) {
|
|
@@ -4836,7 +4568,7 @@ var Collection = class {
|
|
|
4836
4568
|
}
|
|
4837
4569
|
/** Prune history entries for a record (or all records if id is undefined). */
|
|
4838
4570
|
async pruneRecordHistory(id, options) {
|
|
4839
|
-
const pruned = await this.
|
|
4571
|
+
const pruned = await this.strategies.history.pruneHistory(
|
|
4840
4572
|
this.adapter,
|
|
4841
4573
|
this.vault,
|
|
4842
4574
|
this.name,
|
|
@@ -4855,7 +4587,7 @@ var Collection = class {
|
|
|
4855
4587
|
}
|
|
4856
4588
|
/** Clear all history for this collection (or a specific record). */
|
|
4857
4589
|
async clearHistory(id) {
|
|
4858
|
-
return this.
|
|
4590
|
+
return this.strategies.history.clearHistory(this.adapter, this.vault, this.name, id);
|
|
4859
4591
|
}
|
|
4860
4592
|
// ─── Core Methods ─────────────────────────────────────────────
|
|
4861
4593
|
/**
|
|
@@ -5277,7 +5009,7 @@ var Collection = class {
|
|
|
5277
5009
|
* vault-shared `_blob` DEK (enabling cross-collection deduplication).
|
|
5278
5010
|
*/
|
|
5279
5011
|
blob(id) {
|
|
5280
|
-
return this.
|
|
5012
|
+
return this.strategies.blobs.openSlot({
|
|
5281
5013
|
store: this.adapter,
|
|
5282
5014
|
vault: this.vault,
|
|
5283
5015
|
collection: this.name,
|
|
@@ -5510,7 +5242,7 @@ var Collection = class {
|
|
|
5510
5242
|
const persisted = this.persistedIndexes;
|
|
5511
5243
|
if (!persisted) {
|
|
5512
5244
|
throw new Error(
|
|
5513
|
-
`Collection "${this.name}": lazyQuery() requires indexing to be enabled. Pass \`withIndexing()\` from "@noy-db/hub/indexing" to \`createNoydb({
|
|
5245
|
+
`Collection "${this.name}": lazyQuery() requires indexing to be enabled. Pass \`withIndexing()\` from "@noy-db/hub/indexing" to \`createNoydb({ indexingStrategy: withIndexing() })\`.`
|
|
5514
5246
|
);
|
|
5515
5247
|
}
|
|
5516
5248
|
if (persisted.fields().length === 0) {
|
|
@@ -5549,14 +5281,14 @@ var Collection = class {
|
|
|
5549
5281
|
/** C-A/R10: persist the classified marker once per classified handle (store I/O in config-drift.ts). */
|
|
5550
5282
|
async _ensureClassifiedMarker() {
|
|
5551
5283
|
if (this._markerPersisted || this.vdigFields === null) return;
|
|
5552
|
-
const { persistClassifiedMarkerForFields } = await import("./classified-marker-
|
|
5284
|
+
const { persistClassifiedMarkerForFields } = await import("./classified-marker-7PKJBFCG.js");
|
|
5553
5285
|
await persistClassifiedMarkerForFields(this.adapter, this.vault, this.name, this.vdigFields, await this.getDEK(this.name));
|
|
5554
5286
|
this._markerPersisted = true;
|
|
5555
5287
|
}
|
|
5556
5288
|
/** C-A/R10 drift signal — the marker's declared digest-only set, memoized to one store read per handle (see config-drift.ts). */
|
|
5557
5289
|
async _classifiedMarkerDigestOnly() {
|
|
5558
5290
|
if (this._markerDigestOnlyCache !== void 0) return this._markerDigestOnlyCache;
|
|
5559
|
-
const { readClassifiedMarkerDigestOnly } = await import("./classified-marker-
|
|
5291
|
+
const { readClassifiedMarkerDigestOnly } = await import("./classified-marker-7PKJBFCG.js");
|
|
5560
5292
|
this._markerDigestOnlyCache = await readClassifiedMarkerDigestOnly(this.adapter, this.vault, this.name, await this.getDEK(this.name));
|
|
5561
5293
|
return this._markerDigestOnlyCache;
|
|
5562
5294
|
}
|
|
@@ -5598,23 +5330,23 @@ var Collection = class {
|
|
|
5598
5330
|
// ─── Hierarchical Access ──────────────────────────
|
|
5599
5331
|
/** tier-aware put — gated behind `tiersStrategy: withTiers()`. `searchResidue: true` = stuck search compensation (#774, mirroring #764's elevate/demote posture); the write itself always completes. */
|
|
5600
5332
|
putAtTier(id, record, tier, opts) {
|
|
5601
|
-
return this.
|
|
5333
|
+
return this.strategies.tiers.putAtTier(this.tiersContext(), id, record, tier, opts);
|
|
5602
5334
|
}
|
|
5603
5335
|
/** tier-aware get — gated behind `tiersStrategy: withTiers()`. */
|
|
5604
5336
|
getAtTier(id) {
|
|
5605
|
-
return this.
|
|
5337
|
+
return this.strategies.tiers.getAtTier(this.tiersContext(), id);
|
|
5606
5338
|
}
|
|
5607
5339
|
/** list ids grouped by the caller's readability — gated behind `withTiers()`. */
|
|
5608
5340
|
listAtTier() {
|
|
5609
|
-
return this.
|
|
5341
|
+
return this.strategies.tiers.listAtTier(this.tiersContext());
|
|
5610
5342
|
}
|
|
5611
5343
|
/** elevate a record to a higher tier — gated behind `withTiers()`. `searchResidue: true` = stuck search compensation (#764); the move itself always completes. */
|
|
5612
5344
|
elevate(id, toTier) {
|
|
5613
|
-
return this.
|
|
5345
|
+
return this.strategies.tiers.elevate(this.tiersContext(), id, toTier);
|
|
5614
5346
|
}
|
|
5615
5347
|
/** demote a record to a lower tier — gated behind `withTiers()`. Same `searchResidue` posture as {@link elevate} (#764). */
|
|
5616
5348
|
demote(id, toTier) {
|
|
5617
|
-
return this.
|
|
5349
|
+
return this.strategies.tiers.demote(this.tiersContext(), id, toTier);
|
|
5618
5350
|
}
|
|
5619
5351
|
/**
|
|
5620
5352
|
* Emit a cross-tier access event. The subscriber sink stays collection-resident (it captures `onCrossTierAccess`); the tiers module reaches it via the {@link TiersContext.emitCrossTierEvent} callback.
|
|
@@ -5675,16 +5407,16 @@ var Collection = class {
|
|
|
5675
5407
|
},
|
|
5676
5408
|
syncIndexes: (id, rec, version, priorEnvelope) => syncTierIndexes(this.indexingContext(), id, rec, version, priorEnvelope),
|
|
5677
5409
|
syncSearch: (id, rec, version) => syncTierSearch(this.searchContext(), id, rec, version),
|
|
5678
|
-
syncHistory: async (id, fromDek, toDek) => this.
|
|
5410
|
+
syncHistory: async (id, fromDek, toDek) => this.strategies.history.rewrapHistory(this.adapter, this.vault, this.name, id, fromDek, toDek, await this.getDEK(this.name)),
|
|
5679
5411
|
saveHistorySnapshot: async (id, envelope) => {
|
|
5680
5412
|
if (this.historyConfig.enabled === false) return;
|
|
5681
|
-
await this.
|
|
5413
|
+
await this.strategies.history.saveHistory(this.adapter, this.vault, this.name, id, envelope);
|
|
5682
5414
|
this.emitter.emit("history:save", { vault: this.vault, collection: this.name, id, version: envelope._v });
|
|
5683
|
-
if (this.historyConfig.maxVersions) await this.
|
|
5415
|
+
if (this.historyConfig.maxVersions) await this.strategies.history.pruneHistory(this.adapter, this.vault, this.name, id, { keepVersions: this.historyConfig.maxVersions });
|
|
5684
5416
|
},
|
|
5685
|
-
historyEnabled: this.historyConfig.enabled !== false && this.
|
|
5417
|
+
historyEnabled: this.historyConfig.enabled !== false && this.strategies.history !== NO_HISTORY,
|
|
5686
5418
|
// #728/#737: lets putAtTier skip decrypting `existing` when no real history strategy is wired
|
|
5687
|
-
syncBlobs: (id, fromTier, toTier) => this.
|
|
5419
|
+
syncBlobs: (id, fromTier, toTier) => this.strategies.blobs !== NO_BLOBS ? this.blob(id).syncTierMove(fromTier, toTier, this.blobTierPolicy) : Promise.resolve(),
|
|
5688
5420
|
// #724 I1: gate on blob storage enabled (not on declared blobFields) so undeclared-field blobs still rehome; #746: syncTierMove mints/resumes the rehome journal marker; self-no-ops on an empty slot map
|
|
5689
5421
|
syncLedger: async (id) => {
|
|
5690
5422
|
await this.ledger?.purgeRecordDeltas(this.name, id);
|
|
@@ -5727,6 +5459,64 @@ var Collection = class {
|
|
|
5727
5459
|
}
|
|
5728
5460
|
};
|
|
5729
5461
|
|
|
5462
|
+
// src/port/with/capabilities.ts
|
|
5463
|
+
function assertCanExport(keyring, tier, format) {
|
|
5464
|
+
if (tier === "plaintext") {
|
|
5465
|
+
if (format === void 0) {
|
|
5466
|
+
throw new Error("vault.assertCanExport: plaintext tier requires a format");
|
|
5467
|
+
}
|
|
5468
|
+
if (!hasExportCapability(keyring, "plaintext", format)) {
|
|
5469
|
+
throw new ExportCapabilityError({
|
|
5470
|
+
tier: "plaintext",
|
|
5471
|
+
userId: keyring.userId,
|
|
5472
|
+
format
|
|
5473
|
+
});
|
|
5474
|
+
}
|
|
5475
|
+
return;
|
|
5476
|
+
}
|
|
5477
|
+
if (!hasExportCapability(keyring, "bundle")) {
|
|
5478
|
+
throw new ExportCapabilityError({
|
|
5479
|
+
tier: "bundle",
|
|
5480
|
+
userId: keyring.userId
|
|
5481
|
+
});
|
|
5482
|
+
}
|
|
5483
|
+
}
|
|
5484
|
+
function assertCanImport(keyring, tier, format) {
|
|
5485
|
+
if (tier === "plaintext") {
|
|
5486
|
+
if (format === void 0) {
|
|
5487
|
+
throw new Error("vault.assertCanImport: plaintext tier requires a format");
|
|
5488
|
+
}
|
|
5489
|
+
if (!hasImportCapability(keyring, "plaintext", format)) {
|
|
5490
|
+
throw new ImportCapabilityError({
|
|
5491
|
+
tier: "plaintext",
|
|
5492
|
+
userId: keyring.userId,
|
|
5493
|
+
format
|
|
5494
|
+
});
|
|
5495
|
+
}
|
|
5496
|
+
return;
|
|
5497
|
+
}
|
|
5498
|
+
if (!hasImportCapability(keyring, "bundle")) {
|
|
5499
|
+
throw new ImportCapabilityError({
|
|
5500
|
+
tier: "bundle",
|
|
5501
|
+
userId: keyring.userId
|
|
5502
|
+
});
|
|
5503
|
+
}
|
|
5504
|
+
}
|
|
5505
|
+
function canExport(keyring, tier, format) {
|
|
5506
|
+
if (tier === "plaintext") {
|
|
5507
|
+
if (format === void 0) return false;
|
|
5508
|
+
return hasExportCapability(keyring, "plaintext", format);
|
|
5509
|
+
}
|
|
5510
|
+
return hasExportCapability(keyring, "bundle");
|
|
5511
|
+
}
|
|
5512
|
+
function canImport(keyring, tier, format) {
|
|
5513
|
+
if (tier === "plaintext") {
|
|
5514
|
+
if (format === void 0) return false;
|
|
5515
|
+
return hasImportCapability(keyring, "plaintext", format);
|
|
5516
|
+
}
|
|
5517
|
+
return hasImportCapability(keyring, "bundle");
|
|
5518
|
+
}
|
|
5519
|
+
|
|
5730
5520
|
// src/with-commit/tx/elevated-handle.ts
|
|
5731
5521
|
var ELEVATION_AUDIT_COLLECTION = "_elevation_audit";
|
|
5732
5522
|
var ElevatedHandle = class {
|
|
@@ -6008,47 +5798,7 @@ var DeferredNumberingStore = class {
|
|
|
6008
5798
|
this.waiters.delete(id);
|
|
6009
5799
|
}
|
|
6010
5800
|
}
|
|
6011
|
-
return assignments;
|
|
6012
|
-
}
|
|
6013
|
-
};
|
|
6014
|
-
|
|
6015
|
-
// src/with-fork/shadow/strategy.ts
|
|
6016
|
-
var NOT_ENABLED2 = new Error(
|
|
6017
|
-
'VaultFrame requires the shadow strategy. Import `{ withShadow }` from "@noy-db/hub/shadow" and pass it to `createNoydb({ shadowStrategy: withShadow() })`.'
|
|
6018
|
-
);
|
|
6019
|
-
var NO_SHADOW = {
|
|
6020
|
-
buildFrame() {
|
|
6021
|
-
throw NOT_ENABLED2;
|
|
6022
|
-
}
|
|
6023
|
-
};
|
|
6024
|
-
|
|
6025
|
-
// src/with-audit/consent/strategy.ts
|
|
6026
|
-
var NO_CONSENT = {
|
|
6027
|
-
async write() {
|
|
6028
|
-
},
|
|
6029
|
-
async read() {
|
|
6030
|
-
return [];
|
|
6031
|
-
}
|
|
6032
|
-
};
|
|
6033
|
-
|
|
6034
|
-
// src/with-audit/periods/strategy.ts
|
|
6035
|
-
var NOT_ENABLED3 = new Error(
|
|
6036
|
-
'Accounting periods require the periods strategy. Import `{ withPeriods }` from "@noy-db/hub/periods" and pass it to `createNoydb({ periodsStrategy: withPeriods() })`.'
|
|
6037
|
-
);
|
|
6038
|
-
var NO_PERIODS = {
|
|
6039
|
-
async loadPeriods() {
|
|
6040
|
-
return [];
|
|
6041
|
-
},
|
|
6042
|
-
async chainAnchor() {
|
|
6043
|
-
return { priorPeriodHash: "" };
|
|
6044
|
-
},
|
|
6045
|
-
assertTsWritable() {
|
|
6046
|
-
},
|
|
6047
|
-
validatePeriodName() {
|
|
6048
|
-
throw NOT_ENABLED3;
|
|
6049
|
-
},
|
|
6050
|
-
async appendPeriodLedgerEntry() {
|
|
6051
|
-
throw NOT_ENABLED3;
|
|
5801
|
+
return assignments;
|
|
6052
5802
|
}
|
|
6053
5803
|
};
|
|
6054
5804
|
|
|
@@ -6298,6 +6048,7 @@ var VaultPeriods = class {
|
|
|
6298
6048
|
}
|
|
6299
6049
|
/** Return every closed / opened period in `closedAt` order, merged with any freeze + archive companions. */
|
|
6300
6050
|
async listPeriods() {
|
|
6051
|
+
this.periodCache = null;
|
|
6301
6052
|
const all = await this.loadPeriodsCache();
|
|
6302
6053
|
const freezeIds = await this.deps.adapter.list(this.deps.vault, PERIOD_FREEZES_COLLECTION);
|
|
6303
6054
|
const freezes = /* @__PURE__ */ new Map();
|
|
@@ -6389,6 +6140,9 @@ var VaultPeriods = class {
|
|
|
6389
6140
|
};
|
|
6390
6141
|
}
|
|
6391
6142
|
await this.deps.adapter.put(this.deps.vault, collection, key, envelope);
|
|
6143
|
+
if (collection === PERIODS_COLLECTION && this.deps.onDirty) {
|
|
6144
|
+
await this.deps.onDirty(collection, key, "put", envelope._v);
|
|
6145
|
+
}
|
|
6392
6146
|
return envelope;
|
|
6393
6147
|
}
|
|
6394
6148
|
/** Generic reserved-collection reader — serves `_period_freezes` companion reads. */
|
|
@@ -6977,7 +6731,7 @@ var VaultLinks = class {
|
|
|
6977
6731
|
// src/with-shape/links/lazy-handle.ts
|
|
6978
6732
|
function makeLazyLinkSetHandle(d) {
|
|
6979
6733
|
let engine = null;
|
|
6980
|
-
const load = () => engine ??= import("./link-set-
|
|
6734
|
+
const load = () => engine ??= import("./link-set-NK6L2A5S.js").then(
|
|
6981
6735
|
({ LinkSet }) => new LinkSet(d.adapter, d.vault, d.name, d.spec, d.encrypted, d.getDEK, d.actor, d.emitter, d.endpointExists)
|
|
6982
6736
|
);
|
|
6983
6737
|
return {
|
|
@@ -7460,7 +7214,7 @@ var SatelliteRegistry = class {
|
|
|
7460
7214
|
if (reason !== void 0) throw new SatelliteConfigError(reason);
|
|
7461
7215
|
}
|
|
7462
7216
|
/** Per-base async mutex: chains sections on a stored promise tail. */
|
|
7463
|
-
async withPairLock(base,
|
|
7217
|
+
async withPairLock(base, fn) {
|
|
7464
7218
|
const tail = this.locks.get(base) ?? Promise.resolve();
|
|
7465
7219
|
let release;
|
|
7466
7220
|
const gate = new Promise((res) => {
|
|
@@ -7469,7 +7223,7 @@ var SatelliteRegistry = class {
|
|
|
7469
7223
|
this.locks.set(base, tail.then(() => gate));
|
|
7470
7224
|
await tail;
|
|
7471
7225
|
try {
|
|
7472
|
-
return await
|
|
7226
|
+
return await fn();
|
|
7473
7227
|
} finally {
|
|
7474
7228
|
release();
|
|
7475
7229
|
}
|
|
@@ -7515,7 +7269,7 @@ function declareSatellite(ctx, collectionName, options, existingRegistry) {
|
|
|
7515
7269
|
ctx.forEachSyncEngine((e) => e.remirrorPairResolvers([spec.base, spec.satellite]));
|
|
7516
7270
|
const registry = reg;
|
|
7517
7271
|
const baseSchema = ctx.getBaseSchema(spec.base);
|
|
7518
|
-
void import("./post-register-
|
|
7272
|
+
void import("./post-register-VFIYISUK.js").then((m) => m.postRegister(ctx.adapter, ctx.vaultName, spec, ctx.getDEK, baseSchema, registry)).catch(() => {
|
|
7519
7273
|
});
|
|
7520
7274
|
return reg;
|
|
7521
7275
|
}
|
|
@@ -7846,20 +7600,6 @@ async function migrateSatelliteCek(name, coll) {
|
|
|
7846
7600
|
return { migrated };
|
|
7847
7601
|
}
|
|
7848
7602
|
|
|
7849
|
-
// src/with-shape/schema-update/gate.ts
|
|
7850
|
-
var SchemaUpdateGate = class {
|
|
7851
|
-
#decision;
|
|
7852
|
-
constructor(decision) {
|
|
7853
|
-
this.#decision = decision.catch(() => null);
|
|
7854
|
-
}
|
|
7855
|
-
async assertWritable() {
|
|
7856
|
-
const decision = await this.#decision;
|
|
7857
|
-
if (decision && decision.action === "reject") {
|
|
7858
|
-
throw decision.error;
|
|
7859
|
-
}
|
|
7860
|
-
}
|
|
7861
|
-
};
|
|
7862
|
-
|
|
7863
7603
|
// src/with-shape/schema-update/fence-controller.ts
|
|
7864
7604
|
var SchemaFenceController = class {
|
|
7865
7605
|
#coordination;
|
|
@@ -8032,6 +7772,43 @@ var VaultAttestation = class {
|
|
|
8032
7772
|
};
|
|
8033
7773
|
|
|
8034
7774
|
// src/kernel/vault.ts
|
|
7775
|
+
var COLLECTION_PASSTHROUGH_KEYS = [
|
|
7776
|
+
"indexes",
|
|
7777
|
+
"reconcileOnOpen",
|
|
7778
|
+
"prefetch",
|
|
7779
|
+
"cache",
|
|
7780
|
+
"schema",
|
|
7781
|
+
"conflictPolicy",
|
|
7782
|
+
"crdt",
|
|
7783
|
+
"deterministicFields",
|
|
7784
|
+
"acknowledgeDeterministicRisk",
|
|
7785
|
+
"acknowledgeEquatableRisk",
|
|
7786
|
+
"sensitive",
|
|
7787
|
+
"perRecordKeys",
|
|
7788
|
+
"provenance",
|
|
7789
|
+
"ramCiphertext",
|
|
7790
|
+
"tiers",
|
|
7791
|
+
"tierMode",
|
|
7792
|
+
"blobTierPolicy",
|
|
7793
|
+
"i18nFields",
|
|
7794
|
+
"embeddings",
|
|
7795
|
+
"textIndexes",
|
|
7796
|
+
"warmIndexOnOpen",
|
|
7797
|
+
"textIndexPersist",
|
|
7798
|
+
"moneyFields",
|
|
7799
|
+
"viaFields",
|
|
7800
|
+
"computed",
|
|
7801
|
+
"classifiedFields",
|
|
7802
|
+
"fieldMeta",
|
|
7803
|
+
"meta"
|
|
7804
|
+
];
|
|
7805
|
+
function copyDefined(dst, src, keys) {
|
|
7806
|
+
if (src === void 0) return;
|
|
7807
|
+
for (const key of keys) {
|
|
7808
|
+
const value = src[key];
|
|
7809
|
+
if (value !== void 0) dst[key] = value;
|
|
7810
|
+
}
|
|
7811
|
+
}
|
|
8035
7812
|
var Vault = class {
|
|
8036
7813
|
adapter;
|
|
8037
7814
|
/** The vault's name as passed to `openVault()`. Stable for the instance lifetime. */
|
|
@@ -8049,36 +7826,22 @@ var Vault = class {
|
|
|
8049
7826
|
syncAdapter;
|
|
8050
7827
|
getPurgeableTargets;
|
|
8051
7828
|
historyConfig;
|
|
8052
|
-
/**
|
|
8053
|
-
*
|
|
8054
|
-
|
|
7829
|
+
/**
|
|
7830
|
+
* Every opt-in service, resolved once by `createNoydb` (#838). Shared by
|
|
7831
|
+
* reference with the owning `Noydb` and with every `Collection` this vault
|
|
7832
|
+
* opens, so all three always agree about which services are enabled.
|
|
7833
|
+
*/
|
|
7834
|
+
strategies;
|
|
8055
7835
|
objectStore;
|
|
8056
|
-
/** Cold-storage archival strategy (the archive target store). */
|
|
8057
|
-
archiveStrategy;
|
|
8058
7836
|
/** Per-collection record archival policies. Indexed by collection name. */
|
|
8059
7837
|
archiveRegistry = /* @__PURE__ */ new Map();
|
|
8060
|
-
indexStrategy;
|
|
8061
|
-
lazyStrategy;
|
|
8062
|
-
aggregateStrategy;
|
|
8063
|
-
crdtStrategy;
|
|
8064
|
-
tiersStrategy;
|
|
8065
|
-
searchStrategy;
|
|
8066
|
-
/** Cargo (partition extraction) strategy — `NO_CARGO` (throwing) unless `withCargo()` was passed.
|
|
8067
|
-
* Public so the `extractPartition` free function (which takes a `Vault`) routes through it. */
|
|
8068
|
-
cargoStrategy;
|
|
8069
|
-
brokerStrategy;
|
|
8070
|
-
sealedRecordStrategy;
|
|
8071
|
-
portabilityStrategy;
|
|
8072
|
-
sequenceStrategy;
|
|
8073
|
-
consentStrategy;
|
|
8074
7838
|
periods;
|
|
8075
7839
|
linksEnforcer;
|
|
8076
|
-
|
|
8077
|
-
|
|
8078
|
-
|
|
8079
|
-
|
|
8080
|
-
|
|
8081
|
-
classifiedStrategy;
|
|
7840
|
+
/** Cargo (partition extraction) strategy — `NO_CARGO` (throwing) unless `withCargo()` was passed.
|
|
7841
|
+
* Public so the `extractPartition` free function (which takes a `Vault`) routes through it. */
|
|
7842
|
+
get cargoStrategy() {
|
|
7843
|
+
return this.strategies.cargo;
|
|
7844
|
+
}
|
|
8082
7845
|
/** Per-vault guard registry; `null` until `_initGuards()` runs (or for vaults that never register
|
|
8083
7846
|
* one) — the runtime class is dynamic-imported on demand to keep it out of the floor bundle. */
|
|
8084
7847
|
guardRegistry = null;
|
|
@@ -8127,7 +7890,7 @@ var Vault = class {
|
|
|
8127
7890
|
* @see docs/superpowers/specs/2026-06-17-fr6-deed-custodian-liberate-design.md
|
|
8128
7891
|
*/
|
|
8129
7892
|
custody;
|
|
8130
|
-
/** Re-derives an UnlockedKeyring from the adapter using the active user's
|
|
7893
|
+
/** Re-derives an UnlockedKeyring from the adapter using the active user's secret; called by
|
|
8131
7894
|
* `load()` after the on-disk keyring file has been replaced. Provided by Noydb at openVault()
|
|
8132
7895
|
* time; `undefined` in tests that construct Vault directly (load() then skips the refresh). */
|
|
8133
7896
|
reloadKeyring;
|
|
@@ -8260,23 +8023,10 @@ var Vault = class {
|
|
|
8260
8023
|
this.onRegisterConflictResolver = opts.onRegisterConflictResolver;
|
|
8261
8024
|
this.syncAdapter = opts.syncAdapter;
|
|
8262
8025
|
this.getPurgeableTargets = opts.getPurgeableTargets ?? (() => []);
|
|
8263
|
-
this.
|
|
8026
|
+
this.strategies = opts.strategies;
|
|
8264
8027
|
this.objectStore = opts.objectStore;
|
|
8265
|
-
this.archiveStrategy = opts.archiveStrategy;
|
|
8266
|
-
this.indexStrategy = opts.indexStrategy;
|
|
8267
|
-
this.lazyStrategy = opts.lazyStrategy;
|
|
8268
|
-
this.aggregateStrategy = opts.aggregateStrategy;
|
|
8269
|
-
this.crdtStrategy = opts.crdtStrategy;
|
|
8270
|
-
this.tiersStrategy = opts.tiersStrategy;
|
|
8271
|
-
this.searchStrategy = opts.searchStrategy;
|
|
8272
|
-
this.cargoStrategy = opts.cargoStrategy ?? NO_CARGO;
|
|
8273
|
-
this.brokerStrategy = opts.brokerStrategy ?? NO_BROKER;
|
|
8274
|
-
this.sealedRecordStrategy = opts.sealedRecordStrategy ?? NO_SEALED_RECORD;
|
|
8275
|
-
this.portabilityStrategy = opts.portabilityStrategy ?? NO_PORTABILITY;
|
|
8276
|
-
this.sequenceStrategy = opts.sequenceStrategy ?? NO_SEQUENCE;
|
|
8277
|
-
this.consentStrategy = opts.consentStrategy ?? NO_CONSENT;
|
|
8278
8028
|
this.periods = new VaultPeriods({
|
|
8279
|
-
strategy:
|
|
8029
|
+
strategy: this.strategies.periods,
|
|
8280
8030
|
adapter: this.adapter,
|
|
8281
8031
|
vault: this.name,
|
|
8282
8032
|
encrypted: this.encrypted,
|
|
@@ -8286,7 +8036,9 @@ var Vault = class {
|
|
|
8286
8036
|
collection: (name) => this.collection(name),
|
|
8287
8037
|
purgeDeleteMarkers: (before) => this._purgeDeleteMarkers(before),
|
|
8288
8038
|
archiveRecords: (before) => this._archiveClosedPeriod(before),
|
|
8289
|
-
purgeTargets: (before) => this._purgePeriodTargets(before)
|
|
8039
|
+
purgeTargets: (before) => this._purgePeriodTargets(before),
|
|
8040
|
+
// #822: push symmetry for the period summaries — see writeReserved.
|
|
8041
|
+
onDirty: this.onDirty
|
|
8290
8042
|
});
|
|
8291
8043
|
this.linksEnforcer = new VaultLinks({
|
|
8292
8044
|
refRegistry: this.refRegistry,
|
|
@@ -8299,12 +8051,6 @@ var Vault = class {
|
|
|
8299
8051
|
getActiveTxContext: () => this.noydb._activeTxContextOrNull,
|
|
8300
8052
|
emitter: this.emitter
|
|
8301
8053
|
});
|
|
8302
|
-
this.shadowStrategy = opts.shadowStrategy ?? NO_SHADOW;
|
|
8303
|
-
this.historyStrategy = opts.historyStrategy ?? NO_HISTORY;
|
|
8304
|
-
this.forgetStrategy = opts.forgetStrategy ?? NO_FORGET;
|
|
8305
|
-
this.i18nStrategy = opts.i18nStrategy ?? NO_I18N;
|
|
8306
|
-
this.syncStrategy = opts.syncStrategy ?? NO_SYNC;
|
|
8307
|
-
this.classifiedStrategy = opts.classifiedStrategy ?? NO_CLASSIFIED;
|
|
8308
8054
|
this.graph = new ViaGraph();
|
|
8309
8055
|
void opts.guardStrategies;
|
|
8310
8056
|
this.historyConfig = opts.historyConfig ?? { enabled: true };
|
|
@@ -8319,19 +8065,19 @@ var Vault = class {
|
|
|
8319
8065
|
getDEK: (collection) => this.getDEK(collection),
|
|
8320
8066
|
role: () => this.keyring.role,
|
|
8321
8067
|
getRawRecord: async (collection, recId) => await this.collection(collection).get(recId, { locale: "raw" })
|
|
8322
|
-
},
|
|
8068
|
+
}, this.strategies.attestation);
|
|
8323
8069
|
this.user = this.noydb.userApiFactory({
|
|
8324
8070
|
adapter: this.adapter,
|
|
8325
8071
|
vaultName: this.name,
|
|
8326
8072
|
writerKeyringId: this.keyring.userId,
|
|
8327
8073
|
getDek: () => this.getDEK(USER_ENVELOPE_COLLECTION),
|
|
8328
8074
|
checkGate: (gate, presented) => this.noydb.checkGate(this.name, gate, presented),
|
|
8329
|
-
exportAccessible: (opts2) => this.
|
|
8330
|
-
unilateralWithdraw: (opts2) => this.
|
|
8331
|
-
requestWithdraw: (opts2) => this.
|
|
8332
|
-
listWithdrawals: (opts2) => this.
|
|
8333
|
-
approveWithdraw: (requestId, opts2) => this.
|
|
8334
|
-
rejectWithdraw: (requestId, opts2) => this.
|
|
8075
|
+
exportAccessible: (opts2) => this.strategies.portability.exportAccessibleData(this, opts2),
|
|
8076
|
+
unilateralWithdraw: (opts2) => this.strategies.portability.withdrawAccessibleData(this, opts2),
|
|
8077
|
+
requestWithdraw: (opts2) => this.strategies.portability.requestWithdrawal(this, opts2),
|
|
8078
|
+
listWithdrawals: (opts2) => this.strategies.portability.listWithdrawalRequests(this, opts2),
|
|
8079
|
+
approveWithdraw: (requestId, opts2) => this.strategies.portability.approveWithdrawal(this, requestId, opts2),
|
|
8080
|
+
rejectWithdraw: (requestId, opts2) => this.strategies.portability.rejectWithdrawal(this, requestId, opts2)
|
|
8335
8081
|
});
|
|
8336
8082
|
this.custody = new CustodyApi(
|
|
8337
8083
|
(options, factors) => this.noydb.grantCustodian(this.name, options, factors),
|
|
@@ -8389,7 +8135,7 @@ var Vault = class {
|
|
|
8389
8135
|
* dispatch reads/writes — from this vault's OWN privates, rather than passing `this` itself. */
|
|
8390
8136
|
_viaReconcileCtx() {
|
|
8391
8137
|
return {
|
|
8392
|
-
i18nStrategy: this.
|
|
8138
|
+
i18nStrategy: this.strategies.i18n,
|
|
8393
8139
|
locale: this.locale,
|
|
8394
8140
|
translateText: this.translateText,
|
|
8395
8141
|
i18nFieldRegistry: this.i18nFieldRegistry,
|
|
@@ -8405,6 +8151,22 @@ var Vault = class {
|
|
|
8405
8151
|
enforceStaticDictOnPut: (collectionName, record) => this.enforceStaticDictOnPut(collectionName, record)
|
|
8406
8152
|
};
|
|
8407
8153
|
}
|
|
8154
|
+
/** The registries `populateCollectionRegistries` writes into (#841). */
|
|
8155
|
+
#registries() {
|
|
8156
|
+
return {
|
|
8157
|
+
refRegistry: this.refRegistry,
|
|
8158
|
+
i18nFieldRegistry: this.i18nFieldRegistry,
|
|
8159
|
+
blobFieldsRegistry: this.blobFieldsRegistry,
|
|
8160
|
+
archiveRegistry: this.archiveRegistry,
|
|
8161
|
+
attestation: this.attestation,
|
|
8162
|
+
dictKeyFieldRegistry: this.dictKeyFieldRegistry,
|
|
8163
|
+
staticDictNames: this.staticDictNames,
|
|
8164
|
+
staticByName: this.staticByName,
|
|
8165
|
+
staticDescriptorByField: this.staticDescriptorByField,
|
|
8166
|
+
reservedLookupCollections: this.reservedLookupCollections,
|
|
8167
|
+
schemaUpdateNames: this.#schemaUpdateNames
|
|
8168
|
+
};
|
|
8169
|
+
}
|
|
8408
8170
|
collection(collectionName, options) {
|
|
8409
8171
|
const overlayRegistry = this.overlayedViewRegistry;
|
|
8410
8172
|
if (overlayRegistry !== null && overlayRegistry.isOverlay(collectionName)) {
|
|
@@ -8430,7 +8192,7 @@ var Vault = class {
|
|
|
8430
8192
|
this.satelliteRegistry = declareSatellite({
|
|
8431
8193
|
adapter: this.adapter,
|
|
8432
8194
|
vaultName: this.name,
|
|
8433
|
-
forgetSubjects: this.
|
|
8195
|
+
forgetSubjects: this.strategies.forget.subjects,
|
|
8434
8196
|
getDEK: this.getDEK,
|
|
8435
8197
|
getBaseSchema: (base) => this.collectionCache.get(base)?.getSchema(),
|
|
8436
8198
|
getBaseCrdt: (base) => this.collectionCache.get(base)?.getConfig()?.crdt,
|
|
@@ -8438,8 +8200,8 @@ var Vault = class {
|
|
|
8438
8200
|
registerPoisonHook: (hook) => {
|
|
8439
8201
|
this.noydb._writeHooks.onBeforeWrite(hook);
|
|
8440
8202
|
},
|
|
8441
|
-
forEachSyncEngine: (
|
|
8442
|
-
this.noydb._forEachSyncEngine(this.name,
|
|
8203
|
+
forEachSyncEngine: (fn) => {
|
|
8204
|
+
this.noydb._forEachSyncEngine(this.name, fn);
|
|
8443
8205
|
}
|
|
8444
8206
|
}, collectionName, { ...options, satelliteOf: options.satelliteOf }, this.satelliteRegistry);
|
|
8445
8207
|
}
|
|
@@ -8456,60 +8218,14 @@ var Vault = class {
|
|
|
8456
8218
|
});
|
|
8457
8219
|
}
|
|
8458
8220
|
if (!coll) {
|
|
8459
|
-
|
|
8460
|
-
this.refRegistry.register(collectionName, options.refs);
|
|
8461
|
-
}
|
|
8462
|
-
if (effectiveViaFields.i18nFields) {
|
|
8463
|
-
this.i18nFieldRegistry.set(collectionName, effectiveViaFields.i18nFields);
|
|
8464
|
-
}
|
|
8465
|
-
if (options?.blobFields) {
|
|
8466
|
-
this.blobFieldsRegistry.set(collectionName, options.blobFields);
|
|
8467
|
-
}
|
|
8468
|
-
if (options?.archive) {
|
|
8469
|
-
this.archiveRegistry.set(collectionName, options.archive);
|
|
8470
|
-
}
|
|
8471
|
-
if (options?.attestation !== void 0) {
|
|
8472
|
-
this.attestation.register(collectionName, options.attestation);
|
|
8473
|
-
}
|
|
8474
|
-
if (effectiveViaFields.dictKeyFields || effectiveViaFields.lookupFields) {
|
|
8475
|
-
const dictFieldMap = {};
|
|
8476
|
-
const staticFieldMap = {};
|
|
8477
|
-
for (const [field, desc] of Object.entries(effectiveViaFields.dictKeyFields ?? {})) {
|
|
8478
|
-
if (isStaticDictDescriptor(desc)) {
|
|
8479
|
-
staticFieldMap[field] = desc;
|
|
8480
|
-
this.staticDictNames.add(desc.name);
|
|
8481
|
-
this.staticByName.set(desc.name, desc);
|
|
8482
|
-
} else {
|
|
8483
|
-
dictFieldMap[field] = desc.name;
|
|
8484
|
-
}
|
|
8485
|
-
}
|
|
8486
|
-
const lookupCompat = collectLookupDictCompat(effectiveViaFields.lookupFields);
|
|
8487
|
-
Object.assign(dictFieldMap, lookupCompat.dictFieldMap);
|
|
8488
|
-
for (const [field, desc] of lookupCompat.staticEntries) {
|
|
8489
|
-
staticFieldMap[field] = desc;
|
|
8490
|
-
this.staticDictNames.add(desc.name);
|
|
8491
|
-
this.staticByName.set(desc.name, desc);
|
|
8492
|
-
}
|
|
8493
|
-
if (Object.keys(dictFieldMap).length > 0) {
|
|
8494
|
-
this.dictKeyFieldRegistry.set(collectionName, dictFieldMap);
|
|
8495
|
-
for (const dictName of new Set(Object.values(dictFieldMap))) {
|
|
8496
|
-
this.reservedLookupCollections.set(dictCollectionName(dictName), dictName);
|
|
8497
|
-
}
|
|
8498
|
-
}
|
|
8499
|
-
if (Object.keys(staticFieldMap).length > 0) {
|
|
8500
|
-
this.staticDescriptorByField.set(collectionName, staticFieldMap);
|
|
8501
|
-
}
|
|
8502
|
-
}
|
|
8503
|
-
if ((options?.schemaUpdate?.length ?? 0) > 0) {
|
|
8504
|
-
this.#schemaUpdateNames.set(collectionName, (options.schemaUpdate ?? []).map((s) => s.name));
|
|
8505
|
-
}
|
|
8221
|
+
populateCollectionRegistries(this.#registries(), collectionName, options, effectiveViaFields);
|
|
8506
8222
|
let schemaUpdateGate;
|
|
8507
8223
|
if (options?.persistJsonSchema === true && options.schema !== void 0 && (options.schemaUpdate?.length ?? 0) > 0) {
|
|
8508
8224
|
const validator = options.schema;
|
|
8509
8225
|
const strategies = options.schemaUpdate ?? [];
|
|
8510
8226
|
const work = (async () => {
|
|
8511
8227
|
const dek = await this.getDEK(collectionName);
|
|
8512
|
-
const { persistSchemaIfNeeded } = await import("./register-
|
|
8228
|
+
const { persistSchemaIfNeeded } = await import("./register-UKU2J6MN.js");
|
|
8513
8229
|
const result = await persistSchemaIfNeeded({
|
|
8514
8230
|
store: this.adapter,
|
|
8515
8231
|
vault: this.name,
|
|
@@ -8550,22 +8266,9 @@ var Vault = class {
|
|
|
8550
8266
|
// #693: re-create gate fallback
|
|
8551
8267
|
historyConfig: effectiveHistoryConfig,
|
|
8552
8268
|
historyConfigExplicit: options?.historyConfig !== void 0,
|
|
8553
|
-
// thread the vault-wide blob strategy into every
|
|
8554
|
-
// collection. `undefined` is intentionally preserved so the
|
|
8555
|
-
// Collection constructor uses its NO_BLOBS default.
|
|
8556
|
-
...this.blobStrategy !== void 0 ? { blobStrategy: this.blobStrategy } : {},
|
|
8557
8269
|
...this.objectStore !== void 0 ? { objectStore: this.objectStore } : {},
|
|
8558
8270
|
...options?.blobFields !== void 0 ? { blobFields: options.blobFields } : {},
|
|
8559
|
-
|
|
8560
|
-
...this.lazyStrategy !== void 0 ? { lazyStrategy: this.lazyStrategy } : {},
|
|
8561
|
-
...this.aggregateStrategy !== void 0 ? { aggregateStrategy: this.aggregateStrategy } : {},
|
|
8562
|
-
...this.crdtStrategy !== void 0 ? { crdtStrategy: this.crdtStrategy } : {},
|
|
8563
|
-
...this.tiersStrategy !== void 0 ? { tiersStrategy: this.tiersStrategy } : {},
|
|
8564
|
-
...this.searchStrategy !== void 0 ? { searchStrategy: this.searchStrategy } : {},
|
|
8565
|
-
historyStrategy: this.historyStrategy,
|
|
8566
|
-
i18nStrategy: this.i18nStrategy,
|
|
8567
|
-
syncStrategy: this.syncStrategy,
|
|
8568
|
-
classifiedStrategy: this.classifiedStrategy,
|
|
8271
|
+
strategies: this.strategies,
|
|
8569
8272
|
// Per-collection ledger opt-out: when this collection sets
|
|
8570
8273
|
// `historyConfig.ledger: false`, withhold the ledger reference so all
|
|
8571
8274
|
// four `if (this.ledger)` append sites in Collection no-op. The chain
|
|
@@ -8603,31 +8306,12 @@ var Vault = class {
|
|
|
8603
8306
|
}
|
|
8604
8307
|
} : {}
|
|
8605
8308
|
};
|
|
8606
|
-
|
|
8607
|
-
|
|
8608
|
-
if (options?.prefetch !== void 0) collOpts.prefetch = options.prefetch;
|
|
8609
|
-
if (options?.cache !== void 0) collOpts.cache = options.cache;
|
|
8610
|
-
if (options?.schema !== void 0) collOpts.schema = options.schema;
|
|
8611
|
-
if (options?.conflictPolicy !== void 0) collOpts.conflictPolicy = options.conflictPolicy;
|
|
8612
|
-
if (options?.crdt !== void 0) collOpts.crdt = options.crdt;
|
|
8613
|
-
if (options?.deterministicFields !== void 0) {
|
|
8614
|
-
collOpts.deterministicFields = options.deterministicFields;
|
|
8615
|
-
}
|
|
8616
|
-
if (options?.acknowledgeDeterministicRisk !== void 0) {
|
|
8617
|
-
collOpts.acknowledgeDeterministicRisk = options.acknowledgeDeterministicRisk;
|
|
8618
|
-
}
|
|
8619
|
-
if (options?.acknowledgeEquatableRisk !== void 0) {
|
|
8620
|
-
collOpts.acknowledgeEquatableRisk = options.acknowledgeEquatableRisk;
|
|
8621
|
-
}
|
|
8622
|
-
if (options?.sensitive !== void 0) {
|
|
8623
|
-
collOpts.sensitive = options.sensitive;
|
|
8624
|
-
}
|
|
8625
|
-
if (options?.perRecordKeys !== void 0) collOpts.perRecordKeys = options.perRecordKeys;
|
|
8626
|
-
const subjectKey = this.forgetStrategy.subjects[collectionName];
|
|
8309
|
+
copyDefined(collOpts, options, COLLECTION_PASSTHROUGH_KEYS);
|
|
8310
|
+
const subjectKey = this.strategies.forget.subjects[collectionName];
|
|
8627
8311
|
if (subjectKey !== void 0) {
|
|
8628
8312
|
if (options?.perRecordKeys === false) {
|
|
8629
8313
|
console.warn(
|
|
8630
|
-
`[noy-db] Collection "${collectionName}" is declared in
|
|
8314
|
+
`[noy-db] Collection "${collectionName}" is declared in withForget but opened with perRecordKeys: false. Forcing perRecordKeys: true \u2014 GDPR crypto-shred requires per-record CEKs.`
|
|
8631
8315
|
);
|
|
8632
8316
|
}
|
|
8633
8317
|
collOpts.perRecordKeys = true;
|
|
@@ -8637,22 +8321,8 @@ var Vault = class {
|
|
|
8637
8321
|
if (value !== void 0 && value !== null) await this._addSubjectRef(coerceSubjectId(value), { collection: collectionName, id });
|
|
8638
8322
|
};
|
|
8639
8323
|
}
|
|
8640
|
-
if (options?.provenance !== void 0) collOpts.provenance = options.provenance;
|
|
8641
|
-
if (options?.ramCiphertext !== void 0) collOpts.ramCiphertext = options.ramCiphertext;
|
|
8642
|
-
if (options?.tiers !== void 0) collOpts.tiers = options.tiers;
|
|
8643
|
-
if (options?.tierMode !== void 0) collOpts.tierMode = options.tierMode;
|
|
8644
|
-
if (options?.blobTierPolicy !== void 0) collOpts.blobTierPolicy = options.blobTierPolicy;
|
|
8645
8324
|
collOpts.onCrossTierAccess = (event) => this.emitCrossTier(event);
|
|
8646
8325
|
if (this.syncAdapter !== void 0) collOpts.syncAdapter = this.syncAdapter;
|
|
8647
|
-
if (options?.i18nFields !== void 0) collOpts.i18nFields = options.i18nFields;
|
|
8648
|
-
if (options?.embeddings !== void 0) collOpts.embeddings = options.embeddings;
|
|
8649
|
-
if (options?.textIndexes !== void 0) collOpts.textIndexes = options.textIndexes;
|
|
8650
|
-
if (options?.warmIndexOnOpen !== void 0) collOpts.warmIndexOnOpen = options.warmIndexOnOpen;
|
|
8651
|
-
if (options?.textIndexPersist !== void 0) collOpts.textIndexPersist = options.textIndexPersist;
|
|
8652
|
-
if (options?.moneyFields !== void 0) collOpts.moneyFields = options.moneyFields;
|
|
8653
|
-
if (options?.viaFields !== void 0) collOpts.viaFields = options.viaFields;
|
|
8654
|
-
if (options?.computed !== void 0) collOpts.computed = options.computed;
|
|
8655
|
-
if (options?.classifiedFields !== void 0) collOpts.classifiedFields = options.classifiedFields;
|
|
8656
8326
|
if (effectiveViaFields.dictKeyFields !== void 0 || effectiveViaFields.lookupFields !== void 0) {
|
|
8657
8327
|
collOpts.dictLabelResolver = async (dictName, key, locale, fallback) => {
|
|
8658
8328
|
const stat = this.staticByName.get(dictName);
|
|
@@ -8686,10 +8356,6 @@ var Vault = class {
|
|
|
8686
8356
|
if (effectiveViaFields.i18nFields !== void 0 && this.translateText) {
|
|
8687
8357
|
collOpts.autoTranslateHook = this.translateText;
|
|
8688
8358
|
}
|
|
8689
|
-
if (options?.fieldMeta !== void 0) {
|
|
8690
|
-
collOpts.fieldMeta = options.fieldMeta;
|
|
8691
|
-
}
|
|
8692
|
-
if (options?.meta !== void 0) collOpts.meta = options.meta;
|
|
8693
8359
|
if (options?.refs !== void 0) {
|
|
8694
8360
|
collOpts.declaredRefs = this.refRegistry.getOutbound(collectionName);
|
|
8695
8361
|
}
|
|
@@ -8708,7 +8374,7 @@ var Vault = class {
|
|
|
8708
8374
|
const work = (async () => {
|
|
8709
8375
|
try {
|
|
8710
8376
|
const dek = await this.getDEK(collectionName);
|
|
8711
|
-
await (await import("./register-
|
|
8377
|
+
await (await import("./register-UKU2J6MN.js")).persistSchemaIfNeeded({
|
|
8712
8378
|
store: this.adapter,
|
|
8713
8379
|
vault: this.name,
|
|
8714
8380
|
collectionName,
|
|
@@ -9004,7 +8670,7 @@ var Vault = class {
|
|
|
9004
8670
|
const values = getAtPath(obj, field);
|
|
9005
8671
|
for (const value of values) {
|
|
9006
8672
|
if (value === void 0 || value === null) continue;
|
|
9007
|
-
this.
|
|
8673
|
+
this.strategies.i18n.validateI18nTextValue(value, field, descriptor);
|
|
9008
8674
|
}
|
|
9009
8675
|
}
|
|
9010
8676
|
}
|
|
@@ -9045,7 +8711,7 @@ var Vault = class {
|
|
|
9045
8711
|
this.reservedLookupCollections.set(dictCollectionName(name), name);
|
|
9046
8712
|
let handle = this.dictionaryCache.get(name);
|
|
9047
8713
|
if (!handle) {
|
|
9048
|
-
handle = this.
|
|
8714
|
+
handle = this.strategies.i18n.buildDictionaryHandle({
|
|
9049
8715
|
adapter: this.adapter,
|
|
9050
8716
|
compartmentName: this.name,
|
|
9051
8717
|
dictionaryName: name,
|
|
@@ -9206,7 +8872,7 @@ var Vault = class {
|
|
|
9206
8872
|
* is re-keyed for distinct recipients.
|
|
9207
8873
|
*
|
|
9208
8874
|
* Each recipient becomes its own `KeyringFile` sealed with that
|
|
9209
|
-
* recipient's
|
|
8875
|
+
* recipient's secret. The DEKs wrapped into each slot are
|
|
9210
8876
|
* exactly those the recipient's role + permissions justify, and
|
|
9211
8877
|
* never wider than the source keyring's own DEK set
|
|
9212
8878
|
* (privilege-escalation check).
|
|
@@ -9258,7 +8924,7 @@ var Vault = class {
|
|
|
9258
8924
|
};
|
|
9259
8925
|
}
|
|
9260
8926
|
if (!this.sequenceStore) {
|
|
9261
|
-
this.sequenceStore = this.
|
|
8927
|
+
this.sequenceStore = this.strategies.sequence.createStore({
|
|
9262
8928
|
adapter: this.adapter,
|
|
9263
8929
|
vault: this.name,
|
|
9264
8930
|
encrypted: this.encrypted,
|
|
@@ -9331,7 +8997,9 @@ var Vault = class {
|
|
|
9331
8997
|
deleteSlot: async (name, id, slotName) => {
|
|
9332
8998
|
const coll = this.collection(name);
|
|
9333
8999
|
await coll.blob(id).delete(slotName);
|
|
9334
|
-
}
|
|
9000
|
+
},
|
|
9001
|
+
dropLocalCache: async (name, id, slotName) => this.collection(name).blob(id).dropLocalCache(slotName)
|
|
9002
|
+
// #808: budget pass drops device-local external cache copies
|
|
9335
9003
|
}, options);
|
|
9336
9004
|
}
|
|
9337
9005
|
/**
|
|
@@ -9354,7 +9022,7 @@ var Vault = class {
|
|
|
9354
9022
|
return runListArchived(this._archiveContext(), collection);
|
|
9355
9023
|
}
|
|
9356
9024
|
_archiveContext() {
|
|
9357
|
-
const strategy = this.
|
|
9025
|
+
const strategy = this.strategies.archive;
|
|
9358
9026
|
if (!strategy) {
|
|
9359
9027
|
throw new Error(
|
|
9360
9028
|
"vault.archive/restore/listArchived require `archiveStrategy: withArchive({ store })` in createNoydb"
|
|
@@ -9521,7 +9189,7 @@ var Vault = class {
|
|
|
9521
9189
|
*/
|
|
9522
9190
|
getLedgerOrNull() {
|
|
9523
9191
|
if (!this.ledgerStore) {
|
|
9524
|
-
this.ledgerStore = this.
|
|
9192
|
+
this.ledgerStore = this.strategies.history.buildLedger({
|
|
9525
9193
|
adapter: this.adapter,
|
|
9526
9194
|
vault: this.name,
|
|
9527
9195
|
encrypted: this.encrypted,
|
|
@@ -9546,7 +9214,7 @@ var Vault = class {
|
|
|
9546
9214
|
* number of distinct subjects re-indexed.
|
|
9547
9215
|
*/
|
|
9548
9216
|
async rebuildSubjectIndex() {
|
|
9549
|
-
if (Object.keys(this.
|
|
9217
|
+
if (Object.keys(this.strategies.forget.subjects).length === 0) {
|
|
9550
9218
|
throw new ForgetStrategyNotConfiguredError();
|
|
9551
9219
|
}
|
|
9552
9220
|
return rebuildSubjectIndex(
|
|
@@ -9554,7 +9222,7 @@ var Vault = class {
|
|
|
9554
9222
|
this.name,
|
|
9555
9223
|
this.getDEK,
|
|
9556
9224
|
this.encrypted,
|
|
9557
|
-
this.
|
|
9225
|
+
this.strategies.forget.subjects,
|
|
9558
9226
|
async (collectionName, id, env) => {
|
|
9559
9227
|
const coll = this.collection(collectionName);
|
|
9560
9228
|
return coll._decodeEnvelope(env, id);
|
|
@@ -9576,10 +9244,10 @@ var Vault = class {
|
|
|
9576
9244
|
* stay decryptable; migrate, then re-forget) and `blobResidueCollections` (blob attachments, keyed
|
|
9577
9245
|
* off a separate `_blob` DEK, out of scope here).
|
|
9578
9246
|
*
|
|
9579
|
-
* @throws ForgetStrategyNotConfiguredError when no `
|
|
9247
|
+
* @throws ForgetStrategyNotConfiguredError when no `withForget` was set.
|
|
9580
9248
|
*/
|
|
9581
9249
|
async forget(subjectId) {
|
|
9582
|
-
if (Object.keys(this.
|
|
9250
|
+
if (Object.keys(this.strategies.forget.subjects).length === 0) {
|
|
9583
9251
|
throw new ForgetStrategyNotConfiguredError();
|
|
9584
9252
|
}
|
|
9585
9253
|
const ledger = this.getLedgerOrNull();
|
|
@@ -9601,17 +9269,17 @@ var Vault = class {
|
|
|
9601
9269
|
const sealedResidue = [];
|
|
9602
9270
|
const indexResidue = [];
|
|
9603
9271
|
const ledgerDeltaResidue = [];
|
|
9604
|
-
const blobsEnabled = this.
|
|
9272
|
+
const blobsEnabled = this.strategies.blobs !== NO_BLOBS;
|
|
9605
9273
|
const actor = this.keyring.userId;
|
|
9606
9274
|
const fanoutStats = { recordsErased: 0, aggregatesRecomputed: 0, residueFrozen: [], lookupReferencesCascaded: 0, lookupReferencesNullified: 0, lookupReferencesResidue: [], derivedResidueUndecodable: [], derivedResidueDeclined: [] };
|
|
9607
9275
|
const { partitionSealedCekKeys, shouldSkipBlobScan, bumpResidueCount, residueNoticesFromMap } = await import("./purge-scope-FGNNLWHD.js");
|
|
9608
|
-
const scopedPurge = this.
|
|
9276
|
+
const scopedPurge = this.strategies.forget.scopedPurge === true;
|
|
9609
9277
|
const sealedCekScopedSkipped = /* @__PURE__ */ new Map();
|
|
9610
9278
|
const blobScopedSkipped = /* @__PURE__ */ new Map();
|
|
9611
9279
|
for (const ref2 of allRefs) {
|
|
9612
9280
|
const coll = this.collection(ref2.collection);
|
|
9613
9281
|
const satelliteOf = ref2.satelliteOf;
|
|
9614
|
-
const perRecordKeys = this.
|
|
9282
|
+
const perRecordKeys = this.strategies.forget.subjects[satelliteOf ?? ref2.collection] !== void 0;
|
|
9615
9283
|
const lookupCompareKeys = await this.linksEnforcer.checkLookupRefsRestrict(this.graph, ref2.collection, ref2.collection, ref2.id);
|
|
9616
9284
|
const live = await this.adapter.get(this.name, ref2.collection, ref2.id);
|
|
9617
9285
|
if (perRecordKeys && live && live._data && !hasPerRecordKey(live)) {
|
|
@@ -9671,7 +9339,7 @@ var Vault = class {
|
|
|
9671
9339
|
collections.add(ref2.collection);
|
|
9672
9340
|
await forgetDerivedFanout(this, { collection: ref2.collection, id: ref2.id }, live, fanoutStats, lookupCompareKeys);
|
|
9673
9341
|
}
|
|
9674
|
-
historyVersionsShredded += await this.
|
|
9342
|
+
historyVersionsShredded += await this.strategies.history.tombstoneHistory(
|
|
9675
9343
|
this.adapter,
|
|
9676
9344
|
this.name,
|
|
9677
9345
|
ref2.collection,
|
|
@@ -9801,7 +9469,7 @@ var Vault = class {
|
|
|
9801
9469
|
* `<collection>/<id>/<pid>` key the delivery envelope was written under.
|
|
9802
9470
|
*/
|
|
9803
9471
|
async sealRecordToHost(collection, id, hostSealer, opts) {
|
|
9804
|
-
return this.
|
|
9472
|
+
return this.strategies.sealedRecord.sealRecordToHost(this._sealingContext(), collection, id, hostSealer, opts);
|
|
9805
9473
|
}
|
|
9806
9474
|
/**
|
|
9807
9475
|
* Revoke a sealed-CEK grant. **Default is SOFT**: deletes the `pid` delivery
|
|
@@ -9811,7 +9479,7 @@ var Vault = class {
|
|
|
9811
9479
|
* longer open the record. See `revokeSealedRecord` in `record-keys/sealing.ts`.
|
|
9812
9480
|
*/
|
|
9813
9481
|
async revokeSealedRecord(collection, id, pid, opts) {
|
|
9814
|
-
return this.
|
|
9482
|
+
return this.strategies.sealedRecord.revokeSealedRecord(this._sealingContext(), collection, id, pid, opts);
|
|
9815
9483
|
}
|
|
9816
9484
|
/**
|
|
9817
9485
|
* HARD-rotate a record's CEK: decrypt the live body under the old CEK,
|
|
@@ -9831,7 +9499,7 @@ var Vault = class {
|
|
|
9831
9499
|
* @throws {@link RecordCekNotFoundError} if the record is missing or has no `_cek`.
|
|
9832
9500
|
*/
|
|
9833
9501
|
async rotateRecordCek(collection, id) {
|
|
9834
|
-
return this.
|
|
9502
|
+
return this.strategies.sealedRecord.rotateRecordCek(this._sealingContext(), collection, id);
|
|
9835
9503
|
}
|
|
9836
9504
|
/**
|
|
9837
9505
|
* Build the {@link SealingContext} the record-keys grantor functions need:
|
|
@@ -9865,7 +9533,7 @@ var Vault = class {
|
|
|
9865
9533
|
async _initGuards(handles) {
|
|
9866
9534
|
if (handles.length === 0) return;
|
|
9867
9535
|
const [{ GuardRegistry }, { ReadOnlyVaultFacade }] = await Promise.all([
|
|
9868
|
-
import("./registry-
|
|
9536
|
+
import("./registry-BWD2ED52.js"),
|
|
9869
9537
|
import("./read-only-facade-CHCKSEPD.js")
|
|
9870
9538
|
]);
|
|
9871
9539
|
const registry = new GuardRegistry();
|
|
@@ -9893,7 +9561,7 @@ var Vault = class {
|
|
|
9893
9561
|
async _initDerivations(handles) {
|
|
9894
9562
|
if (handles.length === 0) return;
|
|
9895
9563
|
const [{ DerivationRegistry }, { ReadOnlyVaultFacade }] = await Promise.all([
|
|
9896
|
-
import("./registry-
|
|
9564
|
+
import("./registry-DTWRJLSF.js"),
|
|
9897
9565
|
import("./read-only-facade-CHCKSEPD.js")
|
|
9898
9566
|
]);
|
|
9899
9567
|
const registry = new DerivationRegistry();
|
|
@@ -9925,7 +9593,7 @@ var Vault = class {
|
|
|
9925
9593
|
*/
|
|
9926
9594
|
async _initMaterializedViews(handles) {
|
|
9927
9595
|
if (handles.length === 0) return;
|
|
9928
|
-
const { MaterializedViewRegistry } = await import("./registry-
|
|
9596
|
+
const { MaterializedViewRegistry } = await import("./registry-2VCWVHZS.js");
|
|
9929
9597
|
const registry = new MaterializedViewRegistry();
|
|
9930
9598
|
this.materializedViewRegistry = registry;
|
|
9931
9599
|
const db = this;
|
|
@@ -9950,7 +9618,7 @@ var Vault = class {
|
|
|
9950
9618
|
*/
|
|
9951
9619
|
async _initOverlayedViews(handles) {
|
|
9952
9620
|
if (handles.length === 0) return;
|
|
9953
|
-
const { OverlayedViewRegistry } = await import("./registry-
|
|
9621
|
+
const { OverlayedViewRegistry } = await import("./registry-7Y5WF7GS.js");
|
|
9954
9622
|
const registry = new OverlayedViewRegistry();
|
|
9955
9623
|
const mvRegistry = this.materializedViewRegistry;
|
|
9956
9624
|
const overlayNames = /* @__PURE__ */ new Set();
|
|
@@ -9997,14 +9665,14 @@ var Vault = class {
|
|
|
9997
9665
|
if (!reg) {
|
|
9998
9666
|
throw new Error(`refreshView: no MV registered with name "${name}"`);
|
|
9999
9667
|
}
|
|
10000
|
-
const { MaterializedViewExecutor } = await import("./executor-
|
|
9668
|
+
const { MaterializedViewExecutor } = await import("./executor-OTF556PL.js");
|
|
10001
9669
|
const result = await MaterializedViewExecutor.refresh(reg, {
|
|
10002
9670
|
getCollection: (n) => this.collection(n),
|
|
10003
9671
|
getActiveTxContext: () => this.noydb._activeTxContextOrNull,
|
|
10004
9672
|
getQueryContext: () => this,
|
|
10005
9673
|
dispatchCtx: this._dispatchCtx({ collection: name, id: "refreshView" })
|
|
10006
9674
|
});
|
|
10007
|
-
const { clearMVStaleFully } = await import("./stale-
|
|
9675
|
+
const { clearMVStaleFully } = await import("./stale-A4J26OIC.js");
|
|
10008
9676
|
await clearMVStaleFully(this.adapter, this.name, registry, name);
|
|
10009
9677
|
return result;
|
|
10010
9678
|
}
|
|
@@ -10017,7 +9685,7 @@ var Vault = class {
|
|
|
10017
9685
|
if (registry === null) return { derived: 0, failed: 0, skippedFrozen: 0 };
|
|
10018
9686
|
const strategies = registry.strategiesForSource(sourceCollection);
|
|
10019
9687
|
if (strategies.length === 0) return { derived: 0, failed: 0, skippedFrozen: 0 };
|
|
10020
|
-
const { DerivationExecutor } = await import("./executor-
|
|
9688
|
+
const { DerivationExecutor } = await import("./executor-IEBLTBCW.js");
|
|
10021
9689
|
const sourceColl = this.collection(sourceCollection);
|
|
10022
9690
|
const records = await sourceColl.list();
|
|
10023
9691
|
const ctx = { vault: this.derivationFacade ?? new (await import("./read-only-facade-CHCKSEPD.js")).ReadOnlyVaultFacade(this, "derivation") };
|
|
@@ -10044,7 +9712,7 @@ var Vault = class {
|
|
|
10044
9712
|
if (!outSpec) continue;
|
|
10045
9713
|
const outputColl = this.collection(outSpec.collection);
|
|
10046
9714
|
if (out.kind === "array") {
|
|
10047
|
-
const { loadFanoutSidecar, saveFanoutSidecar } = await import("./fanout-sidecar-
|
|
9715
|
+
const { loadFanoutSidecar, saveFanoutSidecar } = await import("./fanout-sidecar-SSMRSC2L.js");
|
|
10048
9716
|
const prior = await loadFanoutSidecar(this.adapter, this.name, spec.source, id, key, this.getDEK, this.encrypted);
|
|
10049
9717
|
const prevKeys = new Set(prior?.keys ?? []);
|
|
10050
9718
|
const newKeysList = out.entries.map((e) => e.key);
|
|
@@ -10138,7 +9806,7 @@ var Vault = class {
|
|
|
10138
9806
|
*/
|
|
10139
9807
|
at(timestamp) {
|
|
10140
9808
|
const iso = timestamp instanceof Date ? timestamp.toISOString() : timestamp;
|
|
10141
|
-
return this.
|
|
9809
|
+
return this.strategies.history.buildVaultInstant(
|
|
10142
9810
|
{
|
|
10143
9811
|
adapter: this.adapter,
|
|
10144
9812
|
name: this.name,
|
|
@@ -10170,11 +9838,11 @@ var Vault = class {
|
|
|
10170
9838
|
*.
|
|
10171
9839
|
*/
|
|
10172
9840
|
frame() {
|
|
10173
|
-
return this.
|
|
9841
|
+
return this.strategies.shadow.buildFrame(this);
|
|
10174
9842
|
}
|
|
10175
9843
|
/** Credential-broker handle (#479); `NO_BROKER` throws unless `brokerStrategy: withBroker(config)` was passed to createNoydb(). */
|
|
10176
9844
|
broker() {
|
|
10177
|
-
return buildCredentialBrokerHandle(this.
|
|
9845
|
+
return buildCredentialBrokerHandle(this.strategies.broker, this.adapter, this.name, () => this.keyring);
|
|
10178
9846
|
}
|
|
10179
9847
|
/**
|
|
10180
9848
|
* Run `fn` under a consent scope. Every `get` / `put` / `delete`
|
|
@@ -10199,11 +9867,11 @@ var Vault = class {
|
|
|
10199
9867
|
*
|
|
10200
9868
|
*.
|
|
10201
9869
|
*/
|
|
10202
|
-
async withConsent(ctx,
|
|
9870
|
+
async withConsent(ctx, fn) {
|
|
10203
9871
|
const prior = this.consentContext;
|
|
10204
9872
|
this.consentContext = ctx;
|
|
10205
9873
|
try {
|
|
10206
|
-
return await
|
|
9874
|
+
return await fn();
|
|
10207
9875
|
} finally {
|
|
10208
9876
|
this.consentContext = prior;
|
|
10209
9877
|
}
|
|
@@ -10216,7 +9884,7 @@ var Vault = class {
|
|
|
10216
9884
|
*.
|
|
10217
9885
|
*/
|
|
10218
9886
|
async consentAudit(filter = {}) {
|
|
10219
|
-
return this.
|
|
9887
|
+
return this.strategies.consent.read(this.adapter, this.name, this.encrypted, this.getDEK, filter);
|
|
10220
9888
|
}
|
|
10221
9889
|
/**
|
|
10222
9890
|
* Called by Collection after every access when a consent scope is
|
|
@@ -10227,7 +9895,7 @@ var Vault = class {
|
|
|
10227
9895
|
async _logConsent(op, collection, recordId) {
|
|
10228
9896
|
const ctx = this.consentContext;
|
|
10229
9897
|
if (!ctx) return;
|
|
10230
|
-
await this.
|
|
9898
|
+
await this.strategies.consent.write(
|
|
10231
9899
|
this.adapter,
|
|
10232
9900
|
this.name,
|
|
10233
9901
|
this.encrypted,
|
|
@@ -10271,10 +9939,10 @@ var Vault = class {
|
|
|
10271
9939
|
* collection.
|
|
10272
9940
|
*/
|
|
10273
9941
|
async delegate(opts) {
|
|
10274
|
-
const { issueDelegation, DELEGATIONS_COLLECTION } = await import("./delegation-
|
|
9942
|
+
const { issueDelegation, DELEGATIONS_COLLECTION } = await import("./delegation-QXZ4MPPH.js");
|
|
10275
9943
|
if (!this.keyring.kek) {
|
|
10276
9944
|
throw new ValidationError(
|
|
10277
|
-
"issueDelegation: keyring.kek is null \u2014 issuing a delegation requires a tier-1 unlock. Re-authenticate at tier 1 (
|
|
9945
|
+
"issueDelegation: keyring.kek is null \u2014 issuing a delegation requires a tier-1 unlock. Re-authenticate at tier 1 (secret) first."
|
|
10278
9946
|
);
|
|
10279
9947
|
}
|
|
10280
9948
|
const targetKek = this.keyring.kek;
|
|
@@ -10293,7 +9961,7 @@ var Vault = class {
|
|
|
10293
9961
|
* if the id does not exist.
|
|
10294
9962
|
*/
|
|
10295
9963
|
async revokeDelegation(id) {
|
|
10296
|
-
const { revokeDelegation, DELEGATIONS_COLLECTION } = await import("./delegation-
|
|
9964
|
+
const { revokeDelegation, DELEGATIONS_COLLECTION } = await import("./delegation-QXZ4MPPH.js");
|
|
10297
9965
|
await revokeDelegation(this.adapter, this.name, id);
|
|
10298
9966
|
void DELEGATIONS_COLLECTION;
|
|
10299
9967
|
}
|
|
@@ -10541,7 +10209,7 @@ var Vault = class {
|
|
|
10541
10209
|
* @see docs/superpowers/specs/2026-05-22-schema-dump-design.md
|
|
10542
10210
|
*/
|
|
10543
10211
|
async dumpSchema(opts = {}) {
|
|
10544
|
-
const { dumpVaultSchema } = await import("./walk-
|
|
10212
|
+
const { dumpVaultSchema } = await import("./walk-P5D6CF4V.js");
|
|
10545
10213
|
return dumpVaultSchema(this, opts);
|
|
10546
10214
|
}
|
|
10547
10215
|
/**
|
|
@@ -10676,13 +10344,9 @@ var Vault = class {
|
|
|
10676
10344
|
* @see https://github.com/vLannaAi/noy-db-docs/blob/main/content/docs/services/public-envelope.md
|
|
10677
10345
|
*/
|
|
10678
10346
|
async getCover(opts = {}) {
|
|
10679
|
-
const { readCover } = await import("./cover
|
|
10347
|
+
const { readCover } = await import("./cover/index.js");
|
|
10680
10348
|
return readCover(this.adapter, this.name, opts);
|
|
10681
10349
|
}
|
|
10682
|
-
/** @deprecated Use {@link Vault.getCover} (#799 rename). */
|
|
10683
|
-
async getPublicEnvelope(opts = {}) {
|
|
10684
|
-
return this.getCover(opts);
|
|
10685
|
-
}
|
|
10686
10350
|
/**
|
|
10687
10351
|
* Dump vault as a verifiable encrypted JSON backup string.
|
|
10688
10352
|
*
|
|
@@ -10695,7 +10359,7 @@ var Vault = class {
|
|
|
10695
10359
|
* both modes round-trip cleanly.
|
|
10696
10360
|
*/
|
|
10697
10361
|
async dump() {
|
|
10698
|
-
const { dumpVault } = await import("./backup-
|
|
10362
|
+
const { dumpVault } = await import("./backup-2UX7PRM5.js");
|
|
10699
10363
|
return dumpVault(this.backupContext());
|
|
10700
10364
|
}
|
|
10701
10365
|
/**
|
|
@@ -10710,7 +10374,7 @@ var Vault = class {
|
|
|
10710
10374
|
vault: this.name,
|
|
10711
10375
|
userId: () => this.keyring.userId,
|
|
10712
10376
|
getLedgerOrNull: () => this.getLedgerOrNull(),
|
|
10713
|
-
envelopePayloadHash: (envelope) => this.
|
|
10377
|
+
envelopePayloadHash: (envelope) => this.strategies.history.envelopePayloadHash(envelope),
|
|
10714
10378
|
reloadKeyringAndRebuildDEK: async () => {
|
|
10715
10379
|
if (this.reloadKeyring) {
|
|
10716
10380
|
this.keyring = await this.reloadKeyring();
|
|
@@ -10747,7 +10411,7 @@ var Vault = class {
|
|
|
10747
10411
|
* — there's no chain to verify against.
|
|
10748
10412
|
*/
|
|
10749
10413
|
async load(backupJson) {
|
|
10750
|
-
const { loadVault } = await import("./backup-
|
|
10414
|
+
const { loadVault } = await import("./backup-2UX7PRM5.js");
|
|
10751
10415
|
return loadVault(this.backupContext(), backupJson);
|
|
10752
10416
|
}
|
|
10753
10417
|
/**
|
|
@@ -10779,7 +10443,7 @@ var Vault = class {
|
|
|
10779
10443
|
* way to detect tampering of an in-place vault.
|
|
10780
10444
|
*/
|
|
10781
10445
|
async verifyBackupIntegrity() {
|
|
10782
|
-
const { verifyBackupIntegrity } = await import("./backup-
|
|
10446
|
+
const { verifyBackupIntegrity } = await import("./backup-2UX7PRM5.js");
|
|
10783
10447
|
return verifyBackupIntegrity(this.backupContext());
|
|
10784
10448
|
}
|
|
10785
10449
|
/**
|
|
@@ -10997,7 +10661,7 @@ var Vault = class {
|
|
|
10997
10661
|
* is the live validator object, not a serialization of it).
|
|
10998
10662
|
*/
|
|
10999
10663
|
async exportJSON(opts = {}) {
|
|
11000
|
-
const { exportVaultJSON } = await import("./backup-
|
|
10664
|
+
const { exportVaultJSON } = await import("./backup-2UX7PRM5.js");
|
|
11001
10665
|
return exportVaultJSON(this.backupContext(), opts);
|
|
11002
10666
|
}
|
|
11003
10667
|
};
|
|
@@ -11074,10 +10738,10 @@ var WriteQueueTracker = class {
|
|
|
11074
10738
|
* (success or failure). The fn's resolved value is returned; a thrown
|
|
11075
10739
|
* error is re-thrown after the queue is decremented.
|
|
11076
10740
|
*/
|
|
11077
|
-
async track(
|
|
10741
|
+
async track(fn) {
|
|
11078
10742
|
this.begin();
|
|
11079
10743
|
try {
|
|
11080
|
-
const value = await
|
|
10744
|
+
const value = await fn();
|
|
11081
10745
|
this.settle();
|
|
11082
10746
|
return value;
|
|
11083
10747
|
} catch (error) {
|
|
@@ -11100,7 +10764,184 @@ var WriteQueueTracker = class {
|
|
|
11100
10764
|
}
|
|
11101
10765
|
};
|
|
11102
10766
|
|
|
11103
|
-
// src/with
|
|
10767
|
+
// src/port/with/write-hooks.ts
|
|
10768
|
+
var WriteHookRegistry = class {
|
|
10769
|
+
#before = [];
|
|
10770
|
+
#after = [];
|
|
10771
|
+
#suppressed = false;
|
|
10772
|
+
/** True while handlers are running — used by the write path to skip nested firing. */
|
|
10773
|
+
get suppressed() {
|
|
10774
|
+
return this.#suppressed;
|
|
10775
|
+
}
|
|
10776
|
+
/** True when any hook is registered (cheap gate for the write path). */
|
|
10777
|
+
get hasHandlers() {
|
|
10778
|
+
return this.#before.length > 0 || this.#after.length > 0;
|
|
10779
|
+
}
|
|
10780
|
+
onBeforeWrite(handler) {
|
|
10781
|
+
this.#before.push(handler);
|
|
10782
|
+
return () => {
|
|
10783
|
+
const i = this.#before.indexOf(handler);
|
|
10784
|
+
if (i >= 0) this.#before.splice(i, 1);
|
|
10785
|
+
};
|
|
10786
|
+
}
|
|
10787
|
+
onAfterWrite(handler) {
|
|
10788
|
+
this.#after.push(handler);
|
|
10789
|
+
return () => {
|
|
10790
|
+
const i = this.#after.indexOf(handler);
|
|
10791
|
+
if (i >= 0) this.#after.splice(i, 1);
|
|
10792
|
+
};
|
|
10793
|
+
}
|
|
10794
|
+
/** Run before-hooks (awaited, in order). A throw propagates and aborts the write. */
|
|
10795
|
+
async runBefore(event) {
|
|
10796
|
+
if (this.#before.length === 0) return;
|
|
10797
|
+
this.#suppressed = true;
|
|
10798
|
+
try {
|
|
10799
|
+
for (const h of this.#before.slice()) await h(event);
|
|
10800
|
+
} finally {
|
|
10801
|
+
this.#suppressed = false;
|
|
10802
|
+
}
|
|
10803
|
+
}
|
|
10804
|
+
/** Run after-hooks (awaited, in order). Per-handler errors are warned, not thrown. */
|
|
10805
|
+
async runAfter(event) {
|
|
10806
|
+
if (this.#after.length === 0) return;
|
|
10807
|
+
this.#suppressed = true;
|
|
10808
|
+
try {
|
|
10809
|
+
for (const h of this.#after.slice()) {
|
|
10810
|
+
try {
|
|
10811
|
+
await h(event);
|
|
10812
|
+
} catch (err) {
|
|
10813
|
+
console.warn(
|
|
10814
|
+
`[noy-db] onAfterWrite handler failed for ${event.collection}/${event.docId}: ` + (err instanceof Error ? err.message : String(err))
|
|
10815
|
+
);
|
|
10816
|
+
}
|
|
10817
|
+
}
|
|
10818
|
+
} finally {
|
|
10819
|
+
this.#suppressed = false;
|
|
10820
|
+
}
|
|
10821
|
+
}
|
|
10822
|
+
};
|
|
10823
|
+
|
|
10824
|
+
// src/port/with/service-bus.ts
|
|
10825
|
+
var ServiceBus = class {
|
|
10826
|
+
#handlers = /* @__PURE__ */ new Map();
|
|
10827
|
+
#gateHandlers = /* @__PURE__ */ new Map();
|
|
10828
|
+
#depth = 0;
|
|
10829
|
+
/** Register a handler for an observe point. Returns an unsubscribe fn. */
|
|
10830
|
+
register(point, handler) {
|
|
10831
|
+
let arr = this.#handlers.get(point);
|
|
10832
|
+
if (!arr) {
|
|
10833
|
+
arr = [];
|
|
10834
|
+
this.#handlers.set(point, arr);
|
|
10835
|
+
}
|
|
10836
|
+
arr.push(handler);
|
|
10837
|
+
return () => {
|
|
10838
|
+
const a = this.#handlers.get(point);
|
|
10839
|
+
if (!a) return;
|
|
10840
|
+
const i = a.indexOf(handler);
|
|
10841
|
+
if (i >= 0) a.splice(i, 1);
|
|
10842
|
+
};
|
|
10843
|
+
}
|
|
10844
|
+
/** Cheap gate for the write path — true when any handler is registered for the point. */
|
|
10845
|
+
hasHandlers(point) {
|
|
10846
|
+
const a = this.#handlers.get(point);
|
|
10847
|
+
return a !== void 0 && a.length > 0;
|
|
10848
|
+
}
|
|
10849
|
+
/**
|
|
10850
|
+
* True while one or more dispatches are in flight. Backed by a depth counter
|
|
10851
|
+
* so that two concurrent async dispatches (`Promise.all([put('a'), put('b')])`
|
|
10852
|
+
* each captured `busAfterPut=true` at their respective put() tops while depth
|
|
10853
|
+
* was 0) both proceed independently — the counter stays > 0 until BOTH finish,
|
|
10854
|
+
* so any nested write attempted by a handler still sees `dispatching === true`
|
|
10855
|
+
* and is suppressed by the write-path gate in `collection.ts`
|
|
10856
|
+
* (`busAfterPut = hasHandlers('afterPut') && !dispatching`). Re-entrancy
|
|
10857
|
+
* suppression lives exclusively on that write-path gate; concurrent independent
|
|
10858
|
+
* dispatches must not drop each other's events.
|
|
10859
|
+
*/
|
|
10860
|
+
get dispatching() {
|
|
10861
|
+
return this.#depth > 0;
|
|
10862
|
+
}
|
|
10863
|
+
/**
|
|
10864
|
+
* Dispatch in registration order, awaited. Per-handler errors are warned, not
|
|
10865
|
+
* thrown — an observe handler must never abort a completed write. A
|
|
10866
|
+
* re-entrancy guard suppresses nested firing so a handler that itself writes
|
|
10867
|
+
* cannot loop (same rationale as WriteHookRegistry.#suppressed).
|
|
10868
|
+
*/
|
|
10869
|
+
async dispatch(point, event) {
|
|
10870
|
+
const a = this.#handlers.get(point);
|
|
10871
|
+
if (!a || a.length === 0) return;
|
|
10872
|
+
this.#depth++;
|
|
10873
|
+
try {
|
|
10874
|
+
for (const h of a.slice()) {
|
|
10875
|
+
try {
|
|
10876
|
+
await h(event);
|
|
10877
|
+
} catch (err) {
|
|
10878
|
+
console.warn(
|
|
10879
|
+
`[noy-db] service observe handler failed at ${point}: ` + (err instanceof Error ? err.message : String(err))
|
|
10880
|
+
);
|
|
10881
|
+
}
|
|
10882
|
+
}
|
|
10883
|
+
} finally {
|
|
10884
|
+
this.#depth--;
|
|
10885
|
+
}
|
|
10886
|
+
}
|
|
10887
|
+
/**
|
|
10888
|
+
* Register a write-gating handler. A throw from the handler ABORTS the
|
|
10889
|
+
* write. Returns an unsubscribe fn. See {@link GateRegisterOptions} for
|
|
10890
|
+
* the `needsPrior` prior-read declaration (#267).
|
|
10891
|
+
*/
|
|
10892
|
+
registerGate(point, handler, opts) {
|
|
10893
|
+
let arr = this.#gateHandlers.get(point);
|
|
10894
|
+
if (!arr) {
|
|
10895
|
+
arr = [];
|
|
10896
|
+
this.#gateHandlers.set(point, arr);
|
|
10897
|
+
}
|
|
10898
|
+
const entry = { fn: handler, needsPrior: opts?.needsPrior !== false };
|
|
10899
|
+
arr.push(entry);
|
|
10900
|
+
return () => {
|
|
10901
|
+
const a = this.#gateHandlers.get(point);
|
|
10902
|
+
if (!a) return;
|
|
10903
|
+
const i = a.indexOf(entry);
|
|
10904
|
+
if (i >= 0) a.splice(i, 1);
|
|
10905
|
+
};
|
|
10906
|
+
}
|
|
10907
|
+
/** Cheap gate for the write path — true when any gate handler is registered for the point. */
|
|
10908
|
+
hasGateHandlers(point) {
|
|
10909
|
+
const a = this.#gateHandlers.get(point);
|
|
10910
|
+
return a !== void 0 && a.length > 0;
|
|
10911
|
+
}
|
|
10912
|
+
/**
|
|
10913
|
+
* True when at least one gate handler at `point` needs the prior record
|
|
10914
|
+
* (the default). False when the point has no handlers or every handler
|
|
10915
|
+
* registered with `needsPrior: false` — the write path then skips the
|
|
10916
|
+
* prior-read before dispatching (#267 prior-read elision).
|
|
10917
|
+
*/
|
|
10918
|
+
gateNeedsPrior(point) {
|
|
10919
|
+
const a = this.#gateHandlers.get(point);
|
|
10920
|
+
if (!a) return false;
|
|
10921
|
+
return a.some((e) => e.needsPrior);
|
|
10922
|
+
}
|
|
10923
|
+
/**
|
|
10924
|
+
* Run gate handlers in registration order, awaited. Unlike `dispatch`
|
|
10925
|
+
* (observe), a handler throw is NOT swallowed — it PROPAGATES, aborting the
|
|
10926
|
+
* write before it reaches the store. The first throw stops the remaining
|
|
10927
|
+
* handlers (fail-fast). This is the seam guards/periods migrate onto.
|
|
10928
|
+
*
|
|
10929
|
+
* Note: gate handlers are validators that read, not write. A gate handler
|
|
10930
|
+
* that writes back into the same collection would re-enter the write path
|
|
10931
|
+
* and re-dispatch this point; loop-suppression for that case is deferred to
|
|
10932
|
+
* the migration slice (contract: gate handlers must not perform writes that
|
|
10933
|
+
* re-trigger their own point).
|
|
10934
|
+
*/
|
|
10935
|
+
async dispatchGate(point, event) {
|
|
10936
|
+
const a = this.#gateHandlers.get(point);
|
|
10937
|
+
if (!a || a.length === 0) return;
|
|
10938
|
+
for (const e of a.slice()) {
|
|
10939
|
+
await e.fn(event);
|
|
10940
|
+
}
|
|
10941
|
+
}
|
|
10942
|
+
};
|
|
10943
|
+
|
|
10944
|
+
// src/with-sync/tab-coordination.ts
|
|
11104
10945
|
var TabCoordinator = class {
|
|
11105
10946
|
tabId;
|
|
11106
10947
|
role = "unknown";
|
|
@@ -11162,13 +11003,13 @@ var TabCoordinator = class {
|
|
|
11162
11003
|
const out = [self, ...[...this.#peers.values()].filter((p) => p.lastSeen >= cutoff)];
|
|
11163
11004
|
return out.sort((a, b) => a.tabId.localeCompare(b.tabId));
|
|
11164
11005
|
}
|
|
11165
|
-
onTabRoleChange(
|
|
11166
|
-
this.#roleHandlers.add(
|
|
11167
|
-
return () => this.#roleHandlers.delete(
|
|
11006
|
+
onTabRoleChange(fn) {
|
|
11007
|
+
this.#roleHandlers.add(fn);
|
|
11008
|
+
return () => this.#roleHandlers.delete(fn);
|
|
11168
11009
|
}
|
|
11169
|
-
onActiveTabsChange(
|
|
11170
|
-
this.#tabsHandlers.add(
|
|
11171
|
-
return () => this.#tabsHandlers.delete(
|
|
11010
|
+
onActiveTabsChange(fn) {
|
|
11011
|
+
this.#tabsHandlers.add(fn);
|
|
11012
|
+
return () => this.#tabsHandlers.delete(fn);
|
|
11172
11013
|
}
|
|
11173
11014
|
dispose() {
|
|
11174
11015
|
if (this.#disposed) return;
|
|
@@ -11281,7 +11122,7 @@ function defaultChannel(name = "noydb:tabs") {
|
|
|
11281
11122
|
};
|
|
11282
11123
|
}
|
|
11283
11124
|
|
|
11284
|
-
// src/with-
|
|
11125
|
+
// src/with-sync/tab-write-relay.ts
|
|
11285
11126
|
var CrossTabWriteRelay = class {
|
|
11286
11127
|
#channel;
|
|
11287
11128
|
#writerId;
|
|
@@ -11395,25 +11236,6 @@ var QuickUnlockStore = class {
|
|
|
11395
11236
|
}
|
|
11396
11237
|
};
|
|
11397
11238
|
|
|
11398
|
-
// src/with-fork/snapshots/strategy.ts
|
|
11399
|
-
var NOT_ENABLED4 = new Error(
|
|
11400
|
-
'Snapshots require the snapshot strategy. Import `{ withSnapshots }` from "@noy-db/hub/snapshots" and pass it to `createNoydb({ snapshotStrategy: withSnapshots({ store }) })`.'
|
|
11401
|
-
);
|
|
11402
|
-
var NO_SNAPSHOTS = {
|
|
11403
|
-
async snapshot() {
|
|
11404
|
-
throw NOT_ENABLED4;
|
|
11405
|
-
},
|
|
11406
|
-
async listSnapshots() {
|
|
11407
|
-
throw NOT_ENABLED4;
|
|
11408
|
-
},
|
|
11409
|
-
async restoreSnapshot() {
|
|
11410
|
-
throw NOT_ENABLED4;
|
|
11411
|
-
},
|
|
11412
|
-
async autoSnapshot() {
|
|
11413
|
-
throw NOT_ENABLED4;
|
|
11414
|
-
}
|
|
11415
|
-
};
|
|
11416
|
-
|
|
11417
11239
|
// src/with-fork/snapshots/scheduler.ts
|
|
11418
11240
|
var SnapshotScheduler = class {
|
|
11419
11241
|
policy;
|
|
@@ -11535,7 +11357,7 @@ var NoydbSnapshots = class {
|
|
|
11535
11357
|
dirtyVaults = /* @__PURE__ */ new Set();
|
|
11536
11358
|
/**
|
|
11537
11359
|
* Take an on-demand checkpoint of the given vault.
|
|
11538
|
-
* Requires `
|
|
11360
|
+
* Requires `snapshotsStrategy: withSnapshots({ store })` in `createNoydb`.
|
|
11539
11361
|
* @throws ValidationError when the vault is not open
|
|
11540
11362
|
*/
|
|
11541
11363
|
async snapshot(vault, opts) {
|
|
@@ -11614,19 +11436,6 @@ var NoydbSnapshots = class {
|
|
|
11614
11436
|
}
|
|
11615
11437
|
};
|
|
11616
11438
|
|
|
11617
|
-
// src/with-commit/tx/strategy.ts
|
|
11618
|
-
var NOT_ENABLED5 = new Error(
|
|
11619
|
-
'Multi-record transactions require the tx strategy. Import `{ withTransactions }` from "@noy-db/hub/tx" and pass it to `createNoydb({ txStrategy: withTransactions() })`.'
|
|
11620
|
-
);
|
|
11621
|
-
var NO_TX = {
|
|
11622
|
-
async runTransaction(_db, _fn, _options, _txInvariants) {
|
|
11623
|
-
throw NOT_ENABLED5;
|
|
11624
|
-
},
|
|
11625
|
-
async runDryRun() {
|
|
11626
|
-
throw NOT_ENABLED5;
|
|
11627
|
-
}
|
|
11628
|
-
};
|
|
11629
|
-
|
|
11630
11439
|
// src/kernel/memory-store.ts
|
|
11631
11440
|
function memoryStore() {
|
|
11632
11441
|
const store = /* @__PURE__ */ new Map();
|
|
@@ -11710,146 +11519,6 @@ function memoryStore() {
|
|
|
11710
11519
|
};
|
|
11711
11520
|
}
|
|
11712
11521
|
|
|
11713
|
-
// src/with-party/session/strategy.ts
|
|
11714
|
-
function notEnabled3(op) {
|
|
11715
|
-
return new Error(
|
|
11716
|
-
`${op} requires the session strategy. Import \`{ withSession }\` from "@noy-db/hub/session" and pass it to \`createNoydb({ sessionStrategy: withSession() })\`.`
|
|
11717
|
-
);
|
|
11718
|
-
}
|
|
11719
|
-
var NO_SESSION = {
|
|
11720
|
-
validateSessionPolicy() {
|
|
11721
|
-
throw notEnabled3("sessionPolicy");
|
|
11722
|
-
},
|
|
11723
|
-
createEnforcer() {
|
|
11724
|
-
throw notEnabled3("session policy enforcement");
|
|
11725
|
-
},
|
|
11726
|
-
revokeAllSessions() {
|
|
11727
|
-
}
|
|
11728
|
-
};
|
|
11729
|
-
|
|
11730
|
-
// src/with-party/auth-introspection/index.ts
|
|
11731
|
-
async function describeAuthConfig(store, vault) {
|
|
11732
|
-
const policy = await loadVaultPolicy(store, vault) ?? defaultPolicySnapshot();
|
|
11733
|
-
const recoveryProfiles = await listRecoveryProfilesEnrolled(store, vault);
|
|
11734
|
-
const lines = [];
|
|
11735
|
-
lines.push(`Vault "${vault}" \u2014 three-tier authentication`);
|
|
11736
|
-
lines.push("");
|
|
11737
|
-
lines.push("Tier 1 \u2014 Passphrase (master)");
|
|
11738
|
-
lines.push(` Phrase format: ${policy.passphrase?.minWords ?? 6}+ words, lowercase letters, \u2265${policy.passphrase?.minWordLength ?? 3} chars/word`);
|
|
11739
|
-
lines.push(" Strength validator: enforced (override available for tests only)");
|
|
11740
|
-
lines.push("");
|
|
11741
|
-
lines.push("Tier 2 \u2014 Authenticate (routine login)");
|
|
11742
|
-
lines.push(" Allowed methods: WebAuthn (passkey), OIDC, Password");
|
|
11743
|
-
lines.push(" Slots per user: unlimited");
|
|
11744
|
-
lines.push("");
|
|
11745
|
-
lines.push("Tier 3 \u2014 Unlock (quick resume)");
|
|
11746
|
-
lines.push(" Method: PIN (per-app configurable)");
|
|
11747
|
-
lines.push("");
|
|
11748
|
-
lines.push(`Recovery profiles enrolled: ${recoveryProfiles.length === 0 ? "none" : recoveryProfiles.join(", ")}`);
|
|
11749
|
-
lines.push("Managed-passphrase mode: off (post-1.0)");
|
|
11750
|
-
lines.push("");
|
|
11751
|
-
lines.push("Sensitive-action gates:");
|
|
11752
|
-
for (const [gate, gp] of Object.entries(policy.gates)) {
|
|
11753
|
-
lines.push(` ${gate} \u2014 ${describeGatePolicy(gp)}`);
|
|
11754
|
-
}
|
|
11755
|
-
return lines.join("\n");
|
|
11756
|
-
}
|
|
11757
|
-
async function diagramAuthConfig(store, vault) {
|
|
11758
|
-
const policy = await loadVaultPolicy(store, vault) ?? defaultPolicySnapshot();
|
|
11759
|
-
const lines = [];
|
|
11760
|
-
lines.push("flowchart TB");
|
|
11761
|
-
lines.push(` vault["Vault: ${escapeMermaid(vault)}"]`);
|
|
11762
|
-
lines.push(' tier1["Tier 1<br/>Passphrase"]');
|
|
11763
|
-
lines.push(' tier2["Tier 2<br/>Multi-slot Authenticate"]');
|
|
11764
|
-
lines.push(' tier3["Tier 3<br/>PIN / Quick-resume"]');
|
|
11765
|
-
lines.push(" vault --> tier1");
|
|
11766
|
-
lines.push(" tier1 --> tier2");
|
|
11767
|
-
lines.push(" tier2 --> tier3");
|
|
11768
|
-
for (const [gateName, gp] of Object.entries(policy.gates)) {
|
|
11769
|
-
if (gp.enabled === false) continue;
|
|
11770
|
-
const id = sanitizeId(gateName);
|
|
11771
|
-
const label = `${gateName}<br/>tier \u2265 ${gp.minTier}`;
|
|
11772
|
-
lines.push(` ${id}["${escapeMermaid(label)}"]`);
|
|
11773
|
-
const tierNode = gp.minTier === 1 ? "tier1" : gp.minTier === 2 ? "tier2" : "tier3";
|
|
11774
|
-
lines.push(` ${tierNode} --> ${id}`);
|
|
11775
|
-
}
|
|
11776
|
-
return lines.join("\n");
|
|
11777
|
-
}
|
|
11778
|
-
async function describeUserAuth(store, vault, userId) {
|
|
11779
|
-
const env = await store.get(vault, "_keyring", userId);
|
|
11780
|
-
if (!env) return "";
|
|
11781
|
-
const file = JSON.parse(env._data);
|
|
11782
|
-
const lines = [];
|
|
11783
|
-
lines.push(
|
|
11784
|
-
`User: ${file.user_id} (joined ${file.created_at.slice(0, 10)}, role: ${file.role})`
|
|
11785
|
-
);
|
|
11786
|
-
lines.push("");
|
|
11787
|
-
lines.push("Tier 2 enrollments:");
|
|
11788
|
-
if (!file.authenticators || file.authenticators.length === 0) {
|
|
11789
|
-
lines.push(" (none enrolled)");
|
|
11790
|
-
} else {
|
|
11791
|
-
for (const slot of file.authenticators) {
|
|
11792
|
-
lines.push(` - ${describeSlot(slot)}`);
|
|
11793
|
-
}
|
|
11794
|
-
}
|
|
11795
|
-
return lines.join("\n");
|
|
11796
|
-
}
|
|
11797
|
-
async function describeAllUsersAuth(store, vault) {
|
|
11798
|
-
const ids = await store.list(vault, "_keyring");
|
|
11799
|
-
const results = [];
|
|
11800
|
-
for (const userId of ids) {
|
|
11801
|
-
const description = await describeUserAuth(store, vault, userId);
|
|
11802
|
-
if (description !== "") results.push({ userId, description });
|
|
11803
|
-
}
|
|
11804
|
-
return results;
|
|
11805
|
-
}
|
|
11806
|
-
var SLOT_FIELD_ALLOWLIST = [
|
|
11807
|
-
"id",
|
|
11808
|
-
"method",
|
|
11809
|
-
"enrolled_at",
|
|
11810
|
-
"enrolled_via_tier"
|
|
11811
|
-
];
|
|
11812
|
-
function describeSlot(slot) {
|
|
11813
|
-
const sanitized = {};
|
|
11814
|
-
for (const key of SLOT_FIELD_ALLOWLIST) {
|
|
11815
|
-
if (key in slot) {
|
|
11816
|
-
sanitized[key] = slot[key];
|
|
11817
|
-
}
|
|
11818
|
-
}
|
|
11819
|
-
const date = (sanitized.enrolled_at ?? "").slice(0, 10);
|
|
11820
|
-
return `${sanitized.method ?? "?"} (id=${sanitized.id ?? "?"}, enrolled ${date}, via tier ${sanitized.enrolled_via_tier ?? "?"})`;
|
|
11821
|
-
}
|
|
11822
|
-
function describeGatePolicy(gp) {
|
|
11823
|
-
if (gp.enabled === false) return "disabled";
|
|
11824
|
-
const parts = [];
|
|
11825
|
-
parts.push(`tier ${gp.minTier}`);
|
|
11826
|
-
if (gp.factors && gp.factors.length > 0) {
|
|
11827
|
-
for (const f of gp.factors) {
|
|
11828
|
-
parts.push(`+ ${f.count ?? 1}\xD7 ${f.anyOf.join("|")}`);
|
|
11829
|
-
}
|
|
11830
|
-
}
|
|
11831
|
-
if (gp.warn?.sharedDevice === "block") parts.push("block-on-shared-device");
|
|
11832
|
-
return parts.join(" ");
|
|
11833
|
-
}
|
|
11834
|
-
function defaultPolicySnapshot() {
|
|
11835
|
-
return {
|
|
11836
|
-
passphrase: { minWords: 6, minWordLength: 3, rejectRepeatedAdjacent: true },
|
|
11837
|
-
gates: {}
|
|
11838
|
-
};
|
|
11839
|
-
}
|
|
11840
|
-
async function listRecoveryProfilesEnrolled(store, vault) {
|
|
11841
|
-
const enrolled = [];
|
|
11842
|
-
const paper = await loadPaperRecoveryEntries(store, vault);
|
|
11843
|
-
if (paper.length > 0) enrolled.push(`paper (${paper.length} codes)`);
|
|
11844
|
-
return enrolled;
|
|
11845
|
-
}
|
|
11846
|
-
function escapeMermaid(s) {
|
|
11847
|
-
return s.replace(/"/g, '\\"').replace(/\n/g, " ");
|
|
11848
|
-
}
|
|
11849
|
-
function sanitizeId(s) {
|
|
11850
|
-
return s.replace(/[^a-zA-Z0-9]/g, "_");
|
|
11851
|
-
}
|
|
11852
|
-
|
|
11853
11522
|
// src/with-party/team/noydb-facade.ts
|
|
11854
11523
|
var TeamFacade = class {
|
|
11855
11524
|
constructor(deps) {
|
|
@@ -11891,8 +11560,9 @@ var TeamFacade = class {
|
|
|
11891
11560
|
async runRotate(engine, vault, collections) {
|
|
11892
11561
|
this.deps.checkPolicyOperation(vault, "rotate");
|
|
11893
11562
|
const keyring = await this.deps.getKeyringInternal(vault);
|
|
11894
|
-
await engine(this.deps.options.store, vault, keyring, collections);
|
|
11563
|
+
const result = await engine(this.deps.options.store, vault, keyring, { collections });
|
|
11895
11564
|
this.deps.keyringCache.set(vault, keyring);
|
|
11565
|
+
return result;
|
|
11896
11566
|
}
|
|
11897
11567
|
// ─── Tier-2 enroll / remove ─────────────────────────────────────
|
|
11898
11568
|
/**
|
|
@@ -11983,7 +11653,7 @@ var TeamFacade = class {
|
|
|
11983
11653
|
* ```ts
|
|
11984
11654
|
* import { enrollWebAuthn } from '@noy-db/on-webauthn'
|
|
11985
11655
|
*
|
|
11986
|
-
* await db.enrollWebAuthn('demo', async (keyring) => {
|
|
11656
|
+
* await db.team.enrollWebAuthn('demo', async (keyring) => {
|
|
11987
11657
|
* const e = await enrollWebAuthn(keyring, 'demo', { rp: {...} })
|
|
11988
11658
|
* return {
|
|
11989
11659
|
* id: `webauthn-${e.credentialId.slice(0, 8)}`,
|
|
@@ -12012,7 +11682,7 @@ var TeamFacade = class {
|
|
|
12012
11682
|
const slotOptions = await ceremony(keyring);
|
|
12013
11683
|
if (slotOptions.method !== "webauthn") {
|
|
12014
11684
|
throw new ValidationError(
|
|
12015
|
-
`enrollWebAuthn: ceremony returned method "${slotOptions.method}"; expected "webauthn". Use db.enrollAuthenticator() for non-webauthn methods.`
|
|
11685
|
+
`enrollWebAuthn: ceremony returned method "${slotOptions.method}"; expected "webauthn". Use db.team.enrollAuthenticator() for non-webauthn methods.`
|
|
12016
11686
|
);
|
|
12017
11687
|
}
|
|
12018
11688
|
const credentialId = slotOptions.meta.credentialId;
|
|
@@ -12090,44 +11760,44 @@ var TeamFacade = class {
|
|
|
12090
11760
|
}
|
|
12091
11761
|
// ─── Tier-1 change flows ────────────────────────────────────────
|
|
12092
11762
|
/**
|
|
12093
|
-
* Rotate the user's
|
|
12094
|
-
* new phrase against the configured `
|
|
12095
|
-
* `rotate-
|
|
11763
|
+
* Rotate the user's secret (user remembers old). Validates the
|
|
11764
|
+
* new phrase against the configured `secret` policy, runs the
|
|
11765
|
+
* `rotate-secret` gate, then re-derives + re-wraps every DEK.
|
|
12096
11766
|
*
|
|
12097
11767
|
* Tier-2 authenticator slots are dropped — each slot wraps the old
|
|
12098
11768
|
* KEK and would need its derivation key to be re-presented. Re-enrol
|
|
12099
11769
|
* via `db.enrollAuthenticator` after rotation.
|
|
12100
11770
|
*
|
|
12101
|
-
* @throws `
|
|
11771
|
+
* @throws `WeakSecretError` on a weak new phrase.
|
|
12102
11772
|
* @throws `PolicyDeniedError` when the gate denies (missing factor, …).
|
|
12103
|
-
* @throws `InvalidKeyError` when `
|
|
11773
|
+
* @throws `InvalidKeyError` when `oldSecret` is wrong.
|
|
12104
11774
|
*/
|
|
12105
|
-
async
|
|
12106
|
-
if (this.deps.options.
|
|
11775
|
+
async rotateSecret(vault, input, factors) {
|
|
11776
|
+
if (this.deps.options.secretMode === "managed") {
|
|
12107
11777
|
throw new PolicyDeniedError(
|
|
12108
|
-
"rotate-
|
|
11778
|
+
"rotate-secret",
|
|
12109
11779
|
"disabled",
|
|
12110
11780
|
{ minTier: 1, enabled: false },
|
|
12111
|
-
"Managed-
|
|
11781
|
+
"Managed-secret mode (#14): the secret is hub-generated and sealed under the SealingKeyProvider \u2014 there is no plaintext to rotate. Use the recovery flow (follow-up issue) to mint a fresh sealed secret."
|
|
12112
11782
|
);
|
|
12113
11783
|
}
|
|
12114
|
-
await this.deps.checkGate(vault, "rotate-
|
|
11784
|
+
await this.deps.checkGate(vault, "rotate-secret", factors);
|
|
12115
11785
|
const userId = this.deps.options.user;
|
|
12116
|
-
const next = await
|
|
11786
|
+
const next = await rotateSecret(this.deps.options.store, vault, userId, input);
|
|
12117
11787
|
this.deps.keyringCache.set(vault, next);
|
|
12118
11788
|
}
|
|
12119
11789
|
/**
|
|
12120
|
-
* Reset the
|
|
11790
|
+
* Reset the secret using a recovery proof (user forgot the old).
|
|
12121
11791
|
* Currently supports the `'paper'` profile end-to-end; the
|
|
12122
11792
|
* other profiles throw {@link RecoveryProfileNotImplementedError}.
|
|
12123
11793
|
*
|
|
12124
11794
|
* Burns the used recovery entry on success.
|
|
12125
11795
|
*/
|
|
12126
|
-
async
|
|
12127
|
-
await this.deps.checkGate(vault, "recover-
|
|
11796
|
+
async recoverSecret(vault, input, factors) {
|
|
11797
|
+
await this.deps.checkGate(vault, "recover-secret", factors);
|
|
12128
11798
|
const userId = this.deps.options.user;
|
|
12129
11799
|
const entriesBeforeRecovery = await loadPaperRecoveryEntries(this.deps.options.store, vault);
|
|
12130
|
-
const next = await
|
|
11800
|
+
const next = await recoverSecret(this.deps.options.shamirRecovery, this.deps.options.store, vault, userId, input);
|
|
12131
11801
|
this.deps.keyringCache.set(vault, next);
|
|
12132
11802
|
const rotateRemaining = input.rotateRemainingCodes ?? true;
|
|
12133
11803
|
const remainingAfterBurn = Math.max(0, entriesBeforeRecovery.length - 1);
|
|
@@ -12149,15 +11819,15 @@ var TeamFacade = class {
|
|
|
12149
11819
|
}
|
|
12150
11820
|
/**
|
|
12151
11821
|
* Deliberate paper-recovery-code regeneration. User knows their
|
|
12152
|
-
*
|
|
11822
|
+
* secret but wants a fresh sheet — they lost the printout or
|
|
12153
11823
|
* suspect compromise of the off-site copy.
|
|
12154
11824
|
*
|
|
12155
|
-
* Symmetric to {@link
|
|
11825
|
+
* Symmetric to {@link rotateSecret} for the recovery profile:
|
|
12156
11826
|
* gated, audit-trackable, ergonomic. Replaces (not appends) the
|
|
12157
11827
|
* paper sheet under `_meta/recovery-paper` in a single envelope `put`.
|
|
12158
11828
|
*
|
|
12159
11829
|
* Gated by the `rotate-recovery` policy gate:
|
|
12160
|
-
* - PERSONAL_POLICY: `{ minTier: 1 }` — knowing the
|
|
11830
|
+
* - PERSONAL_POLICY: `{ minTier: 1 }` — knowing the secret
|
|
12161
11831
|
* suffices, matching the lower-level flow's bar.
|
|
12162
11832
|
* - STRICT_POLICY: `{ minTier: 1, factors: [{ anyOf: ['totp',
|
|
12163
11833
|
* 'email-otp', 'webauthn-roaming'] }] }` — rotation is an
|
|
@@ -12177,13 +11847,13 @@ var TeamFacade = class {
|
|
|
12177
11847
|
*
|
|
12178
11848
|
* @example Default count + show-once UI
|
|
12179
11849
|
* ```ts
|
|
12180
|
-
* const { newCodes } = await db.rotateRecovery('acme', { profile: 'paper' })
|
|
11850
|
+
* const { newCodes } = await db.team.rotateRecovery('acme', { profile: 'paper' })
|
|
12181
11851
|
* showCodesToUser(newCodes)
|
|
12182
11852
|
* ```
|
|
12183
11853
|
*
|
|
12184
11854
|
* @example STRICT-policy site with TOTP factor proof
|
|
12185
11855
|
* ```ts
|
|
12186
|
-
* await db.rotateRecovery(
|
|
11856
|
+
* await db.team.rotateRecovery(
|
|
12187
11857
|
* 'acme',
|
|
12188
11858
|
* { profile: 'paper', count: 10 },
|
|
12189
11859
|
* { factors: [{ kind: 'totp', proof: '123456' }] },
|
|
@@ -12207,7 +11877,7 @@ var TeamFacade = class {
|
|
|
12207
11877
|
const existing = await loadPaperRecoveryEntries(this.deps.options.store, vault);
|
|
12208
11878
|
if (existing.length === 0) {
|
|
12209
11879
|
throw new Error(
|
|
12210
|
-
`db.rotateRecovery: no recovery codes are enrolled for vault "${vault}". Call db.enrollRecovery({ profile: 'paper', entries }) first; rotateRecovery replaces an existing sheet rather than minting one from scratch.`
|
|
11880
|
+
`db.rotateRecovery: no recovery codes are enrolled for vault "${vault}". Call db.team.enrollRecovery({ profile: 'paper', entries }) first; rotateRecovery replaces an existing sheet rather than minting one from scratch.`
|
|
12211
11881
|
);
|
|
12212
11882
|
}
|
|
12213
11883
|
const keyring = await this.getKeyring(vault);
|
|
@@ -12229,7 +11899,7 @@ var TeamFacade = class {
|
|
|
12229
11899
|
const existing = await loadShamirRecoveryEntries(this.deps.options.store, vault);
|
|
12230
11900
|
if (existing.length === 0) {
|
|
12231
11901
|
throw new Error(
|
|
12232
|
-
`db.rotateRecovery: no Shamir recovery entry is enrolled for vault "${vault}". Call db.enrollRecovery({ profile: 'shamir', k, n }) first; rotateRecovery replaces an existing entry rather than minting one from scratch.`
|
|
11902
|
+
`db.rotateRecovery: no Shamir recovery entry is enrolled for vault "${vault}". Call db.team.enrollRecovery({ profile: 'shamir', k, n }) first; rotateRecovery replaces an existing entry rather than minting one from scratch.`
|
|
12233
11903
|
);
|
|
12234
11904
|
}
|
|
12235
11905
|
let targetEntryId;
|
|
@@ -12266,7 +11936,7 @@ var TeamFacade = class {
|
|
|
12266
11936
|
* **Atomic create-and-enroll for managed-mode vaults.**
|
|
12267
11937
|
*
|
|
12268
11938
|
* Bootstraps a managed-mode vault and enrolls strong recovery in
|
|
12269
|
-
* a single ceremony. Under `
|
|
11939
|
+
* a single ceremony. Under `secretMode: 'managed'`, every
|
|
12270
11940
|
* `openVault` call requires a strong recovery profile (Shamir
|
|
12271
11941
|
* today) to be enrolled — otherwise it throws
|
|
12272
11942
|
* {@link ManagedRecoveryNotEnrolledError}. This method bypasses
|
|
@@ -12285,11 +11955,11 @@ var TeamFacade = class {
|
|
|
12285
11955
|
* ```ts
|
|
12286
11956
|
* const db = await createNoydb({
|
|
12287
11957
|
* store, user: 'alice',
|
|
12288
|
-
*
|
|
11958
|
+
* secretMode: 'managed',
|
|
12289
11959
|
* sealingKey: macosKeychainSealingProvider({ ... }),
|
|
12290
11960
|
* })
|
|
12291
11961
|
*
|
|
12292
|
-
* const { vault, recoveryEnrollments } = await db.openVaultAndEnrollRecovery('acme', {
|
|
11962
|
+
* const { vault, recoveryEnrollments } = await db.team.openVaultAndEnrollRecovery('acme', {
|
|
12293
11963
|
* recovery: [{ profile: 'shamir', k: 2, n: 3 }],
|
|
12294
11964
|
* })
|
|
12295
11965
|
* for (const r of recoveryEnrollments) {
|
|
@@ -12306,11 +11976,11 @@ var TeamFacade = class {
|
|
|
12306
11976
|
"openVaultAndEnrollRecovery: at least one recovery enrollment is required."
|
|
12307
11977
|
);
|
|
12308
11978
|
}
|
|
12309
|
-
if (this.deps.options.
|
|
11979
|
+
if (this.deps.options.secretMode === "managed") {
|
|
12310
11980
|
const hasStrong = opts.recovery.some((r) => r.profile === "shamir");
|
|
12311
11981
|
if (!hasStrong) {
|
|
12312
11982
|
throw new ValidationError(
|
|
12313
|
-
'openVaultAndEnrollRecovery: managed-mode vaults require at least one strong recovery profile in the `recovery` array. Paper alone is not strong under managed mode (no user
|
|
11983
|
+
'openVaultAndEnrollRecovery: managed-mode vaults require at least one strong recovery profile in the `recovery` array. Paper alone is not strong under managed mode (no user secret to fall back on). Include { profile: "shamir", k, n } in `recovery`.'
|
|
12314
11984
|
);
|
|
12315
11985
|
}
|
|
12316
11986
|
}
|
|
@@ -12325,7 +11995,7 @@ var TeamFacade = class {
|
|
|
12325
11995
|
for (const enrollment of opts.recovery) {
|
|
12326
11996
|
recoveryEnrollments.push(await this.enrollRecovery(vault, enrollment));
|
|
12327
11997
|
}
|
|
12328
|
-
if (this.deps.options.
|
|
11998
|
+
if (this.deps.options.secretMode === "managed") {
|
|
12329
11999
|
const policy = this.deps.policyCache.get(vault);
|
|
12330
12000
|
if (policy) {
|
|
12331
12001
|
await this.deps.assertRecoveryEnrolled(vault, policy);
|
|
@@ -12334,20 +12004,20 @@ var TeamFacade = class {
|
|
|
12334
12004
|
return { vault: vaultHandle, recoveryEnrollments };
|
|
12335
12005
|
}
|
|
12336
12006
|
/**
|
|
12337
|
-
* **Recovery flow under managed-
|
|
12007
|
+
* **Recovery flow under managed-secret mode.**
|
|
12338
12008
|
*
|
|
12339
|
-
* Replaces the sealed
|
|
12009
|
+
* Replaces the sealed secret of a managed-mode vault with a
|
|
12340
12010
|
* fresh 256-bit random, sealed under the configured
|
|
12341
|
-
* `SealingKeyProvider`. The user never sees the new
|
|
12011
|
+
* `SealingKeyProvider`. The user never sees the new secret.
|
|
12342
12012
|
*
|
|
12343
12013
|
* Internally:
|
|
12344
12014
|
* 1. Verify the recovery proof (Shamir today) and unwrap the
|
|
12345
12015
|
* DEK set.
|
|
12346
|
-
* 2. Mint a fresh 256-bit random as the new effective
|
|
12016
|
+
* 2. Mint a fresh 256-bit random as the new effective secret.
|
|
12347
12017
|
* 3. Rewrap the DEK set under a fresh KEK derived from the new
|
|
12348
|
-
*
|
|
12018
|
+
* secret (via the existing `recoverSecret` path).
|
|
12349
12019
|
* 4. Seal the random bytes under the provider and overwrite
|
|
12350
|
-
* `_meta/sealed-
|
|
12020
|
+
* `_meta/sealed-secret`.
|
|
12351
12021
|
* 5. Drop the keyring cache so the next operation re-derives.
|
|
12352
12022
|
*
|
|
12353
12023
|
* The vault's strong-recovery enrollment is preserved across
|
|
@@ -12355,40 +12025,40 @@ var TeamFacade = class {
|
|
|
12355
12025
|
*
|
|
12356
12026
|
* @throws ValidationError if the Noydb instance is not in managed mode.
|
|
12357
12027
|
*/
|
|
12358
|
-
async
|
|
12359
|
-
if (this.deps.options.
|
|
12028
|
+
async recoverManagedSecret(vault, options) {
|
|
12029
|
+
if (this.deps.options.secretMode !== "managed") {
|
|
12360
12030
|
throw new ValidationError(
|
|
12361
|
-
"
|
|
12031
|
+
"recoverManagedSecret: this method only applies to vaults opened in managed-secret mode. For standard mode, use db.recoverSecret."
|
|
12362
12032
|
);
|
|
12363
12033
|
}
|
|
12364
12034
|
const provider = this.deps.options.sealingKey;
|
|
12365
12035
|
if (!provider) {
|
|
12366
12036
|
throw new ValidationError(
|
|
12367
|
-
'
|
|
12037
|
+
'recoverManagedSecret: createNoydb({ secretMode: "managed" }) requires `sealingKey` to be supplied; without it the new sealed secret cannot be persisted.'
|
|
12368
12038
|
);
|
|
12369
12039
|
}
|
|
12370
12040
|
const randomBytes = new Uint8Array(32);
|
|
12371
12041
|
globalThis.crypto.getRandomValues(randomBytes);
|
|
12372
12042
|
let binary = "";
|
|
12373
12043
|
for (let i = 0; i < randomBytes.length; i++) binary += String.fromCharCode(randomBytes[i]);
|
|
12374
|
-
const
|
|
12044
|
+
const newSecret = btoa(binary);
|
|
12375
12045
|
try {
|
|
12376
12046
|
const sealed = await provider.seal(randomBytes);
|
|
12377
|
-
await
|
|
12047
|
+
await recoverSecret(
|
|
12378
12048
|
this.deps.options.shamirRecovery,
|
|
12379
12049
|
this.deps.options.store,
|
|
12380
12050
|
vault,
|
|
12381
12051
|
this.deps.options.user,
|
|
12382
12052
|
{
|
|
12383
|
-
|
|
12053
|
+
newSecret,
|
|
12384
12054
|
recoveryProof: options.recoveryProof,
|
|
12385
|
-
// The new
|
|
12055
|
+
// The new secret IS 256 bits of random; policy gates on
|
|
12386
12056
|
// length/entropy don't apply.
|
|
12387
|
-
|
|
12388
|
-
...options.
|
|
12057
|
+
allowWeakSecret: true,
|
|
12058
|
+
...options.secretPolicy !== void 0 ? { secretPolicy: options.secretPolicy } : {}
|
|
12389
12059
|
}
|
|
12390
12060
|
);
|
|
12391
|
-
await
|
|
12061
|
+
await saveSealedSecret(this.deps.options.store, vault, {
|
|
12392
12062
|
providerId: provider.id,
|
|
12393
12063
|
sealed
|
|
12394
12064
|
});
|
|
@@ -12399,7 +12069,7 @@ var TeamFacade = class {
|
|
|
12399
12069
|
}
|
|
12400
12070
|
/**
|
|
12401
12071
|
* Atomic peer-recovery — re-wraps an EXISTING user's keyring under
|
|
12402
|
-
* a fresh temp
|
|
12072
|
+
* a fresh temp secret in a single store write. Closes the
|
|
12403
12073
|
* partial-failure window (the previous compose-from-primitives
|
|
12404
12074
|
* pattern was `db.revoke + db.grant`, two writes — if the issuer
|
|
12405
12075
|
* cancelled between them the target was locked out entirely).
|
|
@@ -12418,17 +12088,17 @@ var TeamFacade = class {
|
|
|
12418
12088
|
* recovery / TOTP / email-OTP factor proof at the moment of
|
|
12419
12089
|
* recovery, so the issuer affirmatively re-asserts identity.
|
|
12420
12090
|
*
|
|
12421
|
-
* The recipient should call `db.
|
|
12091
|
+
* The recipient should call `db.rotateSecret` on first session
|
|
12422
12092
|
* to choose their own phrase — the temp acts as a single-use
|
|
12423
12093
|
* bridge.
|
|
12424
12094
|
*
|
|
12425
12095
|
* ```ts
|
|
12426
|
-
* await db.recoverUser('acme', {
|
|
12096
|
+
* await db.team.recoverUser('acme', {
|
|
12427
12097
|
* userId: 'bob',
|
|
12428
|
-
*
|
|
12098
|
+
* secret: 'temporary-correct-horse-battery-staple-printer',
|
|
12429
12099
|
* }, { factors: [{ kind: 'recovery' }] })
|
|
12430
12100
|
* // Bob opens createNoydb({ user: 'bob', secret: tempPhrase })
|
|
12431
|
-
* // and immediately calls db.
|
|
12101
|
+
* // and immediately calls db.rotateSecret to set his own.
|
|
12432
12102
|
* ```
|
|
12433
12103
|
*
|
|
12434
12104
|
* @throws `NoAccessError` when no keyring exists for the target.
|
|
@@ -12454,17 +12124,17 @@ var TeamFacade = class {
|
|
|
12454
12124
|
* The hub wraps the user's DEK set (not the KEK) under a code-derived
|
|
12455
12125
|
* AES-GCM key — see `team/recovery.ts` for the rationale. The mint
|
|
12456
12126
|
* helper {@link mintPaperRecoveryEntry} is the canonical primitive;
|
|
12457
|
-
* pair it with `db.getKeyring(vault)` to obtain the live DEK set:
|
|
12127
|
+
* pair it with `db.team.getKeyring(vault)` to obtain the live DEK set:
|
|
12458
12128
|
*
|
|
12459
12129
|
* ```ts
|
|
12460
12130
|
* import { mintPaperRecoveryEntry } from '@noy-db/hub'
|
|
12461
12131
|
*
|
|
12462
|
-
* const keyring = await db.getKeyring('acme')
|
|
12132
|
+
* const keyring = await db.team.getKeyring('acme')
|
|
12463
12133
|
* const codes: string[] = ['CORRECT-HORSE-1', 'BATTERY-STAPLE-2', ...]
|
|
12464
12134
|
* const entries = await Promise.all(
|
|
12465
12135
|
* codes.map((code, i) => mintPaperRecoveryEntry(keyring.deks, code, `code-${i}`)),
|
|
12466
12136
|
* )
|
|
12467
|
-
* await db.enrollRecovery('acme', { profile: 'paper', entries })
|
|
12137
|
+
* await db.team.enrollRecovery('acme', { profile: 'paper', entries })
|
|
12468
12138
|
* showCodesToUser(codes)
|
|
12469
12139
|
* ```
|
|
12470
12140
|
*
|
|
@@ -12475,7 +12145,7 @@ var TeamFacade = class {
|
|
|
12475
12145
|
* ```ts
|
|
12476
12146
|
* import { generateRecoveryCodeSet } from '@noy-db/on-recovery'
|
|
12477
12147
|
* const { codes, entries } = await generateRecoveryCodeSet({ deks: keyring.deks, count: 8 })
|
|
12478
|
-
* await db.enrollRecovery('acme', { profile: 'paper', entries })
|
|
12148
|
+
* await db.team.enrollRecovery('acme', { profile: 'paper', entries })
|
|
12479
12149
|
* ```
|
|
12480
12150
|
*/
|
|
12481
12151
|
async enrollRecovery(vault, enrollment) {
|
|
@@ -12575,7 +12245,7 @@ var TeamFacade = class {
|
|
|
12575
12245
|
* and no `secret` / `getKeyring` is configured.
|
|
12576
12246
|
*
|
|
12577
12247
|
* ```ts
|
|
12578
|
-
* const keyring = await db.getKeyring('acme')
|
|
12248
|
+
* const keyring = await db.team.getKeyring('acme')
|
|
12579
12249
|
* // keyring.deks: Map<collection, CryptoKey>
|
|
12580
12250
|
* // keyring.kek: CryptoKey | null (null for tier-3 / wrap-DEKs sessions)
|
|
12581
12251
|
* // keyring.role / .permissions / .authenticators
|
|
@@ -12652,7 +12322,7 @@ var Noydb = class {
|
|
|
12652
12322
|
keyringCache = /* @__PURE__ */ new Map();
|
|
12653
12323
|
syncEngines = /* @__PURE__ */ new Map();
|
|
12654
12324
|
/**
|
|
12655
|
-
* Per-vault active session tier — defaults to `1` after a
|
|
12325
|
+
* Per-vault active session tier — defaults to `1` after a secret
|
|
12656
12326
|
* unlock; tier-2 / tier-3 unlocks downgrade it. Used by
|
|
12657
12327
|
* {@link checkGate} to evaluate `gate.minTier`.
|
|
12658
12328
|
*/
|
|
@@ -12680,26 +12350,43 @@ var Noydb = class {
|
|
|
12680
12350
|
writeRelay;
|
|
12681
12351
|
/** Per-vault policy enforcers. */
|
|
12682
12352
|
policyEnforcers = /* @__PURE__ */ new Map();
|
|
12683
|
-
txStrategy;
|
|
12684
|
-
forgetStrategy;
|
|
12685
12353
|
/**
|
|
12686
|
-
*
|
|
12687
|
-
* `
|
|
12688
|
-
*
|
|
12354
|
+
* Every opt-in service, resolved once (#838). Shared by reference with each
|
|
12355
|
+
* `Vault` this instance opens and, through them, every `Collection` — so
|
|
12356
|
+
* there is exactly one resolution and no construction path can disagree
|
|
12357
|
+
* about which services are enabled (the #834 bug class).
|
|
12689
12358
|
*/
|
|
12690
|
-
|
|
12359
|
+
strategies;
|
|
12691
12360
|
/**
|
|
12692
|
-
* Opt-in
|
|
12693
|
-
* `
|
|
12694
|
-
*
|
|
12695
|
-
|
|
12696
|
-
|
|
12697
|
-
|
|
12361
|
+
* Opt-in sovereign-custody (FR-6) strategy — `NO_CUSTODY` (throwing) unless
|
|
12362
|
+
* `withCustody()` was passed. Kept as a public accessor because `Vault`
|
|
12363
|
+
* routes `vault.custody.liberate` through `this.noydb.custodyStrategy`.
|
|
12364
|
+
* @internal
|
|
12365
|
+
*/
|
|
12366
|
+
get custodyStrategy() {
|
|
12367
|
+
return this.strategies.custody;
|
|
12368
|
+
}
|
|
12698
12369
|
snapshots;
|
|
12699
12370
|
policyManager;
|
|
12700
12371
|
/** Pre-resolved policy-gate engine function (mirrors `coordinationProvider`/`userApiFactory` above). */
|
|
12701
12372
|
policyCheckGate;
|
|
12702
|
-
|
|
12373
|
+
/**
|
|
12374
|
+
* Credential and multi-user operations — enrolment, secret rotation,
|
|
12375
|
+
* recovery, quick-unlock (#846).
|
|
12376
|
+
*
|
|
12377
|
+
* Public because 23 methods on this class did nothing but restate a
|
|
12378
|
+
* TeamFacade signature and forward to it, so every signature had to be
|
|
12379
|
+
* hand-kept in sync with its counterpart. `db.team.rotateSecret(…)`
|
|
12380
|
+
* reads the same and has one source of truth.
|
|
12381
|
+
*
|
|
12382
|
+
* A getter, not a field, so it appears in the prototype-based kernel API
|
|
12383
|
+
* manifest — an instance field is invisible to it (the same reason
|
|
12384
|
+
* `custodyStrategy` became one in #838).
|
|
12385
|
+
*/
|
|
12386
|
+
get team() {
|
|
12387
|
+
return this.#team;
|
|
12388
|
+
}
|
|
12389
|
+
#team;
|
|
12703
12390
|
/**
|
|
12704
12391
|
* Currently-running multi-record transaction, set by
|
|
12705
12392
|
* `runTransaction` at the start of Phase 2 (commit) and cleared in
|
|
@@ -12738,14 +12425,9 @@ var Noydb = class {
|
|
|
12738
12425
|
this.userApiFactory = options.userApiFactory;
|
|
12739
12426
|
if (!options.policyFactory || !options.policyCheckGateFn) throw new ValidationError("Noydb must be constructed via createNoydb(), which resolves the default policy service.");
|
|
12740
12427
|
this.policyCheckGate = options.policyCheckGateFn;
|
|
12741
|
-
this.
|
|
12742
|
-
this.forgetStrategy = options.forgetStrategy ?? NO_FORGET;
|
|
12743
|
-
this.custodyStrategy = options.custodyStrategy ?? NO_CUSTODY;
|
|
12744
|
-
this.teamStrategy = options.teamStrategy ?? NO_TEAM;
|
|
12745
|
-
this.sessionStrategy = options.sessionStrategy ?? NO_SESSION;
|
|
12746
|
-
this.syncStrategy = options.syncStrategy ?? NO_SYNC;
|
|
12428
|
+
this.strategies = resolveStrategies(options);
|
|
12747
12429
|
this.snapshots = new NoydbSnapshots({
|
|
12748
|
-
strategy:
|
|
12430
|
+
strategy: this.strategies.snapshots,
|
|
12749
12431
|
user: options.user,
|
|
12750
12432
|
isClosed: () => this.closed,
|
|
12751
12433
|
getVault: (name) => this.vaultCache.get(name),
|
|
@@ -12766,7 +12448,7 @@ var Noydb = class {
|
|
|
12766
12448
|
this.vaultCache.delete(vault);
|
|
12767
12449
|
}
|
|
12768
12450
|
});
|
|
12769
|
-
this
|
|
12451
|
+
this.#team = new TeamFacade({
|
|
12770
12452
|
options: this.options,
|
|
12771
12453
|
keyringCache: this.keyringCache,
|
|
12772
12454
|
activeTier: this.activeTier,
|
|
@@ -12782,7 +12464,7 @@ var Noydb = class {
|
|
|
12782
12464
|
}
|
|
12783
12465
|
});
|
|
12784
12466
|
if (options.sessionPolicy) {
|
|
12785
|
-
this.
|
|
12467
|
+
this.strategies.session.validateSessionPolicy(options.sessionPolicy);
|
|
12786
12468
|
}
|
|
12787
12469
|
this.#registerGuardGate();
|
|
12788
12470
|
this.#registerPeriodGate();
|
|
@@ -12791,9 +12473,9 @@ var Noydb = class {
|
|
|
12791
12473
|
}
|
|
12792
12474
|
/** @internal — resolved forget strategy (NO_FORGET when not configured). */
|
|
12793
12475
|
get _forgetStrategy() {
|
|
12794
|
-
return this.
|
|
12476
|
+
return this.strategies.forget;
|
|
12795
12477
|
}
|
|
12796
|
-
// GDPR subject-index maintenance. When `
|
|
12478
|
+
// GDPR subject-index maintenance. When `withForget` declares
|
|
12797
12479
|
// any subject fields, keep the encrypted `_subject_index` in lock-step with
|
|
12798
12480
|
// writes so `vault.forget(subjectId)` can find every record for a subject.
|
|
12799
12481
|
//
|
|
@@ -12804,7 +12486,7 @@ var Noydb = class {
|
|
|
12804
12486
|
// does NOT) — drop the ref so a deleted record never lingers in the
|
|
12805
12487
|
// index (RISK #2). Without it, forget() would try to shred a ghost.
|
|
12806
12488
|
#registerForgetHooks() {
|
|
12807
|
-
const subjects = this.
|
|
12489
|
+
const subjects = this.strategies.forget.subjects;
|
|
12808
12490
|
if (Object.keys(subjects).length === 0) return;
|
|
12809
12491
|
const subjectFieldFor = (collection) => subjects[collection];
|
|
12810
12492
|
this.writeHooks.onAfterWrite(async (event) => {
|
|
@@ -12868,7 +12550,7 @@ var Noydb = class {
|
|
|
12868
12550
|
if (!facade) return;
|
|
12869
12551
|
const ctx = { existing, vault: facade, userId: e.userId, role: e.role };
|
|
12870
12552
|
await registry.runChecks(e.collection, incoming, ctx);
|
|
12871
|
-
const { GuardExecutor } = await import("./executor-
|
|
12553
|
+
const { GuardExecutor } = await import("./executor-RM7XWQDU.js");
|
|
12872
12554
|
for (const g of guards) {
|
|
12873
12555
|
await GuardExecutor.checkFrozenFields(g, e.docId, existing, incoming, e.computedFieldNames);
|
|
12874
12556
|
}
|
|
@@ -12992,8 +12674,9 @@ var Noydb = class {
|
|
|
12992
12674
|
const targets = normalizeSyncTargets(this.options.sync);
|
|
12993
12675
|
if (targets.length > 0) {
|
|
12994
12676
|
const primary = targets.find((t) => t.role === "sync-peer") ?? targets[0];
|
|
12995
|
-
const
|
|
12996
|
-
|
|
12677
|
+
const declaredPolicy = this.options.syncPolicy ?? primary.policy;
|
|
12678
|
+
const effectivePolicy = declaredPolicy ?? INDEXED_STORE_POLICY;
|
|
12679
|
+
syncEngine = this.strategies.sync.buildSyncEngine({
|
|
12997
12680
|
local: this.options.store,
|
|
12998
12681
|
remote: primary.store,
|
|
12999
12682
|
vault: name,
|
|
@@ -13004,10 +12687,11 @@ var Noydb = class {
|
|
|
13004
12687
|
...primary.label !== void 0 ? { label: primary.label } : {}
|
|
13005
12688
|
});
|
|
13006
12689
|
this.syncEngines.set(name, syncEngine);
|
|
12690
|
+
if (declaredPolicy) syncEngine.startScheduler();
|
|
13007
12691
|
for (const target of targets) {
|
|
13008
12692
|
if (target === primary) continue;
|
|
13009
12693
|
const targetPolicy = target.policy ?? this.options.syncPolicy ?? INDEXED_STORE_POLICY;
|
|
13010
|
-
const engine = this.
|
|
12694
|
+
const engine = this.strategies.sync.buildSyncEngine({
|
|
13011
12695
|
local: this.options.store,
|
|
13012
12696
|
remote: target.store,
|
|
13013
12697
|
vault: name,
|
|
@@ -13019,6 +12703,7 @@ var Noydb = class {
|
|
|
13019
12703
|
});
|
|
13020
12704
|
const key = `${name}::${target.label ?? target.role}`;
|
|
13021
12705
|
this.syncEngines.set(key, engine);
|
|
12706
|
+
if (target.policy ?? this.options.syncPolicy) engine.startScheduler();
|
|
13022
12707
|
}
|
|
13023
12708
|
}
|
|
13024
12709
|
const comp = new Vault({
|
|
@@ -13040,31 +12725,14 @@ var Noydb = class {
|
|
|
13040
12725
|
syncAdapter: targets.length > 0 ? targets[0].store : void 0,
|
|
13041
12726
|
getPurgeableTargets: () => targets.filter((t) => t.role === "backup" || t.role === "archive").map((t) => ({ store: t.store, role: t.role, ...t.label !== void 0 ? { label: t.label } : {} })),
|
|
13042
12727
|
historyConfig: this.options.history,
|
|
13043
|
-
|
|
12728
|
+
// #838 — the 21 conditional strategy spreads that used to live here are
|
|
12729
|
+
// one shared reference. This block is where #834's drift happened: a
|
|
12730
|
+
// copy of it silently omitted six strategies, and there was nothing to
|
|
12731
|
+
// catch that. There is no longer a per-service line to omit.
|
|
12732
|
+
strategies: this.strategies,
|
|
13044
12733
|
...this.options.objectStore !== void 0 ? { objectStore: this.options.objectStore } : {},
|
|
13045
|
-
...this.options.archiveStrategy !== void 0 ? { archiveStrategy: this.options.archiveStrategy } : {},
|
|
13046
|
-
...this.options.indexStrategy !== void 0 ? { indexStrategy: this.options.indexStrategy } : {},
|
|
13047
|
-
...this.options.lazyStrategy !== void 0 ? { lazyStrategy: this.options.lazyStrategy } : {},
|
|
13048
|
-
...this.options.aggregateStrategy !== void 0 ? { aggregateStrategy: this.options.aggregateStrategy } : {},
|
|
13049
|
-
...this.options.crdtStrategy !== void 0 ? { crdtStrategy: this.options.crdtStrategy } : {},
|
|
13050
|
-
...this.options.tiersStrategy !== void 0 ? { tiersStrategy: this.options.tiersStrategy } : {},
|
|
13051
|
-
...this.options.searchStrategy !== void 0 ? { searchStrategy: this.options.searchStrategy } : {},
|
|
13052
|
-
...this.options.cargoStrategy !== void 0 ? { cargoStrategy: this.options.cargoStrategy } : {},
|
|
13053
|
-
...this.options.brokerStrategy !== void 0 ? { brokerStrategy: this.options.brokerStrategy } : {},
|
|
13054
|
-
...this.options.consentStrategy !== void 0 ? { consentStrategy: this.options.consentStrategy } : {},
|
|
13055
|
-
...this.options.periodsStrategy !== void 0 ? { periodsStrategy: this.options.periodsStrategy } : {},
|
|
13056
|
-
...this.options.shadowStrategy !== void 0 ? { shadowStrategy: this.options.shadowStrategy } : {},
|
|
13057
|
-
...this.options.historyStrategy !== void 0 ? { historyStrategy: this.options.historyStrategy } : {},
|
|
13058
|
-
...this.options.i18nStrategy !== void 0 ? { i18nStrategy: this.options.i18nStrategy } : {},
|
|
13059
|
-
...this.options.syncStrategy !== void 0 ? { syncStrategy: this.options.syncStrategy } : {},
|
|
13060
12734
|
...this.options.guardStrategies !== void 0 ? { guardStrategies: this.options.guardStrategies } : {},
|
|
13061
12735
|
...this.options.numbering !== void 0 ? { numberingConfigs: this.options.numbering } : {},
|
|
13062
|
-
forgetStrategy: this.forgetStrategy,
|
|
13063
|
-
...this.options.attestationStrategy !== void 0 ? { attestationStrategy: this.options.attestationStrategy } : {},
|
|
13064
|
-
...this.options.classifiedStrategy !== void 0 ? { classifiedStrategy: this.options.classifiedStrategy } : {},
|
|
13065
|
-
...this.options.sealedRecordStrategy !== void 0 ? { sealedRecordStrategy: this.options.sealedRecordStrategy } : {},
|
|
13066
|
-
...this.options.portabilityStrategy !== void 0 ? { portabilityStrategy: this.options.portabilityStrategy } : {},
|
|
13067
|
-
...this.options.sequenceStrategy !== void 0 ? { sequenceStrategy: this.options.sequenceStrategy } : {},
|
|
13068
12736
|
locale: opts?.locale,
|
|
13069
12737
|
...opts?.meta !== void 0 ? { meta: opts.meta } : {},
|
|
13070
12738
|
// Thread the translator hook so Collection.put() can invoke it
|
|
@@ -13076,12 +12744,10 @@ var Noydb = class {
|
|
|
13076
12744
|
// compartments leave it null and load() skips the refresh.
|
|
13077
12745
|
reloadKeyring: this.options.encrypt !== false && this.options.secret ? async () => {
|
|
13078
12746
|
this.keyringCache.delete(name);
|
|
13079
|
-
const refreshed = await loadKeyring(
|
|
13080
|
-
this.options.
|
|
13081
|
-
|
|
13082
|
-
|
|
13083
|
-
this.options.secret
|
|
13084
|
-
);
|
|
12747
|
+
const refreshed = await loadKeyring(this.options.store, name, {
|
|
12748
|
+
userId: this.options.user,
|
|
12749
|
+
secret: this.options.secret
|
|
12750
|
+
});
|
|
13085
12751
|
this.keyringCache.set(name, refreshed);
|
|
13086
12752
|
return refreshed;
|
|
13087
12753
|
} : void 0
|
|
@@ -13091,6 +12757,7 @@ var Noydb = class {
|
|
|
13091
12757
|
engine.setGraphBatchController({ begin: () => comp._beginGraphBatch(), flush: () => comp._flushGraphBatch() });
|
|
13092
12758
|
engine.setReservedLookupSource({ collections: () => comp._reservedLookupCollectionNames() });
|
|
13093
12759
|
engine.setReservedDictExpander((names) => comp._reservedDictDepsOf(names));
|
|
12760
|
+
engine.setPeriodPullSource({ periods: () => comp.listPeriods() });
|
|
13094
12761
|
});
|
|
13095
12762
|
await comp._initGuards(this.options.guardStrategies ?? []);
|
|
13096
12763
|
await comp._initDerivations(this.options.derivationStrategies ?? []);
|
|
@@ -13100,85 +12767,25 @@ var Noydb = class {
|
|
|
13100
12767
|
this.vaultCache.set(name, comp);
|
|
13101
12768
|
return comp;
|
|
13102
12769
|
}
|
|
13103
|
-
/**
|
|
12770
|
+
/**
|
|
12771
|
+
* Synchronous access to an ALREADY-OPEN vault.
|
|
12772
|
+
*
|
|
12773
|
+
* Returns the instance `openVault()` produced, or throws — it never
|
|
12774
|
+
* constructs. It used to fall back to building a Vault itself (once for
|
|
12775
|
+
* plaintext, once for encrypted-with-cached-keyring), and those copies
|
|
12776
|
+
* drifted from the real open path: the encrypted one silently omitted six
|
|
12777
|
+
* strategies, so a vault reached this way threw `*NotEnabledError` for
|
|
12778
|
+
* services the caller had configured (#834). Both fallbacks also skipped
|
|
12779
|
+
* the async registry init and schema-fence snapshot that `openVault`
|
|
12780
|
+
* performs, which a synchronous method cannot await. One construction
|
|
12781
|
+
* path is the only way that divergence stays fixed.
|
|
12782
|
+
*/
|
|
13104
12783
|
vault(name) {
|
|
13105
12784
|
const cached = this.vaultCache.get(name);
|
|
13106
12785
|
if (cached) return cached;
|
|
13107
|
-
|
|
13108
|
-
|
|
13109
|
-
|
|
13110
|
-
adapter: this.options.store,
|
|
13111
|
-
name,
|
|
13112
|
-
noydb: this,
|
|
13113
|
-
keyring: keyring2,
|
|
13114
|
-
encrypted: false,
|
|
13115
|
-
emitter: this.emitter,
|
|
13116
|
-
historyConfig: this.options.history,
|
|
13117
|
-
...this.options.blobStrategy !== void 0 ? { blobStrategy: this.options.blobStrategy } : {},
|
|
13118
|
-
...this.options.objectStore !== void 0 ? { objectStore: this.options.objectStore } : {},
|
|
13119
|
-
...this.options.archiveStrategy !== void 0 ? { archiveStrategy: this.options.archiveStrategy } : {},
|
|
13120
|
-
...this.options.indexStrategy !== void 0 ? { indexStrategy: this.options.indexStrategy } : {},
|
|
13121
|
-
...this.options.lazyStrategy !== void 0 ? { lazyStrategy: this.options.lazyStrategy } : {},
|
|
13122
|
-
...this.options.aggregateStrategy !== void 0 ? { aggregateStrategy: this.options.aggregateStrategy } : {},
|
|
13123
|
-
...this.options.crdtStrategy !== void 0 ? { crdtStrategy: this.options.crdtStrategy } : {},
|
|
13124
|
-
...this.options.tiersStrategy !== void 0 ? { tiersStrategy: this.options.tiersStrategy } : {},
|
|
13125
|
-
...this.options.searchStrategy !== void 0 ? { searchStrategy: this.options.searchStrategy } : {},
|
|
13126
|
-
...this.options.cargoStrategy !== void 0 ? { cargoStrategy: this.options.cargoStrategy } : {},
|
|
13127
|
-
...this.options.brokerStrategy !== void 0 ? { brokerStrategy: this.options.brokerStrategy } : {},
|
|
13128
|
-
...this.options.consentStrategy !== void 0 ? { consentStrategy: this.options.consentStrategy } : {},
|
|
13129
|
-
...this.options.periodsStrategy !== void 0 ? { periodsStrategy: this.options.periodsStrategy } : {},
|
|
13130
|
-
...this.options.shadowStrategy !== void 0 ? { shadowStrategy: this.options.shadowStrategy } : {},
|
|
13131
|
-
...this.options.historyStrategy !== void 0 ? { historyStrategy: this.options.historyStrategy } : {},
|
|
13132
|
-
...this.options.i18nStrategy !== void 0 ? { i18nStrategy: this.options.i18nStrategy } : {},
|
|
13133
|
-
...this.options.syncStrategy !== void 0 ? { syncStrategy: this.options.syncStrategy } : {},
|
|
13134
|
-
...this.options.guardStrategies !== void 0 ? { guardStrategies: this.options.guardStrategies } : {},
|
|
13135
|
-
...this.options.numbering !== void 0 ? { numberingConfigs: this.options.numbering } : {},
|
|
13136
|
-
forgetStrategy: this.forgetStrategy,
|
|
13137
|
-
...this.options.attestationStrategy !== void 0 ? { attestationStrategy: this.options.attestationStrategy } : {},
|
|
13138
|
-
...this.options.classifiedStrategy !== void 0 ? { classifiedStrategy: this.options.classifiedStrategy } : {},
|
|
13139
|
-
...this.options.sealedRecordStrategy !== void 0 ? { sealedRecordStrategy: this.options.sealedRecordStrategy } : {},
|
|
13140
|
-
...this.options.portabilityStrategy !== void 0 ? { portabilityStrategy: this.options.portabilityStrategy } : {},
|
|
13141
|
-
...this.options.sequenceStrategy !== void 0 ? { sequenceStrategy: this.options.sequenceStrategy } : {}
|
|
13142
|
-
});
|
|
13143
|
-
this.vaultCache.set(name, comp2);
|
|
13144
|
-
return comp2;
|
|
13145
|
-
}
|
|
13146
|
-
const keyring = this.keyringCache.get(name);
|
|
13147
|
-
if (!keyring) {
|
|
13148
|
-
throw new ValidationError(
|
|
13149
|
-
`Vault "${name}" not opened. Use await db.openVault("${name}") first.`
|
|
13150
|
-
);
|
|
13151
|
-
}
|
|
13152
|
-
const comp = new Vault({
|
|
13153
|
-
adapter: this.options.store,
|
|
13154
|
-
name,
|
|
13155
|
-
noydb: this,
|
|
13156
|
-
keyring,
|
|
13157
|
-
encrypted: true,
|
|
13158
|
-
historyConfig: this.options.history,
|
|
13159
|
-
...this.options.blobStrategy !== void 0 ? { blobStrategy: this.options.blobStrategy } : {},
|
|
13160
|
-
...this.options.objectStore !== void 0 ? { objectStore: this.options.objectStore } : {},
|
|
13161
|
-
...this.options.archiveStrategy !== void 0 ? { archiveStrategy: this.options.archiveStrategy } : {},
|
|
13162
|
-
...this.options.indexStrategy !== void 0 ? { indexStrategy: this.options.indexStrategy } : {},
|
|
13163
|
-
...this.options.lazyStrategy !== void 0 ? { lazyStrategy: this.options.lazyStrategy } : {},
|
|
13164
|
-
...this.options.aggregateStrategy !== void 0 ? { aggregateStrategy: this.options.aggregateStrategy } : {},
|
|
13165
|
-
...this.options.crdtStrategy !== void 0 ? { crdtStrategy: this.options.crdtStrategy } : {},
|
|
13166
|
-
...this.options.tiersStrategy !== void 0 ? { tiersStrategy: this.options.tiersStrategy } : {},
|
|
13167
|
-
...this.options.searchStrategy !== void 0 ? { searchStrategy: this.options.searchStrategy } : {},
|
|
13168
|
-
...this.options.cargoStrategy !== void 0 ? { cargoStrategy: this.options.cargoStrategy } : {},
|
|
13169
|
-
...this.options.brokerStrategy !== void 0 ? { brokerStrategy: this.options.brokerStrategy } : {},
|
|
13170
|
-
...this.options.consentStrategy !== void 0 ? { consentStrategy: this.options.consentStrategy } : {},
|
|
13171
|
-
...this.options.periodsStrategy !== void 0 ? { periodsStrategy: this.options.periodsStrategy } : {},
|
|
13172
|
-
...this.options.shadowStrategy !== void 0 ? { shadowStrategy: this.options.shadowStrategy } : {},
|
|
13173
|
-
...this.options.historyStrategy !== void 0 ? { historyStrategy: this.options.historyStrategy } : {},
|
|
13174
|
-
...this.options.i18nStrategy !== void 0 ? { i18nStrategy: this.options.i18nStrategy } : {},
|
|
13175
|
-
...this.options.syncStrategy !== void 0 ? { syncStrategy: this.options.syncStrategy } : {},
|
|
13176
|
-
...this.options.guardStrategies !== void 0 ? { guardStrategies: this.options.guardStrategies } : {},
|
|
13177
|
-
...this.options.numbering !== void 0 ? { numberingConfigs: this.options.numbering } : {},
|
|
13178
|
-
emitter: this.emitter
|
|
13179
|
-
});
|
|
13180
|
-
this.vaultCache.set(name, comp);
|
|
13181
|
-
return comp;
|
|
12786
|
+
throw new ValidationError(
|
|
12787
|
+
`Vault "${name}" is not open. Call \`await db.openVault("${name}")\` first \u2014 vault() only returns an already-open vault, because opening involves async work (registry init, schema fence) that a sync accessor cannot do.`
|
|
12788
|
+
);
|
|
13182
12789
|
}
|
|
13183
12790
|
/**
|
|
13184
12791
|
* Grant access to a user for a vault.
|
|
@@ -13192,7 +12799,7 @@ var Noydb = class {
|
|
|
13192
12799
|
* Opt-in (#267): throws {@link TeamNotEnabledError} without `withTeam()`.
|
|
13193
12800
|
*/
|
|
13194
12801
|
async grant(vault, options, factors) {
|
|
13195
|
-
return this.
|
|
12802
|
+
return this.strategies.team.grant(this.team, vault, options, factors);
|
|
13196
12803
|
}
|
|
13197
12804
|
/**
|
|
13198
12805
|
* Revoke a user's access to a vault.
|
|
@@ -13205,7 +12812,7 @@ var Noydb = class {
|
|
|
13205
12812
|
* Opt-in (#267): throws {@link TeamNotEnabledError} without `withTeam()`.
|
|
13206
12813
|
*/
|
|
13207
12814
|
async revoke(vault, options, factors) {
|
|
13208
|
-
return this.
|
|
12815
|
+
return this.strategies.team.revoke(this.team, vault, options, factors);
|
|
13209
12816
|
}
|
|
13210
12817
|
/**
|
|
13211
12818
|
* Grant the FR-6 `custodian` role to a user (owner-only custody API).
|
|
@@ -13218,7 +12825,7 @@ var Noydb = class {
|
|
|
13218
12825
|
* owner-only invariant even if a host mis-configures the gate.
|
|
13219
12826
|
*/
|
|
13220
12827
|
async grantCustodian(vault, options, factors) {
|
|
13221
|
-
return this.
|
|
12828
|
+
return this.strategies.custody.grantCustodian(this, vault, options, factors);
|
|
13222
12829
|
}
|
|
13223
12830
|
/** @internal — grant-custodian engine, reached only via withCustody(); the
|
|
13224
12831
|
* keyring engine arrives as an argument so the floor never carries it (#267). */
|
|
@@ -13237,7 +12844,7 @@ var Noydb = class {
|
|
|
13237
12844
|
* 'owner'` check, so an admin cannot unwind a custodianship.
|
|
13238
12845
|
*/
|
|
13239
12846
|
async revokeCustodian(vault, options, factors) {
|
|
13240
|
-
return this.
|
|
12847
|
+
return this.strategies.custody.revokeCustodian(this, vault, options, factors);
|
|
13241
12848
|
}
|
|
13242
12849
|
/** @internal — revoke-custodian engine, reached only via withCustody().
|
|
13243
12850
|
* Mirrors `_grantCustodianImpl` (#267: engine passed in). */
|
|
@@ -13299,16 +12906,26 @@ var Noydb = class {
|
|
|
13299
12906
|
/**
|
|
13300
12907
|
* Rotate the DEKs for the given collections in a vault.
|
|
13301
12908
|
*
|
|
13302
|
-
* Generates fresh DEKs
|
|
13303
|
-
*
|
|
13304
|
-
*
|
|
13305
|
-
*
|
|
13306
|
-
* key-rotation policy.
|
|
12909
|
+
* Generates fresh DEKs and re-encrypts every record in each collection.
|
|
12910
|
+
* The old DEKs become unreachable — useful as a defense-in-depth measure
|
|
12911
|
+
* after a suspected key leak, or as the scheduled half of a key-rotation
|
|
12912
|
+
* policy.
|
|
13307
12913
|
*
|
|
13308
|
-
*
|
|
13309
|
-
*
|
|
13310
|
-
*
|
|
13311
|
-
*
|
|
12914
|
+
* ## Other members LOSE access to the rotated collections (#854)
|
|
12915
|
+
*
|
|
12916
|
+
* A member's DEKs are wrapped under that member's KEK, and a KEK derives
|
|
12917
|
+
* only from that member's secret. The caller cannot derive anyone else's
|
|
12918
|
+
* KEK, so re-wrapping a fresh DEK for them is impossible — that is the
|
|
12919
|
+
* zero-knowledge property working as designed. Rotation therefore DROPS
|
|
12920
|
+
* the rotated collections from every other member's keyring.
|
|
12921
|
+
*
|
|
12922
|
+
* The returned {@link RotateResult.needsRegrant} names each (member,
|
|
12923
|
+
* collection) pair that was dropped. Re-run `grant()` for those pairs, or
|
|
12924
|
+
* they stay locked out.
|
|
12925
|
+
*
|
|
12926
|
+
* Unlike `revoke({ rotateKeys: true })`, this call does not REMOVE any
|
|
12927
|
+
* user from the vault — they keep membership and their other collections.
|
|
12928
|
+
* This is the "just rotate" path; "revoke and rotate" lives in `revoke()`.
|
|
13312
12929
|
*
|
|
13313
12930
|
* Exposed on Noydb (rather than only on the lower-level keyring
|
|
13314
12931
|
* module) so CLI and admin tooling can trigger rotation without
|
|
@@ -13316,7 +12933,7 @@ var Noydb = class {
|
|
|
13316
12933
|
* Opt-in (#267): throws {@link TeamNotEnabledError} without `withTeam()`.
|
|
13317
12934
|
*/
|
|
13318
12935
|
async rotate(vault, collections) {
|
|
13319
|
-
return this.
|
|
12936
|
+
return this.strategies.team.rotate(this.team, vault, collections);
|
|
13320
12937
|
}
|
|
13321
12938
|
/** List all users with access to a vault. */
|
|
13322
12939
|
async listUsers(vault) {
|
|
@@ -13329,9 +12946,9 @@ var Noydb = class {
|
|
|
13329
12946
|
*
|
|
13330
12947
|
* The walk is a two-step pipeline: first ask the adapter for the
|
|
13331
12948
|
* universe of compartments it stores, then for each one attempt to
|
|
13332
|
-
* load the calling user's keyring with the in-memory
|
|
12949
|
+
* load the calling user's keyring with the in-memory secret.
|
|
13333
12950
|
* Compartments where the user has no keyring file (`NoAccessError`)
|
|
13334
|
-
* or where the
|
|
12951
|
+
* or where the secret doesn't unwrap (`InvalidKeyError`) are
|
|
13335
12952
|
* silently dropped from the result — the existence of those
|
|
13336
12953
|
* compartments is **not** confirmed in the return value.
|
|
13337
12954
|
*
|
|
@@ -13352,15 +12969,15 @@ var Noydb = class {
|
|
|
13352
12969
|
* **Known edge case.** A vault whose keyring file
|
|
13353
12970
|
* happens to have an empty wrapped-DEKs map (because the owner
|
|
13354
12971
|
* granted access before any collection was created) will pass the
|
|
13355
|
-
* `loadKeyring` probe with *any*
|
|
12972
|
+
* `loadKeyring` probe with *any* secret — there are no DEKs to
|
|
13356
12973
|
* unwrap, so the integrity-checked unwrap that normally rejects
|
|
13357
|
-
* wrong
|
|
12974
|
+
* wrong secrets never runs. The result is that an unrelated
|
|
13358
12975
|
* principal who happens to know the user-id and the vault
|
|
13359
12976
|
* name can show up in `listAccessibleVaults()` as having
|
|
13360
12977
|
* access to that empty vault. They cannot read any actual
|
|
13361
12978
|
* data (their DEK set is empty), so this is a metadata leak
|
|
13362
12979
|
* (vault name + user-id), not a content leak. Hardening this
|
|
13363
|
-
* via a
|
|
12980
|
+
* via a secret canary in the keyring file is a deferred
|
|
13364
12981
|
* follow-up.
|
|
13365
12982
|
*
|
|
13366
12983
|
* **Cost.** O(compartments × keyring-load) — one `loadKeyring`
|
|
@@ -13401,7 +13018,7 @@ var Noydb = class {
|
|
|
13401
13018
|
}
|
|
13402
13019
|
if (!this.options.secret) {
|
|
13403
13020
|
throw new ValidationError(
|
|
13404
|
-
"Noydb.listAccessibleVaults(): a secret (
|
|
13021
|
+
"Noydb.listAccessibleVaults(): a secret (secret) is required when encryption is enabled."
|
|
13405
13022
|
);
|
|
13406
13023
|
}
|
|
13407
13024
|
const minRank = ROLE_RANK[options.minRole ?? "client"];
|
|
@@ -13410,12 +13027,10 @@ var Noydb = class {
|
|
|
13410
13027
|
for (const vault of universe) {
|
|
13411
13028
|
let keyring;
|
|
13412
13029
|
try {
|
|
13413
|
-
keyring = await loadKeyring(
|
|
13414
|
-
|
|
13415
|
-
|
|
13416
|
-
|
|
13417
|
-
this.options.secret
|
|
13418
|
-
);
|
|
13030
|
+
keyring = await loadKeyring(adapter, vault, {
|
|
13031
|
+
userId: this.options.user,
|
|
13032
|
+
secret: this.options.secret
|
|
13033
|
+
});
|
|
13419
13034
|
} catch (err) {
|
|
13420
13035
|
if (err instanceof NoAccessError || err instanceof InvalidKeyError || err instanceof KeyringCorruptError) {
|
|
13421
13036
|
continue;
|
|
@@ -13476,7 +13091,7 @@ var Noydb = class {
|
|
|
13476
13091
|
* })
|
|
13477
13092
|
* ```
|
|
13478
13093
|
*/
|
|
13479
|
-
async queryAcross(vaultIds,
|
|
13094
|
+
async queryAcross(vaultIds, fn, options = {}) {
|
|
13480
13095
|
if (this.closed) throw new ValidationError("Instance is closed");
|
|
13481
13096
|
this.resetSessionTimer();
|
|
13482
13097
|
const concurrency = Math.max(1, options.concurrency ?? 1);
|
|
@@ -13490,7 +13105,7 @@ var Noydb = class {
|
|
|
13490
13105
|
const task = (async () => {
|
|
13491
13106
|
try {
|
|
13492
13107
|
const comp = await this.openVault(vaultId, { create: options.create !== false });
|
|
13493
|
-
const result = await
|
|
13108
|
+
const result = await fn(comp);
|
|
13494
13109
|
results[idx] = { vault: vaultId, result };
|
|
13495
13110
|
} catch (err) {
|
|
13496
13111
|
results[idx] = {
|
|
@@ -13540,23 +13155,20 @@ var Noydb = class {
|
|
|
13540
13155
|
return store.resolveBackend ? store.resolveBackend(vaultId) : this.options.store;
|
|
13541
13156
|
}
|
|
13542
13157
|
/**
|
|
13543
|
-
* Change the current user's
|
|
13158
|
+
* Change the current user's secret for a vault.
|
|
13544
13159
|
*
|
|
13545
|
-
* Validates the new
|
|
13546
|
-
* `{
|
|
13547
|
-
* fixtures and migrations. Pass a `
|
|
13160
|
+
* Validates the new secret against the strength rules. Pass
|
|
13161
|
+
* `{ allowWeakSecret: true }` to skip — typically only useful for
|
|
13162
|
+
* fixtures and migrations. Pass a `SecretPolicy` to override the
|
|
13548
13163
|
* default rules (e.g. consumer-tunable `pattern` / `customValidator`).
|
|
13549
13164
|
*/
|
|
13550
|
-
async changeSecret(vault,
|
|
13165
|
+
async changeSecret(vault, newSecret, options) {
|
|
13551
13166
|
this.checkPolicyOperation(vault, "changeSecret");
|
|
13552
13167
|
const keyring = await this._getKeyringInternal(vault);
|
|
13553
|
-
const updated = await changeSecret(
|
|
13554
|
-
|
|
13555
|
-
|
|
13556
|
-
|
|
13557
|
-
newPassphrase,
|
|
13558
|
-
options
|
|
13559
|
-
);
|
|
13168
|
+
const updated = await changeSecret(this.options.store, vault, keyring, {
|
|
13169
|
+
...options,
|
|
13170
|
+
newSecret
|
|
13171
|
+
});
|
|
13560
13172
|
this.keyringCache.set(vault, updated);
|
|
13561
13173
|
}
|
|
13562
13174
|
// ─── Sync ──────────────────────────────────────────────────────
|
|
@@ -13606,7 +13218,7 @@ var Noydb = class {
|
|
|
13606
13218
|
}
|
|
13607
13219
|
transaction(arg, maybeFn) {
|
|
13608
13220
|
if (typeof arg === "function") {
|
|
13609
|
-
return this.
|
|
13221
|
+
return this.strategies.transactions.runTransaction(this, arg);
|
|
13610
13222
|
}
|
|
13611
13223
|
if (typeof arg === "object" && arg !== null && arg.dryRun === true) {
|
|
13612
13224
|
if (typeof maybeFn !== "function") {
|
|
@@ -13614,7 +13226,7 @@ var Noydb = class {
|
|
|
13614
13226
|
"db.transaction({ dryRun: true }, fn) requires the callback as the second argument."
|
|
13615
13227
|
);
|
|
13616
13228
|
}
|
|
13617
|
-
return this.
|
|
13229
|
+
return this.strategies.transactions.runDryRun(this, maybeFn);
|
|
13618
13230
|
}
|
|
13619
13231
|
if (typeof arg === "object" && arg !== null && arg.amendment === true) {
|
|
13620
13232
|
if (typeof maybeFn !== "function") {
|
|
@@ -13622,7 +13234,7 @@ var Noydb = class {
|
|
|
13622
13234
|
"db.transaction({ amendment: true }, fn) requires the callback as the second argument."
|
|
13623
13235
|
);
|
|
13624
13236
|
}
|
|
13625
|
-
return this.
|
|
13237
|
+
return this.strategies.transactions.runTransaction(this, maybeFn, arg);
|
|
13626
13238
|
}
|
|
13627
13239
|
const vault = arg;
|
|
13628
13240
|
const comp = this.vaultCache.get(vault);
|
|
@@ -13632,7 +13244,7 @@ var Noydb = class {
|
|
|
13632
13244
|
);
|
|
13633
13245
|
}
|
|
13634
13246
|
const engine = this.getSyncEngine(vault);
|
|
13635
|
-
return this.
|
|
13247
|
+
return this.strategies.sync.buildSyncTransaction(comp, engine);
|
|
13636
13248
|
}
|
|
13637
13249
|
/**
|
|
13638
13250
|
* Internal accessor for the primary store — used by the tx
|
|
@@ -13712,8 +13324,8 @@ var Noydb = class {
|
|
|
13712
13324
|
}
|
|
13713
13325
|
return engine;
|
|
13714
13326
|
}
|
|
13715
|
-
_forEachSyncEngine(vault,
|
|
13716
|
-
for (const [key, engine] of this.syncEngines) if (key === vault || key.startsWith(`${vault}::`))
|
|
13327
|
+
_forEachSyncEngine(vault, fn) {
|
|
13328
|
+
for (const [key, engine] of this.syncEngines) if (key === vault || key.startsWith(`${vault}::`)) fn(engine);
|
|
13717
13329
|
}
|
|
13718
13330
|
// ─── Events ────────────────────────────────────────────────────
|
|
13719
13331
|
on(event, handler) {
|
|
@@ -13757,9 +13369,9 @@ var Noydb = class {
|
|
|
13757
13369
|
return this.writeHooks.onAfterWrite(handler);
|
|
13758
13370
|
}
|
|
13759
13371
|
/** Subscribe to cross-tab write conflicts. Returns an unsubscribe. */
|
|
13760
|
-
onWriteConflict(
|
|
13761
|
-
this.on("write:conflict",
|
|
13762
|
-
return () => this.off("write:conflict",
|
|
13372
|
+
onWriteConflict(fn) {
|
|
13373
|
+
this.on("write:conflict", fn);
|
|
13374
|
+
return () => this.off("write:conflict", fn);
|
|
13763
13375
|
}
|
|
13764
13376
|
/**
|
|
13765
13377
|
* Enable same-device multi-tab coordination: primary/secondary
|
|
@@ -13833,12 +13445,12 @@ var Noydb = class {
|
|
|
13833
13445
|
activeTabs() {
|
|
13834
13446
|
return this.tabCoordinator?.activeTabs() ?? [];
|
|
13835
13447
|
}
|
|
13836
|
-
onTabRoleChange(
|
|
13837
|
-
return this.tabCoordinator?.onTabRoleChange(
|
|
13448
|
+
onTabRoleChange(fn) {
|
|
13449
|
+
return this.tabCoordinator?.onTabRoleChange(fn) ?? (() => {
|
|
13838
13450
|
});
|
|
13839
13451
|
}
|
|
13840
|
-
onActiveTabsChange(
|
|
13841
|
-
return this.tabCoordinator?.onActiveTabsChange(
|
|
13452
|
+
onActiveTabsChange(fn) {
|
|
13453
|
+
return this.tabCoordinator?.onActiveTabsChange(fn) ?? (() => {
|
|
13842
13454
|
});
|
|
13843
13455
|
}
|
|
13844
13456
|
/** @internal The write-hook registry, threaded into each Collection. */
|
|
@@ -13905,6 +13517,7 @@ var Noydb = class {
|
|
|
13905
13517
|
close() {
|
|
13906
13518
|
this.closed = true;
|
|
13907
13519
|
this.snapshots.stop();
|
|
13520
|
+
for (const engine of this.syncEngines.values()) engine.stopScheduler();
|
|
13908
13521
|
if (this.sessionTimer) {
|
|
13909
13522
|
clearTimeout(this.sessionTimer);
|
|
13910
13523
|
this.sessionTimer = null;
|
|
@@ -13913,7 +13526,7 @@ var Noydb = class {
|
|
|
13913
13526
|
enforcer.destroy();
|
|
13914
13527
|
}
|
|
13915
13528
|
this.policyEnforcers.clear();
|
|
13916
|
-
this.
|
|
13529
|
+
this.strategies.session.revokeAllSessions();
|
|
13917
13530
|
for (const engine of this.syncEngines.values()) {
|
|
13918
13531
|
engine.stopAutoSync();
|
|
13919
13532
|
}
|
|
@@ -14035,7 +13648,7 @@ var Noydb = class {
|
|
|
14035
13648
|
* denial; resolves with `void` on success.
|
|
14036
13649
|
*
|
|
14037
13650
|
* @param vault The vault whose policy applies.
|
|
14038
|
-
* @param gate Gate name — built-in (e.g. `'rotate-
|
|
13651
|
+
* @param gate Gate name — built-in (e.g. `'rotate-secret'`)
|
|
14039
13652
|
* or app-defined (`app:*`).
|
|
14040
13653
|
* @param presented Caller-supplied factor proofs.
|
|
14041
13654
|
*/
|
|
@@ -14060,12 +13673,12 @@ var Noydb = class {
|
|
|
14060
13673
|
* Two enforcement modes:
|
|
14061
13674
|
*
|
|
14062
13675
|
* 1. **Managed-mode mandatory strong-recovery.** When
|
|
14063
|
-
* `
|
|
13676
|
+
* `secretMode === 'managed'`, the vault MUST have at least
|
|
14064
13677
|
* one **strong** recovery profile (Shamir today). Paper alone is
|
|
14065
13678
|
* rejected because under managed mode the user has no memorized
|
|
14066
|
-
*
|
|
13679
|
+
* secret, so losing the paper sheet = losing every record.
|
|
14067
13680
|
* This check is unconditional — independent of `requireRecovery`
|
|
14068
|
-
* and the `recover-
|
|
13681
|
+
* and the `recover-secret` gate.
|
|
14069
13682
|
*
|
|
14070
13683
|
* 2. **Opt-in strict mandatory-recovery.** When
|
|
14071
13684
|
* `requireRecovery: true` is set on createNoydb (and the gate is
|
|
@@ -14079,14 +13692,14 @@ var Noydb = class {
|
|
|
14079
13692
|
*/
|
|
14080
13693
|
async assertRecoveryEnrolled(vault, policy, opts) {
|
|
14081
13694
|
const skipManaged = (opts?.skipManagedCheck ?? false) || this._skipNextManagedRecoveryCheck;
|
|
14082
|
-
if (this.options.
|
|
13695
|
+
if (this.options.secretMode === "managed" && !skipManaged) {
|
|
14083
13696
|
const enrolled2 = await hasStrongRecoveryEnrolled(this.options.store, vault);
|
|
14084
13697
|
if (!enrolled2) {
|
|
14085
13698
|
throw new ManagedRecoveryNotEnrolledError(vault);
|
|
14086
13699
|
}
|
|
14087
13700
|
}
|
|
14088
13701
|
if (this.options.requireRecovery !== true) return;
|
|
14089
|
-
const gate = policy.gates["recover-
|
|
13702
|
+
const gate = policy.gates["recover-secret"];
|
|
14090
13703
|
if (gate?.enabled === false) return;
|
|
14091
13704
|
const enrolled = await hasRecoveryEnrolled(this.options.store, vault);
|
|
14092
13705
|
if (enrolled) return;
|
|
@@ -14101,34 +13714,6 @@ var Noydb = class {
|
|
|
14101
13714
|
this.activeTier.set(vault, tier);
|
|
14102
13715
|
}
|
|
14103
13716
|
// ─── Tier-2 enroll / remove ─────────────────────────────────────
|
|
14104
|
-
/** Add a tier-2 authenticator slot — see {@link TeamFacade.enrollAuthenticator}. */
|
|
14105
|
-
async enrollAuthenticator(vault, options, factors) {
|
|
14106
|
-
return this.team.enrollAuthenticator(vault, options, factors);
|
|
14107
|
-
}
|
|
14108
|
-
/** Remove a tier-2 authenticator slot — see {@link TeamFacade.removeAuthenticator}. */
|
|
14109
|
-
async removeAuthenticator(vault, slotId, factors) {
|
|
14110
|
-
return this.team.removeAuthenticator(vault, slotId, factors);
|
|
14111
|
-
}
|
|
14112
|
-
/** Read the slot list for a vault — see {@link TeamFacade.listAuthenticators}. */
|
|
14113
|
-
async listAuthenticators(vault) {
|
|
14114
|
-
return this.team.listAuthenticators(vault);
|
|
14115
|
-
}
|
|
14116
|
-
/** Mutate an authenticator slot's `meta` — see {@link TeamFacade.updateAuthenticator}. */
|
|
14117
|
-
async updateAuthenticator(vault, slotId, options, factors) {
|
|
14118
|
-
return this.team.updateAuthenticator(vault, slotId, options, factors);
|
|
14119
|
-
}
|
|
14120
|
-
/** Native WebAuthn enrollment — see {@link TeamFacade.enrollWebAuthn}. */
|
|
14121
|
-
async enrollWebAuthn(vault, ceremony, factors) {
|
|
14122
|
-
return this.team.enrollWebAuthn(vault, ceremony, factors);
|
|
14123
|
-
}
|
|
14124
|
-
/** List webauthn-method slots — see {@link TeamFacade.listWebAuthnSlots}. */
|
|
14125
|
-
async listWebAuthnSlots(vault) {
|
|
14126
|
-
return this.team.listWebAuthnSlots(vault);
|
|
14127
|
-
}
|
|
14128
|
-
/** Unlock via a tier-2 authenticator slot — see {@link TeamFacade.unlockViaAuthenticator}. */
|
|
14129
|
-
async unlockViaAuthenticator(vault, slotId, verify) {
|
|
14130
|
-
return this.team.unlockViaAuthenticator(vault, slotId, verify);
|
|
14131
|
-
}
|
|
14132
13717
|
// ─── Cover (https://github.com/vLannaAi/noy-db-docs/blob/main/content/docs/services/public-envelope.md) ──────
|
|
14133
13718
|
/**
|
|
14134
13719
|
* Set the owner-curated cover for a vault. Throws
|
|
@@ -14146,13 +13731,13 @@ var Noydb = class {
|
|
|
14146
13731
|
* value, absent ones are preserved, `null` deletes (#800).
|
|
14147
13732
|
*/
|
|
14148
13733
|
async setCover(vault, input) {
|
|
14149
|
-
const coverOption = this.options.cover
|
|
13734
|
+
const coverOption = this.options.cover;
|
|
14150
13735
|
if (!coverOption) {
|
|
14151
13736
|
throw new ValidationError(
|
|
14152
13737
|
"setCover: the cover feature is not enabled. Pass `cover: true` (or a schema object) to `createNoydb`."
|
|
14153
13738
|
);
|
|
14154
13739
|
}
|
|
14155
|
-
const { loadCover, saveCover, resolveSchema, validateCoverInput, mergeCustom, validateCoverSize } = await import("./cover
|
|
13740
|
+
const { loadCover, saveCover, resolveSchema, validateCoverInput, mergeCustom, validateCoverSize } = await import("./cover/index.js");
|
|
14156
13741
|
const schema = resolveSchema(coverOption);
|
|
14157
13742
|
validateCoverInput(input, schema);
|
|
14158
13743
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -14184,84 +13769,12 @@ var Noydb = class {
|
|
|
14184
13769
|
* regardless).
|
|
14185
13770
|
*/
|
|
14186
13771
|
async getCover(vault, opts = {}) {
|
|
14187
|
-
const { readCover } = await import("./cover
|
|
13772
|
+
const { readCover } = await import("./cover/index.js");
|
|
14188
13773
|
return readCover(this.options.store, vault, opts);
|
|
14189
13774
|
}
|
|
14190
|
-
/** @deprecated Use {@link Noydb.setCover} (#799 rename). */
|
|
14191
|
-
async setPublicEnvelope(vault, input) {
|
|
14192
|
-
return this.setCover(vault, input);
|
|
14193
|
-
}
|
|
14194
|
-
/** @deprecated Use {@link Noydb.getCover} (#799 rename). */
|
|
14195
|
-
async getPublicEnvelope(vault, opts = {}) {
|
|
14196
|
-
return this.getCover(vault, opts);
|
|
14197
|
-
}
|
|
14198
13775
|
// ─── Auth introspection ─────────────────────────────────────────
|
|
14199
|
-
/** English summary of the configured auth model — see {@link TeamFacade.describeAuthConfig}. */
|
|
14200
|
-
async describeAuthConfig(vault) {
|
|
14201
|
-
return this.team.describeAuthConfig(vault);
|
|
14202
|
-
}
|
|
14203
|
-
/** Mermaid `flowchart TB` source for the auth graph — see {@link TeamFacade.diagramAuthConfig}. */
|
|
14204
|
-
async diagramAuthConfig(vault) {
|
|
14205
|
-
return this.team.diagramAuthConfig(vault);
|
|
14206
|
-
}
|
|
14207
|
-
/** Per-user enrollment summary — see {@link TeamFacade.describeUserAuth}. */
|
|
14208
|
-
async describeUserAuth(vault, userId, factors) {
|
|
14209
|
-
return this.team.describeUserAuth(vault, userId, factors);
|
|
14210
|
-
}
|
|
14211
|
-
/** Bulk per-user enrollment summary — see {@link TeamFacade.describeAllUsersAuth}. */
|
|
14212
|
-
async describeAllUsersAuth(vault, factors) {
|
|
14213
|
-
return this.team.describeAllUsersAuth(vault, factors);
|
|
14214
|
-
}
|
|
14215
13776
|
// ─── Tier-1 change flows ────────────────────────────────────────
|
|
14216
|
-
/** Rotate the user's passphrase (user remembers old) — see {@link TeamFacade.rotatePassphrase}. */
|
|
14217
|
-
async rotatePassphrase(vault, input, factors) {
|
|
14218
|
-
return this.team.rotatePassphrase(vault, input, factors);
|
|
14219
|
-
}
|
|
14220
|
-
/** Reset the passphrase using a recovery proof — see {@link TeamFacade.recoverPassphrase}. */
|
|
14221
|
-
async recoverPassphrase(vault, input, factors) {
|
|
14222
|
-
return this.team.recoverPassphrase(vault, input, factors);
|
|
14223
|
-
}
|
|
14224
|
-
/** Deliberate paper/Shamir recovery-code regeneration — see {@link TeamFacade.rotateRecovery}. */
|
|
14225
|
-
async rotateRecovery(vault, options, factors) {
|
|
14226
|
-
return this.team.rotateRecovery(vault, options, factors);
|
|
14227
|
-
}
|
|
14228
|
-
/** Atomic create-and-enroll for managed-mode vaults — see {@link TeamFacade.openVaultAndEnrollRecovery}. */
|
|
14229
|
-
async openVaultAndEnrollRecovery(vault, opts) {
|
|
14230
|
-
return this.team.openVaultAndEnrollRecovery(vault, opts);
|
|
14231
|
-
}
|
|
14232
|
-
/** Recovery flow under managed-passphrase mode — see {@link TeamFacade.recoverManagedPassphrase}. */
|
|
14233
|
-
async recoverManagedPassphrase(vault, options) {
|
|
14234
|
-
return this.team.recoverManagedPassphrase(vault, options);
|
|
14235
|
-
}
|
|
14236
|
-
/** Atomic peer-recovery of an existing user's keyring — see {@link TeamFacade.recoverUser}. */
|
|
14237
|
-
async recoverUser(vault, options, factors) {
|
|
14238
|
-
return this.team.recoverUser(vault, options, factors);
|
|
14239
|
-
}
|
|
14240
|
-
/** Persist a recovery enrollment (paper or Shamir) — see {@link TeamFacade.enrollRecovery}. */
|
|
14241
|
-
async enrollRecovery(vault, enrollment) {
|
|
14242
|
-
return this.team.enrollRecovery(vault, enrollment);
|
|
14243
|
-
}
|
|
14244
|
-
/** Read the persisted recovery entries (paper + Shamir) — see {@link TeamFacade.listRecoveryEntries}. */
|
|
14245
|
-
async listRecoveryEntries(vault) {
|
|
14246
|
-
return this.team.listRecoveryEntries(vault);
|
|
14247
|
-
}
|
|
14248
13777
|
// ─── Tier-3 enroll / unlock ─────────────────────────────────────
|
|
14249
|
-
/** Register a tier-3 quick-unlock state — see {@link TeamFacade.enrollUnlock}. */
|
|
14250
|
-
async enrollUnlock(vault, state, factors) {
|
|
14251
|
-
return this.team.enrollUnlock(vault, state, factors);
|
|
14252
|
-
}
|
|
14253
|
-
/** Resume a session via the registered tier-3 state — see {@link TeamFacade.unlockViaPin}. */
|
|
14254
|
-
async unlockViaPin(vault, resume) {
|
|
14255
|
-
return this.team.unlockViaPin(vault, resume);
|
|
14256
|
-
}
|
|
14257
|
-
/** Drop the tier-3 state for a vault — see {@link TeamFacade.clearQuickUnlock}. */
|
|
14258
|
-
clearQuickUnlock(vault) {
|
|
14259
|
-
this.team.clearQuickUnlock(vault);
|
|
14260
|
-
}
|
|
14261
|
-
/** Public defensive-copy accessor for the unlocked keyring — see {@link TeamFacade.getKeyring}. */
|
|
14262
|
-
async getKeyring(vault) {
|
|
14263
|
-
return this.team.getKeyring(vault);
|
|
14264
|
-
}
|
|
14265
13778
|
/**
|
|
14266
13779
|
* Live-reference variant used by the hub's own code paths. Internal
|
|
14267
13780
|
* mutations on `deks` (e.g. {@link ensureCollectionDEK} adding a
|
|
@@ -14282,7 +13795,7 @@ var Noydb = class {
|
|
|
14282
13795
|
}
|
|
14283
13796
|
await assertKeyringOpenAllowed(this.options.store, vault, this.options.user, opts.create);
|
|
14284
13797
|
let effectiveSecret;
|
|
14285
|
-
if (this.options.
|
|
13798
|
+
if (this.options.secretMode === "managed") {
|
|
14286
13799
|
effectiveSecret = await resolveManagedSecret(
|
|
14287
13800
|
this.options.store,
|
|
14288
13801
|
vault,
|
|
@@ -14292,37 +13805,29 @@ var Noydb = class {
|
|
|
14292
13805
|
effectiveSecret = this.options.secret;
|
|
14293
13806
|
}
|
|
14294
13807
|
if (!effectiveSecret) {
|
|
14295
|
-
throw new ValidationError("A secret (
|
|
13808
|
+
throw new ValidationError("A secret (secret) or getKeyring callback is required when encryption is enabled");
|
|
14296
13809
|
}
|
|
14297
13810
|
let keyring;
|
|
14298
13811
|
try {
|
|
14299
|
-
keyring = await loadKeyring(this.options.store, vault, this.options.user, effectiveSecret);
|
|
13812
|
+
keyring = await loadKeyring(this.options.store, vault, { userId: this.options.user, secret: effectiveSecret });
|
|
14300
13813
|
} catch (err) {
|
|
14301
13814
|
if (err instanceof NoAccessError) {
|
|
14302
|
-
keyring = await createOwnerKeyring(
|
|
14303
|
-
this.options.
|
|
14304
|
-
|
|
14305
|
-
|
|
14306
|
-
|
|
14307
|
-
|
|
14308
|
-
|
|
14309
|
-
|
|
14310
|
-
|
|
14311
|
-
// 256 bits by construction.
|
|
14312
|
-
validate: this.options.passphraseMode === "managed" ? false : this.options.validatePassphrase === true
|
|
14313
|
-
}
|
|
14314
|
-
);
|
|
13815
|
+
keyring = await createOwnerKeyring(this.options.store, vault, {
|
|
13816
|
+
userId: this.options.user,
|
|
13817
|
+
secret: effectiveSecret,
|
|
13818
|
+
// Managed mode generates 256-bit base64 strings that don't satisfy
|
|
13819
|
+
// the human-secret strength rules (no spaces, no "words").
|
|
13820
|
+
// Skip validation in managed mode — the entropy floor is already
|
|
13821
|
+
// 256 bits by construction.
|
|
13822
|
+
validate: this.options.secretMode === "managed" ? false : this.options.validateSecret === true
|
|
13823
|
+
});
|
|
14315
13824
|
} else if (err instanceof InvalidKeyError && this.options.onInvalidKey === "reset") {
|
|
14316
13825
|
await this.options.store.delete(vault, "_keyring", this.options.user);
|
|
14317
|
-
keyring = await createOwnerKeyring(
|
|
14318
|
-
this.options.
|
|
14319
|
-
|
|
14320
|
-
this.options.
|
|
14321
|
-
|
|
14322
|
-
{
|
|
14323
|
-
validate: this.options.passphraseMode === "managed" ? false : this.options.validatePassphrase === true
|
|
14324
|
-
}
|
|
14325
|
-
);
|
|
13826
|
+
keyring = await createOwnerKeyring(this.options.store, vault, {
|
|
13827
|
+
userId: this.options.user,
|
|
13828
|
+
secret: effectiveSecret,
|
|
13829
|
+
validate: this.options.secretMode === "managed" ? false : this.options.validateSecret === true
|
|
13830
|
+
});
|
|
14326
13831
|
} else {
|
|
14327
13832
|
throw err;
|
|
14328
13833
|
}
|
|
@@ -14332,7 +13837,7 @@ var Noydb = class {
|
|
|
14332
13837
|
}
|
|
14333
13838
|
/**
|
|
14334
13839
|
* Take an on-demand checkpoint of the given vault.
|
|
14335
|
-
* Requires `
|
|
13840
|
+
* Requires `snapshotsStrategy: withSnapshots({ store })` in `createNoydb`.
|
|
14336
13841
|
* @throws ValidationError when the vault is not open
|
|
14337
13842
|
*/
|
|
14338
13843
|
async snapshot(vault, opts) {
|
|
@@ -14358,34 +13863,34 @@ var Noydb = class {
|
|
|
14358
13863
|
async function createNoydb(options) {
|
|
14359
13864
|
if (!options.store) options = { ...options, store: memoryStore() };
|
|
14360
13865
|
const encrypted = options.encrypt !== false;
|
|
14361
|
-
const managed = options.
|
|
13866
|
+
const managed = options.secretMode === "managed";
|
|
14362
13867
|
if (options.secret && options.getKeyring) {
|
|
14363
13868
|
throw new ValidationError("Provide either `secret` or `getKeyring`, not both");
|
|
14364
13869
|
}
|
|
14365
13870
|
if (managed) {
|
|
14366
13871
|
if (options.secret) {
|
|
14367
13872
|
throw new ValidationError(
|
|
14368
|
-
'`
|
|
13873
|
+
'`secretMode: "managed"` is mutually exclusive with `secret` \u2014 managed mode generates the secret itself. Drop `secret`.'
|
|
14369
13874
|
);
|
|
14370
13875
|
}
|
|
14371
13876
|
if (options.getKeyring) {
|
|
14372
13877
|
throw new ValidationError(
|
|
14373
|
-
'`
|
|
13878
|
+
'`secretMode: "managed"` is mutually exclusive with `getKeyring` \u2014 a custom unlock callback would bypass the sealing flow. Drop `getKeyring`.'
|
|
14374
13879
|
);
|
|
14375
13880
|
}
|
|
14376
13881
|
if (!options.sealingKey) {
|
|
14377
13882
|
throw new ValidationError(
|
|
14378
|
-
'`
|
|
13883
|
+
'`secretMode: "managed"` requires `sealingKey: SealingKeyProvider` (see @noy-db/seal-macos-keychain / @noy-db/seal-aws-kms / etc.).'
|
|
14379
13884
|
);
|
|
14380
13885
|
}
|
|
14381
13886
|
}
|
|
14382
13887
|
if (encrypted && !managed && !options.secret && !options.getKeyring) {
|
|
14383
|
-
throw new ValidationError("A secret (
|
|
13888
|
+
throw new ValidationError("A secret (secret) or getKeyring callback is required when encryption is enabled");
|
|
14384
13889
|
}
|
|
14385
13890
|
if (!options.coordinationStrategy) options = { ...options, coordinationStrategy: await createDefaultCoordinationProvider(options.store) };
|
|
14386
|
-
if (!options.userApiFactory) options = { ...options, userApiFactory: (await import("./api-
|
|
13891
|
+
if (!options.userApiFactory) options = { ...options, userApiFactory: (await import("./api-ZDKTWNBB.js")).createUserApi };
|
|
14387
13892
|
if (!options.policyFactory) {
|
|
14388
|
-
const policyModule = await import("./policy
|
|
13893
|
+
const policyModule = await import("./policy/index.js");
|
|
14389
13894
|
options = { ...options, policyFactory: policyModule.createNoydbPolicy, policyCheckGateFn: policyModule.checkGate };
|
|
14390
13895
|
}
|
|
14391
13896
|
return new Noydb(options);
|
|
@@ -14415,11 +13920,7 @@ export {
|
|
|
14415
13920
|
RefRegistry,
|
|
14416
13921
|
Vault,
|
|
14417
13922
|
QuickUnlockStore,
|
|
14418
|
-
describeAuthConfig,
|
|
14419
|
-
diagramAuthConfig,
|
|
14420
|
-
describeUserAuth,
|
|
14421
|
-
describeAllUsersAuth,
|
|
14422
13923
|
Noydb,
|
|
14423
13924
|
createNoydb
|
|
14424
13925
|
};
|
|
14425
|
-
//# sourceMappingURL=chunk-
|
|
13926
|
+
//# sourceMappingURL=chunk-NFIBXF4V.js.map
|