npm install @ferrow/sse-stream-parserIncremental Server-Sent Events parser for LLM streaming — spec-correct
multi-line fields, comments, CRLF/LF, chunk-boundary splits, [DONE]
convention, and JSON-delta accumulation. Zero runtime dependencies, strict
TypeScript.
import { SSEParser, isDoneEvent, createDeltaAccumulator } from "sse-stream-parser";
const parser = new SSEParser();
const accumulator = createDeltaAccumulator(
(parsed) => parsed?.choices?.[0]?.delta?.content ?? null
);
// Feed raw chunks as they arrive from your HTTP stream reader — any
// alignment, including split mid-event.
for await (const chunk of responseBodyChunks) {
for (const event of parser.feed(chunk)) {
if (isDoneEvent(event)) break;
accumulator.feed(event);
}
}
console.log(accumulator.text); // the fully reassembled textfeed(chunk: string): SSEEvent[]— feed one raw chunk, get back the event(s) that completed as a result.flush(): SSEEvent[]— flush any buffered partial event at stream end, for sources that don't send a trailing blank line.
interface SSEEvent {
data: string; // multi-line data: fields joined with "\n"
event: string; // defaults to "message" per spec
id?: string;
retry?: number;
}True if event.data.trim() === "[DONE]" — the OpenAI-style stream-end
sentinel.
Builds a running-text accumulator for JSON-delta streams. extract pulls
the delta string out of the parsed JSON for one event (return
null/undefined for events with no text delta, e.g. role markers).
Malformed JSON in data is skipped rather than throwing.
interface DeltaAccumulator {
feed(event: SSEEvent): string | null; // returns the delta appended, or null
text: string; // full accumulated text
reset(): void;
}- This is an SSE parser, not an HTTP client — you supply the chunks
(e.g. from
fetch'sReadableStream,EventSourceis not used since it doesn't expose raw chunk boundaries the way this library is designed to stress-test). id:fields containing a space are ignored, per the SSE spec (idmust not contain U+0000 or whitespace in strict implementations — this parser is lenient elsewhere but enforces this one).createDeltaAccumulatorassumes each event'sdatais a full JSON object; it does not reassemble JSON that itself spans multiple SSE events.
Part of the ferrow-toolkit collection · Sponsored by Ferrow