UNPKG

eventsource

Version:

WhatWG/W3C compliant EventSource client for Node.js and browsers

212 lines (156 loc) 6.54 kB
# eventsource [![npm version](https://img.shields.io/npm/v/eventsource.svg?style=flat-square)](https://www.npmjs.com/package/eventsource)[![npm bundle size](https://img.shields.io/bundlephobia/minzip/eventsource?style=flat-square)](https://bundlephobia.com/result?p=eventsource)[![npm weekly downloads](https://img.shields.io/npm/dw/eventsource.svg?style=flat-square)](https://www.npmjs.com/package/eventsource) WhatWG/W3C-compatible [server-sent events/eventsource](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events) client. The module attempts to implement an absolute minimal amount of features/changes beyond the specification. If you're looking for a modern alternative with a less constrained API, check out the [`eventsource-client` package](https://www.npmjs.com/package/eventsource-client). ## Installation ```bash npm install --save eventsource ``` ## Supported engines - Node.js >= 20 - Chrome >= 71 - Safari >= 11.3 - Firefox >= 65 - Edge >= 79 - Deno >= 1.30 - Bun >= 1.1.23 Basically, any environment that supports: - [fetch](https://developer.mozilla.org/en-US/docs/Web/API/fetch) - [ReadableStream](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) - [TextDecoder](https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder) - [URL](https://developer.mozilla.org/en-US/docs/Web/API/URL) - [Event](https://developer.mozilla.org/en-US/docs/Web/API/Event), [MessageEvent](https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent), [EventTarget](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget) If you need to support older runtimes, try the `2.x` branch/version range (note: 2.x branch is primarily targetted at Node.js, not browsers). ## Usage ```ts import {EventSource} from 'eventsource' const es = new EventSource('https://my-server.com/sse') /* * This will listen for events with the field `event: notice`. */ es.addEventListener('notice', (event) => { console.log(event.data) }) /* * This will listen for events with the field `event: update`. */ es.addEventListener('update', (event) => { console.log(event.data) }) /* * The event "message" is a special case, as it will capture events _without_ an * event field, as well as events that have the specific type `event: message`. * It will not trigger on any other event type. */ es.addEventListener('message', (event) => { console.log(event.data) }) /** * To explicitly close the connection, call the `close` method. * This will prevent any reconnection from happening. */ setTimeout(() => { es.close() }, 10_000) ``` ### TypeScript Make sure you have configured your TSConfig so it matches the environment you are targetting. If you are targetting browsers, this would be `dom`: ```jsonc { "compilerOptions": { "lib": ["dom"], }, } ``` If you're using Node.js, ensure you have `@types/node` installed (and it is version 18 or higher). Cloudflare workers have `@cloudflare/workers-types` etc. The following errors are caused by targetting an environment that does not have the necessary types available: ``` error TS2304: Cannot find name 'Event'. error TS2304: Cannot find name 'EventTarget'. error TS2304: Cannot find name 'MessageEvent'. ``` ## Migrating from v1 / v2 See [MIGRATION.md](MIGRATION.md#v2-to-v3) for a detailed migration guide. ## Extensions to the WhatWG/W3C API ### Message and code properties on errors The `error` event has a `message` and `code` property that can be used to get more information about the error. In the specification, the Event ```ts es.addEventListener('error', (err) => { if (err.code === 401 || err.code === 403) { console.log('not authorized') } }) ``` ### Specify `fetch` implementation The `EventSource` constructor accepts an optional `fetch` property in the second argument that can be used to specify the `fetch` implementation to use. This can be useful in environments where the global `fetch` function is not available - but it can also be used to alter the request/response behaviour. #### Setting HTTP request headers ```ts const es = new EventSource('https://my-server.com/sse', { fetch: (input, init) => fetch(input, { ...init, headers: { ...init.headers, Authorization: 'Bearer myToken', }, }), }) ``` #### HTTP/HTTPS proxy Use a package like [`undici`](https://github.com/nodejs/undici) to add proxy support, either through environment variables or explicit configuration. ```ts // 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}), }) ``` #### Using HTTP2 Use a package like [`undici`](https://github.com/nodejs/undici) that supports HTTP2. ```ts // npm install undici --save import {Agent, fetch} from 'undici' const http2Dispatcher = new Agent({allowH2: true}) const es = new EventSource('https://my-server.com/sse', { fetch: (url, init) => fetch(url, {...init, dispatcher: http2Dispatcher}), }) ``` #### Allow unauthorized HTTPS requests Use a package like [`undici`](https://github.com/nodejs/undici) for more control of fetch options through the use of an [`Agent`](https://undici.nodejs.org/#/docs/api/Agent.md). ```ts // 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, }) ``` #### Feature checking For library authors, you may want to feature-check if an EventSource implementation supports passing a custom `fetch` implementation (such as this library does). We declare (from 4.1.0 and onwards) a non-enumerable symbol on the EventSource class to indicate this, named `eventsource.supports-fetch-override`. It can be used downstream such as: ```ts function yourLibrary(options) { const OurEventSource = options.polyfills.EventSource || globalThis.EventSource if (OurEventSource && Symbol.for('eventsource.supports-fetch-override') in OurEventSource) { // We can safely assume this supports overriding/specifying `fetch`! const es = new OurEventSource('https://some.url', { fetch: (input, init) => fetch(input, { ...init, headers: { ...(init.headers || {}), 'x-some-header': 'foo', }, }), }) // … } } ``` ## License MIT-licensed. See [LICENSE](LICENSE).