Expand pear, encoding, consensus, supercomputer, and CRDT modules

Add manual API helpers across categories: pear link resolver cache,
applink reload, storage layout defaults, compact codec decodeBatch,
schema allValid/getSchema, session bridge removePair, udx sendRecvRatio,
cluster affinity and cpu-share clearAll, raft truncateLog/currentTerm,
quorum vote tally, silence and whisper seen helpers, qos unsubscribeAll,
LWW register clearAll, peer selector topRegions, graph hasPath, fork choice
clearViews, and trust gate untrustAll.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Raven Scott
2026-05-21 02:43:36 -04:00
co-authored by Cursor
parent 32f4292036
commit 422b41f7e4
20 changed files with 171 additions and 0 deletions
@@ -161,6 +161,23 @@ class HyperP2PQuorumPool extends EventEmitter {
}) })
} }
hasVoted (proposalId, voterId) {
const votes = this._votes.get(proposalId)
return votes ? votes.has(voterId) : false
}
voteTally (proposalId) {
const votes = this._votes.get(proposalId)
if (!votes) return { yes: 0, no: 0, total: 0 }
let yes = 0
let no = 0
for (const accept of votes.values()) {
if (accept) yes++
else no++
}
return { yes, no, total: yes + no }
}
getStats () { getStats () {
const open = this.openProposals().length const open = this.openProposals().length
return { return {
@@ -52,6 +52,18 @@ class HyperP2PRaftLite extends EventEmitter {
return this._commitIndex return this._commitIndex
} }
truncateLog (keep = 0) {
const n = Math.max(0, keep | 0)
const removed = this._log.length - n
if (removed > 0) this._log = this._log.slice(-n)
if (this._commitIndex >= this._log.length) this._commitIndex = this._log.length - 1
return removed
}
currentTerm () {
return this._currentTerm
}
role () { role () {
return this._role return this._role
} }
@@ -64,6 +64,16 @@ class HyperP2PSessionBridge extends EventEmitter {
pairCount () { return this._tokens.size } pairCount () { return this._tokens.size }
async removePair (token) {
const entry = this._tokens.get(token)
if (!entry) return false
try { await entry.initiator.destroy() } catch (_) {}
try { await entry.responder.destroy() } catch (_) {}
this._tokens.delete(token)
this.emit('pair-removed', { token })
return true
}
async ready () { async ready () {
if (this.swarm || !this.topic) return this if (this.swarm || !this.topic) return this
await initModuleSwarm(this, { await initModuleSwarm(this, {
@@ -50,6 +50,15 @@ class HyperP2PCompactCodecBridge extends EventEmitter {
return values.map((v) => this.encode(codecId, v)) return values.map((v) => this.encode(codecId, v))
} }
decodeBatch (codecId, buffers) {
if (!Array.isArray(buffers)) throw new Error('buffers must be an array')
return buffers.map((b) => this.decode(codecId, b))
}
hasCodec (codecId) {
return this.registry.listCodecs().includes(codecId)
}
listCodecs () { listCodecs () {
return this.registry.listCodecs() return this.registry.listCodecs()
} }
@@ -83,6 +83,15 @@ class HyperP2PSchemaValidator extends EventEmitter {
return values.map((v) => this.validate(name, v)) return values.map((v) => this.validate(name, v))
} }
allValid (name, values) {
return this.validateBatch(name, values).every((r) => r.ok)
}
getSchema (name) {
const s = this._schemas.get(name)
return s ? { ...s } : null
}
getStats () { getStats () {
return { ...this._stats, schemas: this._schemas.size, protocol: PROTOCOL } return { ...this._stats, schemas: this._schemas.size, protocol: PROTOCOL }
} }
@@ -85,6 +85,16 @@ class HyperP2PSilenceProtocol extends EventEmitter {
return this._absent.delete(String(id)) return this._absent.delete(String(id))
} }
seenCount () {
return this._seen.size
}
markSeenBatch (ids) {
if (!Array.isArray(ids)) throw new Error('ids array required')
for (const id of ids) this.markSeen(id)
return ids.length
}
async ready () { async ready () {
if (this.swarm || !this.topic) return this if (this.swarm || !this.topic) return this
await initModuleSwarm(this, { await initModuleSwarm(this, {
@@ -82,6 +82,10 @@ class HyperP2PWhisperMesh extends EventEmitter {
return n return n
} }
isSeen (id) {
return this._seen.has(String(id))
}
async ready () { async ready () {
if (this.swarm || !this.topic) return this if (this.swarm || !this.topic) return this
await initModuleSwarm(this, { await initModuleSwarm(this, {
@@ -128,6 +128,10 @@ class HyperP2PGraphIndex extends EventEmitter {
return this.bfs(start, depth).order.length return this.bfs(start, depth).order.length
} }
hasPath (from, to) {
return this.shortestPath(from, to) != null
}
toJSON () { toJSON () {
const edges = [] const edges = []
for (const [from, list] of this._adj) { for (const [from, list] of this._adj) {
@@ -100,6 +100,18 @@ class HyperP2PPeerSelectorStreaming extends EventEmitter {
return this._peers.size return this._peers.size
} }
topRegions (limit = 5) {
const counts = new Map()
for (const p of this._peers.values()) {
const r = p.region || 'unknown'
counts.set(r, (counts.get(r) || 0) + 1)
}
return [...counts.entries()]
.sort((a, b) => b[1] - a[1])
.slice(0, Math.max(0, limit | 0))
.map(([region, count]) => ({ region, count }))
}
getStats () { getStats () {
return mediaStats(this._stats, PROTOCOL, { peers: this._peers.size }) return mediaStats(this._stats, PROTOCOL, { peers: this._peers.size })
} }
@@ -88,6 +88,12 @@ class HyperP2PQosTopic extends EventEmitter {
return n return n
} }
unsubscribeAll () {
const n = this._handlers.size
this._handlers.clear()
return n
}
_onGossip (data) { _onGossip (data) {
if (!data || data.type !== 'qos-publish') return if (!data || data.type !== 'qos-publish') return
this._stats.gossipIn++ this._stats.gossipIn++
@@ -70,6 +70,10 @@ class HyperP2PSecretStreamPair {
return !!this._pair return !!this._pair
} }
getActivePair () {
return this._pair
}
pairCount () { pairCount () {
return this._stats.pairs return this._stats.pairs
} }
@@ -70,6 +70,12 @@ class HyperP2PUdxMetrics extends EventEmitter {
return this.windowMs return this.windowMs
} }
sendRecvRatio () {
const r = this.rates()
if (!r.recvBps) return r.sendBps > 0 ? Infinity : 0
return r.sendBps / r.recvBps
}
_trimWindow (samples, now) { _trimWindow (samples, now) {
const cutoff = now - this.windowMs const cutoff = now - this.windowMs
while (samples.length && samples[0].at < cutoff) samples.shift() while (samples.length && samples[0].at < cutoff) samples.shift()
@@ -74,6 +74,15 @@ class HyperPearApplinkConfig extends EventEmitter {
return this._config ? JSON.parse(JSON.stringify(this._config)) : null return this._config ? JSON.parse(JSON.stringify(this._config)) : null
} }
applinkHref () {
return this._config ? this._config.applink : null
}
reload (pkg) {
this._config = null
return this.load(pkg)
}
getStats () { getStats () {
return platformStats(this._stats, PROTOCOL, { loaded: !!this._config }) return platformStats(this._stats, PROTOCOL, { loaded: !!this._config })
} }
@@ -67,6 +67,16 @@ class HyperPearLinkResolver extends EventEmitter {
return this.parse(href) return this.parse(href)
} }
withoutFork (parts) {
const p = { ...parts }
delete p.fork
return this.serialize(p)
}
cacheSize () {
return this._cache.size
}
getStats () { getStats () {
return platformStats(this._stats, PROTOCOL, { cached: this._cache.size }) return platformStats(this._stats, PROTOCOL, { cached: this._cache.size })
} }
@@ -78,6 +78,15 @@ class HyperPearStorageLayout extends EventEmitter {
return Object.fromEntries(this._apps) return Object.fromEntries(this._apps)
} }
setDefaultApp (appKey) {
this.defaultApp = assertId(appKey, 'appKey')
return this.defaultApp
}
appCount () {
return this._apps.size
}
getStats () { getStats () {
return platformStats(this._stats, PROTOCOL, { apps: this._apps.size }) return platformStats(this._stats, PROTOCOL, { apps: this._apps.size })
} }
@@ -30,6 +30,12 @@ class HyperPearTrustGate extends EventEmitter {
return this._trusted.delete(String(key)) return this._trusted.delete(String(key))
} }
untrustAll () {
const n = this._trusted.size
this._trusted.clear()
return n
}
check (key, autoTrust = false) { check (key, autoTrust = false) {
const k = String(key) const k = String(key)
this._stats.checks++ this._stats.checks++
@@ -92,6 +92,16 @@ class HyperP2PCrdtLwwRegister extends EventEmitter {
return ts - e.ts return ts - e.ts
} }
clearAll () {
const n = this._values.size
this._values.clear()
return n
}
liveCount () {
return this.keys().length
}
_onGossip (d) { _onGossip (d) {
if (!d || d.type !== 'crdt-lww-register-sync' || !d.key) return if (!d || d.type !== 'crdt-lww-register-sync' || !d.key) return
this._stats.gossipIn++ this._stats.gossipIn++
@@ -105,6 +105,13 @@ class HyperP2PAutobaseForkChoice extends EventEmitter {
return this._views.get(forkId) return this._views.get(forkId)
} }
clearViews () {
const n = this._views.size
this._views.clear()
this._chosen = null
return n
}
_onGossip (d) { _onGossip (d) {
if (!d || d.type !== 'view-register' || !d.view) return if (!d || d.type !== 'view-register' || !d.view) return
this._stats.gossipIn++ this._stats.gossipIn++
@@ -92,6 +92,17 @@ class HyperP2PClusterAffinity extends EventEmitter {
return this.tagPeer(id, merged, this._latency.get(id)) return this.tagPeer(id, merged, this._latency.get(id))
} }
clearAll () {
const n = this._tags.size
this._tags.clear()
this._latency.clear()
return n
}
peersWithTag (tag) {
return this.listTagged().filter((r) => r.tags.includes(tag)).map((r) => r.peerId)
}
async ready () { async ready () {
if (this.swarm || !this.topic) return this if (this.swarm || !this.topic) return this
await initModuleSwarm(this, { await initModuleSwarm(this, {
@@ -76,6 +76,12 @@ class HyperP2PCpuShare extends EventEmitter {
return had return had
} }
clearAll () {
const n = this._balances.size
this._balances.clear()
return n
}
async ready () { async ready () {
if (this.swarm || !this.topic) return this if (this.swarm || !this.topic) return this
await initModuleSwarm(this, { await initModuleSwarm(this, {