Backend — SSE Endpoint
Express sends Server-Sent Events with 500ms intervals. The proxy forwards the stream to the client.
ts
// Express SSE endpoint
router.get("/stream", (_req, res) => {
res.setHeader("Content-Type", "text/event-stream")
res.setHeader("Cache-Control", "no-cache")
res.setHeader("Connection", "keep-alive")
const items = ["Hello", "from", "the", "streaming", "endpoint!"]
let index = 0
const interval = setInterval(() => {
if (index < items.length) {
res.write(`data: ${JSON.stringify({ chunk: items[index], index })}\n\n`)
index++
} else {
res.write("data: [DONE]\n\n")
clearInterval(interval)
res.end()
}
}, 500)
})The backend sends 5 chunks at 500ms intervals, then a [DONE] signal. The courier proxy passes the ReadableStream through transparently.
Progressive Rendering
Watch chunks arrive in real time. Each chunk appears as the server sends it.
ts
// Endpoint definition — return type is ReadableStream
const misc = defineGroup({
prefix: "misc",
endpoints: {
stream: endpoint.get("stream").response<ReadableStream>(),
},
})
// Call with stream: true via .with() — returns raw Response instead of parsed JSON
const response = await caller.misc.with({ stream: true }).stream()
// Read the stream
const reader = response.body.getReader()
const decoder = new TextDecoder()
while (true) {
const { done, value } = await reader.read()
if (done) break
const text = decoder.decode(value, { stream: true })
// Parse SSE: "data: {...}\n\n"
}caller.misc.with({ stream: true }).stream()SANDBOX