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
@@ -79,6 +79,20 @@ Sets `status: 'closed'`, `winner` to highest bid (or `null`), gossips `auction-c
All auctions with `status === 'open'`.
### `listAuctionIds() → string[]`
### `highestBid(auctionId) → bid | null`
Top bid after sort, or `null` if none.
### `withdrawBid(auctionId, bidder = null) → number`
Removes all bids from `bidder` (defaults to `peerHex`). Returns count removed; gossips `auction-withdraw`.
### `cancelAuction(auctionId) → boolean`
Deletes an open auction locally and gossips `auction-cancel`.
## Events
| Event | When | Payload |
@@ -97,6 +111,8 @@ All auctions with `status === 'open'`.
| `auction-open` | `auction` | `Map.set`; emit `remote-open` |
| `auction-bid` | `auctionId`, `bid` | append + sort if auction open; emit `remote-bid` |
| `auction-close` | `auctionId`, `winner`, `closedAt` | set closed; emit `remote-close` |
| `auction-withdraw` | `auctionId`, `bidder` | filter bids for bidder |
| `auction-cancel` | `auctionId` | delete auction |
Gossip is skipped until `ready()` has initialized `_peerMsgs`.
@@ -75,6 +75,37 @@ class HyperP2PAuctionGossip extends EventEmitter {
return [...this._auctions.values()].filter((a) => a.status === 'open')
}
listAuctionIds () { return [...this._auctions.keys()] }
highestBid (auctionId) {
const a = this._auctions.get(auctionId)
return a && a.bids.length ? a.bids[0] : null
}
withdrawBid (auctionId, bidder = null) {
const a = this._auctions.get(auctionId)
if (!a || a.status !== 'open') return 0
const who = bidder || this.peerHex
const before = a.bids.length
a.bids = a.bids.filter((b) => b.bidder !== who)
a.bids.sort((x, y) => y.amount - x.amount)
const removed = before - a.bids.length
if (removed) {
this._gossip({ type: 'auction-withdraw', auctionId, bidder: who })
this.emit('withdraw', { auctionId, bidder: who, removed })
}
return removed
}
cancelAuction (auctionId) {
const a = this._auctions.get(auctionId)
if (!a || a.status !== 'open') return false
this._auctions.delete(auctionId)
this._gossip({ type: 'auction-cancel', auctionId })
this.emit('cancel', { auctionId })
return true
}
_gossip (payload) {
if (!this._peerMsgs) return
gossipSend(this, payload)
@@ -105,6 +136,12 @@ class HyperP2PAuctionGossip extends EventEmitter {
this.emit('remote-close', a)
}
}
if (data.type === 'auction-withdraw' && data.auctionId) {
this.withdrawBid(data.auctionId, data.bidder)
}
if (data.type === 'auction-cancel' && data.auctionId) {
this._auctions.delete(data.auctionId)
}
}
getStats () {
@@ -37,3 +37,16 @@ test('getStats', async (t) => {
t.is(m.getStats().opened, 1)
await m.close()
})
test('withdraw cancel highest', async (t) => {
const m = new HyperP2PAuctionGossip()
m.openAuction('a1')
m.placeBid('a1', 10)
m._onGossip({ type: 'auction-bid', auctionId: 'a1', bid: { amount: 30, bidder: 'remote', at: 2 } })
t.is(m.highestBid('a1').amount, 30)
t.is(m.withdrawBid('a1', 'remote'), 1)
t.is(m.highestBid('a1').amount, 10)
t.ok(m.cancelAuction('a1'))
t.is(m.listAuctionIds().length, 0)
await m.close()
})