Quick Start
Installation
npm install @ai-zen/node-fetch-event-sourceMinimal Example
fetchEventSource continuously consumes the server event stream in the background and hands each event to onmessage:
import { fetchEventSource } from '@ai-zen/node-fetch-event-source';
await fetchEventSource('/api/sse', {
onmessage(ev) {
console.log(ev.data);
}
});onmessage is triggered for all events, including those with a custom event field (unlike the browser's built-in EventSource.onmessage, which only fires for the default message event).
Sending a Request Body and Custom Headers
Since it uses fetch under the hood, you can pass every parameter supported by RequestInit:
import { fetchEventSource } from '@ai-zen/node-fetch-event-source';
await fetchEventSource('/api/sse', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ foo: 'bar' })
});Note:
headersonly supports theRecord<string, string>format (not compatible with aHeadersinstance).
Cancelling with AbortController
Pass a signal to abort the connection when needed. When the signal fires an abort, resources are released and the Promise returned by fetchEventSource is resolved (it will not enter the onerror retry flow).
import { fetchEventSource } from '@ai-zen/node-fetch-event-source';
const ctrl = new AbortController();
await fetchEventSource('/api/sse', {
signal: ctrl.signal,
onmessage(ev) {
console.log(ev.data);
}
});
// Cancel the request at any time:
// ctrl.abort();Better Error Handling
The following example distinguishes between "retriable" and "fatal" errors: client-side 4xx (except 429) are usually non-retriable, while server errors or unexpected closes trigger a retry.
class RetriableError extends Error {}
class FatalError extends Error {}
fetchEventSource('/api/sse', {
async onopen(response) {
if (response.ok && response.headers.get('content-type') === EventStreamContentType) {
return; // OK
} else if (response.status >= 400 && response.status < 500 && response.status !== 429) {
throw new FatalError(); // client-side error, do not retry
} else {
throw new RetriableError(); // otherwise retry
}
},
onmessage(msg) {
if (msg.event === 'FatalError') {
throw new FatalError(msg.data);
}
},
onclose() {
throw new RetriableError(); // server closed unexpectedly, retry
},
onerror(err) {
if (err instanceof FatalError) {
throw err; // rethrow to stop the whole operation
}
// otherwise do nothing to retry automatically, or return a specific interval in milliseconds
}
});For more on reconnection and onerror semantics, see Reconnection and Error Handling.
Next Steps
- For the complete set of options and type definitions, see API Reference.
- For an overview, environment requirements, and core concepts, see index.