An unopinionated, minimalist, standard-focused API for managing Server-Sent Events (SSE) in Node.js.
Discussion and suggestions for improvements are welcome.
Node.js
const http = require('http');
const { SSEService } = require('sse');
const sseService = new SSEService()
http.createServer((request, response) => {
if(request.method === 'GET' && request.url === '/sse')
sseService.register(request, response);
}).listen(8080);
sseService.on('connection', sseId => {
sseService.send('hello', sseId); // sends data to a single response
sseService.send({event:'user-connected'}); // broadcasts data to all responses
});
Express.js
const http = require('http');
const express = require('express');
const { SSEService } = require('sse');
const app = express();
const sseService = new SSEService();
app.get('/sse', sseService.register);
http.createServer(app).listen(8080);
sseService.on('connection', sseId => {
sseService.send('hello', sseId); // sends data to a single response
sseService.send({event:'user-connected'}); // broadcasts data to all responses
})
Server-Sent Events are entirely managed by an sseService.
This service guarantees consistency with respect to the EventSource specification, provided that the server delegates the request to the sseService without sending any headers/data to the response.
The sseService exposes methods to send data with fine-grained targeting on the open SSE connections.
Stability : 1 - Experimental
Object representing an open SSE connection on the server
opts {Object}(optional)opts.heartbeatInterval {number}(optional) - Number of seconds between heartbeats. Heartbeats are':heartbeat\n\n'comments sent periodically to all clients in order to keep their connection alive. If this parameter is set to a negative number, heartbeat is disabled. The setInterval that deals with heartbeats is unReffed. Defaults to15opts.maxNbConnections {integer}(optional) - Allowed maximum number of simultaneously open SSE connections. If set to a negative number, there is no limit. If the number of open SSE connections reaches the limit, incoming connections will be ended immediately. Defaults to-1
While it is allowed to have multiple instances of an
SSEServiceon a same server, it is not recommended as doing so would multiply the number of open connections to that server, consuming resources unnecessarily.Instead, it is preferable to have a single route for Server-Sent Events per server, and implement event management at the application level.
sseId {sse.SSEID}- Connection's SSE identifierlocals {Object}- Theres.localsobject of the connection
Event emitted when an SSE connection has been successfully established
Example :
sseService.on('connection', (sseId, {userName}) => {
sseService.send('greetings', sseId);
sseService.send(userName, 'userConnected');
});
sseId {sse.SSEID}- Connection's SSE identifierlocals {Object}- Theres.localsobject of the connection
Event emitted when the client closed the connection
err {Error}- The error
Event emitted when an error occurred during SSE connection's establishment.
cb {function}(optional) - Callback function
Closes the service by terminating all open connections, and frees up resources. The service won't accept any more connection.
Further incoming connections will be terminated immediately with a 204 HTTP status code, preventing clients from attempting to reconnect.
req {http.IncomingMessage}- The incoming HTTP requestres {http.ServerResponse}- The server response
Sets up an SSE connection by doing the following :
- sends appropriate HTTP headers to the response
- maintains connection alive with the regular sending of heartbeats, unless disabled in the constructor options
- assigns an
sseIdto the response and extends theres.localsobject with ansseproperty :res.locals.sse.id {object}: thesseIdassigned to the responseres.locals.sse.lastEventId {string}(optional) : theLast-Event-IDHTTP header specified inreq, if any
The connection will be rejected if the Accept header in the req object is not set to 'text/event-stream'.
This function accepts no callback, to avoid subsequent code to possibly sending data to the res object.
Instead, the service will emit a 'connection' event if the connection was successful. If not, it will emit an 'error' event.
cb {function}(optional) - Callback function
Resets the Last-Event-ID to the client
opts {Object}opts.data {*}(optional) - Defaults to the empty stringopts.event {string}(optional) - If falsy, noeventfield will be sentopts.id {string}(optional) - If falsy, noidfield will be sentopts.retry {number}(optional) - If falsy, noretryfield will be sentopts.comment {string}(optional) - If falsy, no comment will be senttarget {sse.SSEID | function}(optional) - The target connection(s). Defaults tonull(targets all connections)cb {function}(optional) - Callback function
General-purpose method for sending information to the client.
Convenience methods are also available :
sendData(data[, target[, cb]])
sendEvent(event, data[, id[, target[, cb]]])
sendComment(comment[, target[, cb]])
sendRetry(retry[, target[, cb]])
They all are shorthand methods that call sseService.send under the hood with the correct parameters
target {sse.SSEID | function}- The target connection(s). Defaults tonull(targets all connections)cb {function}(optional) - Callback function
This operation closes the response(s) object(s) matching the target argument and frees up resources. If no target argument is provided, all connections will be closed.
Once a connection has been closed, it can't be sent down any more data.
Clients that close the connection on their own will be automatically unregistered from the service.
Note Due to the optional nature of both the
targetandcbarguments, ifsseService.unRegisteris called with only one function as its argument, this function will be considered as the callback. This behaviour will be applied to all methods having atargetargument.
Supports Node.js 6.x and above.
Implementation of this specification is expected to use Node.js core methods to respond to the client, in particular ServerResponse.writeHead(), ServerResponse.write() and ServerResponse.end().
For this reason, it is does not support Koa.js, that has its own way of handling responses (see http://koajs.com/#context)