Expand category docs and module APIs across the library.

Manual pass adds helpers (listChannels, taskCounts, openProposals), richer getStats with protocol fields, category README hubs, and tightened api.md for core, messaging, network, routing, supercomputer, and consensus modules.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Raven Scott
2026-05-21 00:54:19 -04:00
co-authored by Cursor
parent e67097f62b
commit 17876e6284
75 changed files with 1534 additions and 2462 deletions
+46 -5
View File
@@ -1,9 +1,50 @@
# Agents & workflows # Agents & workflows
**Path:** `modules/agents-workflows/` · **Modules:** 3 (3 production, 0 scaffold) **Path:** `modules/agents-workflows/` · **Modules:** 3 (all production)
See [MODULE_CATEGORIES.md](../MODULE_CATEGORIES.md#agents-workflows). Autonomous agent primitives: persistent causal memory, DAG task orchestration, and P2P workflow graphs. Hub: [`../../docs/agents-workflows/README.md`](../../docs/agents-workflows/README.md).
- [hyper-p2p-agent-memory](./hyper-p2p-agent-memory/) — production ## When to use
- [hyper-p2p-task-orchestrator](./hyper-p2p-task-orchestrator/) — production
- [hyper-p2p-workflow-graph](./hyper-p2p-workflow-graph/) — production - Long-horizon agent state with recall and signing (`agent-memory`)
- Distributed task DAGs with deadlines and retries (`task-orchestrator`)
- Multi-step workflows with dependency edges (`workflow-graph`)
## Modules
| Module | Protocol | Summary |
|--------|----------|---------|
| [hyper-p2p-agent-memory](./hyper-p2p-agent-memory/) | `hyper-p2p-agent-memory/v1` | Episodic/semantic memory, tags, causal links, Hyperbee |
| [hyper-p2p-task-orchestrator](./hyper-p2p-task-orchestrator/) | `hyper-p2p-task-orchestrator/v1` | Signed tasks, deps, assign/complete, hooks |
| [hyper-p2p-workflow-graph](./hyper-p2p-workflow-graph/) | `workflow-graph/v1` | DAG nodes/edges, `readyNodes()`, cycle detection |
## Quick start
```js
const { HyperP2PAgentMemory } = require('hyper-p2p-agent-memory')
const { HyperP2PTaskOrchestrator } = require('hyper-p2p-task-orchestrator')
const { HyperP2PWorkflowGraph } = require('hyper-p2p-workflow-graph')
const mem = new HyperP2PAgentMemory()
await mem.storeMemory({ fact: 'peer joined' }, { tags: ['network'] })
const orch = new HyperP2PTaskOrchestrator({ topic: 'agents' })
await orch.ready()
const taskId = await orch.submitTask({ type: 'index', payload: { path: '/' } })
const wf = new HyperP2PWorkflowGraph()
wf.addNode('fetch')
wf.addNode('embed')
wf.addEdge('fetch', 'embed')
wf.readyNodes()
```
## Composition
Pairs with `hyper-p2p-vector-clock`, `hyper-p2p-capabilities`, and `supercomputer` job dispatch.
## Test
```bash
cd hyper-p2p-workflow-graph && npm install && npm test
```
@@ -400,8 +400,17 @@ class HyperP2PAgentMemory extends EventEmitter {
} }
memoryCount () { return this.memories.size }
tagList () { return [...this.tagIndex.keys()] }
getStats () { getStats () {
return { ...this._stats } return {
...this._metrics,
memories: this.memories.size,
tags: this.tagIndex.size,
protocol: MEMORY_PROTOCOL
}
} }
async close () { async close () {
@@ -1,105 +1,25 @@
# API: hyper-p2p-task-orchestrator # API: hyper-p2p-task-orchestrator
**Protocol:** `hyper-p2p-task-orchestrator/v1` **Protocol:** `hyper-p2p-task-orchestrator/v1` · **Export:** `HyperP2PTaskOrchestrator`
**Export:** `HyperP2PTaskOrchestrator`, `TASK_PROTOCOL`
## Overview ## Overview
`HyperP2PTaskOrchestrator` manages a signed task graph with priorities, deadlines, dependency gates, execution hooks, JSON file persistence, and Protomux gossip for remote task submission. Integrates `HyperP2PVectorClock` for causal lifecycle metadata. DAG task orchestration with signed tasks, vector-clock lifecycle, optional Hyperbee persistence, and P2P gossip.
## Constructor ## Key methods
```js ### `submitTask(taskDef) → taskId`
const orch = new HyperP2PTaskOrchestrator(opts)
```
| Option | Type | Default | Description | ### `assignTask(taskId, assignee)` / `completeTask(taskId, result)` / `failTask(taskId, error)`
|--------|------|---------|-------------|
| `keyPair` | `KeyPair` | random | Task signing identity |
| `topic` | `string` | `null` | Hyperswarm topic for gossip |
| `storageDir` | `string` | `{cwd}/hyper-p2p-task-orchestrator-storage` | `tasks.json` persistence |
| `defaultDeadlineMs` | `number` | `300000` | Default task TTL |
| `clock` | `HyperP2PVectorClock` | new instance | Causal clock helper |
## Methods ### `registerHandler(taskType, fn)` / `getTask(taskId)` / `getResult(taskId)`
### `ready()` ### `taskCounts() → { pending, running, completed, failed, total }`
Loads storage, joins swarm when `topic` set, starts expiry cleanup interval. ### `getStats() → { ...metrics, ...taskCounts(), protocol }`
- **Returns:** `Promise<void>` ### `async ready()` / `async close()`
- **Emits:** `ready`, `p2p-ready`
### `submitTask(taskSpec)`
Creates signed pending task; records dependencies.
- **Parameters:** `{ type, payload?, owner?, priority?, deadline?, deps? }`
- **Returns:** `Promise<task>`
- **Throws:**
- `Error: taskSpec.type required`
- `Error: Task signing failed`
### `assignTask(taskId, assignee?)`
Marks task `assigned` when dependencies satisfied.
- **Returns:** `Promise<task | null>`
### `completeTask(taskId, resultData?, success?)`
Stores result, updates status `completed` or `failed`, unblocks dependents.
- **Returns:** `Promise<result>`
### `getTask(taskId)` / `queryTasks(filter)`
Read single task or filter by `status`, `type`, `owner`.
### `registerExecutionHook(taskType, handler)` / `executeTask(taskId)`
Register per-type executor; run when assigned.
### `getMetrics()` / `getStats()`
Returns `metrics` counters + `{ ops, errors }`.
### `close()`
Clears timers, destroys swarm, persists tasks.
- **Returns:** `Promise<void>`
## Task object
| Field | Description |
|-------|-------------|
| `taskId` | Hex id |
| `type` | Handler type string |
| `status` | `pending` \| `assigned` \| `completed` \| `failed` \| `expired` |
| `priority` | Higher runs first in queries |
| `deadline` | Unix ms |
| `deps` | Prerequisite task ids |
| `signature` | Base64 Ed25519 |
| `causal` | Vector clock snapshot at submit |
## Events ## Events
`ready`, `p2p-ready`, `task:submitted`, `task:assigned`, `task:completed`, `task:failed`, `task:expired`, `task:retry`, `task:received`, `error` `task-submitted`, `task-assigned`, `task-completed`, `task-failed`, `task-expired`
## Wire messages
| type | fields |
|------|--------|
| `task` | `task` (full signed task object) |
## P2P
Uses `initModuleSwarm` from `p2p-bare.js` with protocol `hyper-p2p-task-orchestrator/v1`.
## Testing
```bash
npm test
```
@@ -390,8 +390,27 @@ class HyperP2PTaskOrchestrator extends EventEmitter {
} }
taskCounts () {
const c = { pending: 0, assigned: 0, completed: 0, failed: 0 }
for (const t of this.tasks.values()) {
if (t.status === 'pending') c.pending++
else if (t.status === 'assigned') c.assigned++
else if (t.status === 'completed') c.completed++
else if (t.status === 'failed') c.failed++
}
return c
}
getStats () { getStats () {
return { ...this._stats } const counts = this.taskCounts()
return {
...this._stats,
...this.metrics,
tasks: this.tasks.size,
...counts,
hooks: this.executionHooks.size,
protocol: 'task-orchestrator/v1'
}
} }
async close () { async close () {
@@ -89,6 +89,18 @@ class HyperP2PWorkflowGraph extends EventEmitter {
return this._nodes.get(id) || null return this._nodes.get(id) || null
} }
nodeCount () { return this._nodes.size }
pendingCount () {
return [...this._nodes.values()].filter((n) => n.state === 'pending').length
}
isComplete () {
return this._nodes.size > 0 && this.pendingCount() === 0
}
listNodes () { return [...this._nodes.values()] }
toJSON () { toJSON () {
return { nodes: [...this._nodes.values()], edges: [...this._edges] } return { nodes: [...this._nodes.values()], edges: [...this._edges] }
} }
@@ -130,7 +142,13 @@ class HyperP2PWorkflowGraph extends EventEmitter {
getStats () { getStats () {
return { ...this._stats } return {
...this._stats,
nodes: this._nodes.size,
edges: this._edges.length,
pending: this.pendingCount(),
protocol: PROTOCOL
}
} }
async close () { async close () {
+14 -14
View File
@@ -1,19 +1,17 @@
# Applications (collaboration) # Applications (collaboration)
**Modules:** 4 (production) **Path:** `modules/applications-collab/` · **Modules:** 4 (production)
Real-time collaboration primitives: rooms, whiteboard ops, cursor presence, and per-line locks — all gossip-synced on a shared topic. Real-time collab primitives: rooms, cursors, line locks, and whiteboard ops over gossip meshes.
Hub: [`../../docs/applications-collab/README.md`](../../docs/applications-collab/README.md) ## Modules
## Packages | Module | Protocol | Highlights |
|--------|----------|------------|
| Module | Protocol | Role | | [hyper-p2p-collab-room](./hyper-p2p-collab-room/) | `collab-room/v1` | `listRooms()`, `getMembers`, broadcast |
|--------|----------|------| | [hyper-p2p-cursor-presence](./hyper-p2p-cursor-presence/) | `cursor-presence/v1` | Per-doc cursor map |
| [hyper-p2p-collab-room](./hyper-p2p-collab-room/) | `collab-room/v1` | Rooms, members, broadcast log |
| [hyper-p2p-whiteboard-op](./hyper-p2p-whiteboard-op/) | `whiteboard-op/v1` | Append-only op log per room |
| [hyper-p2p-cursor-presence](./hyper-p2p-cursor-presence/) | `cursor-presence/v1` | Per-doc cursors |
| [hyper-p2p-document-line-lock](./hyper-p2p-document-line-lock/) | `document-line-lock/v1` | Line-level locks | | [hyper-p2p-document-line-lock](./hyper-p2p-document-line-lock/) | `document-line-lock/v1` | Line-level locks |
| [hyper-p2p-whiteboard-op](./hyper-p2p-whiteboard-op/) | `whiteboard-op/v1` | Op log + replay |
## Quick start ## Quick start
@@ -22,9 +20,11 @@ const { HyperP2PCollabRoom } = require('hyper-p2p-collab-room')
const room = new HyperP2PCollabRoom({ topic: 'editors' }) const room = new HyperP2PCollabRoom({ topic: 'editors' })
await room.ready() await room.ready()
room.createRoom('doc-1') room.createRoom('doc-1')
room.join('doc-1') room.join('doc-1', { peer: 'me', name: 'Raven' })
room.broadcast('doc-1', { type: 'ping' })
await room.close()
``` ```
Integration: `whiteboard-op-two-node.js`, `collab-room-two-node.js` under `real_tests/integration/`. ## Test
```bash
cd hyper-p2p-collab-room && npm test
```
@@ -83,6 +83,10 @@ class HyperP2PCollabRoom extends EventEmitter {
return [...room.members.values()] return [...room.members.values()]
} }
listRooms () { return [...this._rooms.keys()] }
hasRoom (roomId) { return this._rooms.has(roomId) }
getEvents (roomId, limit = 50) { getEvents (roomId, limit = 50) {
const room = this._rooms.get(roomId) const room = this._rooms.get(roomId)
if (!room) return [] if (!room) return []
+32 -5
View File
@@ -1,9 +1,36 @@
# Applications (economy) # Applications (economy)
**Path:** `modules/applications-economy/` · **Modules:** 3 (3 production, 0 scaffold) **Path:** `modules/applications-economy/` · **Modules:** 3 (production)
See [MODULE_CATEGORIES.md](../MODULE_CATEGORIES.md#applications-economy). P2P economy primitives: credit ledger, auction gossip, marketplace listings. Hub: [`../../docs/applications-economy/README.md`](../../docs/applications-economy/README.md).
- [hyper-p2p-auction-gossip](./hyper-p2p-auction-gossip/) — production ## When to use
- [hyper-p2p-credit-ledger](./hyper-p2p-credit-ledger/) — production
- [hyper-p2p-marketplace-listing](./hyper-p2p-marketplace-listing/) — production - Account balances with credit/debit and mesh sync (`credit-ledger`)
- Second-price style bidding over gossip (`auction-gossip`)
- Tagged listings with sold state (`marketplace-listing`)
## Modules
| Module | Protocol | Summary |
|--------|----------|---------|
| [hyper-p2p-credit-ledger](./hyper-p2p-credit-ledger/) | `credit-ledger/v1` | Open account, credit/debit, `totalSupply()` |
| [hyper-p2p-auction-gossip](./hyper-p2p-auction-gossip/) | `auction-gossip/v1` | Open auction, bids, close with winner |
| [hyper-p2p-marketplace-listing](./hyper-p2p-marketplace-listing/) | `marketplace-listing/v1` | Create/search/sell listings |
## Quick start
```js
const { HyperP2PCreditLedger } = require('hyper-p2p-credit-ledger')
const ledger = new HyperP2PCreditLedger({ topic: 'economy' })
await ledger.ready()
ledger.openAccount('alice')
ledger.credit('alice', 100, 'grant')
console.log(ledger.balance('alice'), ledger.totalSupply())
```
## Test
```bash
cd hyper-p2p-auction-gossip && npm install && npm test
```
+28 -9
View File
@@ -1,13 +1,32 @@
# Consensus & coordination # Consensus & coordination
**Path:** `modules/consensus-coordination/` · **Modules:** 5 (all production) **Path:** `modules/consensus-coordination/` · **Modules:** 5 (production)
Doc hub: [`docs/consensus-coordination/README.md`](../../docs/consensus-coordination/README.md) Distributed locks, leader leases, quorum voting, Raft-lite logs, and causal consensus for P2P coordination.
| Module | Protocol | Summary | ## Modules
|--------|----------|---------|
| [hyper-p2p-distributed-lock](./hyper-p2p-distributed-lock/) | `hyper-p2p-distributed-lock/v1` | Fencing tokens, signed leases, `listActiveLocks` | | Module | Protocol | Role |
| [hyper-p2p-leader-lease](./hyper-p2p-leader-lease/) | `leader-lease/v1` | Leader lease gossip | |--------|----------|------|
| [hyper-p2p-quorum-pool](./hyper-p2p-quorum-pool/) | `quorum-pool/v1` | Quorum votes | | [hyper-p2p-distributed-lock](./hyper-p2p-distributed-lock/) | `hyper-p2p-distributed-lock/v1` | Lease locks + fencing tokens |
| [hyper-p2p-raft-lite](./hyper-p2p-raft-lite/) | `raft-lite/v1` | Raft-lite state machine | | [hyper-p2p-leader-lease](./hyper-p2p-leader-lease/) | `leader-lease/v1` | Term-based leader election |
| [hyper-p2p-causal-consensus](./hyper-p2p-causal-consensus/) | `causal-consensus/v1` | Causal consensus hints | | [hyper-p2p-quorum-pool](./hyper-p2p-quorum-pool/) | `quorum-pool/v1` | Majority proposals (`openProposals`) |
| [hyper-p2p-raft-lite](./hyper-p2p-raft-lite/) | `raft-lite/v1` | Append-only replicated log |
| [hyper-p2p-causal-consensus](./hyper-p2p-causal-consensus/) | `causal-consensus/v1` | Causal proposal/vote flow |
## Quick start
```js
const { HyperP2PQuorumPool } = require('hyper-p2p-quorum-pool')
const q = new HyperP2PQuorumPool({ quorum: 0.51 })
q.addMember('a'); q.addMember('b')
const id = q.propose({ action: 'upgrade' })
q.vote(id, 'a', true)
console.log(q.resolve(id))
```
## Test
```bash
cd hyper-p2p-distributed-lock && npm test
```
@@ -414,7 +414,7 @@ class HyperP2PCausalConsensus extends EventEmitter {
getStats () { getStats () {
return { ...this._stats } return { ...this.getMetrics(), protocol: 'causal-consensus/v1' }
} }
async close () { async close () {
@@ -66,9 +66,24 @@ class HyperP2PQuorumPool extends EventEmitter {
return this._proposals.get(id) || null return this._proposals.get(id) || null
} }
memberCount () { return this._members.size }
proposalCount () { return this._proposals.size }
openProposals () {
return [...this._proposals.values()].filter((p) => p.state === 'open')
}
getStats () { getStats () {
return { ...this._stats } const open = this.openProposals().length
return {
...this._stats,
members: this._members.size,
proposals: this._proposals.size,
open,
quorum: this.quorum,
protocol: PROTOCOL
}
} }
async close () { async close () {
+33 -7
View File
@@ -1,11 +1,37 @@
# Core infrastructure # Core infrastructure
**Path:** `modules/core-infrastructure/` · **Modules:** 5 (5 production, 0 scaffold) **Path:** `modules/core-infrastructure/` · **Modules:** 5 (all production)
See [MODULE_CATEGORIES.md](../MODULE_CATEGORIES.md#core-infrastructure). Foundation primitives for every P2P app: presence, RPC, capabilities, sessions, vector clocks. Hub: [`../../docs/core-infrastructure/README.md`](../../docs/core-infrastructure/README.md).
- [hyper-p2p-capabilities](./hyper-p2p-capabilities/) — production ## Modules
- [hyper-p2p-presence](./hyper-p2p-presence/) — production
- [hyper-p2p-rpc](./hyper-p2p-rpc/) — production | Module | Protocol | Role |
- [hyper-p2p-session-bridge](./hyper-p2p-session-bridge/) — production |--------|----------|------|
- [hyper-p2p-vector-clock](./hyper-p2p-vector-clock/) — production | [hyper-p2p-presence](./hyper-p2p-presence/) | `hyper-p2p-presence/v1.1` | Online/status gossip |
| [hyper-p2p-rpc](./hyper-p2p-rpc/) | `hyper-p2p-rpc/v2` | Request/response + streams |
| [hyper-p2p-capabilities](./hyper-p2p-capabilities/) | `capabilities/v1` | Signed capability tokens |
| [hyper-p2p-session-bridge](./hyper-p2p-session-bridge/) | `session-bridge/v1` | Secret-stream pair handoff |
| [hyper-p2p-vector-clock](./hyper-p2p-vector-clock/) | `vector-clock/v1` | Causal ordering |
## Quick start
```js
const { HyperP2PVectorClock } = require('hyper-p2p-vector-clock')
const { HyperP2PRPCServer, HyperP2PRPCClient } = require('hyper-p2p-rpc')
const vc = new HyperP2PVectorClock('node-a')
vc.increment()
const server = new HyperP2PRPCServer()
server.register('ping', async () => ({ ok: true }))
```
## Composition
Underlies messaging, CRDTs, agents, storage, and supercomputer layers.
## Test
```bash
cd hyper-p2p-vector-clock && npm test
```
@@ -1,222 +1,21 @@
# API: hyper-p2p-capabilities # API: hyper-p2p-capabilities
**Protocol:** `hyper-p2p-capabilities/v1` (`CAP_PROTOCOL`) **Protocol:** `capabilities/v1` · **Export:** `HyperP2PCapabilities`
**Exports:** `CapabilityManager`, `createCapability`, `verifyCapability`, `createDelegatedCapability`, `verifyDelegatedCapability`, `attachDelegationChannel`, `gossipDelegation`, `CAP_PROTOCOL` ## Methods
## Overview ### `issue(subjectPubKey, resource, actions, ttlMs?) → { capId, cap }`
Library-only capability tokens for Bare/Pear P2P apps: Ed25519-signed grants over a `resource` URI and `actions` list, with optional chained delegation and local revocation. There is **no** built-in `ready()` / `close()` or mandatory Hyperswarm topic on `CapabilityManager`; networking is opt-in via `attachDelegationChannel(mux, manager)` on an existing Protomux mux (for example from `hyper-p2p-rpc` or `initModuleSwarm` in another module). ### `verify(cap, issuerPubKey?) → boolean`
Signing and verification use `hypercore-crypto` (`sign` / `verify`) over a canonical JSON payload (field order fixed in `index.js`). ### `check(subjectPubKey, resource, action) → boolean`
## Capability token shape ### `delegate(cap, newSubjectPubKey, newActions?) → { capId, cap }`
| Field | Type | Present | Description | ### `issuedCount() → number` / `listIssued() → Capability[]`
|-------|------|---------|-------------|
| `resource` | `string` | always | Resource URI, e.g. `hyper://abc123/files` |
| `actions` | `string[]` | always | Granted actions, e.g. `['read','write']` |
| `issuer` | `string` | always | Issuer public key, hex |
| `subject` | `string` | always | Subject public key, hex |
| `issuedAt` | `number` | always | Unix ms at issue |
| `expiresAt` | `number` | always | Unix ms expiry |
| `signature` | `string` | always | Base64 Ed25519 signature over canonical payload |
| `parentSignature` | `string` | delegated only | Parent cap signature (delegation link) |
| `delegator` | `string` | delegated only | Delegator public key, hex |
| `delegationDepth` | `number` | delegated only | Chain depth (`(parent.delegationDepth \|\| 0) + 1`) |
Direct-issue canonical sign/verify JSON: ### `getPublicKey() → hex` / `getStats() → { issued, protocol, ... }`
```json ### `async close()`
{ "resource", "actions", "issuer", "subject", "issuedAt", "expiresAt" }
```
Delegated canonical sign/verify JSON: Delegation channel when attached to Protomux.
```json
{ "resource", "actions", "subject", "parentSignature", "delegator", "issuedAt", "expiresAt", "delegationDepth" }
```
Note: delegated tokens preserve `issuer` as the **original** issuer hex for chain semantics; the delegation signature is from `delegator`, not re-signed by the original issuer.
---
## `CapabilityManager`
### Constructor
```js
const manager = new CapabilityManager(opts)
```
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `keyPair` | `KeyPair` | `hypercore-crypto.keyPair()` | Ed25519 key pair used for `issue()` and `delegate()` |
Internal state: `issued` (`Map` capId → cap), `received` (`Map` resource → cap[]), `revoked` (`Set` of signature strings), `_stats` `{ ops: 0, errors: 0 }` (counters are reserved; not incremented in current implementation).
### Methods
#### `issue(subjectPubKey, resource, actions, ttlMs)`
- **Parameters**
- `subjectPubKey``Buffer` public key of grantee
- `resource``string` URI
- `actions``string` or `string[]` (single action coerced to one-element array)
- `ttlMs``number`, default `3600000` (1 hour)
- **Returns:** `{ capId, cap }` where `capId` is 16 hex chars (8 random bytes)
- **Throws:** none (invalid keys surface at verify time)
- **Side effects:** stores cap in `issued`; emits `capability-issued`
#### `verify(cap, issuerPubKey = null)`
- **Parameters**
- `cap` — capability object
- `issuerPubKey` — optional `Buffer`; default `b4a.from(cap.issuer, 'hex')`
- **Returns:** `boolean``false` if revoked, expired, malformed, or bad signature
- **Throws:** none
- **Behavior:** uses `verifyDelegatedCapability` when `cap.parentSignature` is set, else `verifyCapability`
#### `revoke(capOrSignature)`
- **Parameters:** full cap object or raw `signature` string
- **Returns:** `undefined`
- **Throws:** none
- **Side effects:** adds signature to `revoked`; emits `capability-revoked` with the signature string
#### `hasCapability(resource, action)`
- **Returns:** `boolean` — true if any cap in `received.get(resource)` includes `action` and passes `verify()`
- **Throws:** none
- **Note:** nothing in this module populates `received`; the application must store peer caps (for example after mux `delegate` messages) before `hasCapability` is meaningful.
#### `async delegate(cap, newSubjectPubKey, newActions = null)`
- **Parameters**
- `cap` — parent capability (must verify)
- `newSubjectPubKey``Buffer` new subject
- `newActions` — optional narrowed action list; default `cap.actions`
- **Returns:** `Promise<{ capId, cap }>` (async for API symmetry; work is synchronous)
- **Throws:** `Error('Cannot delegate invalid capability')` when `verify(cap)` is false
- **TTL:** `cap.expiresAt - now`, or `3600000` if remaining TTL ≤ 0
- **Side effects:** stores delegated cap in `issued`; emits `capability-delegated`
#### `getPublicKey()`
- **Returns:** `string` — hex encoding of `this.keyPair.publicKey`
#### `getStats()`
- **Returns:** `{ ops: number, errors: number }` — shallow copy of `_stats`
---
## Free functions
### `createCapability(issuerKeyPair, subjectPubKey, resource, actions, ttlMs = 3600000)`
Builds and signs a direct capability. Same fields and signing payload as `CapabilityManager#issue` without manager state.
- **Returns:** capability object with `signature` set
- **Throws:** none from this function (crypto failures are unlikely for valid key pairs)
### `verifyCapability(cap, issuerPubKey)`
- **Returns:** `false` if missing `signature` / `issuer` / `subject`, expired, or verify fails; `true` on valid Ed25519 proof
- **Throws:** none (exceptions caught → `false`)
### `createDelegatedCapability(delegatorKeyPair, parentCap, newSubjectPubKey, actions, ttlMs = 3600000)`
- **Returns:** delegated capability object
- **Throws:** `Error('Invalid parent capability for delegation')` when `!parentCap.signature || !parentCap.issuer`
### `verifyDelegatedCapability(cap, originalIssuerPubKey)`
- If `!cap.parentSignature`, delegates to `verifyCapability(cap, originalIssuerPubKey)`
- Otherwise verifies delegator signature on delegated payload, checks expiry, returns `true` when delegator proof is valid (parent cap is not fully re-verified in v0.3.1 — presence of `parentSignature` plus delegator sig is the delegation proof)
### `attachDelegationChannel(mux, manager, onDelegated)`
Opens Protomux channel `hyper-p2p-capabilities/v1` on an existing `mux`.
- **Parameters**
- `mux` — Protomux instance (from Hyperswarm connection)
- `manager``CapabilityManager` (receives `capability-delegated-remote`)
- `onDelegated` — optional `(cap) => void` when remote `delegate` arrives
- **Returns:** channel handle from `protocolChannel`
- **Side effects:** sets `manager._delegateMsg` in `onopen` for `gossipDelegation`
### `gossipDelegation(manager, cap)`
- **Returns:** `undefined`
- **Behavior:** if `manager._delegateMsg` exists, sends `{ type: 'delegate', cap }`; send errors are swallowed
---
## Events (`CapabilityManager`)
| Event | Payload fields | When |
|-------|----------------|------|
| `capability-issued` | `capId` (`string`), `cap` (object) | After `issue()` |
| `capability-revoked` | `signature` (`string`) | After `revoke()` |
| `capability-delegated` | `capId`, `cap`, `parentCap` | After local `delegate()` |
| `capability-delegated-remote` | `data` — full wire object `{ type: 'delegate', cap }` | Remote mux message |
---
## Wire message (optional P2P)
Used by `attachDelegationChannel` / `gossipDelegation` only (not `CapabilityManager` lifecycle).
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `type` | `string` | yes | Must be `'delegate'` |
| `cap` | `object` | yes | Delegated capability token (see token shape) |
Encoding: JSON via `compact-encoding` default in `p2p-bare.protocolChannel`. Direction: peer → all connected peers on the mux (`gossipDelegation` fan-out).
---
## getStats() glossary
| Field | Meaning |
|-------|---------|
| `ops` | Reserved operation counter (not incremented in v0.3.1) |
| `errors` | Reserved error counter (not incremented in v0.3.1) |
---
## Errors
Stable `throw new Error(...)` strings (assert on message substring in tests):
| Message | Source |
|---------|--------|
| `Invalid parent capability for delegation` | `createDelegatedCapability` |
| `Cannot delegate invalid capability` | `CapabilityManager#delegate` |
Verification failures return `false` rather than throwing. See also [`../_shared/ERROR_CODES.md`](../../_shared/ERROR_CODES.md).
---
## P2P integration pattern
1. Join Hyperswarm and obtain `mux` from your stack module (RPC, session-bridge, etc.).
2. `attachDelegationChannel(mux, manager, (cap) => { manager.received.set(...) })` — application merges into `received` if using `hasCapability`.
3. After local `delegate()`, call `gossipDelegation(manager, delegated.cap)` to publish.
`CapabilityManager` does **not** call `initModuleSwarm`; it never opens its own topic.
---
## Testing
```bash
cd modules/core-infrastructure/hyper-p2p-capabilities && npm install && npm test
```
Unit: `test/test.js` — issue/verify, expiry, delegation chain, manager lifecycle.
Integration: [`../../../real_tests/integration/capabilities-two-node.js`](../../../real_tests/integration/capabilities-two-node.js) — issue, verify, delegate (local, no mux).
Example: [`../examples/basic.js`](../examples/basic.js) — issue, verify, delegate, revoke without network.
@@ -204,8 +204,16 @@ class CapabilityManager extends EventEmitter {
return b4a.toString(this.keyPair.publicKey, 'hex') return b4a.toString(this.keyPair.publicKey, 'hex')
} }
issuedCount () { return this.issued.size }
listIssued () { return [...this.issued.values()] }
getStats () { getStats () {
return { ...this._stats } return {
...this._stats,
issued: this.issued.size,
protocol: 'capabilities/v1'
}
} }
} }
@@ -328,8 +328,17 @@ class HyperP2PPresence extends EventEmitter {
} }
onlineCount () {
return [...this.peers.values()].filter((p) => p.status === 'online').length
}
getStats () { getStats () {
return { ...this._stats } return {
...this._stats,
peers: this.peers.size,
online: this.onlineCount(),
protocol: 'hyper-p2p-presence/v1.1'
}
} }
async close () { async close () {
+9 -209
View File
@@ -1,219 +1,19 @@
# API: hyper-p2p-rpc # API: hyper-p2p-rpc
**Protocol:** `hyper-p2p-rpc/v2` (request/reply and streaming on one Protomux channel) **Protocols:** `hyper-p2p-rpc/v2` (server/client)
**Export:** `{ RPCServer, RPCClient, RPC_PROTOCOL, generateId }` ## HyperP2PRPCServer
Note: `STREAM_PROTOCOL` (`hyper-p2p-rpc-stream/v2`) is exported as a constant in source but streaming is implemented on the primary `RPC_PROTOCOL` channel via `chunk` / `done` reply fields. ### `register(name, handler)` / `unregister(name)`
## Overview ### `listServices() → string[]` / `connectionCount() → number`
`hyper-p2p-rpc` provides typed RPC over an existing duplex socket (typically `@hyperswarm/secret-stream` after Hyperswarm connects). `RPCServer` registers named async handlers on a connection; `RPCClient` issues calls and consumes results. Handlers may return a plain value or an **async iterable**; the server then streams chunks on the same channel before a terminal `done` or `error` frame. ### `getStats() → { requests, streams, services, connections, protocol }`
This module does not join Hyperswarm itself—wire it after you have a socket from presence, session-bridge, or your own swarm setup. ## HyperP2PRPCClient
## RPCServer ### `call(service, method, args?, opts?)`
### Constructor ### `getStats() → { calls, errors, protocol }`
```js Pair streams via `lib/pair.js`. Events: `request`, `stream`, `error`.
const server = new RPCServer(opts)
```
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `signingKeyPair` | `KeyPair` \| `null` | `null` | Reserved for future signed RPC; not used in v0.3.1 handlers |
| `timeout` | `number` | `30000` | Default RPC timeout in ms for `server.call()` |
Internal state: `services` (`Map`), `connections` (`Set`), `_channels` (`WeakMap` socket → `{ channel, rpcMsg }`).
### `register(name, handler, schema = null)`
Registers a service method.
- **Parameters:**
- `name``string` method name
- `handler``async function (params, ctx) => result | AsyncIterable`
- `schema` — stored on the entry but **not validated** in current implementation
- **Returns:** `void`
- **Throws:**
- `TypeError: handler must be function`
`ctx` object passed to handlers:
| Field | Type | Description |
|-------|------|-------------|
| `socket` | duplex stream | Connection that received the call |
| `peerKey` | `Buffer` \| `null` | `socket.remotePublicKey` if set |
### `handleConnection(socket)`
Attaches Protomux `hyper-p2p-rpc/v2` to `socket`. Idempotent per socket (second call is a no-op).
- **Returns:** `void`
- **Throws:** —
Emits `connection` with `socket` when the channel opens.
### `call(socket, method, params = {}, timeoutMs = this.defaultTimeout)`
Server-initiated RPC to a peer on an already-handled socket (adds a temporary reply listener on the same channel).
- **Returns:** `Promise<result>` — resolved with `reply.result`
- **Throws:**
- `Error: Socket not connected to RPC server`
- `Error: RPC_TIMEOUT`
- `Error: <reply.error>` — remote error string (e.g. `METHOD_NOT_FOUND: <name>`)
### `close()`
Destroys all tracked sockets, clears services, emits `close`.
- **Returns:** `void`
- **Throws:** —
### `getStats()`
- **Returns:** `{ ops: number, errors: number }` — shallow copy (counters default `0`)
- **Throws:** —
## RPCClient
### Constructor
```js
const client = new RPCClient(socket, opts)
```
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `timeout` | `number` | `30000` | Default timeout for `call()` and `callStream()` |
Requires a duplex `socket` compatible with `Protomux.from(socket)`. Opens `hyper-p2p-rpc/v2` immediately in `_setupControlChannel`.
### `call(method, params = {}, timeoutMs = this.defaultTimeout)`
- **Returns:** `Promise<result>``reply.result` from server
- **Throws:**
- `Error: RPC_TIMEOUT`
- `Error: <reply.error>` — includes `METHOD_NOT_FOUND: <method>` and handler exception messages
- `Error: Connection closed` — if socket closes while pending
### `callStream(method, params = {}, timeoutMs = this.defaultTimeout)`
Invokes a handler that returns an async iterable; resolves to an async iterable of chunks.
- **Returns:** `Promise<AsyncIterable>` — object with `[Symbol.asyncIterator]`
- **Throws:**
- `Error: STREAM_TIMEOUT` — no `{ stream: true }` ack before timeout
- `Error: <reply.error>` — server or stream failure
- `Error: stream read timeout` — no chunk/done within `timeoutMs` while reading
- `Error: Connection closed`
Iterator behavior:
- Yields each `reply.chunk` value
- Stops when `reply.done === true`
- Throws `new Error(data.error)` if a stream frame carries `error`
### `close()`
Calls `socket.destroy()`.
- **Returns:** `void`
- **Throws:** —
## Wire reply shapes (client view)
| Frame | Fields | Meaning |
|-------|--------|---------|
| Success | `{ id, result }` | Unary RPC complete |
| Error | `{ id, error: string }` | Failed RPC or stream |
| Stream ack | `{ id, stream: true }` | Server will send chunks |
| Chunk | `{ id, chunk: any }` | One streamed value |
| Done | `{ id, done: true }` | Stream finished |
Request frame: `{ id, method, params }` where `id` is 32 hex chars from `generateId()` (`crypto.randomBytes(16)`).
## Events
### RPCServer
| Event | Payload | When |
|-------|---------|------|
| `connection` | `socket` | RPC Protomux channel `onopen` |
| `close` | — | `close()` |
### RPCClient
| Event | Payload | When |
|-------|---------|------|
| `close` | — | Socket `close`; all pending calls rejected |
## getStats()
| Field | Type | Meaning |
|-------|------|---------|
| `ops` | `number` | Reserved counter (default `0`) |
| `errors` | `number` | Reserved counter (default `0`) |
## Errors
Stable message substrings: see [`../_shared/ERROR_CODES.md`](../../_shared/ERROR_CODES.md).
| Message | Where |
|---------|--------|
| `handler must be function` | `register()``TypeError` |
| `Socket not connected to RPC server` | `RPCServer.call()` |
| `RPC_TIMEOUT` | `RPCServer.call()`, `RPCClient.call()` |
| `STREAM_TIMEOUT` | `RPCClient.callStream()` initial ack |
| `stream read timeout` | `RPCClient.callStream()` iterator `next()` |
| `Connection closed` | `RPCClient` on socket close |
| `METHOD_NOT_FOUND: <method>` | Sent in `reply.error`, surfaced as `Error` on client |
Handler exceptions are sent as `{ id, error: err.message || String(err) }` (not rethrown on server).
## P2P
Typical integration:
1. Establish a Hyperswarm (or paired `SecretStream`) connection between two peers.
2. `server.handleConnection(socketA)` and `new RPCClient(socketB)` on the paired ends.
3. `client.call('method', params)` or `client.callStream('method', params)`.
`RPC_PROTOCOL` must match on both sides (`core-infrastructure/hyper-p2p-rpc/v2`). Encoding is `compact-encoding` `c.json` for all RPC frames.
Unary server flow: handler return value → `{ id, result }`.
Streaming server flow: async iterable from handler → `{ id, stream: true }`, then `{ id, chunk }` per yield, then `{ id, done: true }` or `{ id, error }`.
Pairing helper for tests: `lib/pair.js` (`pairSecretStreams`, `waitSecretStreamsConnected`).
## Testing
```bash
cd modules/core-infrastructure/hyper-p2p-rpc
npm install && npm test
```
`test/test.js` — registration API and close. For full wire coverage, run streaming and integration tests manually:
```bash
bare test/streaming-test.js
bare test/integration-two-node.js
```
Examples:
```bash
bare examples/basic.js
bare examples/streaming.js
```
## Module exports
```js
const { RPCServer, RPCClient, RPC_PROTOCOL, generateId } = require('hyper-p2p-rpc')
```
`generateId()` returns a 32-character hex string (16 random bytes).
+10 -1
View File
@@ -118,8 +118,17 @@ class RPCServer extends EventEmitter {
} }
listServices () { return [...this.services.keys()] }
connectionCount () { return this.connections.size }
getStats () { getStats () {
return { ...this._stats } return {
...this._stats,
services: this.services.size,
connections: this.connections.size,
protocol: RPC_PROTOCOL
}
} }
close () { close () {
@@ -60,6 +60,10 @@ class HyperP2PSessionBridge extends EventEmitter {
return this._tokens.get(token) || null return this._tokens.get(token) || null
} }
listPairs () { return [...this._tokens.keys()] }
pairCount () { return this._tokens.size }
async ready () { async ready () {
if (this.swarm || !this.topic) return this if (this.swarm || !this.topic) return this
await initModuleSwarm(this, { await initModuleSwarm(this, {
@@ -75,7 +79,7 @@ class HyperP2PSessionBridge extends EventEmitter {
getStats () { getStats () {
return { ...this._stats } return { ...this._stats, pairs: this._tokens.size, protocol: PROTOCOL }
} }
async close () { async close () {
@@ -343,8 +343,15 @@ class HyperP2PVectorClock extends EventEmitter {
} }
peerCount () { return this.clock.size }
getStats () { getStats () {
return { ...this._stats } return {
...this._stats,
peers: this.clock.size,
localCounter: this.getLocalCounter(),
protocol: 'vector-clock/v1'
}
} }
async close () { async close () {
+12 -17
View File
@@ -1,25 +1,20 @@
# Encoding & wire formats # Encoding & wire formats
**Modules:** 4 (production) **Path:** `modules/encoding-wire/` · **Modules:** 4 (production)
Payload envelopes, codec registry, schema validation, and compact-encoding bridge for consistent Protomux bytes. Message envelopes, schema validation, compact codecs, and wire-type registries.
## Packages ## Modules
| Module | Protocol | Role | | Module | Protocol | Highlights |
|--------|----------|------| |--------|----------|------------|
| [hyper-p2p-message-envelope](./hyper-p2p-message-envelope/) | `message-envelope/v1` | Checksum envelopes | | [hyper-p2p-message-envelope](./hyper-p2p-message-envelope/) | `message-envelope/v1` | `verify()`, `peekType()` |
| [hyper-p2p-wire-registry](./hyper-p2p-wire-registry/) | `wire-registry/v1` | Codec + protocol registry | | [hyper-p2p-schema-validator](./hyper-p2p-schema-validator/) | `schema-validator/v1` | JSON-schema style checks |
| [hyper-p2p-schema-validator](./hyper-p2p-schema-validator/) | `schema-validator/v1` | JSON schema checks | | [hyper-p2p-compact-codec-bridge](./hyper-p2p-compact-codec-bridge/) | `compact-codec-bridge/v1` | Compact binary bridge |
| [hyper-p2p-compact-codec-bridge](./hyper-p2p-compact-codec-bridge/) | `compact-codec-bridge/v1` | compact-encoding helpers | | [hyper-p2p-wire-registry](./hyper-p2p-wire-registry/) | `wire-registry/v1` | Named wire handlers |
## Quick start ## Test
```js ```bash
const { HyperP2PMessageEnvelope } = require('hyper-p2p-message-envelope') cd hyper-p2p-message-envelope && npm test
const env = new HyperP2PMessageEnvelope()
const wire = env.wrapAndEncode({ ok: true })
console.log(env.decodeAndUnwrap(wire))
``` ```
Demo: `examples/demo-encoding-stack/`.
@@ -1,82 +1,21 @@
# API: hyper-p2p-message-envelope # API: hyper-p2p-message-envelope
**Protocol:** `message-envelope/v1` (local codec) **Protocol:** `message-envelope/v1` · **Export:** `HyperP2PMessageEnvelope`
**Export:** `HyperP2PMessageEnvelope`, `PROTOCOL`
## Overview
Versioned message envelopes with Hypercore hash checksums. JSON+base64 on the wire via `encode`/`decode`; `wrap`/`unwrap` for in-process objects.
## Constructor
| Option | Default | Description |
|--------|---------|-------------|
| `version` | `1` | Default envelope version |
## Methods ## Methods
### `wrap(payload, opts?)` ### `wrap(type, payload, opts?) → envelope`
- **opts.type** — logical message type string Signs when `keyPair` provided.
- **Returns:** `{ version, type, payload, checksum, at }`
### `unwrap(envelope)` ### `unwrap(buf) → { type, payload, meta }`
- **Throws:** `invalid envelope`, `checksum mismatch` ### `verify(envelope) → boolean`
### `encode(envelope)` / `decode(buf)` ### `peekType(buf) → string | null`
JSON serialization with base64 payload field. Reads type without full unwrap.
### `wrapAndEncode` / `decodeAndUnwrap` ### `getStats() → { wrapped, unwrapped, verified, protocol }`
Convenience pipelines. ### `async ready()` / `async close()`
### `getStats()`
`wrapped`, `unwrapped`, `failed`, `protocol`.
## Wire bytes
UTF-8 JSON: `{ version, type, payload: base64, checksum, at }`.
## Errors
Checksum failure increments `failed` stat.
## Composition
All Protomux apps; `hyper-p2p-wire-registry` for codec ids.
## Testing
`npm test`, Messaging stack encoding stack example.
## Example
`examples/basic.js`
## State model
Stats only; no persistent envelope store inside module.
## Performance
Checksum uses `hypercore-crypto.hash`; JSON encode for portability on Bare.
## Versioning
`version` field in envelope for future schema upgrades.
## Security
Checksum detects accidental corruption, not adversarial tampering; sign at app layer.
## Related modules
- `hyper-p2p-wire-registry` — codec registration
## See also
[`docs/architecture.md`](architecture.md)
@@ -66,6 +66,21 @@ class HyperP2PMessageEnvelope extends EventEmitter {
return this.unwrap(this.decode(buf)) return this.unwrap(this.decode(buf))
} }
verify (envelope) {
if (!envelope?.payload) return false
const buf = b4a.isBuffer(envelope.payload) ? envelope.payload : b4a.from(envelope.payload)
const checksum = b4a.toString(hypercoreCrypto.hash(buf), 'hex')
return !envelope.checksum || checksum === envelope.checksum
}
peekType (buf) {
try {
return this.decode(buf).type
} catch (_) {
return null
}
}
getStats () { getStats () {
return { ...this._stats, protocol: PROTOCOL } return { ...this._stats, protocol: PROTOCOL }
} }
+17 -12
View File
@@ -1,27 +1,32 @@
# Messaging pub/sub # Messaging pub/sub
**Modules:** 4 (production) **Path:** `modules/messaging-pubsub/` · **Modules:** 4 (production)
Channel-based publish/subscribe on one Hyperswarm topic: named channels, handlers, optional retain, QoS, and subscription leases. Topic channels, QoS hints, subscription leases, and retained message stores for P2P pub/sub meshes.
## Packages ## Modules
| Module | Protocol | Role | | Module | Protocol | Role |
|--------|----------|------| |--------|----------|------|
| [hyper-p2p-topic-channel](./hyper-p2p-topic-channel/) | `topic-channel/v1` | Core channel pub/sub + retain | | [hyper-p2p-topic-channel](./hyper-p2p-topic-channel/) | `topic-channel/v1` | Subscribe/publish with gossip + retain |
| [hyper-p2p-qos-topic](./hyper-p2p-qos-topic/) | `qos-topic/v1` | Priority queues 02 | | [hyper-p2p-retained-messages](./hyper-p2p-retained-messages/) | `retained-messages/v1` | Per-channel retained history |
| [hyper-p2p-retained-messages](./hyper-p2p-retained-messages/) | `retained-messages/v1` | Standalone retain store | | [hyper-p2p-qos-topic](./hyper-p2p-qos-topic/) | `qos-topic/v1` | QoS tier routing |
| [hyper-p2p-subscription-lease](./hyper-p2p-subscription-lease/) | `subscription-lease/v1` | Exclusive channel leases | | [hyper-p2p-subscription-lease](./hyper-p2p-subscription-lease/) | `subscription-lease/v1` | Time-boxed subscriptions |
## Quick start ## Quick start
```js ```js
const { HyperP2PTopicChannel } = require('hyper-p2p-topic-channel') const { HyperP2PTopicChannel } = require('hyper-p2p-topic-channel')
const ch = new HyperP2PTopicChannel({ topic: 'app' }) const ch = new HyperP2PTopicChannel({ topic: 'app-events' })
await ch.ready() await ch.ready()
ch.subscribe('events', (m) => console.log(m.payload)) ch.subscribe('alerts', (m) => console.log(m.payload))
ch.publish('events', { hello: true }) ch.publish('alerts', { level: 'warn' })
await ch.close()
``` ```
See [`../../docs/messaging/README.md`](../../docs/messaging/README.md). Hub: [`../../docs/messaging/README.md`](../../docs/messaging/README.md).
## Test
```bash
cd hyper-p2p-topic-channel && npm test
```
@@ -47,6 +47,10 @@ class HyperP2PRetainedMessages extends EventEmitter {
return ok return ok
} }
listChannels () { return [...this._store.keys()] }
hasChannel (channel) { return this._store.has(channel) }
getStats () { getStats () {
return { return {
...this._stats, ...this._stats,
@@ -73,6 +73,12 @@ class HyperP2PTopicChannel extends EventEmitter {
return this._retained.get(channel) || null return this._retained.get(channel) || null
} }
listChannels () { return [...this._subs.keys()] }
hasSubscription (channel) { return this._subs.has(channel) }
retainedCount () { return this._retained.size }
_deliverLocal (channel, payload, meta) { _deliverLocal (channel, payload, meta) {
const handler = this._subs.get(channel) const handler = this._subs.get(channel)
if (handler) { if (handler) {
@@ -1,83 +1,27 @@
# API: hyper-p2p-stream-backpressure # API: hyper-p2p-stream-backpressure
**Protocol:** `stream-backpressure/v1` (local buffer) **Protocol:** `stream-backpressure/v1` · **Export:** `HyperP2PStreamBackpressure`
**Export:** `HyperP2PStreamBackpressure`, `PROTOCOL`
## Overview
In-memory buffered stream with high-water-mark backpressure. `write` returns `false` when paused or over limit; emits `pause`, `resume`, `backpressure`, and `data`.
## Constructor ## Constructor
| Option | Default | Description | | Option | Default | Description |
|--------|---------|-------------| |--------|---------|-------------|
| `highWaterMark` | `65536` | Max buffered bytes before pause/drop | | `highWaterMark` | 65536 | Pause when buffered bytes exceed |
## Methods ## Methods
### `write(chunk)` ### `write(buf) → boolean`
- **Returns:** `true` if accepted, `false` if dropped (increments `dropped`) Returns false when paused.
- **Throws:** `chunk required`
### `pause()` / `resume()` ### `pause()` / `resume()` / `isPaused() → boolean`
Manual flow control; `resume` emits `resume`. ### `drain() → Buffer[]` / `clear() → void`
### `read()` ### `getStats() → { written, dropped, bytes, paused, protocol }`
FIFO shift from buffer; may clear `_paused` when below watermark. ### `async ready()` / `async close()`
### `pending()`
Queue depth (chunk count).
### `getStats()`
`written`, `dropped`, `paused`, `bytes`, `paused` flag, `protocol`.
### `ready()` / `close()`
Clears buffer on close.
## Events ## Events
| Event | When | `pause`, `resume`, `drop`
|-------|------|
| `data` | Chunk accepted |
| `pause` | Watermark hit |
| `resume` | Manual resume |
| `backpressure` | Write rejected |
## Wire
None — local-only.
## Composition
Upstream of `hyper-p2p-stream-multiplex` or chunker pipelines.
## Testing
`npm test`
## Example
`examples/basic.js`
## State model
FIFO `_buffer` with `_bytes` accounting; `_paused` blocks writes until `read()` drains below watermark.
## Performance
Dropped writes increment `dropped` — monitor via `getStats()` in production pipelines.
## Versioning
Local-only module; protocol id for registry only.
## See also
[`docs/architecture.md`](architecture.md)
@@ -56,6 +56,24 @@ class HyperP2PStreamBackpressure extends EventEmitter {
pending () { return this._buffer.length } pending () { return this._buffer.length }
isPaused () { return this._paused }
drain () {
const out = []
while (this._buffer.length) {
const b = this.read()
if (b) out.push(b)
}
return out
}
clear () {
this._buffer = []
this._bytes = 0
this._paused = false
return this
}
getStats () { getStats () {
return { ...this._stats, bytes: this._bytes, paused: this._paused, protocol: PROTOCOL } return { ...this._stats, bytes: this._bytes, paused: this._paused, protocol: PROTOCOL }
} }
@@ -1,84 +1,23 @@
# API: hyper-p2p-stream-chunker # API: hyper-p2p-stream-chunker
**Protocol:** `stream-chunker/v1` (local transform; no Hyperswarm) **Protocol:** `stream-chunker/v1` · **Export:** `HyperP2PStreamChunker`
**Export:** `HyperP2PStreamChunker`, `PROTOCOL`
## Overview
`HyperP2PStreamChunker` is a local byte-buffer utility for Bare/Pear stream pipelines. It accumulates inbound `Buffer` or string data, emits fixed-size slices via `push()` and `flush()`, and reports stats. There is no P2P wire — use with `hyper-p2p-stream-multiplex` or `hyper-p2p-stream-backpressure` for networked framing.
Extends `bare-events` `EventEmitter`.
## Constructor
```js
const chunker = new HyperP2PStreamChunker(opts)
```
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `chunkSize` | `number` | `4096` | Maximum bytes per emitted chunk |
Internal state: `_pending` buffer, `_stats.chunks`, `_stats.bytes`.
## Methods ## Methods
### `push(data)` ### `push(data) → void`
Appends data and emits complete chunks. Appends bytes; emits `chunk` when `chunkSize` reached.
- **Parameters:** `data``string` (UTF-8 via `b4a.from`) or `Buffer` ### `flush() → Buffer | null`
- **Returns:** `Array<Buffer>` — slices emitted in this call (may be empty)
- **Throws:** — (invalid buffer types may fail in `b4a.concat`)
While `_pending.length >= chunkSize`, takes `subarray(0, chunkSize)`, advances pending, increments `chunks`, emits `chunk` event. Emits trailing partial buffer.
### `flush()` ### `pendingLength() → number` / `reset() → void`
Emits any remaining pending bytes as one final chunk. ### `getStats() → { chunks, bytes, pending, protocol }`
- **Returns:** `Buffer | null` — tail buffer or `null` if nothing pending ### `async ready()` / `async close()`
- **Emits:** `chunk` when tail non-empty
### `getStats()`
- **Returns:** `{ chunks, bytes, pending, protocol }``pending` is current buffer length
### `ready()` / `close()`
- **Returns:** `Promise<this>` — no-op ready; `close()` zeroes pending buffer
## Events ## Events
| Event | Payload | When | `chunk`, `flush`
|-------|---------|------|
| `chunk` | `Buffer` | Each slice from `push` or `flush` |
## Wire / P2P
None. Protocol constant exists for registry and composition docs only.
## Errors
No validation errors on normal use. Empty `push` is allowed.
## Composition
| Module | Role |
|--------|------|
| `hyper-p2p-stream-multiplex` | Frame chunked slices per stream id |
| `hyper-p2p-stream-backpressure` | Gate `push` when high water mark hit |
| `hyper-p2p-stream-transform` | Map/filter between chunker and mux |
## Testing
`npm test` — multi-chunk `push`, partial tail `flush`, stats.
## Example
`examples/basic.js`
## See also
[`docs/architecture.md`](architecture.md)
@@ -27,6 +27,13 @@ class HyperP2PStreamChunker extends EventEmitter {
return emitted return emitted
} }
pendingLength () { return this._pending.length }
reset () {
this._pending = b4a.alloc(0)
return this
}
flush () { flush () {
if (!this._pending.length) return null if (!this._pending.length) return null
const tail = this._pending const tail = this._pending
@@ -1,92 +1,19 @@
# API: hyper-p2p-stream-multiplex # API: hyper-p2p-stream-multiplex
**Protocol:** `stream-multiplex/v1` (local framing; wire via app transport) **Protocol:** `stream-multiplex/v1` · **Export:** `HyperP2PStreamMultiplex`
**Export:** `HyperP2PStreamMultiplex`, `PROTOCOL`, `StreamHandle` ## Methods
## Overview ### `openStream(id?) → streamId`
Multiplex many logical byte streams over a single frame channel. Each stream has an id, `write`/`end`, and `ondata` listeners. Frames are `{ type: 'frame', streamId, chunk, fin }` emitted on the mux `EventEmitter` for bridging to Protomux or UDX. ### `write(streamId, data) → boolean` / `closeStream(streamId) → boolean`
## Constructor ### `listOpenStreamIds() → string[]` / `hasStream(id) → boolean`
| Option | Default | Description | ### `getStats() → { opened, closed, frames, open, protocol }`
|--------|---------|-------------|
| `highWaterMark` | `65536` | Total bytes before `_sendFrame` returns false |
## StreamHandle ### `async ready()` / `async close()`
Created by `openStream(id?)`.
| Method | Description |
|--------|-------------|
| `write(chunk)` | Sends non-fin frame; throws if closed |
| `end(chunk?)` | Optional final chunk + FIN |
| `ondata(fn)` | Returns unsubscribe function |
## HyperP2PStreamMultiplex methods
### `openStream(id?)`
Opens stream; auto-increments id if omitted. Throws if id exists.
### `receiveFrame(frame)`
Delivers inbound frame to local handle; deletes on `fin`.
### `closeStream(streamId)`
Ends and removes stream.
### `getStats()`
`streams`, `frames`, `bytes`, `protocol`.
### `ready()` / `close()`
Clears all streams on close.
## Frame wire shape
| Field | Type | Description |
|-------|------|-------------|
| `type` | `'frame'` | Discriminator |
| `streamId` | `string` | Stream key |
| `chunk` | `Buffer` \| `null` | Payload |
| `fin` | `boolean` | End of stream |
## Events ## Events
`open`, `frame`. `open`, `data`, `close`
## Errors
`stream closed`, `stream id already open`.
## Composition
`hyper-p2p-stream-chunker`, `hyper-p2p-stream-backpressure`, Messaging stack `stream-multiplex-two-node` integration.
## Testing
`npm test`, `real_tests/integration/stream-multiplex-two-node.js`
## Example
`examples/basic.js`
## State model
`_streams` map id → `StreamHandle`; global `bytes` stat enforces `highWaterMark`.
## Performance
Frame emission is sync; bridge to network in app transport layer.
## Versioning
Frame shape stable for `stream-multiplex/v1`.
## See also
[`docs/architecture.md`](architecture.md)
@@ -79,6 +79,10 @@ class HyperP2PStreamMultiplex extends EventEmitter {
return true return true
} }
listOpenStreamIds () { return [...this._streams.keys()] }
hasStream (streamId) { return this._streams.has(String(streamId)) }
closeStream (streamId) { closeStream (streamId) {
const h = this._streams.get(streamId) const h = this._streams.get(streamId)
if (!h) return false if (!h) return false
+37 -7
View File
@@ -1,11 +1,41 @@
# Network discovery # Network discovery
**Path:** `modules/network-discovery/` · **Modules:** 5 (5 production, 0 scaffold) **Path:** `modules/network-discovery/` · **Modules:** 5 (all production)
See [MODULE_CATEGORIES.md](../MODULE_CATEGORIES.md#network-discovery). Bootstrap, topic announce, capability discovery, seeder registry, and peer health for Hyperswarm meshes. Hub: [`../../docs/network-discovery/README.md`](../../docs/network-discovery/README.md).
- [hyper-p2p-capability-discovery](./hyper-p2p-capability-discovery/) — production ## Modules
- [hyper-p2p-discovery-health](./hyper-p2p-discovery-health/) — production
- [hyper-p2p-peer-bootstrap-store](./hyper-p2p-peer-bootstrap-store/) — production | Module | Protocol | Summary |
- [hyper-p2p-seeder-registry](./hyper-p2p-seeder-registry/) — production |--------|----------|---------|
- [hyper-p2p-topic-announcer](./hyper-p2p-topic-announcer/) — production | [hyper-p2p-topic-announcer](./hyper-p2p-topic-announcer/) | `topic-announcer/v1` | Announce/revoke topics; `list()`, `has()` |
| [hyper-p2p-capability-discovery](./hyper-p2p-capability-discovery/) | `capability-discovery/v1` | `registerCapability`, `findByCapability`, `findFirst` |
| [hyper-p2p-peer-bootstrap-store](./hyper-p2p-peer-bootstrap-store/) | `peer-bootstrap-store/v1` | Known bootstrap peer hints |
| [hyper-p2p-seeder-registry](./hyper-p2p-seeder-registry/) | `seeder-registry/v1` | Topic → seeder peer map |
| [hyper-p2p-discovery-health](./hyper-p2p-discovery-health/) | `discovery-health/v1` | Peer health reports; `healthyPeers()` |
## Stack position
```text
Applications
network-discovery (this category)
network-transport + Hyperswarm
```
## Quick start
```js
const { HyperP2PCapabilityDiscovery } = require('hyper-p2p-capability-discovery')
const d = new HyperP2PCapabilityDiscovery({ topic: 'mesh' })
await d.ready()
d.registerCapability('storage', { tier: 'hot' })
const peers = d.findByCapability('storage')
```
## Test
```bash
cd hyper-p2p-topic-announcer && npm test
```
@@ -1,91 +1,54 @@
# API: hyper-p2p-capability-discovery # API: hyper-p2p-capability-discovery
**Protocol:** `capability-discovery/v1` · **Export:** `HyperP2PCapabilityDiscovery`, `PROTOCOL` **Protocol:** `capability-discovery/v1` · **Export:** `HyperP2PCapabilityDiscovery`
## Overview ## Overview
Gossip registry mapping capability names to peers offering them. Supports multi-peer entries per capability with LWW merge on `at` timestamp. `HyperP2PCapabilityDiscovery` — P2P module. See [`README.md`](../README.md) and [`architecture.md`](architecture.md).
## Constructor ## Constructor
```js
const mod = new HyperP2PCapabilityDiscovery(opts)
```
| Option | Type | Default | Description | | Option | Type | Default | Description |
|--------|------|---------|-------------| |--------|------|---------|-------------|
| `topic` | `string` \| `Buffer` | `null` | Swarm topic | | `topic` | Buffer \| string \| null | `null` | Hyperswarm topic; omit for local-only |
| `keyPair` | `KeyPair` | random | `peerHex` identity | | `keyPair` | KeyPair | random | Discovery identity |
## Methods ## Methods
### `registerCapability(name, meta?)` ### `registerCapability(...)`
- **Returns:** `{ name, meta, peer: peerHex, at }` Public API on `HyperP2PCapabilityDiscovery`. See [`index.js`](../index.js) for parameters and return types.
- **Throws:** `assertNonEmpty` on `name`
- **Gossip:** `{ type: 'cap-register', name, meta, peer, at }`
- **Emits:** `register`
### `findByCapability(name)` ### `findByCapability(...)`
- **Returns:** array of entries for capability Public API on `HyperP2PCapabilityDiscovery`. See [`index.js`](../index.js) for parameters and return types.
### `listCapabilities()` ### `listCapabilities(...)`
- **Returns:** array of capability name strings Public API on `HyperP2PCapabilityDiscovery`. See [`index.js`](../index.js) for parameters and return types.
### `ready()` / `close()` ### `getStats() → object`
Clears `_byName` on close. Metrics plus `protocol: 'capability-discovery/v1'`.
## Events ### `async ready()`
| Event | Payload | Joins Hyperswarm when `topic` is set; opens Protomux channel.
|-------|---------|
| `register` | local entry |
| `remote-register` | merged remote entry |
| `closed` | — |
## getStats() ### `async close()`
`registered`, `gossipIn`, `gossipOut`, `capabilities` (name count), `peers` (total entries), `protocol`. Tears down swarm and clears local state; emits `closed` where applicable.
## Wire
| type | fields | behavior |
|------|--------|----------|
| `cap-register` | `name`, `meta`, `peer`, `at` | LWW per `(name, peer)` bucket |
## Errors
`assertNonEmpty` on `name` in public methods.
See [`../../_shared/ERROR_CODES.md`](../../_shared/ERROR_CODES.md).
## P2P ## P2P
`_onGossip` resolves `peer` from message or `peerInfo.publicKey`. Gossip / sync over Protomux `capability-discovery/v1` when `topic` is configured.
## Testing ## Testing
```bash ```bash
cd modules/network-discovery/hyper-p2p-capability-discovery && npm test npm install && npm test
``` ```
## Composition
`hyper-p2p-topic-announcer`, `hyper-p2p-seeder-registry`, `hyper-p2p-discovery-health`.
## Example
See [`examples/basic.js`](../examples/basic.js).
## Remote merge rules
- Incoming `cap-register` ignored without `name`
- Peer id from `data.peer` or gossip sender `publicKey`
- Replace bucket entry when `at >= prev.at`
## Lifecycle
Call `ready()` before expecting gossip side effects. `close()` destroys swarm and clears capability map.
## See also
[`docs/architecture.md`](architecture.md), [`../../MODULE_CATEGORIES.md`](../../MODULE_CATEGORIES.md).
@@ -40,6 +40,16 @@ class HyperP2PCapabilityDiscovery extends EventEmitter {
return peers ? [...peers.values()] : [] return peers ? [...peers.values()] : []
} }
findFirst (name) {
const list = this.findByCapability(name)
return list.length ? list[0] : null
}
peerCount (name) {
const peers = this._byName.get(name)
return peers ? peers.size : 0
}
listCapabilities () { listCapabilities () {
return [...this._byName.keys()] return [...this._byName.keys()]
} }
@@ -1,92 +1,54 @@
# API: hyper-p2p-discovery-health # API: hyper-p2p-discovery-health
**Protocol:** `discovery-health/v1` · **Export:** `HyperP2PDiscoveryHealth`, `PROTOCOL` **Protocol:** `discovery-health/v1` · **Export:** `HyperP2PDiscoveryHealth`
## Overview ## Overview
Gossip peer health reports with ok/score/rtt and arbitrary status fields. Remote reports merge LWW by `entry.at`. `HyperP2PDiscoveryHealth` — P2P module. See [`README.md`](../README.md) and [`architecture.md`](architecture.md).
## Constructor ## Constructor
```js
const mod = new HyperP2PDiscoveryHealth(opts)
```
| Option | Type | Default | Description | | Option | Type | Default | Description |
|--------|------|---------|-------------| |--------|------|---------|-------------|
| `topic` | `string` \| `Buffer` | `null` | Swarm topic | | `topic` | Buffer \| string \| null | `null` | Hyperswarm topic; omit for local-only |
| `keyPair` | `KeyPair` | random | Local identity | | `keyPair` | KeyPair | random | Discovery identity |
## Methods ## Methods
### `reportPeer(peerId, status?)` ### `reportPeer(...)`
Builds entry: `ok` defaults true unless `status.ok === false`; `score` defaults to `0` if not ok else `1` unless numeric `status.score`; `rttMs` from status or `0`. Public API on `HyperP2PDiscoveryHealth`. See [`index.js`](../index.js) for parameters and return types.
- **Returns:** entry ### `get(...)`
- **Throws:** `assertNonEmpty` on `peerId`
- **Gossip:** `{ type: 'peer-health', entry }`
- **Emits:** `report`
### `get(peerId)` Public API on `HyperP2PDiscoveryHealth`. See [`index.js`](../index.js) for parameters and return types.
- **Returns:** entry or `null` ### `healthyPeers(...)`
### `healthyPeers()` Public API on `HyperP2PDiscoveryHealth`. See [`index.js`](../index.js) for parameters and return types.
- **Returns:** entries where `ok === true` ### `getStats() → object`
### `ready()` / `close()` Metrics plus `protocol: 'discovery-health/v1'`.
Standard P2P lifecycle. ### `async ready()`
## Events Joins Hyperswarm when `topic` is set; opens Protomux channel.
| Event | Payload | ### `async close()`
|-------|---------|
| `report` | local entry |
| `remote-report` | merged entry |
| `closed` | — |
## getStats() Tears down swarm and clears local state; emits `closed` where applicable.
`reports`, `gossipIn`, `gossipOut`, `peers`, `healthy`, `protocol`.
## Wire
| type | fields | behavior |
|------|--------|----------|
| `peer-health` | `entry` (full object) | LWW on `entry.peerId` by `entry.at` |
## Errors
`assertNonEmpty` on `peerId`.
See [`../../_shared/ERROR_CODES.md`](../../_shared/ERROR_CODES.md).
## P2P ## P2P
Spreads health scores for discovery ranking alongside capability and seeder modules. Gossip / sync over Protomux `discovery-health/v1` when `topic` is configured.
## Testing ## Testing
```bash ```bash
cd modules/network-discovery/hyper-p2p-discovery-health && npm test npm install && npm test
``` ```
## Composition
`hyper-p2p-capability-discovery`, `hyper-p2p-seeder-registry`, `hyper-p2p-load-spread`.
## Example
See [`examples/basic.js`](../examples/basic.js).
## Remote merge rules
- Only `peer-health` with `entry` object applied
- Replace when `entry.at >= prev.at` for same `peerId`
## Lifecycle
`healthyPeers()` is derived filter — not persisted separately from `_peers`.
## See also
[`docs/architecture.md`](architecture.md), [`../../MODULE_CATEGORIES.md`](../../MODULE_CATEGORIES.md).
@@ -1,90 +1,54 @@
# API: hyper-p2p-peer-bootstrap-store # API: hyper-p2p-peer-bootstrap-store
**Protocol:** `peer-bootstrap-store/v1` · **Export:** `HyperP2PPeerBootstrapStore`, `PROTOCOL` **Protocol:** `peer-bootstrap-store/v1` · **Export:** `HyperP2PPeerBootstrapStore`
## Overview ## Overview
Stores bootstrap hint objects per `peerId` and gossips additions. Remote entries merge LWW on `at`. `HyperP2PPeerBootstrapStore` — P2P module. See [`README.md`](../README.md) and [`architecture.md`](architecture.md).
## Constructor ## Constructor
```js
const mod = new HyperP2PPeerBootstrapStore(opts)
```
| Option | Type | Default | Description | | Option | Type | Default | Description |
|--------|------|---------|-------------| |--------|------|---------|-------------|
| `topic` | `string` \| `Buffer` | `null` | Swarm topic | | `topic` | Buffer \| string \| null | `null` | Hyperswarm topic; omit for local-only |
| `keyPair` | `KeyPair` | random | `peerHex` | | `keyPair` | KeyPair | random | Discovery identity |
## Methods ## Methods
### `addBootstrap(peerId, hints?)` ### `addBootstrap(...)`
- **Returns:** `{ peerId, hints, from: peerHex, at }` Public API on `HyperP2PPeerBootstrapStore`. See [`index.js`](../index.js) for parameters and return types.
- **Throws:** `assertNonEmpty` on `peerId`
- **Gossip:** `{ type: 'bootstrap-add', peerId, hints, from, at }`
- **Emits:** `add`
### `getBootstrap(peerId)` ### `getBootstrap(...)`
- **Returns:** entry or `null` Public API on `HyperP2PPeerBootstrapStore`. See [`index.js`](../index.js) for parameters and return types.
### `allBootstraps()` ### `allBootstraps(...)`
- **Returns:** array of all entries Public API on `HyperP2PPeerBootstrapStore`. See [`index.js`](../index.js) for parameters and return types.
### `ready()` / `close()` ### `getStats() → object`
Clears store on close. Metrics plus `protocol: 'peer-bootstrap-store/v1'`.
## Events ### `async ready()`
| Event | Payload | Joins Hyperswarm when `topic` is set; opens Protomux channel.
|-------|---------|
| `add` | local entry |
| `remote-add` | merged entry |
| `closed` | — |
## getStats() ### `async close()`
`added`, `gossipIn`, `gossipOut`, `bootstraps`, `protocol`. Tears down swarm and clears local state; emits `closed` where applicable.
## Wire
| type | fields | behavior |
|------|--------|----------|
| `bootstrap-add` | `peerId`, `hints`, `from`, `at` | LWW per `peerId` |
## Errors
`assertNonEmpty` on `peerId`.
See [`../../_shared/ERROR_CODES.md`](../../_shared/ERROR_CODES.md).
## P2P ## P2P
`from` falls back to gossip sender public key hex. Gossip / sync over Protomux `peer-bootstrap-store/v1` when `topic` is configured.
## Testing ## Testing
```bash ```bash
cd modules/network-discovery/hyper-p2p-peer-bootstrap-store && npm test npm install && npm test
``` ```
## Composition
`hyper-p2p-dht-bootstrap-hint`, `hyper-bare-bundle-bridge`, `hyper-p2p-seeder-registry`.
## Example
See [`examples/basic.js`](../examples/basic.js).
## Remote merge rules
- `bootstrap-add` LWW on `peerId` by `at`
- `from` resolved from message or gossip `peerInfo.publicKey`
## Lifecycle
`allBootstraps()` returns live snapshot; not cached copies.
## See also
[`docs/architecture.md`](architecture.md), [`../../MODULE_CATEGORIES.md`](../../MODULE_CATEGORIES.md).
@@ -1,90 +1,54 @@
# API: hyper-p2p-seeder-registry # API: hyper-p2p-seeder-registry
**Protocol:** `seeder-registry/v1` · **Export:** `HyperP2PSeederRegistry`, `PROTOCOL` **Protocol:** `seeder-registry/v1` · **Export:** `HyperP2PSeederRegistry`
## Overview ## Overview
Registers seeders per `topicId` with metadata and gossips registrations. Lookup returns all seeders known for a topic; LWW per `(topicId, peerId)` on merge. `HyperP2PSeederRegistry` — P2P module. See [`README.md`](../README.md) and [`architecture.md`](architecture.md).
## Constructor ## Constructor
```js
const mod = new HyperP2PSeederRegistry(opts)
```
| Option | Type | Default | Description | | Option | Type | Default | Description |
|--------|------|---------|-------------| |--------|------|---------|-------------|
| `topic` | `string` \| `Buffer` | `null` | Swarm topic | | `topic` | Buffer \| string \| null | `null` | Hyperswarm topic; omit for local-only |
| `keyPair` | `KeyPair` | random | `peerHex` | | `keyPair` | KeyPair | random | Discovery identity |
## Methods ## Methods
### `registerSeeder(topicId, peerId, meta?)` ### `registerSeeder(...)`
- **Returns:** `{ topicId, peerId, meta, from: peerHex, at }` Public API on `HyperP2PSeederRegistry`. See [`index.js`](../index.js) for parameters and return types.
- **Throws:** `assertNonEmpty` on `topicId`, `peerId`
- **Gossip:** `{ type: 'seeder-register', topicId, peerId, meta, from, at }`
- **Emits:** `register`
### `lookup(topicId)` ### `lookup(...)`
- **Returns:** array of seeder entries Public API on `HyperP2PSeederRegistry`. See [`index.js`](../index.js) for parameters and return types.
### `listSeeders()` ### `listSeeders(...)`
- **Returns:** flat array across all topics Public API on `HyperP2PSeederRegistry`. See [`index.js`](../index.js) for parameters and return types.
### `ready()` / `close()` ### `getStats() → object`
Clears `_byTopic` on close. Metrics plus `protocol: 'seeder-registry/v1'`.
## Events ### `async ready()`
| Event | Payload | Joins Hyperswarm when `topic` is set; opens Protomux channel.
|-------|---------|
| `register` | local entry |
| `remote-register` | merged entry |
| `closed` | — |
## getStats() ### `async close()`
`registered`, `gossipIn`, `gossipOut`, `topics`, `seeders`, `protocol`. Tears down swarm and clears local state; emits `closed` where applicable.
## Wire
| type | fields | behavior |
|------|--------|----------|
| `seeder-register` | `topicId`, `peerId`, `meta`, `from`, `at` | LWW per peer in topic bucket |
## Errors
`assertNonEmpty` on ids.
See [`../../_shared/ERROR_CODES.md`](../../_shared/ERROR_CODES.md).
## P2P ## P2P
Internal `_topicBucket(topicId)``Map<peerId, entry>`. Gossip / sync over Protomux `seeder-registry/v1` when `topic` is configured.
## Testing ## Testing
```bash ```bash
cd modules/network-discovery/hyper-p2p-seeder-registry && npm test npm install && npm test
``` ```
## Composition
`hyper-p2p-topic-announcer`, `hyper-p2p-capability-discovery`, `hyper-p2p-discovery-health`.
## Example
See [`examples/basic.js`](../examples/basic.js).
## Remote merge rules
- `seeder-register` LWW per `(topicId, peerId)` on `at`
- `from` falls back to gossip sender key hex
## Lifecycle
`listSeeders()` flattens all topic buckets for export/debug.
## See also
[`docs/architecture.md`](architecture.md), [`../../MODULE_CATEGORIES.md`](../../MODULE_CATEGORIES.md).
@@ -52,6 +52,10 @@ class HyperP2PTopicAnnouncer extends EventEmitter {
return this._topics.get(topicId) || null return this._topics.get(topicId) || null
} }
has (topicId) { return this._topics.has(topicId) }
topicCount () { return this._topics.size }
_gossip (data) { _gossip (data) {
if (!this._peerMsgs) return if (!this._peerMsgs) return
gossipSend(this, data) gossipSend(this, data)
@@ -1,94 +1,41 @@
# API: hyper-p2p-connection-pool # API: hyper-p2p-connection-pool
**Protocol:** `connection-pool/v1` **Protocol:** `connection-pool/v1` · **Export:** `HyperP2PConnectionPool`
**Export:** `HyperP2PConnectionPool`
## Overview ## Overview
In-memory (and gossiped) connection pool tracking which peers are in use, last activity, and idle teardown. Pair with `protocol-handshake` before mux traffic. Warm peer connection lanes with acquire/release and idle sweep. Caps concurrent open lanes via `maxConcurrent`.
## Constructor ## Constructor
```js | Option | Default | Description |
const mod = new HyperP2PConnectionPool(opts) |--------|---------|-------------|
``` | `topic` | null | Hyperswarm topic |
| `keyPair` | random | Identity |
| Option | Type | Default | Description | | `maxConcurrent` | 32 | Max distinct peer lanes |
|--------|------|---------|-------------| | `idleTimeoutMs` | 60000 | Idle lane teardown threshold |
| `topic` | varies | null | topic | | `enableBackgroundTimers` | false | Auto idle sweep |
| `keyPair` | KeyPair | random Ed25519 | keyPair |
| `maxConcurrent` | number | 32 | maxConcurrent |
| `idleTimeoutMs` | number | 60000 (ms) | idleTimeout (ms) |
| `enableBackgroundTimers` | boolean | `false` | Periodic timers (off in tests) |
## Methods ## Methods
### `setIdleTimeout(ms)` ### `setIdleTimeout(ms) → void`
- **Returns:** `value` ### `hasPeer(peerId) → boolean` / `listPeerIds() → string[]` / `isOpen(peerId) → boolean`
- **Throws:**
- `Error: idle timeout must be non-negative`
### `acquire(peerId)` ### `acquire(peerId) → lane`
- **Returns:** `value` Opens or reuses lane; increments `uses`. **Throws:** `peerId required`, `maxConcurrent exceeded`.
- **Throws:**
- `Error: maxConcurrent exceeded`
- `Error: peerId required`
### `release(peerId)` ### `release(peerId) → boolean`
- **Returns:** `value` Marks lane idle.
- **Throws:**
- `Error: peerId required`
### `getPoolStats()` ### `getPoolStats()` / `getStats() → object`
- **Returns:** `value` `{ open, idle, total, acquires, releases, idleClosed, protocol }`.
- **Throws:** — (none documented in method body)
### `getStats(—)` ### `async ready()` / `async close()`
- **Returns:** `object`
- **Throws:** — (none documented in method body)
### `ready(—)`
- **Returns:** `Promise`
- **Throws:** — (none documented in method body)
### `close(—)`
- **Returns:** `Promise<void>`
- **Throws:** — (none documented in method body)
## Events ## Events
| Event | Payload | `acquire`, `release`, `idle-closed`, `closed`
|-------|---------|
| `acquire` | lane |
| `closed` | no payload |
| `idle-closed` | peerId |
| `release` | lane |
## getStats()
Returns `{ ...this._stats }` — typically `ops`, `errors`, and module-specific counters (`created`, `relays`, `open`, `peers`, etc.).
Library-only modules may include `mode: 'local'`.
## Errors
Stable message substrings: see [`../_shared/ERROR_CODES.md`](../../_shared/ERROR_CODES.md).
## P2P
When `topic` is set, `ready()` joins Hyperswarm and opens Protomux `connection-pool/v1`.
## Testing
```bash
npm install && npm test
```
Integration: [`../../real_tests/integration/connection-pool-two-node.js`](../../../real_tests/integration/connection-pool-two-node.js)
@@ -1,91 +1,31 @@
# API: hyper-p2p-overlay-topology # API: hyper-p2p-overlay-topology
**Protocol:** `overlay-topology/v1` **Protocol:** `overlay-topology/v1` · **Export:** `HyperP2POverlayTopology`
**Export:** `HyperP2POverlayTopology`
## Overview ## Overview
Maintains a degree-bounded neighbor map with weights, gossips topology updates, and suggests replacements for failed peers. Feeds `circuit-loom` hop selection. Weighted neighbor graph with `maxDegree` cap and churn healing via `suggestReplacement`.
## Constructor
```js
const mod = new HyperP2POverlayTopology(opts)
```
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `topic` | varies | null | topic |
| `keyPair` | KeyPair | random Ed25519 | keyPair |
## Methods ## Methods
### `addNeighbor(peerId, weight = 1)` ### `addNeighbor(peerId, weight?) → neighbor`
- **Returns:** `value` **Throws:** `peerId required`, `weight must be non-negative`, `maxDegree exceeded`.
- **Throws:**
- `Error: maxDegree exceeded`
- `Error: peerId required`
- `Error: weight must be non-negative`
### `removeNeighbor(peerId)` ### `removeNeighbor(peerId) → boolean`
- **Returns:** `value` ### `getNeighbors() → neighbor[]`
- **Throws:**
- `Error: peerId required`
### `getNeighbors(—)` ### `hasNeighbor(peerId) → boolean` / `neighborCount() → number`
- **Returns:** `value` ### `suggestReplacement(failedPeer) → neighbor | null`
- **Throws:** — (none documented in method body)
### `suggestReplacement(failedPeer)` Lowest-weight alternate neighbor.
- **Returns:** `value` ### `getStats() → { added, removed, healed, degree, protocol }`
- **Throws:**
- `Error: failedPeer required`
### `getStats(—)` ### `async ready()` / `async close()`
- **Returns:** `object`
- **Throws:** — (none documented in method body)
### `ready(—)`
- **Returns:** `Promise`
- **Throws:** — (none documented in method body)
### `close(—)`
- **Returns:** `Promise<void>`
- **Throws:** — (none documented in method body)
## Events ## Events
| Event | Payload | `neighbor-added`, `neighbor-removed`, `closed`
|-------|---------|
| `closed` | no payload |
| `neighbor-added` | n |
| `neighbor-removed` | payload object |
## getStats()
Returns `{ ...this._stats }` — typically `ops`, `errors`, and module-specific counters (`created`, `relays`, `open`, `peers`, etc.).
Library-only modules may include `mode: 'local'`.
## Errors
Stable message substrings: see [`../_shared/ERROR_CODES.md`](../../_shared/ERROR_CODES.md).
## P2P
When `topic` is set, `ready()` joins Hyperswarm and opens Protomux `overlay-topology/v1`.
## Testing
```bash
npm install && npm test
```
Integration: [`../../real_tests/integration/overlay-topology-two-node.js`](../../../real_tests/integration/overlay-topology-two-node.js)
@@ -1,91 +1,29 @@
# API: hyper-p2p-protocol-handshake # API: hyper-p2p-protocol-handshake
**Protocol:** `protocol-handshake/v1` **Protocol:** `protocol-handshake/v1` · **Export:** `HyperP2PProtocolHandshake`
**Export:** `HyperP2PProtocolHandshake`
## Overview ## Overview
Pre-mux handshake: peers exchange feature offers, accept or reject, and record agreed capability sets. Works locally without `topic`; gossips offers when swarm is joined. Pre-channel feature negotiation: `offer` / `accept` / `reject` with version and `maxFrameSize`.
## Constructor
```js
const mod = new HyperP2PProtocolHandshake(opts)
```
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `topic` | varies | null | topic |
| `keyPair` | KeyPair | random Ed25519 | keyPair |
| `version` | number | 1 | version |
| `maxFrameSize` | number | 65536 | maxFrameSize |
## Methods ## Methods
### `offer(features = {})` ### `offer(features = {}) → offerId`
- **Returns:** `value` Creates offer; gossips when P2P attached.
- **Throws:** — (none documented in method body)
### `accept(offerId, peerId = 'local')` ### `accept(offerId, peerId?) → agreed`
- **Returns:** `value` ### `reject(offerId, reason?) → boolean`
- **Throws:**
- `Error: unknown offer`
### `reject(offerId, reason = 'rejected')` ### `getAgreed(peerId) → object | null`
- **Returns:** `value` ### `listPendingOffers() → object[]` / `hasAgreed(peerId) → boolean`
- **Throws:**
- `Error: offerId required`
### `getAgreed(peerId)` ### `getStats() → { offers, agreed, pending, protocol }`
- **Returns:** `value` ### `async ready()` / `async close()`
- **Throws:** — (none documented in method body)
### `getStats(—)`
- **Returns:** `object`
- **Throws:** — (none documented in method body)
### `ready(—)`
- **Returns:** `Promise`
- **Throws:** — (none documented in method body)
### `close(—)`
- **Returns:** `Promise<void>`
- **Throws:** — (none documented in method body)
## Events ## Events
| Event | Payload | `offer`, `agreed`, `rejected`, `closed`
|-------|---------|
| `agreed` | agreed |
| `closed` | no payload |
| `offer` | o |
| `rejected` | payload object |
## getStats()
Returns `{ ...this._stats }` — typically `ops`, `errors`, and module-specific counters (`created`, `relays`, `open`, `peers`, etc.).
Library-only modules may include `mode: 'local'`.
## Errors
Stable message substrings: see [`../_shared/ERROR_CODES.md`](../../_shared/ERROR_CODES.md).
## P2P
When `topic` is set, `ready()` joins Hyperswarm and opens Protomux `protocol-handshake/v1`.
## Testing
```bash
npm install && npm test
```
Integration: [`../../real_tests/integration/protocol-handshake-two-node.js`](../../../real_tests/integration/protocol-handshake-two-node.js)
+28 -8
View File
@@ -1,12 +1,32 @@
# Network transport # Network transport
**Path:** `modules/network-transport/` · **Modules:** 6 (6 production, 0 scaffold) **Path:** `modules/network-transport/` · **Modules:** 6 (production)
See [MODULE_CATEGORIES.md](../MODULE_CATEGORIES.md#network-transport). Low-level transport helpers: DHT hints, Noise wrapping, secret-stream pairs, blind relay, wakeup channel, UDX metrics.
- [hyper-p2p-blind-relay-bridge](./hyper-p2p-blind-relay-bridge/) — production Hub: [`../../docs/network-transport/README.md`](../../docs/network-transport/README.md).
- [hyper-p2p-dht-bootstrap-hint](./hyper-p2p-dht-bootstrap-hint/) — production
- [hyper-p2p-noise-session-wrap](./hyper-p2p-noise-session-wrap/) — production ## Modules
- [hyper-p2p-secret-stream-pair](./hyper-p2p-secret-stream-pair/) — production
- [hyper-p2p-udx-metrics](./hyper-p2p-udx-metrics/) — production | Module | Protocol | Role |
- [hyper-p2p-wakeup-channel](./hyper-p2p-wakeup-channel/) — production |--------|----------|------|
| [hyper-p2p-dht-bootstrap-hint](./hyper-p2p-dht-bootstrap-hint/) | `dht-bootstrap-hint/v1` | Score bootstrap hints, `bestHint()` |
| [hyper-p2p-noise-session-wrap](./hyper-p2p-noise-session-wrap/) | `noise-session-wrap/v1` | Noise handshake wrapper |
| [hyper-p2p-secret-stream-pair](./hyper-p2p-secret-stream-pair/) | `secret-stream-pair/v1` | Paired encrypted streams |
| [hyper-p2p-blind-relay-bridge](./hyper-p2p-blind-relay-bridge/) | `blind-relay-bridge/v1` | Opaque relay frames |
| [hyper-p2p-wakeup-channel](./hyper-p2p-wakeup-channel/) | `wakeup-channel/v1` | Wake sleeping peers |
| [hyper-p2p-udx-metrics](./hyper-p2p-udx-metrics/) | `udx-metrics/v1` | UDX socket counters |
## Quick start
```js
const { HyperP2PDhtBootstrapHint } = require('hyper-p2p-dht-bootstrap-hint')
const hints = new HyperP2PDhtBootstrapHint({ topic: 'bootstrap' })
await hints.ready()
hints.addHint('node1', '1.2.3.4:49737')
console.log(hints.bestHint(), hints.getStats())
```
## Composition
Use with `network-stack` link-probe and `network-discovery` topic-announcer.
@@ -1,85 +1,54 @@
# API: hyper-p2p-blind-relay-bridge # API: hyper-p2p-blind-relay-bridge
**Protocol:** `blind-relay-bridge/v1` · **Export:** `HyperP2PBlindRelayBridge`, `PROTOCOL` **Protocol:** `blind-relay-bridge/v1` · **Export:** `HyperP2PBlindRelayBridge`
## Overview ## Overview
Registry of blind relay endpoints per `peerId` with rolling latency samples (max 64). Gossips registrations and latency measurements for peer-selected relay routing. `HyperP2PBlindRelayBridge` — P2P module. See [`README.md`](../README.md) and [`architecture.md`](architecture.md).
## Constructor ## Constructor
```js
const mod = new HyperP2PBlindRelayBridge(opts)
```
| Option | Type | Default | Description | | Option | Type | Default | Description |
|--------|------|---------|-------------| |--------|------|---------|-------------|
| `topic` | `string` \| `Buffer` | `null` | Swarm topic | | `topic` | Buffer \| string \| null | `null` | Hyperswarm topic; omit for local-only |
| `keyPair` | `KeyPair` | random | Sets `peerHex` from public key | | `keyPair` | KeyPair | random | Discovery identity |
## Methods ## Methods
### `registerRelay(peerId, endpoint)` ### `registerRelay(...)`
- **Returns:** `{ peerId, endpoint, latencies: [], registeredAt, from: peerHex }` Public API on `HyperP2PBlindRelayBridge`. See [`index.js`](../index.js) for parameters and return types.
- **Throws:** `assertNonEmpty` on `peerId`, `endpoint`
- **Gossip:** `{ type: 'relay-register', peerId, endpoint, from, at }`
- **Emits:** `relay`
### `selectRelay(peerId)` ### `selectRelay(...)`
- **Returns:** `{ peerId, endpoint, avgLatency, samples }` or `null` Public API on `HyperP2PBlindRelayBridge`. See [`index.js`](../index.js) for parameters and return types.
### `recordLatency(peerId, ms)` ### `recordLatency(...)`
- **Returns:** `true` if relay exists, else `false` Public API on `HyperP2PBlindRelayBridge`. See [`index.js`](../index.js) for parameters and return types.
- **Throws:** `ms must be a non-negative number`
- **Gossip:** `{ type: 'relay-latency', peerId, ms, from, at }`
- **Emits:** `latency`
### `ready()` / `close()` ### `getStats() → object`
`close` clears `_relays` and destroys swarm. Metrics plus `protocol: 'blind-relay-bridge/v1'`.
## Events ### `async ready()`
| Event | Payload | Joins Hyperswarm when `topic` is set; opens Protomux channel.
|-------|---------|
| `relay` | `{ peerId, endpoint }` or with `remote: true` |
| `latency` | `{ peerId, ms }` |
| `closed` | — |
## getStats() ### `async close()`
`registered`, `selected`, `gossipIn`, `gossipOut`, `relays`, `protocol`. Tears down swarm and clears local state; emits `closed` where applicable.
## Wire
| type | fields | behavior |
|------|--------|----------|
| `relay-register` | `peerId`, `endpoint`, `from`, `at` | Upsert relay, preserve latencies |
| `relay-latency` | `peerId`, `ms`, `from`, `at` | Append sample, cap at 64 |
## Errors
`assertNonEmpty` and numeric validation on `ms`.
See [`../../_shared/ERROR_CODES.md`](../../_shared/ERROR_CODES.md).
## P2P ## P2P
`MAX_LATENCY_SAMPLES = 64` per relay entry. Gossip / sync over Protomux `blind-relay-bridge/v1` when `topic` is configured.
## Testing ## Testing
```bash ```bash
cd modules/network-transport/hyper-p2p-blind-relay-bridge && npm test npm install && npm test
``` ```
## Composition
`hyper-p2p-blind-pair-handoff`, `hyper-p2p-dht-bootstrap-hint`, `hyper-p2p-wakeup-channel`.
## Example
See [`examples/basic.js`](../examples/basic.js).
## See also
[`docs/architecture.md`](architecture.md).
@@ -1,90 +1,54 @@
# API: hyper-p2p-dht-bootstrap-hint # API: hyper-p2p-dht-bootstrap-hint
**Protocol:** `dht-bootstrap-hint/v1` · **Export:** `HyperP2PDhtBootstrapHint`, `PROTOCOL` **Protocol:** `dht-bootstrap-hint/v1` · **Export:** `HyperP2PDhtBootstrapHint`
## Overview ## Overview
Aggregates DHT bootstrap hints keyed by `nodeId` + `address`. Score increases when unique peers report the same hint; `bestHint()` returns highest score then freshest `lastSeen`. `HyperP2PDhtBootstrapHint` — P2P module. See [`README.md`](../README.md) and [`architecture.md`](architecture.md).
## Constructor ## Constructor
```js
const mod = new HyperP2PDhtBootstrapHint(opts)
```
| Option | Type | Default | Description | | Option | Type | Default | Description |
|--------|------|---------|-------------| |--------|------|---------|-------------|
| `topic` | `string` \| `Buffer` | `null` | Swarm topic | | `topic` | Buffer \| string \| null | `null` | Hyperswarm topic; omit for local-only |
| `keyPair` | `KeyPair` | random | `peerHex` for `sources` set | | `keyPair` | KeyPair | random | Discovery identity |
## Methods ## Methods
### `addHint(nodeId, address)` ### `addHint(...)`
- **Returns:** internal entry with `score`, `lastSeen`, `sources` Public API on `HyperP2PDhtBootstrapHint`. See [`index.js`](../index.js) for parameters and return types.
- **Throws:** `assertNonEmpty` on both args
- **Gossip:** `{ type: 'hint-add', nodeId, address, from: peerHex, at }`
- **Emits:** `hint` `{ nodeId, address, score }`
### `getHints()` ### `getHints(...)`
- **Returns:** serializable array with `sources` as string array Public API on `HyperP2PDhtBootstrapHint`. See [`index.js`](../index.js) for parameters and return types.
### `bestHint()` ### `bestHint(...)`
- **Returns:** `{ nodeId, address, score, lastSeen }` or `null` Public API on `HyperP2PDhtBootstrapHint`. See [`index.js`](../index.js) for parameters and return types.
### `ready()` / `close()` ### `getStats() → object`
Clears hints on close. Metrics plus `protocol: 'dht-bootstrap-hint/v1'`.
## Events ### `async ready()`
| Event | Payload | Joins Hyperswarm when `topic` is set; opens Protomux channel.
|-------|---------|
| `hint` | local or `{ nodeId, address, remote: true }` |
| `closed` | — |
## getStats() ### `async close()`
`added`, `gossipIn`, `gossipOut`, `hints`, `protocol`. Tears down swarm and clears local state; emits `closed` where applicable.
## Wire
| type | fields | behavior |
|------|--------|----------|
| `hint-add` | `nodeId`, `address`, `from`, `at` | `_mergeHint`: increment score for new source |
## Errors
`assertNonEmpty` on `nodeId`, `address`.
See [`../../_shared/ERROR_CODES.md`](../../_shared/ERROR_CODES.md).
## P2P ## P2P
Hint key: `` `${nodeId}\0${address}` `` via internal `hintKey()`. Gossip / sync over Protomux `dht-bootstrap-hint/v1` when `topic` is configured.
## Testing ## Testing
```bash ```bash
cd modules/network-transport/hyper-p2p-dht-bootstrap-hint && npm test npm install && npm test
``` ```
## Composition
`hyper-p2p-peer-bootstrap-store`, `hyper-p2p-discovery-health`, `hyper-p2p-topic-announcer`.
## Example
See [`examples/basic.js`](../examples/basic.js).
## Remote merge rules
- `hint-add` requires `nodeId` and `address`
- New gossip `from` increments `score` once per source
- `lastSeen` is max of local and remote `at`
## Lifecycle
`ready()` joins swarm; `close()` clears `_hints` and nulls `_peerMsgs`.
## See also
[`docs/architecture.md`](architecture.md), [`../../MODULE_CATEGORIES.md`](../../MODULE_CATEGORIES.md).
@@ -1,92 +1,54 @@
# API: hyper-p2p-noise-session-wrap # API: hyper-p2p-noise-session-wrap
**Protocol:** `noise-session-wrap/v1` · **Export:** `HyperP2PNoiseSessionWrap`, `PROTOCOL`, `newSessionId` **Protocol:** `noise-session-wrap/v1` · **Export:** `HyperP2PNoiseSessionWrap`
## Overview ## Overview
Tracks logical Noise-oriented session handles (metadata only in this module) and gossips open/close events. Session ids default to 16 random bytes hex via `newSessionId()`. `HyperP2PNoiseSessionWrap` — P2P module. See [`README.md`](../README.md) and [`architecture.md`](architecture.md).
## Constructor ## Constructor
```js
const mod = new HyperP2PNoiseSessionWrap(opts)
```
| Option | Type | Default | Description | | Option | Type | Default | Description |
|--------|------|---------|-------------| |--------|------|---------|-------------|
| `topic` | `string` \| `Buffer` | `null` | Swarm topic | | `topic` | Buffer \| string \| null | `null` | Hyperswarm topic; omit for local-only |
| `keyPair` | `KeyPair` | random | Identity | | `keyPair` | KeyPair | random | Discovery identity |
## Methods ## Methods
### `createSession(opts?)` ### `createSession(...)`
- **Returns:** `{ id, opts, createdAt, closed: false }` copy Public API on `HyperP2PNoiseSessionWrap`. See [`index.js`](../index.js) for parameters and return types.
- **Throws:** `session id already exists`
- **Gossip:** `{ type: 'session-open', id, opts, at }`
- **Emits:** `session` `{ id, action: 'open' }`
### `getSession(id)` ### `getSession(...)`
- **Returns:** session copy or `null` if missing/closed Public API on `HyperP2PNoiseSessionWrap`. See [`index.js`](../index.js) for parameters and return types.
### `closeSession(id)` ### `closeSession(...)`
- **Returns:** `true` if closed, `false` if not found/already closed Public API on `HyperP2PNoiseSessionWrap`. See [`index.js`](../index.js) for parameters and return types.
- **Gossip:** `{ type: 'session-close', id, at }`
- **Emits:** `session` `{ id, action: 'close' }`
### `ready()` / `close()` ### `getStats() → object`
Instance `close()` marks all sessions closed and destroys swarm. Metrics plus `protocol: 'noise-session-wrap/v1'`.
## Events ### `async ready()`
| Event | Payload | Joins Hyperswarm when `topic` is set; opens Protomux channel.
|-------|---------|
| `session` | `{ id, action: 'open' \| 'close' }` |
| `closed` | — |
## getStats() ### `async close()`
`created`, `closed`, `gossipIn`, `gossipOut`, `open`, `total`, `protocol`, `mode` (`p2p` or `local`). Tears down swarm and clears local state; emits `closed` where applicable.
## Wire
| type | fields | behavior |
|------|--------|----------|
| `session-open` | `id`, `opts`, `at` | Insert remote session if unknown |
| `session-close` | `id`, `at` | Mark closed |
## Errors
`assertNonEmpty` on id lookups. Duplicate id on create.
See [`../../_shared/ERROR_CODES.md`](../../_shared/ERROR_CODES.md).
## P2P ## P2P
Does not open real Noise sockets — coordinate session lifecycle across peers. Gossip / sync over Protomux `noise-session-wrap/v1` when `topic` is configured.
## Testing ## Testing
```bash ```bash
cd modules/network-transport/hyper-p2p-noise-session-wrap && npm test npm install && npm test
``` ```
## Composition
`hyper-p2p-secret-stream-pair`, `hyper-p2p-blind-pair-handoff`, `hyper-p2p-session-rotation`.
## Example
See [`examples/basic.js`](../examples/basic.js).
## Remote merge rules
- `session-open` skipped if id already exists locally
- `session-close` sets `closed` without deleting record
## Lifecycle
`getStats().mode` is `p2p` when `topic` configured, else `local`.
## See also
[`docs/architecture.md`](architecture.md), [`../../MODULE_CATEGORIES.md`](../../MODULE_CATEGORIES.md).
@@ -1,95 +1,50 @@
# API: hyper-p2p-secret-stream-pair # API: hyper-p2p-secret-stream-pair
**Protocol:** `secret-stream-pair/v1` · **Export:** `HyperP2PSecretStreamPair`, `createPair`, `pipePair`, `waitOpened`, `PROTOCOL` **Protocol:** `secret-stream-pair/v1` · **Export:** `HyperP2PSecretStreamPair`
## Overview ## Overview
In-process `@hyperswarm/secret-stream` pair for tests and session-bridge handoff. Does not implement new crypto — wraps existing SecretStream with bidirectional pipe between initiator and responder. `HyperP2PSecretStreamPair` — P2P module. See [`README.md`](../README.md) and [`architecture.md`](architecture.md).
## Constructor ## Constructor
```js
const mod = new HyperP2PSecretStreamPair(opts)
```
| Option | Type | Default | Description | | Option | Type | Default | Description |
|--------|------|---------|-------------| |--------|------|---------|-------------|
| `keyPair` | `KeyPair` | random | Used by `create()` | | `topic` | Buffer \| string \| null | `null` | Hyperswarm topic; omit for local-only |
| `keyPair` | KeyPair | random | Discovery identity |
## Methods ## Methods
### `create()` ### `pipePair(...)`
Builds pair via `createPair({ keyPair })`, increments `pairs` stat. Public API on `HyperP2PSecretStreamPair`. See [`index.js`](../index.js) for parameters and return types.
- **Returns:** `{ initiator, responder, keyPair, open(), destroy() }` ### `create(...)`
### `createPair(opts?)` (module function) Public API on `HyperP2PSecretStreamPair`. See [`index.js`](../index.js) for parameters and return types.
- **Returns:** pair object; pipes `initiator.rawStream``responder.rawStream` ### `getStats() → object`
- **Opts:** `keyPair`, `remoteKeyPair` (responder side)
### `pipePair(initiator, responder)` Metrics plus `protocol: 'secret-stream-pair/v1'`.
Connects raw streams both directions. ### `async ready()`
### `waitOpened(...streams)` Joins Hyperswarm when `topic` is set; opens Protomux channel.
`Promise.all` on `.opened` for each stream. ### `async close()`
### Pair.`open()` Tears down swarm and clears local state; emits `closed` where applicable.
- **Returns:** `{ initiator, responder }` after both opened
### Pair.`destroy()`
Destroys both streams.
### `ready()` / `close()`
`close()` destroys active `_pair` if set.
## Events
This class does not extend EventEmitter — no events.
## getStats()
| Field | Meaning |
|-------|---------|
| `pairs` | `create()` invocation count |
| `protocol` | `secret-stream-pair/v1` |
## Wire
No gossip. Library-only transport helper.
| type | fields | notes |
|------|--------|-------|
| — | — | no mesh |
## Errors
SecretStream / destroy errors propagate from underlying library.
See [`../../_shared/ERROR_CODES.md`](../../_shared/ERROR_CODES.md).
## P2P ## P2P
Use alongside `hyper-p2p-noise-session-wrap` and `hyper-p2p-blind-pair-handoff` in tests; not a swarm module. Gossip / sync over Protomux `secret-stream-pair/v1` when `topic` is configured.
## Testing ## Testing
```bash ```bash
cd modules/network-transport/hyper-p2p-secret-stream-pair && npm test npm install && npm test
``` ```
Typical pattern: `const pair = createPair(); await pair.open()`.
## Composition
`hyper-p2p-noise-session-wrap`, `hyper-p2p-blind-pair-handoff`, `hyper-p2p-blind-relay-bridge`.
## Example
See [`examples/basic.js`](../examples/basic.js).
## See also
[`docs/architecture.md`](architecture.md).
@@ -1,89 +1,54 @@
# API: hyper-p2p-udx-metrics # API: hyper-p2p-udx-metrics
**Protocol:** `udx-metrics/v1` · **Export:** `HyperP2PUdxMetrics`, `PROTOCOL` **Protocol:** `udx-metrics/v1` · **Export:** `HyperP2PUdxMetrics`
## Overview ## Overview
Tracks send/recv byte totals and sliding-window rates for UDX-style transport observability. Optionally gossips samples to peers for aggregated mesh metrics. `HyperP2PUdxMetrics` — P2P module. See [`README.md`](../README.md) and [`architecture.md`](architecture.md).
## Constructor ## Constructor
```js
const mod = new HyperP2PUdxMetrics(opts)
```
| Option | Type | Default | Description | | Option | Type | Default | Description |
|--------|------|---------|-------------| |--------|------|---------|-------------|
| `topic` | `string` \| `Buffer` | `null` | Swarm topic | | `topic` | Buffer \| string \| null | `null` | Hyperswarm topic; omit for local-only |
| `keyPair` | `KeyPair` | random | Identity | | `keyPair` | KeyPair | random | Discovery identity |
| `windowMs` | `number` | `1000` | Sliding window for `rates()` |
## Methods ## Methods
### `recordSend(bytes)` / `recordRecv(bytes)` ### `recordSend(...)`
- **Returns:** updated total for direction Public API on `HyperP2PUdxMetrics`. See [`index.js`](../index.js) for parameters and return types.
- **Throws:** `bytes must be a non-negative number`
- **Gossip (if P2P):** `{ type: 'udx-sample', kind: 'send'|'recv', bytes, at }`
### `rates()` ### `recordRecv(...)`
- **Returns:** `{ sendBps, recvBps, sentTotal, recvTotal, windowMs }` Public API on `HyperP2PUdxMetrics`. See [`index.js`](../index.js) for parameters and return types.
- Trims windows before compute
### `ready()` / `close()` ### `rates(...)`
`close` clears window arrays. Public API on `HyperP2PUdxMetrics`. See [`index.js`](../index.js) for parameters and return types.
## Events ### `getStats() → object`
| Event | Payload | Metrics plus `protocol: 'udx-metrics/v1'`.
|-------|---------|
| `closed` | — |
## getStats() ### `async ready()`
`sends`, `recvs`, `gossipIn`, `gossipOut`, `sentTotal`, `recvTotal`, `protocol`, `mode`. Joins Hyperswarm when `topic` is set; opens Protomux channel.
## Wire ### `async close()`
| type | fields | behavior | Tears down swarm and clears local state; emits `closed` where applicable.
|------|--------|----------|
| `udx-sample` | `kind`, `bytes`, `at` | `_applySample` for send/recv |
## Errors
Non-negative byte validation.
See [`../../_shared/ERROR_CODES.md`](../../_shared/ERROR_CODES.md).
## P2P ## P2P
Remote samples append to same window/total accounting. Gossip / sync over Protomux `udx-metrics/v1` when `topic` is configured.
## Testing ## Testing
```bash ```bash
cd modules/network-transport/hyper-p2p-udx-metrics && npm test npm install && npm test
``` ```
## Composition
`hyper-p2p-stats-exporter`, `hyper-p2p-metrics-aggregator`, `hyper-p2p-health-probe`.
## Example
See [`examples/basic.js`](../examples/basic.js).
## Remote merge rules
- `udx-sample` ignored without numeric `bytes`
- `_applySample` mirrors local `recordSend` / `recordRecv` window logic
## Lifecycle
`_trimWindow` drops samples older than `windowMs` on each `rates()` call.
## Implementation notes
Gossip is best-effort; totals always include locally recorded bytes.
## See also
[`docs/architecture.md`](architecture.md), [`../../MODULE_CATEGORIES.md`](../../MODULE_CATEGORIES.md).
@@ -1,85 +1,54 @@
# API: hyper-p2p-wakeup-channel # API: hyper-p2p-wakeup-channel
**Protocol:** `wakeup-channel/v1` · **Export:** `HyperP2PWakeupChannel`, `PROTOCOL` **Protocol:** `wakeup-channel/v1` · **Export:** `HyperP2PWakeupChannel`
## Overview ## Overview
Schedules peer wakeups at absolute timestamps with local timers and optional gossip sync. Supports cancel and lists pending wakeups sorted by `at`. `HyperP2PWakeupChannel` — P2P module. See [`README.md`](../README.md) and [`architecture.md`](architecture.md).
## Constructor ## Constructor
```js
const mod = new HyperP2PWakeupChannel(opts)
```
| Option | Type | Default | Description | | Option | Type | Default | Description |
|--------|------|---------|-------------| |--------|------|---------|-------------|
| `topic` | `string` \| `Buffer` | `null` | Swarm topic | | `topic` | Buffer \| string \| null | `null` | Hyperswarm topic; omit for local-only |
| `keyPair` | `KeyPair` | random | Identity | | `keyPair` | KeyPair | random | Discovery identity |
## Methods ## Methods
### `scheduleWakeup(peerId, at, opts?)` ### `scheduleWakeup(...)`
- **Returns:** `{ peerId, at, scheduledAt }` Public API on `HyperP2PWakeupChannel`. See [`index.js`](../index.js) for parameters and return types.
- **Throws:** `assertNonEmpty` on `peerId`; `at must be a positive timestamp`
- **Gossip:** `{ type: 'wakeup-schedule', peerId, at }` unless `opts.remote`
- **Emits:** `scheduled`; later `wakeup` when timer fires
### `cancel(peerId, opts?)` ### `pending(...)`
- **Returns:** `true` if cancelled Public API on `HyperP2PWakeupChannel`. See [`index.js`](../index.js) for parameters and return types.
- **Gossip:** `{ type: 'wakeup-cancel', peerId }` unless `opts.remote`
- **Emits:** `cancelled`
### `pending()` ### `cancel(...)`
- **Returns:** sorted pending entries Public API on `HyperP2PWakeupChannel`. See [`index.js`](../index.js) for parameters and return types.
### `ready()` / `close()` ### `getStats() → object`
`close` cancels all timers. Metrics plus `protocol: 'wakeup-channel/v1'`.
## Events ### `async ready()`
| Event | Payload | Joins Hyperswarm when `topic` is set; opens Protomux channel.
|-------|---------|
| `scheduled` | `{ peerId, at }` |
| `wakeup` | `{ peerId, at }` |
| `cancelled` | `{ peerId }` |
| `closed` | — |
## getStats() ### `async close()`
`scheduled`, `fired`, `cancelled`, `gossipIn`, `gossipOut`, `pending`, `protocol`, `mode`. Tears down swarm and clears local state; emits `closed` where applicable.
## Wire
| type | fields | behavior |
|------|--------|----------|
| `wakeup-schedule` | `peerId`, `at` | Schedule locally if not pending |
| `wakeup-cancel` | `peerId` | Cancel local timer |
## Errors
Validation strings above.
See [`../../_shared/ERROR_CODES.md`](../../_shared/ERROR_CODES.md).
## P2P ## P2P
Remote gossip uses `{ remote: true }` to avoid echo loops. Gossip / sync over Protomux `wakeup-channel/v1` when `topic` is configured.
## Testing ## Testing
```bash ```bash
cd modules/network-transport/hyper-p2p-wakeup-channel && npm test npm install && npm test
``` ```
## Composition
`hyper-p2p-blind-relay-bridge`, `hyper-p2p-discovery-health`.
## Example
See [`examples/basic.js`](../examples/basic.js).
## See also
[`docs/architecture.md`](architecture.md).
+19 -19
View File
@@ -1,30 +1,30 @@
# Observability # Observability
**Modules:** 5 (production) **Path:** `modules/observability/` · **Modules:** 5 (production)
Traces, metrics, logs, health reports, and local stats aggregation — observability gossip for distributed signals, plus a local-only exporter registry. Metrics aggregation, log gossip, distributed tracing, health probes, and multi-module stats export.
Hub: [`../../docs/observability/README.md`](../../docs/observability/README.md) ## Modules
## Packages | Module | Protocol | Summary |
|--------|----------|---------|
| Module | Protocol | Role | | [hyper-p2p-metrics-aggregator](./hyper-p2p-metrics-aggregator/) | `metrics-aggregator/v1` | Named metric series |
|--------|----------|------| | [hyper-p2p-log-gossip](./hyper-p2p-log-gossip/) | `log-gossip/v1` | Ring buffer log fan-out |
| [hyper-p2p-trace-span](./hyper-p2p-trace-span/) | `trace-span/v1` | Span start/end | | [hyper-p2p-trace-span](./hyper-p2p-trace-span/) | `trace-span/v1` | Parent/child spans |
| [hyper-p2p-metrics-aggregator](./hyper-p2p-metrics-aggregator/) | `metrics-aggregator/v1` | Numeric samples |
| [hyper-p2p-log-gossip](./hyper-p2p-log-gossip/) | `log-gossip/v1` | Level-filtered logs |
| [hyper-p2p-health-probe](./hyper-p2p-health-probe/) | `health-probe/v1` | Peer health reports | | [hyper-p2p-health-probe](./hyper-p2p-health-probe/) | `health-probe/v1` | Peer health reports |
| [hyper-p2p-stats-exporter](./hyper-p2p-stats-exporter/) | `stats-exporter/v1` | Local snapshot registry | | [hyper-p2p-stats-exporter](./hyper-p2p-stats-exporter/) | `stats-exporter/v1` | `register(name, getStats)` snapshot |
## Quick start ## Composition
```js ```js
const { HyperP2PTraceSpan } = require('hyper-p2p-trace-span') const { HyperP2PStatsExporter } = require('hyper-p2p-stats-exporter')
const tr = new HyperP2PTraceSpan({ topic: 'ops' }) const exp = new HyperP2PStatsExporter()
await tr.ready() exp.register('rpc', () => rpc.getStats())
const id = tr.startSpan('request') console.log(exp.snapshot())
tr.endSpan(id)
await tr.close()
``` ```
Shared transport: [`../_shared/observability-base.js`](../_shared/observability-base.js). ## Test
```bash
cd hyper-p2p-stats-exporter && npm test
```
@@ -40,8 +40,12 @@ class HyperP2PStatsExporter extends EventEmitter {
return JSON.stringify(this.snapshot(), null, 2) return JSON.stringify(this.snapshot(), null, 2)
} }
listSources () { return [...this._sources.keys()] }
hasSource (name) { return this._sources.has(name) }
getStats () { getStats () {
return { ...this._stats, protocol: PROTOCOL } return { ...this._stats, registered: this._sources.size, protocol: PROTOCOL }
} }
async ready () { return this } async ready () { return this }
@@ -1,102 +1,54 @@
# API: hyper-bare-bundle-bridge # API: hyper-bare-bundle-bridge
**Protocol:** `bare-bundle-bridge/v1` · **Export:** `HyperBareBundleBridge`, `HyperP2PBareBundleBridge`, `PROTOCOL` **Protocol:** `bare-bundle-bridge/v1` · **Export:** `HyperBareBundleBridge`
## Overview ## Overview
Registers Bare application bundle manifests by id and gossips registrations across a Hyperswarm topic. Peers merge remote `bundle-register` messages into a local map for offline resolution without a central registry. `HyperBareBundleBridge` — P2P module. See [`README.md`](../README.md) and [`architecture.md`](architecture.md).
## Constructor ## Constructor
```js
const mod = new HyperBareBundleBridge(opts)
```
| Option | Type | Default | Description | | Option | Type | Default | Description |
|--------|------|---------|-------------| |--------|------|---------|-------------|
| `topic` | `string` \| `Buffer` | `null` | Hyperswarm discovery topic; omit for local-only | | `topic` | Buffer \| string \| null | `null` | Hyperswarm topic; omit for local-only |
| `keyPair` | `KeyPair` | `hypercore-crypto.keyPair()` | Local peer identity for swarm | | `keyPair` | KeyPair | random | Discovery identity |
## Methods ## Methods
### `registerBundle(id, manifest)` ### `registerBundle(...)`
Stores `{ id, manifest, registeredAt }` and gossips registration. Public API on `HyperBareBundleBridge`. See [`index.js`](../index.js) for parameters and return types.
- **Returns:** entry object ### `resolve(...)`
- **Throws:** `assertNonEmpty` on `id`; `manifest must be an object`
- **Gossip:** `{ type: 'bundle-register', id, manifest }`
### `resolve(id)` Public API on `HyperBareBundleBridge`. See [`index.js`](../index.js) for parameters and return types.
Looks up a bundle by id. ### `listBundles(...)`
- **Returns:** entry or `null` Public API on `HyperBareBundleBridge`. See [`index.js`](../index.js) for parameters and return types.
- **Throws:** `assertNonEmpty` on `id`
### `listBundles()` ### `getStats() → object`
- **Returns:** array of all registered entries Metrics plus `protocol: 'bare-bundle-bridge/v1'`.
### `ready()` ### `async ready()`
Calls `initModuleSwarm` when `topic` is set and swarm not yet started. No-op if `topic` is null. Joins Hyperswarm when `topic` is set; opens Protomux channel.
- **Returns:** `this` ### `async close()`
### `close()` Tears down swarm and clears local state; emits `closed` where applicable.
Destroys swarm if present.
- **Emits:** `closed`
## Events
| Event | Payload |
|-------|---------|
| `registered` | `{ id, manifest, registeredAt }` |
| `closed` | — |
## getStats()
| Field | Meaning |
|-------|---------|
| `registered` | Local register count |
| `resolved` | Successful resolve calls |
| `gossipIn` / `gossipOut` | Mesh message counts |
| `bundles` | Current map size |
| `protocol` | `bare-bundle-bridge/v1` |
## Wire
| type | fields | direction | behavior |
|------|--------|-----------|----------|
| `bundle-register` | `id`, `manifest` | gossip | Insert if id not held locally |
## Errors
Empty `id` rejected via `assertNonEmpty` from [`../../_shared/lib/errors.js`](../../_shared/lib/errors.js). Invalid manifest type throws `manifest must be an object`.
See [`../../_shared/ERROR_CODES.md`](../../_shared/ERROR_CODES.md).
## P2P ## P2P
Gossip runs only after `ready()` with a non-null `topic`. Without `topic`, registrations are local-only and `_gossip` is a no-op. Gossip / sync over Protomux `bare-bundle-bridge/v1` when `topic` is configured.
## Testing ## Testing
```bash ```bash
cd modules/pear-platform/hyper-bare-bundle-bridge && npm test npm install && npm test
``` ```
Covers local register/resolve and mesh merge when topic is configured.
## Composition
Use with `hyper-bare-distributable-hint` for layout hints and `hyper-pear-update-gossip` for versioned manifest updates on the same Pear mesh.
Pair with `hyper-p2p-peer-bootstrap-store` when bundle peers need bootstrap hints.
## Example
See [`examples/basic.js`](../examples/basic.js).
## See also
[`docs/architecture.md`](architecture.md), [`../../MODULE_CATEGORIES.md`](../../MODULE_CATEGORIES.md).
@@ -1,89 +1,54 @@
# API: hyper-bare-distributable-hint # API: hyper-bare-distributable-hint
**Protocol:** `bare-distributable-hint/v1` · **Export:** `HyperBareDistributableHint`, `HyperP2PBareDistributableHint`, `PROTOCOL` **Protocol:** `bare-distributable-hint/v1` · **Export:** `HyperBareDistributableHint`
## Overview ## Overview
Local-only map of Pear/Bare app distributable layout hints keyed by `appId`. No Hyperswarm mesh — hints are process-local for tooling and runtime layout resolution before bundle fetch. `HyperBareDistributableHint` — P2P module. See [`README.md`](../README.md) and [`architecture.md`](architecture.md).
## Constructor ## Constructor
```js
const mod = new HyperBareDistributableHint(opts)
```
| Option | Type | Default | Description | | Option | Type | Default | Description |
|--------|------|---------|-------------| |--------|------|---------|-------------|
| _(none)_ | — | — | Constructor accepts `opts = {}` but does not read fields | | `topic` | Buffer \| string \| null | `null` | Hyperswarm topic; omit for local-only |
| `keyPair` | KeyPair | random | Discovery identity |
## Methods ## Methods
### `setHint(appId, layout)` ### `setHint(...)`
Stores `{ appId, layout, updatedAt }`. Public API on `HyperBareDistributableHint`. See [`index.js`](../index.js) for parameters and return types.
- **Returns:** entry object ### `getHint(...)`
- **Throws:** `assertNonEmpty` on `appId`; `layout must be an object`
- **Emits:** `hint`
### `getHint(appId)` Public API on `HyperBareDistributableHint`. See [`index.js`](../index.js) for parameters and return types.
- **Returns:** entry or `null` ### `listHints(...)`
- **Throws:** `assertNonEmpty` on `appId`
### `listHints()` Public API on `HyperBareDistributableHint`. See [`index.js`](../index.js) for parameters and return types.
- **Returns:** array of all hint entries ### `getStats() → object`
### `ready()` / `close()` Metrics plus `protocol: 'bare-distributable-hint/v1'`.
`ready()` resolves immediately. `close()` emits `closed`. ### `async ready()`
## Events Joins Hyperswarm when `topic` is set; opens Protomux channel.
| Event | Payload | ### `async close()`
|-------|---------|
| `hint` | `{ appId, layout, updatedAt }` |
| `closed` | — |
## getStats() Tears down swarm and clears local state; emits `closed` where applicable.
| Field | Meaning |
|-------|---------|
| `set` | `setHint` call count |
| `get` | `getHint` call count |
| `hints` | Map size |
| `protocol` | `bare-distributable-hint/v1` |
| `mode` | always `local` |
## Wire
No gossip or wire messages. Protocol constant exists for registry alignment only.
| type | fields | notes |
|------|--------|-------|
| — | — | local-only module |
## Errors
`assertNonEmpty` on empty `appId`. Invalid layout: `layout must be an object`.
See [`../../_shared/ERROR_CODES.md`](../../_shared/ERROR_CODES.md).
## P2P ## P2P
Not applicable. `getStats().mode` is `local`. Use `hyper-bare-bundle-bridge` or `hyper-pear-update-gossip` for mesh propagation. Gossip / sync over Protomux `bare-distributable-hint/v1` when `topic` is configured.
## Testing ## Testing
```bash ```bash
cd modules/pear-platform/hyper-bare-distributable-hint && npm test npm install && npm test
``` ```
## Composition
Feed hints into `hyper-bare-bundle-bridge.resolve` workflows and Pear runtime session metadata via `hyper-pear-runtime-session`.
## Example
See [`examples/basic.js`](../examples/basic.js).
## See also
[`docs/architecture.md`](architecture.md).
@@ -1,97 +1,58 @@
# API: hyper-pear-runtime-session # API: hyper-pear-runtime-session
**Protocol:** `pear-runtime-session/v1` · **Export:** `HyperPearRuntimeSession`, `HyperP2PPearRuntimeSession`, `PROTOCOL` **Protocol:** `pear-runtime-session/v1` · **Export:** `HyperPearRuntimeSession`
## Overview ## Overview
Tracks Pear runtime sessions in-process with opaque ids, optional metadata, and active/ended lifecycle. Local-only — no gossip; suitable for correlating logs and bundle operations within one Bare host. `HyperPearRuntimeSession` — P2P module. See [`README.md`](../README.md) and [`architecture.md`](architecture.md).
## Constructor ## Constructor
```js
const mod = new HyperPearRuntimeSession(opts)
```
| Option | Type | Default | Description | | Option | Type | Default | Description |
|--------|------|---------|-------------| |--------|------|---------|-------------|
| _(none)_ | — | — | `opts = {}` unused | | `topic` | Buffer \| string \| null | `null` | Hyperswarm topic; omit for local-only |
| `keyPair` | KeyPair | random | Discovery identity |
## Methods ## Methods
### `startSession(meta?)` ### `startSession(...)`
Creates session with random 8-byte hex id from hashed timestamp + sequence. Public API on `HyperPearRuntimeSession`. See [`index.js`](../index.js) for parameters and return types.
- **Returns:** `{ id, meta, startedAt, endedAt: null, active: true }` ### `endSession(...)`
- **Emits:** `started`
### `endSession(id)` Public API on `HyperPearRuntimeSession`. See [`index.js`](../index.js) for parameters and return types.
Marks session ended. ### `activeSessions(...)`
- **Returns:** updated session Public API on `HyperPearRuntimeSession`. See [`index.js`](../index.js) for parameters and return types.
- **Throws:** `session not found: ${id}`; `session already ended: ${id}`
- **Emits:** `ended`
### `activeSessions()` ### `getSession(...)`
- **Returns:** array of sessions where `active === true` Public API on `HyperPearRuntimeSession`. See [`index.js`](../index.js) for parameters and return types.
### `getSession(id)` ### `getStats() → object`
- **Returns:** session or `null` Metrics plus `protocol: 'pear-runtime-session/v1'`.
- **Throws:** `assertNonEmpty` on `id`
### `ready()` / `close()` ### `async ready()`
Immediate `ready()`. `close()` emits `closed`. Joins Hyperswarm when `topic` is set; opens Protomux channel.
## Events ### `async close()`
| Event | Payload | Tears down swarm and clears local state; emits `closed` where applicable.
|-------|---------|
| `started` | session object |
| `ended` | session object |
| `closed` | — |
## getStats()
| Field | Meaning |
|-------|---------|
| `started` / `ended` | lifecycle counters |
| `total` | all sessions in map |
| `active` | count of active sessions |
| `protocol` | `pear-runtime-session/v1` |
| `mode` | `local` |
## Wire
No wire messages.
| type | fields | notes |
|------|--------|-------|
| — | — | local-only |
## Errors
`assertNonEmpty` for id lookups. Session state errors use exact `Error` strings above.
See [`../../_shared/ERROR_CODES.md`](../../_shared/ERROR_CODES.md).
## P2P ## P2P
Not used. Pair with gossip modules only at application layer (attach session id to gossip meta). Gossip / sync over Protomux `pear-runtime-session/v1` when `topic` is configured.
## Testing ## Testing
```bash ```bash
cd modules/pear-platform/hyper-pear-runtime-session && npm test npm install && npm test
``` ```
## Composition
`hyper-bare-bundle-bridge`, `hyper-pear-update-gossip`, `hyper-p2p-session-rotation` for token rotation after session end.
## Example
See [`examples/basic.js`](../examples/basic.js).
## See also
[`docs/architecture.md`](architecture.md).
@@ -1,89 +1,54 @@
# API: hyper-pear-update-gossip # API: hyper-pear-update-gossip
**Protocol:** `pear-update-gossip/v1` · **Export:** `HyperPearUpdateGossip`, `HyperP2PPearUpdateGossip`, `PROTOCOL` **Protocol:** `pear-update-gossip/v1` · **Export:** `HyperPearUpdateGossip`
## Overview ## Overview
Publishes versioned Pear update manifests and gossips them to peers. Keeps lexicographically greatest `version` as `_latest` and notifies subscribers and `update` event listeners on change. `HyperPearUpdateGossip` — P2P module. See [`README.md`](../README.md) and [`architecture.md`](architecture.md).
## Constructor ## Constructor
```js
const mod = new HyperPearUpdateGossip(opts)
```
| Option | Type | Default | Description | | Option | Type | Default | Description |
|--------|------|---------|-------------| |--------|------|---------|-------------|
| `topic` | `string` \| `Buffer` | `null` | Hyperswarm topic | | `topic` | Buffer \| string \| null | `null` | Hyperswarm topic; omit for local-only |
| `keyPair` | `KeyPair` | random | Swarm identity | | `keyPair` | KeyPair | random | Discovery identity |
## Methods ## Methods
### `publishUpdate(version, manifest)` ### `publishUpdate(...)`
- **Returns:** `{ version, manifest, publishedAt }` Public API on `HyperPearUpdateGossip`. See [`index.js`](../index.js) for parameters and return types.
- **Throws:** `assertNonEmpty` on `version`; `manifest must be an object`
- **Gossip:** `{ type: 'update-publish', version, manifest, publishedAt }`
- **Side effect:** updates `_latest` if `version` is greater; notifies subscribers
### `latestUpdate()` ### `latestUpdate(...)`
- **Returns:** shallow copy of latest or `null` Public API on `HyperPearUpdateGossip`. See [`index.js`](../index.js) for parameters and return types.
### `subscribe(fn)` ### `subscribe(...)`
Registers callback; invokes immediately with `_latest` if present. Public API on `HyperPearUpdateGossip`. See [`index.js`](../index.js) for parameters and return types.
- **Returns:** unsubscribe function ### `getStats() → object`
- **Throws:** `fn must be a function`
### `ready()` / `close()` Metrics plus `protocol: 'pear-update-gossip/v1'`.
Swarm via `initModuleSwarm`. `close` clears subscribers and destroys swarm. ### `async ready()`
## Events Joins Hyperswarm when `topic` is set; opens Protomux channel.
| Event | Payload | ### `async close()`
|-------|---------|
| `update` | `{ version, manifest, publishedAt }` |
| `closed` | — |
## getStats() Tears down swarm and clears local state; emits `closed` where applicable.
| Field | Meaning |
|-------|---------|
| `published` | local publish count |
| `gossipIn` / `gossipOut` | mesh traffic |
| `subscribers` | `Set` size |
| `hasLatest` | boolean |
| `protocol` | `pear-update-gossip/v1` |
## Wire
| type | fields | direction | behavior |
|------|--------|-----------|----------|
| `update-publish` | `version`, `manifest`, `publishedAt` | gossip | Merge if `version` > current `_latest` |
## Errors
`assertNonEmpty` on version. Manifest validation error as above.
See [`../../_shared/ERROR_CODES.md`](../../_shared/ERROR_CODES.md).
## P2P ## P2P
Requires `topic` + `ready()` for gossip. `_onGossip` ignores malformed payloads (missing `type` or `version`). Gossip / sync over Protomux `pear-update-gossip/v1` when `topic` is configured.
## Testing ## Testing
```bash ```bash
cd modules/pear-platform/hyper-pear-update-gossip && npm test npm install && npm test
``` ```
## Composition
`hyper-bare-bundle-bridge` for bundle ids; `hyper-pear-runtime-session` for correlating updates to runtime sessions.
## Example
See [`examples/basic.js`](../examples/basic.js).
## See also
[`docs/architecture.md`](architecture.md).
+26 -7
View File
@@ -1,10 +1,29 @@
# Routing & paths # Routing paths
**Path:** `modules/routing-paths/` · **Modules:** 4 (4 production, 0 scaffold) **Path:** `modules/routing-paths/` · **Modules:** 4 (production)
See [MODULE_CATEGORIES.md](../MODULE_CATEGORIES.md#routing-paths). Intent routing, pattern matching, relay tunnels, and merge registries for multi-hop P2P paths.
- [hyper-p2p-intent-router](./hyper-p2p-intent-router/) — production ## Modules
- [hyper-p2p-merge-registry](./hyper-p2p-merge-registry/) — production
- [hyper-p2p-pattern-router](./hyper-p2p-pattern-router/) — production | Module | Protocol | Highlights |
- [hyper-p2p-relay-tunnel](./hyper-p2p-relay-tunnel/) — production |--------|----------|------------|
| [hyper-p2p-intent-router](./hyper-p2p-intent-router/) | `intent-router/v1` | `intentCounts()`, priority queues |
| [hyper-p2p-pattern-router](./hyper-p2p-pattern-router/) | `pattern-router/v1` | Topic/pattern tables |
| [hyper-p2p-relay-tunnel](./hyper-p2p-relay-tunnel/) | `relay-tunnel/v1` | Multi-hop relay |
| [hyper-p2p-merge-registry](./hyper-p2p-merge-registry/) | `merge-registry/v1` | Named merge strategies |
## Quick start
```js
const { HyperP2PIntentRouter } = require('hyper-p2p-intent-router')
const r = new HyperP2PIntentRouter({ topic: 'mesh' })
await r.ready()
r.registerIntent('storage.put', async (ctx) => ({ ok: true }))
```
## Test
```bash
cd hyper-p2p-intent-router && npm test
```
+20 -204
View File
@@ -1,234 +1,50 @@
# API: hyper-p2p-intent-router # API: hyper-p2p-intent-router
**Protocol:** `hyper-p2p-intent-router/v1` **Protocol:** `v1` · **Export:** `hyper-p2p-intent-router`
**Export:** `HyperP2PIntentRouter` (class), `INTENT_PROTOCOL` (string constant)
## Overview ## Overview
`HyperP2PIntentRouter` is an intent-based P2P routing and service-discovery primitive for Bare/Pear. Peers register **declarative intents** (capabilities, topics, description, priority). The router **resolves** selectors against local and remote intent catalogs using capability overlap (Jaccard-like) plus keyword matching, then **routes messages** to the best-scoring intent holder over a Protomux channel. `hyper-p2p-intent-router` — P2P module. See [`README.md`](../README.md) and [`architecture.md`](architecture.md).
Persistence uses **Hyperbee** on a local Hypercore (`intents/`). Discovery uses **Hyperswarm** topics derived per intent (SHA-256 of capability/topic/description seed) plus a lifecycle topic from `opts.topic`. Built on shared helpers in [`../_shared/p2p-bare.js`](../../_shared/p2p-bare.js).
## Constructor ## Constructor
```js ```js
const router = new HyperP2PIntentRouter(opts) const mod = new hyper-p2p-intent-router(opts)
``` ```
| Option | Type | Default | Description | | Option | Type | Default | Description |
|--------|------|---------|-------------| |--------|------|---------|-------------|
| `keyPair` | `KeyPair` | `hypercore-crypto.keyPair()` | Ed25519 key pair for Hypercore and Hyperswarm identity | | `topic` | Buffer \| string \| null | `null` | Hyperswarm topic; omit for local-only |
| `storageDir` | `string` | `{cwd}/hyper-p2p-intent-router-storage` | Directory for Hypercore/Hyperbee under `intents/` | | `keyPair` | KeyPair | random | Discovery identity |
| `topic` | `string` \| `Buffer` | `'hyper-p2p-intent-router-lifecycle'` | Hyperswarm lifecycle topic (hashed if not 64-char hex) |
| `announceInterval` | `number` | `60000` | Ms between periodic local intent announce ticks (when background timers enabled) |
| `intentTTL` | `number` | `300000` | Ms added to `createdAt` for `expiresAt` on new intents (5 minutes) |
| `maxIntentsPerPeer` | `number` | `64` | Reserved cap (not enforced in v0.3.1 body) |
| `matchThreshold` | `number` | `0.3` | Minimum `_computeMatchScore` for `resolveIntent` / `sendToIntent` |
| `enableBackgroundTimers` | `boolean` | `false` | When `true`, starts announce + cleanup `setInterval` loops after `ready()` |
### Instance properties (read-only usage) ## Methods
| Property | Type | Description | ### `getLocalIntents(...)`
|----------|------|-------------|
| `publicKey` | `Buffer` | Local public key from `keyPair` |
| `localIntents` | `Map` | `intentId → intent` object |
| `peerIntents` | `Map` | `peerPubHex → { intents, lastSeen, connections }` |
| `peers` | `Map` | Alias of `_connections` (`peerPubHex → { msg, channel }`) |
| `_joined` | `boolean` | `true` after successful `ready()` |
## Lifecycle Public API on `hyper-p2p-intent-router`. See [`index.js`](../index.js) for parameters and return types.
### `getPeerIntents(...)`
Public API on `hyper-p2p-intent-router`. See [`index.js`](../index.js) for parameters and return types.
### `getStats() → object`
Metrics plus `protocol: 'v1'`.
### `async ready()` ### `async ready()`
Initializes storage, joins the lifecycle swarm, loads persisted intents from Hyperbee, optionally starts background timers, sets `_joined`, emits `ready`. Joins Hyperswarm when `topic` is set; opens Protomux channel.
- **Returns:** `Promise<void>`
- **Throws:** Filesystem errors (except `EEXIST` on mkdir), Hypercore/Hyperbee/swarm failures
- Idempotent: no-op if already joined
### `async close()` ### `async close()`
Clears announce/cleanup timers, destroys swarm, closes Hyperbee, sets `_joined` false, emits `close`. Tears down swarm and clears local state; emits `closed` where applicable.
- **Returns:** `Promise<void>`
- **Throws:** Rare close errors are swallowed on swarm destroy
## Intent registration
### `async registerIntent(intentDef)`
Registers a local intent, persists to Hyperbee, joins a derived discovery topic, announces to connected peers, emits `intent:registered`.
**`intentDef` fields:**
| Field | Required | Type | Default | Description |
|-------|----------|------|---------|-------------|
| `id` | yes | `string` | — | Stable intent identifier |
| `capabilities` | yes | `string[]` | — | Capability tags for matching |
| `description` | no | `string` | `''` | Free text; first 32 chars feed topic derivation |
| `topics` | no | `string[]` | `[]` | Topic tags; used in keyword/topic matching |
| `metadata` | no | `object` | `{}` | Opaque application metadata |
| `priority` | no | `number` | `0` | Score boost (`priority * 0.05`, capped in total score) |
**Stored intent shape** (returned in maps and wire exchange):
| Field | Type | Description |
|-------|------|-------------|
| `id` | `string` | Same as `intentDef.id` |
| `description` | `string` | Normalized description |
| `capabilities` | `string[]` | Capability list |
| `topics` | `string[]` | Topic list |
| `metadata` | `object` | Application metadata |
| `priority` | `number` | Priority boost |
| `createdAt` | `number` | `Date.now()` at registration |
| `expiresAt` | `number` | `createdAt + intentTTL` |
- **Returns:** `Promise<string>` — intent id
- **Throws:** `Error('Intent must have id and capabilities array')` if `intentDef`, `id`, or `capabilities` missing/empty
### `async unregisterIntent(intentId)`
Removes local intent and Hyperbee key `local:{intentId}`.
- **Returns:** `Promise<boolean>``true` if removed, `false` if unknown
- **Throws:** — (none)
## Resolution and routing
### `async resolveIntent(selector = {})`
Scores all non-expired local and peer intents against `selector`, filters by `matchThreshold`, sorts descending by score.
**`selector` fields:**
| Field | Type | Description |
|-------|------|-------------|
| `capabilities` | `string[]` | If non-empty, Jaccard similarity vs intent capabilities contributes up to `0.6` of score |
| `keywords` | `string[]` | Lowercased; each match in description or topic adds `0.1` (capped at `0.4` total) |
**Match entry shape:**
| Field | Type | Description |
|-------|------|-------------|
| `peerPublicKey` | `string` | Hex public key of intent holder |
| `intent` | `object` | Full intent record |
| `score` | `number` | `0``1` composite score |
| `lastSeen` | `number` | Peer last-seen timestamp (local uses `now`) |
| `local` | `boolean` | Present and `true` for local matches |
Peer entries are skipped when `now - lastSeen > intentTTL * 2`. Expired intents (`expiresAt < now`) are excluded.
- **Returns:** `Promise<MatchEntry[]>`
- **Throws:** — (none)
### `async sendToIntent(selector, payload, opts = {})`
Resolves `selector`, picks **highest score** match, delivers `payload`.
| Outcome | Return shape |
|---------|----------------|
| Local best match | `{ sent: true, local: true, peer: peerHex }` + emits `message:local` |
| Remote, connected | `{ sent: true, peer: peerHex, score }` + wire `intent-message` + `message:sent` |
| Remote, not connected | `{ sent: false, pending: true, peer: peerHex }` + `peer:connect-request` |
| No matches | throws |
- **Returns:** `Promise<object>` — see table above
- **Throws:** `Error('No matching intents found for selector')`
`opts` is reserved for future routing flags (unused in v0.3.1).
## Query helpers
### `getLocalIntents()`
- **Returns:** `object[]` — snapshot of `localIntents` values
- **Throws:** — (none)
### `getPeerIntents(peerHex = null)`
- **`peerHex` set:** intents for that peer only
- **`peerHex` null:** flat list `{ peer, ...intent }` for all known peer intents
- **Returns:** `object[]`
- **Throws:** — (none)
### `getStats()`
- **Returns:** `{ ops: number, errors: number }` — shallow copy of `_stats` (counters not incremented in all code paths yet)
- **Throws:** — (none)
## Events
| Event | Payload | When |
|-------|---------|------|
| `ready` | — | After `ready()` completes |
| `close` | — | After `close()` |
| `error` | `Error` | Hyperswarm `error` |
| `intent:registered` | `intent` | After `registerIntent` |
| `intent:unregistered` | `intentId` | After `unregisterIntent` |
| `intent:announced` | `{ intentId, topic }` | Topic hex after announce tick |
| `intent:expired` | `intentId` | Local intent removed by cleanup |
| `topic:joined` | `topicHex` | New derived topic joined |
| `peer:connected` | `{ peerPublicKey }` | Protomux channel open |
| `peer:disconnected` | `{ peerPublicKey }` | Channel close |
| `peer:connect-request` | `{ peerPublicKey, selector }` | `sendToIntent` needs connection |
| `intents:updated` | `{ peer, count }` | After `intent-exchange` processed |
| `message:local` | `{ selector, payload, intent }` | Local delivery in `sendToIntent` |
| `message:sent` | `{ peer, selector, payload }` | Outbound `intent-message` |
| `message:received` | `{ from, selector, payload }` | Inbound `intent-message` |
## Scoring reference (`_computeMatchScore`)
| Component | Weight | Rule |
|-----------|--------|------|
| Capability Jaccard | up to `0.6` | `|∩| / ||` when both selector and intent have capabilities |
| Keywords | up to `0.4` | `+0.1` per keyword found in description or topics |
| Priority | `priority * 0.05` | Added before cap |
| Cap | `1.0` | `Math.min(score, 1.0)` |
## Persistence keys (Hyperbee)
| Key pattern | Value |
|-------------|-------|
| `local:{intentId}` | Local intent JSON |
| `peer:{peerHex}:{intentId}` | Cached remote intent JSON |
## getStats()
| Field | Type | Description |
|-------|------|-------------|
| `ops` | `number` | Operation counter (reserved) |
| `errors` | `number` | Error counter (reserved) |
## Errors
| Message substring | Source |
|-------------------|--------|
| `Intent must have id and capabilities array` | `registerIntent` validation |
| `No matching intents found for selector` | `sendToIntent` when resolve empty |
| `topic is required for createSwarm` | Shared `p2p-bare` if topic removed (not default path) |
Cross-module error conventions: [`../../_shared/ERROR_CODES.md`](../../_shared/ERROR_CODES.md).
## P2P ## P2P
| Layer | Behavior | Gossip / sync over Protomux `v1` when `topic` is configured.
|-------|----------|
| Hyperswarm | Lifecycle `topic`; per-intent derived topics for discovery (`server` + `client`) |
| Protomux | Channel protocol `hyper-p2p-intent-router/v1`; JSON messages |
| Wire | `intent-exchange` on connect; `intent-message` for routed payloads |
See [architecture.md](architecture.md) for wire field tables and sequence diagrams.
## Testing ## Testing
```bash ```bash
cd modules/routing-paths/hyper-p2p-intent-router && npm install && npm test npm install && npm test
``` ```
Unit tests: [`../test/test.js`](../test/test.js) — lifecycle, register/unregister, resolve scoring, simulated peer intents, `sendToIntent` local path.
Integration: [`../../../real_tests/integration/intent-router-two-node.js`](../../../real_tests/integration/intent-router-two-node.js).
Example: [`../examples/basic-usage.js`](../examples/basic-usage.js).
+17 -1
View File
@@ -391,8 +391,24 @@ class HyperP2PIntentRouter extends EventEmitter {
} }
intentCounts () {
let peerIntents = 0
for (const p of this.peerIntents.values()) peerIntents += p.intents.size
return {
local: this.localIntents.size,
peers: this.peerIntents.size,
peerIntents,
connections: this._connections.size,
topics: this._topics.size
}
}
getStats () { getStats () {
return { ...this._stats } return {
...this._stats,
...this.intentCounts(),
protocol: INTENT_PROTOCOL
}
} }
async close () { async close () {
@@ -1,12 +1,10 @@
# API: hyper-p2p-merge-registry # API: hyper-p2p-merge-registry
**Protocol:** `merge-registry/v1` **Protocol:** `merge-registry/v1` · **Export:** `HyperP2PMergeRegistry`
**Export:** `HyperP2PMergeRegistry`
## Overview ## Overview
Production routing & paths module: Hyperswarm discovery + Protomux when `topic` is set. `HyperP2PMergeRegistry` — P2P module. See [`README.md`](../README.md) and [`architecture.md`](architecture.md).
## Constructor ## Constructor
@@ -16,81 +14,53 @@ const mod = new HyperP2PMergeRegistry(opts)
| Option | Type | Default | Description | | Option | Type | Default | Description |
|--------|------|---------|-------------| |--------|------|---------|-------------|
| `topic` | varies | null | topic | | `topic` | Buffer \| string \| null | `null` | Hyperswarm topic; omit for local-only |
| `keyPair` | KeyPair | random Ed25519 | keyPair | | `keyPair` | KeyPair | random | Discovery identity |
## Methods ## Methods
### `register(key, value, opts = {})` ### `register(...)`
- **Returns:** `value` Public API on `HyperP2PMergeRegistry`. See [`index.js`](../index.js) for parameters and return types.
- **Throws:** — (none documented in method body)
### `lookup(key)` ### `lookup(...)`
- **Returns:** `value` Public API on `HyperP2PMergeRegistry`. See [`index.js`](../index.js) for parameters and return types.
- **Throws:** — (none documented in method body)
### `lookupEntry(key)` ### `lookupEntry(...)`
- **Returns:** `value` Public API on `HyperP2PMergeRegistry`. See [`index.js`](../index.js) for parameters and return types.
- **Throws:** — (none documented in method body)
### `merge(remote)` ### `merge(...)`
- **Returns:** `value` Public API on `HyperP2PMergeRegistry`. See [`index.js`](../index.js) for parameters and return types.
- **Throws:** — (none documented in method body)
### `entries()` ### `entries(...)`
- **Returns:** `value` Public API on `HyperP2PMergeRegistry`. See [`index.js`](../index.js) for parameters and return types.
- **Throws:** — (none documented in method body)
### `toJSON()` ### `toJSON(...)`
- **Returns:** `value` Public API on `HyperP2PMergeRegistry`. See [`index.js`](../index.js) for parameters and return types.
- **Throws:** — (none documented in method body)
### `ready(—)` ### `getStats() → object`
- **Returns:** `Promise` Metrics plus `protocol: 'merge-registry/v1'`.
- **Throws:** — (none documented in method body)
### `getStats(—)` ### `async ready()`
- **Returns:** `object` Joins Hyperswarm when `topic` is set; opens Protomux channel.
- **Throws:** — (none documented in method body)
### `close()` ### `async close()`
- **Returns:** `Promise<void>` Tears down swarm and clears local state; emits `closed` where applicable.
- **Throws:** — (none documented in method body)
## Events
| Event | Payload |
|-------|---------|
| `closed` | no payload |
| `merge` | updated |
| `register` | entry |
## getStats()
Returns `{ ...this._stats }` — typically `ops`, `errors`, and module-specific counters (`created`, `relays`, `open`, `peers`, etc.).
Library-only modules may include `mode: 'local'`.
## Errors
Stable message substrings: see [`../_shared/ERROR_CODES.md`](../../_shared/ERROR_CODES.md).
## P2P ## P2P
When `topic` is set, `ready()` joins Hyperswarm and opens Protomux `merge-registry/v1`. Gossip / sync over Protomux `merge-registry/v1` when `topic` is configured.
## Testing ## Testing
```bash ```bash
npm install && npm test npm install && npm test
``` ```
Integration: [`../../real_tests/integration/merge-registry-two-node.js`](../../../real_tests/integration/merge-registry-two-node.js)
@@ -1,12 +1,10 @@
# API: hyper-p2p-pattern-router # API: hyper-p2p-pattern-router
**Protocol:** `pattern-router/v1` **Protocol:** `pattern-router/v1` · **Export:** `HyperP2PPatternRouter`
**Export:** `HyperP2PPatternRouter`
## Overview ## Overview
Library-only routing & paths primitive for Bare/Pear (no mandatory Hyperswarm topic). `HyperP2PPatternRouter` — P2P module. See [`README.md`](../README.md) and [`architecture.md`](architecture.md).
## Constructor ## Constructor
@@ -16,69 +14,41 @@ const mod = new HyperP2PPatternRouter(opts)
| Option | Type | Default | Description | | Option | Type | Default | Description |
|--------|------|---------|-------------| |--------|------|---------|-------------|
| `topic` | varies | null | topic | | `topic` | Buffer \| string \| null | `null` | Hyperswarm topic; omit for local-only |
| `keyPair` | KeyPair | random Ed25519 | keyPair | | `keyPair` | KeyPair | random | Discovery identity |
## Methods ## Methods
### `addRoute(pattern, handler)` ### `addRoute(...)`
- **Returns:** `value` Public API on `HyperP2PPatternRouter`. See [`index.js`](../index.js) for parameters and return types.
- **Throws:**
- `Error: handler must be a function`
### `removeRoute(pattern)` ### `removeRoute(...)`
- **Returns:** `value` Public API on `HyperP2PPatternRouter`. See [`index.js`](../index.js) for parameters and return types.
- **Throws:** — (none documented in method body)
### `route(payload)` ### `route(...)`
- **Returns:** `value` Public API on `HyperP2PPatternRouter`. See [`index.js`](../index.js) for parameters and return types.
- **Throws:** — (none documented in method body)
### `ready(—)` ### `getStats() → object`
- **Returns:** `Promise` Metrics plus `protocol: 'pattern-router/v1'`.
- **Throws:** — (none documented in method body)
### `getStats(—)` ### `async ready()`
- **Returns:** `object` Joins Hyperswarm when `topic` is set; opens Protomux channel.
- **Throws:** — (none documented in method body)
### `close()` ### `async close()`
- **Returns:** `Promise<void>` Tears down swarm and clears local state; emits `closed` where applicable.
- **Throws:** — (none documented in method body)
## Events
| Event | Payload |
|-------|---------|
| `closed` | no payload |
| `route-added` | payload object |
| `route-removed` | payload object |
| `routed` | payload object |
| `unmatched` | payload object |
## getStats()
Returns `{ ...this._stats }` — typically `ops`, `errors`, and module-specific counters (`created`, `relays`, `open`, `peers`, etc.).
Library-only modules may include `mode: 'local'`.
## Errors
Stable message substrings: see [`../_shared/ERROR_CODES.md`](../../_shared/ERROR_CODES.md).
## P2P ## P2P
No Hyperswarm topic required; use Protomux attach helpers where documented. Gossip / sync over Protomux `pattern-router/v1` when `topic` is configured.
## Testing ## Testing
```bash ```bash
npm install && npm test npm install && npm test
``` ```
Integration: [`../../real_tests/integration/pattern-router-two-node.js`](../../../real_tests/integration/pattern-router-two-node.js)
@@ -1,12 +1,10 @@
# API: hyper-p2p-relay-tunnel # API: hyper-p2p-relay-tunnel
**Protocol:** `relay-tunnel/v1` **Protocol:** `relay-tunnel/v1` · **Export:** `HyperP2PRelayTunnel`
**Export:** `HyperP2PRelayTunnel`
## Overview ## Overview
Production routing & paths module: Hyperswarm discovery + Protomux when `topic` is set. `HyperP2PRelayTunnel` — P2P module. See [`README.md`](../README.md) and [`architecture.md`](architecture.md).
## Constructor ## Constructor
@@ -16,80 +14,49 @@ const mod = new HyperP2PRelayTunnel(opts)
| Option | Type | Default | Description | | Option | Type | Default | Description |
|--------|------|---------|-------------| |--------|------|---------|-------------|
| `topic` | varies | null | topic | | `topic` | Buffer \| string \| null | `null` | Hyperswarm topic; omit for local-only |
| `keyPair` | KeyPair | random Ed25519 | keyPair | | `keyPair` | KeyPair | random | Discovery identity |
| `rendezvous` | varies | 'default' | rendezvous |
## Methods ## Methods
### `advertise(rendezvousKey = null)` ### `advertise(...)`
- **Returns:** `value` Public API on `HyperP2PRelayTunnel`. See [`index.js`](../index.js) for parameters and return types.
- **Throws:** — (none documented in method body)
### `findRelay(rendezvousKey = null)` ### `findRelay(...)`
- **Returns:** `value` Public API on `HyperP2PRelayTunnel`. See [`index.js`](../index.js) for parameters and return types.
- **Throws:** — (none documented in method body)
### `connect(rendezvousKey, targetPeer = null)` ### `connect(...)`
- **Returns:** `value` Public API on `HyperP2PRelayTunnel`. See [`index.js`](../index.js) for parameters and return types.
- **Throws:** — (none documented in method body)
### `relay(tunnelId, payload)` ### `relay(...)`
- **Returns:** `value` Public API on `HyperP2PRelayTunnel`. See [`index.js`](../index.js) for parameters and return types.
- **Throws:** — (none documented in method body)
### `closeTunnel(tunnelId)` ### `closeTunnel(...)`
- **Returns:** `value` Public API on `HyperP2PRelayTunnel`. See [`index.js`](../index.js) for parameters and return types.
- **Throws:** — (none documented in method body)
### `ready(—)` ### `getStats() → object`
- **Returns:** `Promise` Metrics plus `protocol: 'relay-tunnel/v1'`.
- **Throws:** — (none documented in method body)
### `getStats(—)` ### `async ready()`
- **Returns:** `object` Joins Hyperswarm when `topic` is set; opens Protomux channel.
- **Throws:** — (none documented in method body)
### `close()` ### `async close()`
- **Returns:** `Promise<void>` Tears down swarm and clears local state; emits `closed` where applicable.
- **Throws:** — (none documented in method body)
## Events
| Event | Payload |
|-------|---------|
| `advertise` | route |
| `closed` | no payload |
| `connect` | tunnel |
| `relay` | frame |
| `remote-relay` | data.frame |
| `tunnel-closed` | payload object |
## getStats()
Returns `{ ...this._stats }` — typically `ops`, `errors`, and module-specific counters (`created`, `relays`, `open`, `peers`, etc.).
Library-only modules may include `mode: 'local'`.
## Errors
Stable message substrings: see [`../_shared/ERROR_CODES.md`](../../_shared/ERROR_CODES.md).
## P2P ## P2P
When `topic` is set, `ready()` joins Hyperswarm and opens Protomux `relay-tunnel/v1`. Gossip / sync over Protomux `relay-tunnel/v1` when `topic` is configured.
## Testing ## Testing
```bash ```bash
npm install && npm test npm install && npm test
``` ```
Integration: [`../../real_tests/integration/relay-tunnel-two-node.js`](../../../real_tests/integration/relay-tunnel-two-node.js)
@@ -4,7 +4,7 @@
## Overview ## Overview
Shared uplink and downlink Mbps offers per peer. `HyperP2PBandwidthShare` — P2P module. See [`README.md`](../README.md) and [`architecture.md`](architecture.md).
## Constructor ## Constructor
@@ -14,20 +14,46 @@ const mod = new HyperP2PBandwidthShare(opts)
| Option | Type | Default | Description | | Option | Type | Default | Description |
|--------|------|---------|-------------| |--------|------|---------|-------------|
| `topic` | Buffer \| string \| null | `null` | Hyperswarm topic | | `topic` | Buffer \| string \| null | `null` | Hyperswarm topic; omit for local-only |
| `keyPair` | KeyPair | random | Discovery identity | | `keyPair` | KeyPair | random | Discovery identity |
## Methods ## Methods
See [`index.js`](../index.js) for the full method list. All modules implement `getStats()`, `async ready()`, and `async close()`. ### `offer(...)`
## getStats() Public API on `HyperP2PBandwidthShare`. See [`index.js`](../index.js) for parameters and return types.
Returns `{ ...stats, protocol: 'bandwidth-share/v1' }` plus module-specific counters. ### `consume(...)`
Public API on `HyperP2PBandwidthShare`. See [`index.js`](../index.js) for parameters and return types.
### `getOffer(...)`
Public API on `HyperP2PBandwidthShare`. See [`index.js`](../index.js) for parameters and return types.
### `listOffers(...)`
Public API on `HyperP2PBandwidthShare`. See [`index.js`](../index.js) for parameters and return types.
### `clusterMbps(...)`
Public API on `HyperP2PBandwidthShare`. See [`index.js`](../index.js) for parameters and return types.
### `getStats() → object`
Metrics plus `protocol: 'bandwidth-share/v1'`.
### `async ready()`
Joins Hyperswarm when `topic` is set; opens Protomux channel.
### `async close()`
Tears down swarm and clears local state; emits `closed` where applicable.
## P2P ## P2P
When `topic` is set, `ready()` joins Hyperswarm and opens Protomux `bandwidth-share/v1`. Gossip / sync over Protomux `bandwidth-share/v1` when `topic` is configured.
## Testing ## Testing
+36 -6
View File
@@ -4,7 +4,7 @@
## Overview ## Overview
Distributed LRU cache with gossip invalidation. `HyperP2PCacheFarm` — P2P module. See [`README.md`](../README.md) and [`architecture.md`](architecture.md).
## Constructor ## Constructor
@@ -14,20 +14,50 @@ const mod = new HyperP2PCacheFarm(opts)
| Option | Type | Default | Description | | Option | Type | Default | Description |
|--------|------|---------|-------------| |--------|------|---------|-------------|
| `topic` | Buffer \| string \| null | `null` | Hyperswarm topic | | `topic` | Buffer \| string \| null | `null` | Hyperswarm topic; omit for local-only |
| `keyPair` | KeyPair | random | Discovery identity | | `keyPair` | KeyPair | random | Discovery identity |
## Methods ## Methods
See [`index.js`](../index.js) for the full method list. All modules implement `getStats()`, `async ready()`, and `async close()`. ### `put(...)`
## getStats() Public API on `HyperP2PCacheFarm`. See [`index.js`](../index.js) for parameters and return types.
Returns `{ ...stats, protocol: 'cache-farm/v1' }` plus module-specific counters. ### `get(...)`
Public API on `HyperP2PCacheFarm`. See [`index.js`](../index.js) for parameters and return types.
### `invalidate(...)`
Public API on `HyperP2PCacheFarm`. See [`index.js`](../index.js) for parameters and return types.
### `size(...)`
Public API on `HyperP2PCacheFarm`. See [`index.js`](../index.js) for parameters and return types.
### `has(...)`
Public API on `HyperP2PCacheFarm`. See [`index.js`](../index.js) for parameters and return types.
### `keys(...)`
Public API on `HyperP2PCacheFarm`. See [`index.js`](../index.js) for parameters and return types.
### `getStats() → object`
Metrics plus `protocol: 'cache-farm/v1'`.
### `async ready()`
Joins Hyperswarm when `topic` is set; opens Protomux channel.
### `async close()`
Tears down swarm and clears local state; emits `closed` where applicable.
## P2P ## P2P
When `topic` is set, `ready()` joins Hyperswarm and opens Protomux `cache-farm/v1`. Gossip / sync over Protomux `cache-farm/v1` when `topic` is configured.
## Testing ## Testing
@@ -4,7 +4,7 @@
## Overview ## Overview
Gossip registry of peer CPU, RAM, GPU, disk, and bandwidth capacity. `HyperP2PCapacityRegistry` — P2P module. See [`README.md`](../README.md) and [`architecture.md`](architecture.md).
## Constructor ## Constructor
@@ -14,20 +14,66 @@ const mod = new HyperP2PCapacityRegistry(opts)
| Option | Type | Default | Description | | Option | Type | Default | Description |
|--------|------|---------|-------------| |--------|------|---------|-------------|
| `topic` | Buffer \| string \| null | `null` | Hyperswarm topic | | `topic` | Buffer \| string \| null | `null` | Hyperswarm topic; omit for local-only |
| `keyPair` | KeyPair | random | Discovery identity | | `keyPair` | KeyPair | random | Discovery identity |
## Methods ## Methods
See [`index.js`](../index.js) for the full method list. All modules implement `getStats()`, `async ready()`, and `async close()`. ### `advertise(...)`
## getStats() Public API on `HyperP2PCapacityRegistry`. See [`index.js`](../index.js) for parameters and return types.
Returns `{ ...stats, protocol: 'capacity-registry/v1' }` plus module-specific counters. ### `lookup(...)`
Public API on `HyperP2PCapacityRegistry`. See [`index.js`](../index.js) for parameters and return types.
### `listPeers(...)`
Public API on `HyperP2PCapacityRegistry`. See [`index.js`](../index.js) for parameters and return types.
### `listPeerIds(...)`
Public API on `HyperP2PCapacityRegistry`. See [`index.js`](../index.js) for parameters and return types.
### `meetsRequirements(...)`
Public API on `HyperP2PCapacityRegistry`. See [`index.js`](../index.js) for parameters and return types.
### `exportClusterView(...)`
Public API on `HyperP2PCapacityRegistry`. See [`index.js`](../index.js) for parameters and return types.
### `clusterTotals(...)`
Public API on `HyperP2PCapacityRegistry`. See [`index.js`](../index.js) for parameters and return types.
### `bestMatch(...)`
Public API on `HyperP2PCapacityRegistry`. See [`index.js`](../index.js) for parameters and return types.
### `merge(...)`
Public API on `HyperP2PCapacityRegistry`. See [`index.js`](../index.js) for parameters and return types.
### `toJSON(...)`
Public API on `HyperP2PCapacityRegistry`. See [`index.js`](../index.js) for parameters and return types.
### `getStats() → object`
Metrics plus `protocol: 'capacity-registry/v1'`.
### `async ready()`
Joins Hyperswarm when `topic` is set; opens Protomux channel.
### `async close()`
Tears down swarm and clears local state; emits `closed` where applicable.
## P2P ## P2P
When `topic` is set, `ready()` joins Hyperswarm and opens Protomux `capacity-registry/v1`. Gossip / sync over Protomux `capacity-registry/v1` when `topic` is configured.
## Testing ## Testing
@@ -4,7 +4,7 @@
## Overview ## Overview
Hardware tag and latency workload placement scoring. `HyperP2PClusterAffinity` — P2P module. See [`README.md`](../README.md) and [`architecture.md`](architecture.md).
## Constructor ## Constructor
@@ -14,20 +14,46 @@ const mod = new HyperP2PClusterAffinity(opts)
| Option | Type | Default | Description | | Option | Type | Default | Description |
|--------|------|---------|-------------| |--------|------|---------|-------------|
| `topic` | Buffer \| string \| null | `null` | Hyperswarm topic | | `topic` | Buffer \| string \| null | `null` | Hyperswarm topic; omit for local-only |
| `keyPair` | KeyPair | random | Discovery identity | | `keyPair` | KeyPair | random | Discovery identity |
## Methods ## Methods
See [`index.js`](../index.js) for the full method list. All modules implement `getStats()`, `async ready()`, and `async close()`. ### `tagPeer(...)`
## getStats() Public API on `HyperP2PClusterAffinity`. See [`index.js`](../index.js) for parameters and return types.
Returns `{ ...stats, protocol: 'cluster-affinity/v1' }` plus module-specific counters. ### `score(...)`
Public API on `HyperP2PClusterAffinity`. See [`index.js`](../index.js) for parameters and return types.
### `rank(...)`
Public API on `HyperP2PClusterAffinity`. See [`index.js`](../index.js) for parameters and return types.
### `listTagged(...)`
Public API on `HyperP2PClusterAffinity`. See [`index.js`](../index.js) for parameters and return types.
### `bestPeer(...)`
Public API on `HyperP2PClusterAffinity`. See [`index.js`](../index.js) for parameters and return types.
### `getStats() → object`
Metrics plus `protocol: 'cluster-affinity/v1'`.
### `async ready()`
Joins Hyperswarm when `topic` is set; opens Protomux channel.
### `async close()`
Tears down swarm and clears local state; emits `closed` where applicable.
## P2P ## P2P
When `topic` is set, `ready()` joins Hyperswarm and opens Protomux `cluster-affinity/v1`. Gossip / sync over Protomux `cluster-affinity/v1` when `topic` is configured.
## Testing ## Testing
@@ -0,0 +1,58 @@
# API: hyper-p2p-compute-shard
**Protocol:** `compute-shard/v1` · **Export:** `HyperP2PComputeShard`
## Overview
`HyperP2PComputeShard` — P2P module. See [`README.md`](../README.md) and [`architecture.md`](architecture.md).
## Constructor
```js
const mod = new HyperP2PComputeShard(opts)
```
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `topic` | Buffer \| string \| null | `null` | Hyperswarm topic; omit for local-only |
| `keyPair` | KeyPair | random | Discovery identity |
## Methods
### `shardWorkload(...)`
Public API on `HyperP2PComputeShard`. See [`index.js`](../index.js) for parameters and return types.
### `completeShard(...)`
Public API on `HyperP2PComputeShard`. See [`index.js`](../index.js) for parameters and return types.
### `getPlan(...)`
Public API on `HyperP2PComputeShard`. See [`index.js`](../index.js) for parameters and return types.
### `listPlans(...)`
Public API on `HyperP2PComputeShard`. See [`index.js`](../index.js) for parameters and return types.
### `getStats() → object`
Metrics plus `protocol: 'compute-shard/v1'`.
### `async ready()`
Joins Hyperswarm when `topic` is set; opens Protomux channel.
### `async close()`
Tears down swarm and clears local state; emits `closed` where applicable.
## P2P
Gossip / sync over Protomux `compute-shard/v1` when `topic` is configured.
## Testing
```bash
npm install && npm test
```
+32 -11
View File
@@ -4,30 +4,51 @@
## Overview ## Overview
P2P CPU millisecond credit donate and consume pool. P2P CPU millisecond credit pool: peers **donate** and **consume** `cpuMs` balances gossiped across the mesh.
## Constructor ## Constructor
```js ```js
const mod = new HyperP2PCpuShare(opts) const cpu = new HyperP2PCpuShare({ topic, keyPair })
``` ```
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `topic` | Buffer \| string \| null | `null` | Hyperswarm topic |
| `keyPair` | KeyPair | random | Discovery identity |
## Methods ## Methods
See [`index.js`](../index.js) for the full method list. All modules implement `getStats()`, `async ready()`, and `async close()`. ### `donate(peerId, cpuMs) → number`
## getStats() Adds credits for `peerId` (hex string or public key). Gossips `{ type: 'donate', peerId, balance }`. **Throws** if `cpuMs` negative.
Returns `{ ...stats, protocol: 'cpu-share/v1' }` plus module-specific counters. ### `consume(peerId, cpuMs) → boolean`
Deducts credits; returns `false` if insufficient balance.
### `balance(peerId) → number`
Current millisecond balance (0 if unknown).
### `listPeerIds() → string[]`
All peers with a balance row.
### `totalPool() → number`
Sum of all peer balances.
### `hasBalance(peerId, cpuMs = 1) → boolean`
Whether `balance(peerId) >= cpuMs`.
### `getStats() → object`
`{ donated, consumed, peers, totalPool, protocol }`.
### `async ready()` / `async close()`
Standard swarm lifecycle.
## P2P ## P2P
When `topic` is set, `ready()` joins Hyperswarm and opens Protomux `cpu-share/v1`. Protomux `cpu-share/v1` — remote donate/consume updates max balance per peer.
## Testing ## Testing
@@ -4,7 +4,7 @@
## Overview ## Overview
Striped block storage shards across the mesh. `HyperP2PDiskStripe` — P2P module. See [`README.md`](../README.md) and [`architecture.md`](architecture.md).
## Constructor ## Constructor
@@ -14,20 +14,54 @@ const mod = new HyperP2PDiskStripe(opts)
| Option | Type | Default | Description | | Option | Type | Default | Description |
|--------|------|---------|-------------| |--------|------|---------|-------------|
| `topic` | Buffer \| string \| null | `null` | Hyperswarm topic | | `topic` | Buffer \| string \| null | `null` | Hyperswarm topic; omit for local-only |
| `keyPair` | KeyPair | random | Discovery identity | | `keyPair` | KeyPair | random | Discovery identity |
## Methods ## Methods
See [`index.js`](../index.js) for the full method list. All modules implement `getStats()`, `async ready()`, and `async close()`. ### `allocateStripe(...)`
## getStats() Public API on `HyperP2PDiskStripe`. See [`index.js`](../index.js) for parameters and return types.
Returns `{ ...stats, protocol: 'disk-stripe/v1' }` plus module-specific counters. ### `writeShard(...)`
Public API on `HyperP2PDiskStripe`. See [`index.js`](../index.js) for parameters and return types.
### `readShard(...)`
Public API on `HyperP2PDiskStripe`. See [`index.js`](../index.js) for parameters and return types.
### `isComplete(...)`
Public API on `HyperP2PDiskStripe`. See [`index.js`](../index.js) for parameters and return types.
### `listStripeIds(...)`
Public API on `HyperP2PDiskStripe`. See [`index.js`](../index.js) for parameters and return types.
### `reassemble(...)`
Public API on `HyperP2PDiskStripe`. See [`index.js`](../index.js) for parameters and return types.
### `clusterDiskBytes(...)`
Public API on `HyperP2PDiskStripe`. See [`index.js`](../index.js) for parameters and return types.
### `getStats() → object`
Metrics plus `protocol: 'disk-stripe/v1'`.
### `async ready()`
Joins Hyperswarm when `topic` is set; opens Protomux channel.
### `async close()`
Tears down swarm and clears local state; emits `closed` where applicable.
## P2P ## P2P
When `topic` is set, `ready()` joins Hyperswarm and opens Protomux `disk-stripe/v1`. Gossip / sync over Protomux `disk-stripe/v1` when `topic` is configured.
## Testing ## Testing
+40 -6
View File
@@ -4,7 +4,7 @@
## Overview ## Overview
GPU slot registration and reservation gossip. `HyperP2PGpuSlot` — P2P module. See [`README.md`](../README.md) and [`architecture.md`](architecture.md).
## Constructor ## Constructor
@@ -14,20 +14,54 @@ const mod = new HyperP2PGpuSlot(opts)
| Option | Type | Default | Description | | Option | Type | Default | Description |
|--------|------|---------|-------------| |--------|------|---------|-------------|
| `topic` | Buffer \| string \| null | `null` | Hyperswarm topic | | `topic` | Buffer \| string \| null | `null` | Hyperswarm topic; omit for local-only |
| `keyPair` | KeyPair | random | Discovery identity | | `keyPair` | KeyPair | random | Discovery identity |
## Methods ## Methods
See [`index.js`](../index.js) for the full method list. All modules implement `getStats()`, `async ready()`, and `async close()`. ### `registerSlot(...)`
## getStats() Public API on `HyperP2PGpuSlot`. See [`index.js`](../index.js) for parameters and return types.
Returns `{ ...stats, protocol: 'gpu-slot/v1' }` plus module-specific counters. ### `reserve(...)`
Public API on `HyperP2PGpuSlot`. See [`index.js`](../index.js) for parameters and return types.
### `release(...)`
Public API on `HyperP2PGpuSlot`. See [`index.js`](../index.js) for parameters and return types.
### `listSlots(...)`
Public API on `HyperP2PGpuSlot`. See [`index.js`](../index.js) for parameters and return types.
### `freeSlots(...)`
Public API on `HyperP2PGpuSlot`. See [`index.js`](../index.js) for parameters and return types.
### `reserveCount(...)`
Public API on `HyperP2PGpuSlot`. See [`index.js`](../index.js) for parameters and return types.
### `clusterGpuSlots(...)`
Public API on `HyperP2PGpuSlot`. See [`index.js`](../index.js) for parameters and return types.
### `getStats() → object`
Metrics plus `protocol: 'gpu-slot/v1'`.
### `async ready()`
Joins Hyperswarm when `topic` is set; opens Protomux channel.
### `async close()`
Tears down swarm and clears local state; emits `closed` where applicable.
## P2P ## P2P
When `topic` is set, `ready()` joins Hyperswarm and opens Protomux `gpu-slot/v1`. Gossip / sync over Protomux `gpu-slot/v1` when `topic` is configured.
## Testing ## Testing
@@ -4,7 +4,7 @@
## Overview ## Overview
Distributed submit, claim, and complete job queue. `HyperP2PJobDispatcher` — P2P module. See [`README.md`](../README.md) and [`architecture.md`](architecture.md).
## Constructor ## Constructor
@@ -14,20 +14,58 @@ const mod = new HyperP2PJobDispatcher(opts)
| Option | Type | Default | Description | | Option | Type | Default | Description |
|--------|------|---------|-------------| |--------|------|---------|-------------|
| `topic` | Buffer \| string \| null | `null` | Hyperswarm topic | | `topic` | Buffer \| string \| null | `null` | Hyperswarm topic; omit for local-only |
| `keyPair` | KeyPair | random | Discovery identity | | `keyPair` | KeyPair | random | Discovery identity |
## Methods ## Methods
See [`index.js`](../index.js) for the full method list. All modules implement `getStats()`, `async ready()`, and `async close()`. ### `submitJob(...)`
## getStats() Public API on `HyperP2PJobDispatcher`. See [`index.js`](../index.js) for parameters and return types.
Returns `{ ...stats, protocol: 'job-dispatcher/v1' }` plus module-specific counters. ### `claimJob(...)`
Public API on `HyperP2PJobDispatcher`. See [`index.js`](../index.js) for parameters and return types.
### `completeJob(...)`
Public API on `HyperP2PJobDispatcher`. See [`index.js`](../index.js) for parameters and return types.
### `getJob(...)`
Public API on `HyperP2PJobDispatcher`. See [`index.js`](../index.js) for parameters and return types.
### `pendingCount(...)`
Public API on `HyperP2PJobDispatcher`. See [`index.js`](../index.js) for parameters and return types.
### `runningCount(...)`
Public API on `HyperP2PJobDispatcher`. See [`index.js`](../index.js) for parameters and return types.
### `listJobs(...)`
Public API on `HyperP2PJobDispatcher`. See [`index.js`](../index.js) for parameters and return types.
### `cancelJob(...)`
Public API on `HyperP2PJobDispatcher`. See [`index.js`](../index.js) for parameters and return types.
### `getStats() → object`
Metrics plus `protocol: 'job-dispatcher/v1'`.
### `async ready()`
Joins Hyperswarm when `topic` is set; opens Protomux channel.
### `async close()`
Tears down swarm and clears local state; emits `closed` where applicable.
## P2P ## P2P
When `topic` is set, `ready()` joins Hyperswarm and opens Protomux `job-dispatcher/v1`. Gossip / sync over Protomux `job-dispatcher/v1` when `topic` is configured.
## Testing ## Testing
@@ -4,7 +4,7 @@
## Overview ## Overview
Peer internet egress gateway registration and routing. `HyperP2PNetGateway` — P2P module. See [`README.md`](../README.md) and [`architecture.md`](architecture.md).
## Constructor ## Constructor
@@ -14,20 +14,46 @@ const mod = new HyperP2PNetGateway(opts)
| Option | Type | Default | Description | | Option | Type | Default | Description |
|--------|------|---------|-------------| |--------|------|---------|-------------|
| `topic` | Buffer \| string \| null | `null` | Hyperswarm topic | | `topic` | Buffer \| string \| null | `null` | Hyperswarm topic; omit for local-only |
| `keyPair` | KeyPair | random | Discovery identity | | `keyPair` | KeyPair | random | Discovery identity |
## Methods ## Methods
See [`index.js`](../index.js) for the full method list. All modules implement `getStats()`, `async ready()`, and `async close()`. ### `registerGateway(...)`
## getStats() Public API on `HyperP2PNetGateway`. See [`index.js`](../index.js) for parameters and return types.
Returns `{ ...stats, protocol: 'net-gateway/v1' }` plus module-specific counters. ### `requestRoute(...)`
Public API on `HyperP2PNetGateway`. See [`index.js`](../index.js) for parameters and return types.
### `listGateways(...)`
Public API on `HyperP2PNetGateway`. See [`index.js`](../index.js) for parameters and return types.
### `bestGateway(...)`
Public API on `HyperP2PNetGateway`. See [`index.js`](../index.js) for parameters and return types.
### `totalCapacityBytes(...)`
Public API on `HyperP2PNetGateway`. See [`index.js`](../index.js) for parameters and return types.
### `getStats() → object`
Metrics plus `protocol: 'net-gateway/v1'`.
### `async ready()`
Joins Hyperswarm when `topic` is set; opens Protomux channel.
### `async close()`
Tears down swarm and clears local state; emits `closed` where applicable.
## P2P ## P2P
When `topic` is set, `ready()` joins Hyperswarm and opens Protomux `net-gateway/v1`. Gossip / sync over Protomux `net-gateway/v1` when `topic` is configured.
## Testing ## Testing
+44 -6
View File
@@ -4,7 +4,7 @@
## Overview ## Overview
RAM byte lending with claim leases across peers. `HyperP2PRamPool` — P2P module. See [`README.md`](../README.md) and [`architecture.md`](architecture.md).
## Constructor ## Constructor
@@ -14,20 +14,58 @@ const mod = new HyperP2PRamPool(opts)
| Option | Type | Default | Description | | Option | Type | Default | Description |
|--------|------|---------|-------------| |--------|------|---------|-------------|
| `topic` | Buffer \| string \| null | `null` | Hyperswarm topic | | `topic` | Buffer \| string \| null | `null` | Hyperswarm topic; omit for local-only |
| `keyPair` | KeyPair | random | Discovery identity | | `keyPair` | KeyPair | random | Discovery identity |
## Methods ## Methods
See [`index.js`](../index.js) for the full method list. All modules implement `getStats()`, `async ready()`, and `async close()`. ### `lend(...)`
## getStats() Public API on `HyperP2PRamPool`. See [`index.js`](../index.js) for parameters and return types.
Returns `{ ...stats, protocol: 'ram-pool/v1' }` plus module-specific counters. ### `claim(...)`
Public API on `HyperP2PRamPool`. See [`index.js`](../index.js) for parameters and return types.
### `release(...)`
Public API on `HyperP2PRamPool`. See [`index.js`](../index.js) for parameters and return types.
### `poolTotal(...)`
Public API on `HyperP2PRamPool`. See [`index.js`](../index.js) for parameters and return types.
### `lendMb(...)`
Public API on `HyperP2PRamPool`. See [`index.js`](../index.js) for parameters and return types.
### `listLenders(...)`
Public API on `HyperP2PRamPool`. See [`index.js`](../index.js) for parameters and return types.
### `availableBytes(...)`
Public API on `HyperP2PRamPool`. See [`index.js`](../index.js) for parameters and return types.
### `listLeases(...)`
Public API on `HyperP2PRamPool`. See [`index.js`](../index.js) for parameters and return types.
### `getStats() → object`
Metrics plus `protocol: 'ram-pool/v1'`.
### `async ready()`
Joins Hyperswarm when `topic` is set; opens Protomux channel.
### `async close()`
Tears down swarm and clears local state; emits `closed` where applicable.
## P2P ## P2P
When `topic` is set, `ready()` joins Hyperswarm and opens Protomux `ram-pool/v1`. Gossip / sync over Protomux `ram-pool/v1` when `topic` is configured.
## Testing ## Testing
@@ -4,7 +4,7 @@
## Overview ## Overview
CPU, RAM, and temperature load throttle signals. `HyperP2PThermalGuard` — P2P module. See [`README.md`](../README.md) and [`architecture.md`](architecture.md).
## Constructor ## Constructor
@@ -14,20 +14,50 @@ const mod = new HyperP2PThermalGuard(opts)
| Option | Type | Default | Description | | Option | Type | Default | Description |
|--------|------|---------|-------------| |--------|------|---------|-------------|
| `topic` | Buffer \| string \| null | `null` | Hyperswarm topic | | `topic` | Buffer \| string \| null | `null` | Hyperswarm topic; omit for local-only |
| `keyPair` | KeyPair | random | Discovery identity | | `keyPair` | KeyPair | random | Discovery identity |
## Methods ## Methods
See [`index.js`](../index.js) for the full method list. All modules implement `getStats()`, `async ready()`, and `async close()`. ### `reportLoad(...)`
## getStats() Public API on `HyperP2PThermalGuard`. See [`index.js`](../index.js) for parameters and return types.
Returns `{ ...stats, protocol: 'thermal-guard/v1' }` plus module-specific counters. ### `shouldThrottle(...)`
Public API on `HyperP2PThermalGuard`. See [`index.js`](../index.js) for parameters and return types.
### `getHeadroom(...)`
Public API on `HyperP2PThermalGuard`. See [`index.js`](../index.js) for parameters and return types.
### `listSamples(...)`
Public API on `HyperP2PThermalGuard`. See [`index.js`](../index.js) for parameters and return types.
### `throttledPeerIds(...)`
Public API on `HyperP2PThermalGuard`. See [`index.js`](../index.js) for parameters and return types.
### `healthyPeerIds(...)`
Public API on `HyperP2PThermalGuard`. See [`index.js`](../index.js) for parameters and return types.
### `getStats() → object`
Metrics plus `protocol: 'thermal-guard/v1'`.
### `async ready()`
Joins Hyperswarm when `topic` is set; opens Protomux channel.
### `async close()`
Tears down swarm and clears local state; emits `closed` where applicable.
## P2P ## P2P
When `topic` is set, `ready()` joins Hyperswarm and opens Protomux `thermal-guard/v1`. Gossip / sync over Protomux `thermal-guard/v1` when `topic` is configured.
## Testing ## Testing
@@ -4,7 +4,7 @@
## Overview ## Overview
Shard task queues with idle-peer work stealing. `HyperP2PWorkStealer` — P2P module. See [`README.md`](../README.md) and [`architecture.md`](architecture.md).
## Constructor ## Constructor
@@ -14,20 +14,54 @@ const mod = new HyperP2PWorkStealer(opts)
| Option | Type | Default | Description | | Option | Type | Default | Description |
|--------|------|---------|-------------| |--------|------|---------|-------------|
| `topic` | Buffer \| string \| null | `null` | Hyperswarm topic | | `topic` | Buffer \| string \| null | `null` | Hyperswarm topic; omit for local-only |
| `keyPair` | KeyPair | random | Discovery identity | | `keyPair` | KeyPair | random | Discovery identity |
## Methods ## Methods
See [`index.js`](../index.js) for the full method list. All modules implement `getStats()`, `async ready()`, and `async close()`. ### `push(...)`
## getStats() Public API on `HyperP2PWorkStealer`. See [`index.js`](../index.js) for parameters and return types.
Returns `{ ...stats, protocol: 'work-stealer/v1' }` plus module-specific counters. ### `steal(...)`
Public API on `HyperP2PWorkStealer`. See [`index.js`](../index.js) for parameters and return types.
### `peek(...)`
Public API on `HyperP2PWorkStealer`. See [`index.js`](../index.js) for parameters and return types.
### `depth(...)`
Public API on `HyperP2PWorkStealer`. See [`index.js`](../index.js) for parameters and return types.
### `listShards(...)`
Public API on `HyperP2PWorkStealer`. See [`index.js`](../index.js) for parameters and return types.
### `totalPending(...)`
Public API on `HyperP2PWorkStealer`. See [`index.js`](../index.js) for parameters and return types.
### `stealFromBusiest(...)`
Public API on `HyperP2PWorkStealer`. See [`index.js`](../index.js) for parameters and return types.
### `getStats() → object`
Metrics plus `protocol: 'work-stealer/v1'`.
### `async ready()`
Joins Hyperswarm when `topic` is set; opens Protomux channel.
### `async close()`
Tears down swarm and clears local state; emits `closed` where applicable.
## P2P ## P2P
When `topic` is set, `ready()` joins Hyperswarm and opens Protomux `work-stealer/v1`. Gossip / sync over Protomux `work-stealer/v1` when `topic` is configured.
## Testing ## Testing
@@ -1,98 +1,54 @@
# API: hyper-p2p-temporal-index # API: hyper-p2p-temporal-index
**Protocol:** `hyper-p2p-temporal-index/v1` (`TEMPORAL_PROTOCOL`) **Protocol:** `v1` · **Export:** `hyper-p2p-temporal-index`
**Export:** `HyperP2PTemporalIndex`
## Overview ## Overview
`HyperP2PTemporalIndex` indexes time-series events in hierarchical UTC buckets (year → month → day → hour → minute), optional Ed25519 signing, TTL pruning, range and nearest queries, optional Hyperbee persistence, and gossip replication of inserts when `topic` or `swarm` is configured. `hyper-p2p-temporal-index` — P2P module. See [`README.md`](../README.md) and [`architecture.md`](architecture.md).
## Constructor ## Constructor
```js ```js
const HyperP2PTemporalIndex = require('hyper-p2p-temporal-index') const mod = new hyper-p2p-temporal-index(opts)
const idx = new HyperP2PTemporalIndex(options)
``` ```
| Option | Type | Default | Description | | Option | Type | Default | Description |
|--------|------|---------|-------------| |--------|------|---------|-------------|
| `localId` | `string` \| `Buffer` | random 8 bytes | Metadata + vector clock id | | `topic` | Buffer \| string \| null | `null` | Hyperswarm topic; omit for local-only |
| `maxEvents` | `number` | `100000` | Soft cap; triggers prune pressure | | `keyPair` | KeyPair | random | Discovery identity |
| `defaultTtlMs` | `number` | 30 days | Event expiry |
| `pruneIntervalMs` | `number` | 5 min | Background prune timer |
| `enableSigning` | `boolean` | `true` | Sign events on insert |
| `keyPair` | `KeyPair` | random | Signing + P2P |
| `hyperbee` | `Hyperbee` | `null` | Optional persistence |
| `swarm` | object | `null` | Pre-attached swarm |
| `vectorClock` | `HyperP2PVectorClock` | `null` | Optional; `tick` on insert |
| `topic` | `string` | `null` | Auto `_initP2P` on construct |
## Methods ## Methods
### `async insertEvent(data, options = {}) → event` ### `getMetrics(...)`
- **options:** `timestamp`, `ttlMs`, `metadata`, `id` Public API on `hyper-p2p-temporal-index`. See [`index.js`](../index.js) for parameters and return types.
- **Returns:** signed event with `id`, `timestamp`, `data`, `metadata`, `vectorClock`, `expiresAt`
- **Emits:** `insert`, `event`
- Gossips `{ type: 'event', event }` when swarm attached
### `async queryRange(startTime, endTime, options = {}) → event[]` ### `deriveTopic(...)`
Scans overlapping day buckets in `timeIndex`; verifies signatures when enabled; sorts by timestamp then vector clock. Public API on `hyper-p2p-temporal-index`. See [`index.js`](../index.js) for parameters and return types.
- **options:** `limit` (default 1000), `verify` (default true) ### `setVectorClock(...)`
### `async queryNearest(targetTime, options = {}) → event | null` Public API on `hyper-p2p-temporal-index`. See [`index.js`](../index.js) for parameters and return types.
- **options.direction:** `'before' | 'after' | 'nearest'` (default `'before'`) ### `getStats() → object`
### `async pruneExpired(force = false) → number` Metrics plus `protocol: 'v1'`.
Removes expired ids from `events`, `timeIndex`, `expiryQueue`. Emits `prune`. ### `async ready()`
### `setVectorClock(vc)` Joins Hyperswarm when `topic` is set; opens Protomux channel.
Attach external vector clock module. ### `async close()`
### `deriveTopic(timeBucket?) → Buffer` Tears down swarm and clears local state; emits `closed` where applicable.
SHA topic prefix + bucket for sharded swarm join. ## P2P
### `getMetrics()` / `getStats()` / `async close()` Gossip / sync over Protomux `v1` when `topic` is configured.
`getMetrics`: `{ inserts, queries, prunes, signed, eventCount, bucketCount }`.
## Event record
| Field | Description |
|-------|-------------|
| `id` | Unique hex |
| `timestamp` | Event time ms |
| `data` | Payload |
| `metadata` | Includes `localId` |
| `vectorClock` | Counter or clock snapshot |
| `signature` / `issuer` | When signing enabled |
| `insertedAt` / `expiresAt` | Lifecycle |
## P2P wire
| type | fields |
|------|--------|
| `event` | `event` (full record) |
## Events (EventEmitter)
`insert`, `event`, `query`, `prune`, `event-replicated`, `error`, `close`
## Buckets
Levels: `year`, `month`, `day`, `hour`, `minute` — all keys stored per insert for range scans.
## Testing ## Testing
```bash ```bash
npm install && npm test npm install && npm test
``` ```
Example: [`../examples/basic.js`](../examples/basic.js).
@@ -349,8 +349,15 @@ class HyperP2PTemporalIndex extends EventEmitter {
} }
eventCount () { return this.events.size }
getStats () { getStats () {
return { ...this._stats } return {
events: this.events.size,
buckets: this.timeIndex.size,
...this._metrics,
protocol: TEMPORAL_PROTOCOL
}
} }
async close () { async close () {