@optimystic/db-core 0.13.5 → 0.14.1
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/src/cluster/structs.d.ts +13 -0
- package/dist/src/cluster/structs.d.ts.map +1 -1
- package/dist/src/cohort-topic/addressing.d.ts +53 -0
- package/dist/src/cohort-topic/addressing.d.ts.map +1 -0
- package/dist/src/cohort-topic/addressing.js +95 -0
- package/dist/src/cohort-topic/addressing.js.map +1 -0
- package/dist/src/cohort-topic/antidos/bootstrap-evidence-envelope.d.ts +105 -0
- package/dist/src/cohort-topic/antidos/bootstrap-evidence-envelope.d.ts.map +1 -0
- package/dist/src/cohort-topic/antidos/bootstrap-evidence-envelope.js +197 -0
- package/dist/src/cohort-topic/antidos/bootstrap-evidence-envelope.js.map +1 -0
- package/dist/src/cohort-topic/antidos/bootstrap-evidence.d.ts +50 -0
- package/dist/src/cohort-topic/antidos/bootstrap-evidence.d.ts.map +1 -0
- package/dist/src/cohort-topic/antidos/bootstrap-evidence.js +62 -0
- package/dist/src/cohort-topic/antidos/bootstrap-evidence.js.map +1 -0
- package/dist/src/cohort-topic/antidos/index.d.ts +6 -0
- package/dist/src/cohort-topic/antidos/index.d.ts.map +1 -0
- package/dist/src/cohort-topic/antidos/index.js +6 -0
- package/dist/src/cohort-topic/antidos/index.js.map +1 -0
- package/dist/src/cohort-topic/antidos/rate-limiter.d.ts +95 -0
- package/dist/src/cohort-topic/antidos/rate-limiter.d.ts.map +1 -0
- package/dist/src/cohort-topic/antidos/rate-limiter.js +146 -0
- package/dist/src/cohort-topic/antidos/rate-limiter.js.map +1 -0
- package/dist/src/cohort-topic/antidos/replay-guard.d.ts +37 -0
- package/dist/src/cohort-topic/antidos/replay-guard.d.ts.map +1 -0
- package/dist/src/cohort-topic/antidos/replay-guard.js +78 -0
- package/dist/src/cohort-topic/antidos/replay-guard.js.map +1 -0
- package/dist/src/cohort-topic/antidos/topic-budget.d.ts +50 -0
- package/dist/src/cohort-topic/antidos/topic-budget.d.ts.map +1 -0
- package/dist/src/cohort-topic/antidos/topic-budget.js +95 -0
- package/dist/src/cohort-topic/antidos/topic-budget.js.map +1 -0
- package/dist/src/cohort-topic/antiflood/index.d.ts +3 -0
- package/dist/src/cohort-topic/antiflood/index.d.ts.map +1 -0
- package/dist/src/cohort-topic/antiflood/index.js +3 -0
- package/dist/src/cohort-topic/antiflood/index.js.map +1 -0
- package/dist/src/cohort-topic/antiflood/invariants.d.ts +70 -0
- package/dist/src/cohort-topic/antiflood/invariants.d.ts.map +1 -0
- package/dist/src/cohort-topic/antiflood/invariants.js +86 -0
- package/dist/src/cohort-topic/antiflood/invariants.js.map +1 -0
- package/dist/src/cohort-topic/antiflood/jitter.d.ts +65 -0
- package/dist/src/cohort-topic/antiflood/jitter.d.ts.map +1 -0
- package/dist/src/cohort-topic/antiflood/jitter.js +75 -0
- package/dist/src/cohort-topic/antiflood/jitter.js.map +1 -0
- package/dist/src/cohort-topic/coldstart.d.ts +117 -0
- package/dist/src/cohort-topic/coldstart.d.ts.map +1 -0
- package/dist/src/cohort-topic/coldstart.js +127 -0
- package/dist/src/cohort-topic/coldstart.js.map +1 -0
- package/dist/src/cohort-topic/dmax.d.ts +44 -0
- package/dist/src/cohort-topic/dmax.d.ts.map +1 -0
- package/dist/src/cohort-topic/dmax.js +70 -0
- package/dist/src/cohort-topic/dmax.js.map +1 -0
- package/dist/src/cohort-topic/gossip/bus.d.ts +85 -0
- package/dist/src/cohort-topic/gossip/bus.d.ts.map +1 -0
- package/dist/src/cohort-topic/gossip/bus.js +146 -0
- package/dist/src/cohort-topic/gossip/bus.js.map +1 -0
- package/dist/src/cohort-topic/gossip/index.d.ts +4 -0
- package/dist/src/cohort-topic/gossip/index.d.ts.map +1 -0
- package/dist/src/cohort-topic/gossip/index.js +4 -0
- package/dist/src/cohort-topic/gossip/index.js.map +1 -0
- package/dist/src/cohort-topic/gossip/records.d.ts +12 -0
- package/dist/src/cohort-topic/gossip/records.d.ts.map +1 -0
- package/dist/src/cohort-topic/gossip/records.js +41 -0
- package/dist/src/cohort-topic/gossip/records.js.map +1 -0
- package/dist/src/cohort-topic/gossip/view.d.ts +39 -0
- package/dist/src/cohort-topic/gossip/view.d.ts.map +1 -0
- package/dist/src/cohort-topic/gossip/view.js +30 -0
- package/dist/src/cohort-topic/gossip/view.js.map +1 -0
- package/dist/src/cohort-topic/index.d.ts +21 -0
- package/dist/src/cohort-topic/index.d.ts.map +1 -0
- package/dist/src/cohort-topic/index.js +21 -0
- package/dist/src/cohort-topic/index.js.map +1 -0
- package/dist/src/cohort-topic/load/barometer.d.ts +78 -0
- package/dist/src/cohort-topic/load/barometer.d.ts.map +1 -0
- package/dist/src/cohort-topic/load/barometer.js +93 -0
- package/dist/src/cohort-topic/load/barometer.js.map +1 -0
- package/dist/src/cohort-topic/load/index.d.ts +2 -0
- package/dist/src/cohort-topic/load/index.d.ts.map +1 -0
- package/dist/src/cohort-topic/load/index.js +2 -0
- package/dist/src/cohort-topic/load/index.js.map +1 -0
- package/dist/src/cohort-topic/member-engine.d.ts +134 -0
- package/dist/src/cohort-topic/member-engine.d.ts.map +1 -0
- package/dist/src/cohort-topic/member-engine.js +264 -0
- package/dist/src/cohort-topic/member-engine.js.map +1 -0
- package/dist/src/cohort-topic/membership/index.d.ts +4 -0
- package/dist/src/cohort-topic/membership/index.d.ts.map +1 -0
- package/dist/src/cohort-topic/membership/index.js +4 -0
- package/dist/src/cohort-topic/membership/index.js.map +1 -0
- package/dist/src/cohort-topic/membership/publisher.d.ts +82 -0
- package/dist/src/cohort-topic/membership/publisher.d.ts.map +1 -0
- package/dist/src/cohort-topic/membership/publisher.js +107 -0
- package/dist/src/cohort-topic/membership/publisher.js.map +1 -0
- package/dist/src/cohort-topic/membership/source.d.ts +31 -0
- package/dist/src/cohort-topic/membership/source.d.ts.map +1 -0
- package/dist/src/cohort-topic/membership/source.js +32 -0
- package/dist/src/cohort-topic/membership/source.js.map +1 -0
- package/dist/src/cohort-topic/membership/verifier.d.ts +96 -0
- package/dist/src/cohort-topic/membership/verifier.d.ts.map +1 -0
- package/dist/src/cohort-topic/membership/verifier.js +250 -0
- package/dist/src/cohort-topic/membership/verifier.js.map +1 -0
- package/dist/src/cohort-topic/ports.d.ts +149 -0
- package/dist/src/cohort-topic/ports.d.ts.map +1 -0
- package/dist/src/cohort-topic/ports.js +25 -0
- package/dist/src/cohort-topic/ports.js.map +1 -0
- package/dist/src/cohort-topic/promotion.d.ts +135 -0
- package/dist/src/cohort-topic/promotion.d.ts.map +1 -0
- package/dist/src/cohort-topic/promotion.js +269 -0
- package/dist/src/cohort-topic/promotion.js.map +1 -0
- package/dist/src/cohort-topic/registration/bytes.d.ts +16 -0
- package/dist/src/cohort-topic/registration/bytes.d.ts.map +1 -0
- package/dist/src/cohort-topic/registration/bytes.js +32 -0
- package/dist/src/cohort-topic/registration/bytes.js.map +1 -0
- package/dist/src/cohort-topic/registration/handoff.d.ts +69 -0
- package/dist/src/cohort-topic/registration/handoff.d.ts.map +1 -0
- package/dist/src/cohort-topic/registration/handoff.js +98 -0
- package/dist/src/cohort-topic/registration/handoff.js.map +1 -0
- package/dist/src/cohort-topic/registration/index.d.ts +7 -0
- package/dist/src/cohort-topic/registration/index.d.ts.map +1 -0
- package/dist/src/cohort-topic/registration/index.js +7 -0
- package/dist/src/cohort-topic/registration/index.js.map +1 -0
- package/dist/src/cohort-topic/registration/renewal.d.ts +115 -0
- package/dist/src/cohort-topic/registration/renewal.d.ts.map +1 -0
- package/dist/src/cohort-topic/registration/renewal.js +306 -0
- package/dist/src/cohort-topic/registration/renewal.js.map +1 -0
- package/dist/src/cohort-topic/registration/sharding.d.ts +31 -0
- package/dist/src/cohort-topic/registration/sharding.d.ts.map +1 -0
- package/dist/src/cohort-topic/registration/sharding.js +48 -0
- package/dist/src/cohort-topic/registration/sharding.js.map +1 -0
- package/dist/src/cohort-topic/registration/store.d.ts +13 -0
- package/dist/src/cohort-topic/registration/store.d.ts.map +1 -0
- package/dist/src/cohort-topic/registration/store.js +72 -0
- package/dist/src/cohort-topic/registration/store.js.map +1 -0
- package/dist/src/cohort-topic/registration/types.d.ts +71 -0
- package/dist/src/cohort-topic/registration/types.d.ts.map +1 -0
- package/dist/src/cohort-topic/registration/types.js +27 -0
- package/dist/src/cohort-topic/registration/types.js.map +1 -0
- package/dist/src/cohort-topic/ring-hash.d.ts +27 -0
- package/dist/src/cohort-topic/ring-hash.d.ts.map +1 -0
- package/dist/src/cohort-topic/ring-hash.js +45 -0
- package/dist/src/cohort-topic/ring-hash.js.map +1 -0
- package/dist/src/cohort-topic/service.d.ts +157 -0
- package/dist/src/cohort-topic/service.d.ts.map +1 -0
- package/dist/src/cohort-topic/service.js +237 -0
- package/dist/src/cohort-topic/service.js.map +1 -0
- package/dist/src/cohort-topic/sig/index.d.ts +3 -0
- package/dist/src/cohort-topic/sig/index.d.ts.map +1 -0
- package/dist/src/cohort-topic/sig/index.js +3 -0
- package/dist/src/cohort-topic/sig/index.js.map +1 -0
- package/dist/src/cohort-topic/sig/payloads.d.ts +25 -0
- package/dist/src/cohort-topic/sig/payloads.d.ts.map +1 -0
- package/dist/src/cohort-topic/sig/payloads.js +25 -0
- package/dist/src/cohort-topic/sig/payloads.js.map +1 -0
- package/dist/src/cohort-topic/sig/threshold.d.ts +33 -0
- package/dist/src/cohort-topic/sig/threshold.d.ts.map +1 -0
- package/dist/src/cohort-topic/sig/threshold.js +51 -0
- package/dist/src/cohort-topic/sig/threshold.js.map +1 -0
- package/dist/src/cohort-topic/tiers.d.ts +58 -0
- package/dist/src/cohort-topic/tiers.d.ts.map +1 -0
- package/dist/src/cohort-topic/tiers.js +49 -0
- package/dist/src/cohort-topic/tiers.js.map +1 -0
- package/dist/src/cohort-topic/traffic.d.ts +90 -0
- package/dist/src/cohort-topic/traffic.d.ts.map +1 -0
- package/dist/src/cohort-topic/traffic.js +146 -0
- package/dist/src/cohort-topic/traffic.js.map +1 -0
- package/dist/src/cohort-topic/walk.d.ts +123 -0
- package/dist/src/cohort-topic/walk.d.ts.map +1 -0
- package/dist/src/cohort-topic/walk.js +150 -0
- package/dist/src/cohort-topic/walk.js.map +1 -0
- package/dist/src/cohort-topic/willingness.d.ts +123 -0
- package/dist/src/cohort-topic/willingness.d.ts.map +1 -0
- package/dist/src/cohort-topic/willingness.js +143 -0
- package/dist/src/cohort-topic/willingness.js.map +1 -0
- package/dist/src/cohort-topic/wire/codec.d.ts +42 -0
- package/dist/src/cohort-topic/wire/codec.d.ts.map +1 -0
- package/dist/src/cohort-topic/wire/codec.js +163 -0
- package/dist/src/cohort-topic/wire/codec.js.map +1 -0
- package/dist/src/cohort-topic/wire/index.d.ts +6 -0
- package/dist/src/cohort-topic/wire/index.d.ts.map +1 -0
- package/dist/src/cohort-topic/wire/index.js +6 -0
- package/dist/src/cohort-topic/wire/index.js.map +1 -0
- package/dist/src/cohort-topic/wire/payloads.d.ts +38 -0
- package/dist/src/cohort-topic/wire/payloads.d.ts.map +1 -0
- package/dist/src/cohort-topic/wire/payloads.js +102 -0
- package/dist/src/cohort-topic/wire/payloads.js.map +1 -0
- package/dist/src/cohort-topic/wire/types.d.ts +304 -0
- package/dist/src/cohort-topic/wire/types.d.ts.map +1 -0
- package/dist/src/cohort-topic/wire/types.js +16 -0
- package/dist/src/cohort-topic/wire/types.js.map +1 -0
- package/dist/src/cohort-topic/wire/validate.d.ts +25 -0
- package/dist/src/cohort-topic/wire/validate.d.ts.map +1 -0
- package/dist/src/cohort-topic/wire/validate.js +427 -0
- package/dist/src/cohort-topic/wire/validate.js.map +1 -0
- package/dist/src/collection/collection.d.ts +58 -1
- package/dist/src/collection/collection.d.ts.map +1 -1
- package/dist/src/collection/collection.js +76 -0
- package/dist/src/collection/collection.js.map +1 -1
- package/dist/src/collections/tree/tree.d.ts +58 -2
- package/dist/src/collections/tree/tree.d.ts.map +1 -1
- package/dist/src/collections/tree/tree.js +59 -2
- package/dist/src/collections/tree/tree.js.map +1 -1
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +3 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/log/log.d.ts +42 -4
- package/dist/src/log/log.d.ts.map +1 -1
- package/dist/src/log/log.js +71 -3
- package/dist/src/log/log.js.map +1 -1
- package/dist/src/log/struct.d.ts +122 -2
- package/dist/src/log/struct.d.ts.map +1 -1
- package/dist/src/log/struct.js.map +1 -1
- package/dist/src/matchmaking/capability-filter.d.ts +24 -0
- package/dist/src/matchmaking/capability-filter.d.ts.map +1 -0
- package/dist/src/matchmaking/capability-filter.js +37 -0
- package/dist/src/matchmaking/capability-filter.js.map +1 -0
- package/dist/src/matchmaking/config.d.ts +77 -0
- package/dist/src/matchmaking/config.d.ts.map +1 -0
- package/dist/src/matchmaking/config.js +69 -0
- package/dist/src/matchmaking/config.js.map +1 -0
- package/dist/src/matchmaking/index.d.ts +21 -0
- package/dist/src/matchmaking/index.d.ts.map +1 -0
- package/dist/src/matchmaking/index.js +21 -0
- package/dist/src/matchmaking/index.js.map +1 -0
- package/dist/src/matchmaking/multi-cohort-seeker.d.ts +133 -0
- package/dist/src/matchmaking/multi-cohort-seeker.d.ts.map +1 -0
- package/dist/src/matchmaking/multi-cohort-seeker.js +142 -0
- package/dist/src/matchmaking/multi-cohort-seeker.js.map +1 -0
- package/dist/src/matchmaking/provider.d.ts +70 -0
- package/dist/src/matchmaking/provider.d.ts.map +1 -0
- package/dist/src/matchmaking/provider.js +93 -0
- package/dist/src/matchmaking/provider.js.map +1 -0
- package/dist/src/matchmaking/query-eval.d.ts +53 -0
- package/dist/src/matchmaking/query-eval.d.ts.map +1 -0
- package/dist/src/matchmaking/query-eval.js +69 -0
- package/dist/src/matchmaking/query-eval.js.map +1 -0
- package/dist/src/matchmaking/seeker-walk.d.ts +95 -0
- package/dist/src/matchmaking/seeker-walk.d.ts.map +1 -0
- package/dist/src/matchmaking/seeker-walk.js +75 -0
- package/dist/src/matchmaking/seeker-walk.js.map +1 -0
- package/dist/src/matchmaking/seeker.d.ts +51 -0
- package/dist/src/matchmaking/seeker.d.ts.map +1 -0
- package/dist/src/matchmaking/seeker.js +62 -0
- package/dist/src/matchmaking/seeker.js.map +1 -0
- package/dist/src/matchmaking/topic-anchor.d.ts +54 -0
- package/dist/src/matchmaking/topic-anchor.d.ts.map +1 -0
- package/dist/src/matchmaking/topic-anchor.js +67 -0
- package/dist/src/matchmaking/topic-anchor.js.map +1 -0
- package/dist/src/matchmaking/voting-quorum.d.ts +233 -0
- package/dist/src/matchmaking/voting-quorum.d.ts.map +1 -0
- package/dist/src/matchmaking/voting-quorum.js +238 -0
- package/dist/src/matchmaking/voting-quorum.js.map +1 -0
- package/dist/src/matchmaking/wire.d.ts +259 -0
- package/dist/src/matchmaking/wire.d.ts.map +1 -0
- package/dist/src/matchmaking/wire.js +484 -0
- package/dist/src/matchmaking/wire.js.map +1 -0
- package/dist/src/network/i-repo.d.ts +9 -0
- package/dist/src/network/i-repo.d.ts.map +1 -1
- package/dist/src/network/repo-protocol.d.ts +3 -1
- package/dist/src/network/repo-protocol.d.ts.map +1 -1
- package/dist/src/network/struct.d.ts +23 -1
- package/dist/src/network/struct.d.ts.map +1 -1
- package/dist/src/reactivity/backfill.d.ts +118 -0
- package/dist/src/reactivity/backfill.d.ts.map +1 -0
- package/dist/src/reactivity/backfill.js +137 -0
- package/dist/src/reactivity/backfill.js.map +1 -0
- package/dist/src/reactivity/backpressure.d.ts +99 -0
- package/dist/src/reactivity/backpressure.d.ts.map +1 -0
- package/dist/src/reactivity/backpressure.js +153 -0
- package/dist/src/reactivity/backpressure.js.map +1 -0
- package/dist/src/reactivity/checkpoint.d.ts +165 -0
- package/dist/src/reactivity/checkpoint.d.ts.map +1 -0
- package/dist/src/reactivity/checkpoint.js +232 -0
- package/dist/src/reactivity/checkpoint.js.map +1 -0
- package/dist/src/reactivity/config.d.ts +131 -0
- package/dist/src/reactivity/config.d.ts.map +1 -0
- package/dist/src/reactivity/config.js +135 -0
- package/dist/src/reactivity/config.js.map +1 -0
- package/dist/src/reactivity/dedupe.d.ts +51 -0
- package/dist/src/reactivity/dedupe.d.ts.map +1 -0
- package/dist/src/reactivity/dedupe.js +90 -0
- package/dist/src/reactivity/dedupe.js.map +1 -0
- package/dist/src/reactivity/forwarder.d.ts +50 -0
- package/dist/src/reactivity/forwarder.d.ts.map +1 -0
- package/dist/src/reactivity/forwarder.js +52 -0
- package/dist/src/reactivity/forwarder.js.map +1 -0
- package/dist/src/reactivity/index.d.ts +34 -0
- package/dist/src/reactivity/index.d.ts.map +1 -0
- package/dist/src/reactivity/index.js +34 -0
- package/dist/src/reactivity/index.js.map +1 -0
- package/dist/src/reactivity/notification.d.ts +72 -0
- package/dist/src/reactivity/notification.d.ts.map +1 -0
- package/dist/src/reactivity/notification.js +92 -0
- package/dist/src/reactivity/notification.js.map +1 -0
- package/dist/src/reactivity/policy.d.ts +59 -0
- package/dist/src/reactivity/policy.d.ts.map +1 -0
- package/dist/src/reactivity/policy.js +64 -0
- package/dist/src/reactivity/policy.js.map +1 -0
- package/dist/src/reactivity/push-state.d.ts +140 -0
- package/dist/src/reactivity/push-state.d.ts.map +1 -0
- package/dist/src/reactivity/push-state.js +270 -0
- package/dist/src/reactivity/push-state.js.map +1 -0
- package/dist/src/reactivity/recover.d.ts +75 -0
- package/dist/src/reactivity/recover.d.ts.map +1 -0
- package/dist/src/reactivity/recover.js +105 -0
- package/dist/src/reactivity/recover.js.map +1 -0
- package/dist/src/reactivity/replay-buffer.d.ts +57 -0
- package/dist/src/reactivity/replay-buffer.d.ts.map +1 -0
- package/dist/src/reactivity/replay-buffer.js +88 -0
- package/dist/src/reactivity/replay-buffer.js.map +1 -0
- package/dist/src/reactivity/resume.d.ts +214 -0
- package/dist/src/reactivity/resume.d.ts.map +1 -0
- package/dist/src/reactivity/resume.js +358 -0
- package/dist/src/reactivity/resume.js.map +1 -0
- package/dist/src/reactivity/rotation.d.ts +283 -0
- package/dist/src/reactivity/rotation.d.ts.map +1 -0
- package/dist/src/reactivity/rotation.js +265 -0
- package/dist/src/reactivity/rotation.js.map +1 -0
- package/dist/src/reactivity/subscriber.d.ts +66 -0
- package/dist/src/reactivity/subscriber.d.ts.map +1 -0
- package/dist/src/reactivity/subscriber.js +75 -0
- package/dist/src/reactivity/subscriber.js.map +1 -0
- package/dist/src/reactivity/subscription.d.ts +52 -0
- package/dist/src/reactivity/subscription.d.ts.map +1 -0
- package/dist/src/reactivity/subscription.js +28 -0
- package/dist/src/reactivity/subscription.js.map +1 -0
- package/dist/src/reactivity/topic-anchor.d.ts +46 -0
- package/dist/src/reactivity/topic-anchor.d.ts.map +1 -0
- package/dist/src/reactivity/topic-anchor.js +61 -0
- package/dist/src/reactivity/topic-anchor.js.map +1 -0
- package/dist/src/reactivity/verify.d.ts +41 -0
- package/dist/src/reactivity/verify.d.ts.map +1 -0
- package/dist/src/reactivity/verify.js +48 -0
- package/dist/src/reactivity/verify.js.map +1 -0
- package/dist/src/reactivity/wire-validate.d.ts +28 -0
- package/dist/src/reactivity/wire-validate.d.ts.map +1 -0
- package/dist/src/reactivity/wire-validate.js +79 -0
- package/dist/src/reactivity/wire-validate.js.map +1 -0
- package/dist/src/reactivity/wire.d.ts +102 -0
- package/dist/src/reactivity/wire.d.ts.map +1 -0
- package/dist/src/reactivity/wire.js +129 -0
- package/dist/src/reactivity/wire.js.map +1 -0
- package/dist/src/transaction/coordinator.d.ts +9 -5
- package/dist/src/transaction/coordinator.d.ts.map +1 -1
- package/dist/src/transaction/coordinator.js +48 -25
- package/dist/src/transaction/coordinator.js.map +1 -1
- package/dist/src/transactor/change-notifier.d.ts +74 -0
- package/dist/src/transactor/change-notifier.d.ts.map +1 -0
- package/dist/src/transactor/change-notifier.js +4 -0
- package/dist/src/transactor/change-notifier.js.map +1 -0
- package/dist/src/transactor/index.d.ts +1 -0
- package/dist/src/transactor/index.d.ts.map +1 -1
- package/dist/src/transactor/index.js +1 -0
- package/dist/src/transactor/index.js.map +1 -1
- package/dist/src/transactor/network-transactor.d.ts +34 -2
- package/dist/src/transactor/network-transactor.d.ts.map +1 -1
- package/dist/src/transactor/network-transactor.js +113 -13
- package/dist/src/transactor/network-transactor.js.map +1 -1
- package/package.json +2 -2
- package/src/cluster/structs.ts +13 -0
- package/src/cohort-topic/addressing.ts +112 -0
- package/src/cohort-topic/antidos/bootstrap-evidence-envelope.ts +253 -0
- package/src/cohort-topic/antidos/bootstrap-evidence.ts +94 -0
- package/src/cohort-topic/antidos/index.ts +5 -0
- package/src/cohort-topic/antidos/rate-limiter.ts +210 -0
- package/src/cohort-topic/antidos/replay-guard.ts +109 -0
- package/src/cohort-topic/antidos/topic-budget.ts +145 -0
- package/src/cohort-topic/antiflood/index.ts +2 -0
- package/src/cohort-topic/antiflood/invariants.ts +108 -0
- package/src/cohort-topic/antiflood/jitter.ts +117 -0
- package/src/cohort-topic/coldstart.ts +204 -0
- package/src/cohort-topic/dmax.ts +88 -0
- package/src/cohort-topic/gossip/bus.ts +217 -0
- package/src/cohort-topic/gossip/index.ts +3 -0
- package/src/cohort-topic/gossip/records.ts +45 -0
- package/src/cohort-topic/gossip/view.ts +66 -0
- package/src/cohort-topic/index.ts +20 -0
- package/src/cohort-topic/load/barometer.ts +134 -0
- package/src/cohort-topic/load/index.ts +1 -0
- package/src/cohort-topic/member-engine.ts +409 -0
- package/src/cohort-topic/membership/index.ts +3 -0
- package/src/cohort-topic/membership/publisher.ts +171 -0
- package/src/cohort-topic/membership/source.ts +41 -0
- package/src/cohort-topic/membership/verifier.ts +345 -0
- package/src/cohort-topic/ports.ts +157 -0
- package/src/cohort-topic/promotion.ts +384 -0
- package/src/cohort-topic/registration/bytes.ts +37 -0
- package/src/cohort-topic/registration/handoff.ts +154 -0
- package/src/cohort-topic/registration/index.ts +6 -0
- package/src/cohort-topic/registration/renewal.ts +423 -0
- package/src/cohort-topic/registration/sharding.ts +61 -0
- package/src/cohort-topic/registration/store.ts +81 -0
- package/src/cohort-topic/registration/types.ts +76 -0
- package/src/cohort-topic/ring-hash.ts +50 -0
- package/src/cohort-topic/service.ts +390 -0
- package/src/cohort-topic/sig/index.ts +2 -0
- package/src/cohort-topic/sig/payloads.ts +39 -0
- package/src/cohort-topic/sig/threshold.ts +64 -0
- package/src/cohort-topic/tiers.ts +74 -0
- package/src/cohort-topic/traffic.ts +211 -0
- package/src/cohort-topic/walk.ts +255 -0
- package/src/cohort-topic/willingness.ts +237 -0
- package/src/cohort-topic/wire/codec.ts +204 -0
- package/src/cohort-topic/wire/index.ts +16 -0
- package/src/cohort-topic/wire/payloads.ts +117 -0
- package/src/cohort-topic/wire/types.ts +343 -0
- package/src/cohort-topic/wire/validate.ts +478 -0
- package/src/collection/collection.ts +93 -1
- package/src/collections/tree/tree.ts +84 -3
- package/src/index.ts +3 -0
- package/src/log/log.ts +86 -7
- package/src/log/struct.ts +126 -2
- package/src/matchmaking/capability-filter.ts +45 -0
- package/src/matchmaking/config.ts +98 -0
- package/src/matchmaking/index.ts +21 -0
- package/src/matchmaking/multi-cohort-seeker.ts +234 -0
- package/src/matchmaking/provider.ts +123 -0
- package/src/matchmaking/query-eval.ts +105 -0
- package/src/matchmaking/seeker-walk.ts +127 -0
- package/src/matchmaking/seeker.ts +86 -0
- package/src/matchmaking/topic-anchor.ts +90 -0
- package/src/matchmaking/voting-quorum.ts +394 -0
- package/src/matchmaking/wire.ts +680 -0
- package/src/network/i-repo.ts +9 -0
- package/src/network/repo-protocol.ts +3 -2
- package/src/network/struct.ts +24 -1
- package/src/reactivity/backfill.ts +220 -0
- package/src/reactivity/backpressure.ts +191 -0
- package/src/reactivity/checkpoint.ts +308 -0
- package/src/reactivity/config.ts +172 -0
- package/src/reactivity/dedupe.ts +132 -0
- package/src/reactivity/forwarder.ts +87 -0
- package/src/reactivity/index.ts +34 -0
- package/src/reactivity/notification.ts +123 -0
- package/src/reactivity/policy.ts +79 -0
- package/src/reactivity/push-state.ts +343 -0
- package/src/reactivity/recover.ts +153 -0
- package/src/reactivity/replay-buffer.ts +141 -0
- package/src/reactivity/resume.ts +549 -0
- package/src/reactivity/rotation.ts +415 -0
- package/src/reactivity/subscriber.ts +132 -0
- package/src/reactivity/subscription.ts +66 -0
- package/src/reactivity/topic-anchor.ts +71 -0
- package/src/reactivity/verify.ts +73 -0
- package/src/reactivity/wire-validate.ts +87 -0
- package/src/reactivity/wire.ts +224 -0
- package/src/transaction/coordinator.ts +53 -27
- package/src/transactor/change-notifier.ts +80 -0
- package/src/transactor/index.ts +1 -0
- package/src/transactor/network-transactor.ts +133 -15
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reactivity — configuration defaults (single source for the hot path).
|
|
3
|
+
*
|
|
4
|
+
* Transcribed from `docs/reactivity.md` §Configuration. Every tunable the reactivity hot path reads
|
|
5
|
+
* is sourced from {@link DEFAULT_REACTIVITY_CONFIG} — never hard-coded at a call site — so the
|
|
6
|
+
* simulator fold-back ([fold-simulator-findings-into-design-docs]) can retune `W` / `dedupe_window`
|
|
7
|
+
* without touching origination, forwarding, the replay buffer, or delivery.
|
|
8
|
+
*
|
|
9
|
+
* **Simulator-validated-pending.** `W` (replay buffer depth), `dedupe_window`, `T_drain`, `queue_max`,
|
|
10
|
+
* and `block_fill_size` are *provisional* pending the design simulator ([simulator-reactivity-replay],
|
|
11
|
+
* folded back by [fold-simulator-findings-into-design-docs]). The simulator's REVISED guidance is that `W`
|
|
12
|
+
* SHOULD become adaptive per measured commit-rate on hot collections (`W ≈ ⌈min_coverage × cps⌉`); the
|
|
13
|
+
* static `W = 256` is kept as the Edge/low-rate default. {@link resolveW} exposes that hook; the
|
|
14
|
+
* simulator's tail-rotation scenario also confirms the re-registration burst stays inside
|
|
15
|
+
* `cap_promote_fast` within `T_drain`, and flags whether `queue_max` should scale with cohort size/tier
|
|
16
|
+
* ({@link resolveQueueMax} is the parallel hook for that fold-back). Sourcing every tunable from this
|
|
17
|
+
* single table is what lets the fold-back revise the values without touching the protocol code.
|
|
18
|
+
*
|
|
19
|
+
* Ownership: `W` / `dedupe_window` ← [reactivity-origination-replay-delivery]; `W_checkpoint` ←
|
|
20
|
+
* [reactivity-backfill-resume-checkpoints]; `queue_max` / `delta_max` / `T_drain` / `warm_threshold` /
|
|
21
|
+
* `block_fill_size` ← [reactivity-rotation-backpressure-policy] (this ticket). `T_rejoin_jitter`, TTL, and
|
|
22
|
+
* ping are inherited from the cohort-topic defaults.
|
|
23
|
+
*/
|
|
24
|
+
import { DEFAULT_T_REJOIN_JITTER_MS } from "../cohort-topic/antiflood/jitter.js";
|
|
25
|
+
/** Replay buffer depth (revisions per cohort, per collection). Simulator-validated-pending. */
|
|
26
|
+
export const W_DEFAULT = 256;
|
|
27
|
+
/** Sliding dedupe-window size (revisions). Simulator-validated-pending. */
|
|
28
|
+
export const DEDUPE_WINDOW_DEFAULT = 64;
|
|
29
|
+
/** Parent-checkpoint span (revisions). Owned by the backfill/resume ticket; default carried here. */
|
|
30
|
+
export const W_CHECKPOINT_DEFAULT = 4096;
|
|
31
|
+
/** Per-subscriber bounded queue depth at a forwarder. Simulator-validated-pending (may scale with cohort/tier). */
|
|
32
|
+
export const QUEUE_MAX_DEFAULT = 32;
|
|
33
|
+
/** Max delta payload size on a Core node (bytes). */
|
|
34
|
+
export const DELTA_MAX_CORE_BYTES = 4096;
|
|
35
|
+
/** Max delta payload size on an Edge node (bytes) — Edge declines deltas (`0` ⇒ omit `delta`). */
|
|
36
|
+
export const DELTA_MAX_EDGE_BYTES = 0;
|
|
37
|
+
/** Subscriber registration TTL on a Core node (ms), inherited from cohort-topic. */
|
|
38
|
+
export const SUBSCRIBER_TTL_CORE_MS = 90_000;
|
|
39
|
+
/** Subscriber registration TTL on an Edge node (ms), inherited from cohort-topic. */
|
|
40
|
+
export const SUBSCRIBER_TTL_EDGE_MS = 60_000;
|
|
41
|
+
/** Transactions per block — drives tail rotation. Simulator-validated-pending. */
|
|
42
|
+
export const BLOCK_FILL_SIZE_DEFAULT = 64;
|
|
43
|
+
/** Old-tail drain time after rotation (ms). Simulator-validated-pending. */
|
|
44
|
+
export const T_DRAIN_MS = 60_000;
|
|
45
|
+
/** Transactions remaining in tail before anticipatory warm-up. Owned by the rotation ticket. */
|
|
46
|
+
export const WARM_THRESHOLD_DEFAULT = 8;
|
|
47
|
+
/** Subscriber re-registration jitter span after a rotation hint (ms). Inherited from cohort-topic `T_rejoin_jitter`. */
|
|
48
|
+
export const T_REJOIN_JITTER_MS = DEFAULT_T_REJOIN_JITTER_MS;
|
|
49
|
+
/** The default reactivity config (`docs/reactivity.md` §Configuration). */
|
|
50
|
+
export const DEFAULT_REACTIVITY_CONFIG = {
|
|
51
|
+
w: W_DEFAULT,
|
|
52
|
+
dedupeWindow: DEDUPE_WINDOW_DEFAULT,
|
|
53
|
+
wCheckpoint: W_CHECKPOINT_DEFAULT,
|
|
54
|
+
queueMax: QUEUE_MAX_DEFAULT,
|
|
55
|
+
deltaMaxCoreBytes: DELTA_MAX_CORE_BYTES,
|
|
56
|
+
deltaMaxEdgeBytes: DELTA_MAX_EDGE_BYTES,
|
|
57
|
+
subscriberTtlCoreMs: SUBSCRIBER_TTL_CORE_MS,
|
|
58
|
+
subscriberTtlEdgeMs: SUBSCRIBER_TTL_EDGE_MS,
|
|
59
|
+
blockFillSize: BLOCK_FILL_SIZE_DEFAULT,
|
|
60
|
+
tDrainMs: T_DRAIN_MS,
|
|
61
|
+
warmThreshold: WARM_THRESHOLD_DEFAULT,
|
|
62
|
+
tRejoinJitterMs: T_REJOIN_JITTER_MS,
|
|
63
|
+
};
|
|
64
|
+
/** `delta_max` for a node profile: Core admits deltas up to `delta_max`, Edge declines them (`0`). */
|
|
65
|
+
export function deltaMaxForProfile(profile, config = DEFAULT_REACTIVITY_CONFIG) {
|
|
66
|
+
return profile.kind === "edge" ? config.deltaMaxEdgeBytes : config.deltaMaxCoreBytes;
|
|
67
|
+
}
|
|
68
|
+
/** Subscriber TTL for a node profile (`docs/reactivity.md` §Subscription): Core 90 s / Edge 60 s. */
|
|
69
|
+
export function subscriberTtlForProfile(profile, config = DEFAULT_REACTIVITY_CONFIG) {
|
|
70
|
+
return profile.kind === "edge" ? config.subscriberTtlEdgeMs : config.subscriberTtlCoreMs;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Resolve the replay-buffer depth `W` for a collection.
|
|
74
|
+
*
|
|
75
|
+
* Static default (no `cps`): returns the configured `config.w` unchanged — the simulator-confirmed
|
|
76
|
+
* Edge/low-rate default. Adaptive (a measured `cps` and `minCoverageSeconds`): returns
|
|
77
|
+
* `⌈minCoverageSeconds × cps⌉` clamped to `[config.w, maxW]`, the simulator's REVISED guidance for hot
|
|
78
|
+
* collections. This is the single hook the backfill/resume ticket extends; the hot path here only ever
|
|
79
|
+
* calls the static form, so behavior is unchanged until a `cps` is wired through.
|
|
80
|
+
*/
|
|
81
|
+
export function resolveW(opts = {}) {
|
|
82
|
+
const config = opts.config ?? DEFAULT_REACTIVITY_CONFIG;
|
|
83
|
+
if (opts.cps === undefined || opts.minCoverageSeconds === undefined) {
|
|
84
|
+
return config.w;
|
|
85
|
+
}
|
|
86
|
+
if (!Number.isFinite(opts.cps) || opts.cps <= 0 || !Number.isFinite(opts.minCoverageSeconds) || opts.minCoverageSeconds <= 0) {
|
|
87
|
+
return config.w;
|
|
88
|
+
}
|
|
89
|
+
const adaptive = Math.ceil(opts.minCoverageSeconds * opts.cps);
|
|
90
|
+
const maxW = opts.maxW ?? Number.POSITIVE_INFINITY;
|
|
91
|
+
return Math.min(Math.max(config.w, adaptive), maxW);
|
|
92
|
+
}
|
|
93
|
+
/** Default `W_checkpoint`-to-`W` ratio (`docs/reactivity.md` §Parent checkpoint summaries: 16×). */
|
|
94
|
+
export const W_CHECKPOINT_RATIO = 16;
|
|
95
|
+
/**
|
|
96
|
+
* Resolve the parent-checkpoint span `W_checkpoint` for a collection.
|
|
97
|
+
*
|
|
98
|
+
* Static default (no `cps`): the configured `config.wCheckpoint` (4096). Adaptive: `W_checkpoint`
|
|
99
|
+
* "scales the same way and may stay a fixed 16× multiple of the resolved `W`" (`docs/reactivity.md`
|
|
100
|
+
* §Configuration), so when a `cps` is supplied it tracks `W_CHECKPOINT_RATIO × resolveW(opts)`. This is
|
|
101
|
+
* the single hook the simulator fold-back ([fold-simulator-findings-into-design-docs]) retunes; the
|
|
102
|
+
* resume classifier reads it so a hot collection's stacked recovery range scales with the replay depth.
|
|
103
|
+
*/
|
|
104
|
+
export function resolveWCheckpoint(opts = {}) {
|
|
105
|
+
const config = opts.config ?? DEFAULT_REACTIVITY_CONFIG;
|
|
106
|
+
if (opts.cps === undefined || opts.minCoverageSeconds === undefined) {
|
|
107
|
+
return config.wCheckpoint;
|
|
108
|
+
}
|
|
109
|
+
const ratio = opts.ratio ?? W_CHECKPOINT_RATIO;
|
|
110
|
+
return resolveW(opts) * ratio;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Resolve the per-subscriber bounded-queue depth `queue_max` for a cohort.
|
|
114
|
+
*
|
|
115
|
+
* Static default (no scaling input): the configured `config.queueMax` (32). The simulator flags whether
|
|
116
|
+
* `queue_max` should scale with cohort size / tier on hot collections; this is the single hook the
|
|
117
|
+
* fold-back ([fold-simulator-findings-into-design-docs]) retunes. When a `cohortSubscribers` count is
|
|
118
|
+
* supplied, the depth scales as `⌈queue_max × subscribers / scaleBaseline⌉` clamped to `[queueMax, maxQueue]`
|
|
119
|
+
* — never below the static default, optionally capped at a per-cohort memory budget. With no scaling input
|
|
120
|
+
* the hot path is unchanged (constant `queue_max`).
|
|
121
|
+
*/
|
|
122
|
+
export function resolveQueueMax(opts = {}) {
|
|
123
|
+
const config = opts.config ?? DEFAULT_REACTIVITY_CONFIG;
|
|
124
|
+
if (opts.cohortSubscribers === undefined) {
|
|
125
|
+
return config.queueMax;
|
|
126
|
+
}
|
|
127
|
+
const baseline = opts.scaleBaseline ?? 1;
|
|
128
|
+
if (!Number.isFinite(opts.cohortSubscribers) || opts.cohortSubscribers <= 0 || !(baseline > 0)) {
|
|
129
|
+
return config.queueMax;
|
|
130
|
+
}
|
|
131
|
+
const scaled = Math.ceil((config.queueMax * opts.cohortSubscribers) / baseline);
|
|
132
|
+
const maxQueue = opts.maxQueue ?? Number.POSITIVE_INFINITY;
|
|
133
|
+
return Math.min(Math.max(config.queueMax, scaled), maxQueue);
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/reactivity/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reactivity — per-revision dedupe (sliding-window set), `docs/reactivity.md` §Per-revision dedupe.
|
|
3
|
+
*
|
|
4
|
+
* A scalar `lastRevision` is insufficient under partition healing: the same revision may legitimately
|
|
5
|
+
* arrive from multiple parents during a merge, and dropping all but the first on `revision > lastRevision`
|
|
6
|
+
* would discard honest retransmits exactly when a subscriber needs them. Instead each forwarder keeps a
|
|
7
|
+
* sliding set of `(revision, sigDigest)` pairs for the last `dedupe_window` revisions (default 64).
|
|
8
|
+
*
|
|
9
|
+
* A notification is forwarded if:
|
|
10
|
+
* - it is for the *highest revision* seen in the window (normal case), OR
|
|
11
|
+
* - it is for an earlier revision, its `(revision, sigDigest)` is not already in the set, and it passes
|
|
12
|
+
* verification (recovery: a retransmit closing a gap).
|
|
13
|
+
*
|
|
14
|
+
* Both reduce to: **forward iff the `(revision, sigDigest)` key is not already present** (verification is
|
|
15
|
+
* the forwarder's prior step, applied to every inbound). Keys already in the set are dropped silently.
|
|
16
|
+
* The set is gossiped within the cohort ({@link DedupeWindow.serialize} / {@link DedupeWindow.merge}) so
|
|
17
|
+
* all members agree on what has been seen.
|
|
18
|
+
*/
|
|
19
|
+
/** The dedupe decision for one inbound notification. */
|
|
20
|
+
export type DedupeOutcome = "forward" | "duplicate";
|
|
21
|
+
/** Serializable dedupe state for intra-cohort gossip convergence. */
|
|
22
|
+
export interface DedupeStateV1 {
|
|
23
|
+
/** Highest revision observed (anchors the sliding window's high edge). */
|
|
24
|
+
readonly highestRevision: number;
|
|
25
|
+
/** Seen `(revision, sigDigest)` keys with their revision, for window-bounded merge. */
|
|
26
|
+
readonly entries: ReadonlyArray<{
|
|
27
|
+
readonly key: string;
|
|
28
|
+
readonly revision: number;
|
|
29
|
+
}>;
|
|
30
|
+
}
|
|
31
|
+
/** A sliding-window dedupe set over `(revision, sigDigest)` pairs. */
|
|
32
|
+
export interface DedupeWindow {
|
|
33
|
+
/** Highest revision observed so far (`-1` before any observation). */
|
|
34
|
+
readonly highestRevision: number;
|
|
35
|
+
/** Number of retained keys. */
|
|
36
|
+
readonly size: number;
|
|
37
|
+
/** True iff `(revision, sigDigest)` is already in the set. */
|
|
38
|
+
has(revision: number, sigDigest: string): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Record `(revision, sigDigest)` and report whether it should be forwarded. Returns `"duplicate"`
|
|
41
|
+
* (no state change) if already seen, else records it, advances the window, and returns `"forward"`.
|
|
42
|
+
*/
|
|
43
|
+
observe(revision: number, sigDigest: string): DedupeOutcome;
|
|
44
|
+
/** Snapshot for gossip. */
|
|
45
|
+
serialize(): DedupeStateV1;
|
|
46
|
+
/** Union another member's gossiped state into this one (idempotent, commutative within the window). */
|
|
47
|
+
merge(state: DedupeStateV1): void;
|
|
48
|
+
}
|
|
49
|
+
/** Build a {@link DedupeWindow} with the configured (default {@link DEDUPE_WINDOW_DEFAULT}) span. */
|
|
50
|
+
export declare function createDedupeWindow(windowSize?: number): DedupeWindow;
|
|
51
|
+
//# sourceMappingURL=dedupe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dedupe.d.ts","sourceRoot":"","sources":["../../../src/reactivity/dedupe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,wDAAwD;AACxD,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,WAAW,CAAC;AAEpD,qEAAqE;AACrE,MAAM,WAAW,aAAa;IAC7B,0EAA0E;IAC1E,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,uFAAuF;IACvF,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;QAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACrF;AAED,sEAAsE;AACtE,MAAM,WAAW,YAAY;IAC5B,sEAAsE;IACtE,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,+BAA+B;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,8DAA8D;IAC9D,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;IAClD;;;OAGG;IACH,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,aAAa,CAAC;IAC5D,2BAA2B;IAC3B,SAAS,IAAI,aAAa,CAAC;IAC3B,uGAAuG;IACvG,KAAK,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CAAC;CAClC;AA+ED,qGAAqG;AACrG,wBAAgB,kBAAkB,CAAC,UAAU,GAAE,MAA8B,GAAG,YAAY,CAE3F"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reactivity — per-revision dedupe (sliding-window set), `docs/reactivity.md` §Per-revision dedupe.
|
|
3
|
+
*
|
|
4
|
+
* A scalar `lastRevision` is insufficient under partition healing: the same revision may legitimately
|
|
5
|
+
* arrive from multiple parents during a merge, and dropping all but the first on `revision > lastRevision`
|
|
6
|
+
* would discard honest retransmits exactly when a subscriber needs them. Instead each forwarder keeps a
|
|
7
|
+
* sliding set of `(revision, sigDigest)` pairs for the last `dedupe_window` revisions (default 64).
|
|
8
|
+
*
|
|
9
|
+
* A notification is forwarded if:
|
|
10
|
+
* - it is for the *highest revision* seen in the window (normal case), OR
|
|
11
|
+
* - it is for an earlier revision, its `(revision, sigDigest)` is not already in the set, and it passes
|
|
12
|
+
* verification (recovery: a retransmit closing a gap).
|
|
13
|
+
*
|
|
14
|
+
* Both reduce to: **forward iff the `(revision, sigDigest)` key is not already present** (verification is
|
|
15
|
+
* the forwarder's prior step, applied to every inbound). Keys already in the set are dropped silently.
|
|
16
|
+
* The set is gossiped within the cohort ({@link DedupeWindow.serialize} / {@link DedupeWindow.merge}) so
|
|
17
|
+
* all members agree on what has been seen.
|
|
18
|
+
*/
|
|
19
|
+
import { DEDUPE_WINDOW_DEFAULT } from "./config.js";
|
|
20
|
+
class SlidingDedupeWindow {
|
|
21
|
+
windowSize;
|
|
22
|
+
/** key → revision, for window-bounded eviction. */
|
|
23
|
+
seen = new Map();
|
|
24
|
+
highest = -1;
|
|
25
|
+
constructor(windowSize) {
|
|
26
|
+
if (!Number.isInteger(windowSize) || windowSize < 1) {
|
|
27
|
+
throw new RangeError(`reactivity dedupe: windowSize must be an integer >= 1, got ${windowSize}`);
|
|
28
|
+
}
|
|
29
|
+
this.windowSize = windowSize;
|
|
30
|
+
}
|
|
31
|
+
get highestRevision() {
|
|
32
|
+
return this.highest;
|
|
33
|
+
}
|
|
34
|
+
get size() {
|
|
35
|
+
return this.seen.size;
|
|
36
|
+
}
|
|
37
|
+
has(revision, sigDigest) {
|
|
38
|
+
return this.seen.has(keyOf(revision, sigDigest));
|
|
39
|
+
}
|
|
40
|
+
observe(revision, sigDigest) {
|
|
41
|
+
const key = keyOf(revision, sigDigest);
|
|
42
|
+
if (this.seen.has(key)) {
|
|
43
|
+
return "duplicate";
|
|
44
|
+
}
|
|
45
|
+
this.insert(key, revision);
|
|
46
|
+
return "forward";
|
|
47
|
+
}
|
|
48
|
+
serialize() {
|
|
49
|
+
return {
|
|
50
|
+
highestRevision: this.highest,
|
|
51
|
+
entries: [...this.seen].map(([key, rev]) => ({ key, revision: rev })),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
merge(state) {
|
|
55
|
+
if (state.highestRevision > this.highest) {
|
|
56
|
+
this.highest = state.highestRevision;
|
|
57
|
+
}
|
|
58
|
+
for (const { key, revision } of state.entries) {
|
|
59
|
+
if (!this.seen.has(key)) {
|
|
60
|
+
this.seen.set(key, revision);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
this.evictBelowWindow();
|
|
64
|
+
}
|
|
65
|
+
insert(key, revision) {
|
|
66
|
+
if (revision > this.highest) {
|
|
67
|
+
this.highest = revision;
|
|
68
|
+
}
|
|
69
|
+
this.seen.set(key, revision);
|
|
70
|
+
this.evictBelowWindow();
|
|
71
|
+
}
|
|
72
|
+
/** Retain only revisions within `[highest - windowSize + 1, highest]`. */
|
|
73
|
+
evictBelowWindow() {
|
|
74
|
+
const low = this.highest - this.windowSize + 1;
|
|
75
|
+
for (const [key, revision] of this.seen) {
|
|
76
|
+
if (revision < low) {
|
|
77
|
+
this.seen.delete(key);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/** `${revision}:${sigDigest}` — the dedupe-set key. */
|
|
83
|
+
function keyOf(revision, sigDigest) {
|
|
84
|
+
return `${revision}:${sigDigest}`;
|
|
85
|
+
}
|
|
86
|
+
/** Build a {@link DedupeWindow} with the configured (default {@link DEDUPE_WINDOW_DEFAULT}) span. */
|
|
87
|
+
export function createDedupeWindow(windowSize = DEDUPE_WINDOW_DEFAULT) {
|
|
88
|
+
return new SlidingDedupeWindow(windowSize);
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=dedupe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dedupe.js","sourceRoot":"","sources":["../../../src/reactivity/dedupe.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reactivity — forwarder receive path (`docs/reactivity.md` §Propagation).
|
|
3
|
+
*
|
|
4
|
+
* A receiving forwarder primary, for each inbound notification:
|
|
5
|
+
* 1. **verifies** the threshold signature against the tail cohort's `MembershipCertV1`;
|
|
6
|
+
* 2. runs the **dedupe** check (sliding `(revision, sigDigest)` window);
|
|
7
|
+
* 3. **appends** to the replay buffer;
|
|
8
|
+
* 4. **forwards the unmodified notification** to its own direct subscribers and child cohorts.
|
|
9
|
+
*
|
|
10
|
+
* This module owns steps 1–3 and the forward *decision* (step 4's transport — dialing each subscriber's
|
|
11
|
+
* primary and each child cohort — is the db-p2p binding). Forwarders never re-sign: a compromised
|
|
12
|
+
* forwarder can drop or delay, but cannot forge. An unverifiable notification is dropped **before**
|
|
13
|
+
* touching the dedupe set or buffer, so a forged payload can neither poison dedupe nor occupy a ring
|
|
14
|
+
* slot. The buffer + dedupe set are gossiped across the cohort by the host's gossip cadence (see
|
|
15
|
+
* {@link PushState}), so any member can serve a replay.
|
|
16
|
+
*/
|
|
17
|
+
import type { PushState } from "./push-state.js";
|
|
18
|
+
import type { NotificationV1 } from "./wire.js";
|
|
19
|
+
import type { NotificationVerifier } from "./verify.js";
|
|
20
|
+
import type { IRingHash } from "../cohort-topic/ports.js";
|
|
21
|
+
/** The forwarder's decision for one inbound notification. */
|
|
22
|
+
export type ForwardDecision =
|
|
23
|
+
/** Verified, fresh: append to buffer and fan out unmodified. */
|
|
24
|
+
"forward"
|
|
25
|
+
/** Already in the dedupe set: drop silently (an honest retransmit or merge duplicate). */
|
|
26
|
+
| "duplicate"
|
|
27
|
+
/** Signature did not verify against the tail cohort: drop without buffering. */
|
|
28
|
+
| "untrusted";
|
|
29
|
+
/** Drives the forwarder receive path over one collection's {@link PushState}. */
|
|
30
|
+
export interface ReactivityForwarder {
|
|
31
|
+
/** The per-collection push state this forwarder serves. */
|
|
32
|
+
readonly state: PushState;
|
|
33
|
+
/**
|
|
34
|
+
* Run verify → dedupe → append for one inbound notification, returning the forward decision. The
|
|
35
|
+
* caller fans the *unmodified* notification out only on `"forward"`.
|
|
36
|
+
*/
|
|
37
|
+
receive(n: NotificationV1, now: number): Promise<ForwardDecision>;
|
|
38
|
+
}
|
|
39
|
+
/** Construction inputs for a {@link ReactivityForwarder}. */
|
|
40
|
+
export interface ReactivityForwarderDeps {
|
|
41
|
+
readonly state: PushState;
|
|
42
|
+
readonly verifier: NotificationVerifier;
|
|
43
|
+
/** Ring hash for the `sigDigest` dedupe key (must match the verifier's). Default db-core SHA-256. */
|
|
44
|
+
readonly hash?: IRingHash;
|
|
45
|
+
}
|
|
46
|
+
/** Build a {@link ReactivityForwarder} over a collection's {@link PushState} and a verifier. */
|
|
47
|
+
export declare function createReactivityForwarder(deps: ReactivityForwarderDeps): ReactivityForwarder;
|
|
48
|
+
/** The dedupe key a forwarder would compute for a notification (exposed for tests/diagnostics). */
|
|
49
|
+
export declare function notificationDedupeKey(n: NotificationV1, hash?: IRingHash): string;
|
|
50
|
+
//# sourceMappingURL=forwarder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"forwarder.d.ts","sourceRoot":"","sources":["../../../src/reactivity/forwarder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAE1D,6DAA6D;AAC7D,MAAM,MAAM,eAAe;AAC1B,gEAAgE;AAC9D,SAAS;AACX,0FAA0F;GACxF,WAAW;AACb,gFAAgF;GAC9E,WAAW,CAAC;AAEf,iFAAiF;AACjF,MAAM,WAAW,mBAAmB;IACnC,2DAA2D;IAC3D,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B;;;OAGG;IACH,OAAO,CAAC,CAAC,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;CAClE;AAED,6DAA6D;AAC7D,MAAM,WAAW,uBAAuB;IACvC,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,oBAAoB,CAAC;IACxC,qGAAqG;IACrG,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC;CAC1B;AA6BD,gGAAgG;AAChG,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,uBAAuB,GAAG,mBAAmB,CAE5F;AAED,mGAAmG;AACnG,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,cAAc,EAAE,IAAI,CAAC,EAAE,SAAS,GAAG,MAAM,CAEjF"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reactivity — forwarder receive path (`docs/reactivity.md` §Propagation).
|
|
3
|
+
*
|
|
4
|
+
* A receiving forwarder primary, for each inbound notification:
|
|
5
|
+
* 1. **verifies** the threshold signature against the tail cohort's `MembershipCertV1`;
|
|
6
|
+
* 2. runs the **dedupe** check (sliding `(revision, sigDigest)` window);
|
|
7
|
+
* 3. **appends** to the replay buffer;
|
|
8
|
+
* 4. **forwards the unmodified notification** to its own direct subscribers and child cohorts.
|
|
9
|
+
*
|
|
10
|
+
* This module owns steps 1–3 and the forward *decision* (step 4's transport — dialing each subscriber's
|
|
11
|
+
* primary and each child cohort — is the db-p2p binding). Forwarders never re-sign: a compromised
|
|
12
|
+
* forwarder can drop or delay, but cannot forge. An unverifiable notification is dropped **before**
|
|
13
|
+
* touching the dedupe set or buffer, so a forged payload can neither poison dedupe nor occupy a ring
|
|
14
|
+
* slot. The buffer + dedupe set are gossiped across the cohort by the host's gossip cadence (see
|
|
15
|
+
* {@link PushState}), so any member can serve a replay.
|
|
16
|
+
*/
|
|
17
|
+
import { dedupeKey, sigDigest } from "./notification.js";
|
|
18
|
+
class PushStateForwarder {
|
|
19
|
+
deps;
|
|
20
|
+
state;
|
|
21
|
+
constructor(deps) {
|
|
22
|
+
this.deps = deps;
|
|
23
|
+
this.state = deps.state;
|
|
24
|
+
}
|
|
25
|
+
async receive(n, now) {
|
|
26
|
+
// 1. Verify end-to-end before any state mutation — a forged notification touches nothing.
|
|
27
|
+
const verdict = await this.deps.verifier.verify(n);
|
|
28
|
+
if (verdict !== "verified") {
|
|
29
|
+
return "untrusted";
|
|
30
|
+
}
|
|
31
|
+
// 2. Dedupe on `(revision, sigDigest)`. Already-seen → drop silently.
|
|
32
|
+
const digest = sigDigest(n.sig, this.deps.hash);
|
|
33
|
+
if (this.state.dedupe.observe(n.revision, digest) === "duplicate") {
|
|
34
|
+
return "duplicate";
|
|
35
|
+
}
|
|
36
|
+
// 3. Append the full signed notification to the replay ring (gossiped across the cohort).
|
|
37
|
+
this.state.replayBuffer.append({ revision: n.revision, payload: n, receivedAt: now });
|
|
38
|
+
if (n.revision > this.state.lastRevision) {
|
|
39
|
+
this.state.lastRevision = n.revision;
|
|
40
|
+
}
|
|
41
|
+
return "forward";
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/** Build a {@link ReactivityForwarder} over a collection's {@link PushState} and a verifier. */
|
|
45
|
+
export function createReactivityForwarder(deps) {
|
|
46
|
+
return new PushStateForwarder(deps);
|
|
47
|
+
}
|
|
48
|
+
/** The dedupe key a forwarder would compute for a notification (exposed for tests/diagnostics). */
|
|
49
|
+
export function notificationDedupeKey(n, hash) {
|
|
50
|
+
return dedupeKey(n.revision, n.sig, hash);
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=forwarder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"forwarder.js","sourceRoot":"","sources":["../../../src/reactivity/forwarder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAkCzD,MAAM,kBAAkB;IAGM;IAFpB,KAAK,CAAY;IAE1B,YAA6B,IAA6B;QAA7B,SAAI,GAAJ,IAAI,CAAyB;QACzD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;IACzB,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,CAAiB,EAAE,GAAW;QAC3C,0FAA0F;QAC1F,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACnD,IAAI,OAAO,KAAK,UAAU,EAAE,CAAC;YAC5B,OAAO,WAAW,CAAC;QACpB,CAAC;QACD,sEAAsE;QACtE,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChD,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,EAAE,MAAM,CAAC,KAAK,WAAW,EAAE,CAAC;YACnE,OAAO,WAAW,CAAC;QACpB,CAAC;QACD,0FAA0F;QAC1F,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,OAAO,EAAE,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC;QACtF,IAAI,CAAC,CAAC,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC;YAC1C,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,CAAC,CAAC,QAAQ,CAAC;QACtC,CAAC;QACD,OAAO,SAAS,CAAC;IAClB,CAAC;CACD;AAED,gGAAgG;AAChG,MAAM,UAAU,yBAAyB,CAAC,IAA6B;IACtE,OAAO,IAAI,kBAAkB,CAAC,IAAI,CAAC,CAAC;AACrC,CAAC;AAED,mGAAmG;AACnG,MAAM,UAAU,qBAAqB,CAAC,CAAiB,EAAE,IAAgB;IACxE,OAAO,SAAS,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;AAC3C,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reactivity — push-based change notifications on the cohort-topic substrate.
|
|
3
|
+
*
|
|
4
|
+
* See `docs/reactivity.md`. This module lands the reactivity hot path — the rotating tail-anchored topic,
|
|
5
|
+
* the subscribe `appPayload`, notification origination (reusing the commit cert unchanged), the forwarder
|
|
6
|
+
* receive path (verify → dedupe → buffer → forward), the `W`-entry replay ring with cohort gossip, the
|
|
7
|
+
* sliding `(revision, sigDigest)` dedupe window, and subscriber-side verify/deliver with gap detection
|
|
8
|
+
* ([reactivity-origination-replay-delivery]) — plus **recovery beyond the live stream**
|
|
9
|
+
* ([reactivity-backfill-resume-checkpoints]): the {@link ./backfill.js} RPC served from the replay ring,
|
|
10
|
+
* the rolling parent {@link ./checkpoint.js} stacked below it, and the four-variant {@link ./resume.js}
|
|
11
|
+
* protocol for mobile wake — plus **tail rotation, slow-subscriber backpressure, and Edge/Core policy**
|
|
12
|
+
* ([reactivity-rotation-backpressure-policy]): the {@link ./rotation.js} lifecycle (pre-announce, drain,
|
|
13
|
+
* jittered re-registration, buffer-to-checkpoint handoff, warm-up), the per-subscriber drop-oldest
|
|
14
|
+
* {@link ./backpressure.js}, and the {@link ./policy.js} Edge-subscriber-only / `delta_max` gate.
|
|
15
|
+
*/
|
|
16
|
+
export * from "./config.js";
|
|
17
|
+
export * from "./topic-anchor.js";
|
|
18
|
+
export * from "./wire.js";
|
|
19
|
+
export * from "./notification.js";
|
|
20
|
+
export * from "./dedupe.js";
|
|
21
|
+
export * from "./replay-buffer.js";
|
|
22
|
+
export * from "./checkpoint.js";
|
|
23
|
+
export * from "./backpressure.js";
|
|
24
|
+
export * from "./push-state.js";
|
|
25
|
+
export * from "./verify.js";
|
|
26
|
+
export * from "./forwarder.js";
|
|
27
|
+
export * from "./subscriber.js";
|
|
28
|
+
export * from "./subscription.js";
|
|
29
|
+
export * from "./backfill.js";
|
|
30
|
+
export * from "./resume.js";
|
|
31
|
+
export * from "./recover.js";
|
|
32
|
+
export * from "./rotation.js";
|
|
33
|
+
export * from "./policy.js";
|
|
34
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/reactivity/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,WAAW,CAAC;AAC1B,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reactivity — push-based change notifications on the cohort-topic substrate.
|
|
3
|
+
*
|
|
4
|
+
* See `docs/reactivity.md`. This module lands the reactivity hot path — the rotating tail-anchored topic,
|
|
5
|
+
* the subscribe `appPayload`, notification origination (reusing the commit cert unchanged), the forwarder
|
|
6
|
+
* receive path (verify → dedupe → buffer → forward), the `W`-entry replay ring with cohort gossip, the
|
|
7
|
+
* sliding `(revision, sigDigest)` dedupe window, and subscriber-side verify/deliver with gap detection
|
|
8
|
+
* ([reactivity-origination-replay-delivery]) — plus **recovery beyond the live stream**
|
|
9
|
+
* ([reactivity-backfill-resume-checkpoints]): the {@link ./backfill.js} RPC served from the replay ring,
|
|
10
|
+
* the rolling parent {@link ./checkpoint.js} stacked below it, and the four-variant {@link ./resume.js}
|
|
11
|
+
* protocol for mobile wake — plus **tail rotation, slow-subscriber backpressure, and Edge/Core policy**
|
|
12
|
+
* ([reactivity-rotation-backpressure-policy]): the {@link ./rotation.js} lifecycle (pre-announce, drain,
|
|
13
|
+
* jittered re-registration, buffer-to-checkpoint handoff, warm-up), the per-subscriber drop-oldest
|
|
14
|
+
* {@link ./backpressure.js}, and the {@link ./policy.js} Edge-subscriber-only / `delta_max` gate.
|
|
15
|
+
*/
|
|
16
|
+
export * from "./config.js";
|
|
17
|
+
export * from "./topic-anchor.js";
|
|
18
|
+
export * from "./wire.js";
|
|
19
|
+
export * from "./notification.js";
|
|
20
|
+
export * from "./dedupe.js";
|
|
21
|
+
export * from "./replay-buffer.js";
|
|
22
|
+
export * from "./checkpoint.js";
|
|
23
|
+
export * from "./backpressure.js";
|
|
24
|
+
export * from "./push-state.js";
|
|
25
|
+
export * from "./verify.js";
|
|
26
|
+
export * from "./forwarder.js";
|
|
27
|
+
export * from "./subscriber.js";
|
|
28
|
+
export * from "./subscription.js";
|
|
29
|
+
export * from "./backfill.js";
|
|
30
|
+
export * from "./resume.js";
|
|
31
|
+
export * from "./recover.js";
|
|
32
|
+
export * from "./rotation.js";
|
|
33
|
+
export * from "./policy.js";
|
|
34
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/reactivity/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,WAAW,CAAC;AAC1B,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reactivity — notification origination (`docs/reactivity.md` §Notification origination).
|
|
3
|
+
*
|
|
4
|
+
* The tail cohort's primary for a collection is, by construction, the transaction-layer tail-cluster:
|
|
5
|
+
* the cohort-topic primary at `coord_0(_, topicId)` where `topicId = H(tailId ‖ "reactivity")`. As soon
|
|
6
|
+
* as the commit's threshold signature is assembled, it emits a {@link NotificationV1} whose `sig` is
|
|
7
|
+
* **bit-for-bit** the commit certificate's threshold signature — reactivity never re-signs.
|
|
8
|
+
*
|
|
9
|
+
* This module is the pure assembler. The local-change-notifier bridge ([local-change-notifier-bridge])
|
|
10
|
+
* supplies the {@link CollectionChangeEvent} and the pass-through {@link CommitCert}; db-p2p's
|
|
11
|
+
* origination manager calls {@link buildNotificationV1} with those plus the per-emission context
|
|
12
|
+
* (`tailId`, `timestamp`, the per-collection `deltaMaxBytes`) and fans the result out. Crypto-free: it
|
|
13
|
+
* copies `commitCert.thresholdSig` and `commitCert.signers` through unchanged.
|
|
14
|
+
*/
|
|
15
|
+
import type { IRingHash } from "../cohort-topic/ports.js";
|
|
16
|
+
import type { CollectionChangeEvent, CommitCert } from "../transactor/change-notifier.js";
|
|
17
|
+
import type { NotificationV1, RotationHintV1 } from "./wire.js";
|
|
18
|
+
/** Per-emission context the origination point supplies alongside the bridge's event + cert. */
|
|
19
|
+
export interface OriginationContext {
|
|
20
|
+
/** Current tail block id (base64url) the reactivity topic is anchored on. */
|
|
21
|
+
readonly tailId: string;
|
|
22
|
+
/** Emission timestamp (unix ms). */
|
|
23
|
+
readonly timestamp: number;
|
|
24
|
+
/**
|
|
25
|
+
* Per-collection delta budget (bytes). `0` ⇒ omit `delta` entirely (Edge profile, or a collection
|
|
26
|
+
* that declines deltas). Origination MUST respect a `deltaMaxBytes` of `0` by omitting the field.
|
|
27
|
+
*/
|
|
28
|
+
readonly deltaMaxBytes: number;
|
|
29
|
+
/** Optional bounded delta (raw bytes); included only when within `deltaMaxBytes` and `> 0`. */
|
|
30
|
+
readonly delta?: Uint8Array;
|
|
31
|
+
/** Tail-rotation pre-announce to embed (rotation ticket supplies it). */
|
|
32
|
+
readonly rotationHint?: RotationHintV1;
|
|
33
|
+
/**
|
|
34
|
+
* Map a {@link CommitCert} signer (the cluster's peer-id string keying its commit vote) to the
|
|
35
|
+
* base64url cohort member-id bytes the subscriber's membership verifier compares against. Default:
|
|
36
|
+
* identity (the signer is already base64url) — db-p2p supplies `s ⇒ bytesToB64url(peerIdToBytes(s))`.
|
|
37
|
+
*/
|
|
38
|
+
readonly encodeSigner?: (signer: string) => string;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Assemble the {@link NotificationV1} for one committed change, reusing the commit cert's threshold
|
|
42
|
+
* signature unchanged.
|
|
43
|
+
*
|
|
44
|
+
* `digest` carries the commit-vote **signed payload** the threshold signature was computed over —
|
|
45
|
+
* `commitCert.signedPayload`, the cluster's per-member `utf8(commitHash + ":approve")` byte image,
|
|
46
|
+
* identical across all approving signers. Because the verifier recomputes the cohort threshold check over
|
|
47
|
+
* exactly these bytes (`payload = b64urlToBytes(n.digest)`), a subscriber's **real** Ed25519
|
|
48
|
+
* threshold-verify over `digest` reproduces the signed image and succeeds — the cluster↔reactivity
|
|
49
|
+
* integration seam is **closed** (no pass-crypto stub required). The hint-only contract still holds for
|
|
50
|
+
* the optional `delta`: deltas are advisory; the digest + threshold signature are the authoritative proof.
|
|
51
|
+
*/
|
|
52
|
+
export declare function buildNotificationV1(event: CollectionChangeEvent, commitCert: CommitCert, ctx: OriginationContext): NotificationV1;
|
|
53
|
+
/**
|
|
54
|
+
* Compact, stable digest of a notification's signature for the dedupe key `(revision, sigDigest)`
|
|
55
|
+
* (`docs/reactivity.md` §Per-revision dedupe). Hashing the signature bytes keeps the key bounded and
|
|
56
|
+
* distinguishes two distinct threshold sigs that legitimately share a revision during partition merge.
|
|
57
|
+
*/
|
|
58
|
+
export declare function sigDigest(sig: string, hash?: IRingHash): string;
|
|
59
|
+
/** The dedupe-set key for a notification: `${revision}:${sigDigest(sig)}`. */
|
|
60
|
+
export declare function dedupeKey(revision: number, sig: string, hash?: IRingHash): string;
|
|
61
|
+
/**
|
|
62
|
+
* Collapse a batch of inbound notifications to the distinct **invalidated action ids** a client must act
|
|
63
|
+
* on, in first-seen order. A single dispute can fan out several invalidation notifications — one per
|
|
64
|
+
* cascade child (`docs/right-is-right.md` §Read-Dependency Cascade) — and a client holding dependents of
|
|
65
|
+
* several may receive several; coalescing by `invalidatedActionId` lets it drop + resubmit each affected
|
|
66
|
+
* unit exactly once instead of once per notification. Notifications that are not invalidations (ordinary
|
|
67
|
+
* commits) and invalidations missing an `invalidatedActionId` are ignored here — the former drive a plain
|
|
68
|
+
* refresh, the latter still surface the reverted state on the next authoritative read. A hint-layer helper:
|
|
69
|
+
* the client still verifies against committed state.
|
|
70
|
+
*/
|
|
71
|
+
export declare function coalesceInvalidatedActionIds(notifications: Iterable<NotificationV1>): string[];
|
|
72
|
+
//# sourceMappingURL=notification.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notification.d.ts","sourceRoot":"","sources":["../../../src/reactivity/notification.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,KAAK,EAAE,qBAAqB,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAC1F,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAIhE,+FAA+F;AAC/F,MAAM,WAAW,kBAAkB;IAClC,6EAA6E;IAC7E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,oCAAoC;IACpC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;;;OAGG;IACH,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,+FAA+F;IAC/F,QAAQ,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC;IAC5B,yEAAyE;IACzE,QAAQ,CAAC,YAAY,CAAC,EAAE,cAAc,CAAC;IACvC;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC;CACnD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,qBAAqB,EAAE,UAAU,EAAE,UAAU,EAAE,GAAG,EAAE,kBAAkB,GAAG,cAAc,CA4BjI;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE,SAA4B,GAAG,MAAM,CAEjF;AAED,8EAA8E;AAC9E,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,SAAS,GAAG,MAAM,CAEjF;AAED;;;;;;;;;GASG;AACH,wBAAgB,4BAA4B,CAAC,aAAa,EAAE,QAAQ,CAAC,cAAc,CAAC,GAAG,MAAM,EAAE,CAU9F"}
|