# Express SSE relay for the Responses API

The Node SDK's `client.responses.create({ stream: true })` returns an async
iterator of typed events. Your Express route re-frames the deltas as SSE.

## Route shape (order matters)

1. `res.writeHead(200, { "Content-Type": "text/event-stream", "Cache-Control":
   "no-cache", "Connection": "keep-alive" })`.
2. `res.flushHeaders()` immediately, so the browser starts the EventSource before
   the first model token arrives.
3. `for await (const event of stream)`: on events with
   `event.type === "response.output_text.delta"`, do
   `res.write("data: " + JSON.stringify({ delta: event.delta }) + "\n\n")`.
   On `response.completed`, break and `res.end()`.

## The compression trap

If the app uses the `compression` middleware, it buffers SSE chunks to compress
them, which defeats streaming. Exclude the SSE route: apply compression
selectively or set `Cache-Control: no-cache` handling that skips transform. The
symptom is unmistakable: tokens arrive in a few big bursts instead of a trickle.

## The client-disconnect trap

- On `req.on("close")`, break out of the loop. Otherwise the upstream OpenAI
  stream keeps generating (and billing) for a user who left.
- Do not `await` anything slow between events; backpressure from a slow client
  is handled by the socket, not by your loop.

## Check before you ship

- curl -N the route: frames must arrive incrementally from the first seconds.
- Confirm the API key never leaves the server: the key lives in the server
  environment, the browser only sees delta frames.