{"id":18065,"library":"sse.js","title":"sse.js: Flexible Server-Sent Events Client","description":"sse.js is a robust JavaScript library designed as a flexible replacement for the standard `EventSource` API, enabling more control over Server-Sent Events (SSE) streams. Unlike `EventSource`, it supports POST requests and allows custom HTTP headers, making it suitable for authenticated or complex SSE integrations. The library is currently at version 2.8.0 and receives active maintenance, with recent releases focusing on spec compliance, type definition fixes, and enhanced auto-reconnect capabilities. It differentiates itself by providing a comprehensive EventSource polyfill that addresses the limitations of the native API, such as the inability to send payloads or custom headers, while offering features like configurable reconnection logic and exposure of HTTP response details.","status":"active","version":"2.8.0","language":"javascript","source_language":"en","source_url":"https://github.com/mpetazzoni/sse.js","tags":["javascript","sse","server-side-events","server-sent-events","eventsource","typescript"],"install":[{"cmd":"npm install sse.js","lang":"bash","label":"npm"},{"cmd":"yarn add sse.js","lang":"bash","label":"yarn"},{"cmd":"pnpm add sse.js","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"The primary `SSE` class is a named export. Ensure to destructure it from the module.","wrong":"import SSE from 'sse.js'; // SSE is a named export, not default.","symbol":"SSE","correct":"import { SSE } from 'sse.js';"},{"note":"Import `SSEOptions` using `import type` for type-only declarations to ensure it's removed during compilation and avoid potential runtime errors in environments that don't support it directly.","wrong":"import { SSEOptions } from 'sse.js'; // 'type' keyword is for type-only imports.","symbol":"SSEOptions","correct":"import type { SSEOptions } from 'sse.js';"},{"note":"While `sse.js` is primarily designed for ESM, this CJS pattern *might* work in environments with appropriate transpilation or Node.js module interop settings, but direct named export destructuring is still preferred. For pure ESM projects, stick to `import` statements.","wrong":"const SSE = require('sse.js'); // Assuming default export, but it's a named export.","symbol":"SSE (CommonJS)","correct":"const { SSE } = require('sse.js');"}],"quickstart":{"code":"import { SSE } from 'sse.js';\n\nconst SSE_SERVER_URL = process.env.SSE_SERVER_URL ?? 'http://localhost:3000/events';\nconst AUTH_TOKEN = process.env.AUTH_TOKEN ?? 'your-secret-token';\n\ninterface MyEventData {\n  message: string;\n  timestamp: number;\n}\n\nasync function connectToSSE() {\n  const source = new SSE(SSE_SERVER_URL, {\n    headers: {\n      'Authorization': `Bearer ${AUTH_TOKEN}`,\n      'Accept': 'text/event-stream',\n    },\n    method: 'POST',\n    payload: JSON.stringify({ initialData: 'client-hello' }),\n    autoReconnect: true,\n    reconnectDelay: 5000,\n    maxRetries: 5,\n    useLastEventId: true, // Recommended for resuming streams\n    start: false, // Don't start streaming immediately\n  });\n\n  source.addEventListener('open', (event: Event) => {\n    const openEvent = event as Event & { responseCode?: number; headers?: Record<string, string[]> };\n    console.log(`SSE connection opened. HTTP Status: ${openEvent.responseCode}`);\n    if (openEvent.headers) {\n      console.log('Response Headers:', openEvent.headers);\n    }\n  });\n\n  source.addEventListener('message', (event: MessageEvent) => {\n    try {\n      const payload: MyEventData = JSON.parse(event.data);\n      console.log(`Received event (id: ${event.lastEventId}):`, payload.message, `at ${new Date(payload.timestamp).toLocaleTimeString()}`);\n    } catch (e) {\n      console.error('Failed to parse event data:', e, event.data);\n    }\n  });\n\n  source.addEventListener('error', (event: Event) => {\n    const errorEvent = event as Event & { responseCode?: number; message?: string };\n    console.error(`SSE connection error. HTTP Status: ${errorEvent.responseCode}, Message: ${errorEvent.message}`);\n    if (source.autoReconnect && source.retryCount < (source.maxRetries ?? Infinity)) {\n      console.log(`Attempting to reconnect in ${source.reconnectDelay}ms (attempt ${source.retryCount + 1}/${source.maxRetries ?? '∞'})...`);\n    } else if (source.autoReconnect && source.maxRetries && source.retryCount >= source.maxRetries) {\n      console.log('Max reconnection retries reached. Connection permanently closed.');\n    } else {\n      console.log('Connection closed or not configured for auto-reconnect.');\n    }\n  });\n\n  source.addEventListener('abort', () => {\n    console.log('SSE connection aborted by client.');\n  });\n\n  // Manually start the stream after setting up listeners\n  console.log('Starting SSE stream...');\n  source.stream();\n\n  // Example of closing the connection after some time\n  setTimeout(() => {\n    console.log('Closing SSE connection after 60 seconds...');\n    source.close();\n  }, 60000);\n}\n\nconnectToSSE();\n","lang":"typescript","description":"This quickstart demonstrates how to establish an SSE connection using `sse.js` with custom headers, POST requests, and robust auto-reconnect logic. It includes event listeners for 'open', 'message', 'error', and 'abort' events, showing how to handle incoming JSON data and reconnection attempts, all within a TypeScript context. The stream is manually started and closed after a timeout."},"warnings":[{"fix":"Do not use version 2.4.0 in TypeScript projects. Upgrade to v2.4.1 or later to resolve the missing type definitions.","message":"Version 2.4.0 mistakenly removed the TypeScript type definition for the `SSE` constructor, leading to compilation errors in TypeScript projects.","severity":"breaking","affected_versions":"=2.4.0"},{"fix":"Deploy your SSE server over HTTP/2 or HTTP/3 to mitigate the connection limit, which increases to around 100 simultaneous streams. Alternatively, consider using techniques like sub-domains or reusing connections across tabs if HTTP/1.1 is unavoidable.","message":"When not using HTTP/2, native Server-Sent Events (and thus `sse.js` as a polyfill) are subject to a browser-imposed limit of 6 concurrent connections per domain. This limit applies across all tabs and can lead to connection failures if exceeded.","severity":"gotcha","affected_versions":">=2.0.0"},{"fix":"Review server-side SSE event formatting and client-side logic, particularly around event IDs, retry delays, and data parsing, to ensure compatibility with the updated specification compliance.","message":"Version 2.8.0 introduced several changes to improve SSE specification compliance, which might alter behavior if previous implementations relied on non-compliant aspects. Specifically, the `retry` field now correctly updates the reconnect delay, `id` fields containing NULL are ignored, UTF-8 BOM is stripped, and `lastEventId` is updated even when no event is dispatched.","severity":"breaking","affected_versions":">=2.8.0"},{"fix":"Implement 'keep-alive' messages (e.g., empty comment lines `:\\n\\n`) from the server every 15-30 seconds to prevent proxy timeouts. Consider using HTTP/2 or HTTP/3 where possible, as they handle streaming more robustly. Advise users encountering issues to check their network or firewall settings.","message":"Proxies or corporate firewalls can sometimes interfere with SSE streams, causing unexpected disconnections or delayed event delivery, even if the server is correctly configured. This is due to the `text/event-stream` nature and lack of `Content-Length` header in SSE, which some proxies might misinterpret.","severity":"gotcha","affected_versions":">=2.0.0"},{"fix":"Ensure `useLastEventId: true` is set in the `SSE` constructor options, especially if using `autoReconnect`, to leverage the `Last-Event-ID` header for seamless stream resumption. Upgrade to v2.3.0 or later for improved `Last-Event-ID` support.","message":"Older versions of `EventSource` (and thus `sse.js` if configured not to send `Last-Event-ID`) or certain browsers might not send the `Last-Event-ID` header on reconnection attempts, leading to potential data loss if the server expects it to resume the stream.","severity":"gotcha","affected_versions":"<2.3.0"}],"env_vars":null,"last_verified":"2026-04-25T00:00:00.000Z","next_check":"2026-07-24T00:00:00.000Z","problems":[{"fix":"Use a named import for `SSE`: `import { SSE } from 'sse.js';` for ESM or `const { SSE } = require('sse.js');` for CommonJS.","cause":"Attempting to import `SSE` as a default export using `import SSE from 'sse.js';` or `const SSE = require('sse.js');` when it is a named export.","error":"TypeError: SSE is not a constructor"},{"fix":"If `sse.js` is bundled for browser use and intended to be global, ensure its types are globally declared or accessed as a module. For module-based projects, stick to `import { SSE } from 'sse.js';`. The README shows an async import to attach to `window` for non-module contexts: `(async () => { const { SSE } = await import('./sse.js'); window.SSE = SSE; })();`","cause":"Trying to access `SSE` globally (e.g., `window.SSE`) in a TypeScript project without proper global declaration or module bundling.","error":"Property 'SSE' does not exist on type 'Window & typeof globalThis'."},{"fix":"Verify the `SSE_SERVER_URL` is correct and accessible. Check if the server is running and configured to handle SSE requests (e.g., `Content-Type: text/event-stream`, `Connection: keep-alive`). Also, ensure proper CORS headers are set on the server if the client is on a different origin.","cause":"The SSE server URL provided to the `SSE` constructor is unreachable, incorrect, or the server is not running or misconfigured (e.g., wrong port, CORS issues).","error":"Failed to load resource: net::ERR_CONNECTION_REFUSED"},{"fix":"Configure your SSE server to include the `Access-Control-Allow-Origin` header in its response, allowing requests from your client's origin. For example, `res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8080');` or `res.setHeader('Access-Control-Allow-Origin', '*');` for development.","cause":"The SSE endpoint is hosted on a different origin than the client, and the server is not sending appropriate Cross-Origin Resource Sharing (CORS) headers.","error":"Access to XMLHttpRequest at 'http://example.com/events' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource."}],"ecosystem":"npm","meta_description":null,"install_score":null,"install_tag":null,"quickstart_score":null,"quickstart_tag":null}