Parse Server-Sent Events
`parse-sse` is a lightweight, spec-compliant JavaScript library designed for parsing Server-Sent Events (SSE) from a standard Web `Response` object, typically obtained via the native Fetch API. Currently at version 0.1.0, it is a new release focused on providing a robust and efficient way to consume streaming APIs. The library differentiates itself by being fully compatible with native `ReadableStream` and `TransformStream` interfaces, enabling maximum composability with other stream-based operations. It is particularly well-suited for integrating with modern streaming services like OpenAI and Anthropic, which extensively utilize SSE for real-time data delivery. As a relatively new package, a specific release cadence has not yet been established, but its focus on web platform standards and minimal dependencies suggests a stable foundation.
Common errors
-
ReferenceError: require is not defined
cause Attempting to use CommonJS `require()` syntax in an ES module environment, which `parse-sse` exclusively supports.fixChange `const { parseServerSentEvents } = require('parse-sse');` to `import { parseServerSentEvents } from 'parse-sse';` and ensure your `package.json` has `"type": "module"` or your file has `.mjs` extension. -
TypeError: parseServerSentEvents is not a function
cause Incorrectly importing the `parseServerSentEvents` function, often due to a mixed CommonJS/ESM environment issue or incorrect named import.fixVerify that your environment is set up for ES modules (Node.js 20+ and correct `package.json` `type` field) and that you are using `import { parseServerSentEvents } from 'parse-sse';`. -
Error: Response body is null
cause The `Response` object from `fetch` did not contain a readable body, possibly due to a non-streaming response type, an error status, or the body already being consumed.fixEnsure the server is actually sending a stream (`Content-Type: text/event-stream`) and the `response.ok` is true. Handle cases where `response.body` might be `null` or already consumed before passing it to `parseServerSentEvents`. -
TypeError: If you pass byte chunks, a TypeError will be thrown.
cause `ServerSentEventTransformStream` received byte chunks (e.g., from `response.body`) instead of decoded string chunks.fixPrepend a `TextDecoderStream` to the pipeline: `response.body.pipeThrough(new TextDecoderStream()).pipeThrough(new ServerSentEventTransformStream())`.
Warnings
- breaking `parse-sse` is an ESM-only package and explicitly requires Node.js version 20 or higher. Older Node.js versions or CommonJS environments are not supported.
- gotcha When using `ServerSentEventTransformStream` directly, the input stream is expected to consist of string chunks. If you are piping from a raw byte stream (e.g., `response.body`), you must pipe through a `TextDecoderStream` first to ensure proper Unicode decoding and chunk handling.
- gotcha Server-Sent Events are processed based on `\n\n` delimiters. If your `data` field contains literal newline characters that are *not* part of a JSON string or properly escaped, it can lead to misinterpretation by the parser, breaking multi-line data.
Install
-
npm install parse-sse -
yarn add parse-sse -
pnpm add parse-sse
Imports
- parseServerSentEvents
const { parseServerSentEvents } = require('parse-sse');import { parseServerSentEvents } from 'parse-sse'; - ServerSentEventTransformStream
const { ServerSentEventTransformStream } = require('parse-sse');import { ServerSentEventTransformStream } from 'parse-sse';
Quickstart
import { parseServerSentEvents } from 'parse-sse';
const apiKey = process.env.OPENAI_API_KEY ?? 'YOUR_OPENAI_API_KEY_HERE';
async function getStreamingCompletion() {
const response = await fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${apiKey}`,
},
body: JSON.stringify({
model: 'gpt-4',
messages: [{ role: 'user', content: 'Tell me a story about a futuristic city.' }],
stream: true,
}),
});
if (!response.body) {
throw new Error('Response body is null, expected a ReadableStream.');
}
console.log('--- Streaming Chat Completion ---\n');
for await (const event of parseServerSentEvents(response)) {
if (event.data === '[DONE]') {
console.log('\n--- Stream Ended ---');
break;
}
try {
const data = JSON.parse(event.data);
process.stdout.write(data.choices[0]?.delta?.content || '');
} catch (error) {
console.error('Error parsing event data:', event.data, error);
}
}
}
getStreamingCompletion().catch(console.error);