@noy-db/hub 0.4.0-pre.9 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{api-3NKVNZPM.js → api-SI2IVBQO.js} +6 -6
- package/dist/attestation/index.js +12 -12
- package/dist/{backup-PTSVXDDW.js → backup-X7F3TCFV.js} +6 -6
- package/dist/blobs/index.js +5 -5
- package/dist/broker/index.js +6 -6
- package/dist/cargo/index.js +20 -20
- package/dist/{chunk-WZ3NCMK6.js → chunk-2BET5QTS.js} +3 -3
- package/dist/{chunk-Y6B6HVKC.js → chunk-2J6UEN2V.js} +41 -17
- package/dist/chunk-2J6UEN2V.js.map +1 -0
- package/dist/{chunk-BYFXLDVV.js → chunk-3ECU57YH.js} +7 -7
- package/dist/{chunk-ZWBKDKXC.js → chunk-467SWYT5.js} +2 -2
- package/dist/{chunk-MTJLOC3Y.js → chunk-55LKVALY.js} +106 -10
- package/dist/chunk-55LKVALY.js.map +1 -0
- package/dist/{chunk-XIDQKFZF.js → chunk-5UQ7Y6SQ.js} +2 -2
- package/dist/{chunk-GZACYEOB.js → chunk-77AEMXFA.js} +1 -1
- package/dist/chunk-77AEMXFA.js.map +1 -0
- package/dist/{chunk-IMRB2C4O.js → chunk-7H3WWH6J.js} +3 -3
- package/dist/{chunk-OLIWCCFM.js → chunk-CLE3TMIS.js} +2 -2
- package/dist/{chunk-ZFUFAHZ3.js → chunk-DAFBJS4Y.js} +2 -2
- package/dist/{chunk-ISRKW4YN.js → chunk-DQZXPGGZ.js} +2 -2
- package/dist/{chunk-FMNU7IUG.js → chunk-DTFA5DO4.js} +2 -2
- package/dist/{chunk-VH6SOCXH.js → chunk-EFJAAFBW.js} +2 -2
- package/dist/{chunk-TIVK6PRK.js → chunk-ERGECZEI.js} +5 -5
- package/dist/{chunk-NGSJZFGL.js → chunk-GTYFIVIZ.js} +83 -21
- package/dist/chunk-GTYFIVIZ.js.map +1 -0
- package/dist/{chunk-KW42W6SV.js → chunk-HLKXPJ4V.js} +4 -4
- package/dist/{chunk-MANUDU7I.js → chunk-HZZP2ZIG.js} +4 -4
- package/dist/{chunk-DZAF24PG.js → chunk-IFOH7RBI.js} +3 -3
- package/dist/{chunk-FRMW23UK.js → chunk-IVYQAVWO.js} +2 -2
- package/dist/{chunk-SGQ4N5FS.js → chunk-JEI6JJNI.js} +3 -3
- package/dist/{chunk-BN4HRYAZ.js → chunk-JQ2AX4T5.js} +2 -2
- package/dist/{chunk-OBPVWOSQ.js → chunk-KD4HGBJV.js} +3 -3
- package/dist/{chunk-QADFHRQM.js → chunk-KYRDJI5O.js} +8 -8
- package/dist/{chunk-2NMEGSFV.js → chunk-LLYIMSQQ.js} +9 -9
- package/dist/{chunk-GP3UWP22.js → chunk-LRRX57UA.js} +2 -2
- package/dist/{chunk-OLSARBZU.js → chunk-LXRTP3AQ.js} +2 -2
- package/dist/{chunk-EBKCYQ2D.js → chunk-NBXFCQX4.js} +3 -3
- package/dist/{chunk-BXHMZ2XW.js → chunk-NLYALJMY.js} +24 -14
- package/dist/chunk-NLYALJMY.js.map +1 -0
- package/dist/{chunk-EZNTORXE.js → chunk-NM5UYF6Q.js} +1 -1
- package/dist/chunk-NM5UYF6Q.js.map +1 -0
- package/dist/{chunk-NEX7JCMO.js → chunk-OWHP3H5C.js} +3 -3
- package/dist/{chunk-WO4T4OD5.js → chunk-P4JO3H6R.js} +2 -2
- package/dist/{chunk-CCDP6EPB.js → chunk-PWPYO73B.js} +2 -2
- package/dist/{chunk-56IIVAEO.js → chunk-Q2SEJMP2.js} +2 -2
- package/dist/{chunk-JIDLU57U.js → chunk-Q36YXK77.js} +2 -2
- package/dist/{chunk-KPXM4WO6.js → chunk-Q5YJCVJY.js} +3 -3
- package/dist/{chunk-JYV4JJV2.js → chunk-QGIBI6GL.js} +4 -4
- package/dist/{chunk-DGBIHDVK.js → chunk-RBTVFPHF.js} +3 -3
- package/dist/{chunk-6R6Q3MRN.js → chunk-RQ4ZI4ZI.js} +4 -4
- package/dist/{chunk-FO6RNKKW.js → chunk-S7GIXBXV.js} +2 -2
- package/dist/chunk-SBHN6QUT.js +25 -0
- package/dist/chunk-SBHN6QUT.js.map +1 -0
- package/dist/{chunk-3XKESW5E.js → chunk-SF2ZIRD6.js} +2 -2
- package/dist/{chunk-TE6LH6J2.js → chunk-SFBYQMZM.js} +3 -3
- package/dist/{chunk-RZPOZPZU.js → chunk-SU6SGWXM.js} +3 -3
- package/dist/{chunk-6L3DKWRY.js → chunk-T2MOJF76.js} +2 -2
- package/dist/{chunk-SKM35Y4Q.js → chunk-TS5XLBZR.js} +3 -3
- package/dist/{chunk-HFUAFR6B.js → chunk-TWPK7KUJ.js} +3 -3
- package/dist/{chunk-6M2I3DKF.js → chunk-WK7ULBTP.js} +2 -2
- package/dist/{chunk-IF6WNGAK.js → chunk-WUHEP3HH.js} +2 -2
- package/dist/{chunk-NQSO4UAH.js → chunk-WYUAEZSC.js} +3 -3
- package/dist/{chunk-Y6VZQGGH.js → chunk-YGK2HMLR.js} +4 -4
- package/dist/{chunk-OW5Y6HA6.js → chunk-ZBYFMI6D.js} +223 -119
- package/dist/chunk-ZBYFMI6D.js.map +1 -0
- package/dist/{chunk-N5PLUFH2.js → chunk-ZFG5EBI3.js} +4 -4
- package/dist/{chunk-KFRPNHWR.js → chunk-ZHDSUZQU.js} +3 -3
- package/dist/{chunk-C25JXSOR.js → chunk-ZNWSG7XC.js} +5 -5
- package/dist/classified/index.js +3 -3
- package/dist/{classified-marker-EOOSMWFC.js → classified-marker-LE54HWSX.js} +3 -3
- package/dist/{collection-facade-TTRF5NFJ.js → collection-facade-DO2AABZT.js} +8 -8
- package/dist/consent/index.js +4 -4
- package/dist/cover/index.js +2 -2
- package/dist/custody/index.js +6 -6
- package/dist/{dead-filter-6DYY7S64.js → dead-filter-V3LVWYEJ.js} +2 -2
- package/dist/debug/index.js +29 -0
- package/dist/debug/index.js.map +1 -0
- package/dist/{delegation-ONOZVPIP.js → delegation-JDUMAF6L.js} +4 -4
- package/dist/derivations/index.js +3 -3
- package/dist/{derive-IGGVSUPH.js → derive-ZPGVLE2Q.js} +4 -4
- package/dist/directory/index.js +5 -5
- package/dist/{dispatch-RPTLK7LJ.js → dispatch-6TV3DGO6.js} +5 -5
- package/dist/{dispatch-7T45NN7C.js → dispatch-W7NWQ637.js} +9 -9
- package/dist/{enclave-CLJVSDFG.js → enclave-YFCLPIDR.js} +4 -4
- package/dist/{executor-XZYM4KHT.js → executor-FPHKWDWT.js} +8 -8
- package/dist/{export-accessible-24XCCD3A.js → export-accessible-EKM3HGB2.js} +7 -7
- package/dist/{extract-partition-H2TPEEOF.js → extract-partition-LS4ET5A6.js} +10 -10
- package/dist/{fanout-sidecar-TV7CXAJ6.js → fanout-sidecar-273RDMYS.js} +4 -4
- package/dist/forget/index.js +4 -4
- package/dist/history/index.js +6 -6
- package/dist/i18n/index.js +6 -6
- package/dist/index.d.ts +7 -7
- package/dist/index.js +148 -96
- package/dist/index.js.map +1 -1
- package/dist/introspection/index.js +5 -5
- package/dist/{issue-55HJE7JF.js → issue-LIA7FXBJ.js} +6 -6
- package/dist/kernel/collection.d.ts +89 -2
- package/dist/kernel/debug.d.ts +11 -0
- package/dist/kernel/noydb.d.ts +3 -3
- package/dist/kernel/prepared-write.d.ts +70 -0
- package/dist/kernel/sync-policy.d.ts +75 -3
- package/dist/kernel/types.d.ts +27 -8
- package/dist/{ledger-XY6NP3J2.js → ledger-XE7JF2I2.js} +6 -6
- package/dist/liberate-WZ3RHVKW.js +24 -0
- package/dist/{link-set-POQB7BU5.js → link-set-CGYC3OH5.js} +5 -5
- package/dist/materialized-views/index.js +13 -13
- package/dist/{noydb-MGPOYDOD.js → noydb-ZLPVCDES.js} +30 -31
- package/dist/periods/index.js +8 -8
- package/dist/pod/index.js +6 -6
- package/dist/policy/index.js +3 -3
- package/dist/port/with/strategies.d.ts +1 -1
- package/dist/portability/index.js +6 -6
- package/dist/{post-register-URQANI3B.js → post-register-LY35EDTJ.js} +4 -4
- package/dist/{register-5W6CG4RM.js → register-6RIBIT3I.js} +6 -6
- package/dist/{registry-UJFP3NWF.js → registry-MUSL4AW6.js} +4 -4
- package/dist/{registry-MCSGBZXI.js → registry-RON4WHAP.js} +4 -4
- package/dist/{request-withdrawal-IWYDM4SO.js → request-withdrawal-FT3ORAWN.js} +9 -9
- package/dist/{reveal-BXZGWIOP.js → reveal-T34ADTPY.js} +3 -3
- package/dist/{revoke-TINYPHYY.js → revoke-HC7WG3HE.js} +6 -6
- package/dist/sealed-record/index.js +6 -6
- package/dist/search/index.js +1 -1
- package/dist/{seed-F7YYQTRC.js → seed-JOV54PB3.js} +6 -6
- package/dist/seed-JOV54PB3.js.map +1 -0
- package/dist/sequence/index.js +4 -4
- package/dist/session/index.js +3 -3
- package/dist/{signer-WMZKCNKC.js → signer-CTWOH6KT.js} +5 -5
- package/dist/snapshots/index.js +5 -5
- package/dist/{stale-JOE7GBAE.js → stale-T3V7XEOB.js} +5 -5
- package/dist/{storage-B3WBKXKT.js → storage-LLNLPWWB.js} +5 -5
- package/dist/{store-coordination-provider-5LX2UFU2.js → store-coordination-provider-AHGFEMFA.js} +3 -3
- package/dist/sync/index.js +9 -10
- package/dist/sync/index.js.map +1 -1
- package/dist/team/index.js +8 -30
- package/dist/tiers/index.js +4 -4
- package/dist/transactions/index.js +1 -1
- package/dist/{walk-6OHAWGBS.js → walk-G3NFEP5L.js} +6 -6
- package/dist/with-commit/tx/atomic-eligibility.d.ts +47 -0
- package/dist/with-commit/tx/transaction.d.ts +22 -9
- package/dist/with-party/broker/seed.d.ts +1 -1
- package/dist/with-party/team/index.d.ts +0 -5
- package/dist/{with-party/team/sync-active.d.ts → with-sync/active.d.ts} +1 -1
- package/dist/{with-party/team/sync-credentials.d.ts → with-sync/credentials.d.ts} +3 -3
- package/dist/{with-party/team/sync.d.ts → with-sync/engine.d.ts} +5 -5
- package/dist/{with-party/sync → with-sync}/index.d.ts +3 -3
- package/dist/{with-party/team/sync-period-scope.d.ts → with-sync/period-scope.d.ts} +2 -2
- package/dist/{with-party/team → with-sync}/presence.d.ts +2 -2
- package/dist/{with-party/team/sync-strategy.d.ts → with-sync/strategy.d.ts} +6 -6
- package/dist/{with-party/team/sync-transaction.d.ts → with-sync/transaction.d.ts} +3 -3
- package/dist/{withdraw-accessible-DEUCOO4F.js → withdraw-accessible-ANSVG6XG.js} +8 -8
- package/package.json +8 -4
- package/dist/chunk-BXHMZ2XW.js.map +0 -1
- package/dist/chunk-EP5L47XV.js +0 -22
- package/dist/chunk-EP5L47XV.js.map +0 -1
- package/dist/chunk-EZNTORXE.js.map +0 -1
- package/dist/chunk-GZACYEOB.js.map +0 -1
- package/dist/chunk-MTJLOC3Y.js.map +0 -1
- package/dist/chunk-NGSJZFGL.js.map +0 -1
- package/dist/chunk-OW5Y6HA6.js.map +0 -1
- package/dist/chunk-SHYIA73K.js +0 -99
- package/dist/chunk-SHYIA73K.js.map +0 -1
- package/dist/chunk-Y6B6HVKC.js.map +0 -1
- package/dist/liberate-LXOJ2EMB.js +0 -24
- package/dist/seed-F7YYQTRC.js.map +0 -1
- /package/dist/{api-3NKVNZPM.js.map → api-SI2IVBQO.js.map} +0 -0
- /package/dist/{backup-PTSVXDDW.js.map → backup-X7F3TCFV.js.map} +0 -0
- /package/dist/{chunk-WZ3NCMK6.js.map → chunk-2BET5QTS.js.map} +0 -0
- /package/dist/{chunk-BYFXLDVV.js.map → chunk-3ECU57YH.js.map} +0 -0
- /package/dist/{chunk-ZWBKDKXC.js.map → chunk-467SWYT5.js.map} +0 -0
- /package/dist/{chunk-XIDQKFZF.js.map → chunk-5UQ7Y6SQ.js.map} +0 -0
- /package/dist/{chunk-IMRB2C4O.js.map → chunk-7H3WWH6J.js.map} +0 -0
- /package/dist/{chunk-OLIWCCFM.js.map → chunk-CLE3TMIS.js.map} +0 -0
- /package/dist/{chunk-ZFUFAHZ3.js.map → chunk-DAFBJS4Y.js.map} +0 -0
- /package/dist/{chunk-ISRKW4YN.js.map → chunk-DQZXPGGZ.js.map} +0 -0
- /package/dist/{chunk-FMNU7IUG.js.map → chunk-DTFA5DO4.js.map} +0 -0
- /package/dist/{chunk-VH6SOCXH.js.map → chunk-EFJAAFBW.js.map} +0 -0
- /package/dist/{chunk-TIVK6PRK.js.map → chunk-ERGECZEI.js.map} +0 -0
- /package/dist/{chunk-KW42W6SV.js.map → chunk-HLKXPJ4V.js.map} +0 -0
- /package/dist/{chunk-MANUDU7I.js.map → chunk-HZZP2ZIG.js.map} +0 -0
- /package/dist/{chunk-DZAF24PG.js.map → chunk-IFOH7RBI.js.map} +0 -0
- /package/dist/{chunk-FRMW23UK.js.map → chunk-IVYQAVWO.js.map} +0 -0
- /package/dist/{chunk-SGQ4N5FS.js.map → chunk-JEI6JJNI.js.map} +0 -0
- /package/dist/{chunk-BN4HRYAZ.js.map → chunk-JQ2AX4T5.js.map} +0 -0
- /package/dist/{chunk-OBPVWOSQ.js.map → chunk-KD4HGBJV.js.map} +0 -0
- /package/dist/{chunk-QADFHRQM.js.map → chunk-KYRDJI5O.js.map} +0 -0
- /package/dist/{chunk-2NMEGSFV.js.map → chunk-LLYIMSQQ.js.map} +0 -0
- /package/dist/{chunk-GP3UWP22.js.map → chunk-LRRX57UA.js.map} +0 -0
- /package/dist/{chunk-OLSARBZU.js.map → chunk-LXRTP3AQ.js.map} +0 -0
- /package/dist/{chunk-EBKCYQ2D.js.map → chunk-NBXFCQX4.js.map} +0 -0
- /package/dist/{chunk-NEX7JCMO.js.map → chunk-OWHP3H5C.js.map} +0 -0
- /package/dist/{chunk-WO4T4OD5.js.map → chunk-P4JO3H6R.js.map} +0 -0
- /package/dist/{chunk-CCDP6EPB.js.map → chunk-PWPYO73B.js.map} +0 -0
- /package/dist/{chunk-56IIVAEO.js.map → chunk-Q2SEJMP2.js.map} +0 -0
- /package/dist/{chunk-JIDLU57U.js.map → chunk-Q36YXK77.js.map} +0 -0
- /package/dist/{chunk-KPXM4WO6.js.map → chunk-Q5YJCVJY.js.map} +0 -0
- /package/dist/{chunk-JYV4JJV2.js.map → chunk-QGIBI6GL.js.map} +0 -0
- /package/dist/{chunk-DGBIHDVK.js.map → chunk-RBTVFPHF.js.map} +0 -0
- /package/dist/{chunk-6R6Q3MRN.js.map → chunk-RQ4ZI4ZI.js.map} +0 -0
- /package/dist/{chunk-FO6RNKKW.js.map → chunk-S7GIXBXV.js.map} +0 -0
- /package/dist/{chunk-3XKESW5E.js.map → chunk-SF2ZIRD6.js.map} +0 -0
- /package/dist/{chunk-TE6LH6J2.js.map → chunk-SFBYQMZM.js.map} +0 -0
- /package/dist/{chunk-RZPOZPZU.js.map → chunk-SU6SGWXM.js.map} +0 -0
- /package/dist/{chunk-6L3DKWRY.js.map → chunk-T2MOJF76.js.map} +0 -0
- /package/dist/{chunk-SKM35Y4Q.js.map → chunk-TS5XLBZR.js.map} +0 -0
- /package/dist/{chunk-HFUAFR6B.js.map → chunk-TWPK7KUJ.js.map} +0 -0
- /package/dist/{chunk-6M2I3DKF.js.map → chunk-WK7ULBTP.js.map} +0 -0
- /package/dist/{chunk-IF6WNGAK.js.map → chunk-WUHEP3HH.js.map} +0 -0
- /package/dist/{chunk-NQSO4UAH.js.map → chunk-WYUAEZSC.js.map} +0 -0
- /package/dist/{chunk-Y6VZQGGH.js.map → chunk-YGK2HMLR.js.map} +0 -0
- /package/dist/{chunk-N5PLUFH2.js.map → chunk-ZFG5EBI3.js.map} +0 -0
- /package/dist/{chunk-KFRPNHWR.js.map → chunk-ZHDSUZQU.js.map} +0 -0
- /package/dist/{chunk-C25JXSOR.js.map → chunk-ZNWSG7XC.js.map} +0 -0
- /package/dist/{classified-marker-EOOSMWFC.js.map → classified-marker-LE54HWSX.js.map} +0 -0
- /package/dist/{collection-facade-TTRF5NFJ.js.map → collection-facade-DO2AABZT.js.map} +0 -0
- /package/dist/{dead-filter-6DYY7S64.js.map → dead-filter-V3LVWYEJ.js.map} +0 -0
- /package/dist/{delegation-ONOZVPIP.js.map → delegation-JDUMAF6L.js.map} +0 -0
- /package/dist/{derive-IGGVSUPH.js.map → derive-ZPGVLE2Q.js.map} +0 -0
- /package/dist/{dispatch-RPTLK7LJ.js.map → dispatch-6TV3DGO6.js.map} +0 -0
- /package/dist/{dispatch-7T45NN7C.js.map → dispatch-W7NWQ637.js.map} +0 -0
- /package/dist/{enclave-CLJVSDFG.js.map → enclave-YFCLPIDR.js.map} +0 -0
- /package/dist/{executor-XZYM4KHT.js.map → executor-FPHKWDWT.js.map} +0 -0
- /package/dist/{export-accessible-24XCCD3A.js.map → export-accessible-EKM3HGB2.js.map} +0 -0
- /package/dist/{extract-partition-H2TPEEOF.js.map → extract-partition-LS4ET5A6.js.map} +0 -0
- /package/dist/{fanout-sidecar-TV7CXAJ6.js.map → fanout-sidecar-273RDMYS.js.map} +0 -0
- /package/dist/{issue-55HJE7JF.js.map → issue-LIA7FXBJ.js.map} +0 -0
- /package/dist/{ledger-XY6NP3J2.js.map → ledger-XE7JF2I2.js.map} +0 -0
- /package/dist/{liberate-LXOJ2EMB.js.map → liberate-WZ3RHVKW.js.map} +0 -0
- /package/dist/{link-set-POQB7BU5.js.map → link-set-CGYC3OH5.js.map} +0 -0
- /package/dist/{noydb-MGPOYDOD.js.map → noydb-ZLPVCDES.js.map} +0 -0
- /package/dist/{post-register-URQANI3B.js.map → post-register-LY35EDTJ.js.map} +0 -0
- /package/dist/{register-5W6CG4RM.js.map → register-6RIBIT3I.js.map} +0 -0
- /package/dist/{registry-MCSGBZXI.js.map → registry-MUSL4AW6.js.map} +0 -0
- /package/dist/{registry-UJFP3NWF.js.map → registry-RON4WHAP.js.map} +0 -0
- /package/dist/{request-withdrawal-IWYDM4SO.js.map → request-withdrawal-FT3ORAWN.js.map} +0 -0
- /package/dist/{reveal-BXZGWIOP.js.map → reveal-T34ADTPY.js.map} +0 -0
- /package/dist/{revoke-TINYPHYY.js.map → revoke-HC7WG3HE.js.map} +0 -0
- /package/dist/{signer-WMZKCNKC.js.map → signer-CTWOH6KT.js.map} +0 -0
- /package/dist/{stale-JOE7GBAE.js.map → stale-T3V7XEOB.js.map} +0 -0
- /package/dist/{storage-B3WBKXKT.js.map → storage-LLNLPWWB.js.map} +0 -0
- /package/dist/{store-coordination-provider-5LX2UFU2.js.map → store-coordination-provider-AHGFEMFA.js.map} +0 -0
- /package/dist/{walk-6OHAWGBS.js.map → walk-G3NFEP5L.js.map} +0 -0
- /package/dist/{with-party → with-sync}/tab-coordination.d.ts +0 -0
- /package/dist/{with-party → with-sync}/tab-write-relay.d.ts +0 -0
- /package/dist/{withdraw-accessible-DEUCOO4F.js.map → withdraw-accessible-ANSVG6XG.js.map} +0 -0
|
@@ -8,6 +8,35 @@ var POD_STORE_POLICY = {
|
|
|
8
8
|
pull: { mode: "interval", intervalMs: 6e4 }
|
|
9
9
|
};
|
|
10
10
|
var BUNDLE_STORE_POLICY = POD_STORE_POLICY;
|
|
11
|
+
function validatePullPolicy(pull) {
|
|
12
|
+
if (pull.mode !== "phased") {
|
|
13
|
+
if (pull.sequence !== void 0) {
|
|
14
|
+
throw new Error(
|
|
15
|
+
`syncPolicy.pull.sequence is only meaningful with mode: 'phased' (got '${pull.mode}'). Set mode: 'phased' to run the sequence, or drop the field.`
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const { sequence } = pull;
|
|
21
|
+
if (!sequence || sequence.length === 0) {
|
|
22
|
+
throw new Error(
|
|
23
|
+
`syncPolicy.pull.mode: 'phased' requires a non-empty 'sequence' of collection names.`
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
for (const name of sequence) {
|
|
27
|
+
if (typeof name !== "string" || name.length === 0) {
|
|
28
|
+
throw new Error(
|
|
29
|
+
`syncPolicy.pull.sequence entries must be non-empty collection names (got ${JSON.stringify(name)}).`
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const duplicate = sequence.find((name, i) => sequence.indexOf(name) !== i);
|
|
34
|
+
if (duplicate !== void 0) {
|
|
35
|
+
throw new Error(
|
|
36
|
+
`syncPolicy.pull.sequence lists "${duplicate}" more than once. Each collection is pulled whole, so a repeat does no additional work.`
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
11
40
|
var SyncScheduler = class {
|
|
12
41
|
policy;
|
|
13
42
|
callbacks;
|
|
@@ -17,6 +46,10 @@ var SyncScheduler = class {
|
|
|
17
46
|
_lastError = null;
|
|
18
47
|
_lastPushTime = 0;
|
|
19
48
|
// monotonic ms for minIntervalMs enforcement
|
|
49
|
+
// Phased-pull progress. Empty for every other mode, so non-adopters carry
|
|
50
|
+
// an empty Map and a null — no per-read cost, nothing to interpret.
|
|
51
|
+
_readiness = /* @__PURE__ */ new Map();
|
|
52
|
+
_phase = null;
|
|
20
53
|
// Timers
|
|
21
54
|
debounceTimer = null;
|
|
22
55
|
pushIntervalTimer = null;
|
|
@@ -27,6 +60,7 @@ var SyncScheduler = class {
|
|
|
27
60
|
boundOnPageHide = null;
|
|
28
61
|
started = false;
|
|
29
62
|
constructor(policy, callbacks) {
|
|
63
|
+
validatePullPolicy(policy.pull);
|
|
30
64
|
this.policy = policy;
|
|
31
65
|
this.callbacks = callbacks;
|
|
32
66
|
if (this.shouldRegisterUnload()) {
|
|
@@ -42,7 +76,10 @@ var SyncScheduler = class {
|
|
|
42
76
|
lastPushAt: this._lastPushAt,
|
|
43
77
|
lastPullAt: this._lastPullAt,
|
|
44
78
|
lastError: this._lastError,
|
|
45
|
-
pendingWrites: this.callbacks.getDirtyCount()
|
|
79
|
+
pendingWrites: this.callbacks.getDirtyCount(),
|
|
80
|
+
// Copied, not aliased — a status snapshot must not mutate under its reader.
|
|
81
|
+
readiness: new Map(this._readiness),
|
|
82
|
+
phase: this._phase
|
|
46
83
|
};
|
|
47
84
|
}
|
|
48
85
|
/** Start the scheduler — registers timers, event listeners. */
|
|
@@ -54,10 +91,13 @@ var SyncScheduler = class {
|
|
|
54
91
|
void this.executePush();
|
|
55
92
|
}, this.policy.push.intervalMs);
|
|
56
93
|
}
|
|
57
|
-
if (this.policy.pull.mode === "interval"
|
|
58
|
-
this.
|
|
59
|
-
|
|
60
|
-
|
|
94
|
+
if (this.policy.pull.mode === "interval") {
|
|
95
|
+
this.startPullInterval();
|
|
96
|
+
}
|
|
97
|
+
if (this.policy.pull.mode === "phased") {
|
|
98
|
+
const sequence = this.policy.pull.sequence ?? [];
|
|
99
|
+
for (const collection of sequence) this._readiness.set(collection, "cold");
|
|
100
|
+
void this.runSequence(sequence);
|
|
61
101
|
}
|
|
62
102
|
if (this.policy.pull.mode === "on-focus" && typeof document !== "undefined") {
|
|
63
103
|
document.addEventListener("visibilitychange", this.handleFocusPull);
|
|
@@ -78,6 +118,10 @@ var SyncScheduler = class {
|
|
|
78
118
|
stop() {
|
|
79
119
|
if (!this.started) return;
|
|
80
120
|
this.started = false;
|
|
121
|
+
for (const [collection, state] of this._readiness) {
|
|
122
|
+
if (state === "pulling") this._readiness.set(collection, "cold");
|
|
123
|
+
}
|
|
124
|
+
this._phase = null;
|
|
81
125
|
if (this.debounceTimer) {
|
|
82
126
|
clearTimeout(this.debounceTimer);
|
|
83
127
|
this.debounceTimer = null;
|
|
@@ -126,6 +170,37 @@ var SyncScheduler = class {
|
|
|
126
170
|
await this.executePull();
|
|
127
171
|
}
|
|
128
172
|
// ─── Internal ─────────────────────────────────────────────────────
|
|
173
|
+
/**
|
|
174
|
+
* Arm the steady-state pull timer, if the policy specifies a cadence.
|
|
175
|
+
* Shared by `'interval'` mode and by `'phased'` once its sequence drains.
|
|
176
|
+
*/
|
|
177
|
+
startPullInterval() {
|
|
178
|
+
if (this.pullIntervalTimer || !this.policy.pull.intervalMs) return;
|
|
179
|
+
this.pullIntervalTimer = setInterval(() => {
|
|
180
|
+
void this.executePull();
|
|
181
|
+
}, this.policy.pull.intervalMs);
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Pull each collection in turn, then hand over to steady state.
|
|
185
|
+
*
|
|
186
|
+
* Strictly sequential — running phases concurrently would defeat the
|
|
187
|
+
* prioritisation that is the entire point of a sequence. Each phase is an
|
|
188
|
+
* ordinary scoped pull, so a phase that reports errors does not abort the
|
|
189
|
+
* ones behind it; `executePull` records the failure and the walk continues.
|
|
190
|
+
* `started` is re-checked between phases so `stop()` cuts a sequence short
|
|
191
|
+
* instead of letting it run on against a closed vault.
|
|
192
|
+
*/
|
|
193
|
+
async runSequence(sequence) {
|
|
194
|
+
for (const [i, collection] of sequence.entries()) {
|
|
195
|
+
if (!this.started) return;
|
|
196
|
+
this._readiness.set(collection, "pulling");
|
|
197
|
+
this._phase = { index: i + 1, total: sequence.length };
|
|
198
|
+
const outcome = await this.executePull([collection]);
|
|
199
|
+
this._readiness.set(collection, outcome === "complete" ? "live" : "cold");
|
|
200
|
+
}
|
|
201
|
+
this._phase = null;
|
|
202
|
+
if (this.started) this.startPullInterval();
|
|
203
|
+
}
|
|
129
204
|
async executePush() {
|
|
130
205
|
if (this._state === "pushing") return;
|
|
131
206
|
const minInterval = this.policy.push.minIntervalMs ?? 0;
|
|
@@ -154,18 +229,20 @@ var SyncScheduler = class {
|
|
|
154
229
|
this._state = "error";
|
|
155
230
|
}
|
|
156
231
|
}
|
|
157
|
-
async executePull() {
|
|
158
|
-
if (this._state === "pulling") return;
|
|
232
|
+
async executePull(collections) {
|
|
233
|
+
if (this._state === "pulling") return "incomplete";
|
|
159
234
|
const previousState = this._state;
|
|
160
235
|
this._state = "pulling";
|
|
161
236
|
try {
|
|
162
|
-
await this.callbacks.pull();
|
|
237
|
+
const outcome = await this.callbacks.pull(collections);
|
|
163
238
|
this._lastPullAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
164
239
|
this._lastError = null;
|
|
165
240
|
this._state = previousState === "pending" ? "pending" : "idle";
|
|
241
|
+
return outcome ?? "complete";
|
|
166
242
|
} catch (err) {
|
|
167
243
|
this._lastError = err instanceof Error ? err : new Error(String(err));
|
|
168
244
|
this._state = "error";
|
|
245
|
+
return "incomplete";
|
|
169
246
|
}
|
|
170
247
|
}
|
|
171
248
|
resetDebounce() {
|
|
@@ -210,10 +287,29 @@ var SyncScheduler = class {
|
|
|
210
287
|
}
|
|
211
288
|
};
|
|
212
289
|
|
|
290
|
+
// src/with-sync/strategy.ts
|
|
291
|
+
function notEnabled(op) {
|
|
292
|
+
return new Error(
|
|
293
|
+
`${op} requires the sync strategy. Import \`{ withSync }\` from "@noy-db/hub/sync" and pass it to \`createNoydb({ syncStrategy: withSync() })\`.`
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
var NO_SYNC = {
|
|
297
|
+
buildSyncEngine() {
|
|
298
|
+
throw notEnabled("SyncEngine");
|
|
299
|
+
},
|
|
300
|
+
buildSyncTransaction() {
|
|
301
|
+
throw notEnabled("SyncTransaction");
|
|
302
|
+
},
|
|
303
|
+
buildPresence() {
|
|
304
|
+
throw notEnabled("collection.presence()");
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
|
|
213
308
|
export {
|
|
214
309
|
INDEXED_STORE_POLICY,
|
|
215
310
|
POD_STORE_POLICY,
|
|
216
311
|
BUNDLE_STORE_POLICY,
|
|
217
|
-
SyncScheduler
|
|
312
|
+
SyncScheduler,
|
|
313
|
+
NO_SYNC
|
|
218
314
|
};
|
|
219
|
-
//# sourceMappingURL=chunk-
|
|
315
|
+
//# sourceMappingURL=chunk-55LKVALY.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/kernel/sync-policy.ts","../src/with-sync/strategy.ts"],"sourcesContent":["/**\n * Sync scheduling policy.\n *\n * ## What it controls\n *\n * A {@link SyncPolicy} has two halves:\n * - **push** ({@link PushPolicy}) — when dirty local writes are sent to the remote.\n * - **pull** ({@link PullPolicy}) — when the remote is polled for new data.\n *\n * ## Choosing a policy\n *\n * The right policy depends on the backend's operational characteristics:\n *\n * | Backend type | Recommended policy |\n * |---|---|\n * | Per-record (DynamoDB, S3, IDB) | {@link INDEXED_STORE_POLICY} — `on-change` push, `manual` pull |\n * | Bundle (Drive, WebDAV, Git) | {@link POD_STORE_POLICY} — `debounce` push, `interval` pull |\n *\n * Consumers can override via `createNoydb({ syncPolicy: { ... } })`:\n *\n * ```ts\n * const db = await createNoydb({\n * store: toFile({ dir: './data' }),\n * syncPolicy: {\n * push: { mode: 'debounce', debounceMs: 5_000 },\n * pull: { mode: 'on-focus' },\n * },\n * })\n * ```\n *\n * ## Scheduler lifecycle\n *\n * {@link SyncScheduler} owns all timers, debounce logic, and browser lifecycle\n * hooks (`visibilitychange`, `pagehide`, `beforeExit`). Call `scheduler.start()`\n * after opening a vault and `scheduler.stop()` when closing it. The scheduler\n * delegates actual push/pull work to {@link SyncSchedulerCallbacks} provided\n * by the {@link SyncEngine}.\n *\n * @module\n */\n\n// ─── Policy types ───────────────────────────────────────────────────────\n\n/**\n * When push operations are triggered automatically.\n *\n * - `'manual'` — only on explicit `sync.push()` calls.\n * - `'on-change'` — immediately after every local write (respecting `minIntervalMs`).\n * - `'debounce'` — after `debounceMs` of inactivity following a write.\n * - `'interval'` — on a fixed timer regardless of writes.\n */\nexport type PushMode = 'manual' | 'on-change' | 'debounce' | 'interval'\n\n/**\n * When pull operations are triggered automatically.\n *\n * - `'manual'` — only on explicit `sync.pull()` calls.\n * - `'interval'` — on a fixed `intervalMs` timer.\n * - `'on-focus'` — when the browser tab regains visibility.\n * - `'phased'` — pull the collections named in `sequence`, in order, one at a\n * time, then settle into steady state. For thin clients that need their\n * navigation-critical collections before bulk history.\n */\nexport type PullMode = 'manual' | 'interval' | 'on-focus' | 'phased'\n\n/**\n * Push half of a sync policy. Controls the trigger mode and timing guards\n * for outbound sync operations.\n */\nexport interface PushPolicy {\n /** Push trigger mode. */\n readonly mode: PushMode\n /** Debounce delay in ms. Only used when `mode: 'debounce'`. Default: 30_000. */\n readonly debounceMs?: number\n /** Interval in ms between automatic pushes. Used by `'interval'` and as floor for `'debounce'`. */\n readonly intervalMs?: number\n /**\n * Hard floor between pushes regardless of mode. Prevents burst writes\n * from hammering the remote. Default: 0 (no floor).\n */\n readonly minIntervalMs?: number\n /**\n * Force a push on page unload (`pagehide` / `visibilitychange → hidden`)\n * in browsers, `beforeExit` in Node. Default: true for non-manual modes.\n */\n readonly onUnload?: boolean\n}\n\n/**\n * Pull half of a sync policy. Controls when and how often inbound sync\n * operations are triggered.\n */\nexport interface PullPolicy {\n /** Pull trigger mode. */\n readonly mode: PullMode\n /**\n * Interval in ms between automatic pulls. Used by `'interval'` mode. Default: 60_000.\n * Under `'phased'` it is the steady-state cadence adopted *after* the sequence\n * completes; omit it to go idle instead.\n */\n readonly intervalMs?: number\n /**\n * Collection names to pull in order, one at a time. Required when\n * `mode: 'phased'` and rejected otherwise. Entries must be non-empty and\n * unique — without period narrowing a repeated collection can only be a\n * mistake, so it is rejected rather than silently merged.\n *\n * Period-scoped phases (`collection@period`) are deferred to `partitions`;\n * use `db.pull(vault, { periods })` explicitly meanwhile.\n */\n readonly sequence?: readonly string[]\n}\n\n/**\n * Combined push + pull sync scheduling policy for a vault.\n *\n * Pass via `createNoydb({ syncPolicy })` to override the default policy\n * derived from the active store type. Pre-built defaults are available\n * as `INDEXED_STORE_POLICY` and `POD_STORE_POLICY`.\n */\nexport interface SyncPolicy {\n readonly push: PushPolicy\n readonly pull: PullPolicy\n}\n\n// ─── Default policies by store category ─────────────────────────────────\n\n/** Default for per-record stores (DynamoDB, S3, file, IDB). */\nexport const INDEXED_STORE_POLICY: SyncPolicy = {\n push: { mode: 'on-change', minIntervalMs: 0, onUnload: true },\n pull: { mode: 'manual' },\n}\n\n/** Default for bundle stores (Drive, WebDAV, Git). */\nexport const POD_STORE_POLICY: SyncPolicy = {\n push: { mode: 'debounce', debounceMs: 30_000, minIntervalMs: 120_000, onUnload: true },\n pull: { mode: 'interval', intervalMs: 60_000 },\n}\n\n/** @deprecated Use `POD_STORE_POLICY`. */\nexport const BUNDLE_STORE_POLICY = POD_STORE_POLICY\n\n// ─── Sync scheduler ─────────────────────────────────────────────────────\n\n/**\n * Current operational state of the `SyncScheduler`.\n *\n * - `'idle'` — no pending or active sync operations.\n * - `'pending'` — local writes are queued, waiting for debounce/interval to fire.\n * - `'pushing'` — push in progress.\n * - `'pulling'` — pull in progress.\n * - `'error'` — last sync operation failed; `lastError` holds the cause.\n */\nexport type SyncSchedulerState = 'idle' | 'pending' | 'pushing' | 'pulling' | 'error'\n\n/**\n * How much of a collection a caller may rely on, under a `'phased'` pull.\n *\n * - `'cold'` — not pulled yet, or its phase did not complete cleanly. A miss\n * from `get()` proves nothing.\n * - `'pulling'` — its phase is in flight. Never terminal: a phase always ends\n * in `'live'` or back in `'cold'`, because a stuck `'pulling'` would leave a\n * permanent skeleton in the UI.\n * - `'live'` — its phase completed cleanly, so a miss is a real absence.\n */\nexport type ReadinessState = 'cold' | 'pulling' | 'live'\n\n/**\n * What a scheduler-initiated pull achieved, as reported by the callback.\n *\n * `'incomplete'` covers both a pull that reported errors (`PullResult.errors`\n * accumulates without throwing) and one that was skipped — e.g. role-gated on a\n * backup target. Either way nothing may be claimed about completeness.\n */\nexport type PullPhaseOutcome = 'complete' | 'incomplete'\n\n/**\n * Snapshot of the sync scheduler's state, returned by `SyncScheduler.status`.\n * Safe to expose in a reactive UI status indicator.\n */\nexport interface SyncSchedulerStatus {\n readonly state: SyncSchedulerState\n readonly lastPushAt: string | null\n readonly lastPullAt: string | null\n readonly lastError: Error | null\n readonly pendingWrites: number\n /**\n * Per-collection readiness. Empty unless `pull.mode === 'phased'`.\n *\n * A collection the sequence never names is **absent** from the map, and\n * `undefined` means *\"no claim made\"* — never a reason to gate a UI.\n */\n readonly readiness: ReadonlyMap<string, ReadinessState>\n /** 1-based position in the sequence, or `null` outside a phased run. */\n readonly phase: { readonly index: number; readonly total: number } | null\n}\n\n/**\n * Callbacks injected into `SyncScheduler` by the SyncEngine.\n *\n * The scheduler owns timers and lifecycle hooks; it delegates actual push/pull\n * work to these callbacks to stay decoupled from the sync implementation.\n */\nexport interface SyncSchedulerCallbacks {\n push(): Promise<void>\n /**\n * @param collections - Narrow the pull to these collections. Passed by a\n * `'phased'` sequence, one collection per phase; omitted for a whole-vault pull.\n * @returns Whether the pull may be treated as complete. Returning `void` reads\n * as `'complete'`, so callers with nothing to report need not opt in.\n */\n pull(collections?: readonly string[]): Promise<PullPhaseOutcome | void>\n getDirtyCount(): number\n}\n\n/**\n * Reject a policy that cannot mean anything, at construction rather than on\n * the first tick. Module-private: `SyncScheduler` is the choke point every\n * policy that can actually schedule must pass through — primary and per-target\n * alike — so validating here needs no new public surface and costs the kernel\n * floor nothing.\n */\nfunction validatePullPolicy(pull: PullPolicy): void {\n if (pull.mode !== 'phased') {\n if (pull.sequence !== undefined) {\n throw new Error(\n `syncPolicy.pull.sequence is only meaningful with mode: 'phased' (got '${pull.mode}'). ` +\n `Set mode: 'phased' to run the sequence, or drop the field.`,\n )\n }\n return\n }\n\n const { sequence } = pull\n if (!sequence || sequence.length === 0) {\n throw new Error(\n `syncPolicy.pull.mode: 'phased' requires a non-empty 'sequence' of collection names.`,\n )\n }\n for (const name of sequence) {\n if (typeof name !== 'string' || name.length === 0) {\n throw new Error(\n `syncPolicy.pull.sequence entries must be non-empty collection names (got ${JSON.stringify(name)}).`,\n )\n }\n }\n const duplicate = sequence.find((name, i) => sequence.indexOf(name) !== i)\n if (duplicate !== undefined) {\n throw new Error(\n `syncPolicy.pull.sequence lists \"${duplicate}\" more than once. ` +\n `Each collection is pulled whole, so a repeat does no additional work.`,\n )\n }\n}\n\n/**\n * Manages sync timing according to a `SyncPolicy`.\n *\n * The scheduler owns all timers and lifecycle hooks. It delegates actual\n * push/pull work to callbacks provided by the SyncEngine.\n */\nexport class SyncScheduler {\n private readonly policy: SyncPolicy\n private readonly callbacks: SyncSchedulerCallbacks\n\n private _state: SyncSchedulerState = 'idle'\n private _lastPushAt: string | null = null\n private _lastPullAt: string | null = null\n private _lastError: Error | null = null\n private _lastPushTime = 0 // monotonic ms for minIntervalMs enforcement\n\n // Phased-pull progress. Empty for every other mode, so non-adopters carry\n // an empty Map and a null — no per-read cost, nothing to interpret.\n private readonly _readiness = new Map<string, ReadinessState>()\n private _phase: { readonly index: number; readonly total: number } | null = null\n\n // Timers\n private debounceTimer: ReturnType<typeof setTimeout> | null = null\n private pushIntervalTimer: ReturnType<typeof setInterval> | null = null\n private pullIntervalTimer: ReturnType<typeof setInterval> | null = null\n\n // Bound handlers for cleanup\n private readonly boundOnVisibilityChange: (() => void) | null = null\n private readonly boundOnBeforeExit: (() => void) | null = null\n private readonly boundOnPageHide: (() => void) | null = null\n\n private started = false\n\n constructor(policy: SyncPolicy, callbacks: SyncSchedulerCallbacks) {\n validatePullPolicy(policy.pull)\n this.policy = policy\n this.callbacks = callbacks\n\n // Pre-bind handlers\n if (this.shouldRegisterUnload()) {\n this.boundOnVisibilityChange = this.handleVisibilityChange.bind(this)\n this.boundOnPageHide = this.handlePageHide.bind(this)\n this.boundOnBeforeExit = this.handleBeforeExit.bind(this)\n }\n }\n\n /** Current scheduler status snapshot. */\n get status(): SyncSchedulerStatus {\n return {\n state: this._state,\n lastPushAt: this._lastPushAt,\n lastPullAt: this._lastPullAt,\n lastError: this._lastError,\n pendingWrites: this.callbacks.getDirtyCount(),\n // Copied, not aliased — a status snapshot must not mutate under its reader.\n readiness: new Map(this._readiness),\n phase: this._phase,\n }\n }\n\n /** Start the scheduler — registers timers, event listeners. */\n start(): void {\n if (this.started) return\n this.started = true\n\n // Push: interval mode\n if (this.policy.push.mode === 'interval' && this.policy.push.intervalMs) {\n this.pushIntervalTimer = setInterval(() => {\n void this.executePush()\n }, this.policy.push.intervalMs)\n }\n\n // Pull: interval mode\n if (this.policy.pull.mode === 'interval') {\n this.startPullInterval()\n }\n\n // Pull: phased mode — walk the sequence in order, then settle into steady\n // state. Unawaited by design: start() is synchronous and the caller\n // (vault open) must not block on a bootstrap pull.\n if (this.policy.pull.mode === 'phased') {\n const sequence = this.policy.pull.sequence ?? []\n // Every named collection is 'cold' from the moment we start, so a reader\n // that races the first phase sees \"not ready\", never a missing entry.\n for (const collection of sequence) this._readiness.set(collection, 'cold')\n void this.runSequence(sequence)\n }\n\n // Pull: on-focus mode\n if (this.policy.pull.mode === 'on-focus' && typeof document !== 'undefined') {\n document.addEventListener('visibilitychange', this.handleFocusPull)\n }\n\n // Unload hooks\n if (this.shouldRegisterUnload()) {\n if (typeof document !== 'undefined' && this.boundOnVisibilityChange) {\n document.addEventListener('visibilitychange', this.boundOnVisibilityChange)\n }\n if (typeof globalThis.addEventListener === 'function' && this.boundOnPageHide) {\n globalThis.addEventListener('pagehide', this.boundOnPageHide)\n }\n if (typeof process !== 'undefined' && this.boundOnBeforeExit) {\n process.on('beforeExit', this.boundOnBeforeExit)\n }\n }\n }\n\n /** Stop the scheduler — clears timers, removes event listeners. */\n stop(): void {\n if (!this.started) return\n this.started = false\n\n // A sequence cut mid-phase must not leave that collection 'pulling' —\n // a reader would show a skeleton that never resolves.\n for (const [collection, state] of this._readiness) {\n if (state === 'pulling') this._readiness.set(collection, 'cold')\n }\n this._phase = null\n\n if (this.debounceTimer) {\n clearTimeout(this.debounceTimer)\n this.debounceTimer = null\n }\n if (this.pushIntervalTimer) {\n clearInterval(this.pushIntervalTimer)\n this.pushIntervalTimer = null\n }\n if (this.pullIntervalTimer) {\n clearInterval(this.pullIntervalTimer)\n this.pullIntervalTimer = null\n }\n\n // Focus pull\n if (this.policy.pull.mode === 'on-focus' && typeof document !== 'undefined') {\n document.removeEventListener('visibilitychange', this.handleFocusPull)\n }\n\n // Unload hooks\n if (typeof document !== 'undefined' && this.boundOnVisibilityChange) {\n document.removeEventListener('visibilitychange', this.boundOnVisibilityChange)\n }\n if (typeof globalThis.removeEventListener === 'function' && this.boundOnPageHide) {\n globalThis.removeEventListener('pagehide', this.boundOnPageHide)\n }\n if (typeof process !== 'undefined' && this.boundOnBeforeExit) {\n process.removeListener('beforeExit', this.boundOnBeforeExit)\n }\n }\n\n /**\n * Notify the scheduler that a local write occurred.\n * For `on-change` mode: triggers immediate push (respecting minIntervalMs).\n * For `debounce` mode: resets the debounce timer.\n * For `manual` / `interval`: no-op.\n */\n notifyChange(): void {\n if (!this.started) return\n\n if (this.policy.push.mode === 'on-change') {\n void this.executePush()\n } else if (this.policy.push.mode === 'debounce') {\n this.resetDebounce()\n }\n }\n\n /** Force an immediate push, bypassing the scheduler. */\n async forcePush(): Promise<void> {\n await this.executePush()\n }\n\n /** Force an immediate pull, bypassing the scheduler. */\n async forcePull(): Promise<void> {\n await this.executePull()\n }\n\n // ─── Internal ─────────────────────────────────────────────────────\n\n /**\n * Arm the steady-state pull timer, if the policy specifies a cadence.\n * Shared by `'interval'` mode and by `'phased'` once its sequence drains.\n */\n private startPullInterval(): void {\n if (this.pullIntervalTimer || !this.policy.pull.intervalMs) return\n this.pullIntervalTimer = setInterval(() => {\n void this.executePull()\n }, this.policy.pull.intervalMs)\n }\n\n /**\n * Pull each collection in turn, then hand over to steady state.\n *\n * Strictly sequential — running phases concurrently would defeat the\n * prioritisation that is the entire point of a sequence. Each phase is an\n * ordinary scoped pull, so a phase that reports errors does not abort the\n * ones behind it; `executePull` records the failure and the walk continues.\n * `started` is re-checked between phases so `stop()` cuts a sequence short\n * instead of letting it run on against a closed vault.\n */\n private async runSequence(sequence: readonly string[]): Promise<void> {\n for (const [i, collection] of sequence.entries()) {\n if (!this.started) return\n this._readiness.set(collection, 'pulling')\n this._phase = { index: i + 1, total: sequence.length }\n\n const outcome = await this.executePull([collection])\n\n // 'live' only on a clean phase. Anything else — reported errors, a\n // role-gated skip, a throw — goes back to 'cold', because 'live' is a\n // promise that a miss from get() is a real absence.\n this._readiness.set(collection, outcome === 'complete' ? 'live' : 'cold')\n }\n this._phase = null\n if (this.started) this.startPullInterval()\n }\n\n private async executePush(): Promise<void> {\n if (this._state === 'pushing') return // already in progress\n\n // minIntervalMs enforcement\n const minInterval = this.policy.push.minIntervalMs ?? 0\n if (minInterval > 0) {\n const elapsed = Date.now() - this._lastPushTime\n if (elapsed < minInterval) {\n // Schedule for later if debounce mode\n if (this.policy.push.mode === 'debounce') {\n this.scheduleDebounce(minInterval - elapsed)\n }\n return\n }\n }\n\n // Nothing to push\n if (this.callbacks.getDirtyCount() === 0) {\n this._state = 'idle'\n return\n }\n\n this._state = 'pushing'\n try {\n await this.callbacks.push()\n this._lastPushAt = new Date().toISOString()\n this._lastPushTime = Date.now()\n this._lastError = null\n this._state = this.callbacks.getDirtyCount() > 0 ? 'pending' : 'idle'\n } catch (err) {\n this._lastError = err instanceof Error ? err : new Error(String(err))\n this._state = 'error'\n }\n }\n\n private async executePull(collections?: readonly string[]): Promise<PullPhaseOutcome> {\n if (this._state === 'pulling') return 'incomplete'\n\n const previousState = this._state\n this._state = 'pulling'\n try {\n const outcome = await this.callbacks.pull(collections)\n this._lastPullAt = new Date().toISOString()\n this._lastError = null\n this._state = previousState === 'pending' ? 'pending' : 'idle'\n return outcome ?? 'complete'\n } catch (err) {\n this._lastError = err instanceof Error ? err : new Error(String(err))\n this._state = 'error'\n return 'incomplete'\n }\n }\n\n private resetDebounce(): void {\n if (this.debounceTimer) clearTimeout(this.debounceTimer)\n const ms = this.policy.push.debounceMs ?? 30_000\n this._state = 'pending'\n this.scheduleDebounce(ms)\n }\n\n private scheduleDebounce(ms: number): void {\n if (this.debounceTimer) clearTimeout(this.debounceTimer)\n this.debounceTimer = setTimeout(() => {\n this.debounceTimer = null\n void this.executePush()\n }, ms)\n }\n\n private shouldRegisterUnload(): boolean {\n const onUnload = this.policy.push.onUnload\n if (onUnload !== undefined) return onUnload\n return this.policy.push.mode !== 'manual'\n }\n\n // ─── Event handlers ───────────────────────────────────────────────\n\n private handleVisibilityChange(): void {\n if (typeof document !== 'undefined' && document.visibilityState === 'hidden') {\n this.fireUnloadPush()\n }\n }\n\n private handlePageHide(): void {\n this.fireUnloadPush()\n }\n\n private handleBeforeExit(): void {\n this.fireUnloadPush()\n }\n\n private handleFocusPull = (): void => {\n if (typeof document !== 'undefined' && document.visibilityState === 'visible') {\n void this.executePull()\n }\n }\n\n private fireUnloadPush(): void {\n if (this.callbacks.getDirtyCount() === 0) return\n // Best-effort synchronous-ish push on unload\n void this.callbacks.push().catch(() => {})\n }\n}\n","/**\n * Strategy seam for the optional sync engine + presence service.\n * Core imports `SyncStrategy` type-only + `NO_SYNC` stub; the real\n * `SyncEngine`, `SyncTransaction`, and `PresenceHandle` constructors\n * are only reachable via `withSync()` in `./sync-active.ts`.\n *\n * Solo apps that never configure `sync` and never call\n * `collection.presence()` ship none of the ~856 LOC behind this seam\n * (`sync.ts` + `sync-transaction.ts` + `presence.ts`).\n *\n * Note: `keyring.ts` (~746 LOC) stays in core because it's required\n * for any multi-user vault — even single-owner vaults use a keyring\n * to wrap the DEK. The team package's grant/revoke/magic-link/\n * delegation modules tree-shake naturally via direct named imports.\n *\n * Behavior under NO_SYNC:\n *\n * - **buildSyncEngine** — throws. Only fires when `createNoydb({ sync })`\n * passes a remote target.\n * - **buildSyncTransaction** — throws. Only fires when `db.transaction(vault)`\n * is called on a vault with sync configured.\n * - **buildPresence** — throws. Only fires when user code calls\n * `collection.presence()`.\n *\n * @internal\n */\n\nimport type {\n NoydbStore,\n ConflictStrategy,\n SyncTargetRole,\n} from '../kernel/types.js'\nimport type { NoydbEventEmitter } from '../kernel/events.js'\nimport type { SyncPolicy } from '../kernel/sync-policy.js'\nimport type { SyncEngine } from './engine.js'\nimport type { SyncTransaction } from './transaction.js'\nimport type { PresenceHandle, PresenceHandleOpts } from './presence.js'\nimport type { Vault } from '../kernel/vault.js'\n\n/**\n * Options accepted by `SyncStrategy.buildSyncEngine`. Mirrors the\n * `SyncEngine` constructor verbatim — kept here so core code never\n * imports the sync module at runtime.\n *\n * @internal\n */\nexport interface BuildSyncEngineOptions {\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\n/**\n * @internal\n */\nexport interface SyncStrategy {\n buildSyncEngine(opts: BuildSyncEngineOptions): SyncEngine\n buildSyncTransaction(vault: Vault, engine: SyncEngine): SyncTransaction\n buildPresence<P>(opts: PresenceHandleOpts): PresenceHandle<P>\n}\n\nfunction notEnabled(op: string): Error {\n return new Error(\n `${op} requires the sync strategy. Import ` +\n '`{ withSync }` from \"@noy-db/hub/sync\" and pass it to ' +\n '`createNoydb({ syncStrategy: withSync() })`.',\n )\n}\n\n/**\n * No-sync stub. Every constructor throws with an actionable pointer\n * — there is no useful \"off\" mode for sync engine / presence /\n * sync-transaction; if the consumer reached one of these surfaces,\n * they intended to use it.\n *\n * @internal\n */\nexport const NO_SYNC: SyncStrategy = {\n buildSyncEngine() { throw notEnabled('SyncEngine') },\n buildSyncTransaction() { throw notEnabled('SyncTransaction') },\n buildPresence() { throw notEnabled('collection.presence()') },\n}\n"],"mappings":"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","names":[]}
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
} from "./chunk-ZJADGNYF.js";
|
|
4
4
|
import {
|
|
5
5
|
openEnvelopeJson
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-SU6SGWXM.js";
|
|
7
7
|
import {
|
|
8
8
|
encrypt
|
|
9
9
|
} from "./chunk-AKKRXT23.js";
|
|
@@ -72,4 +72,4 @@ export {
|
|
|
72
72
|
writeConsentEntry,
|
|
73
73
|
loadConsentEntries
|
|
74
74
|
};
|
|
75
|
-
//# sourceMappingURL=chunk-
|
|
75
|
+
//# sourceMappingURL=chunk-5UQ7Y6SQ.js.map
|