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 to15
opts.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
SSEService
on 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.locals
object 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.locals
object 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
sseId
to the response and extends theres.locals
object with ansse
property :res.locals.sse.id {object}
: thesseId
assigned to the responseres.locals.sse.lastEventId {string}
(optional) : theLast-Event-ID
HTTP 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, noevent
field will be sentopts.id {string}
(optional) - If falsy, noid
field will be sentopts.retry {number}
(optional) - If falsy, noretry
field 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
target
andcb
arguments, ifsseService.unRegister
is 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 atarget
argument.
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)