Resolve WebSocket event target open questions, add subscription control protocol
- Resolve OQ1: WS server accepts raw WebSocket instances via addConnection/removeConnection (framework-agnostic, not coupled to Hono/Express/Bun/Deno) - Resolve OQ2: Backpressure handled by disconnecting slow consumers at configurable threshold (default 1MB), with onBackpressure callback for observability - Resolve OQ3: Topic-based fan-out with subscription tracking instead of broadcast-all; spokes send __subscribe/__unsubscribe control events; direct messaging via 'direct:' topic pattern Add ADR-003 for subscription control protocol decision. Update all fan-out adapters (WS server, Iroh hub) and spoke adapters (WS client, Iroh spoke) with subscription tracking/forwarding. Fix routing key ambiguity (full topic string, not event type alone). Add error handling, composition, and reserved type sections. Clarify Worker as symmetric-only.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
---
|
||||
status: draft
|
||||
last_updated: 2026-05-07
|
||||
last_updated: 2026-05-08
|
||||
---
|
||||
|
||||
# Iroh Spoke Event Target
|
||||
@@ -49,12 +49,24 @@ The JSON payload is the `EventEnvelope`:
|
||||
4. Spoke wraps streams in `IrohSpokeEventTarget`
|
||||
5. On disconnect: `RecvStream.readExact()` throws, spoke must reconnect
|
||||
|
||||
## Subscription Forwarding
|
||||
|
||||
Same pattern as [WebSocket Client](websocket-client.md): when `addEventListener` is called for the first listener on a topic, the spoke sends a `__subscribe` control event to the hub. When `removeEventListener` removes the last listener for a topic, the spoke sends `__unsubscribe`. Reference counting ensures `__subscribe` is sent only on the first `addEventListener` for a topic, and `__unsubscribe` only when the last `removeEventListener` for that topic is called. This enables the hub's topic-based fan-out (see [ADR-003](../decisions/003-subscription-control-protocol.md)).
|
||||
|
||||
Control events use the existing `EventEnvelope` format:
|
||||
|
||||
```json
|
||||
{ "type": "__subscribe", "id": "", "payload": { "topic": "message.sent:conv-123" } }
|
||||
{ "type": "__unsubscribe", "id": "", "payload": { "topic": "message.sent:conv-123" } }
|
||||
```
|
||||
|
||||
## Key Properties
|
||||
|
||||
- **NAT traversal** — spoke dials hub by `NodeId`, no public IP needed
|
||||
- **Cryptographic identity** — `Connection.remoteNodeId()` verifies the hub
|
||||
- **Bidirectional** — `dispatchEvent` writes to `SendStream`, `addEventListener` reads from `RecvStream`
|
||||
- **Per-connection** — one event target per QUIC connection
|
||||
- **Subscription forwarding** — `addEventListener`/`removeEventListener` send `__subscribe`/`__unsubscribe` control events to the hub (see [ADR-003](../decisions/003-subscription-control-protocol.md))
|
||||
|
||||
## R&D Needed
|
||||
|
||||
|
||||
Reference in New Issue
Block a user