@noy-db/hub 0.3.0-pre.6 → 0.3.0-pre.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapter/index.d.ts +1 -1
- package/dist/aggregate/index.d.ts +2 -2
- package/dist/{api-OQ65LUSK.js → api-JDWL67WL.js} +6 -6
- package/dist/as/index.d.ts +3 -3
- package/dist/as/index.js +5 -5
- package/dist/at/index.d.ts +1 -1
- package/dist/attestation/index.d.ts +2 -2
- package/dist/attestation/index.js +12 -12
- package/dist/{backup-Y3RMFGVX.js → backup-WRGNTGJF.js} +6 -6
- package/dist/blobs/index.d.ts +3 -3
- package/dist/blobs/index.js +5 -5
- package/dist/bundle/index.d.ts +4 -4
- package/dist/bundle/index.js +14 -14
- package/dist/{bundle-BPOSpGZG.d.ts → bundle-DzWtVw7w.d.ts} +1 -1
- package/dist/cargo/index.d.ts +3 -3
- package/dist/cargo/index.js +13 -13
- package/dist/{chunk-QQQE6QUO.js → chunk-25G7PUTA.js} +7 -7
- package/dist/{chunk-S2IDC6MO.js → chunk-2PJB6H3H.js} +2 -2
- package/dist/{chunk-OCVO2V63.js → chunk-37JZR7CY.js} +18 -5
- package/dist/chunk-37JZR7CY.js.map +1 -0
- package/dist/{chunk-RIZQZKU6.js → chunk-3KBK5LU4.js} +3 -3
- package/dist/{chunk-MT4YWJRW.js → chunk-3YKBGS3I.js} +4 -4
- package/dist/{chunk-TSAT3E7Y.js → chunk-44DV37ZV.js} +2 -2
- package/dist/{chunk-7A7LTSJR.js → chunk-4VDFUBTS.js} +3 -3
- package/dist/{chunk-D6ADQ4QL.js → chunk-56JB2BGI.js} +420 -81
- package/dist/chunk-56JB2BGI.js.map +1 -0
- package/dist/{chunk-4I4UNXHM.js → chunk-5HRJQSKN.js} +3 -3
- package/dist/{chunk-3IMGBWP7.js → chunk-5YBUFCFF.js} +5 -5
- package/dist/{chunk-73C4RPMX.js → chunk-62APEMF3.js} +3 -3
- package/dist/{chunk-GGFT2XFF.js → chunk-723XB5NX.js} +3 -3
- package/dist/{chunk-7AGLCOYE.js → chunk-7TAV3BFQ.js} +6 -5
- package/dist/chunk-7TAV3BFQ.js.map +1 -0
- package/dist/{chunk-C57J6AWN.js → chunk-BJ2XF2RC.js} +3 -3
- package/dist/{chunk-YXGIPYH4.js → chunk-BM6E4MUT.js} +164 -51
- package/dist/chunk-BM6E4MUT.js.map +1 -0
- package/dist/{chunk-T45LAT2Y.js → chunk-BTFTHF6Q.js} +2 -2
- package/dist/{chunk-C2ZKWL37.js → chunk-DCVVCJVB.js} +2 -2
- package/dist/{chunk-ZHK3F5RB.js → chunk-F3EKFGUS.js} +4 -4
- package/dist/{chunk-3UUXDQPM.js → chunk-FWART3VA.js} +2 -2
- package/dist/{chunk-C6A2DPRE.js → chunk-FZK3JJJK.js} +3 -3
- package/dist/{chunk-E7MAS736.js → chunk-GDOOG5YQ.js} +2 -2
- package/dist/{chunk-I7GTYPWF.js → chunk-GLVXQU3E.js} +2 -2
- package/dist/{chunk-65FW3ALF.js → chunk-I6URUNTD.js} +3 -3
- package/dist/{chunk-RXUFMTD5.js → chunk-IARAK3PK.js} +2 -2
- package/dist/{chunk-DBBP35OP.js → chunk-J5YUA6JB.js} +2 -2
- package/dist/{chunk-BYS45GOJ.js → chunk-J7OH6R4K.js} +3 -3
- package/dist/{chunk-YFF2RP3X.js → chunk-L6Q5NA22.js} +2 -2
- package/dist/{chunk-ML5UP7YN.js → chunk-M3OYTM5Z.js} +4 -4
- package/dist/{chunk-UZZFV3O3.js → chunk-NTPWQH4S.js} +5 -5
- package/dist/{chunk-VWGCJUTV.js → chunk-P2PEPSPK.js} +2 -2
- package/dist/{chunk-XDWNF4BS.js → chunk-P6TZ3IVN.js} +7 -7
- package/dist/{chunk-WQAT24C2.js → chunk-PMMV5SQC.js} +5 -5
- package/dist/{chunk-PLQCXH75.js → chunk-PPPZIBKY.js} +2 -2
- package/dist/chunk-PVC2FBCQ.js +45 -0
- package/dist/chunk-PVC2FBCQ.js.map +1 -0
- package/dist/{chunk-NL4HVTNO.js → chunk-QABECTNN.js} +2 -2
- package/dist/{chunk-IVIGZTFH.js → chunk-QYMMMKOO.js} +4 -4
- package/dist/{chunk-ZRJBLWKQ.js → chunk-R4IVPJHN.js} +3 -3
- package/dist/{chunk-LN22XH4B.js → chunk-REWTMYSF.js} +1 -1
- package/dist/chunk-REWTMYSF.js.map +1 -0
- package/dist/{chunk-GEK6UGOJ.js → chunk-TCGVRKOS.js} +2 -2
- package/dist/{chunk-RLP65PI3.js → chunk-TIAYXOEI.js} +2 -2
- package/dist/{chunk-WAL4MRBK.js → chunk-TUL5YQWF.js} +3 -3
- package/dist/{chunk-TWJVOYU2.js → chunk-UMH35AQV.js} +2 -2
- package/dist/{chunk-SXLMLECV.js → chunk-VVLOWY74.js} +3 -3
- package/dist/{chunk-HJZ3CTZ2.js → chunk-W3JABOVB.js} +2 -2
- package/dist/{chunk-S55MJQUQ.js → chunk-WPNP3NF5.js} +4 -4
- package/dist/{chunk-WAW4VFS7.js → chunk-X5QZAJDB.js} +3 -3
- package/dist/{chunk-OLVIGEHQ.js → chunk-X6VNIRHS.js} +2 -2
- package/dist/{chunk-CYWF3JJE.js → chunk-XBPUVQDO.js} +8 -8
- package/dist/classified/index.d.ts +3 -3
- package/dist/classified/index.js +1 -1
- package/dist/{collection-facade-5V3JS7SD.js → collection-facade-EJVIN2BY.js} +9 -9
- package/dist/{config-drift-SWZNEH5H.js → config-drift-RFEVGBKR.js} +3 -3
- package/dist/consent/index.d.ts +2 -2
- package/dist/consent/index.js +4 -4
- package/dist/crdt/index.d.ts +2 -2
- package/dist/{dead-filter-MGWMNRO2.js → dead-filter-RHMNYOXP.js} +2 -2
- package/dist/{delegation-AUY42TGU.js → delegation-IHXOASHV.js} +5 -5
- package/dist/derivations/index.d.ts +3 -3
- package/dist/derivations/index.js +3 -3
- package/dist/{derive-FWSEWWI7.js → derive-CD3ZVIXK.js} +4 -4
- package/dist/{dev-unlock-DxecHstJ.d.ts → dev-unlock-wgQ7Ci5I.d.ts} +1 -1
- package/dist/{enclave-UYZGSE2C.js → enclave-KGEUW2GL.js} +11 -5
- package/dist/{executor-XWPD5PIM.js → executor-MHUM2VZK.js} +4 -4
- package/dist/{export-accessible-M54OI6FO.js → export-accessible-Z3NSZZHN.js} +7 -7
- package/dist/{extract-partition-MIHAL6PP.js → extract-partition-VSKT35JG.js} +10 -10
- package/dist/{fanout-sidecar-SSEW7BQB.js → fanout-sidecar-NBDKKCHT.js} +4 -4
- package/dist/forget/index.js +4 -4
- package/dist/guards/index.d.ts +3 -3
- package/dist/{hash-umqwdLhO.d.ts → hash-CwHnoKyW.d.ts} +1 -1
- package/dist/history/index.d.ts +3 -3
- package/dist/history/index.js +6 -6
- package/dist/i18n/index.d.ts +2 -2
- package/dist/i18n/index.js +7 -7
- package/dist/in/index.d.ts +1 -1
- package/dist/{index-zdEVWlkZ.d.ts → index-CTvUp94-.d.ts} +2 -2
- package/dist/{index-B-LKCpm6.d.ts → index-Dn5GzPg_.d.ts} +304 -4
- package/dist/index.d.ts +26 -19
- package/dist/index.js +52 -51
- package/dist/index.js.map +1 -1
- package/dist/indexing/index.d.ts +2 -2
- package/dist/{issue-PHWTGH2G.js → issue-AEOL6RXA.js} +6 -6
- package/dist/kernel/index.d.ts +2 -2
- package/dist/kernel/index.js +3 -3
- package/dist/lazy/index.d.ts +2 -2
- package/dist/{ledger-IWWY7IIC.js → ledger-3LR3YO2W.js} +6 -6
- package/dist/liberate-XSEPRWEA.js +24 -0
- package/dist/{link-set-HJOC7GB7.js → link-set-NSUIX6BR.js} +5 -5
- package/dist/materialized-views/index.d.ts +3 -3
- package/dist/materialized-views/index.js +4 -4
- package/dist/{mime-magic-C_O9KsAk.d.ts → mime-magic-CYbFNQ4h.d.ts} +1 -1
- package/dist/{noydb-Y5L74IDJ.js → noydb-POVTIVQ6.js} +23 -23
- package/dist/on/index.d.ts +1 -1
- package/dist/on/index.js +4 -4
- package/dist/overlay-views/index.d.ts +3 -3
- package/dist/periods/index.d.ts +2 -2
- package/dist/periods/index.js +15 -7
- package/dist/pod/index.d.ts +2 -2
- package/dist/pod/index.js +5 -5
- package/dist/{policy-3ZKSGSRK.js → policy-Y7HL2KGA.js} +4 -4
- package/dist/portability/index.d.ts +2 -2
- package/dist/portability/index.js +6 -6
- package/dist/{post-register-BIXGCZ2M.js → post-register-KOFRTCDD.js} +4 -4
- package/dist/{public-envelope-6UBQ4IUY.js → public-envelope-NC7SPNMV.js} +3 -3
- package/dist/query/index.d.ts +1 -1
- package/dist/{register-OVONZ2MJ.js → register-3D6R2MKN.js} +6 -6
- package/dist/{registry-AIEYUOSG.js → registry-AI4E46PD.js} +4 -4
- package/dist/{registry-D5J7SVJ2.js → registry-WIX6QCV5.js} +4 -4
- package/dist/{request-withdrawal-IHF64VIT.js → request-withdrawal-GU4XS2R5.js} +9 -9
- package/dist/{reveal-B77Q2BJW.js → reveal-5Y777N5Q.js} +3 -3
- package/dist/{revoke-BPPOUZPE.js → revoke-ZFETCLYV.js} +6 -6
- package/dist/satellites/index.d.ts +1 -1
- package/dist/sealed-record/index.d.ts +2 -2
- package/dist/sealed-record/index.js +6 -6
- package/dist/session/index.d.ts +3 -3
- package/dist/session/index.js +3 -3
- package/dist/shadow/index.d.ts +2 -2
- package/dist/{signer-MNQEL27B.js → signer-GAIMQQ2J.js} +5 -5
- package/dist/snapshots/index.d.ts +2 -2
- package/dist/snapshots/index.js +5 -5
- package/dist/{stale-COBBJORL.js → stale-77LP2EEF.js} +2 -2
- package/dist/{storage-DVKYH7UU.js → storage-KEXIXLGM.js} +5 -5
- package/dist/{store-coordination-provider-JJCEMTAE.js → store-coordination-provider-NJDDZ264.js} +3 -3
- package/dist/sync/index.d.ts +1 -1
- package/dist/sync/index.js +4 -4
- package/dist/team/index.d.ts +2 -2
- package/dist/team/index.js +9 -9
- package/dist/tiers/index.d.ts +1 -1
- package/dist/tiers/index.js +4 -4
- package/dist/to/index.d.ts +1 -1
- package/dist/{transition-guard-CzqWwVGP.d.ts → transition-guard-D5RLJv8S.d.ts} +1 -1
- package/dist/tx/index.d.ts +2 -2
- package/dist/{validators-Bdiv0ucK.d.ts → validators-C3lrVF-c.d.ts} +1 -1
- package/dist/{vault-diff-BbZngJUP.d.ts → vault-diff-_LSIcOMv.d.ts} +1 -1
- package/dist/{walk-CVNXFUEF.js → walk-SMAE4IEI.js} +5 -5
- package/dist/with/index.d.ts +2 -2
- package/dist/with/index.js +6 -6
- package/dist/{with-materialized-view-BmKXygt2.d.ts → with-materialized-view-Xv1-9Bh0.d.ts} +1 -1
- package/dist/{with-overlayed-view-Bnwe7E75.d.ts → with-overlayed-view-CuWhq_-C.d.ts} +1 -1
- package/dist/{with-rollup-JXTxc9cu.d.ts → with-rollup-K_iwal4b.d.ts} +1 -1
- package/dist/{withdraw-accessible-5ALN3ZGM.js → withdraw-accessible-Q7BULAN5.js} +8 -8
- package/package.json +3 -3
- package/dist/chunk-7AGLCOYE.js.map +0 -1
- package/dist/chunk-D6ADQ4QL.js.map +0 -1
- package/dist/chunk-LN22XH4B.js.map +0 -1
- package/dist/chunk-OCVO2V63.js.map +0 -1
- package/dist/chunk-QKVILR7N.js +0 -25
- package/dist/chunk-QKVILR7N.js.map +0 -1
- package/dist/chunk-YXGIPYH4.js.map +0 -1
- package/dist/liberate-QDTNV7SM.js +0 -24
- /package/dist/{api-OQ65LUSK.js.map → api-JDWL67WL.js.map} +0 -0
- /package/dist/{backup-Y3RMFGVX.js.map → backup-WRGNTGJF.js.map} +0 -0
- /package/dist/{chunk-QQQE6QUO.js.map → chunk-25G7PUTA.js.map} +0 -0
- /package/dist/{chunk-S2IDC6MO.js.map → chunk-2PJB6H3H.js.map} +0 -0
- /package/dist/{chunk-RIZQZKU6.js.map → chunk-3KBK5LU4.js.map} +0 -0
- /package/dist/{chunk-MT4YWJRW.js.map → chunk-3YKBGS3I.js.map} +0 -0
- /package/dist/{chunk-TSAT3E7Y.js.map → chunk-44DV37ZV.js.map} +0 -0
- /package/dist/{chunk-7A7LTSJR.js.map → chunk-4VDFUBTS.js.map} +0 -0
- /package/dist/{chunk-4I4UNXHM.js.map → chunk-5HRJQSKN.js.map} +0 -0
- /package/dist/{chunk-3IMGBWP7.js.map → chunk-5YBUFCFF.js.map} +0 -0
- /package/dist/{chunk-73C4RPMX.js.map → chunk-62APEMF3.js.map} +0 -0
- /package/dist/{chunk-GGFT2XFF.js.map → chunk-723XB5NX.js.map} +0 -0
- /package/dist/{chunk-C57J6AWN.js.map → chunk-BJ2XF2RC.js.map} +0 -0
- /package/dist/{chunk-T45LAT2Y.js.map → chunk-BTFTHF6Q.js.map} +0 -0
- /package/dist/{chunk-C2ZKWL37.js.map → chunk-DCVVCJVB.js.map} +0 -0
- /package/dist/{chunk-ZHK3F5RB.js.map → chunk-F3EKFGUS.js.map} +0 -0
- /package/dist/{chunk-3UUXDQPM.js.map → chunk-FWART3VA.js.map} +0 -0
- /package/dist/{chunk-C6A2DPRE.js.map → chunk-FZK3JJJK.js.map} +0 -0
- /package/dist/{chunk-E7MAS736.js.map → chunk-GDOOG5YQ.js.map} +0 -0
- /package/dist/{chunk-I7GTYPWF.js.map → chunk-GLVXQU3E.js.map} +0 -0
- /package/dist/{chunk-65FW3ALF.js.map → chunk-I6URUNTD.js.map} +0 -0
- /package/dist/{chunk-RXUFMTD5.js.map → chunk-IARAK3PK.js.map} +0 -0
- /package/dist/{chunk-DBBP35OP.js.map → chunk-J5YUA6JB.js.map} +0 -0
- /package/dist/{chunk-BYS45GOJ.js.map → chunk-J7OH6R4K.js.map} +0 -0
- /package/dist/{chunk-YFF2RP3X.js.map → chunk-L6Q5NA22.js.map} +0 -0
- /package/dist/{chunk-ML5UP7YN.js.map → chunk-M3OYTM5Z.js.map} +0 -0
- /package/dist/{chunk-UZZFV3O3.js.map → chunk-NTPWQH4S.js.map} +0 -0
- /package/dist/{chunk-VWGCJUTV.js.map → chunk-P2PEPSPK.js.map} +0 -0
- /package/dist/{chunk-XDWNF4BS.js.map → chunk-P6TZ3IVN.js.map} +0 -0
- /package/dist/{chunk-WQAT24C2.js.map → chunk-PMMV5SQC.js.map} +0 -0
- /package/dist/{chunk-PLQCXH75.js.map → chunk-PPPZIBKY.js.map} +0 -0
- /package/dist/{chunk-NL4HVTNO.js.map → chunk-QABECTNN.js.map} +0 -0
- /package/dist/{chunk-IVIGZTFH.js.map → chunk-QYMMMKOO.js.map} +0 -0
- /package/dist/{chunk-ZRJBLWKQ.js.map → chunk-R4IVPJHN.js.map} +0 -0
- /package/dist/{chunk-GEK6UGOJ.js.map → chunk-TCGVRKOS.js.map} +0 -0
- /package/dist/{chunk-RLP65PI3.js.map → chunk-TIAYXOEI.js.map} +0 -0
- /package/dist/{chunk-WAL4MRBK.js.map → chunk-TUL5YQWF.js.map} +0 -0
- /package/dist/{chunk-TWJVOYU2.js.map → chunk-UMH35AQV.js.map} +0 -0
- /package/dist/{chunk-SXLMLECV.js.map → chunk-VVLOWY74.js.map} +0 -0
- /package/dist/{chunk-HJZ3CTZ2.js.map → chunk-W3JABOVB.js.map} +0 -0
- /package/dist/{chunk-S55MJQUQ.js.map → chunk-WPNP3NF5.js.map} +0 -0
- /package/dist/{chunk-WAW4VFS7.js.map → chunk-X5QZAJDB.js.map} +0 -0
- /package/dist/{chunk-OLVIGEHQ.js.map → chunk-X6VNIRHS.js.map} +0 -0
- /package/dist/{chunk-CYWF3JJE.js.map → chunk-XBPUVQDO.js.map} +0 -0
- /package/dist/{collection-facade-5V3JS7SD.js.map → collection-facade-EJVIN2BY.js.map} +0 -0
- /package/dist/{config-drift-SWZNEH5H.js.map → config-drift-RFEVGBKR.js.map} +0 -0
- /package/dist/{dead-filter-MGWMNRO2.js.map → dead-filter-RHMNYOXP.js.map} +0 -0
- /package/dist/{delegation-AUY42TGU.js.map → delegation-IHXOASHV.js.map} +0 -0
- /package/dist/{derive-FWSEWWI7.js.map → derive-CD3ZVIXK.js.map} +0 -0
- /package/dist/{enclave-UYZGSE2C.js.map → enclave-KGEUW2GL.js.map} +0 -0
- /package/dist/{executor-XWPD5PIM.js.map → executor-MHUM2VZK.js.map} +0 -0
- /package/dist/{export-accessible-M54OI6FO.js.map → export-accessible-Z3NSZZHN.js.map} +0 -0
- /package/dist/{extract-partition-MIHAL6PP.js.map → extract-partition-VSKT35JG.js.map} +0 -0
- /package/dist/{fanout-sidecar-SSEW7BQB.js.map → fanout-sidecar-NBDKKCHT.js.map} +0 -0
- /package/dist/{issue-PHWTGH2G.js.map → issue-AEOL6RXA.js.map} +0 -0
- /package/dist/{ledger-IWWY7IIC.js.map → ledger-3LR3YO2W.js.map} +0 -0
- /package/dist/{liberate-QDTNV7SM.js.map → liberate-XSEPRWEA.js.map} +0 -0
- /package/dist/{link-set-HJOC7GB7.js.map → link-set-NSUIX6BR.js.map} +0 -0
- /package/dist/{noydb-Y5L74IDJ.js.map → noydb-POVTIVQ6.js.map} +0 -0
- /package/dist/{policy-3ZKSGSRK.js.map → policy-Y7HL2KGA.js.map} +0 -0
- /package/dist/{post-register-BIXGCZ2M.js.map → post-register-KOFRTCDD.js.map} +0 -0
- /package/dist/{public-envelope-6UBQ4IUY.js.map → public-envelope-NC7SPNMV.js.map} +0 -0
- /package/dist/{register-OVONZ2MJ.js.map → register-3D6R2MKN.js.map} +0 -0
- /package/dist/{registry-AIEYUOSG.js.map → registry-AI4E46PD.js.map} +0 -0
- /package/dist/{registry-D5J7SVJ2.js.map → registry-WIX6QCV5.js.map} +0 -0
- /package/dist/{request-withdrawal-IHF64VIT.js.map → request-withdrawal-GU4XS2R5.js.map} +0 -0
- /package/dist/{reveal-B77Q2BJW.js.map → reveal-5Y777N5Q.js.map} +0 -0
- /package/dist/{revoke-BPPOUZPE.js.map → revoke-ZFETCLYV.js.map} +0 -0
- /package/dist/{signer-MNQEL27B.js.map → signer-GAIMQQ2J.js.map} +0 -0
- /package/dist/{stale-COBBJORL.js.map → stale-77LP2EEF.js.map} +0 -0
- /package/dist/{storage-DVKYH7UU.js.map → storage-KEXIXLGM.js.map} +0 -0
- /package/dist/{store-coordination-provider-JJCEMTAE.js.map → store-coordination-provider-NJDDZ264.js.map} +0 -0
- /package/dist/{walk-CVNXFUEF.js.map → walk-SMAE4IEI.js.map} +0 -0
- /package/dist/{withdraw-accessible-5ALN3ZGM.js.map → withdraw-accessible-Q7BULAN5.js.map} +0 -0
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SyncScheduler
|
|
3
3
|
} from "./chunk-VQNJ7UZL.js";
|
|
4
|
+
import {
|
|
5
|
+
isDeleteMarker,
|
|
6
|
+
isTombstoneShape
|
|
7
|
+
} from "./chunk-PVC2FBCQ.js";
|
|
4
8
|
import {
|
|
5
9
|
NOYDB_SYNC_VERSION
|
|
6
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-REWTMYSF.js";
|
|
7
11
|
import {
|
|
8
12
|
bufferToBase64,
|
|
9
13
|
decrypt,
|
|
@@ -249,6 +253,12 @@ var SyncEngine = class {
|
|
|
249
253
|
* users.
|
|
250
254
|
*/
|
|
251
255
|
pairExpander;
|
|
256
|
+
/** #598: refreshes Collection in-memory views after a sync-applied local write. Wired by the vault at open. */
|
|
257
|
+
cacheInvalidator;
|
|
258
|
+
/** Wire the Collection-cache invalidation hook (#598). Same injection pattern as `setPairExpander`. */
|
|
259
|
+
setCacheInvalidator(fn) {
|
|
260
|
+
this.cacheInvalidator = fn;
|
|
261
|
+
}
|
|
252
262
|
constructor(opts) {
|
|
253
263
|
this.local = opts.local;
|
|
254
264
|
this.remote = opts.remote;
|
|
@@ -346,6 +356,7 @@ var SyncEngine = class {
|
|
|
346
356
|
await this.ensureLoaded();
|
|
347
357
|
let pushed = 0;
|
|
348
358
|
const conflicts = [];
|
|
359
|
+
const erasures = [];
|
|
349
360
|
const errors = [];
|
|
350
361
|
const completed = [];
|
|
351
362
|
const filter = options?.collections ? new Set(this.pairExpander?.(options.collections) ?? options.collections) : null;
|
|
@@ -365,6 +376,12 @@ var SyncEngine = class {
|
|
|
365
376
|
completed.push(i);
|
|
366
377
|
continue;
|
|
367
378
|
}
|
|
379
|
+
if (isTombstoneShape(envelope)) {
|
|
380
|
+
await this.remote.put(this.vault, entry.collection, entry.id, envelope);
|
|
381
|
+
completed.push(i);
|
|
382
|
+
pushed++;
|
|
383
|
+
continue;
|
|
384
|
+
}
|
|
368
385
|
try {
|
|
369
386
|
await this.remote.put(
|
|
370
387
|
this.vault,
|
|
@@ -379,27 +396,42 @@ var SyncEngine = class {
|
|
|
379
396
|
if (err instanceof ConflictError) {
|
|
380
397
|
const remoteEnvelope = await this.remote.get(this.vault, entry.collection, entry.id);
|
|
381
398
|
if (remoteEnvelope) {
|
|
382
|
-
|
|
383
|
-
entry.collection,
|
|
384
|
-
entry.id,
|
|
385
|
-
envelope,
|
|
386
|
-
remoteEnvelope,
|
|
387
|
-
"push"
|
|
388
|
-
);
|
|
389
|
-
conflicts.push(conflict);
|
|
390
|
-
if (handled === "local") {
|
|
391
|
-
await this.remote.put(this.vault, entry.collection, entry.id, conflict.local);
|
|
399
|
+
if (isTombstoneShape(remoteEnvelope)) {
|
|
400
|
+
await this.applyRemote(entry.collection, entry.id, remoteEnvelope);
|
|
401
|
+
erasures.push(this.reportErasure(entry.collection, entry.id, remoteEnvelope, envelope, "push"));
|
|
392
402
|
completed.push(i);
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
+
} else if (remoteEnvelope._v === envelope._v && isDeleteMarker(remoteEnvelope) !== isDeleteMarker(envelope) && !this.conflictResolvers.get(entry.collection)) {
|
|
404
|
+
if (isDeleteMarker(remoteEnvelope)) {
|
|
405
|
+
await this.applyRemote(entry.collection, entry.id, remoteEnvelope);
|
|
406
|
+
completed.push(i);
|
|
407
|
+
} else {
|
|
408
|
+
await this.remote.put(this.vault, entry.collection, entry.id, envelope);
|
|
409
|
+
completed.push(i);
|
|
410
|
+
pushed++;
|
|
411
|
+
}
|
|
412
|
+
} else {
|
|
413
|
+
const { handled, conflict } = await this.handleConflict(
|
|
414
|
+
entry.collection,
|
|
415
|
+
entry.id,
|
|
416
|
+
envelope,
|
|
417
|
+
remoteEnvelope,
|
|
418
|
+
"push"
|
|
419
|
+
);
|
|
420
|
+
conflicts.push(conflict);
|
|
421
|
+
if (handled === "local") {
|
|
422
|
+
await this.remote.put(this.vault, entry.collection, entry.id, conflict.local);
|
|
423
|
+
completed.push(i);
|
|
424
|
+
pushed++;
|
|
425
|
+
} else if (handled === "remote") {
|
|
426
|
+
await this.applyRemote(entry.collection, entry.id, conflict.remote);
|
|
427
|
+
completed.push(i);
|
|
428
|
+
} else if (handled === "merged" && conflict.local !== envelope) {
|
|
429
|
+
const merged = conflict.local;
|
|
430
|
+
await this.remote.put(this.vault, entry.collection, entry.id, merged);
|
|
431
|
+
await this.applyRemote(entry.collection, entry.id, merged);
|
|
432
|
+
completed.push(i);
|
|
433
|
+
pushed++;
|
|
434
|
+
}
|
|
403
435
|
}
|
|
404
436
|
}
|
|
405
437
|
} else {
|
|
@@ -416,7 +448,7 @@ var SyncEngine = class {
|
|
|
416
448
|
}
|
|
417
449
|
this.lastPush = (/* @__PURE__ */ new Date()).toISOString();
|
|
418
450
|
await this.persistMeta();
|
|
419
|
-
const result = { pushed, conflicts, errors };
|
|
451
|
+
const result = { pushed, conflicts, errors, erasures };
|
|
420
452
|
this.emitter.emit("sync:push", result);
|
|
421
453
|
return result;
|
|
422
454
|
}
|
|
@@ -425,6 +457,7 @@ var SyncEngine = class {
|
|
|
425
457
|
await this.ensureLoaded();
|
|
426
458
|
let pulled = 0;
|
|
427
459
|
const conflicts = [];
|
|
460
|
+
const erasures = [];
|
|
428
461
|
const errors = [];
|
|
429
462
|
const filter = options?.collections ? new Set(this.pairExpander?.(options.collections) ?? options.collections) : null;
|
|
430
463
|
try {
|
|
@@ -434,14 +467,44 @@ var SyncEngine = class {
|
|
|
434
467
|
continue;
|
|
435
468
|
}
|
|
436
469
|
for (const [id, remoteEnvelope] of Object.entries(records)) {
|
|
437
|
-
if (options?.modifiedSince && remoteEnvelope._ts <= options.modifiedSince) {
|
|
470
|
+
if (options?.modifiedSince && remoteEnvelope._ts <= options.modifiedSince && !isTombstoneShape(remoteEnvelope) && !isDeleteMarker(remoteEnvelope)) {
|
|
438
471
|
continue;
|
|
439
472
|
}
|
|
440
473
|
try {
|
|
441
474
|
const localEnvelope = await this.local.get(this.vault, collName, id);
|
|
475
|
+
const remoteIsTombstone = isTombstoneShape(remoteEnvelope);
|
|
442
476
|
if (!localEnvelope) {
|
|
443
|
-
await this.
|
|
477
|
+
await this.applyRemote(collName, id, remoteEnvelope);
|
|
478
|
+
pulled++;
|
|
479
|
+
} else if (isTombstoneShape(localEnvelope)) {
|
|
480
|
+
if (remoteIsTombstone) {
|
|
481
|
+
if (remoteEnvelope._v > localEnvelope._v) await this.applyRemote(collName, id, remoteEnvelope);
|
|
482
|
+
} else {
|
|
483
|
+
erasures.push(await this.reassertTombstone(collName, id, localEnvelope, remoteEnvelope));
|
|
484
|
+
}
|
|
485
|
+
} else if (remoteIsTombstone) {
|
|
486
|
+
const wasDirty = this.dirty.some((d) => d.collection === collName && d.id === id);
|
|
487
|
+
await this.applyRemote(collName, id, remoteEnvelope);
|
|
488
|
+
this.dirty = this.dirty.filter((d) => !(d.collection === collName && d.id === id));
|
|
444
489
|
pulled++;
|
|
490
|
+
if (wasDirty) erasures.push(this.reportErasure(collName, id, remoteEnvelope, localEnvelope, "pull"));
|
|
491
|
+
} else if (remoteEnvelope._v === localEnvelope._v && isDeleteMarker(remoteEnvelope) !== isDeleteMarker(localEnvelope)) {
|
|
492
|
+
const resolver = this.conflictResolvers.get(collName);
|
|
493
|
+
if (resolver) {
|
|
494
|
+
const winner = await resolver(id, localEnvelope, remoteEnvelope);
|
|
495
|
+
if (winner !== localEnvelope && winner !== null) {
|
|
496
|
+
if (winner !== remoteEnvelope) {
|
|
497
|
+
await this.remote.put(this.vault, collName, id, winner);
|
|
498
|
+
}
|
|
499
|
+
await this.applyRemote(collName, id, winner);
|
|
500
|
+
this.dirty = this.dirty.filter((d) => !(d.collection === collName && d.id === id));
|
|
501
|
+
pulled++;
|
|
502
|
+
}
|
|
503
|
+
} else if (isDeleteMarker(remoteEnvelope)) {
|
|
504
|
+
await this.applyRemote(collName, id, remoteEnvelope);
|
|
505
|
+
this.dirty = this.dirty.filter((d) => !(d.collection === collName && d.id === id));
|
|
506
|
+
pulled++;
|
|
507
|
+
}
|
|
445
508
|
} else if (remoteEnvelope._v > localEnvelope._v) {
|
|
446
509
|
const isDirty = this.dirty.some((d) => d.collection === collName && d.id === id);
|
|
447
510
|
if (isDirty) {
|
|
@@ -454,17 +517,17 @@ var SyncEngine = class {
|
|
|
454
517
|
);
|
|
455
518
|
conflicts.push(conflict);
|
|
456
519
|
if (handled === "remote") {
|
|
457
|
-
await this.
|
|
520
|
+
await this.applyRemote(collName, id, conflict.remote);
|
|
458
521
|
this.dirty = this.dirty.filter((d) => !(d.collection === collName && d.id === id));
|
|
459
522
|
pulled++;
|
|
460
523
|
} else if (handled === "merged" && conflict.local !== localEnvelope) {
|
|
461
524
|
const merged = conflict.local;
|
|
462
|
-
await this.
|
|
525
|
+
await this.applyRemote(collName, id, merged);
|
|
463
526
|
this.dirty = this.dirty.filter((d) => !(d.collection === collName && d.id === id));
|
|
464
527
|
pulled++;
|
|
465
528
|
}
|
|
466
529
|
} else {
|
|
467
|
-
await this.
|
|
530
|
+
await this.applyRemote(collName, id, remoteEnvelope);
|
|
468
531
|
pulled++;
|
|
469
532
|
}
|
|
470
533
|
}
|
|
@@ -478,7 +541,7 @@ var SyncEngine = class {
|
|
|
478
541
|
}
|
|
479
542
|
this.lastPull = (/* @__PURE__ */ new Date()).toISOString();
|
|
480
543
|
await this.persistMeta();
|
|
481
|
-
const result = { pulled, conflicts, errors };
|
|
544
|
+
const result = { pulled, conflicts, errors, erasures };
|
|
482
545
|
this.emitter.emit("sync:pull", result);
|
|
483
546
|
return result;
|
|
484
547
|
}
|
|
@@ -497,6 +560,7 @@ var SyncEngine = class {
|
|
|
497
560
|
await this.ensureLoaded();
|
|
498
561
|
let pushed = 0;
|
|
499
562
|
const conflicts = [];
|
|
563
|
+
const erasures = [];
|
|
500
564
|
const errors = [];
|
|
501
565
|
const completed = [];
|
|
502
566
|
for (let i = 0; i < this.dirty.length; i++) {
|
|
@@ -513,6 +577,12 @@ var SyncEngine = class {
|
|
|
513
577
|
completed.push(i);
|
|
514
578
|
continue;
|
|
515
579
|
}
|
|
580
|
+
if (isTombstoneShape(envelope)) {
|
|
581
|
+
await this.remote.put(this.vault, entry.collection, entry.id, envelope);
|
|
582
|
+
completed.push(i);
|
|
583
|
+
pushed++;
|
|
584
|
+
continue;
|
|
585
|
+
}
|
|
516
586
|
try {
|
|
517
587
|
await this.remote.put(
|
|
518
588
|
this.vault,
|
|
@@ -527,27 +597,42 @@ var SyncEngine = class {
|
|
|
527
597
|
if (err instanceof ConflictError) {
|
|
528
598
|
const remoteEnvelope = await this.remote.get(this.vault, entry.collection, entry.id);
|
|
529
599
|
if (remoteEnvelope) {
|
|
530
|
-
|
|
531
|
-
entry.collection,
|
|
532
|
-
entry.id,
|
|
533
|
-
envelope,
|
|
534
|
-
remoteEnvelope,
|
|
535
|
-
"push"
|
|
536
|
-
);
|
|
537
|
-
conflicts.push(conflict);
|
|
538
|
-
if (handled === "local") {
|
|
539
|
-
await this.remote.put(this.vault, entry.collection, entry.id, conflict.local);
|
|
540
|
-
completed.push(i);
|
|
541
|
-
pushed++;
|
|
542
|
-
} else if (handled === "remote") {
|
|
543
|
-
await this.local.put(this.vault, entry.collection, entry.id, conflict.remote);
|
|
600
|
+
if (isTombstoneShape(remoteEnvelope)) {
|
|
601
|
+
await this.applyRemote(entry.collection, entry.id, remoteEnvelope);
|
|
602
|
+
erasures.push(this.reportErasure(entry.collection, entry.id, remoteEnvelope, envelope, "push"));
|
|
544
603
|
completed.push(i);
|
|
545
|
-
} else if (
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
604
|
+
} else if (remoteEnvelope._v === envelope._v && isDeleteMarker(remoteEnvelope) !== isDeleteMarker(envelope) && !this.conflictResolvers.get(entry.collection)) {
|
|
605
|
+
if (isDeleteMarker(remoteEnvelope)) {
|
|
606
|
+
await this.applyRemote(entry.collection, entry.id, remoteEnvelope);
|
|
607
|
+
completed.push(i);
|
|
608
|
+
} else {
|
|
609
|
+
await this.remote.put(this.vault, entry.collection, entry.id, envelope);
|
|
610
|
+
completed.push(i);
|
|
611
|
+
pushed++;
|
|
612
|
+
}
|
|
613
|
+
} else {
|
|
614
|
+
const { handled, conflict } = await this.handleConflict(
|
|
615
|
+
entry.collection,
|
|
616
|
+
entry.id,
|
|
617
|
+
envelope,
|
|
618
|
+
remoteEnvelope,
|
|
619
|
+
"push"
|
|
620
|
+
);
|
|
621
|
+
conflicts.push(conflict);
|
|
622
|
+
if (handled === "local") {
|
|
623
|
+
await this.remote.put(this.vault, entry.collection, entry.id, conflict.local);
|
|
624
|
+
completed.push(i);
|
|
625
|
+
pushed++;
|
|
626
|
+
} else if (handled === "remote") {
|
|
627
|
+
await this.applyRemote(entry.collection, entry.id, conflict.remote);
|
|
628
|
+
completed.push(i);
|
|
629
|
+
} else if (handled === "merged" && conflict.local !== envelope) {
|
|
630
|
+
const merged = conflict.local;
|
|
631
|
+
await this.remote.put(this.vault, entry.collection, entry.id, merged);
|
|
632
|
+
await this.applyRemote(entry.collection, entry.id, merged);
|
|
633
|
+
completed.push(i);
|
|
634
|
+
pushed++;
|
|
635
|
+
}
|
|
551
636
|
}
|
|
552
637
|
}
|
|
553
638
|
} else {
|
|
@@ -564,7 +649,7 @@ var SyncEngine = class {
|
|
|
564
649
|
}
|
|
565
650
|
this.lastPush = (/* @__PURE__ */ new Date()).toISOString();
|
|
566
651
|
await this.persistMeta();
|
|
567
|
-
const result = { pushed, conflicts, errors };
|
|
652
|
+
const result = { pushed, conflicts, errors, erasures };
|
|
568
653
|
this.emitter.emit("sync:push", result);
|
|
569
654
|
return result;
|
|
570
655
|
}
|
|
@@ -613,6 +698,33 @@ var SyncEngine = class {
|
|
|
613
698
|
this.isOnline = false;
|
|
614
699
|
this.emitter.emit("sync:offline", void 0);
|
|
615
700
|
};
|
|
701
|
+
/** Apply an envelope to the local store and refresh in-memory views (#598). */
|
|
702
|
+
async applyRemote(collection, id, envelope) {
|
|
703
|
+
await this.local.put(this.vault, collection, id, envelope);
|
|
704
|
+
await this.cacheInvalidator?.(collection, id);
|
|
705
|
+
}
|
|
706
|
+
/** Record + emit a tombstone enforcement (#590). */
|
|
707
|
+
reportErasure(collection, id, tombstone, suppressed, direction) {
|
|
708
|
+
const enforcement = { vault: this.vault, collection, id, tombstone, suppressed, direction };
|
|
709
|
+
this.emitter.emit("sync:erasure", enforcement);
|
|
710
|
+
return enforcement;
|
|
711
|
+
}
|
|
712
|
+
/**
|
|
713
|
+
* Re-assert a local tombstone over a live remote envelope (#590): the shred
|
|
714
|
+
* wins in both directions, regardless of `_v`. Bumps the tombstone to the
|
|
715
|
+
* suppressed envelope's `_v` when higher so per-key version counters stay
|
|
716
|
+
* monotonic on every store; `_by` (the shredding actor) is preserved.
|
|
717
|
+
*/
|
|
718
|
+
async reassertTombstone(collection, id, tombstone, suppressedRemote) {
|
|
719
|
+
let winner = tombstone;
|
|
720
|
+
if (suppressedRemote._v > tombstone._v) {
|
|
721
|
+
winner = { ...tombstone, _v: suppressedRemote._v, _ts: (/* @__PURE__ */ new Date()).toISOString() };
|
|
722
|
+
await this.applyRemote(collection, id, winner);
|
|
723
|
+
}
|
|
724
|
+
await this.remote.put(this.vault, collection, id, winner);
|
|
725
|
+
this.dirty = this.dirty.filter((d) => !(d.collection === collection && d.id === id));
|
|
726
|
+
return this.reportErasure(collection, id, winner, suppressedRemote, "pull");
|
|
727
|
+
}
|
|
616
728
|
/**
|
|
617
729
|
* Resolve a conflict, checking per-collection resolvers first,
|
|
618
730
|
* then falling back to the db-level `ConflictStrategy`.
|
|
@@ -755,7 +867,8 @@ var SyncTransaction = class {
|
|
|
755
867
|
return {
|
|
756
868
|
status: pushResult.conflicts.length > 0 ? "conflict" : "committed",
|
|
757
869
|
pushed: pushResult.pushed,
|
|
758
|
-
conflicts: pushResult.conflicts
|
|
870
|
+
conflicts: pushResult.conflicts,
|
|
871
|
+
...pushResult.erasures?.length ? { erasures: pushResult.erasures } : {}
|
|
759
872
|
};
|
|
760
873
|
}
|
|
761
874
|
};
|
|
@@ -765,4 +878,4 @@ export {
|
|
|
765
878
|
SyncEngine,
|
|
766
879
|
SyncTransaction
|
|
767
880
|
};
|
|
768
|
-
//# sourceMappingURL=chunk-
|
|
881
|
+
//# sourceMappingURL=chunk-BM6E4MUT.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/with-party/team/presence.ts","../src/with-party/team/sync.ts","../src/with-party/team/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 type { NoydbStore, PresencePeer } from '../../kernel/types.js'\nimport { encrypt, decrypt, generateIV, bufferToBase64, derivePresenceKey, type EnclaveKey } from '../../kernel/enclave/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 /** Calling user's ID, embedded unencrypted in storage records. */\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 `{ userId, lastSeen, iv, data }`.\n */\ninterface StoragePresenceRecord {\n userId: string\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 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 = generateIV()\n const ivB64 = bufferToBase64(iv)\n const { data } = await encrypt(plaintext, key)\n encryptedPayload = JSON.stringify({ iv: ivB64, 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 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 const plaintext = JSON.stringify(payload)\n let iv = ''\n let data: string\n\n if (this.encrypted && key) {\n const ivBytes = generateIV()\n iv = bufferToBase64(ivBytes)\n const result = await encrypt(plaintext, key)\n data = result.data\n } else {\n data = plaintext\n }\n\n const record: StoragePresenceRecord = { userId: this.userId, 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 = {\n _noydb: 1 as const,\n _v: 1,\n _ts: now,\n _iv: '',\n _data: json,\n }\n try {\n await storeAdapter.put(\n this.vault,\n this.storageCollection,\n this.userId,\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 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\n for (const id of ids) {\n if (id === this.userId) continue // skip ourselves\n const envelope = await storeAdapter.get(this.vault, this.storageCollection, id)\n if (!envelope) continue\n\n const record = JSON.parse(envelope._data) as StoragePresenceRecord\n if (record.lastSeen < cutoff) continue\n\n let peerPayload: P\n if (this.encrypted && this.presenceKey && record.iv) {\n const plaintext = await decrypt(record.iv, record.data, this.presenceKey)\n peerPayload = JSON.parse(plaintext) as P\n } else {\n peerPayload = JSON.parse(record.data) as P\n }\n\n peers.push({ userId: record.userId, payload: peerPayload, lastSeen: record.lastSeen })\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","import 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} from '../../kernel/types.js'\nimport { NOYDB_SYNC_VERSION } from '../../kernel/types.js'\nimport { ConflictError } from '../../kernel/errors.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 } from '../../kernel/enclave/index.js'\n\n/** Sync engine: dirty tracking, push, pull, conflict resolution, scheduling. */\nexport class SyncEngine {\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\n private dirty: DirtyEntry[] = []\n private lastPush: string | null = null\n private lastPull: 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 vault at open. */\n private cacheInvalidator?: (collection: string, id: string) => Promise<void>\n\n /** Wire the Collection-cache invalidation hook (#598). Same injection pattern as `setPairExpander`. */\n setCacheInvalidator(fn: (collection: string, id: string) => Promise<void>): void {\n this.cacheInvalidator = fn\n }\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 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\n // Create scheduler if a policy is provided\n const policy = opts.syncPolicy\n if (policy && policy.push.mode !== 'manual') {\n this.scheduler = new SyncScheduler(policy, {\n push: () => this.push().then(() => {}),\n pull: () => this.pull().then(() => {}),\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: 'put' | 'delete', 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 /** Push dirty records to remote adapter. Accepts optional `PushOptions` for partial sync. */\n async push(options?: PushOptions): Promise<PushResult> {\n await this.ensureLoaded()\n\n let pushed = 0\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)\n const filter = options?.collections ? new Set(this.pairExpander?.(options.collections) ?? options.collections) : null\n\n for (let i = 0; i < this.dirty.length; i++) {\n const entry = this.dirty[i]!\n\n // Partial sync: skip collections not in the filter\n if (filter && !filter.has(entry.collection)) {\n continue\n }\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 // Record was deleted locally after being marked dirty\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 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 (err instanceof ConflictError) {\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 await this.remote.put(this.vault, entry.collection, entry.id, conflict.local)\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 // 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 completed.push(i)\n pushed++\n }\n // handled === 'deferred': leave in dirty log\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 // 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 this.lastPush = new Date().toISOString()\n await this.persistMeta()\n\n const result: PushResult = { pushed, conflicts, errors, erasures }\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 const conflicts: Conflict[] = []\n const erasures: ErasureEnforcement[] = []\n const errors: Error[] = []\n\n // Partial sync: expand the filter to cover satellite pair partners (#591 rule 5b)\n const filter = options?.collections ? new Set(this.pairExpander?.(options.collections) ?? options.collections) : null\n\n try {\n const remoteSnapshot = await this.remote.loadAll(this.vault)\n\n for (const [collName, records] of Object.entries(remoteSnapshot)) {\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 // 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 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 (remoteEnvelope._v > localEnvelope._v) {\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 } catch (err) {\n errors.push(err instanceof Error ? err : new Error(String(err)))\n }\n\n this.lastPull = new Date().toISOString()\n await this.persistMeta()\n\n const result: PullResult = { pulled, conflicts, errors, erasures }\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 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 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 (err instanceof ConflictError) {\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 await this.remote.put(this.vault, entry.collection, entry.id, conflict.local)\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.lastPush = new Date().toISOString()\n await this.persistMeta()\n\n const result: PushResult = { pushed, conflicts, errors, erasures }\n this.emitter.emit('sync:push', result)\n return result\n }\n\n /** Get current sync status. */\n status(): SyncStatus {\n return {\n dirty: this.dirty.length,\n lastPush: this.lastPush,\n lastPull: this.lastPull,\n online: this.isOnline,\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). */\n private async applyRemote(collection: string, id: string, envelope: EncryptedEnvelope): Promise<void> {\n await this.local.put(this.vault, collection, id, envelope)\n await this.cacheInvalidator?.(collection, id)\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 }\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 }\n\n const envelope: EncryptedEnvelope = {\n _noydb: 1,\n _v: 1,\n _ts: new Date().toISOString(),\n _iv: '',\n _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 './sync.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":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
NOYDB_FORMAT_VERSION
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-REWTMYSF.js";
|
|
4
4
|
|
|
5
5
|
// src/with-party/policy/storage.ts
|
|
6
6
|
var META_COLLECTION = "_meta";
|
|
@@ -39,4 +39,4 @@ export {
|
|
|
39
39
|
loadVaultPolicy,
|
|
40
40
|
saveVaultPolicy
|
|
41
41
|
};
|
|
42
|
-
//# sourceMappingURL=chunk-
|
|
42
|
+
//# sourceMappingURL=chunk-BTFTHF6Q.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
writePod
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-BJ2XF2RC.js";
|
|
4
4
|
|
|
5
5
|
// src/with-audit/portability/export-accessible.ts
|
|
6
6
|
function resolveAccessibleCollections(keyring, scope, writableOnly = false) {
|
|
@@ -42,4 +42,4 @@ export {
|
|
|
42
42
|
buildAccessibleBundle,
|
|
43
43
|
exportAccessibleData
|
|
44
44
|
};
|
|
45
|
-
//# sourceMappingURL=chunk-
|
|
45
|
+
//# sourceMappingURL=chunk-DCVVCJVB.js.map
|
|
@@ -4,13 +4,13 @@ import {
|
|
|
4
4
|
grant,
|
|
5
5
|
revoke,
|
|
6
6
|
rotateKeys
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-TUL5YQWF.js";
|
|
8
8
|
import {
|
|
9
9
|
openEnvelopeJson
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-7TAV3BFQ.js";
|
|
11
11
|
import {
|
|
12
12
|
NOYDB_FORMAT_VERSION
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-REWTMYSF.js";
|
|
14
14
|
import {
|
|
15
15
|
encrypt
|
|
16
16
|
} from "./chunk-5HZULLHE.js";
|
|
@@ -96,4 +96,4 @@ export {
|
|
|
96
96
|
listCredentials,
|
|
97
97
|
credentialStatus
|
|
98
98
|
};
|
|
99
|
-
//# sourceMappingURL=chunk-
|
|
99
|
+
//# sourceMappingURL=chunk-F3EKFGUS.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
NOYDB_FORMAT_VERSION
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-REWTMYSF.js";
|
|
4
4
|
import {
|
|
5
5
|
derivePassphraseKey
|
|
6
6
|
} from "./chunk-5HZULLHE.js";
|
|
@@ -202,4 +202,4 @@ export {
|
|
|
202
202
|
mintPaperRecoveryEntry,
|
|
203
203
|
unwrapDeksFromPaperEntry
|
|
204
204
|
};
|
|
205
|
-
//# sourceMappingURL=chunk-
|
|
205
|
+
//# sourceMappingURL=chunk-FWART3VA.js.map
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
openEnvelopeJson
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-7TAV3BFQ.js";
|
|
4
4
|
import {
|
|
5
5
|
NOYDB_FORMAT_VERSION
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-REWTMYSF.js";
|
|
7
7
|
import {
|
|
8
8
|
encrypt
|
|
9
9
|
} from "./chunk-5HZULLHE.js";
|
|
@@ -147,4 +147,4 @@ export {
|
|
|
147
147
|
deleteUserEnvelope,
|
|
148
148
|
listUserEnvelopeIds
|
|
149
149
|
};
|
|
150
|
-
//# sourceMappingURL=chunk-
|
|
150
|
+
//# sourceMappingURL=chunk-FZK3JJJK.js.map
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
persistUserVisibility,
|
|
5
5
|
readUserVisibility,
|
|
6
6
|
saveUserEnvelope
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-FZK3JJJK.js";
|
|
8
8
|
import {
|
|
9
9
|
PolicyDeniedError
|
|
10
10
|
} from "./chunk-OJ64XMPJ.js";
|
|
@@ -379,4 +379,4 @@ export {
|
|
|
379
379
|
UserApi,
|
|
380
380
|
createUserApi
|
|
381
381
|
};
|
|
382
|
-
//# sourceMappingURL=chunk-
|
|
382
|
+
//# sourceMappingURL=chunk-GDOOG5YQ.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
NOYDB_FORMAT_VERSION
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-REWTMYSF.js";
|
|
4
4
|
import {
|
|
5
5
|
ValidationError
|
|
6
6
|
} from "./chunk-OJ64XMPJ.js";
|
|
@@ -152,4 +152,4 @@ export {
|
|
|
152
152
|
resolveLocale,
|
|
153
153
|
pickLocale
|
|
154
154
|
};
|
|
155
|
-
//# sourceMappingURL=chunk-
|
|
155
|
+
//# sourceMappingURL=chunk-GLVXQU3E.js.map
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ATTESTATIONS_COLLECTION,
|
|
3
3
|
loadOrCreateSigner
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-X5QZAJDB.js";
|
|
5
5
|
import {
|
|
6
6
|
generateULID
|
|
7
7
|
} from "./chunk-ZJADGNYF.js";
|
|
8
8
|
import {
|
|
9
9
|
NOYDB_FORMAT_VERSION
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-REWTMYSF.js";
|
|
11
11
|
import {
|
|
12
12
|
encrypt
|
|
13
13
|
} from "./chunk-5HZULLHE.js";
|
|
@@ -56,4 +56,4 @@ async function issueAttestationCore(ctx, args) {
|
|
|
56
56
|
export {
|
|
57
57
|
issueAttestationCore
|
|
58
58
|
};
|
|
59
|
-
//# sourceMappingURL=chunk-
|
|
59
|
+
//# sourceMappingURL=chunk-I6URUNTD.js.map
|