Add per-adapter architecture docs in event-targets/ directory
- Create docs/architecture/event-targets/ with individual specs: in-process, redis, websocket-client, websocket-server, worker, iroh-spoke, iroh-hub - Update event-targets.md to serve as index with topology model (symmetric vs fan-out) and adapter status table - Update architecture.md index to reference new directory
This commit is contained in:
66
docs/architecture/event-targets/iroh-spoke.md
Normal file
66
docs/architecture/event-targets/iroh-spoke.md
Normal file
@@ -0,0 +1,66 @@
|
||||
---
|
||||
status: draft
|
||||
last_updated: 2026-05-07
|
||||
---
|
||||
|
||||
# Iroh Spoke Event Target
|
||||
|
||||
**Import**: `@alkdev/pubsub/event-target-iroh-spoke`
|
||||
**Peer dep**: `@rayhanadev/iroh` (optional, NAPI-RS native addon)
|
||||
**Status**: Not yet implemented. Needs R&D on binding stability and Deno/NAPI compatibility.
|
||||
|
||||
P2P QUIC event target for the spoke (client) side. The spoke initiates the connection and opens the bidirectional stream.
|
||||
|
||||
## `createIrohSpokeEventTarget`
|
||||
|
||||
```ts
|
||||
async function createIrohSpokeEventTarget<TEvent extends TypedEvent>(
|
||||
args: CreateIrohSpokeEventTargetArgs,
|
||||
): Promise<TypedEventTarget<TEvent>>;
|
||||
```
|
||||
|
||||
### `CreateIrohSpokeEventTargetArgs`
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `endpoint` | `Endpoint` | Yes | iroh endpoint (created with `Endpoint.create()`) |
|
||||
| `hubNodeId` | `string` \| `NodeId` | Yes | The hub's public key (Ed25519) |
|
||||
| `alpn` | `string` | No | Application-layer protocol. Default: `"alkpubsub/1"` |
|
||||
|
||||
## Protocol
|
||||
|
||||
Single bidirectional QUIC stream per connection. Length-prefixed JSON messages:
|
||||
|
||||
```
|
||||
[4 bytes: length N][N bytes: JSON payload]
|
||||
```
|
||||
|
||||
The JSON payload is the `EventEnvelope`:
|
||||
|
||||
```json
|
||||
{ "type": "call.responded", "id": "uuid-123", "payload": { "output": 42 } }
|
||||
```
|
||||
|
||||
## Connection Flow
|
||||
|
||||
1. Spoke creates `Endpoint`
|
||||
2. Spoke calls `endpoint.connect(hubNodeId, alpn)` → `Connection`
|
||||
3. Spoke calls `connection.openBi()` → `SendStream` + `RecvStream`
|
||||
4. Spoke wraps streams in `IrohSpokeEventTarget`
|
||||
5. On disconnect: `RecvStream.readExact()` throws, spoke must reconnect
|
||||
|
||||
## 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
|
||||
|
||||
## R&D Needed
|
||||
|
||||
1. **Binding stability** — `@rayhanadev/iroh` has one author and no tests. API surface is small (10 methods) but needs validation.
|
||||
2. **NAPI under Deno** — NAPI-RS `.node` binaries need testing under Deno 2.x.
|
||||
3. **Stream multiplexing** — multiple `openBi()` streams on one connection vs. single stream with multiplexed events. Single stream + JSON framing is simpler.
|
||||
4. **Reconnection** — `RecvStream.readExact()` throws on connection close. Need to propagate this to listeners and support reconnect.
|
||||
|
||||
See [../iroh-transport.md](../iroh-transport.md) for full protocol details, identity, and comparison with WebSocket.
|
||||
Reference in New Issue
Block a user