ctx.stream(spec, options?) returns an AsyncIterable for streamed
responses — NDJSON, Server-Sent Events, or raw bytes. Unlike ctx.request,
streaming intentionally bypasses cache, dedup, and response validation
(meaningless for a stream).
defineModule({
methods: {
// Stream newline-delimited JSON rows
tail: async function* (ctx) {
for await (const row of ctx.stream(
{ method: 'GET', path: '/logs/stream' },
{ mode: 'ndjson' },
)) {
yield row as LogRow
}
},
// Stream Server-Sent Events
subscribe: async function* (ctx, channel: string) {
for await (const event of ctx.stream(
{ method: 'GET', path: '/events/{channel}', pathParams: { channel } },
{ mode: 'sse' },
)) {
yield event // { event?, data, id?, retry? }
}
},
},
})interface StreamOptions {
mode?: 'ndjson' | 'sse' | 'raw' // how to decode the byte stream
signal?: AbortSignal // aborting rejects the iterator with an AbortError
}'ndjson'→ yields each parsed JSON line.'sse'→ yieldsSseEventobjects ({ event?, data, id?, retry? }).'raw'→ yieldsUint8Arraybyte chunks.
The parsing helpers are exported for use with your own readers:
import { parseNdjson, parseSse } from '@developerehsan/api-client'for await (const row of api.logs.tail()) {
console.log(row)
}- Client-side streaming works with both the
fetchand Axios adapters. - Streaming through the SSR RPC bridge is a follow-up (Server Actions can't stream); use a route handler for streamed endpoints today. See the roadmap.