# Express Realtime websocket relay

## Setup

1. `npm install ws` (and `openai` if you use the SDK helpers).
2. Create an HTTP server from your Express app and attach a `ws` WebSocketServer
   with `noServer: true`; handle the `upgrade` event and route by path, for
   example `/realtime`.
3. When a browser client connects, open the upstream OpenAI websocket from the
   server with the Authorization Bearer header carrying your server-side key.
4. Send `session.start` first, wait for `session.started`, then begin relaying
   frames in both directions.

## Frame relay rules

- Browser audio arrives as JSON events with base64 PCM16 24kHz chunks; forward
  them upstream unchanged.
- Upstream `response.audio.delta` events go straight back to the browser socket.
- Never parse-and-rebuild frames you do not need to inspect; forward the raw
  message to avoid corrupting base64 payloads.

## Lifecycle (the Node traps)

- `ws` sockets do not auto-ping. Send ping frames on an interval and terminate
  sockets that miss pong; otherwise dead mobile clients hold sessions open.
- On `close` of either socket, `close()` the other immediately and clear the
  heartbeat timer. Forgetting the timer is a slow memory leak, one per call.
- Backpressure: check `socket.bufferedAmount` before forwarding large audio
  bursts; pause the upstream reader when the browser falls behind.

## Check before you ship

- Two concurrent calls must not cross audio: tag each relay pair with the
  session id from `session.started` and assert isolation in a test.
- Confirm the server-side key never reaches the browser; the browser socket
  carries only audio and control frames.