Expand pubsub, economy, routing-advanced, and platform categories.

Manual pass adds listChannels, totalSupply, openCount, listSessionIds, new api.md files, corrected trust/reactive/conflict getStats docs, and category README hubs for routing-advanced, measurement, pear-platform, and trust-security.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Raven Scott
2026-05-21 00:58:14 -04:00
co-authored by Cursor
parent 0a75712c81
commit f1536f9b6b
19 changed files with 176 additions and 367 deletions
@@ -1,104 +1,29 @@
# API: hyper-p2p-credit-ledger
**Protocol:** `credit-ledger/v1`
**Export:** `{ HyperP2PCreditLedger, PROTOCOL }`
## Overview
`HyperP2PCreditLedger` provides gossip-synchronized account balances. Each account holds a numeric `balance`; `credit`, `debit`, and `transfer` update local state and emit `ledger-entry` gossip with the **authoritative balance** after each mutation (not operation logs).
Extends `bare-events` `EventEmitter`.
## Constructor
```js
const { HyperP2PCreditLedger } = require('hyper-p2p-credit-ledger')
const ledger = new HyperP2PCreditLedger(opts)
```
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `topic` | `string` \| `Buffer` | `null` | Hyperswarm topic |
| `keyPair` | `KeyPair` | random | Signing identity; `peerHex` on entries |
## Lifecycle
### `async ready() → HyperP2PCreditLedger`
Initializes swarm when `topic` set.
### `async close() → void`
Destroys swarm; clears `_accounts`.
### `getStats() → object`
`{ credits, debits, gossipIn, gossipOut, accounts, protocol }`.
**Protocol:** `credit-ledger/v1` · **Export:** `HyperP2PCreditLedger`
## Methods
### `openAccount(accountId, initial = 0) → account`
### `openAccount(accountId, initial?) → account`
Creates account; gossips `ledger-entry` with `kind: 'open'`.
- **Returns:** `{ id, balance, updatedAt }`
- **Throws:** `Error: account exists`
### `credit(accountId, amount, reason = '') → account`
Adds `Math.abs(amount)` to balance; `kind: 'credit'`.
### `debit(accountId, amount, reason = '') → account`
Subtracts `Math.abs(amount)`; `kind: 'debit'`.
### `credit(accountId, amount, reason?)` / `debit(accountId, amount, reason?)`
### `transfer(fromId, toId, amount) → { from, to, amount, at }`
Atomic pair: debit then credit with linked reasons.
- **Throws:** `unknown account`, `insufficient balance`, `amount must be positive`
### `balance(accountId) → number | null`
Current balance or `null` if unknown.
### `listAccounts() → string[]` / `hasAccount(accountId) → boolean`
## Account gossip entry
### `totalSupply() → number`
Remote handler applies **balance snapshot** from gossip (not replay of deltas):
Sum of all account balances.
| Field | Type | Description |
|-------|------|-------------|
| `type` | `'ledger-entry'` | Fixed discriminator |
| `accountId` | `string` | Account key |
| `kind` | `'open' \| 'credit' \| 'debit'` | Mutation class |
| `balance` | `number` | Balance after operation |
| `at` | `number` | Timestamp ms |
| `delta` | `number` | Optional; present on credit/debit |
| `reason` | `string` | Optional note |
| `peer` | `string` | Hex pubkey of originator |
### `getStats() → { credits, debits, accounts, gossipIn, gossipOut, protocol }`
## Events
### `async ready()` / `async close()`
| Event | When | Payload |
|-------|------|---------|
| `account` | `openAccount` | account |
| `credit` | `credit()` | `{ accountId, balance, delta, reason }` |
| `debit` | `debit()` | same shape |
| `remote-entry` | inbound gossip | full ledger-entry |
## Wire
## Errors
`account exists`, `unknown account`, `insufficient balance`, `amount must be positive`, `assertNonEmpty` on ids.
## P2P
Single wire type `ledger-entry`. New accounts created on remote `kind === 'open'`; updates overwrite `balance` when account exists.
## Testing
```bash
npm install && npm test
```
Example: [`../examples/basic.js`](../examples/basic.js).
| type | behavior |
|------|----------|
| `ledger-entry` | Open or update remote balance |
@@ -54,6 +54,16 @@ class HyperP2PCreditLedger extends EventEmitter {
return a ? a.balance : null
}
listAccounts () { return [...this._accounts.keys()] }
hasAccount (accountId) { return this._accounts.has(accountId) }
totalSupply () {
let sum = 0
for (const acct of this._accounts.values()) sum += acct.balance
return sum
}
_apply (accountId, delta, kind, reason) {
assertNonEmpty(accountId, 'accountId')
const acct = this._accounts.get(accountId)
@@ -38,3 +38,13 @@ test('getStats', async (t) => {
t.ok(m.getStats().accounts >= 1)
await m.close()
})
test('totalSupply and listAccounts', async (t) => {
const m = new HyperP2PCreditLedger()
m.openAccount('a', 10)
m.openAccount('b', 20)
t.is(m.totalSupply(), 30)
t.ok(m.hasAccount('a'))
t.alike(m.listAccounts().sort(), ['a', 'b'])
await m.close()
})