v0.15.0
Better SSE Version 0.15.0
npm install better-sse@latestyarn add better-sse@latestpnpm add better-sse@latestThis release brings support for web standards to Better SSE.
Most notably, sessions can now take in a Request and an optional Response object, enabling compatibility with the growing number of modern web-server frameworks based on the Fetch API.
This means the following frameworks and runtimes, among others, are now supported by Better SSE:
See the Recipes section of the documentation for example usage with various Fetch-based frameworks.
Changes
Sessions now support the Fetch API
Sessions can now take in a Request and an optional Response object, enabling compatibility with modern web-server frameworks based on the Fetch API.
Its overloads are now:
new Session(IncomingMessage, ServerResponse, SessionOptions?)
new Session(Http2ServerRequest, Http2ServerResponse, SessionOptions?)
new Session(Request, Response, SessionOptions?)
new Session(Request, SessionOptions?)To get started, use the new createResponse function to create a new session and return a corresponding Response object from your route handler. For example (using Hono):
app.get("/sse", (c) =>
createResponse(c.req.raw, (session) => {
session.push("Hello world!")
})
)Why a new createResponse function instead of createSession?
You can still use createSession when using the Fetch API, but createResponse removes the small amount of boilerplate code necessary to do so.
After creating a session we must wait for the underlying connection to be initialized before we can begin pushing events to it.
When using the Node HTTP/1 or HTTP/2 APIs we can flush the response headers and any other preamble data ahead of time and thus immediately begin pushing events to the session:
// Express uses the Node HTTP/1 API
app.get("/sse", async (req, res) => {
const session = await createSession(req, res)
session.push("Hello world!")
})When using a Fetch-based framework, however, we must first return a Response object from our route handler for the session to able to connect and send data.
We can either do this manually (using the new getResponse method):
// Hono uses the Fetch API
app.get("/sse", async (c) => {
const session = await createSession(c.req.raw)
session.addListener("connected", () => {
session.push("Hello world!")
})
return session.getResponse()
})Or use the shorthand createResponse utility function:
app.get("/sse", (c) =>
createResponse(c.req.raw, (session) => {
session.push("Hello world!")
})
)The previous two code snippets are equivalent.
Once you have a connected session instance passed to the callback function you can use it the exact same as you would before, pushing events or registering it to channels.
For more details, see the original pull request and the API reference for createResponse.
Support for web streams
The Session#stream and EventBuffer#stream methods can now accept a ReadableStream from the standardised Web Streams API:
const stream = ReadableStream.from([1, 2, 3])
await session.stream(stream)⚠️ BREAKING: Omit response headers with undefined instead of an empty string
Previously, if you passed an empty string as a header value in the Session constructor options it would be omitted from the response headers:
// Before
res.setHeader("Connection", "keep-alive")
res.setHeader("Cache-Control", "no-cache")
res.setHeader("Content-Type", "text/html")
const session = await createSession(req, res, {
headers: {
Connection: "overwritten",
"Cache-Control": "",
"Content-Type": undefined,
},
})
/**
* Sent headers:
* {
* Connection: "overwritten"
* Content-Type: "text/html"
* }
*/This behaviour has now been changed. Passing an empty string will now simply override the header value with an empty string, while passing undefined will fully omit the header from being sent at all:
// After
res.setHeader("Connection", "keep-alive")
res.setHeader("Cache-Control", "no-cache")
res.setHeader("Content-Type", "text/html")
const session = await createSession(req, res, {
headers: {
Connection: "overwritten",
"Cache-Control": "",
"Content-Type": undefined,
},
})
/**
* Sent headers:
* {
* Connection: "overwritten"
* Cache-Control: ""
* }
*/This is an improvement as previously it was impossible to set header values to an empty string whilst still preserving the header in the response.
⚠️ BREAKING: Deprecated session buffer modification methods removed
The ability to modify the internal session buffer was deprecated almost two years ago and has now been removed.
Specifically, the .event, .data, .id, .retry, .comment, .dispatch and .flush methods are no longer available on the Session class.
If you wish to write raw SSE fields over the wire, use an EventBuffer instead.
See the original deprecation issue for more details.
Full Changelog
Added
- Added support for the
Sessionconstructor to be able to take in aRequest(and optionally aResponse) object from the Fetch API. - Added the
Session#getRequestandSession#getResponsemethods to retrieve the Fetch APIRequestandResponseobjects, respectively. - Added the
createResponseutility function to create aSessioninstance and immediately return its associatedResponseobject. - Added type overloads for each combination of arguments to
createSessionand theSessionconstructor. - Added support for passing a
ReadableStreamfrom the Web Streams API toSession#streamandEventBuffer#stream.
Changed
- Update type of
Sessionconstructoroptions#headersargument to accept anystring->(string | string[] | undefined)type rather than onlyOutgoingHttpHeaders. - Update the
Sessionconstructoroptions#headersargument to omit headers whose values are given asundefined, rather than an empty string. - Update the
Sessionconstructor to throw if given anIncomingMessageorHttp2ServerRequestwith no correspondingServerResponseorHttp2ServerResponse, respectively.
Fixed
- Fixed connection-specific headers being sent when using HTTP/2, causing the response to be treated as malformed.
Removed
- Removed the deprecated Session
.event,.data,.id,.retry,.comment,.dispatchand.flushmethods.