Expand economy, autobase, network, observability, and scheduling modules.

Add auction withdraw/cancel, marketplace search helpers, update gossip history, autobase fork/lease/indexer/view APIs, link-probe and circuit-loom utilities, trace trees, pheromone ranking, and scheduling/measurement helpers with tests.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Raven Scott
2026-05-21 01:09:29 -04:00
co-authored by Cursor
parent b8b815fce6
commit 44b8a80907
36 changed files with 508 additions and 4 deletions
@@ -31,6 +31,14 @@ Public API on `HyperPearUpdateGossip`. See [`index.js`](../index.js) for paramet
Public API on `HyperPearUpdateGossip`. See [`index.js`](../index.js) for parameters and return types.
### `isNewerThan(version) → boolean`
`true` when `latestUpdate().version` is newer than `version` (numeric or string compare).
### `updateHistory(limit = 10) → object[]`
Recent published updates (ring buffer, `maxHistory` constructor option, default 32).
### `getStats() → object`
Metrics plus `protocol: 'pear-update-gossip/v1'`.
@@ -11,6 +11,8 @@ class HyperPearUpdateGossip extends EventEmitter {
this.topic = opts.topic || null
this.keyPair = opts.keyPair || require('hypercore-crypto').keyPair()
this._latest = null
this._history = []
this.maxHistory = opts.maxHistory ?? 32
this._subs = new Set()
this._stats = { published: 0, gossipIn: 0, gossipOut: 0 }
this.swarm = null
@@ -23,19 +25,37 @@ class HyperPearUpdateGossip extends EventEmitter {
throw new Error('manifest must be an object')
}
const update = { version, manifest, publishedAt: Date.now() }
if (!this._latest || version > this._latest.version) {
if (!this._latest || this._isNewer(version, this._latest.version)) {
this._latest = update
}
this._history.push(update)
if (this._history.length > this.maxHistory) this._history.shift()
this._stats.published++
this._gossip({ type: 'update-publish', version, manifest, publishedAt: update.publishedAt })
this._notify(update)
return update
}
_isNewer (a, b) {
const na = Number(a)
const nb = Number(b)
if (!Number.isNaN(na) && !Number.isNaN(nb)) return na > nb
return String(a) > String(b)
}
latestUpdate () {
return this._latest ? { ...this._latest } : null
}
isNewerThan (version) {
if (!this._latest) return false
return this._isNewer(this._latest.version, version)
}
updateHistory (limit = 10) {
return this._history.slice(-Math.max(0, limit | 0))
}
subscribe (fn) {
if (typeof fn !== 'function') throw new Error('fn must be a function')
this._subs.add(fn)
@@ -59,12 +79,14 @@ class HyperPearUpdateGossip extends EventEmitter {
_onGossip (d) {
if (!d || d.type !== 'update-publish' || !d.version) return
this._stats.gossipIn++
if (!this._latest || d.version > this._latest.version) {
if (!this._latest || this._isNewer(d.version, this._latest.version)) {
this._latest = {
version: d.version,
manifest: d.manifest,
publishedAt: d.publishedAt || Date.now()
}
this._history.push(this._latest)
if (this._history.length > this.maxHistory) this._history.shift()
this._notify(this._latest)
}
}
@@ -35,3 +35,12 @@ test('getStats', async (t) => {
t.is(m.getStats().published, 1)
await m.close()
})
test('history and isNewer', async (t) => {
const m = new HyperPearUpdateGossip()
m.publishUpdate('1.0.0', {})
m.publishUpdate('2.0.0', {})
t.ok(m.isNewerThan('1.5.0'))
t.is(m.updateHistory(2).length, 2)
await m.close()
})