EventSource/Server-Sent Events Parser
eventsource-parser is a highly performant and source-agnostic streaming parser for Server-Sent Events (SSE) / EventSource data. It does not assume how the data stream is obtained, making it a versatile building block for various JavaScript environments like browsers, Node.js, and Deno. The current stable version is 3.0.7, with frequent releases addressing bug fixes, performance improvements, and ongoing maintenance. Key differentiators include its streaming nature, a `TransformStream` variant for modern environments, and its role as a low-level parser that can be integrated into custom networking stacks or clients, contrasting with higher-level clients like `eventsource-client` or Node.js polyfills like `eventsource`.
Common errors
-
TypeError: createParser is not a function
cause Attempting to use `createParser` as a default import (e.g., `import createParser from '...'`) or via `require()` in a CommonJS environment, which is no longer supported since v3.0.0 which moved to named exports and ESM-first. Alternatively, passing a function directly to `createParser` instead of an options object in v3+ can also lead to similar runtime issues.fixUse a named import: `import { createParser } from 'eventsource-parser'`. For CommonJS environments, consider a tool like `esm` or ensure your build process correctly handles ESM imports. If passing a function directly, wrap it in an object for the `onEvent` callback: `createParser({ onEvent: myEventHandler })`. -
ReferenceError: EventSourceMessage is not defined
cause This error typically occurs if `EventSourceMessage` is used as a type but not correctly imported as a type, or if an older version of the parser (v1.x/v2.x) used `ParsedEvent` instead, which was renamed in v3.0.0.fixEnsure you import it as a type: `import type { EventSourceMessage } from 'eventsource-parser'`. If you are on an older version, use `ParsedEvent` instead. -
UnhandledPromiseRejectionWarning: TypeError: Invalid minimum Node.js version
cause Running `eventsource-parser` v2.0.0 or higher in a Node.js environment older than v18.fixUpgrade your Node.js runtime to version 18 or newer, or downgrade `eventsource-parser` to v1.x if older Node.js versions are required.
Warnings
- breaking Version 3.0.0 introduced significant breaking changes to the parser's API. Instead of a single `onParse` callback that required type checking, `createParser` now expects an object of callbacks (`onEvent`, `onRetry`, `onError`, `onComment`) for specific event types. The `ParsedEvent` type was also renamed to `EventSourceMessage`, and its `type` attribute was removed.
- breaking As of version 2.0.0, the minimum supported Node.js version is Node.js 18. This change was introduced to leverage modern Web Streams and `fetch` API capabilities.
- gotcha When consuming a stream, it's crucial to call `parser.reset({ consume: true })` after the stream ends or an error occurs. This flushes any remaining buffered data and resets the parser's internal state. Failing to do so might prevent the last incomplete event from being processed or leave the parser in an inconsistent state.
- gotcha In versions 3.0.2 and 3.0.3, there were changes and reintroductions of legacy module exports. While v3.0.2 dropped a legacy module export, v3.0.3 specifically reintroduced legacy exports for the `stream` module. This could lead to inconsistent import behavior depending on the exact patch version and target environment.
- gotcha The `createParser` function will throw a helpful error if you mistakenly pass a function directly to it instead of an object of callbacks, particularly since the v3 API change. This indicates a misuse of the updated API.
Install
-
npm install eventsource-parser -
yarn add eventsource-parser -
pnpm add eventsource-parser
Imports
- createParser
import createParser from 'eventsource-parser'
import { createParser } from 'eventsource-parser' - EventSourceMessage
import { EventSourceMessage } from 'eventsource-parser'import type { EventSourceMessage } from 'eventsource-parser' - EventSourceParserStream
import { EventSourceParserStream } from 'eventsource-parser'import { EventSourceParserStream } from 'eventsource-parser/stream'
Quickstart
import { createParser, type EventSourceMessage, type ParseError } from 'eventsource-parser';
// Simulate a readable stream, e.g., from a fetch response body
async function getSimulatedSseStream(): Promise<ReadableStreamDefaultReader<Uint8Array>> {
const sseData = `id: 1\nevent: message\ndata: Hello, world!\n\nretry: 5000\nid: 2\ndata: Another message\n\n`;
const encoder = new TextEncoder();
const stream = new ReadableStream<Uint8Array>({
start(controller) {
controller.enqueue(encoder.encode(sseData.substring(0, 20)));
setTimeout(() => {
controller.enqueue(encoder.encode(sseData.substring(20, 50)));
}, 100);
setTimeout(() => {
controller.enqueue(encoder.encode(sseData.substring(50)));
controller.close();
}, 200);
},
});
return stream.getReader();
}
async function parseSseStream() {
let retryInterval = 3000;
const parser = createParser({
onEvent(event: EventSourceMessage) {
console.log('Received event:');
console.log(' id:', event.id || '<none>');
console.log(' event:', event.event || '<none>');
console.log(' data:', event.data);
},
onRetry(interval: number) {
console.log('Server requested retry interval of %dms', interval);
retryInterval = interval;
},
onError(error: ParseError) {
console.error('Error parsing event stream:', error.message);
if (error.type === 'invalid-retry') {
console.error('Invalid retry value:', error.value);
}
}
});
const sseStreamReader = await getSimulatedSseStream();
try {
while (true) {
const { done, value } = await sseStreamReader.read();
if (done) break;
parser.feed(new TextDecoder().decode(value));
}
} finally {
parser.reset({ consume: true }); // Important: flush any pending data and reset state
}
console.log('Stream parsing complete. Last known retry interval:', retryInterval);
}
parseSseStream().catch(console.error);