Skip to content

Latest commit

 

History

History
158 lines (105 loc) · 5.79 KB

File metadata and controls

158 lines (105 loc) · 5.79 KB

Migration guide

v4 to v5

Runtime support

Node.js 22.12 or later is now required. Older Node.js versions may still work, but are not supported or guaranteed going forward because Node.js 20 is out of LTS.

Support for Chrome versions before 84, Safari before 15, Firefox before 105, and Edge before 84 has been dropped. This also applies to JavaScript environments that do not support private fields, methods, and accessors.

CommonJS distribution

The separate CommonJS variant is no longer published. Node.js 22.12 and later transparently supports require() of ESM, so most CommonJS consumers should continue to work. Removing the CommonJS variant avoids the dual-package hazard.

Parser buffer limit

The client now fails the connection, emits an error event, and does not reconnect if it buffers 100 MB without receiving a valid, complete EventSource line. Pass maxBufferSize in the constructor options to configure another limit.

Servers should ideally emit smaller chunks or newlines more frequently rather than requiring a larger buffer.

Event handler order

When both an on* property handler and an addEventListener() listener are registered for the same event, they now run in registration order. Previously, the on* handler always ran first. Code that relied on the old order can observe a different callback sequence.

v3 to v4

Runtime support

Dropped support for Node.js version 18, as it is no longer maintained. While there are no explicit changes that makes it incompatible, we make no guarantees of it being supported going forward.

Code changes

Dropped FetchLikeInit type

If you're using TypeScript, FetchLikeInit is now called EventSourceFetchInit and most of it's properties are now marked as required - since they will always be passed from the EventSource library to your custom fetch method. This makes it easier to use.

v2 to v3

Code changes

Named export

The module now uses named exports instead of a default export. This means you need to change your import statements from:

ESM:

-import EventSource from 'eventsource'
import {EventSource} from 'eventsource'

CommonJS:

-const EventSource = require('eventsource')
const {EventSource} = require('eventsource')

UMD bundle dropped

If you were previously importing/using the eventsource-polyfill.js file/module, you should instead use a bundler like Vite, Rollup or similar. You can theoretically also use something like esm.sh to load the module directly in the browser - eg:

import {EventSource} from 'https://esm.sh/eventsource@3.0.0-beta.0'

Custom headers dropped

In v2 you could specify custom headers through the headers property in the options/init object to the constructor. In v3, the same can be achieved by passing a custom fetch function:

const es = new EventSource('https://my-server.com/sse', {
-  headers: {Authorization: 'Bearer foobar'}
+  fetch: (input, init) => fetch(input, {
+    ...init,
+    headers: {...init.headers, Authorization: 'Bearer foobar'},
+  }),
})

HTTP/HTTPS proxy dropped

Use a package like undici to add proxy support, either through environment variables or explicit configuration.

// npm install undici --save
import {fetch, EnvHttpProxyAgent} from 'undici'

const proxyAgent = new EnvHttpProxyAgent()

const es = new EventSource('https://my-server.com/sse', {
  fetch: (input, init) => fetch(input, {...init, dispatcher: proxyAgent}),
})

Custom HTTPS/connection options dropped

Use a package like undici for more control of fetch options through the use of an Agent.

// npm install undici --save
import {fetch, Agent} from 'undici'

const unsafeAgent = new Agent({
  connect: {
    rejectUnauthorized: false,
  },
})

await fetch('https://my-server.com/sse', {
  dispatcher: unsafeAgent,
})

Behavior changes

New default reconnect timeout

The default reconnect timeout is now 3 seconds - up from 1 second in v1/v2. This aligns better with browsers (Chrome and Safari, Firefox uses 5 seconds). Servers are (as always) free to set their own reconnect timeout through the retry field.

Redirect handling

Redirect handling now matches Chrome/Safari. On disconnects, we will always reconnect to the original URL. In v1/v2, only HTTP 307 would reconnect to the original, while 301 and 302 would both redirect to the destination.

While the ideal behavior would be for 301 and 308 to reconnect to the redirect destination, and 302/307 to reconnect to the original URL, this is not possible to do cross-platform (cross-origin requests in browsers do not allow reading location headers, and redirect handling will have to be done manually).

Strict checking of Content-Type header

The Content-Type header is now checked. It's value must be text/event-stream (or text/event-stream; charset=utf-8), and the connection will be failed otherwise.

To maintain the previous behaviour, you can use the fetch option to override the returned Content-Type header if your server does not send the required header:

const es = new EventSource('https://my-server.com/sse', {
  fetch: async (input, init) => {
    const response = await fetch(input, init)

    if (response.headers.get('content-type').startsWith('text/event-stream')) {
      // Valid header, forward response
      return response
    }

    // Server did not respond with the correct content-type - override it
    const newHeaders = new Headers(response.headers)
    newHeaders.set('content-type', 'text/event-stream')
    return new Response(response.body, {
      status: response.status,
      statusText: response.statusText,
      headers: newHeaders,
    })
  },
})