Update peer dep from @rayhanadev/iroh to @alkdev/iroh. Document platform strategy: Linux native + WASM fallback, Windows/macOS deferred. Fix outdated single-import reference in iroh-transport.md to split spoke/hub imports. Resolve binding stability and NAPI/Deno R&D items as covered by the fork path.
4.3 KiB
status, last_updated
| status | last_updated |
|---|---|
| draft | 2026-05-08 |
Iroh Hub Event Target
Import: @alkdev/pubsub/event-target-iroh-hub
Peer dep: @alkdev/iroh (optional, NAPI-RS native addon — pending fork of iroh-ts)
Status: Deferred. Pending fork of iroh-ts with Linux + WASM platform targets.
P2P QUIC event target for the hub (server) side. The hub accepts incoming connections and bidirectional streams. Manages multiple connected spokes.
createIrohHubEventTarget
async function createIrohHubEventTarget<TEvent extends TypedEvent>(
args: CreateIrohHubEventTargetArgs,
): Promise<TypedEventTarget<TEvent>>;
CreateIrohHubEventTargetArgs
| Field | Type | Required | Description |
|---|---|---|---|
endpoint |
Endpoint |
Yes | iroh endpoint (created with Endpoint.create()) |
alpn |
string |
No | Application-layer protocol. Default: "alkpubsub/1" |
How It Works
Similar to the WebSocket server adapter, the Iroh hub adapter manages multiple connections:
dispatchEvent→ writes JSON envelope to all connected spokes'SendStreamsaddEventListener→ registers local listeners for events from any spoke- On incoming connection →
endpoint.accept()→connection.acceptBi()→ new spoke tracked
Each spoke gets its own read loop that parses length-prefixed JSON messages from RecvStream and dispatches locally.
Connection Lifecycle
Unlike the WebSocket server adapter (where the caller passes connections via addConnection), the Iroh hub adapter manages connections automatically via endpoint.accept(). This is a deliberate design difference: Iroh QUIC connections are accepted by the endpoint, not passed in by a framework. The hub has no addConnection/removeConnection API — connections are internal to the adapter.
- Hub creates
Endpointand starts accepting - Spoke connects → hub gets
Connectionfromendpoint.accept() - Hub accepts stream →
connection.acceptBi()→SendStream+RecvStream - Hub creates per-spoke read loop
- On disconnect →
RecvStream.readExact()throws → remove spoke from set - Hub continues accepting new connections
Fan-Out
As a fan-out adapter, the Iroh hub must implement topic-based fan-out — dispatchEvent sends only to spokes subscribed to that topic, not to all connected spokes. This requires a subscriptions map (Map<string, Set<Spoke>>) updated by __subscribe/__unsubscribe control events from spokes. See ADR-003 and WebSocket server adapter for the established pattern.
dispatchEvent(event) {
// event.type is the full topic string, e.g. "message.sent:conv-123"
// This matches the topics that spokes subscribe to via __subscribe
const message = encodeEnvelope(event.detail);
// Send only to spokes subscribed to this topic
const subscribers = this.subscriptions.get(event.type);
if (subscribers) {
for (const spoke of subscribers) {
spoke.sendStream.writeAll(message);
}
}
return true;
}
Key Properties
- Multi-connection — manages a set of connected spokes
- Topic-based fan-out — dispatchEvent sends only to spokes subscribed to the event type
- Subscription tracking — maintains topic-to-spoke mapping, updated by
__subscribe/__unsubscribecontrol events - Accepts incoming — endpoint.accept() loop runs continuously
- Cryptographic identity — each spoke verified by Ed25519 NodeId
R&D Needed
- Fork of iroh-ts — same as spoke adapter. Pending fork as
@alkdev/iroh. - Concurrent accept — can
endpoint.accept()handle multiple simultaneous connections? - Stream vs. Connection per spoke — current design: one bidirectional stream per spoke on a single connection. Alternative: one connection per spoke. Need to benchmark which is better for the expected workload.
- iroh-gossip — for true broadcast to many spokes,
iroh-gossipwould be more efficient than per-spoke streams. Not yet available in TS. The current subscription-tracked fan-out design works for moderate fan-out; gossip would be an optimization for very large fan-out later. - Connection rejection — how to reject connections from unknown
NodeIds.
See ../iroh-transport.md for full protocol details, identity, and comparison with WebSocket.