Status: Accepted
Date: 2026-04-22
Branch / PR: aggregation/http-transport
Depends on: ADR 028
Both the broadcast advert stream and the per-DID inbox are Server-Sent Events (SSE) endpoints. The standard browser API for SSE is EventSource, which:
Last-Event-ID resume.The inbox stream at GET /v1/actors/{did}/inbox requires authentication: otherwise any actor can subscribe to any DID’s inbox and observe metadata about who’s participating in which cohorts. That authentication needs to commit to at least (did, timestamp, nonce, path) and be signed by the DID’s key.
The missing-headers restriction on EventSource forces auth credentials into the URL, which is problematic:
EventSource + signed query parameter. Works everywhere but leaks credentials to logs.EventSource + cookie-based auth. Requires server-side sessions (rejected by ADR 029’s stateless model).ReadableStream + manual SSE frame parsing. Headers work; we own ~40 lines of parser.Option 3. The HttpClientTransport implements SSE using fetch() + ReadableStream + a small parseSseStream async generator. Inbox subscribe requests carry auth in an Authorization: BTCR2-Sig … header. Automatic reconnection uses exponential backoff (default 1s to 30s with 20% jitter).
The parser is ~80 LOC in sse-stream.ts and handles:
data fieldsevent, id, retry fields (with spec-compliant validation):-prefixed comments (heartbeats)Positive
Authorization header, identical across POSTs and SSE GETs.AbortController to aborted fetch to clean stream unwind. Cancellation is trivially composable with the rest of the client.ReadableStream controller to deliver synthetic SSE events deterministically.Negative
EventSource: we implement reconnect with backoff ourselves. Small amount of code, full control.fetch support (pre-2020 Edge, ancient Safari) are unsupported. Acceptable given the broader Node 22+ runtime requirement.Explicitly accepted trade-offs
EventSource compatibility for the inbox stream. Any future need for standard EventSource (e.g., if a third-party wants to consume adverts with vanilla browser APIs) can still use it against the unauthenticated GET /v1/adverts endpoint.packages/method/src/core/aggregation/transport/http/sse-stream.ts: parser.packages/method/src/core/aggregation/transport/http/sse-writer.ts: server-side frame formatter (pairs with the parser).packages/method/src/core/aggregation/transport/http/request-auth.ts: BTCR2-Sig scheme.