--- id: websocket-client-adapter name: Implement WebSocket client event target adapter status: pending depends_on: [review-core-and-redis] scope: moderate risk: medium impact: component level: implementation --- ## Description Implement the `createWebSocketClientEventTarget` adapter as specified in `docs/architecture/event-targets/websocket-client.md`. This is a symmetric (single-connection) adapter that wraps a `WebSocket` connection for the spoke/client side. It's bidirectional — can both send and receive events. It must implement subscription forwarding using `__subscribe`/`__unsubscribe` control events per ADR-003. Key requirements from the architecture: - Takes an already-connected `WebSocket` (caller handles connection lifecycle) - `dispatchEvent` → `ws.send(JSON.stringify(event.detail))` - `addEventListener` → register local listener + send `__subscribe` control event on first listener for topic - `removeEventListener` → remove local listener + send `__unsubscribe` when no listeners remain - Subscription reference counting: `__subscribe` sent only on first `addEventListener` per topic - Malformed JSON from server → silently ignored, log warning - Control events (`__subscribe`, `__unsubscribe`) received from server → silently ignored - `ws.send()` failure → error propagates to caller, no retry ## Acceptance Criteria - [ ] `src/event-target-websocket-client.ts` exists - [ ] Implements `createWebSocketClientEventTarget(ws: WebSocket): TypedEventTarget` - [ ] `dispatchEvent` serializes envelope and calls `ws.send()` - [ ] `addEventListener` registers local listener and sends `__subscribe` on first listener for topic - [ ] Subscription reference counting: only one `__subscribe` per topic regardless of listener count - [ ] `removeEventListener` removes local listener and sends `__unsubscribe` when no listeners remain - [ ] Malformed JSON messages from server are silently ignored (logged) - [ ] Control events received from server are silently ignored - [ ] `ws.onmessage` parses envelope, creates `CustomEvent` with `type:id` topic, dispatches to listeners - [ ] `ws.send()` failure propagates to caller - [ ] No comments in source code (project convention) - [ ] Sub-path export added to `package.json` and `tsup.config.ts` - [ ] Barrel re-export added to `src/index.ts` ## References - docs/architecture/event-targets/websocket-client.md - docs/architecture/decisions/003-subscription-control-protocol.md - src/types.ts (TypedEventTarget, TypedEvent, EventEnvelope) ## Notes > To be filled by implementation agent ## Summary > To be filled on completion