Event Source Polyfill provides a comprehensive EventSource implementation that enables Server-Sent Events (SSE) functionality across browsers with cross-browser compatibility for IE 8+, Firefox 3.5+, Chrome 3+, Safari 4+, and Opera 12+. It implements the W3C EventSource specification with advanced features including cross-domain requests, custom headers, HTTP Basic Authentication, and configurable parameters.
npm install event-source-polyfillimport { EventSourcePolyfill, NativeEventSource, EventSource } from "event-source-polyfill";For CommonJS:
const { EventSourcePolyfill, NativeEventSource, EventSource } = require("event-source-polyfill");For browser (global):
<script src="node_modules/event-source-polyfill/src/eventsource.js"></script>
<script>
// EventSourcePolyfill, NativeEventSource, and EventSource are now global
</script>import { EventSourcePolyfill } from "event-source-polyfill";
// Create connection
const eventSource = new EventSourcePolyfill("/events", {
headers: {
"Authorization": "Bearer token"
},
withCredentials: true
});
// Listen for events
eventSource.addEventListener("open", (event) => {
console.log("Connection opened");
});
eventSource.addEventListener("message", (event) => {
console.log("Message received:", event.data);
});
eventSource.addEventListener("error", (event) => {
console.log("Error occurred:", event);
});
// Close connection when done
eventSource.close();Event Source Polyfill is built around several key components:
Core EventSource functionality for establishing and managing Server-Sent Event connections.
/**
* EventSourcePolyfill constructor
* @param {string} url - The URL to connect to for Server-Sent Events
* @param {EventSourceOptions} options - Configuration options
*/
function EventSourcePolyfill(url, options);
interface EventSourceOptions {
/** Include credentials (cookies, authorization headers) in requests */
withCredentials?: boolean;
/** Custom headers to send with the request */
headers?: Record<string, string>;
/** Timeout for heartbeat detection in milliseconds (default: 45000) */
heartbeatTimeout?: number;
/** Custom query parameter name for last event ID (default: "lastEventId") */
lastEventIdQueryParameterName?: string;
/** Custom transport implementation */
Transport?: TransportConstructor;
}Properties for monitoring and accessing connection state.
/** Current connection state: CONNECTING (0), OPEN (1), or CLOSED (2) */
readyState: number;
/** The connection URL */
url: string;
/** Whether credentials are included in requests */
withCredentials: boolean;
/** Custom headers sent with requests */
headers: Record<string, string>;State constants for the EventSource connection. Available on both the class and instances.
/** Connection is being established */
EventSourcePolyfill.CONNECTING = 0;
eventSource.CONNECTING = 0;
/** Connection is open and receiving data */
EventSourcePolyfill.OPEN = 1;
eventSource.OPEN = 1;
/** Connection is closed */
EventSourcePolyfill.CLOSED = 2;
eventSource.CLOSED = 2;Methods for controlling the EventSource connection.
/**
* Closes the EventSource connection
*/
close(): void;EventSource follows the standard EventTarget pattern with additional event handler properties.
/** Event handler for connection open events */
onopen: ((event: ConnectionEvent) => void) | null;
/** Event handler for message events */
onmessage: ((event: MessageEvent) => void) | null;
/** Event handler for error events */
onerror: ((event: ErrorEvent) => void) | null;
/**
* Add an event listener
* @param {string} type - Event type ("open", "message", "error", or custom)
* @param {function} listener - Event handler function
*/
addEventListener(type, listener): void;
/**
* Remove an event listener
* @param {string} type - Event type
* @param {function} listener - Event handler function to remove
*/
removeEventListener(type, listener): void;
/**
* Dispatch an event
* @param {Event} event - Event object to dispatch
*/
dispatchEvent(event): void;Event objects passed to event handlers containing relevant data.
/** Connection event fired on open and error */
interface ConnectionEvent {
/** Event type: "open" or "error" */
type: string;
/** HTTP status code */
status: number;
/** HTTP status text */
statusText: string;
/** Response headers */
headers: Headers;
/** Event target (EventSourcePolyfill instance) */
target: EventSourcePolyfill;
}
/** Message event fired when data is received */
interface MessageEvent {
/** Event type: "message" or custom event type from server */
type: string;
/** Message data from server */
data: string;
/** Last event ID for reconnection */
lastEventId: string;
/** Event target (EventSourcePolyfill instance) */
target: EventSourcePolyfill;
}
/** Error event fired on connection errors */
interface ErrorEvent {
/** Event type: "error" */
type: string;
/** Error object with details */
error: Error;
/** Event target (EventSourcePolyfill instance) */
target: EventSourcePolyfill;
}Access to the browser's native EventSource implementation when available.
/** Reference to native EventSource constructor if available, undefined otherwise */
const NativeEventSource: typeof EventSource | undefined;Smart export that uses native EventSource when suitable, polyfill otherwise.
/**
* EventSource constructor - uses native implementation when available and suitable,
* otherwise uses EventSourcePolyfill
*/
const EventSource: typeof EventSourcePolyfill | typeof NativeEventSource;Send custom headers with EventSource requests:
const eventSource = new EventSourcePolyfill("/events", {
headers: {
"Authorization": "Bearer your-token-here",
"X-Custom-Header": "custom-value"
}
});Include credentials (cookies, authorization headers) in cross-origin requests:
const eventSource = new EventSourcePolyfill("https://api.example.com/events", {
withCredentials: true
});Some servers require specific parameter names for the last event ID:
const eventSource = new EventSourcePolyfill("/events", {
lastEventIdQueryParameterName: "Last-Event-Id" // For mercure-hub compatibility
});Configure connection health check timeout:
const eventSource = new EventSourcePolyfill("/events", {
heartbeatTimeout: 30000 // 30 seconds (default: 45000)
});Embed credentials directly in the URL:
const eventSource = new EventSourcePolyfill("http://username:password@example.com/events");For optimal compatibility, servers should:
Content-Type: text/event-streampadding=true query parameter is present)/** Transport constructor for custom transport implementations */
interface TransportConstructor {
new (): Transport;
}
/** Transport interface for custom implementations */
interface Transport {
open(
xhr: any,
onStartCallback: (status: number, statusText: string, contentType: string, headers: Headers) => void,
onProgressCallback: (chunk: string) => void,
onFinishCallback: (error?: Error) => void,
url: string,
withCredentials: boolean,
headers: Record<string, string>
): { abort(): void };
}
/** Headers interface for response headers */
interface Headers {
get(name: string): string | null;
}