Better SSE
Better SSE is a robust, dependency-less, and spec-compliant implementation of Server-Sent Events (SSE) written entirely in TypeScript. It provides a streamlined, framework-agnostic solution for pushing data from a server to clients over HTTP, making it an alternative to WebSockets for unidirectional data flows. Currently stable at version 0.16.1, the project demonstrates a consistent release cadence with updates addressing compatibility, new features like connection adapters and event batching, and continuous type improvements. Key differentiators include its full TypeScript support, extensive documentation, 100% test coverage, and compatibility across various Node.js frameworks and runtimes (e.g., Express, Hono, Fastify, Bun, Deno), operating directly over the HTTP protocol to reduce bandwidth and complexity compared to other real-time solutions.
Common errors
-
TypeError: createSession is not a function
cause Attempting to use `require` for a package primarily designed for ES modules, or incorrect named import.fixEnsure you are using ES module imports: `import { createSession } from 'better-sse';`. If in a CommonJS context, consider configuring your project to support ESM or using an older version if available (though newer versions are ESM-first). -
Headers already sent. Cannot set headers after they are sent to the client.
cause Attempting to modify response headers after SSE session has started or other middleware has sent initial headers.fixEnsure `res.setHeader()` calls for `Cache-Control`, `Content-Type`, and `Connection` are made *before* `createSession(req, res)` or any data is written to the response stream. This often means placing them early in your SSE route handler. -
Error: read ECONNRESET
cause Client disconnected abruptly, leading to a connection reset by the peer on the server side.fixImplement proper session cleanup by listening to the `close` event on the `Session` object (`session.on('close', () => { /* cleanup resources */ });`) to stop sending events or clear timers specific to that client.
Warnings
- breaking Introduction of 'Connection Adapters' in v0.16.0 changed how connections are managed. While not strictly API breaking for simple use cases, custom or complex integrations might need to adapt to this new abstraction, especially when running on environments that do not fully emulate Node's HTTP APIs.
- gotcha Prior to v0.14.0, there were minor issues when importing the package into an ES Module (ESM) environment. Consumers might have encountered unexpected behavior or errors related to module resolution.
- gotcha When using frameworks that do not fully implement Node's HTTP/1 or HTTP/2 Compatibility APIs (e.g., some edge runtimes or newer frameworks), v0.16.0 could crash due to missing `setNoDelay` methods.
- gotcha Event name suggestions for `Session` and `Channel` event listeners were improved in v0.12.1. Older versions might lack proper TypeScript autocompletion for event names, leading to potential typos or runtime errors.
Install
-
npm install better-sse -
yarn add better-sse -
pnpm add better-sse
Imports
- createSession
const { createSession } = require('better-sse')import { createSession } from 'better-sse' - createChannel
import createChannel from 'better-sse'
import { createChannel } from 'better-sse' - Session
import { Session } from 'better-sse'import type { Session } from 'better-sse'
Quickstart
import { createSession } from 'better-sse';
import express from 'express';
const app = express();
const port = 3000;
app.get('/events', (req, res) => {
// Ensure client doesn't cache the response
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Connection', 'keep-alive');
const session = createSession(req, res);
// Optionally, send an initial event
session.push('Hello from the server!', 'greeting');
// Periodically send data
let counter = 0;
const interval = setInterval(() => {
if (session.isClosed()) {
clearInterval(interval);
console.log('Session closed, stopping updates.');
return;
}
session.push(`Data update ${counter++}`, 'update');
}, 2000);
// Handle client disconnect
session.on('close', () => {
clearInterval(interval);
console.log('Client disconnected.');
});
});
app.listen(port, () => {
console.log(`SSE server listening at http://localhost:${port}`);
console.log('Connect with a browser using EventSource: new EventSource("http://localhost:3000/events")');
});