@noy-db/hub 0.9.0-pre.0 → 0.9.0-pre.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +39 -0
- package/dist/api-H4B7ZQXP.js +18 -0
- package/dist/as/index.js +10 -10
- package/dist/at/index.js +8 -8
- package/dist/attestation/index.js +18 -18
- package/dist/{backup-7RKNZMQO.js → backup-E3GBMNDA.js} +92 -31
- package/dist/backup-E3GBMNDA.js.map +1 -0
- package/dist/blobs/index.js +12 -12
- package/dist/broker/index.js +13 -13
- package/dist/by/index.js +2 -2
- package/dist/capsule/contract.js +6 -6
- package/dist/capsule/enclave-aes/crypto.d.ts +18 -0
- package/dist/capsule/enclave-aes/index.d.ts +2 -2
- package/dist/capsule/enclave-aes/index.js +14 -8
- package/dist/capsule/enclave-aes/index.js.map +1 -1
- package/dist/capsule/index.d.ts +1 -1
- package/dist/{capsule-57BDK7LG.js → capsule-YQKQZPH7.js} +14 -8
- package/dist/cargo/index.js +35 -35
- package/dist/{chunk-AJFPAHMW.js → chunk-27NCEPKM.js} +3 -3
- package/dist/{chunk-PGC35KXE.js → chunk-2IASHJPS.js} +2 -2
- package/dist/{chunk-NYJBYVBG.js → chunk-2ODEFG6K.js} +4 -4
- package/dist/{chunk-7BMOS4JQ.js → chunk-2QH3I7QC.js} +11 -11
- package/dist/{chunk-VSUQI5Q6.js → chunk-2RH5SEY7.js} +16 -2
- package/dist/chunk-2RH5SEY7.js.map +1 -0
- package/dist/{chunk-IVMFIKNA.js → chunk-2T2TGRWE.js} +6 -6
- package/dist/{chunk-G66YXUTY.js → chunk-35CNOVQE.js} +3 -3
- package/dist/{chunk-OJU67C23.js → chunk-3EXQXOQ2.js} +4 -4
- package/dist/{chunk-BJH77UY2.js → chunk-4KYKRYRT.js} +2 -2
- package/dist/{chunk-RDOEOPOI.js → chunk-4N4OIVK3.js} +5 -5
- package/dist/{chunk-WHOKGHJ3.js → chunk-4WLI37WK.js} +7 -7
- package/dist/{chunk-RNACRT5H.js → chunk-52ZFNK46.js} +2 -2
- package/dist/{chunk-CB4467G3.js → chunk-5A3HOTP5.js} +33 -7
- package/dist/chunk-5A3HOTP5.js.map +1 -0
- package/dist/{chunk-QDHHHI5Q.js → chunk-5SMCBPJ2.js} +5 -5
- package/dist/{chunk-EMAWOGVH.js → chunk-654RE5YC.js} +3 -3
- package/dist/{chunk-FZXRLNJO.js → chunk-6BEBWHNL.js} +3 -3
- package/dist/{chunk-EUD3HQM4.js → chunk-6WEPFEMJ.js} +4 -4
- package/dist/{chunk-YFFMPZPY.js → chunk-6WIFF46H.js} +2 -2
- package/dist/{chunk-ZVSKSUGI.js → chunk-7C7OF26T.js} +5 -5
- package/dist/{chunk-QXJXG7DN.js → chunk-7IV7GVOS.js} +5 -5
- package/dist/{chunk-MQ7YWBQ5.js → chunk-7JRLCP2J.js} +2 -2
- package/dist/{chunk-QSHATAXJ.js → chunk-7ONMS7QI.js} +2 -2
- package/dist/{chunk-JBMMWYOH.js → chunk-7UHLO4ZN.js} +35 -2
- package/dist/chunk-7UHLO4ZN.js.map +1 -0
- package/dist/{chunk-6WS35E6X.js → chunk-A52BK5AY.js} +2 -2
- package/dist/{chunk-GOJQ5DZA.js → chunk-AI35LNWQ.js} +4 -4
- package/dist/chunk-AI35LNWQ.js.map +1 -0
- package/dist/{chunk-XXQ5XIYY.js → chunk-AMSSAOOB.js} +2 -2
- package/dist/{chunk-3V6LZHUO.js → chunk-AYOQZJDB.js} +2 -2
- package/dist/{chunk-DL6BZKP3.js → chunk-B3B6HV5S.js} +2 -2
- package/dist/{chunk-5XONHAFD.js → chunk-B6EWMGFX.js} +2 -2
- package/dist/{chunk-6Y5E4SJU.js → chunk-BMAXBTYH.js} +5 -5
- package/dist/{chunk-LGGIFKJP.js → chunk-BNYDOF2Q.js} +4 -4
- package/dist/{chunk-XXNWU5QZ.js → chunk-BQJ5ORU5.js} +2 -2
- package/dist/{chunk-Z3ZXVB2Y.js → chunk-BSEPI3HD.js} +12 -12
- package/dist/chunk-BSEPI3HD.js.map +1 -0
- package/dist/{chunk-BYHCKX73.js → chunk-CLOSXHR4.js} +3 -3
- package/dist/{chunk-5HNW4ZTA.js → chunk-CSAN22QG.js} +6 -6
- package/dist/{chunk-TZYTMZZY.js → chunk-DL4GCSTS.js} +10 -10
- package/dist/{chunk-EA4VDI5D.js → chunk-DYIR6RC3.js} +4 -4
- package/dist/{chunk-PUBI455O.js → chunk-EPPAEGH5.js} +2 -2
- package/dist/{chunk-2A56DSRI.js → chunk-EQ6C2ZPT.js} +17 -51
- package/dist/chunk-EQ6C2ZPT.js.map +1 -0
- package/dist/{chunk-BNFNQNEP.js → chunk-F7X7MPK4.js} +2 -2
- package/dist/{chunk-SNM7LSYG.js → chunk-FUHUGKDN.js} +4 -4
- package/dist/{chunk-72XBVN4J.js → chunk-FVKQ5QUC.js} +2 -2
- package/dist/chunk-FVKQ5QUC.js.map +1 -0
- package/dist/{chunk-D4V5JJAK.js → chunk-GHMINSER.js} +4 -4
- package/dist/{chunk-APFFJN5T.js → chunk-GLSCL74M.js} +31 -34
- package/dist/chunk-GLSCL74M.js.map +1 -0
- package/dist/{chunk-XKBTJGFP.js → chunk-GU6QXHPZ.js} +3 -3
- package/dist/chunk-GU6QXHPZ.js.map +1 -0
- package/dist/{chunk-QGFEBNHO.js → chunk-GZISWBCJ.js} +4 -4
- package/dist/{chunk-OM3SEDI4.js → chunk-HTRLQ4ZZ.js} +4 -4
- package/dist/{chunk-SWXLZ4HX.js → chunk-ICHHNI5E.js} +8 -8
- package/dist/{chunk-K673OO6B.js → chunk-ID4ZBC3X.js} +4 -4
- package/dist/{chunk-H3YM66EI.js → chunk-IF2M43G4.js} +2 -2
- package/dist/{chunk-QGSNJD3B.js → chunk-IFUYLIEY.js} +2 -2
- package/dist/{chunk-D5A3GCZ4.js → chunk-IPF5ORDI.js} +3 -3
- package/dist/{delegation-ONLM4JFI.js → chunk-JQMEXCUZ.js} +59 -16
- package/dist/chunk-JQMEXCUZ.js.map +1 -0
- package/dist/{chunk-TFWFPZRU.js → chunk-K5JNK63R.js} +11 -11
- package/dist/{chunk-TFWFPZRU.js.map → chunk-K5JNK63R.js.map} +1 -1
- package/dist/{chunk-BVF3SXD7.js → chunk-KBIS64X4.js} +5 -5
- package/dist/chunk-L4UL4IAR.js +55 -0
- package/dist/chunk-L4UL4IAR.js.map +1 -0
- package/dist/{chunk-RIZTZJX6.js → chunk-LJ744WXU.js} +2 -2
- package/dist/{chunk-XITHENBI.js → chunk-LMC5L3MM.js} +7 -7
- package/dist/{chunk-XITHENBI.js.map → chunk-LMC5L3MM.js.map} +1 -1
- package/dist/{chunk-L5A3KR7R.js → chunk-LUQBG637.js} +3 -3
- package/dist/{chunk-6QLCS7ET.js → chunk-LZN6DTFI.js} +2 -2
- package/dist/{chunk-NIXRB5BP.js → chunk-MMWX5OT5.js} +2 -2
- package/dist/{chunk-JA25QG5M.js → chunk-N6EWQ5VB.js} +622 -119
- package/dist/chunk-N6EWQ5VB.js.map +1 -0
- package/dist/{chunk-UOZOWN73.js → chunk-ND6S2DKC.js} +2 -2
- package/dist/{chunk-WFWFXDNS.js → chunk-NHEKQWFI.js} +2 -2
- package/dist/{chunk-2ZFD2UJC.js → chunk-NIUHKKMM.js} +9 -9
- package/dist/{chunk-XA34THLF.js → chunk-NK4LGBGQ.js} +4 -4
- package/dist/{chunk-JSWKVZCR.js → chunk-NUZ7ROUZ.js} +2 -2
- package/dist/{chunk-DHU2AQ6T.js → chunk-O3NGOHXQ.js} +2 -2
- package/dist/{chunk-ZBUAX4EF.js → chunk-O6VOR4NH.js} +2 -2
- package/dist/{chunk-JZ4EDEIP.js → chunk-ODBOHPZU.js} +3 -3
- package/dist/{chunk-5UUJE4FP.js → chunk-OK44MD3C.js} +2 -2
- package/dist/{chunk-ECGXA4LT.js → chunk-OR3OHKU6.js} +2 -2
- package/dist/{chunk-ZWF3EWZA.js → chunk-P6FATPXQ.js} +2 -2
- package/dist/{chunk-PCYPXLEX.js → chunk-PBEHTFUG.js} +6 -6
- package/dist/{chunk-7CT6SX4M.js → chunk-PFHDQY5L.js} +3 -3
- package/dist/{chunk-PTJY5R3O.js → chunk-PIO6NW7O.js} +2 -2
- package/dist/{chunk-TMIJAR2X.js → chunk-PREYKC76.js} +3 -3
- package/dist/{chunk-ZHQJAV6D.js → chunk-PU5ZEV65.js} +2 -2
- package/dist/{chunk-UNSQZSZP.js → chunk-PWAMX5KU.js} +2 -2
- package/dist/{chunk-GETUTTZU.js → chunk-PZN76MMV.js} +4 -4
- package/dist/{chunk-ABU6A4Z5.js → chunk-Q4DBU5RM.js} +2 -2
- package/dist/{chunk-2WJKJZSO.js → chunk-QHG7GQKM.js} +2 -2
- package/dist/{chunk-UAKY6E4N.js → chunk-QNOWNCZS.js} +2 -2
- package/dist/{chunk-JPSL5GIZ.js → chunk-QQLXKDGC.js} +3 -3
- package/dist/{chunk-45VHWE4C.js → chunk-QVUMKG3Z.js} +271 -69
- package/dist/chunk-QVUMKG3Z.js.map +1 -0
- package/dist/{chunk-OK57EATL.js → chunk-R4GLRJ55.js} +2 -2
- package/dist/{chunk-B65CC6Z6.js → chunk-RF5WDM25.js} +2 -2
- package/dist/{chunk-G46JSSVX.js → chunk-RKBCUP5D.js} +7 -7
- package/dist/{chunk-GCUMOKTN.js → chunk-S2ORTQGS.js} +3 -3
- package/dist/{chunk-MRJDLXI3.js → chunk-SVXFCCSX.js} +8 -8
- package/dist/{chunk-BUE7R3B5.js → chunk-SXPLIRQH.js} +2 -2
- package/dist/{chunk-5LMCVBMY.js → chunk-T5EXREMW.js} +5 -5
- package/dist/{chunk-PT2YCQVK.js → chunk-TBVDI3LY.js} +4 -4
- package/dist/{chunk-BMHQHH7Q.js → chunk-TLIFNRU5.js} +2 -2
- package/dist/{chunk-YKGJ44Z7.js → chunk-TU6ZJTYT.js} +3 -3
- package/dist/{chunk-FSQNGPHH.js → chunk-U277K5GR.js} +612 -175
- package/dist/chunk-U277K5GR.js.map +1 -0
- package/dist/{chunk-55P6OBB7.js → chunk-U43RSPPX.js} +2 -2
- package/dist/{chunk-K7RW7FI4.js → chunk-UADW5NOU.js} +5 -5
- package/dist/{chunk-GRS2HIV6.js → chunk-UMV5GBTJ.js} +2 -2
- package/dist/{chunk-4UIP3QNW.js → chunk-UNAMWK2Q.js} +2 -2
- package/dist/{chunk-J4KAPKBJ.js → chunk-UORWAG7K.js} +2 -2
- package/dist/{chunk-V55JASXO.js → chunk-UQRKAM2R.js} +3 -3
- package/dist/{chunk-2ELOCEXE.js → chunk-URGHKZPL.js} +1 -1
- package/dist/chunk-URGHKZPL.js.map +1 -0
- package/dist/{chunk-ZMVSKYTJ.js → chunk-VLRY2UH4.js} +10 -10
- package/dist/{chunk-SPPOUJLN.js → chunk-VZFTON37.js} +2 -2
- package/dist/{chunk-CAD7N6HQ.js → chunk-WIUH6EJ7.js} +10 -10
- package/dist/chunk-WIUH6EJ7.js.map +1 -0
- package/dist/{chunk-YQFBH5ZJ.js → chunk-WQUIJPN4.js} +3 -3
- package/dist/{chunk-4J3MNVVX.js → chunk-WRLWEYHY.js} +7 -1
- package/dist/{chunk-4J3MNVVX.js.map → chunk-WRLWEYHY.js.map} +1 -1
- package/dist/{chunk-NZULV7LK.js → chunk-WVQDY3UM.js} +4 -4
- package/dist/{chunk-3Y5JLSXS.js → chunk-X5RGG3ZW.js} +2 -2
- package/dist/{chunk-PFCTSXHU.js → chunk-X6Z2SIRF.js} +2 -2
- package/dist/{chunk-UHFGK6YA.js → chunk-XQGKS4OW.js} +3 -3
- package/dist/{chunk-L2F3CFCH.js → chunk-Y22JWHCP.js} +4 -4
- package/dist/{chunk-C53ER7AG.js → chunk-YVA6UPRN.js} +2 -2
- package/dist/{chunk-226V6XXJ.js → chunk-Z2KP6PNF.js} +6 -6
- package/dist/{chunk-G5EDYVSE.js → chunk-ZK2WT532.js} +5 -5
- package/dist/{chunk-SFCD6OU7.js → chunk-ZNVBCKMV.js} +2 -2
- package/dist/{chunk-BU2ABHFW.js → chunk-ZOFNZLAA.js} +4 -4
- package/dist/{chunk-X2RP4TO5.js → chunk-ZVJKHGE5.js} +7 -7
- package/dist/classified/index.js +5 -5
- package/dist/{classified-marker-KHDOYIJB.js → classified-marker-7HXDMYHI.js} +3 -3
- package/dist/collection-facade-V63BEBGU.js +41 -0
- package/dist/{computed-XMFTHAXV.js → computed-LZLSYOPG.js} +3 -3
- package/dist/consent/index.js +8 -8
- package/dist/cover/index.js +8 -8
- package/dist/custody/index.js +12 -12
- package/dist/{dead-filter-CXV5NS67.js → dead-filter-PZIJ4F4G.js} +10 -10
- package/dist/debug/index.js +7 -7
- package/dist/delegation-7SSGIETH.js +26 -0
- package/dist/derivations/index.js +22 -22
- package/dist/derive-IMI3BMDS.js +20 -0
- package/dist/directory/index.js +9 -9
- package/dist/{dispatch-2MQFMEGY.js → dispatch-4BUYPWMJ.js} +19 -19
- package/dist/{dispatch-OFDA4WQV.js → dispatch-KOPDDPEQ.js} +5 -5
- package/dist/executor-7SY3M6TZ.js +8 -0
- package/dist/executor-SNHW4ELF.js +35 -0
- package/dist/executor-Z3IKK7G3.js +8 -0
- package/dist/export-accessible-O7DIVFUO.js +22 -0
- package/dist/extract-partition-ELZEJKXM.js +35 -0
- package/dist/{fanout-sidecar-BO67PCPO.js → fanout-sidecar-FYDRL7F3.js} +8 -8
- package/dist/find-KWB2RYWJ.js +10 -0
- package/dist/forget/index.js +8 -8
- package/dist/guards/index.js +4 -4
- package/dist/history/index.js +15 -13
- package/dist/history/index.js.map +1 -1
- package/dist/i18n/index.js +13 -13
- package/dist/index.d.ts +3 -2
- package/dist/index.js +111 -107
- package/dist/index.js.map +1 -1
- package/dist/indexing/index.js +5 -5
- package/dist/introspection/index.js +10 -10
- package/dist/issue-5ZHXK4HJ.js +19 -0
- package/dist/kernel/collection.d.ts +85 -6
- package/dist/kernel/constants.d.ts +7 -0
- package/dist/kernel/errors.d.ts +9 -0
- package/dist/kernel/merge-authority.d.ts +5 -1
- package/dist/kernel/noydb.d.ts +116 -21
- package/dist/kernel/rejection-seal.d.ts +13 -0
- package/dist/kernel/sync-wiring.d.ts +55 -0
- package/dist/kernel/types.d.ts +366 -8
- package/dist/kernel/vault.d.ts +39 -5
- package/dist/{ledger-MSJGWKGW.js → ledger-UFJCB6T5.js} +10 -10
- package/dist/liberate-OEOSNNFH.js +25 -0
- package/dist/{link-set-QXXSPPHL.js → link-set-KMUBFN2L.js} +10 -10
- package/dist/{managed-secret-VSK7ANQI.js → managed-secret-H5WYSJ46.js} +9 -9
- package/dist/materialized-views/index.js +25 -25
- package/dist/{migrate-cek-GEBFYBDC.js → migrate-cek-SPESQAAO.js} +2 -2
- package/dist/money/index.js +5 -5
- package/dist/noydb-QDZ4QIKO.js +100 -0
- package/dist/on/index.js +12 -12
- package/dist/overlay-views/index.js +4 -4
- package/dist/periods/index.js +11 -11
- package/dist/pod/index.js +66 -64
- package/dist/{pod-handle-YE7CT66T.js → pod-handle-GJLCOUGK.js} +8 -8
- package/dist/policy/index.js +9 -9
- package/dist/port/at/index.d.ts +1 -1
- package/dist/port/by/index.d.ts +1 -1
- package/dist/port/on/index.d.ts +1 -1
- package/dist/port/with/admission-authority.d.ts +34 -0
- package/dist/port/with/broker-strategy.d.ts +10 -0
- package/dist/port/with/rejection-courier.d.ts +37 -0
- package/dist/port/with/restore-host.d.ts +33 -0
- package/dist/port/with/service-bus.d.ts +18 -0
- package/dist/port/with/team-strategy.d.ts +2 -2
- package/dist/port/with/write-hooks.d.ts +2 -0
- package/dist/portability/index.js +8 -8
- package/dist/{post-register-QC5TEAW3.js → post-register-2AC2STHC.js} +6 -6
- package/dist/query/all/index.js +15 -15
- package/dist/query/index.js +7 -7
- package/dist/query/live/index.js +7 -7
- package/dist/query/reduce/index.js +10 -10
- package/dist/query/relate/index.js +9 -9
- package/dist/reduce/index.js +8 -8
- package/dist/register-PIORIMMR.js +30 -0
- package/dist/registry-BIMICFUH.js +23 -0
- package/dist/registry-JGWLW53D.js +35 -0
- package/dist/registry-SELCBYEQ.js +8 -0
- package/dist/registry-W327UNYH.js +8 -0
- package/dist/request-withdrawal-K3SXXODI.js +28 -0
- package/dist/restore-to-OOPKLAPU.js +66 -0
- package/dist/restore-to-OOPKLAPU.js.map +1 -0
- package/dist/{reveal-YQTRNQFH.js → reveal-UAPBG743.js} +7 -7
- package/dist/revoke-6AFVXTWF.js +24 -0
- package/dist/satellites/index.js +1 -1
- package/dist/schema-update/index.js +2 -2
- package/dist/sealed-record/index.js +11 -11
- package/dist/search/index.js +4 -4
- package/dist/{seed-JMQTRKRE.js → seed-BVYDPVIW.js} +33 -18
- package/dist/seed-BVYDPVIW.js.map +1 -0
- package/dist/sequence/index.js +8 -8
- package/dist/session/index.js +8 -8
- package/dist/shadow/index.js +2 -2
- package/dist/signer-TW5MAQJP.js +23 -0
- package/dist/snapshots/index.js +9 -9
- package/dist/{stale-SKV33PBU.js → stale-CROGJBIJ.js} +9 -9
- package/dist/storage-SO2L2Z5J.js +21 -0
- package/dist/{store-coordination-provider-Z6HKPOGM.js → store-coordination-provider-2YD2PTTP.js} +9 -9
- package/dist/sync/index.js +16 -16
- package/dist/sync/index.js.map +1 -1
- package/dist/team/index.js +15 -15
- package/dist/tiers/index.js +10 -10
- package/dist/to/index.js +2 -2
- package/dist/transactions/index.js +3 -3
- package/dist/util/index.js +1 -1
- package/dist/vault-head/index.js +7 -7
- package/dist/{verify-KWQIWLGH.js → verify-QWO5UKD6.js} +7 -7
- package/dist/walk-3KEOL7BY.js +20 -0
- package/dist/with-audit/guards/types.d.ts +2 -0
- package/dist/with-audit/tiers/index.d.ts +5 -5
- package/dist/with-commit/history/history.d.ts +16 -0
- package/dist/with-commit/history/restore-to.d.ts +40 -0
- package/dist/with-party/broker/seed.d.ts +4 -0
- package/dist/with-party/custody/strategy.d.ts +2 -2
- package/dist/with-party/team/delegation.d.ts +41 -11
- package/dist/with-party/team/index.d.ts +2 -0
- package/dist/with-party/team/keyring.d.ts +133 -3
- package/dist/with-party/team/managed-secret.d.ts +1 -1
- package/dist/with-party/team/noydb-facade.d.ts +14 -2
- package/dist/with-party/team/roster-tag.d.ts +1 -1
- package/dist/with-pod/backup.d.ts +9 -17
- package/dist/with-sync/active.d.ts +28 -1
- package/dist/with-sync/engine.d.ts +59 -2
- package/dist/with-sync/index.d.ts +1 -0
- package/dist/with-sync/reserved-mirror.d.ts +27 -4
- package/dist/with-sync/strategy.d.ts +2 -0
- package/dist/withdraw-accessible-OZU525ND.js +25 -0
- package/dist/withdraw-accessible-OZU525ND.js.map +1 -0
- package/package.json +3 -3
- package/dist/api-MSJXVYQG.js +0 -18
- package/dist/backup-7RKNZMQO.js.map +0 -1
- package/dist/chunk-2A56DSRI.js.map +0 -1
- package/dist/chunk-2ELOCEXE.js.map +0 -1
- package/dist/chunk-45VHWE4C.js.map +0 -1
- package/dist/chunk-72XBVN4J.js.map +0 -1
- package/dist/chunk-APFFJN5T.js.map +0 -1
- package/dist/chunk-CAD7N6HQ.js.map +0 -1
- package/dist/chunk-CB4467G3.js.map +0 -1
- package/dist/chunk-FSQNGPHH.js.map +0 -1
- package/dist/chunk-GOJQ5DZA.js.map +0 -1
- package/dist/chunk-JA25QG5M.js.map +0 -1
- package/dist/chunk-JBMMWYOH.js.map +0 -1
- package/dist/chunk-VSUQI5Q6.js.map +0 -1
- package/dist/chunk-XKBTJGFP.js.map +0 -1
- package/dist/chunk-Z3ZXVB2Y.js.map +0 -1
- package/dist/collection-facade-LZIF7GWD.js +0 -41
- package/dist/delegation-ONLM4JFI.js.map +0 -1
- package/dist/derive-3YSIS36W.js +0 -20
- package/dist/executor-E6YDJ7YA.js +0 -8
- package/dist/executor-NJX3YQQ4.js +0 -35
- package/dist/executor-WWM3DD4P.js +0 -8
- package/dist/export-accessible-RLHU5G4W.js +0 -22
- package/dist/extract-partition-QII2EDCS.js +0 -35
- package/dist/find-6M7GYDUZ.js +0 -10
- package/dist/issue-LPEEEMPP.js +0 -19
- package/dist/liberate-LEKDYKTC.js +0 -25
- package/dist/noydb-F2AUF6KL.js +0 -98
- package/dist/register-SN72QALV.js +0 -30
- package/dist/registry-253FF7C6.js +0 -35
- package/dist/registry-3AZWQTDT.js +0 -23
- package/dist/registry-7UEBTHWG.js +0 -8
- package/dist/registry-IVJ67NFQ.js +0 -8
- package/dist/request-withdrawal-UKVJZKX2.js +0 -28
- package/dist/revoke-G2KXJQA5.js +0 -24
- package/dist/seed-JMQTRKRE.js.map +0 -1
- package/dist/signer-IUIYR3CX.js +0 -23
- package/dist/storage-NPBYP2SM.js +0 -21
- package/dist/walk-F4OLXI5H.js +0 -20
- package/dist/withdraw-accessible-ZKPLZ66E.js +0 -25
- /package/dist/{api-MSJXVYQG.js.map → api-H4B7ZQXP.js.map} +0 -0
- /package/dist/{capsule-57BDK7LG.js.map → capsule-YQKQZPH7.js.map} +0 -0
- /package/dist/{chunk-AJFPAHMW.js.map → chunk-27NCEPKM.js.map} +0 -0
- /package/dist/{chunk-PGC35KXE.js.map → chunk-2IASHJPS.js.map} +0 -0
- /package/dist/{chunk-NYJBYVBG.js.map → chunk-2ODEFG6K.js.map} +0 -0
- /package/dist/{chunk-7BMOS4JQ.js.map → chunk-2QH3I7QC.js.map} +0 -0
- /package/dist/{chunk-IVMFIKNA.js.map → chunk-2T2TGRWE.js.map} +0 -0
- /package/dist/{chunk-G66YXUTY.js.map → chunk-35CNOVQE.js.map} +0 -0
- /package/dist/{chunk-OJU67C23.js.map → chunk-3EXQXOQ2.js.map} +0 -0
- /package/dist/{chunk-BJH77UY2.js.map → chunk-4KYKRYRT.js.map} +0 -0
- /package/dist/{chunk-RDOEOPOI.js.map → chunk-4N4OIVK3.js.map} +0 -0
- /package/dist/{chunk-WHOKGHJ3.js.map → chunk-4WLI37WK.js.map} +0 -0
- /package/dist/{chunk-RNACRT5H.js.map → chunk-52ZFNK46.js.map} +0 -0
- /package/dist/{chunk-QDHHHI5Q.js.map → chunk-5SMCBPJ2.js.map} +0 -0
- /package/dist/{chunk-EMAWOGVH.js.map → chunk-654RE5YC.js.map} +0 -0
- /package/dist/{chunk-FZXRLNJO.js.map → chunk-6BEBWHNL.js.map} +0 -0
- /package/dist/{chunk-EUD3HQM4.js.map → chunk-6WEPFEMJ.js.map} +0 -0
- /package/dist/{chunk-YFFMPZPY.js.map → chunk-6WIFF46H.js.map} +0 -0
- /package/dist/{chunk-ZVSKSUGI.js.map → chunk-7C7OF26T.js.map} +0 -0
- /package/dist/{chunk-QXJXG7DN.js.map → chunk-7IV7GVOS.js.map} +0 -0
- /package/dist/{chunk-MQ7YWBQ5.js.map → chunk-7JRLCP2J.js.map} +0 -0
- /package/dist/{chunk-QSHATAXJ.js.map → chunk-7ONMS7QI.js.map} +0 -0
- /package/dist/{chunk-6WS35E6X.js.map → chunk-A52BK5AY.js.map} +0 -0
- /package/dist/{chunk-XXQ5XIYY.js.map → chunk-AMSSAOOB.js.map} +0 -0
- /package/dist/{chunk-3V6LZHUO.js.map → chunk-AYOQZJDB.js.map} +0 -0
- /package/dist/{chunk-DL6BZKP3.js.map → chunk-B3B6HV5S.js.map} +0 -0
- /package/dist/{chunk-5XONHAFD.js.map → chunk-B6EWMGFX.js.map} +0 -0
- /package/dist/{chunk-6Y5E4SJU.js.map → chunk-BMAXBTYH.js.map} +0 -0
- /package/dist/{chunk-LGGIFKJP.js.map → chunk-BNYDOF2Q.js.map} +0 -0
- /package/dist/{chunk-XXNWU5QZ.js.map → chunk-BQJ5ORU5.js.map} +0 -0
- /package/dist/{chunk-BYHCKX73.js.map → chunk-CLOSXHR4.js.map} +0 -0
- /package/dist/{chunk-5HNW4ZTA.js.map → chunk-CSAN22QG.js.map} +0 -0
- /package/dist/{chunk-TZYTMZZY.js.map → chunk-DL4GCSTS.js.map} +0 -0
- /package/dist/{chunk-EA4VDI5D.js.map → chunk-DYIR6RC3.js.map} +0 -0
- /package/dist/{chunk-PUBI455O.js.map → chunk-EPPAEGH5.js.map} +0 -0
- /package/dist/{chunk-BNFNQNEP.js.map → chunk-F7X7MPK4.js.map} +0 -0
- /package/dist/{chunk-SNM7LSYG.js.map → chunk-FUHUGKDN.js.map} +0 -0
- /package/dist/{chunk-D4V5JJAK.js.map → chunk-GHMINSER.js.map} +0 -0
- /package/dist/{chunk-QGFEBNHO.js.map → chunk-GZISWBCJ.js.map} +0 -0
- /package/dist/{chunk-OM3SEDI4.js.map → chunk-HTRLQ4ZZ.js.map} +0 -0
- /package/dist/{chunk-SWXLZ4HX.js.map → chunk-ICHHNI5E.js.map} +0 -0
- /package/dist/{chunk-K673OO6B.js.map → chunk-ID4ZBC3X.js.map} +0 -0
- /package/dist/{chunk-H3YM66EI.js.map → chunk-IF2M43G4.js.map} +0 -0
- /package/dist/{chunk-QGSNJD3B.js.map → chunk-IFUYLIEY.js.map} +0 -0
- /package/dist/{chunk-D5A3GCZ4.js.map → chunk-IPF5ORDI.js.map} +0 -0
- /package/dist/{chunk-BVF3SXD7.js.map → chunk-KBIS64X4.js.map} +0 -0
- /package/dist/{chunk-RIZTZJX6.js.map → chunk-LJ744WXU.js.map} +0 -0
- /package/dist/{chunk-L5A3KR7R.js.map → chunk-LUQBG637.js.map} +0 -0
- /package/dist/{chunk-6QLCS7ET.js.map → chunk-LZN6DTFI.js.map} +0 -0
- /package/dist/{chunk-NIXRB5BP.js.map → chunk-MMWX5OT5.js.map} +0 -0
- /package/dist/{chunk-UOZOWN73.js.map → chunk-ND6S2DKC.js.map} +0 -0
- /package/dist/{chunk-WFWFXDNS.js.map → chunk-NHEKQWFI.js.map} +0 -0
- /package/dist/{chunk-2ZFD2UJC.js.map → chunk-NIUHKKMM.js.map} +0 -0
- /package/dist/{chunk-XA34THLF.js.map → chunk-NK4LGBGQ.js.map} +0 -0
- /package/dist/{chunk-JSWKVZCR.js.map → chunk-NUZ7ROUZ.js.map} +0 -0
- /package/dist/{chunk-DHU2AQ6T.js.map → chunk-O3NGOHXQ.js.map} +0 -0
- /package/dist/{chunk-ZBUAX4EF.js.map → chunk-O6VOR4NH.js.map} +0 -0
- /package/dist/{chunk-JZ4EDEIP.js.map → chunk-ODBOHPZU.js.map} +0 -0
- /package/dist/{chunk-5UUJE4FP.js.map → chunk-OK44MD3C.js.map} +0 -0
- /package/dist/{chunk-ECGXA4LT.js.map → chunk-OR3OHKU6.js.map} +0 -0
- /package/dist/{chunk-ZWF3EWZA.js.map → chunk-P6FATPXQ.js.map} +0 -0
- /package/dist/{chunk-PCYPXLEX.js.map → chunk-PBEHTFUG.js.map} +0 -0
- /package/dist/{chunk-7CT6SX4M.js.map → chunk-PFHDQY5L.js.map} +0 -0
- /package/dist/{chunk-PTJY5R3O.js.map → chunk-PIO6NW7O.js.map} +0 -0
- /package/dist/{chunk-TMIJAR2X.js.map → chunk-PREYKC76.js.map} +0 -0
- /package/dist/{chunk-ZHQJAV6D.js.map → chunk-PU5ZEV65.js.map} +0 -0
- /package/dist/{chunk-UNSQZSZP.js.map → chunk-PWAMX5KU.js.map} +0 -0
- /package/dist/{chunk-GETUTTZU.js.map → chunk-PZN76MMV.js.map} +0 -0
- /package/dist/{chunk-ABU6A4Z5.js.map → chunk-Q4DBU5RM.js.map} +0 -0
- /package/dist/{chunk-2WJKJZSO.js.map → chunk-QHG7GQKM.js.map} +0 -0
- /package/dist/{chunk-UAKY6E4N.js.map → chunk-QNOWNCZS.js.map} +0 -0
- /package/dist/{chunk-JPSL5GIZ.js.map → chunk-QQLXKDGC.js.map} +0 -0
- /package/dist/{chunk-OK57EATL.js.map → chunk-R4GLRJ55.js.map} +0 -0
- /package/dist/{chunk-B65CC6Z6.js.map → chunk-RF5WDM25.js.map} +0 -0
- /package/dist/{chunk-G46JSSVX.js.map → chunk-RKBCUP5D.js.map} +0 -0
- /package/dist/{chunk-GCUMOKTN.js.map → chunk-S2ORTQGS.js.map} +0 -0
- /package/dist/{chunk-MRJDLXI3.js.map → chunk-SVXFCCSX.js.map} +0 -0
- /package/dist/{chunk-BUE7R3B5.js.map → chunk-SXPLIRQH.js.map} +0 -0
- /package/dist/{chunk-5LMCVBMY.js.map → chunk-T5EXREMW.js.map} +0 -0
- /package/dist/{chunk-PT2YCQVK.js.map → chunk-TBVDI3LY.js.map} +0 -0
- /package/dist/{chunk-BMHQHH7Q.js.map → chunk-TLIFNRU5.js.map} +0 -0
- /package/dist/{chunk-YKGJ44Z7.js.map → chunk-TU6ZJTYT.js.map} +0 -0
- /package/dist/{chunk-55P6OBB7.js.map → chunk-U43RSPPX.js.map} +0 -0
- /package/dist/{chunk-K7RW7FI4.js.map → chunk-UADW5NOU.js.map} +0 -0
- /package/dist/{chunk-GRS2HIV6.js.map → chunk-UMV5GBTJ.js.map} +0 -0
- /package/dist/{chunk-4UIP3QNW.js.map → chunk-UNAMWK2Q.js.map} +0 -0
- /package/dist/{chunk-J4KAPKBJ.js.map → chunk-UORWAG7K.js.map} +0 -0
- /package/dist/{chunk-V55JASXO.js.map → chunk-UQRKAM2R.js.map} +0 -0
- /package/dist/{chunk-ZMVSKYTJ.js.map → chunk-VLRY2UH4.js.map} +0 -0
- /package/dist/{chunk-SPPOUJLN.js.map → chunk-VZFTON37.js.map} +0 -0
- /package/dist/{chunk-YQFBH5ZJ.js.map → chunk-WQUIJPN4.js.map} +0 -0
- /package/dist/{chunk-NZULV7LK.js.map → chunk-WVQDY3UM.js.map} +0 -0
- /package/dist/{chunk-3Y5JLSXS.js.map → chunk-X5RGG3ZW.js.map} +0 -0
- /package/dist/{chunk-PFCTSXHU.js.map → chunk-X6Z2SIRF.js.map} +0 -0
- /package/dist/{chunk-UHFGK6YA.js.map → chunk-XQGKS4OW.js.map} +0 -0
- /package/dist/{chunk-L2F3CFCH.js.map → chunk-Y22JWHCP.js.map} +0 -0
- /package/dist/{chunk-C53ER7AG.js.map → chunk-YVA6UPRN.js.map} +0 -0
- /package/dist/{chunk-226V6XXJ.js.map → chunk-Z2KP6PNF.js.map} +0 -0
- /package/dist/{chunk-G5EDYVSE.js.map → chunk-ZK2WT532.js.map} +0 -0
- /package/dist/{chunk-SFCD6OU7.js.map → chunk-ZNVBCKMV.js.map} +0 -0
- /package/dist/{chunk-BU2ABHFW.js.map → chunk-ZOFNZLAA.js.map} +0 -0
- /package/dist/{chunk-X2RP4TO5.js.map → chunk-ZVJKHGE5.js.map} +0 -0
- /package/dist/{classified-marker-KHDOYIJB.js.map → classified-marker-7HXDMYHI.js.map} +0 -0
- /package/dist/{collection-facade-LZIF7GWD.js.map → collection-facade-V63BEBGU.js.map} +0 -0
- /package/dist/{computed-XMFTHAXV.js.map → computed-LZLSYOPG.js.map} +0 -0
- /package/dist/{dead-filter-CXV5NS67.js.map → dead-filter-PZIJ4F4G.js.map} +0 -0
- /package/dist/{derive-3YSIS36W.js.map → delegation-7SSGIETH.js.map} +0 -0
- /package/dist/{executor-E6YDJ7YA.js.map → derive-IMI3BMDS.js.map} +0 -0
- /package/dist/{dispatch-2MQFMEGY.js.map → dispatch-4BUYPWMJ.js.map} +0 -0
- /package/dist/{dispatch-OFDA4WQV.js.map → dispatch-KOPDDPEQ.js.map} +0 -0
- /package/dist/{executor-NJX3YQQ4.js.map → executor-7SY3M6TZ.js.map} +0 -0
- /package/dist/{executor-WWM3DD4P.js.map → executor-SNHW4ELF.js.map} +0 -0
- /package/dist/{export-accessible-RLHU5G4W.js.map → executor-Z3IKK7G3.js.map} +0 -0
- /package/dist/{extract-partition-QII2EDCS.js.map → export-accessible-O7DIVFUO.js.map} +0 -0
- /package/dist/{find-6M7GYDUZ.js.map → extract-partition-ELZEJKXM.js.map} +0 -0
- /package/dist/{fanout-sidecar-BO67PCPO.js.map → fanout-sidecar-FYDRL7F3.js.map} +0 -0
- /package/dist/{issue-LPEEEMPP.js.map → find-KWB2RYWJ.js.map} +0 -0
- /package/dist/{ledger-MSJGWKGW.js.map → issue-5ZHXK4HJ.js.map} +0 -0
- /package/dist/{liberate-LEKDYKTC.js.map → ledger-UFJCB6T5.js.map} +0 -0
- /package/dist/{link-set-QXXSPPHL.js.map → liberate-OEOSNNFH.js.map} +0 -0
- /package/dist/{managed-secret-VSK7ANQI.js.map → link-set-KMUBFN2L.js.map} +0 -0
- /package/dist/{noydb-F2AUF6KL.js.map → managed-secret-H5WYSJ46.js.map} +0 -0
- /package/dist/{migrate-cek-GEBFYBDC.js.map → migrate-cek-SPESQAAO.js.map} +0 -0
- /package/dist/{register-SN72QALV.js.map → noydb-QDZ4QIKO.js.map} +0 -0
- /package/dist/{pod-handle-YE7CT66T.js.map → pod-handle-GJLCOUGK.js.map} +0 -0
- /package/dist/{post-register-QC5TEAW3.js.map → post-register-2AC2STHC.js.map} +0 -0
- /package/dist/{registry-253FF7C6.js.map → register-PIORIMMR.js.map} +0 -0
- /package/dist/{registry-3AZWQTDT.js.map → registry-BIMICFUH.js.map} +0 -0
- /package/dist/{registry-7UEBTHWG.js.map → registry-JGWLW53D.js.map} +0 -0
- /package/dist/{registry-IVJ67NFQ.js.map → registry-SELCBYEQ.js.map} +0 -0
- /package/dist/{request-withdrawal-UKVJZKX2.js.map → registry-W327UNYH.js.map} +0 -0
- /package/dist/{revoke-G2KXJQA5.js.map → request-withdrawal-K3SXXODI.js.map} +0 -0
- /package/dist/{reveal-YQTRNQFH.js.map → reveal-UAPBG743.js.map} +0 -0
- /package/dist/{signer-IUIYR3CX.js.map → revoke-6AFVXTWF.js.map} +0 -0
- /package/dist/{stale-SKV33PBU.js.map → signer-TW5MAQJP.js.map} +0 -0
- /package/dist/{storage-NPBYP2SM.js.map → stale-CROGJBIJ.js.map} +0 -0
- /package/dist/{walk-F4OLXI5H.js.map → storage-SO2L2Z5J.js.map} +0 -0
- /package/dist/{store-coordination-provider-Z6HKPOGM.js.map → store-coordination-provider-2YD2PTTP.js.map} +0 -0
- /package/dist/{verify-KWQIWLGH.js.map → verify-QWO5UKD6.js.map} +0 -0
- /package/dist/{withdraw-accessible-ZKPLZ66E.js.map → walk-3KEOL7BY.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/with-sync/presence.ts","../src/with-sync/reserved-mirror.ts","../src/with-sync/period-scope.ts","../src/with-sync/engine.ts","../src/with-sync/transaction.ts"],"sourcesContent":["/**\n * Presence handle — real-time awareness of who is viewing/editing a collection.\n * encrypted ephemeral channel keyed by collection DEK via HKDF.\n *\n * The presence key is derived from the collection DEK so:\n * - The adapter never learns user identities from presence payloads.\n * - Presence rotates automatically when the DEK rotates (revoked users\n * can no longer participate after a DEK rotation).\n *\n * Two transport strategies:\n * 1. **Pub/sub** (real-time): used when the adapter implements\n * `presencePublish` and `presenceSubscribe`.\n * 2. **Storage-poll** (fallback): presence records are written to a\n * reserved `_presence_<collection>` collection on the sync adapter\n * (if available) or local adapter, and polled periodically.\n */\n\nimport { buildRecordEnvelope } from '../capsule/index.js'\nimport type { NoydbStore, PresencePeer } from '../kernel/types.js'\nimport {\n encrypt, decrypt, derivePresenceKey, derivePresenceTagKey, hmacSignHex, type EnclaveKey,\n} from '../capsule/index.js'\n\n/** Options for constructing a PresenceHandle. @internal */\nexport interface PresenceHandleOpts {\n /** Local adapter for storage-poll fallback. */\n adapter: NoydbStore\n /** Remote (sync) adapter — preferred for broadcasting presence if available. */\n syncAdapter?: NoydbStore\n /** Vault name — used as part of the channel and storage key. */\n vault: string\n /** Collection name — used as HKDF `info` and channel suffix. */\n collectionName: string\n /**\n * Calling user's ID. In encrypted mode it is encrypted inside the\n * storage-poll record's `data` field — the record id is an\n * adapter-opaque HMAC tag, not the userId, so the adapter never learns\n * peer identities. Unencrypted vaults have no key to tag or encrypt\n * with, so the userId is used as the record id in cleartext (dev posture\n * only — identity privacy requires encryption).\n */\n userId: string\n /** Whether encryption is active. When false, presence payloads are stored as JSON. */\n encrypted: boolean\n /** Callback that resolves the collection DEK (used to derive the presence key). */\n getDEK: (collectionName: string) => Promise<EnclaveKey>\n /** How long (ms) before a peer's presence is considered stale. Default: 30_000. */\n staleMs?: number\n /** Poll interval (ms) for the storage-poll fallback. Default: 5_000. */\n pollIntervalMs?: number\n}\n\n/**\n * Internal storage envelope for the storage-poll fallback.\n * Written to `_presence_<collection>` as `{ lastSeen, iv, data }`.\n *\n * In encrypted mode `data` is ciphertext of `{ userId, payload }` — the\n * userId rides inside the encrypted payload, never as a top-level field, and\n * the record's storage id is a separate HMAC tag (see `presenceTag`), not\n * the userId. In unencrypted mode `data` is `JSON.stringify(payload)` and\n * the record id IS the (cleartext) userId — there is no key to tag with.\n */\ninterface StoragePresenceRecord {\n lastSeen: string\n iv: string // base64 AES-GCM IV (empty when not encrypted)\n data: string // base64 ciphertext or JSON string when not encrypted\n}\n\n/** Presence handle for a single collection. */\nexport class PresenceHandle<P> {\n private readonly adapter: NoydbStore\n private readonly syncAdapter: NoydbStore | undefined\n private readonly vault: string\n private readonly collectionName: string\n private readonly userId: string\n private readonly encrypted: boolean\n private readonly getDEK: (collectionName: string) => Promise<EnclaveKey>\n private readonly staleMs: number\n private readonly pollIntervalMs: number\n private readonly channel: string\n private readonly storageCollection: string\n\n private presenceKey: EnclaveKey | null = null\n private presenceTagKey: EnclaveKey | null = null\n private subscribers: Array<(peers: PresencePeer<P>[]) => void> = []\n private unsubscribePubSub: (() => void) | null = null\n private pollTimer: ReturnType<typeof setInterval> | null = null\n private stopped = false\n\n constructor(opts: PresenceHandleOpts) {\n this.adapter = opts.adapter\n this.syncAdapter = opts.syncAdapter\n this.vault = opts.vault\n this.collectionName = opts.collectionName\n this.userId = opts.userId\n this.encrypted = opts.encrypted\n this.getDEK = opts.getDEK\n this.staleMs = opts.staleMs ?? 30_000\n this.pollIntervalMs = opts.pollIntervalMs ?? 5_000\n // Channel used by pub/sub adapters — vault-scoped so two collections\n // in the same vault don't bleed into each other's presence channels.\n this.channel = `${opts.vault}:${opts.collectionName}:presence`\n // Reserved collection name for the storage-poll fallback.\n this.storageCollection = `_presence_${opts.collectionName}`\n }\n\n /**\n * Announce yourself (or update your cursor/status).\n * Encrypts `payload` with the presence key and publishes it.\n */\n async update(payload: P): Promise<void> {\n if (this.stopped) return\n\n const key = await this.getPresenceKey()\n const now = new Date().toISOString()\n const plaintext = JSON.stringify({ userId: this.userId, lastSeen: now, payload })\n let encryptedPayload: string\n\n if (this.encrypted && key) {\n const { iv, data } = await encrypt(plaintext, key)\n encryptedPayload = JSON.stringify({ iv, data })\n } else {\n encryptedPayload = plaintext\n }\n\n // Pub/sub path — publish to any adapter that supports it\n const pubAdapter = this.getPubSubAdapter()\n if (pubAdapter?.presencePublish) {\n await pubAdapter.presencePublish(this.channel, encryptedPayload)\n }\n\n // Storage-poll path — write a record to the storage adapter\n await this.writeStorageRecord(payload, now)\n }\n\n /**\n * Subscribe to presence updates. The callback receives a filtered, decrypted\n * list of all currently-active peers (excluding yourself, excluding stale).\n *\n * Returns an unsubscribe function. Also call `stop()` to release all resources.\n */\n subscribe(cb: (peers: PresencePeer<P>[]) => void): () => void {\n if (this.stopped) return () => {}\n\n this.subscribers.push(cb)\n\n // Start pub/sub listener on first subscriber\n if (this.subscribers.length === 1) {\n this.startListening()\n }\n\n return () => {\n this.subscribers = this.subscribers.filter(s => s !== cb)\n if (this.subscribers.length === 0) this.stopListening()\n }\n }\n\n /** Stop all listening and clear resources. */\n stop(): void {\n this.stopped = true\n this.stopListening()\n this.subscribers = []\n }\n\n // ─── Private ────────────────────────────────────────────────────────\n\n private async getPresenceKey(): Promise<EnclaveKey | null> {\n if (!this.encrypted) return null\n if (!this.presenceKey) {\n try {\n const dek = await this.getDEK(this.collectionName)\n this.presenceKey = await derivePresenceKey(dek, this.collectionName)\n } catch {\n // no-op — presence degrades gracefully if crypto fails\n }\n }\n return this.presenceKey\n }\n\n /**\n * Derive (and cache) the presence-tag key — a non-extractable, sign-only\n * HMAC-SHA256 key HKDF-derived from the collection DEK, domain-separated\n * from the presence payload key by the enclave's `derivePresenceTagKey`\n * domain. Mirrors `deriveClassifyIndexKey` (capsule/enclave-aes/classify/bidx.ts).\n * No PBKDF2 stretch — the adapter never holds this key, so a plain keyed\n * HMAC tag is sufficient and deterministic. Returns `null` when unencrypted\n * (no DEK to derive from).\n */\n private async getPresenceTagKey(): Promise<EnclaveKey | null> {\n if (!this.encrypted) return null\n if (!this.presenceTagKey) {\n try {\n const dek = await this.getDEK(this.collectionName)\n this.presenceTagKey = await derivePresenceTagKey(dek, this.collectionName)\n } catch {\n // no-op — presence degrades gracefully if crypto fails\n }\n }\n return this.presenceTagKey\n }\n\n /**\n * Deterministic, adapter-opaque tag for `userId` — used as the\n * storage-poll record id in encrypted mode so the adapter never sees the\n * userId. Falls back to the raw `userId` when unencrypted (no key exists\n * to tag with — see {@link PresenceHandleOpts.userId}).\n */\n private async presenceTag(userId: string): Promise<string> {\n const tagKey = await this.getPresenceTagKey()\n if (!tagKey) return userId\n return hmacSignHex(tagKey, new TextEncoder().encode(userId))\n }\n\n private getPubSubAdapter(): NoydbStore | undefined {\n // Prefer the sync adapter (it broadcasts to other devices)\n if (this.syncAdapter?.presencePublish) return this.syncAdapter\n if (this.adapter.presencePublish) return this.adapter\n return undefined\n }\n\n private startListening(): void {\n const pubAdapter = this.getPubSubAdapter()\n\n if (pubAdapter?.presenceSubscribe) {\n // Real-time pub/sub path\n this.unsubscribePubSub = pubAdapter.presenceSubscribe(\n this.channel,\n (encryptedPayload) => { void this.handlePubSubMessage(encryptedPayload) },\n )\n } else {\n // Storage-poll fallback\n this.pollTimer = setInterval(\n () => { void this.pollStoragePresence() },\n this.pollIntervalMs,\n )\n // Kick off an immediate poll\n void this.pollStoragePresence()\n }\n }\n\n private stopListening(): void {\n if (this.unsubscribePubSub) {\n this.unsubscribePubSub()\n this.unsubscribePubSub = null\n }\n if (this.pollTimer) {\n clearInterval(this.pollTimer)\n this.pollTimer = null\n }\n }\n\n private async handlePubSubMessage(encryptedPayload: string): Promise<void> {\n try {\n const peer = await this.decryptPresencePayload(encryptedPayload)\n if (!peer || peer.userId === this.userId) return\n\n const cutoff = new Date(Date.now() - this.staleMs).toISOString()\n if (peer.lastSeen < cutoff) return\n\n // Deliver only this new peer to subscribers; a full snapshot poll follows\n // on next interval. For pub/sub, we could maintain a map of active peers,\n // but for simplicity: emit a snapshot read from storage.\n await this.pollStoragePresence()\n } catch {\n // Decrypt failure — stale key or tampered payload, ignore\n }\n }\n\n private async decryptPresencePayload(\n encryptedPayload: string,\n ): Promise<{ userId: string; lastSeen: string; payload: P } | null> {\n const key = await this.getPresenceKey()\n\n if (!this.encrypted || !key) {\n return JSON.parse(encryptedPayload) as { userId: string; lastSeen: string; payload: P }\n }\n\n const { iv: ivB64, data } = JSON.parse(encryptedPayload) as { iv: string; data: string }\n const plaintext = await decrypt(ivB64, data, key)\n return JSON.parse(plaintext) as { userId: string; lastSeen: string; payload: P }\n }\n\n private async writeStorageRecord(payload: P, now: string): Promise<void> {\n const key = await this.getPresenceKey()\n let iv = ''\n let data: string\n let recordId: string\n\n if (this.encrypted && key) {\n // userId rides INSIDE the ciphertext, like the pub/sub path — the\n // adapter never sees it. The record id is a separate deterministic\n // tag, also opaque to the adapter.\n const plaintext = JSON.stringify({ userId: this.userId, payload })\n const result = await encrypt(plaintext, key)\n iv = result.iv\n data = result.data\n recordId = await this.presenceTag(this.userId)\n } else {\n // Unencrypted vault — no key exists to tag or encrypt with.\n data = JSON.stringify(payload)\n recordId = this.userId\n }\n\n const record: StoragePresenceRecord = { lastSeen: now, iv, data }\n const json = JSON.stringify(record)\n\n // Use the sync adapter if available (so other devices can read it);\n // fall back to local adapter.\n const storeAdapter = this.syncAdapter ?? this.adapter\n const envelope = buildRecordEnvelope(\n { collection: this.storageCollection, id: recordId, version: 1 },\n { ts: now, iv: '', data: json },\n )\n try {\n await storeAdapter.put(\n this.vault,\n this.storageCollection,\n recordId,\n envelope,\n )\n } catch {\n // Presence write failure is non-fatal — the user is still present locally\n }\n }\n\n private async pollStoragePresence(): Promise<void> {\n if (this.stopped || this.subscribers.length === 0) return\n\n try {\n const key = await this.getPresenceKey()\n const storeAdapter = this.syncAdapter ?? this.adapter\n const ids = await storeAdapter.list(this.vault, this.storageCollection)\n const cutoff = new Date(Date.now() - this.staleMs).toISOString()\n const peers: PresencePeer<P>[] = []\n const myTag = await this.presenceTag(this.userId)\n\n for (const id of ids) {\n if (id === myTag) continue // skip ourselves\n const envelope = await storeAdapter.get(this.vault, this.storageCollection, id)\n if (!envelope) continue\n\n try {\n const record = JSON.parse(envelope._data ?? '') as StoragePresenceRecord\n if (record.lastSeen < cutoff) continue\n\n let peerUserId: string\n let peerPayload: P\n if (this.encrypted && key && record.iv) {\n const plaintext = await decrypt(record.iv, record.data, key)\n const decoded = JSON.parse(plaintext) as { userId: string; payload: P }\n peerUserId = decoded.userId\n peerPayload = decoded.payload\n } else {\n // Unencrypted mode: the record id IS the userId (see writeStorageRecord).\n peerUserId = id\n peerPayload = JSON.parse(record.data) as P\n }\n\n peers.push({ userId: peerUserId, payload: peerPayload, lastSeen: record.lastSeen })\n } catch {\n // One bad record (e.g. a pre-fix record that fails to decrypt\n // under a new reader) shouldn't blank the whole snapshot — skip\n // just this record.\n continue\n }\n }\n\n for (const cb of this.subscribers) {\n cb(peers)\n }\n } catch {\n // Poll failure is non-fatal\n }\n }\n}\n","/**\n * Reserved-record replication between two stores (core#75, core#83, core#82).\n *\n * `loadAll()` skips every `_`-prefixed collection, so nothing reserved\n * travels through a sync target unless it is named here. `_keyring` was the\n * first (core#75): a target was never a full replica — a device that lost\n * its local store re-opened by MINTING a new owner keyring whose DEKs open\n * nothing, and a granted member could not open on their own device at all.\n * The invite audit doc was the second (core#83): `acceptInvite` refuses\n * without it, by design, so magic-link onboarding onto a fresh sync-peer\n * device was closed.\n *\n * ## Declared, never blanket\n *\n * `_meta` mixes VAULT state (deed, adoption, recovery docs, invite audit\n * docs) with DEVICE/SESSION state (`schema-fence`, the pod `handle`) that\n * must never reach another device — a replicated fence would break every\n * other device's cutover. So replication is a declared set of\n * `(collection, id prefix)` rules, each with its own ordering, and a\n * reserved record travels only when a rule names it. The decision per\n * collection, written down (core#82):\n *\n * | collection | rule | why |\n * |---|---|---|\n * | `_keyring` | higher `roster_epoch` wins | the roster; replay-anchored by #1097 |\n * | `_meta/invite-audit-*` | higher `_v` wins | single-use evidence for magic links (core#83) |\n * | `_users` | higher `_v` wins | the directory's user envelopes; a member app renders these |\n * | `_delegations` | higher `_v` wins | delegation tokens; revocation is a delete |\n * | `_broker`, `_broker_member` | higher `_v` wins | broker seeds (core#91) — sealed under DEKs only their holder has; a fresh device mints from them |\n * | `_history`, `_ledger` | NOT replicated | per-device evidence: the ledger is a hash chain per writer, two devices appending would fork it; `vault.at(T)` runs where history lives |\n * | `_sync_rejections` | higher `_v` wins | core#107 — the arbiter's refusals, sealed under the refused record's own collection DEK |\n * | `_sync` | NOT replicated | this device's dirty log and watermarks |\n * | `_meta/schema-fence`, `_meta/handle`, other `_meta` | NOT replicated | session and instance state; the rest of `_meta` is decided one id at a time |\n *\n * DEK-free by construction: every rule compares a field the mover can read\n * without a key — `roster_epoch` (plaintext JSON on purpose, #1097, read\n * through `team/keyring.ts`'s parser) or the envelope's `_v`.\n *\n * ## The one rule, both directions\n *\n * **The candidate wins when it supersedes; the absent side receives; equal\n * is a no-op.** For `_keyring`, a file with no epoch (pre-#1097) never\n * overwrites one that has an epoch. Why an ordering and not bytes: a device\n * holding a STALE copy (epoch 3, or `_v` 1) must not push it over the newer\n * one (epoch 4, `_v` 2) — byte-difference alone would re-introduce exactly\n * the replay the ordering exists to anchor.\n *\n * ## Deletion\n *\n * A revocation (keyring, delegation, user envelope) deletes the record on\n * the acting device and is pushed through the dirty log as\n * `(collection, id, 'delete')`. On PULL, a record the remote lacks and the\n * local holds is deleted locally only when (a) the remote carries at least\n * one KEYRING file — a target never pushed to is not evidence of revocation,\n * but a collection that emptied by revocation is exactly what must propagate\n * (core#91) — and (b) no dirty entry protects it (a grant made offline, not\n * yet pushed). Invite audit docs are never deleted; revocation is a\n * field update, which the `_v` rule carries.\n */\nimport type { NoydbStore, EncryptedEnvelope } from '../kernel/types.js'\nimport { parseKeyringEnvelope } from '../with-party/team/keyring.js'\nimport { REJECTIONS_COLLECTION } from '../kernel/rejection-seal.js'\n\nconst KEYRING_COLLECTION = '_keyring'\n\ninterface ReservedReplicationRule {\n readonly collection: string\n /** Only ids starting with this prefix are in scope; absent ⇒ the whole collection. */\n readonly idPrefix?: string\n /** True when `candidate` should replace `current`. */\n readonly supersedes: (candidate: EncryptedEnvelope, current: EncryptedEnvelope | null) => boolean\n /** Whether a record the remote lacks is deleted locally on pull (subject to the two guards). */\n readonly propagateDeletes: boolean\n}\n\n/** `roster_epoch` of a keyring envelope; `undefined` for a pre-#1097 file or an unparsable body. */\nfunction keyringEpoch(envelope: EncryptedEnvelope | null | undefined): number | undefined {\n if (!envelope) return undefined\n try {\n const epoch = parseKeyringEnvelope(envelope).roster_epoch\n return typeof epoch === 'number' ? epoch : undefined\n } catch {\n return undefined\n }\n}\n\n/** What makes two copies of a keyring file \"the same edit\": epoch, the authenticated authority (its tag), and the display name. */\nfunction keyringIdentity(envelope: EncryptedEnvelope): string {\n const file = parseKeyringEnvelope(envelope)\n return `${file.roster_epoch ?? ''}:${file.roster_tag.data}:${file.display_name}`\n}\n\nfunction keyringSupersedes(candidate: EncryptedEnvelope, current: EncryptedEnvelope | null): boolean {\n if (!current) return true\n const c = keyringEpoch(candidate)\n const k = keyringEpoch(current)\n if (c === undefined) return false\n if (k === undefined) return true\n return c > k\n}\n\nfunction versionSupersedes(candidate: EncryptedEnvelope, current: EncryptedEnvelope | null): boolean {\n if (!current) return true\n return candidate._v > current._v\n}\n\n/** The declared set. Order matters: the roster travels FIRST, before anything it gates. */\nconst RESERVED_REPLICATION: readonly ReservedReplicationRule[] = [\n { collection: KEYRING_COLLECTION, supersedes: keyringSupersedes, propagateDeletes: true },\n // core#91 — the broker seeds. `_broker/<brokerId>` is sealed under the\n // admin `_broker` DEK (owner/admin only hold it), `_broker_member/<userId>`\n // under that grantee's own DEK: both are ciphertext to the mover and to every\n // other device, and both are exactly what a fresh device needs to mint its\n // first credential. Revocation is a delete that rides the dirty log.\n // core#97 — SECOND, right behind the roster: on a fresh device every target\n // request before the seed has landed cannot be served by the device's own\n // mint, so the seed travels before anything else a first pull carries.\n { collection: '_broker_member', supersedes: versionSupersedes, propagateDeletes: true },\n { collection: '_broker', supersedes: versionSupersedes, propagateDeletes: true },\n { collection: '_meta', idPrefix: 'invite-audit-', supersedes: versionSupersedes, propagateDeletes: false },\n { collection: '_users', supersedes: versionSupersedes, propagateDeletes: true },\n { collection: '_delegations', supersedes: versionSupersedes, propagateDeletes: true },\n // core#107 — the arbiter's admission refusals, so the WRITER learns its\n // offline record was rejected instead of the verdict staying on the device\n // that made it. Sealed under the refused record's OWN collection DEK, so\n // this mover still reads nothing (`_v` is on the envelope) and a member\n // without that collection receives ciphertext they quietly skip.\n // `propagateDeletes: true` — clearing a refusal is how it stops being shown.\n { collection: REJECTIONS_COLLECTION, supersedes: versionSupersedes, propagateDeletes: true },\n]\n\nexport interface ReservedMirrorResult {\n /** Records written to `to`. */\n readonly copied: number\n /** Records deleted from `to` (pull-side revocation propagation only). */\n readonly deleted: number\n /** Ids of `_keyring` files copied — the roster reload seam reads this for the caller's own file. */\n readonly keyringsCopied: readonly string[]\n /**\n * core#96 (pilot-1, finding B) — push only: local `_keyring` files the epoch\n * rule did not write and whose content differs from the remote's (the remote\n * is ahead, or the two diverged at one epoch). The local edit LOST; the\n * engine reports each as a `Conflict` so an authority edit made on a stale\n * copy is never silently dropped.\n */\n readonly staleKeyrings?: readonly { readonly id: string; readonly local: EncryptedEnvelope; readonly remote: EncryptedEnvelope }[]\n}\n\nfunction inScope(rule: ReservedReplicationRule, id: string): boolean {\n return rule.idPrefix === undefined || id.startsWith(rule.idPrefix)\n}\n\n/**\n * Copy every in-scope record that supersedes its counterpart from `from`\n * to `to`, for one rule. Never deletes. `fromIds` lets a caller that already\n * listed `from` avoid a second round-trip.\n */\nasync function mirrorRule(\n rule: ReservedReplicationRule,\n from: NoydbStore,\n to: NoydbStore,\n vault: string,\n fromIds?: readonly string[],\n): Promise<string[]> {\n const copied: string[] = []\n for (const id of fromIds ?? await from.list(vault, rule.collection)) {\n if (!inScope(rule, id)) continue\n const candidate = await from.get(vault, rule.collection, id)\n if (!candidate) continue\n const current = await to.get(vault, rule.collection, id)\n if (!rule.supersedes(candidate, current)) continue\n await to.put(vault, rule.collection, id, candidate)\n copied.push(id)\n }\n return copied\n}\n\n/** The push half: mirror every declared rule from `local` to `remote`. Never deletes. */\nexport async function pushReserved(local: NoydbStore, remote: NoydbStore, vault: string): Promise<ReservedMirrorResult> {\n let copied = 0\n let keyringsCopied: readonly string[] = []\n const staleKeyrings: { id: string; local: EncryptedEnvelope; remote: EncryptedEnvelope }[] = []\n for (const rule of RESERVED_REPLICATION) {\n const ids = await mirrorRule(rule, local, remote, vault)\n copied += ids.length\n if (rule.collection === KEYRING_COLLECTION) {\n keyringsCopied = ids\n // core#96 — a local file that was NOT written above and differs from the\n // remote's copy is an edit the epoch rule discarded: the remote is ahead,\n // or the two diverged at the same epoch (an edit made on a stale copy\n // bumps to the epoch the remote already holds). Right to discard, wrong\n // to swallow — reported here, at the one site that knows.\n for (const id of await local.list(vault, KEYRING_COLLECTION)) {\n if (ids.includes(id)) continue\n const [mine, theirs] = await Promise.all([local.get(vault, KEYRING_COLLECTION, id), remote.get(vault, KEYRING_COLLECTION, id)])\n if (mine && theirs && keyringIdentity(mine) !== keyringIdentity(theirs)) staleKeyrings.push({ id, local: mine, remote: theirs })\n }\n }\n }\n return { copied, deleted: 0, keyringsCopied, ...(staleKeyrings.length > 0 && { staleKeyrings }) }\n}\n\n/**\n * core#96 (pilot-1, finding B) — bring ONE member's keyring file down from the\n * target if the target's copy supersedes the local one. The kernel calls it\n * before every authority edit (`grant` on an existing user, `updateUser`,\n * `revoke`, `recoverUser`), so the edit is made on the current file and its\n * push wins instead of being discarded by the epoch rule. One GET.\n */\nexport async function pullKeyringFile(remote: NoydbStore, local: NoydbStore, vault: string, userId: string): Promise<boolean> {\n const rule = RESERVED_REPLICATION[0]!\n const ids = await mirrorRule(rule, remote, local, vault, [userId])\n return ids.length > 0\n}\n\n/**\n * The pull half: mirror every declared rule from `remote` into `local`, then\n * propagate revocations under the two guards in the module doc.\n * `protectedIds` maps a collection to the ids a pending local dirty entry\n * protects.\n *\n * Costs one `list()` per rule per pull, and nothing at all for a vault with\n * no local keyring: an encrypted vault always holds the caller's own file\n * after open (bootstrapped or minted), so \"no local keyring\" means\n * `encrypt: false` — nothing reserved to mirror, nothing to ask.\n */\nexport async function pullReserved(\n remote: NoydbStore,\n local: NoydbStore,\n vault: string,\n protectedIds: ReadonlyMap<string, ReadonlySet<string>>,\n): Promise<ReservedMirrorResult> {\n const localKeyrings = await local.list(vault, KEYRING_COLLECTION)\n if (localKeyrings.length === 0) return { copied: 0, deleted: 0, keyringsCopied: [] }\n let copied = 0\n let deleted = 0\n let keyringsCopied: readonly string[] = []\n // \"Has this target ever been pushed to?\" is answered by the ROSTER, not by the\n // collection at hand: a pushed target always carries at least the owner's\n // keyring file, whereas `_broker_member` or `_delegations` legitimately\n // become EMPTY when the last record is revoked — and that emptiness is the\n // revocation this must propagate (core#91), not a never-pushed target.\n let remoteInitialised = false\n for (const rule of RESERVED_REPLICATION) {\n const remoteIds = (await remote.list(vault, rule.collection)).filter(id => inScope(rule, id))\n if (rule.collection === KEYRING_COLLECTION) remoteInitialised = remoteIds.length > 0\n const ids = await mirrorRule(rule, remote, local, vault, remoteIds)\n copied += ids.length\n if (rule.collection === KEYRING_COLLECTION) keyringsCopied = ids\n if (!rule.propagateDeletes || !remoteInitialised) continue\n const remoteSet = new Set(remoteIds)\n const protectedSet = protectedIds.get(rule.collection)\n const localIds = rule.collection === KEYRING_COLLECTION ? localKeyrings : await local.list(vault, rule.collection)\n for (const id of localIds) {\n if (!inScope(rule, id) || remoteSet.has(id) || protectedSet?.has(id)) continue\n await local.delete(vault, rule.collection, id)\n deleted++\n }\n }\n return { copied, deleted, keyringsCopied }\n}\n\n/**\n * Open-path bootstrap: an EMPTY local store is not evidence of a new vault\n * when a `sync-peer` already carries the roster. Mirror its keyring files in\n * first; `assertKeyringOpenAllowed` then decides — own file → open, other\n * principals only → refuse, still nothing → genuinely new. Backups are\n * never consulted (never pulled from, #616). No-op when the local already\n * holds any keyring. Only the roster: the rest of the declared set arrives\n * on the first `pull()`.\n */\nexport async function bootstrapKeyrings(local: NoydbStore, peer: NoydbStore | undefined, vault: string): Promise<void> {\n if (!peer) return\n if ((await local.list(vault, KEYRING_COLLECTION)).length > 0) return\n await mirrorRule(RESERVED_REPLICATION[0]!, peer, local, vault)\n}\n","/**\n * #807 — period-scoped pull support for the `SyncEngine` (thin-client\n * bootstrap: first sync pulls the current period + the period summaries;\n * historical periods backfill on demand via `pull({ periods: ['<name>'] })`).\n *\n * ## Membership law\n *\n * The engine only ever sees ciphertext envelopes, so period membership at\n * the sync tier is by write-time `_ts` against the closed periods' windows\n * (`periodExclusiveUpperBound`) — the SAME store-tier law freeze (#604) and\n * archive (#613) use, NOT the business-date (`dateField`) seal the write\n * guard applies inside the trust boundary. A late-booked record (in-period\n * business date, current write-time) therefore syncs with the current\n * period — mirroring how it archives at the NEXT period's archive.\n *\n * Closed periods partition the timeline by their exclusive upper bounds:\n * the earliest closed period's window is unbounded below (a close seals\n * everything at-or-before its `endDate`), each later one starts at its\n * predecessor's bound, and the CURRENT window is everything at-or-after\n * the latest closed bound (everything, when no period was ever closed).\n *\n * ## What a period filter can never drop\n *\n * - **Period summaries** (`_periods` + freeze/archive/target-purge\n * companions) — the navigation index; always pulled in full, exempt from\n * every filter (`collections`, `periods`, `modifiedSince`).\n * - **Delete markers and tombstones** — an erasure or delete must never be\n * skipped by partial sync (the #589/#590 law, mirroring the\n * `modifiedSince` exemption). This is what makes a device that never\n * pulled period P converge instead of resurrecting P's deleted records\n * when it later backfills.\n * - **Reserved lookups** (`_dict_*`/`_lookup_*`) — vocabulary/config rows\n * are not period-partitioned data; their explicit pull loop is exempt.\n *\n * Push is NEVER period-filtered — `PushOptions` has no `periods` member at\n * all; a thin client's writes always flow up in full.\n */\nimport type { EncryptedEnvelope } from '../kernel/types.js'\nimport { ValidationError } from '../kernel/errors.js'\nimport { isTombstoneShape, isDeleteMarker } from '../capsule/index.js'\nimport {\n PERIODS_COLLECTION,\n PERIOD_FREEZES_COLLECTION,\n PERIOD_ARCHIVES_COLLECTION,\n PERIOD_TARGET_PURGES_COLLECTION,\n periodExclusiveUpperBound,\n} from '../with-audit/periods/window.js'\n\nexport { PERIODS_COLLECTION }\n\n/**\n * The reserved period-metadata collections a period-scoped pull always\n * fetches first (phase 1, \"summaries\"): the hash-chained `_periods` index\n * plus its freeze/archive/target-purge companions.\n */\nexport const PERIOD_SUMMARY_COLLECTIONS: readonly string[] = [\n PERIODS_COLLECTION,\n PERIOD_FREEZES_COLLECTION,\n PERIOD_ARCHIVES_COLLECTION,\n PERIOD_TARGET_PURGES_COLLECTION,\n]\n\n/** The subset of a decrypted `PeriodRecord` the window computation needs. */\nexport interface PeriodSyncRecord {\n readonly name: string\n readonly kind: 'closed' | 'opened'\n readonly endDate: string\n}\n\n/**\n * Vault-injected source of decrypted period records, wired via\n * `SyncEngine.setPeriodPullSource` (same injection pattern as\n * `setReservedLookupSource`). MUST re-read from the local store on every\n * call — the engine invokes it right after the summaries phase applied\n * freshly pulled `_periods` envelopes.\n */\nexport interface PeriodPullSource {\n periods(): Promise<readonly PeriodSyncRecord[]>\n}\n\nconst SHAPE_MSG =\n 'pull: `periods` must be an array of closed-period names, or `{ current: true }`.'\n\n/** Validate the raw `PullOptions.periods` value (runtime shape only). */\nexport function validatePeriodsOption(\n periods: unknown,\n): asserts periods is readonly string[] | { readonly current: true } {\n if (Array.isArray(periods)) {\n for (const p of periods) {\n if (typeof p !== 'string' || p.length === 0) throw new ValidationError(SHAPE_MSG)\n }\n return\n }\n if (\n typeof periods === 'object' && periods !== null &&\n (periods as { current?: unknown }).current === true &&\n Object.keys(periods).length === 1\n ) {\n return\n }\n throw new ValidationError(SHAPE_MSG)\n}\n\n/**\n * Resolve the selected `_ts` windows and return the pull-scope predicate:\n * `true` = the envelope is in scope for this pull. Tombstones and delete\n * markers are unconditionally in scope (see module doc).\n *\n * Throws `ValidationError` for a name that is not a closed period in the\n * (freshly synced) `_periods` index — a typo'd backfill must fail loudly,\n * never silently pull nothing.\n */\nexport function buildPeriodScope(\n option: readonly string[] | { readonly current: true },\n records: readonly PeriodSyncRecord[],\n): (envelope: EncryptedEnvelope) => boolean {\n const closed = records\n .filter((r) => r.kind === 'closed')\n .map((r) => ({ name: r.name, bound: periodExclusiveUpperBound(r.endDate) }))\n .sort((a, b) => a.bound.localeCompare(b.bound))\n\n let windows: ReadonlyArray<{ lower: string | null; upper: string | null }>\n if (Array.isArray(option)) {\n windows = (option as readonly string[]).map((name) => {\n const idx = closed.findIndex((c) => c.name === name)\n if (idx < 0) {\n const other = records.find((r) => r.name === name)\n throw new ValidationError(\n other\n ? `pull: period \"${name}\" is \"${other.kind}\" — only closed periods have a backfill window; use \\`{ current: true }\\` for the open period.`\n : `pull: no closed period named \"${name}\" in this vault's _periods index.`,\n )\n }\n return { lower: idx > 0 ? closed[idx - 1]!.bound : null, upper: closed[idx]!.bound }\n })\n } else {\n // { current: true } — everything at-or-after the latest closed bound\n // (everything, when no period was ever closed: with no closed periods\n // there is nothing historical to exclude, so nothing is silently dropped).\n windows = [{ lower: closed.length > 0 ? closed[closed.length - 1]!.bound : null, upper: null }]\n }\n\n return (envelope: EncryptedEnvelope): boolean => {\n if (isTombstoneShape(envelope) || isDeleteMarker(envelope)) return true\n return windows.some(\n (w) =>\n (w.lower === null || envelope._ts >= w.lower) &&\n (w.upper === null || envelope._ts < w.upper),\n )\n }\n}\n","import { buildRecordEnvelope, envelopeBodyForHash, buildDeleteMarker } from '../capsule/index.js'\nimport type {\n NoydbStore,\n DirtyEntry,\n Conflict,\n ConflictStrategy,\n CollectionConflictResolver,\n PushOptions,\n PullOptions,\n PushResult,\n PullResult,\n SyncStatus,\n EncryptedEnvelope,\n SyncMetadata,\n SyncTargetRole,\n ErasureEnforcement,\n SyncProgress,\n RealignResult,\n SyncApplied, SyncRejection, SyncRejectedApi,\n SyncEpochRecord, ReplaceRemoteResult,\n} from '../kernel/types.js'\nimport { NOYDB_SYNC_VERSION } from '../kernel/types.js'\nimport { isConflictError, ValidationError } from '../kernel/errors.js'\nimport { pushReserved, pullReserved, pullKeyringFile } from './reserved-mirror.js'\n\n/** core#74 — where a device parks the records its admission gate refused. Local-only: never mirrored, never full-pushed. */\nexport const REJECTED_COLLECTION = '_sync_rejected'\n/** core#74 — the parking record: the refusal and the untouched envelope, plaintext JSON (the envelope inside is still ciphertext). */\ninterface ParkedRejection { readonly rejection: SyncRejection; readonly envelope: EncryptedEnvelope }\n/** The parking record is a plaintext-body envelope; the capsule's canonical body reader returns exactly its JSON. */\nfunction parseParked(env: EncryptedEnvelope): ParkedRejection {\n return JSON.parse(envelopeBodyForHash(env)) as ParkedRejection\n}\nimport type { MergeAuthority } from '../port/with/merge-authority.js'\nimport type { AdmissionAuthority } from '../port/with/admission-authority.js'\nimport type { RejectionCourier } from '../port/with/rejection-courier.js'\nimport { REJECTIONS_COLLECTION, rejectionKey } from '../kernel/rejection-seal.js'\nimport {\n PERIOD_SUMMARY_COLLECTIONS,\n PERIODS_COLLECTION,\n buildPeriodScope,\n validatePeriodsOption,\n type PeriodPullSource,\n} from './period-scope.js'\nimport type { NoydbEventEmitter } from '../kernel/events.js'\nimport type { SyncPolicy } from '../kernel/sync-policy.js'\nimport { SyncScheduler } from '../kernel/sync-policy.js'\nimport { isTombstoneShape, isDeleteMarker, envelopeBodySize } from '../capsule/index.js'\n\n/** #650 Task 4 (#647) — the declared reserved-lookup (`_dict_*`/`_lookup_*`) collection-name\n * registry a `SyncEngine` enumerates on pull. Explicit, not a blanket underscore-glob — other\n * `_`-prefixed namespaces keep their `loadAll`-skip semantics untouched. */\nexport interface ReservedLookupSource {\n /** Declared reserved-lookup collection names to enumerate on pull. */\n collections(): readonly string[]\n}\n\n/** Sync engine: dirty tracking, push, pull, conflict resolution, scheduling. */\nexport class SyncEngine {\n private readonly mergeAuthority: MergeAuthority | undefined\n /** core#74 — the vault's admission gate for incoming records; wired at open like the other vault seams. */\n private admission: AdmissionAuthority | undefined\n #applied: SyncApplied[] = []\n #rejected: SyncRejection[] = []\n /** core#108 — this device's own records, refused by its own gates on the way OUT. */\n #pushRejected: SyncRejection[] = []\n /** core#107 — the vault's sealing capability for replicated refusals; wired at open like `admission`. */\n private courier: RejectionCourier | undefined\n /** core#107 — this device's refusals replicate. Configuration, not an authority proof — see `withSync`. */\n private readonly arbiter: boolean\n private readonly local: NoydbStore\n private readonly remote: NoydbStore\n private readonly strategy: ConflictStrategy\n private readonly emitter: NoydbEventEmitter\n private readonly vault: string\n readonly role: SyncTargetRole\n readonly label: string | undefined\n /** #948: the resolved policy this engine was constructed with, retained for\n * introspection (`Noydb.listSyncTargets()`) — otherwise lost once consumed\n * into the scheduler below. */\n readonly policy: SyncPolicy | undefined\n\n private dirty: DirtyEntry[] = []\n /** #1036 — last SUCCESSFUL push/pull. Never advanced by a failed attempt. */\n private lastPush: string | null = null\n private lastPull: string | null = null\n /** core#72 — the target's restore epoch this device adopted; null before any. */\n private epoch: number | null = null\n /**\n * #1036 — the failure that ended the most recent attempt, cleared by the next\n * success. Live state only: deliberately NOT persisted in `_sync/meta`, since a\n * reload cannot know whether the target is still failing. It exists so a poller\n * can separate \"never synced\" (both null) from \"synced a while ago, failing\n * since\" (`lastPush` set, `lastError` set).\n */\n private lastError: { readonly at: string; readonly op: 'push' | 'pull'; readonly message: string } | null = null\n private loaded = false\n private autoSyncInterval: ReturnType<typeof setInterval> | null = null\n private isOnline = true\n\n /** Sync scheduler. Manages push/pull timing. */\n readonly scheduler: SyncScheduler | null\n\n /** Per-collection conflict resolvers registered by Collection instances. */\n private readonly conflictResolvers = new Map<string, CollectionConflictResolver>()\n\n /**\n * Expands a collection-name filter to include its satellite pair partner(s)\n * (spec #591 convergence rule 5b) — wired from vault satellite declaration\n * via `setPairExpander`. `undefined` when no satellite has ever been\n * declared for this vault: identity behavior, zero change for non-satellite\n * users.\n */\n private pairExpander?: (names: readonly string[]) => readonly string[]\n\n /** #598: refreshes Collection in-memory views after a sync-applied local write. Wired by the\n * vault at open. `action` (#640): `'delete'` for a pulled tombstone/delete-marker, `'put'`\n * otherwise — classified at `applyRemote`, the one choke point that holds the envelope. */\n private cacheInvalidator?: (collection: string, id: string, action: 'put' | 'delete') => Promise<void>\n\n /** Wire the Collection-cache invalidation hook (#598). Same injection pattern as `setPairExpander`. */\n setCacheInvalidator(fn: (collection: string, id: string, action: 'put' | 'delete') => Promise<void>): void {\n this.cacheInvalidator = fn\n }\n\n /** #638 Task 4: opens/flushes the vault's graph-dispatch touch batch around a whole `pull()`/\n * `push()` call, so N `applyRemote`d records feeding the same derivation/rollup/MV target\n * recompute once. Wired by the vault at open, mirroring `cacheInvalidator`. */\n private graphBatchController?: { begin(): void; flush(): Promise<void> }\n\n /** Wire the graph-dispatch batch controller (#638 Task 4). Same injection pattern as `setCacheInvalidator`. */\n setGraphBatchController(controller: { begin(): void; flush(): Promise<void> }): void {\n this.graphBatchController = controller\n }\n\n /** #650 Task 4 (#647): declared reserved-lookup collections `pull()` enumerates explicitly (the\n * store's `list()` does not skip `_`-prefixed names, unlike `loadAll()`). Wired by the vault at\n * open, same injection pattern as `setCacheInvalidator`/`setGraphBatchController`. */\n private reservedLookup?: ReservedLookupSource\n\n /** Wire the reserved-lookup source (#650 Task 4). */\n setReservedLookupSource(source: ReservedLookupSource): void {\n this.reservedLookup = source\n }\n\n /** #653: expands a (pair-expanded) collection-name filter to include the reserved `_dict_*`\n * collections those names depend on via their lookup fields — mirrors `pairExpander` so a\n * partial `push`/`pull({collections:[...]})` never drops the dictionary a named collection's\n * labels/membership rely on. Wired unconditionally from the vault's `dictKeyFieldRegistry` via\n * `setReservedDictExpander` (returns `[]` when the vault has no dict-backed collections); only\n * `undefined` on a standalone engine that was never vault-attached. */\n private reservedDictExpander?: (names: readonly string[]) => readonly string[]\n\n /** Wire the reserved-dict expansion function (#653). Same injection pattern as `setPairExpander`. */\n setReservedDictExpander(expander: (names: readonly string[]) => readonly string[]): void {\n this.reservedDictExpander = expander\n }\n\n /** #807: vault-injected source of decrypted period records — resolves the `_ts` windows a\n * `pull({ periods })` scopes to. Re-read AFTER the summaries phase, so a fresh device's\n * freshly pulled `_periods` index is what the windows are computed from. `undefined` on a\n * standalone engine that was never vault-attached (period-scoped pull then throws). */\n private periodPullSource?: PeriodPullSource\n\n /** Wire the period-window source (#807). Same injection pattern as `setReservedLookupSource`. */\n setPeriodPullSource(source: PeriodPullSource): void {\n this.periodPullSource = source\n }\n\n /** core#81 — the collections this keyring names; the walk set for a paged pull. Wired by the vault at open. */\n private collectionNames?: () => readonly string[]\n\n /** Wire the paged-pull walk set (core#81). Same injection pattern as `setCacheInvalidator`. */\n setCollectionNames(fn: () => readonly string[]): void {\n this.collectionNames = fn\n }\n\n /**\n * core#81 — one chunk per page of one collection, for `pull({ paged: true })`.\n * `listPage` when the store offers it (200 per page), else `list` + `get` in\n * batches of the same size. Never more than one page in memory.\n */\n private async *pagedChunks(names: readonly string[]): AsyncGenerator<[string, Record<string, EncryptedEnvelope>]> {\n const PAGE = 200\n const remote = this.remote\n for (const coll of names) {\n if (typeof remote.listPage === 'function') {\n let cursor: string | undefined\n do {\n const page = await remote.listPage(this.vault, coll, cursor, PAGE)\n const records: Record<string, EncryptedEnvelope> = {}\n for (const { id, envelope } of page.items) records[id] = envelope\n if (page.items.length > 0) yield [coll, records]\n cursor = page.nextCursor ?? undefined\n } while (cursor !== undefined)\n } else {\n const ids = await remote.list(this.vault, coll)\n for (let i = 0; i < ids.length; i += PAGE) {\n const records: Record<string, EncryptedEnvelope> = {}\n for (const id of ids.slice(i, i + PAGE)) {\n const env = await remote.get(this.vault, coll, id)\n if (env) records[id] = env\n }\n if (Object.keys(records).length > 0) yield [coll, records]\n }\n }\n }\n }\n\n /** core#82 — when a pull replaces the caller's OWN keyring file, the vault reloads it in place. */\n private rosterReload?: { userId: string; reload: () => Promise<void> }\n\n /** Wire the roster-reload seam (core#82). Same injection pattern as `setCacheInvalidator`. */\n /** core#107 — wire the vault's rejection sealing capability. */\n setRejectionCourier(c: RejectionCourier): void {\n this.courier = c\n }\n\n /** core#74 — wire the vault's admission gate. */\n setAdmission(a: AdmissionAuthority): void {\n this.admission = a\n }\n\n /** core#71 — after `vault.load()`: a new base. Drops the dirty log, the watermarks and the adopted epoch. */\n async resetAfterRestore(): Promise<void> {\n await this.ensureLoaded()\n this.dirty = []\n this.lastPush = null\n this.lastPull = null\n this.epoch = null\n await this.persistMeta()\n }\n\n /** core#72 — the target's epoch record, or null when the target was never replaced. */\n async #remoteEpoch(): Promise<SyncEpochRecord | null> {\n const env = await this.remote.get(this.vault, '_sync', 'epoch')\n return env ? (JSON.parse(envelopeBodyForHash(env)) as SyncEpochRecord) : null\n }\n\n /**\n * core#72 — make the LOCAL vault authoritative on this target. Every local\n * record goes up unconditionally, re-sealed above the target's version where\n * the target moved on (so every peer's copy is superseded); every id the\n * target holds that the local vault lacks gets a delete marker at\n * `remote._v + 1` (so every peer removes it); the reserved collections are\n * mirrored; then a new epoch is written at `_sync/epoch`. The dirty log is\n * cleared: the target IS the local state now.\n */\n async replaceRemote(): Promise<ReplaceRemoteResult> {\n await this.ensureLoaded()\n const actor = this.rosterReload?.userId ?? 'sync'\n const [localSnapshot, remoteSnapshot] = await Promise.all([this.local.loadAll(this.vault), this.remote.loadAll(this.vault)])\n let replaced = 0\n let tombstoned = 0\n for (const [collection, records] of Object.entries(localSnapshot)) {\n if (collection === REJECTED_COLLECTION) continue\n for (const [id, envelope] of Object.entries(records)) {\n const current = remoteSnapshot[collection]?.[id]\n let out = envelope\n if (current && current._v >= envelope._v) {\n // The target moved past the local copy: lift the local envelope above\n // it, re-sealed through the merge authority (the AAD binds `_v`).\n out = this.mergeAuthority\n ? await this.mergeAuthority.advance(collection, id, envelope, current._v + 1)\n : { ...envelope, _v: current._v + 1 }\n await this.local.put(this.vault, collection, id, out)\n }\n await this.remote.put(this.vault, collection, id, out)\n replaced++\n }\n }\n for (const [collection, records] of Object.entries(remoteSnapshot)) {\n if (collection === REJECTED_COLLECTION) continue\n for (const [id, envelope] of Object.entries(records)) {\n if (localSnapshot[collection]?.[id] !== undefined) continue\n if (isTombstoneShape(envelope) || isDeleteMarker(envelope)) continue\n const marker = buildDeleteMarker({ collection, id }, envelope._v + 1, actor)\n await this.remote.put(this.vault, collection, id, marker)\n await this.local.put(this.vault, collection, id, marker) // the local mirrors the target exactly: its own next pull brings nothing back\n tombstoned++\n }\n }\n const mirrored = await pushReserved(this.local, this.remote, this.vault)\n const previous = await this.#remoteEpoch()\n const epoch = (previous?.epoch ?? 0) + 1\n const record: SyncEpochRecord = { epoch, at: new Date().toISOString(), by: actor, replaced, tombstoned }\n await this.remote.put(this.vault, '_sync', 'epoch', buildRecordEnvelope({ collection: '_sync', id: 'epoch', version: epoch }, { iv: '', data: JSON.stringify(record) }))\n this.dirty = []\n this.epoch = epoch\n this.lastPush = new Date().toISOString()\n await this.persistMeta()\n const result: ReplaceRemoteResult = { epoch, replaced, tombstoned, reserved: mirrored.copied }\n this.emitter.emit('sync:replace', { vault: this.vault, ...result })\n return result\n }\n\n /**\n * core#72 — at the start of a pull: has the target been replaced since this\n * device last synced? If so, park every unpushed local edit (same fate as an\n * admission refusal, reason `restore-epoch`), drop the dirty log, adopt the\n * epoch. The pull that follows then adopts the target: the restorer lifted\n * its records above every peer's version and tombstoned what it removed.\n */\n async #crossEpoch(): Promise<{ epoch: number; resynced: boolean; parked: number }> {\n const remote = await this.#remoteEpoch()\n if (!remote || remote.epoch === this.epoch) return { epoch: remote?.epoch ?? 0, resynced: false, parked: 0 }\n const from = this.epoch\n let parked = 0\n for (const entry of this.dirty) {\n if (entry.action === 'delete') continue\n const env = await this.local.get(this.vault, entry.collection, entry.id)\n if (!env) continue\n const rejection: SyncRejection = {\n vault: this.vault, collection: entry.collection, id: entry.id, version: env._v,\n reason: `restore-epoch: the target was replaced (epoch ${remote.epoch}) after this edit; readmit to keep it locally, then put again to push`,\n ...(env._by !== undefined ? { by: env._by } : {}), at: new Date().toISOString(),\n }\n const parkedRecord: ParkedRejection = { rejection, envelope: env }\n await this.local.put(this.vault, REJECTED_COLLECTION, `${entry.collection}::${entry.id}`,\n buildRecordEnvelope({ collection: REJECTED_COLLECTION, id: `${entry.collection}::${entry.id}`, version: 1 }, { iv: '', data: JSON.stringify(parkedRecord) }))\n this.#rejected.push(rejection)\n this.emitter.emit('sync:rejected', rejection)\n // Adopting the target WHOLESALE: the unpushed record leaves the local\n // store too (the parking record holds it; `readmit` puts it back).\n await this.local.delete(this.vault, entry.collection, entry.id)\n await this.cacheInvalidator?.(entry.collection, entry.id, 'delete')\n parked++\n }\n this.dirty = []\n this.epoch = remote.epoch\n this.emitter.emit('sync:epoch', { vault: this.vault, from, to: remote.epoch, parked })\n return { epoch: remote.epoch, resynced: true, parked }\n }\n\n /** core#74 — the parked refusals on this device, and their two fates. */\n rejected(): SyncRejectedApi {\n const key = (collection: string, id: string): string => `${collection}::${id}`\n return {\n list: async () => {\n const out: SyncRejection[] = []\n for (const id of await this.local.list(this.vault, REJECTED_COLLECTION)) {\n const env = await this.local.get(this.vault, REJECTED_COLLECTION, id)\n if (!env) continue\n out.push(parseParked(env).rejection)\n }\n return out\n },\n readmit: async (collection, id) => {\n const env = await this.local.get(this.vault, REJECTED_COLLECTION, key(collection, id))\n if (!env) throw new ValidationError(`sync: no rejected record parked for \"${collection}/${id}\".`)\n await this.local.put(this.vault, collection, id, parseParked(env).envelope)\n await this.local.delete(this.vault, REJECTED_COLLECTION, key(collection, id))\n await this.cacheInvalidator?.(collection, id, 'put')\n },\n discard: async (collection, id) => {\n await this.local.delete(this.vault, REJECTED_COLLECTION, key(collection, id))\n },\n }\n }\n\n setRosterReload(seam: { userId: string; reload: () => Promise<void> }): void {\n this.rosterReload = seam\n }\n\n /** core#81 — the running sync's latest progress sample; `null` when idle. Read by `status()`. */\n private inFlight: SyncProgress | null = null\n private progressLastEmit = 0\n private progressLastRecords = 0\n\n /** Emit `sync:progress` no more than every 25 records or ~250 ms; `force` for the final sample. */\n private progress(sample: SyncProgress, force = false): void {\n this.inFlight = sample\n const now = Date.now()\n if (!force && sample.records - this.progressLastRecords < 25 && now - this.progressLastEmit < 250) return\n this.progressLastEmit = now\n this.progressLastRecords = sample.records\n this.emitter.emit('sync:progress', sample)\n }\n\n private progressDone(): void {\n this.inFlight = null\n this.progressLastEmit = 0\n this.progressLastRecords = 0\n }\n\n /** #807: KPI accumulator `applyRemote` feeds during a period-scoped `pull()` — pointed at the\n * active phase's counters (summaries → records) and cleared before pull returns. Approximate\n * by design: a push interleaved mid-pull on the same engine would attribute its converge\n * applies to the open phase; the counters are a download-budget KPI, not an audit source. */\n private pullByteSink: { records: number; bytes: number } | null = null\n /** core#81 — ciphertext bytes applied by the running pull, for `sync:progress`. */\n private pullBytes = 0\n\n constructor(opts: {\n local: NoydbStore\n remote: NoydbStore\n vault: string\n strategy: ConflictStrategy\n emitter: NoydbEventEmitter\n syncPolicy?: SyncPolicy\n role?: SyncTargetRole\n label?: string\n /**\n * #1042 — the merge's verify/re-stamp capability. Optional so an engine\n * built without one behaves exactly as before; the Vault supplies it.\n *\n * A closure, not an import: `with-sync` is DEK-free and\n * `check:architecture` enforces that, so the capability arrives already\n * bound to the keys rather than the engine reaching for them.\n */\n mergeAuthority?: MergeAuthority\n /** core#107 — this device is the vault's arbiter: its refusals replicate. */\n arbiter?: boolean\n }) {\n this.local = opts.local\n this.remote = opts.remote\n this.vault = opts.vault\n this.strategy = opts.strategy\n this.emitter = opts.emitter\n this.role = opts.role ?? 'sync-peer'\n this.label = opts.label\n this.policy = opts.syncPolicy\n this.mergeAuthority = opts.mergeAuthority\n this.arbiter = opts.arbiter === true\n\n // Create a scheduler when the policy asks for ANY automatic behaviour.\n // #897: this used to test `push.mode !== 'manual'` alone, so a policy of\n // `{ push: manual, pull: interval }` silently got no scheduler and its pull\n // mode was ignored.\n const policy = opts.syncPolicy\n if (policy && (policy.push.mode !== 'manual' || policy.pull.mode !== 'manual')) {\n this.scheduler = new SyncScheduler(policy, {\n push: () => this.push().then(() => {}),\n // #618 — role-gate the SCHEDULER-INITIATED pull. The Noydb layer gates\n // pull-from-sink for explicit calls, but the scheduler calls the engine\n // directly and would bypass it: a backup/archive-only primary with an\n // `interval`/`on-focus` pull policy would pull ungated, reintroducing\n // #616. This guards the engine self-initiating on a timer; an explicit\n // `engine.pull()` still pulls for every role.\n // `collections` is set by a 'phased' sequence — one collection per phase.\n // A role-gated skip reports 'incomplete': nothing was pulled, so the\n // phase must not mark its collection ready.\n pull: (collections) =>\n this.role === 'sync-peer'\n ? this.pull(collections ? { collections: [...collections] } : undefined)\n // PullResult.errors accumulates WITHOUT throwing, so a partial\n // failure is only visible here — not via a rejected promise.\n .then(r => (r.errors.length === 0 ? 'complete' : 'incomplete'))\n : Promise.resolve('incomplete'),\n getDirtyCount: () => this.dirty.length,\n })\n } else {\n this.scheduler = null\n }\n }\n\n /** Start the sync scheduler. Called after vault is fully opened. */\n startScheduler(): void {\n this.scheduler?.start()\n }\n\n /** Stop the sync scheduler. Called on close. */\n stopScheduler(): void {\n this.scheduler?.stop()\n }\n\n /**\n * Register a per-collection conflict resolver.\n * Called by Collection when `conflictPolicy` is set.\n *\n * Pair-coupled (#591 rule 5b): registering for one satellite-pair member\n * registers the same resolver for both — the pair converges under one\n * resolution policy. Expands with whatever the pair-expander knows *at this\n * call*; resolvers registered before their pair existed are covered by\n * `remirrorPairResolvers` at pair-registration time.\n */\n registerConflictResolver(collection: string, resolver: CollectionConflictResolver): void {\n for (const n of this.pairExpander?.([collection]) ?? [collection]) this.conflictResolvers.set(n, resolver)\n }\n\n /**\n * Wire a satellite pair-expansion function (vault registration, #591 Task 11).\n * The closure re-reads the live `SatelliteRegistry` on every call, so pairs\n * declared after this is set are still picked up by `push`/`pull` filters.\n */\n setPairExpander(expander: (names: readonly string[]) => readonly string[]): void {\n this.pairExpander = expander\n }\n\n /**\n * Retroactively mirror per-collection conflict resolvers across a newly\n * registered satellite pair (#591 rule 5b) — covers the NORMAL declaration\n * order, where the base's `conflictPolicy` resolver was registered before\n * the satellite was declared (so the call-time expansion in\n * `registerConflictResolver` saw no pair yet). Tie-break: when BOTH members\n * already carry (different) resolvers, the FIRST name in `names` wins —\n * callers pass `[base, satellite]`, so the base's resolver is canonical.\n * Idempotent; a later explicit registration on either member still\n * overwrites both (last-wins, via the call-time expansion above).\n */\n remirrorPairResolvers(names: readonly string[]): void {\n const canonical = names.map(n => this.conflictResolvers.get(n)).find(r => r !== undefined)\n if (!canonical) return\n for (const n of names) this.conflictResolvers.set(n, canonical)\n }\n\n /** Record a local change for later push. */\n async trackChange(collection: string, id: string, action: DirtyEntry['action'], version: number): Promise<void> {\n await this.ensureLoaded()\n\n // Deduplicate: if same collection+id already in dirty, update it\n const idx = this.dirty.findIndex(d => d.collection === collection && d.id === id)\n const entry: DirtyEntry = {\n vault: this.vault,\n collection,\n id,\n action,\n version,\n timestamp: new Date().toISOString(),\n }\n\n if (idx >= 0) {\n this.dirty[idx] = entry\n } else {\n this.dirty.push(entry)\n }\n\n await this.persistMeta()\n\n // Notify scheduler of the write (triggers on-change or debounce)\n this.scheduler?.notifyChange()\n }\n\n /** Remove a dirty entry (satellite fan-out revert cleanup — spec #591). */\n async removeDirty(collection: string, id: string): Promise<void> {\n const before = this.dirty.length\n this.dirty = this.dirty.filter(d => !(d.collection === collection && d.id === id))\n if (this.dirty.length !== before) await this.persistMeta()\n }\n\n /**\n * core#74/#108 — park a refused envelope under `_sync_rejected` and announce\n * it. One helper for both fates: a record that ARRIVED and was turned away,\n * and (core#108) this device's own record refused on the way out. The\n * parking key is `collection::id`, so re-refusing the same record overwrites\n * rather than accumulating.\n */\n async #park(collection: string, id: string, envelope: EncryptedEnvelope, reason: string, origin: 'sync-apply' | 'push-recheck'): Promise<SyncRejection> {\n // core#107 (pilot-1): `origin` is set on EVERY path, including\n // `'sync-apply'`. It used to be omitted there and inferred from absence,\n // which made a consumer switch handle two members and `undefined` for the\n // commonest case of the three.\n const rejection: SyncRejection = {\n vault: this.vault, collection, id, reason, version: envelope._v,\n ...(envelope._by !== undefined ? { by: envelope._by } : {}), at: new Date().toISOString(),\n ...(envelope._ts !== undefined ? { recordAt: envelope._ts } : {}),\n origin,\n }\n await this.#parkBuilt(collection, id, envelope, rejection)\n if (origin === 'sync-apply') await this.#publishRejection(collection, id, rejection)\n return rejection\n }\n\n /** Store half of `#park`, also used for a refusal that arrived already made (core#107). */\n async #parkBuilt(collection: string, id: string, envelope: EncryptedEnvelope, rejection: SyncRejection): Promise<void> {\n const parked: ParkedRejection = { rejection, envelope }\n await this.local.put(\n this.vault, REJECTED_COLLECTION, `${collection}::${id}`,\n buildRecordEnvelope({ collection: REJECTED_COLLECTION, id: `${collection}::${id}`, version: 1 }, { iv: '', data: JSON.stringify(parked) }),\n )\n this.emitter.emit('sync:rejected', rejection)\n }\n\n /**\n * core#107 — turn the arbiter's replicated refusals into THIS device's\n * notification. Runs after the reserved phase has brought `_sync_rejections`.\n *\n * Three filters, each load-bearing:\n * - `courier.open` returns `null` for a member who holds no DEK for that\n * collection. They received the ciphertext like everyone else and skip it.\n * - a refusal names a VERSION. If this device's copy has moved on, the\n * refusal is about a record that no longer exists here and is ignored —\n * otherwise a stale verdict would re-fire against an edit that may well\n * pass now.\n * - an existing parking at the same version means this was already\n * reported; the parking record IS the dedupe, so no extra state is kept\n * and it survives a restart.\n *\n * ⛔ REPORT ONLY (ruled): the local record is never deleted, tombstoned or\n * hidden. The refusal is information; what to do about it is the writer's.\n */\n async #scanReplicatedRejections(): Promise<number> {\n if (!this.courier) return 0\n let keys: readonly string[]\n try { keys = await this.local.list(this.vault, REJECTIONS_COLLECTION) } catch { return 0 }\n let seen = 0\n for (const parkKey of keys) {\n const sep = parkKey.indexOf('::')\n if (sep < 0) continue\n const collection = parkKey.slice(0, sep), id = parkKey.slice(sep + 2)\n const env = await this.local.get(this.vault, REJECTIONS_COLLECTION, parkKey)\n if (!env) continue\n const rejection = await this.courier.open(collection, id, env)\n if (!rejection) continue\n const mine = await this.local.get(this.vault, collection, id)\n if (!mine || mine._v !== rejection.version) continue\n const existing = await this.local.get(this.vault, REJECTED_COLLECTION, parkKey)\n if (existing && parseParked(existing).rejection.version === rejection.version) continue\n const replicated: SyncRejection = { ...rejection, origin: 'arbiter' }\n await this.#parkBuilt(collection, id, mine, replicated)\n this.#rejected.push(replicated)\n seen++\n }\n return seen\n }\n\n /**\n * core#107 — the ARBITER's refusals replicate, so the writer finds out.\n *\n * Only `sync-apply` refusals: a `push-recheck` refusal (core#108) never left\n * this device, so there is no other device to tell, and a `restore-epoch`\n * parking is this device adopting a new base rather than a judgement about\n * the record.\n *\n * ⛔ Best-effort by construction: a failure to publish must not fail the\n * pull that produced it. The local parking, the `PullResult.rejected` row\n * and the event have already happened and are this device's real answer;\n * replication is the courtesy on top. So a courier that cannot seal (no DEK\n * for that collection) or a store that refuses the write leaves the refusal\n * exactly as it was before core#107.\n */\n async #publishRejection(collection: string, id: string, rejection: SyncRejection): Promise<void> {\n if (!this.arbiter || !this.courier) return\n try {\n const key = rejectionKey(collection, id)\n const current = await this.local.get(this.vault, REJECTIONS_COLLECTION, key)\n const envelope = await this.courier.seal(collection, id, rejection, (current?._v ?? 0) + 1)\n if (envelope) await this.local.put(this.vault, REJECTIONS_COLLECTION, key, envelope)\n } catch { /* see the ⛔ above: never fail the pull for the courtesy */ }\n }\n\n /**\n * core#108 — re-run this device's OWN gates against a dirty record before it\n * is pushed. A record written offline may no longer pass the rules this\n * device now holds (a period closed while it was away); today it pushes and\n * every OTHER device refuses it at admission, so the writer is the last to\n * know. Judging it here means the writer's own device catches it the moment\n * it reconnects, before anyone else sees the record.\n *\n * Returns `true` when the entry was WITHHELD. The entry stays dirty and the\n * local copy is untouched, so nothing is lost and a later push carries it\n * unchanged once the rule passes again — which is why a refusal here needs\n * no `readmit()` and no dirty-log surgery.\n *\n * ⛔ `rekey` is never re-checked: core#100 rewrites the SAME content under a\n * new key, so judging it would refuse a record for its content having been\n * legal at write time — the same wrong answer core#74 fixed with\n * `admit: false` for a device's own re-versioned records.\n */\n async #withheldByRecheck(entry: DirtyEntry, envelope: EncryptedEnvelope): Promise<boolean> {\n if (!this.admission || entry.action === 'rekey') return false\n if (isTombstoneShape(envelope) || isDeleteMarker(envelope)) return false\n const verdict = await this.admission.admit(entry.collection, entry.id, envelope, 'push-recheck')\n if (verdict.admitted) return false\n this.#pushRejected.push(await this.#park(entry.collection, entry.id, envelope, verdict.reason, 'push-recheck'))\n return true\n }\n\n /** One dirty entry of `push()`: the CAS put, the tombstone assertion, the delete, and every conflict branch. Extracted so `push({ concurrency })` can run entries in a bounded pool (core#93). */\n async #pushOne(i: number, entry: DirtyEntry, acc: { pushed: number; bytes: number; completed: number[]; conflicts: Conflict[]; erasures: ErasureEnforcement[]; errors: Error[] }): Promise<void> {\n try {\n if (entry.action === 'delete') {\n await this.remote.delete(this.vault, entry.collection, entry.id)\n acc.completed.push(i)\n acc.pushed++\n } else {\n const envelope = await this.local.get(this.vault, entry.collection, entry.id)\n if (!envelope) {\n // Record was deleted locally after being marked dirty\n acc.completed.push(i)\n return\n }\n\n if (isTombstoneShape(envelope)) {\n // #590: a tombstone push is an erasure assertion — unconditional,\n // no CAS, no conflict resolution. Erasure always wins.\n await this.remote.put(this.vault, entry.collection, entry.id, envelope)\n acc.completed.push(i)\n acc.pushed++\n return\n }\n\n // core#108 — this device's own gates, against current local state. A\n // refusal WITHHOLDS the record: not pushed, not completed (so it stays\n // dirty and goes out by itself once the rule passes), local copy intact.\n if (await this.#withheldByRecheck(entry, envelope)) return\n\n try {\n await this.remote.put(\n this.vault,\n entry.collection,\n entry.id,\n envelope,\n // core#100 — a `rekey` re-encrypted the record in place: same `_v`,\n // new bytes; the target still at that version takes it.\n entry.action === 'rekey' ? entry.version : entry.version - 1,\n )\n acc.completed.push(i)\n acc.pushed++\n acc.bytes += envelopeBodySize(envelope) // core#81\n } catch (err) {\n if (isConflictError(err)) {\n const remoteEnvelope = await this.remote.get(this.vault, entry.collection, entry.id)\n if (remoteEnvelope) {\n if (remoteEnvelope._v === envelope._v && envelopeBodyForHash(remoteEnvelope) === envelopeBodyForHash(envelope)) {\n // core#71 (pilot-1's restore run) — the target already holds THIS\n // envelope: a `push({ full: true })` after a restore, or a replay.\n // The CAS refused it because the remote is at the version we\n // expected to advance past; nothing to resolve, nothing to report.\n acc.completed.push(i)\n } else if (isTombstoneShape(remoteEnvelope)) {\n // #590: remote already shredded this record — enforce locally,\n // never resolve. Resolvers must not overrule an erasure.\n await this.applyRemote(entry.collection, entry.id, remoteEnvelope)\n acc.erasures.push(this.reportErasure(entry.collection, entry.id, remoteEnvelope, envelope, 'push'))\n acc.completed.push(i)\n } else if (\n remoteEnvelope._v === envelope._v &&\n isDeleteMarker(remoteEnvelope) !== isDeleteMarker(envelope) &&\n !this.conflictResolvers.get(entry.collection)\n ) {\n // #589: a same-_v delete-vs-edit tie on the push channel. handleConflict's db-level\n // 'version' default would resolve it to local-wins; the tie rule consults ONLY the\n // per-collection resolver, else delete-wins. (When a per-collection resolver IS set,\n // fall through to handleConflict, which already honors it — incl. the merged case.)\n if (isDeleteMarker(remoteEnvelope)) {\n // remote already deleted → converge locally, drop our (edit) push\n await this.applyRemote(entry.collection, entry.id, remoteEnvelope)\n acc.completed.push(i)\n } else {\n // our local is the marker → force the delete onto the remote (unconditional put)\n await this.remote.put(this.vault, entry.collection, entry.id, envelope)\n acc.completed.push(i)\n acc.pushed++\n }\n } else {\n const { handled, conflict } = await this.handleConflict(\n entry.collection,\n entry.id,\n envelope,\n remoteEnvelope,\n 'push',\n )\n acc.conflicts.push(conflict)\n if (handled === 'local') {\n // #936: supersede, don't overwrite in place — see advancePastRemote.\n const winner = await this.advancePastRemote(conflict.local, entry.collection, entry.id, remoteEnvelope)\n await this.remote.put(this.vault, entry.collection, entry.id, winner)\n if (winner !== conflict.local) await this.applyRemote(entry.collection, entry.id, winner, { admit: false })\n acc.completed.push(i)\n acc.pushed++\n } else if (handled === 'remote') {\n await this.applyRemote(entry.collection, entry.id, conflict.remote)\n acc.completed.push(i)\n } else if (handled === 'merged' && conflict.local !== envelope) {\n // Merged envelope is stored in conflict.local (the winner)\n const merged = conflict.local\n await this.remote.put(this.vault, entry.collection, entry.id, merged)\n await this.applyRemote(entry.collection, entry.id, merged)\n acc.completed.push(i)\n acc.pushed++\n }\n // handled === 'deferred': leave in dirty log\n }\n }\n } else {\n throw err\n }\n }\n }\n } catch (err) {\n acc.errors.push(err instanceof Error ? err : new Error(String(err)))\n }\n }\n\n /**\n * core#92 — mark every user-collection record in the local store dirty at its\n * current version, so the next push sends it (CAS against `_v - 1`, so a\n * remote that already holds a newer copy resolves through the conflict path\n * instead of being overwritten). Records already dirty keep their entry.\n */\n async markAllDirty(): Promise<void> {\n await this.ensureLoaded()\n const snapshot = await this.local.loadAll(this.vault)\n for (const [collection, records] of Object.entries(snapshot)) {\n if (collection === REJECTED_COLLECTION) continue // core#74 — parked refusals are this device's alone\n for (const [id, envelope] of Object.entries(records)) {\n if (this.dirty.some(d => d.collection === collection && d.id === id)) continue\n this.dirty.push({ vault: this.vault, collection, id, action: 'put', version: envelope._v, timestamp: new Date().toISOString() })\n }\n }\n await this.persistMeta()\n }\n\n /** Push dirty records to remote adapter. Accepts optional `PushOptions` for partial sync. */\n async push(options?: PushOptions): Promise<PushResult> {\n await this.ensureLoaded()\n if (options?.full) await this.markAllDirty()\n this.graphBatchController?.begin() // #638 Task 4\n\n let reserved = 0\n this.#pushRejected = []\n const conflicts: Conflict[] = []\n const erasures: ErasureEnforcement[] = []\n const errors: Error[] = []\n const completed: number[] = []\n\n // Partial sync: expand the filter to cover satellite pair partners (#591 rule 5b), then the\n // reserved `_dict_*` collections those (expanded) names depend on (#653) — a locally-dirty\n // dict edit pushes alongside push({collections:['orders']}), symmetric with pull below.\n const expanded = options?.collections ? (this.pairExpander?.(options.collections) ?? options.collections) : null\n const filter = expanded ? new Set([...expanded, ...(this.reservedDictExpander?.(expanded) ?? [])]) : null\n\n const pushTotal = filter ? this.dirty.filter(d => filter.has(d.collection)).length : this.dirty.length\n const acc = { pushed: 0, bytes: 0, completed, conflicts, erasures, errors }\n const eligible = [...this.dirty.keys()].filter(i => !filter || filter.has(this.dirty[i]!.collection))\n const width = Math.max(1, Math.floor(options?.concurrency ?? 1))\n // core#93 — a bounded pool: `width` entries in flight, each with its own CAS\n // and conflict path. width 1 is exactly the previous serial loop.\n let next = 0\n const worker = async (): Promise<void> => {\n while (next < eligible.length) {\n const i = eligible[next++]!\n this.progress({ direction: 'push', phase: 'records', records: acc.pushed, bytes: acc.bytes, total: { records: pushTotal } })\n await this.#pushOne(i, this.dirty[i]!, acc)\n }\n }\n await Promise.all(Array.from({ length: Math.min(width, eligible.length) }, () => worker()))\n const pushed = acc.pushed\n const pushBytes = acc.bytes\n\n // Remove completed entries from dirty log (reverse order to preserve indices)\n for (const i of completed.sort((a, b) => b - a)) {\n this.dirty.splice(i, 1)\n }\n\n // core#75 / core#83 — the target is a FULL replica only if it carries the\n // roster and the other declared reserved records (see reserved-mirror.ts).\n // They are written outside the dirty log, so they are mirrored here by\n // their own ordering (higher wins, absent receives), every push, every\n // role: a `backup` must be restorable too. Revocations travel through the\n // dirty loop above as `(collection, id, 'delete')`.\n // Not counted in `pushed`: that is a RECORD count, and consumers assert on it.\n if (!filter) {\n this.progress({ direction: 'push', phase: 'reserved', records: pushed, bytes: pushBytes, total: { records: pushTotal } })\n try {\n const mirrored = await pushReserved(this.local, this.remote, this.vault)\n reserved = mirrored.copied\n // core#96 (pilot-1, finding B) — a local keyring the target supersedes\n // was discarded by the epoch rule; say so, as a conflict on `_keyring`.\n for (const stale of mirrored.staleKeyrings ?? []) {\n conflicts.push({\n vault: this.vault, collection: '_keyring', id: stale.id, local: stale.local, remote: stale.remote,\n localVersion: stale.local._v, remoteVersion: stale.remote._v,\n })\n }\n } catch (err) {\n errors.push(err instanceof Error ? err : new Error(String(err)))\n }\n }\n this.progress({ direction: 'push', phase: 'records', records: pushed, bytes: pushBytes, total: { records: pushTotal } }, true)\n this.progressDone()\n\n this.recordOutcome('push', errors)\n try {\n await this.persistMeta()\n } finally {\n // #644 item 1: flush (which clears `_graphBatch` unconditionally, vault.ts:1316-1320) must\n // run even if `persistMeta()` throws — else a throw here leaves the batch open, corrupting\n // the NEXT pull()/push() call's wave with THIS call's stale touches.\n await this.graphBatchController?.flush() // #638 Task 4\n }\n\n const pushRejected = this.#pushRejected\n this.#pushRejected = []\n const result: PushResult = { pushed, conflicts, errors, erasures, ...(reserved > 0 && { reserved }), ...(pushRejected.length > 0 && { rejected: pushRejected }) }\n this.emitter.emit('sync:push', result)\n return result\n }\n\n /** Pull remote records to local adapter. Accepts optional `PullOptions` for partial sync. */\n async pull(options?: PullOptions): Promise<PullResult> {\n await this.ensureLoaded()\n\n let pulled = 0\n let reserved = 0\n this.#applied = []\n this.#rejected = []\n const conflicts: Conflict[] = []\n const errors: Error[] = []\n let crossed = { epoch: 0, resynced: false, parked: 0 }\n const erasures: ErasureEnforcement[] = []\n\n // core#75 / core#83 — the reserved set comes FIRST, before any record: a\n // device that bootstrapped from this target on open already holds its own\n // keyring file, but a grant or narrowing made elsewhere since must land\n // before the records it gates, and an invite audit doc before the accept\n // that needs it. A local record the remote lacks is a revocation — unless\n // the remote has never carried that collection, or a pending local write\n // protects it. If the caller's OWN keyring file was replaced, the vault\n // reloads it in place (core#82) — no reopen.\n if (!options?.collections) {\n this.progress({ direction: 'pull', phase: 'reserved', records: 0, bytes: 0 })\n try {\n const protectedIds = new Map<string, Set<string>>()\n for (const d of this.dirty) {\n if (d.action === 'delete') continue\n let set = protectedIds.get(d.collection)\n if (!set) { set = new Set(); protectedIds.set(d.collection, set) }\n set.add(d.id)\n }\n const mirrored = await pullReserved(this.remote, this.local, this.vault, protectedIds)\n reserved = mirrored.copied + mirrored.deleted\n if (this.rosterReload && mirrored.keyringsCopied.includes(this.rosterReload.userId)) await this.rosterReload.reload()\n } catch (err) {\n errors.push(err instanceof Error ? err : new Error(String(err)))\n }\n // core#107 — `_sync_rejections` has just landed; match it against what\n // this device holds. Here, not at the end of the pull, because a refusal\n // is about a version the WRITER already has locally — nothing later in\n // this run can make a stale verdict apply.\n try {\n await this.#scanReplicatedRejections()\n } catch (err) {\n errors.push(err instanceof Error ? err : new Error(String(err)))\n }\n }\n\n // core#72 — cross the target's restore epoch AFTER the reserved phase (the\n // roster mirrors by its own epoch and a fresh member device needs its seed\n // before its own mint can serve a request — core#97) and BEFORE any record:\n // unpushed local edits are parked before the target's records land. An\n // unreachable target is a pull error like any other, not a throw.\n try {\n crossed = await this.#crossEpoch()\n } catch (err) {\n errors.push(err instanceof Error ? err : new Error(String(err)))\n }\n\n // ── #807 period-scoped pull: validate the option, sync the period summaries\n // (`_periods` + companions — the navigation index, ALWAYS pulled in full,\n // exempt from every filter), then resolve the selected `_ts` windows from the\n // freshly synced index. All BEFORE the graph batch opens, so an invalid\n // option throws without leaving a batch dangling; summary applies route\n // through `applyRemote` like any pull (reserved names have no Collection\n // instance, so the invalidator/graph seams are no-ops for them). ──\n let periodScope: ((envelope: EncryptedEnvelope) => boolean) | null = null\n let phases: { summaries: { records: number; bytes: number }; records: { records: number; bytes: number } } | null = null\n if (options?.periods !== undefined) {\n validatePeriodsOption(options.periods)\n if (!this.periodPullSource) {\n throw new ValidationError(\n 'period-scoped pull requires a vault-attached sync engine (open the vault via createNoydb + openVault).',\n )\n }\n phases = { summaries: { records: 0, bytes: 0 }, records: { records: 0, bytes: 0 } }\n let remotePeriodCount = 0\n this.pullByteSink = phases.summaries\n try {\n for (const collName of PERIOD_SUMMARY_COLLECTIONS) {\n for (const id of await this.remote.list(this.vault, collName)) {\n if (collName === PERIODS_COLLECTION) remotePeriodCount++\n try {\n const remoteEnvelope = await this.remote.get(this.vault, collName, id)\n if (!remoteEnvelope) continue\n const localEnvelope = await this.local.get(this.vault, collName, id)\n if (!localEnvelope || this.#remoteSupersedes(collName, id, remoteEnvelope, localEnvelope)) {\n await this.applyRemote(collName, id, remoteEnvelope)\n pulled++\n }\n } catch (err) {\n errors.push(err instanceof Error ? err : new Error(String(err)))\n }\n }\n }\n } finally {\n this.pullByteSink = null\n }\n const periodRecords = await this.periodPullSource.periods()\n if (remotePeriodCount > 0 && periodRecords.length === 0) {\n throw new ValidationError(\n 'period-scoped pull: the vault holds _periods records but none are readable — enable the ' +\n 'periods service (`periodsStrategy: withPeriods()`) so pull can resolve the period windows.',\n )\n }\n periodScope = buildPeriodScope(options.periods, periodRecords)\n }\n\n this.graphBatchController?.begin() // #638 Task 4\n if (phases) this.pullByteSink = phases.records\n\n // Partial sync: expand the filter to cover satellite pair partners (#591 rule 5b), then the\n // reserved `_dict_*` collections those (expanded) names depend on (#653) — adopters never\n // name `_dict_*` in a `collections` filter, so a named collection's lookup-field dependency\n // must be pulled alongside it or its labels/membership go stale.\n const expanded = options?.collections ? (this.pairExpander?.(options.collections) ?? options.collections) : null\n const filter = expanded ? new Set([...expanded, ...(this.reservedDictExpander?.(expanded) ?? [])]) : null\n\n try {\n // core#81 — two ways to walk the remote. Default: one `loadAll()`, the\n // total known once the snapshot is down, progress measuring the APPLY\n // phase. Paged: the collections this keyring names (∩ the filter), one\n // page in memory at a time, the total counted by `list()` BEFORE the\n // first apply. Same loop body either way.\n let pullTotal = 0\n let chunks: Iterable<[string, Record<string, EncryptedEnvelope>]> | AsyncIterable<[string, Record<string, EncryptedEnvelope>]>\n if (options?.paged) {\n const known = new Set(this.collectionNames?.() ?? [])\n for (const name of filter ?? []) if (!name.startsWith('_')) known.add(name)\n const names = [...known].filter(n => !n.startsWith('_') && (!filter || filter.has(n)))\n for (const name of names) pullTotal += (await this.remote.list(this.vault, name)).length\n chunks = this.pagedChunks(names)\n } else {\n const remoteSnapshot = await this.remote.loadAll(this.vault)\n for (const [collName, records] of Object.entries(remoteSnapshot)) {\n if (filter && !filter.has(collName)) continue\n pullTotal += Object.keys(records).length\n }\n chunks = Object.entries(remoteSnapshot)\n }\n const pullSample = (): SyncProgress => ({\n direction: 'pull', phase: 'records', records: pulled, bytes: this.pullBytes, total: { records: pullTotal },\n })\n\n for await (const [collName, records] of chunks) {\n // Partial sync: skip collections not in the filter\n if (filter && !filter.has(collName)) {\n continue\n }\n\n for (const [id, remoteEnvelope] of Object.entries(records)) {\n this.progress(pullSample())\n // Partial sync: modifiedSince filter — arriving tombstones are exempt (#590):\n // an erasure must never be skipped by partial sync.\n if (\n options?.modifiedSince &&\n remoteEnvelope._ts <= options.modifiedSince &&\n !isTombstoneShape(remoteEnvelope) &&\n !isDeleteMarker(remoteEnvelope)\n ) {\n continue\n }\n\n // #807: period scope — a record whose `_ts` falls outside every selected\n // window is skipped. Tombstones and delete markers are ALWAYS in scope\n // (built into the predicate): an erasure or delete must never be skipped\n // by partial sync, mirroring the modifiedSince exemption above — that is\n // what lets a device that never pulled a period backfill it later without\n // resurrecting its deleted records.\n if (periodScope !== null && !periodScope(remoteEnvelope)) {\n continue\n }\n\n try {\n const localEnvelope = await this.local.get(this.vault, collName, id)\n const remoteIsTombstone = isTombstoneShape(remoteEnvelope)\n\n if (!localEnvelope) {\n // New record from remote (tombstones included — durable erasure evidence)\n await this.applyRemote(collName, id, remoteEnvelope)\n pulled++\n } else if (isTombstoneShape(localEnvelope)) {\n if (remoteIsTombstone) {\n // Both shredded — keep the higher version counter\n if (remoteEnvelope._v > localEnvelope._v) await this.applyRemote(collName, id, remoteEnvelope)\n } else {\n // Terminal rule (#590): a tombstone is never overwritten by a live\n // envelope, regardless of _v. Re-assert the shred outward instead.\n erasures.push(await this.reassertTombstone(collName, id, localEnvelope, remoteEnvelope))\n }\n } else if (remoteIsTombstone) {\n // Terminal rule (#590): an arriving tombstone wins over any local live\n // envelope — even a newer, dirty one. Resolvers are never consulted.\n const wasDirty = this.dirty.some(d => d.collection === collName && d.id === id)\n await this.applyRemote(collName, id, remoteEnvelope)\n this.dirty = this.dirty.filter(d => !(d.collection === collName && d.id === id))\n pulled++\n if (wasDirty) erasures.push(this.reportErasure(collName, id, remoteEnvelope, localEnvelope, 'pull'))\n } else if (\n remoteEnvelope._v === localEnvelope._v &&\n isDeleteMarker(remoteEnvelope) !== isDeleteMarker(localEnvelope)\n ) {\n // #589: true concurrent delete-vs-edit at the SAME version. Version order\n // can't break the tie. A per-collection resolver decides if one is set;\n // otherwise DELETE wins (the db-level 'version' default is deliberately NOT\n // consulted — it would resolve a tie to local-wins).\n const resolver = this.conflictResolvers.get(collName)\n if (resolver) {\n const winner = await resolver(id, localEnvelope, remoteEnvelope)\n if (winner !== localEnvelope && winner !== null) {\n // #589 (review): a novel/merged winner (neither side verbatim) must also be\n // pushed to remote — mirrors handleConflict's 'merged' handling — so both\n // sides converge instead of local applying it while remote keeps its old copy.\n if (winner !== remoteEnvelope) {\n await this.remote.put(this.vault, collName, id, winner)\n }\n await this.applyRemote(collName, id, winner)\n this.dirty = this.dirty.filter(d => !(d.collection === collName && d.id === id))\n pulled++\n }\n // winner === localEnvelope or null → keep local (its dirty entry, if any, pushes out)\n } else if (isDeleteMarker(remoteEnvelope)) {\n // no resolver → delete wins; the incoming marker is the delete\n await this.applyRemote(collName, id, remoteEnvelope)\n this.dirty = this.dirty.filter(d => !(d.collection === collName && d.id === id))\n pulled++\n }\n // no resolver and LOCAL is the marker → keep local marker; its dirty 'put' pushes it outward\n } else if (this.#remoteSupersedes(collName, id, remoteEnvelope, localEnvelope)) {\n // Remote is newer — check if we have a dirty entry for this\n const isDirty = this.dirty.some(d => d.collection === collName && d.id === id)\n if (isDirty) {\n // Both changed — conflict\n const { handled, conflict } = await this.handleConflict(\n collName,\n id,\n localEnvelope,\n remoteEnvelope,\n 'pull',\n )\n conflicts.push(conflict)\n if (handled === 'remote') {\n await this.applyRemote(collName, id, conflict.remote)\n this.dirty = this.dirty.filter(d => !(d.collection === collName && d.id === id))\n pulled++\n } else if (handled === 'merged' && conflict.local !== localEnvelope) {\n const merged = conflict.local\n await this.applyRemote(collName, id, merged)\n this.dirty = this.dirty.filter(d => !(d.collection === collName && d.id === id))\n pulled++\n }\n // 'local' or 'deferred': push handles it\n } else {\n // Remote is newer, no local changes — update\n await this.applyRemote(collName, id, remoteEnvelope)\n pulled++\n }\n }\n // Same version or local is newer — skip (push will handle)\n } catch (err) {\n errors.push(err instanceof Error ? err : new Error(String(err)))\n }\n }\n }\n\n // #650 Task 4 (#647) — reserved lookup collections (`_dict_*`/`_lookup_*`) are invisible to\n // `remote.loadAll()` above (the store contract skips `_`-prefixed names) but DO sync via\n // this EXPLICIT, declared registry — not a blanket underscore-glob; other `_` namespaces\n // keep their `loadAll`-skip semantics untouched. Applied through the SAME `applyRemote` path,\n // still inside this try block, BEFORE `persistMeta`/`flush` below — so a pulled vocabulary\n // row lands before the wave (flushed at the end of `pull()`) recomputes any dependent.\n //\n // #647 fix wave 1: `LookupHandle.delete()`/`rename()` now write a version-ordered\n // delete-marker row (mirroring #589) instead of a raw adapter delete, so a removed key is\n // a normal row here too — reachable via `remote.list()` like any other id, applied by\n // version like any other write. The only reserved-tier-specific rule is the same-version\n // tie-break below: reserved lookups have no per-collection conflict-resolver concept\n // (dictionaries are admin-edited, not multi-actor-negotiated), so a converging delete\n // unconditionally wins over a same-version live edit.\n //\n // #807: the period scope deliberately does NOT apply here — vocabularies/config rows are\n // not period-partitioned data (a thin client's lookups must be complete regardless of\n // which periods it pulled), the same always-pull rule as the `_periods` summaries phase.\n for (const collName of this.reservedLookup?.collections() ?? []) {\n if (filter && !filter.has(collName)) continue\n for (const id of await this.remote.list(this.vault, collName)) {\n try {\n const remoteEnvelope = await this.remote.get(this.vault, collName, id)\n if (!remoteEnvelope) continue\n\n // Partial sync: modifiedSince filter — a delete marker is exempt, mirroring the\n // main loop's tombstone/marker exemption above: a deletion must never be silently\n // skipped by a time-window partial pull.\n if (\n options?.modifiedSince &&\n remoteEnvelope._ts <= options.modifiedSince &&\n !isDeleteMarker(remoteEnvelope)\n ) {\n continue\n }\n\n const localEnvelope = await this.local.get(this.vault, collName, id)\n if (!localEnvelope) {\n await this.applyRemote(collName, id, remoteEnvelope)\n pulled++\n } else if (\n remoteEnvelope._v === localEnvelope._v &&\n isDeleteMarker(remoteEnvelope) !== isDeleteMarker(localEnvelope)\n ) {\n // Same-version delete-vs-edit tie (#589's rule, reserved-tier default: no\n // resolver concept here, so delete always wins).\n if (isDeleteMarker(remoteEnvelope)) {\n await this.applyRemote(collName, id, remoteEnvelope)\n this.dirty = this.dirty.filter(d => !(d.collection === collName && d.id === id))\n pulled++\n }\n // else: local already holds the marker (a local delete not yet observed\n // remotely) — keep it; push re-asserts it.\n } else if (this.#remoteSupersedes(collName, id, remoteEnvelope, localEnvelope)) {\n await this.applyRemote(collName, id, remoteEnvelope)\n // Drop any now-superseded local dirty entry so a subsequent push doesn't\n // redundantly re-fight a CAS conflict over content pull just overwrote.\n this.dirty = this.dirty.filter(d => !(d.collection === collName && d.id === id))\n pulled++\n }\n } catch (err) {\n errors.push(err instanceof Error ? err : new Error(String(err)))\n }\n }\n }\n } catch (err) {\n errors.push(err instanceof Error ? err : new Error(String(err)))\n }\n\n this.progress({ direction: 'pull', phase: 'records', records: pulled, bytes: this.pullBytes, total: { records: pulled } }, true)\n this.progressDone()\n this.pullBytes = 0\n this.recordOutcome('pull', errors)\n try {\n await this.persistMeta()\n } finally {\n this.pullByteSink = null // #807: stop attributing applies to this pull's KPI counters\n // #644 item 1: flush must run even if `persistMeta()` throws (see push()'s identical guard).\n await this.graphBatchController?.flush() // #638 Task 4\n }\n\n // core#74 — the callers counted a refused record before admission spoke.\n pulled = Math.max(0, pulled - this.#rejected.length)\n const applied = this.#applied, rejected = this.#rejected\n this.#applied = []; this.#rejected = []\n const result: PullResult = {\n pulled, conflicts, errors, erasures, ...(reserved > 0 && { reserved }), ...(phases !== null ? { phases } : {}),\n ...(applied.length > 0 && { applied }), ...(rejected.length > 0 && { rejected }),\n ...(crossed.epoch > 0 && { epoch: crossed.epoch }), ...(crossed.resynced && { resynced: true as const }),\n }\n this.emitter.emit('sync:pull', result)\n return result\n }\n\n /** Bidirectional sync: pull then push. */\n async sync(options?: { push?: PushOptions; pull?: PullOptions }): Promise<{ pull: PullResult; push: PushResult }> {\n const pullResult = await this.pull(options?.pull)\n const pushResult = await this.push(options?.push)\n return { pull: pullResult, push: pushResult }\n }\n\n /**\n * Push a specific subset of dirty entries (for sync transactions, ).\n * Entries are matched by collection+id from the dirty log; matched entries\n * are removed from the dirty log on success.\n */\n async pushFiltered(predicate: (entry: DirtyEntry) => boolean): Promise<PushResult> {\n await this.ensureLoaded()\n\n let pushed = 0\n this.#pushRejected = []\n const conflicts: Conflict[] = []\n const erasures: ErasureEnforcement[] = []\n const errors: Error[] = []\n const completed: number[] = []\n\n for (let i = 0; i < this.dirty.length; i++) {\n const entry = this.dirty[i]!\n if (!predicate(entry)) continue\n\n try {\n if (entry.action === 'delete') {\n await this.remote.delete(this.vault, entry.collection, entry.id)\n completed.push(i)\n pushed++\n } else {\n const envelope = await this.local.get(this.vault, entry.collection, entry.id)\n if (!envelope) {\n completed.push(i)\n continue\n }\n\n if (isTombstoneShape(envelope)) {\n // #590: a tombstone push is an erasure assertion — unconditional,\n // no CAS, no conflict resolution. Erasure always wins.\n await this.remote.put(this.vault, entry.collection, entry.id, envelope)\n completed.push(i)\n pushed++\n continue\n }\n\n // core#108 — same re-check as `push()`. This path duplicates the CAS\n // logic rather than sharing `#pushOne`, so the gate has to be wired\n // twice; leaving it out here would make `pushFiltered` the way round it.\n if (await this.#withheldByRecheck(entry, envelope)) continue\n\n try {\n await this.remote.put(\n this.vault,\n entry.collection,\n entry.id,\n envelope,\n entry.version - 1,\n )\n completed.push(i)\n pushed++\n } catch (err) {\n if (isConflictError(err)) {\n const remoteEnvelope = await this.remote.get(this.vault, entry.collection, entry.id)\n if (remoteEnvelope) {\n if (isTombstoneShape(remoteEnvelope)) {\n // #590: remote already shredded this record — enforce locally,\n // never resolve. Resolvers must not overrule an erasure.\n await this.applyRemote(entry.collection, entry.id, remoteEnvelope)\n erasures.push(this.reportErasure(entry.collection, entry.id, remoteEnvelope, envelope, 'push'))\n completed.push(i)\n } else if (\n remoteEnvelope._v === envelope._v &&\n isDeleteMarker(remoteEnvelope) !== isDeleteMarker(envelope) &&\n !this.conflictResolvers.get(entry.collection)\n ) {\n // #589: a same-_v delete-vs-edit tie on the push channel. handleConflict's db-level\n // 'version' default would resolve it to local-wins; the tie rule consults ONLY the\n // per-collection resolver, else delete-wins. (When a per-collection resolver IS set,\n // fall through to handleConflict, which already honors it — incl. the merged case.)\n if (isDeleteMarker(remoteEnvelope)) {\n // remote already deleted → converge locally, drop our (edit) push\n await this.applyRemote(entry.collection, entry.id, remoteEnvelope)\n completed.push(i)\n } else {\n // our local is the marker → force the delete onto the remote (unconditional put)\n await this.remote.put(this.vault, entry.collection, entry.id, envelope)\n completed.push(i)\n pushed++\n }\n } else {\n const { handled, conflict } = await this.handleConflict(\n entry.collection,\n entry.id,\n envelope,\n remoteEnvelope,\n 'push',\n )\n conflicts.push(conflict)\n if (handled === 'local') {\n // #936: supersede, don't overwrite in place — see advancePastRemote.\n const winner = await this.advancePastRemote(conflict.local, entry.collection, entry.id, remoteEnvelope)\n await this.remote.put(this.vault, entry.collection, entry.id, winner)\n if (winner !== conflict.local) await this.applyRemote(entry.collection, entry.id, winner, { admit: false })\n completed.push(i)\n pushed++\n } else if (handled === 'remote') {\n await this.applyRemote(entry.collection, entry.id, conflict.remote)\n completed.push(i)\n } else if (handled === 'merged' && conflict.local !== envelope) {\n const merged = conflict.local\n await this.remote.put(this.vault, entry.collection, entry.id, merged)\n await this.applyRemote(entry.collection, entry.id, merged)\n completed.push(i)\n pushed++\n }\n }\n }\n } else {\n throw err\n }\n }\n }\n } catch (err) {\n errors.push(err instanceof Error ? err : new Error(String(err)))\n }\n }\n\n for (const i of completed.sort((a, b) => b - a)) {\n this.dirty.splice(i, 1)\n }\n\n this.recordOutcome('push', errors)\n await this.persistMeta()\n\n const pushRejected = this.#pushRejected\n this.#pushRejected = []\n const result: PushResult = { pushed, conflicts, errors, erasures, ...(pushRejected.length > 0 && { rejected: pushRejected }) }\n this.emitter.emit('sync:push', result)\n return result\n }\n\n /**\n * #1036 — close out a push/pull. `push()` and `pull()` collect per-record\n * failures into their result's `errors` rather than throwing, and the clock used\n * to be stamped regardless — so an unreachable store still reported a fresh\n * `lastPush`, and a UI rendered \"Last synced: just now\" over a sync that moved\n * nothing. An attempt only advances the clock when it had no errors.\n *\n * An empty dirty log is a success, not a failure: nothing to send is not the\n * same as failing to send, and treating it otherwise would leave a quiet vault\n * looking permanently unsynced.\n */\n private recordOutcome(op: 'push' | 'pull', errors: readonly Error[]): void {\n const at = new Date().toISOString()\n if (errors.length > 0) {\n this.lastError = { at, op, message: errors[0]!.message }\n return\n }\n this.lastError = null\n if (op === 'push') this.lastPush = at\n else this.lastPull = at\n }\n\n /** Get current sync status. */\n /**\n * core#82 — re-align a CORRUPTED local from the target. An ordinary pull\n * cannot repair a damaged local envelope: it keeps its `_v`, so it wins\n * (or ties) against the target's healthy copy. Here every local\n * user-collection envelope is verified with the same `MergeAuthority`\n * check pull runs on remote envelopes; one that fails is replaced by the\n * target's copy when THAT verifies, and the dirty log is dropped (a dirty\n * entry over a damaged record would push the damage). Records at a tier\n * the caller holds no key for pass unverified, as in pull — this repairs\n * what the caller can read. Requires a `MergeAuthority` (a vault-attached\n * engine on an encrypted vault).\n */\n /**\n * core#96 (pilot-1, finding B) — bring one member's keyring file down from\n * this target if the target's copy supersedes ours. Called by the kernel\n * before an authority edit; reloads the caller's own keyring in place when\n * it is the one refreshed (core#82).\n */\n async refreshKeyring(userId: string): Promise<boolean> {\n await this.ensureLoaded()\n const copied = await pullKeyringFile(this.remote, this.local, this.vault, userId)\n if (copied && this.rosterReload && userId === this.rosterReload.userId) await this.rosterReload.reload()\n return copied\n }\n\n async realign(): Promise<RealignResult> {\n await this.ensureLoaded()\n if (!this.mergeAuthority) throw new ValidationError('realign: requires a vault-attached engine on an encrypted vault (no MergeAuthority).')\n const errors: Error[] = []\n let checked = 0\n let replaced = 0\n let unrecoverable = 0\n const local = await this.local.loadAll(this.vault)\n for (const [collection, records] of Object.entries(local)) {\n for (const [id, envelope] of Object.entries(records)) {\n checked++\n if (isTombstoneShape(envelope) || isDeleteMarker(envelope)) continue\n if (await this.mergeAuthority.verify(collection, id, envelope)) continue\n const remote = await this.remote.get(this.vault, collection, id)\n if (remote && (await this.mergeAuthority.verify(collection, id, remote))) {\n await this.local.put(this.vault, collection, id, remote)\n await this.cacheInvalidator?.(collection, id, 'put')\n replaced++\n } else {\n unrecoverable++\n errors.push(new ValidationError(`realign: \"${collection}/${id}\" fails to authenticate locally and the target holds no healthy copy.`))\n }\n }\n }\n this.dirty = []\n await this.persistMeta()\n return { checked, replaced, unrecoverable, errors }\n }\n\n status(): SyncStatus {\n // #809 — readiness rides the status surface that already exists rather than\n // a second accessor, so an app asks one question to learn everything about\n // this vault's sync. Absent entirely unless a phased policy is running.\n const scheduled = this.scheduler?.status\n return {\n dirty: this.dirty.length,\n lastPush: this.lastPush,\n lastPull: this.lastPull,\n ...(this.epoch !== null ? { epoch: this.epoch } : {}), // core#72\n ...(this.inFlight ? { inFlight: this.inFlight } : {}),\n online: this.isOnline,\n ...(this.lastError ? { lastError: this.lastError } : {}),\n ...(scheduled && scheduled.readiness.size > 0\n ? { readiness: scheduled.readiness, phase: scheduled.phase }\n : {}),\n }\n }\n\n // ─── Auto-Sync ───────────────────────────────────────────────────\n\n /** Start auto-sync: listen for online/offline events, optional periodic sync. */\n startAutoSync(intervalMs?: number): void {\n // Online/offline detection\n if (typeof globalThis.addEventListener === 'function') {\n globalThis.addEventListener('online', this.handleOnline)\n globalThis.addEventListener('offline', this.handleOffline)\n }\n\n // Periodic sync\n if (intervalMs && intervalMs > 0) {\n this.autoSyncInterval = setInterval(() => {\n if (this.isOnline) {\n void this.sync()\n }\n }, intervalMs)\n }\n }\n\n /** Stop auto-sync and scheduler. */\n stopAutoSync(): void {\n this.stopScheduler()\n if (typeof globalThis.removeEventListener === 'function') {\n globalThis.removeEventListener('online', this.handleOnline)\n globalThis.removeEventListener('offline', this.handleOffline)\n }\n if (this.autoSyncInterval) {\n clearInterval(this.autoSyncInterval)\n this.autoSyncInterval = null\n }\n }\n\n private handleOnline = (): void => {\n this.isOnline = true\n this.emitter.emit('sync:online', undefined as never)\n void this.sync()\n }\n\n private handleOffline = (): void => {\n this.isOnline = false\n this.emitter.emit('sync:offline', undefined as never)\n }\n\n /** Apply an envelope to the local store and refresh in-memory views (#598). `action` (#640):\n * classified HERE — the one choke point that still holds the envelope — so the\n * cacheInvalidator seam (and, downstream, the dispatch wave) can tell a pulled delete from an\n * ordinary put. `isTombstoneShape` covers a forgotten-elsewhere record arriving as a shred;\n * `isDeleteMarker` covers an ordinary (#589) delete — both route to the SAME 'delete' action\n * (sync delete ≠ forget: freshness only, no shred/residue channel on the receiving side). */\n /**\n * #936 — a local-wins resolution write must SUPERSEDE the remote, never\n * overwrite it in place: when the winner's `_v` does not already exceed\n * the remote's (the same-`_v` push tie), re-stamp it at `remote._v + 1`.\n * Without this the loser's next pull sees no delta (`_v`-based\n * detection) and the peers stay silently diverged at the same version.\n * ## Why this is async, and why it goes through `MergeAuthority` (#1093)\n *\n * It used to be `{ ...winner, _v: remote._v + 1 }` — a metadata restamp on\n * ciphertext the engine cannot decrypt. That spread was the SOLE reason `_v`\n * could not be bound into the AAD: a version rewritten onto a body sealed at\n * a different one produces a record no reader can open.\n *\n * `with-sync` is DEK-free by design and `check:architecture` enforces it, so\n * the re-seal cannot happen here. It happens in the injected authority, which\n * holds the keys. The engine still decides WHICH version to advance to; it\n * simply no longer pretends it can rewrite a sealed body.\n *\n * The authority is ALWAYS present in the product — `kernel/noydb.ts` builds\n * one from the keyring and passes it at both engine-construction sites, and\n * `with-sync/active.ts` is the only place an engine is constructed. The\n * fallback below is reachable only by constructing `SyncEngine` directly,\n * which tests do. It restamps, as before — and would produce an unreadable\n * record if such a test ever held AEAD-sealed envelopes. None do; the\n * fixtures that reach it build their own plaintext ones.\n *\n * The 'merged' branch needs none of this: resolver output is already stamped\n * `max(local, remote) + 1` by whoever built it.\n */\n private async advancePastRemote(winner: EncryptedEnvelope, collection: string, id: string, remote: EncryptedEnvelope): Promise<EncryptedEnvelope> {\n if (winner._v > remote._v) return winner\n const toVersion = remote._v + 1\n if (!this.mergeAuthority) return { ...winner, _v: toVersion }\n return this.mergeAuthority.advance(collection, id, winner, toVersion)\n }\n\n /**\n * core#100 — does the remote copy supersede ours? A higher `_v`, as always;\n * or the SAME `_v` with different bytes while we hold no pending write for\n * it: a DEK rotation re-encrypts records in place, and a replica that kept\n * the old ciphertext would read `TamperedError` under the delivered key.\n * `applyRemote` still authenticates it (`MergeAuthority`) before it lands.\n */\n #remoteSupersedes(collection: string, id: string, remote: EncryptedEnvelope, local: EncryptedEnvelope): boolean {\n if (remote._v > local._v) return true\n if (remote._v !== local._v) return false\n if (this.dirty.some(d => d.collection === collection && d.id === id)) return false\n return envelopeBodyForHash(remote) !== envelopeBodyForHash(local)\n }\n\n private async applyRemote(collection: string, id: string, envelope: EncryptedEnvelope, opts?: { readonly admit?: boolean }): Promise<void> {\n // #1042 — FAIL CLOSED, and do it HERE rather than at the 14 call sites.\n // Every path that commits store-supplied ciphertext goes through this\n // function, so gating it once covers them all by construction instead of by\n // remembering. A gate added per-caller is a gate someone forgets.\n //\n // Throwing is the correct shape, not a shortcut: each pull entry is wrapped\n // in its own try/catch that records the error and moves on, so a poisoned\n // record becomes one `PullResult.errors` entry rather than a halted sync —\n // which is exactly what a hostile store would want.\n //\n // Ordering is the whole point: this runs BEFORE `local.put`, so a rejection\n // costs the client nothing. Its existing copy is untouched.\n if (this.mergeAuthority && !(await this.mergeAuthority.verify(collection, id, envelope))) {\n throw new ValidationError(\n `sync: refusing remote envelope for \"${collection}/${id}\" — it does not authenticate at the ` +\n 'identity and version it claims. The local copy is unchanged.',\n )\n }\n // core#74 — ADMISSION. The vault runs its gates and hooks on the decrypted\n // incoming record against this device's state. Erasures are never gated.\n // A refusal is a fate, not an error: parked with the envelope intact, the\n // local copy untouched, reported and emitted. `pulled` is corrected at the\n // end of the run (the callers count before they know).\n // `admit: false` (pilot-1 on #74): this device's OWN record, re-versioned past\n // the remote after a conflict it won — it passed the writer's gate when it\n // was written; judging it again as `sync-apply` is wrong and confusing.\n const isErasure = isTombstoneShape(envelope) || isDeleteMarker(envelope)\n if (this.admission && !isErasure && opts?.admit !== false) {\n const verdict = await this.admission.admit(collection, id, envelope)\n if (!verdict.admitted) {\n this.#rejected.push(await this.#park(collection, id, envelope, verdict.reason, 'sync-apply'))\n return\n }\n }\n const prior = await this.local.get(this.vault, collection, id)\n await this.local.put(this.vault, collection, id, envelope)\n this.#applied.push({\n collection, id, action: isErasure ? 'delete' : 'put',\n ...(prior && prior._v < envelope._v ? { replaced: { version: prior._v, ...(prior._by !== undefined ? { by: prior._by } : {}) } } : {}),\n })\n this.pullBytes += envelopeBodySize(envelope) // core#81\n if (this.pullByteSink !== null) {\n // #807: KPI — one applied envelope; bytes ≈ ciphertext payload size.\n this.pullByteSink.records++\n this.pullByteSink.bytes += envelopeBodySize(envelope)\n }\n const action: 'put' | 'delete' = isTombstoneShape(envelope) || isDeleteMarker(envelope) ? 'delete' : 'put'\n await this.cacheInvalidator?.(collection, id, action)\n }\n\n /** Record + emit a tombstone enforcement (#590). */\n private reportErasure(\n collection: string, id: string,\n tombstone: EncryptedEnvelope, suppressed: EncryptedEnvelope,\n direction: 'pull' | 'push',\n ): ErasureEnforcement {\n const enforcement: ErasureEnforcement = { vault: this.vault, collection, id, tombstone, suppressed, direction }\n this.emitter.emit('sync:erasure', enforcement)\n return enforcement\n }\n\n /**\n * Re-assert a local tombstone over a live remote envelope (#590): the shred\n * wins in both directions, regardless of `_v`. Bumps the tombstone to the\n * suppressed envelope's `_v` when higher so per-key version counters stay\n * monotonic on every store; `_by` (the shredding actor) is preserved.\n */\n private async reassertTombstone(\n collection: string, id: string,\n tombstone: EncryptedEnvelope, suppressedRemote: EncryptedEnvelope,\n ): Promise<ErasureEnforcement> {\n let winner = tombstone\n if (suppressedRemote._v > tombstone._v) {\n winner = { ...tombstone, _v: suppressedRemote._v, _ts: new Date().toISOString() }\n await this.applyRemote(collection, id, winner)\n }\n await this.remote.put(this.vault, collection, id, winner)\n // The re-assert already delivered the tombstone remotely — drop any dirty\n // entry so the following push doesn't redundantly re-put it.\n this.dirty = this.dirty.filter(d => !(d.collection === collection && d.id === id))\n return this.reportErasure(collection, id, winner, suppressedRemote, 'pull')\n }\n\n /**\n * Resolve a conflict, checking per-collection resolvers first,\n * then falling back to the db-level `ConflictStrategy`.\n *\n * Returns the resolved `Conflict` object (possibly with `resolve` set for\n * manual mode) and a `handled` discriminant:\n * - `'local'` — keep the local envelope; push it to remote.\n * - `'remote'` — keep the remote envelope; update local.\n * - `'merged'` — a custom merge fn produced a new envelope stored as `conflict.local`.\n * - `'deferred'` — manual mode, resolve was not called synchronously.\n */\n private async handleConflict(\n collection: string,\n id: string,\n local: EncryptedEnvelope,\n remote: EncryptedEnvelope,\n _phase: 'push' | 'pull',\n ): Promise<{ handled: 'local' | 'remote' | 'merged' | 'deferred'; conflict: Conflict }> {\n const resolver = this.conflictResolvers.get(collection)\n\n if (resolver) {\n // Per-collection resolver is responsible for emitting sync:conflict\n // (manual policy emits with a resolve callback; LWW/FWW/custom are silent).\n const winner = await resolver(id, local, remote)\n const base: Conflict = {\n vault: this.vault,\n collection,\n id,\n local,\n remote,\n localVersion: local._v,\n remoteVersion: remote._v,\n }\n if (winner === null) return { handled: 'deferred', conflict: base }\n if (winner === local) return { handled: 'local', conflict: base }\n if (winner === remote) return { handled: 'remote', conflict: base }\n // Custom merge fn produced a new envelope — store as conflict.local for the caller\n return {\n handled: 'merged',\n conflict: { ...base, local: winner, localVersion: winner._v },\n }\n }\n\n // Fall back to db-level strategy — emit once\n const baseConflict: Conflict = {\n vault: this.vault,\n collection,\n id,\n local,\n remote,\n localVersion: local._v,\n remoteVersion: remote._v,\n }\n this.emitter.emit('sync:conflict', baseConflict)\n const side = this.legacyResolve(baseConflict)\n return { handled: side, conflict: baseConflict }\n }\n\n /** DB-level ConflictStrategy resolution (legacy, kept for backward compat). */\n private legacyResolve(conflict: Conflict): 'local' | 'remote' {\n if (typeof this.strategy === 'function') {\n return this.strategy(conflict)\n }\n switch (this.strategy) {\n case 'local-wins': return 'local'\n case 'remote-wins': return 'remote'\n case 'version':\n default:\n return conflict.localVersion >= conflict.remoteVersion ? 'local' : 'remote'\n }\n }\n\n // ─── Persistence ─────────────────────────────────────────────────\n\n private async ensureLoaded(): Promise<void> {\n if (this.loaded) return\n\n const envelope = await this.local.get(this.vault, '_sync', 'meta')\n if (envelope) {\n const meta = JSON.parse(envelope._data ?? '') as SyncMetadata\n this.dirty = [...meta.dirty]\n this.lastPush = meta.last_push\n this.lastPull = meta.last_pull\n this.epoch = meta.epoch ?? null\n }\n\n this.loaded = true\n }\n\n private async persistMeta(): Promise<void> {\n const meta: SyncMetadata = {\n _noydb_sync: NOYDB_SYNC_VERSION,\n last_push: this.lastPush,\n last_pull: this.lastPull,\n dirty: this.dirty,\n ...(this.epoch !== null ? { epoch: this.epoch } : {}),\n }\n\n const envelope: EncryptedEnvelope = buildRecordEnvelope(\n { collection: '_sync', id: 'meta', version: 1 },\n { iv: '', data: JSON.stringify(meta) },\n )\n\n await this.local.put(this.vault, '_sync', 'meta', envelope)\n }\n}\n","import type { SyncTransactionResult } from '../kernel/types.js'\nimport type { SyncEngine } from './engine.js'\nimport type { Vault } from '../kernel/vault.js'\n\ninterface TxOp {\n readonly type: 'put' | 'delete'\n readonly collection: string\n readonly id: string\n readonly record?: unknown\n}\n\n/**\n * Sync transaction.\n *\n * Stages local writes and then pushes only those records to remote in a\n * single batch. If any record conflicts during the push, the result\n * carries `status: 'conflict'` — no automatic rollback is performed;\n * the caller handles conflict resolution.\n *\n * Obtain via `db.transaction(compartmentName)`.\n */\nexport class SyncTransaction {\n private readonly comp: Vault\n private readonly engine: SyncEngine\n private readonly ops: TxOp[] = []\n\n /** @internal — constructed by `Noydb.transaction()` */\n constructor(comp: Vault, engine: SyncEngine) {\n this.comp = comp\n this.engine = engine\n }\n\n /** Stage a record write. Does not write to any adapter until `commit()`. */\n put(collection: string, id: string, record: unknown): this {\n this.ops.push({ type: 'put', collection, id, record })\n return this\n }\n\n /** Stage a record delete. Does not write to any adapter until `commit()`. */\n delete(collection: string, id: string): this {\n this.ops.push({ type: 'delete', collection, id })\n return this\n }\n\n /**\n * Commit the transaction.\n *\n * Phase 1 — writes all staged operations to the local adapter via the\n * collection layer (encryption + dirty-log tracking).\n *\n * Phase 2 — pushes only the records that were written in this\n * transaction to the remote adapter. Existing dirty entries from\n * outside this transaction are not affected.\n *\n * If any record conflicts during the push, `status` is `'conflict'`\n * and `conflicts` lists the affected records. No automatic rollback is\n * performed.\n */\n async commit(): Promise<SyncTransactionResult> {\n // Phase 1: write all staged ops to local via collection layer\n for (const op of this.ops) {\n if (op.type === 'put') {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n await (this.comp.collection<any>(op.collection)).put(op.id, op.record as any)\n } else {\n await this.comp.collection(op.collection).delete(op.id)\n }\n }\n\n // Phase 2: push only the records from this transaction\n const opSet = new Set<string>()\n for (const op of this.ops) {\n opSet.add(`${op.collection}::${op.id}`)\n }\n\n const pushResult = await this.engine.pushFiltered(\n (entry) => opSet.has(`${entry.collection}::${entry.id}`),\n )\n\n return {\n status: pushResult.conflicts.length > 0 ? 'conflict' : 'committed',\n pushed: pushResult.pushed,\n conflicts: pushResult.conflicts,\n ...(pushResult.erasures?.length ? { erasures: pushResult.erasures } : {}),\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
buildRecordEnvelope,
|
|
7
7
|
encrypt,
|
|
8
8
|
openEnvelopeJson
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-WRLWEYHY.js";
|
|
10
10
|
|
|
11
11
|
// src/with-audit/consent/consent.ts
|
|
12
12
|
var CONSENT_AUDIT_COLLECTION = "_consent_audit";
|
|
@@ -62,4 +62,4 @@ export {
|
|
|
62
62
|
writeConsentEntry,
|
|
63
63
|
loadConsentEntries
|
|
64
64
|
};
|
|
65
|
-
//# sourceMappingURL=chunk-
|
|
65
|
+
//# sourceMappingURL=chunk-ND6S2DKC.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SatelliteConfigError
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-2RH5SEY7.js";
|
|
4
4
|
|
|
5
5
|
// src/with-shape/satellites/validate.ts
|
|
6
6
|
function validateSatelliteDeclaration(input) {
|
|
@@ -47,4 +47,4 @@ export {
|
|
|
47
47
|
validateSatelliteDeclaration,
|
|
48
48
|
hashFields
|
|
49
49
|
};
|
|
50
|
-
//# sourceMappingURL=chunk-
|
|
50
|
+
//# sourceMappingURL=chunk-NHEKQWFI.js.map
|
|
@@ -7,15 +7,15 @@ import {
|
|
|
7
7
|
joinsDropLeftRows,
|
|
8
8
|
orderReferencesJoinAlias,
|
|
9
9
|
splitAroundJoins
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-TBVDI3LY.js";
|
|
11
11
|
import {
|
|
12
12
|
describeJoinOn,
|
|
13
13
|
joinOnDispatch,
|
|
14
14
|
normalizeJoinOn
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-OK44MD3C.js";
|
|
16
16
|
import {
|
|
17
17
|
ScanBuilder
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-GZISWBCJ.js";
|
|
19
19
|
import {
|
|
20
20
|
installMethods
|
|
21
21
|
} from "./chunk-F6NCB7KT.js";
|
|
@@ -27,22 +27,22 @@ import {
|
|
|
27
27
|
pickCompound,
|
|
28
28
|
pickCompoundOrder,
|
|
29
29
|
viaOrdersField
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-7C7OF26T.js";
|
|
31
31
|
import {
|
|
32
32
|
gateTerminal
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-O3NGOHXQ.js";
|
|
34
34
|
import {
|
|
35
35
|
readPath
|
|
36
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-SXPLIRQH.js";
|
|
37
37
|
import {
|
|
38
38
|
isViaPrefixProbe
|
|
39
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-PIO6NW7O.js";
|
|
40
40
|
import {
|
|
41
41
|
CrossJoinTooLargeError,
|
|
42
42
|
DanglingReferenceError,
|
|
43
43
|
RefNotDeclaredError,
|
|
44
44
|
TraversalCycleError
|
|
45
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-2RH5SEY7.js";
|
|
46
46
|
|
|
47
47
|
// src/kernel/query/relate/explain.ts
|
|
48
48
|
var WARN_FRACTION = 0.8;
|
|
@@ -1286,4 +1286,4 @@ export {
|
|
|
1286
1286
|
runTraversal,
|
|
1287
1287
|
installRelate
|
|
1288
1288
|
};
|
|
1289
|
-
//# sourceMappingURL=chunk-
|
|
1289
|
+
//# sourceMappingURL=chunk-NIUHKKMM.js.map
|
|
@@ -5,18 +5,18 @@ import {
|
|
|
5
5
|
import {
|
|
6
6
|
ViaGraph,
|
|
7
7
|
matchTargetFieldNames
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-VLRY2UH4.js";
|
|
9
9
|
import {
|
|
10
10
|
schemaFieldKeys
|
|
11
11
|
} from "./chunk-QJNAHPVT.js";
|
|
12
12
|
import {
|
|
13
13
|
sha256Hex
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-WRLWEYHY.js";
|
|
15
15
|
import {
|
|
16
16
|
DerivationCycleError,
|
|
17
17
|
DuplicateBehaviorNameError,
|
|
18
18
|
ValidationError
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-2RH5SEY7.js";
|
|
20
20
|
|
|
21
21
|
// src/with-formula/derivations/strategy-hash.ts
|
|
22
22
|
async function computeStrategyHash(source, outputKeys, derive, sources) {
|
|
@@ -246,4 +246,4 @@ var DerivationRegistry = class {
|
|
|
246
246
|
export {
|
|
247
247
|
DerivationRegistry
|
|
248
248
|
};
|
|
249
|
-
//# sourceMappingURL=chunk-
|
|
249
|
+
//# sourceMappingURL=chunk-NK4LGBGQ.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
linkI18nVia
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-UQRKAM2R.js";
|
|
4
4
|
|
|
5
5
|
// src/via/i18n/dictionary.ts
|
|
6
6
|
function dictKey(name, keysOrMap, opts) {
|
|
@@ -71,4 +71,4 @@ export {
|
|
|
71
71
|
dictKey,
|
|
72
72
|
staticDict
|
|
73
73
|
};
|
|
74
|
-
//# sourceMappingURL=chunk-
|
|
74
|
+
//# sourceMappingURL=chunk-NUZ7ROUZ.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CollectionNotHydratedError
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-2RH5SEY7.js";
|
|
4
4
|
|
|
5
5
|
// src/kernel/query/hydration.ts
|
|
6
6
|
var INSPECT = /* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom");
|
|
@@ -50,4 +50,4 @@ function gateTerminal(gate, terminal, compute) {
|
|
|
50
50
|
export {
|
|
51
51
|
gateTerminal
|
|
52
52
|
};
|
|
53
|
-
//# sourceMappingURL=chunk-
|
|
53
|
+
//# sourceMappingURL=chunk-O3NGOHXQ.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
NoydbError
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-2RH5SEY7.js";
|
|
4
4
|
|
|
5
5
|
// src/capsule/contract.ts
|
|
6
6
|
function assertCapsuleSupports(caps, group, requirer) {
|
|
@@ -24,4 +24,4 @@ export {
|
|
|
24
24
|
assertCapsuleSupports,
|
|
25
25
|
CapsuleNotSupportedError
|
|
26
26
|
};
|
|
27
|
-
//# sourceMappingURL=chunk-
|
|
27
|
+
//# sourceMappingURL=chunk-O6VOR4NH.js.map
|
|
@@ -2,10 +2,10 @@ import {
|
|
|
2
2
|
CURRENT_COST_BYTE,
|
|
3
3
|
iterationsForCostByte,
|
|
4
4
|
mintAt
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-Q4DBU5RM.js";
|
|
6
6
|
import {
|
|
7
7
|
normalizeForVerify
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-EPPAEGH5.js";
|
|
9
9
|
|
|
10
10
|
// src/capsule/enclave-aes/classify/find.ts
|
|
11
11
|
async function computeBidxTarget(candidate, normalize, dek, collection, field, costByte) {
|
|
@@ -19,4 +19,4 @@ async function computeBidxTarget(candidate, normalize, dek, collection, field, c
|
|
|
19
19
|
export {
|
|
20
20
|
computeBidxTarget
|
|
21
21
|
};
|
|
22
|
-
//# sourceMappingURL=chunk-
|
|
22
|
+
//# sourceMappingURL=chunk-ODBOHPZU.js.map
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from "./chunk-4CFHL5RY.js";
|
|
5
5
|
import {
|
|
6
6
|
readPath
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-SXPLIRQH.js";
|
|
8
8
|
|
|
9
9
|
// src/kernel/query/relate/join-on.ts
|
|
10
10
|
var RANGE_OPS = /* @__PURE__ */ new Set(["<", "<=", ">", ">=", "between"]);
|
|
@@ -201,4 +201,4 @@ export {
|
|
|
201
201
|
joinOnDispatch,
|
|
202
202
|
matchDeclaredJoin
|
|
203
203
|
};
|
|
204
|
-
//# sourceMappingURL=chunk-
|
|
204
|
+
//# sourceMappingURL=chunk-OK44MD3C.js.map
|