Skip to content

v0.15.0

Choose a tag to compare

@MatthewWid MatthewWid released this 22 May 08:24
· 84 commits to master since this release

Better SSE Version 0.15.0

npm install better-sse@latest
yarn add better-sse@latest
pnpm add better-sse@latest

This 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 Session constructor to be able to take in a Request (and optionally a Response) object from the Fetch API.
  • Added the Session#getRequest and Session#getResponse methods to retrieve the Fetch API Request and Response objects, respectively.
  • Added the createResponse utility function to create a Session instance and immediately return its associated Response object.
  • Added type overloads for each combination of arguments to createSession and the Session constructor.
  • Added support for passing a ReadableStream from the Web Streams API to Session#stream and EventBuffer#stream.

Changed

  • Update type of Session constructor options#headers argument to accept any string->(string | string[] | undefined) type rather than only OutgoingHttpHeaders.
  • Update the Session constructor options#headers argument to omit headers whose values are given as undefined, rather than an empty string.
  • Update the Session constructor to throw if given an IncomingMessage or Http2ServerRequest with no corresponding ServerResponse or Http2ServerResponse, respectively.

Fixed

Removed

  • Removed the deprecated Session .event, .data, .id, .retry, .comment, .dispatch and .flush methods.