New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

@elefunc/fetcheventsource

Package Overview
Dependencies
Maintainers
1
Versions
5
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@elefunc/fetcheventsource

FetchEventSource - combines the full power of fetch() with EventSource streaming. Supports ALL HTTP methods, request bodies, headers, and fetch options.

latest
npmnpm
Version
1.0.4
Version published
Maintainers
1
Created
Source

FetchEventSource

The FetchEventSource interface represents a connection to server-sent events that supports the fetch() API options. Unlike EventSource, FetchEventSource accepts all fetch() options including request bodies and custom HTTP methods.

Like EventSource, FetchEventSource automatically reconnects after network errors with a default delay of 5 seconds (5000ms). When the server responds with HTTP status 204 (No Content) or any other non-ok HTTP status, the connection is closed and no reconnection attempt is made. When called without method, headers, or body parameters, the constructor returns a standard EventSource instance for backward compatibility.

[!NOTE]

ReadableStream.prototype.events()
Response.prototype.events()

If you don't need strict EventSource API compatibility, consider using Response.prototype.events() instead. It's a simpler method that directly parses SSE streams from fetch responses:

const response = await fetch('https://api.example.com/events');
for await (const { type, data } of response.body.events()) {
  console.log(type, data);
}

Use FetchEventSource when you need the full EventSource API (readyState, automatic reconnection, onerror/onopen handlers, etc.).

API Compatibility Commitment

FetchEventSource preserves 100% API compatibility with both fetch() and EventSource. This is a core design principle:

  • No convenience methods: The library will never add helper functions or shortcuts that don't exist in the standard APIs
  • No proprietary extensions: All options and behaviors strictly follow the fetch() and EventSource specifications
  • Pure compatibility layer: It simply combines the existing APIs without introducing new concepts or patterns
  • Exhaustive testing: The package includes a comprehensive test suite that ensures it behaves exactly like EventSource under all conditions

This commitment ensures that FetchEventSource can serve as a drop-in replacement for EventSource while adding fetch() capabilities, without introducing any non-standard behaviors or API surface.

[!WARNING] When not used over HTTP/2, SSE suffers from a limitation to the maximum number of open connections, which can be specially painful when opening various tabs as the limit is per browser and set to a very low number (6). The issue has been marked as "Won't fix" in Chrome and Firefox. This limit is per browser + domain, so that means that you can open 6 SSE connections across all of the tabs to www.example1.com and another 6 SSE connections to www.example2.com. When using HTTP/2, the maximum number of simultaneous HTTP streams is negotiated between the server and the client (defaults to 100).

Constructor

Static properties

Instance properties

  • FetchEventSource.readyState (Read only)
    • : A number representing the state of the connection. Possible values are 0 (CONNECTING), 1 (OPEN), or 2 (CLOSED).
  • FetchEventSource.url (Read only)
    • : A string representing the URL of the source.
  • FetchEventSource.withCredentials (Read only)
    • : A boolean value indicating whether the FetchEventSource object was instantiated with cross-origin (CORS) credentials set (true), or not (false, the default).

Instance methods

Event handlers

Events

  • error
    • : Fired when a connection to an event source fails to open.
  • message
    • : Fired when data is received from an event source.
  • open
    • : Fired when a connection to an event source is opened.

Additionally, the server can send custom event types with an event field, which will create named events.

Server-Sent Events Protocol

FetchEventSource implements the full SSE protocol, including:

Field Processing

  • Comments: Lines starting with : are ignored
  • Fields: Lines are split on the first : character, with optional space after colon removed
  • Blank lines: Trigger message dispatch

Special Fields

  • event: Sets the event type (defaults to "message")
  • data: Accumulates message data (multiple lines joined with \n)
  • id: Sets the last event ID (rejected if contains null, newline, or carriage return)
  • retry: Updates reconnection delay in milliseconds (must contain only ASCII digits)

Data Handling

  • Multiple data: lines are concatenated with newline characters
  • Messages exceeding 50MB are skipped with an error event
  • Empty messages (no data) are not dispatched

Example

const eventSource = new FetchEventSource('https://api.example.com/events', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer token'
  },
  body: JSON.stringify({ channel: 'updates' })
});

eventSource.onopen = (event) => {
  console.log('Connection opened');
};

eventSource.onmessage = (event) => {
  console.log('Message:', event.data);
};

eventSource.onerror = (event) => {
  console.log('Error occurred');
};

// Close the connection after 30 seconds
setTimeout(() => {
  eventSource.close();
}, 30000);

Specifications

FetchEventSource is not part of any specification. It combines the EventSource API with fetch() request options.

The implementation strictly adheres to:

All behaviors, including reconnection logic, event parsing, and error handling, match the standards exactly.

Browser compatibility

Requires support for:

  • EventSource API
  • Fetch API
  • ReadableStream
  • TextDecoderStream
  • EventTarget
  • Private class fields

The exhaustive test suite verifies compatibility across all major browsers and ensures that FetchEventSource behaves identically to native EventSource in every scenario, including edge cases and error conditions.

See also

Implementation Notes

Request Body Handling

FetchEventSource preserves the original request body and attempts to clone it for each reconnection attempt. This works with cloneable body types like Blob, Response.body, and FormData. Non-cloneable bodies may not work correctly across reconnections.

AbortSignal Handling

When an external signal is provided in options, FetchEventSource uses AbortSignal.any() to combine it with an internal abort controller. This allows both external cancellation and internal connection management.

Content-Type Validation

The response Content-Type header must be exactly text/event-stream (case-insensitive, before any semicolon). Other content types will close the connection without retry.

URL.parse Polyfill

The implementation includes a polyfill for URL.parse() to support environments where it's not available (pre-Baseline September 2024).

FetchEventSource: FetchEventSource() constructor

The FetchEventSource() constructor creates a new FetchEventSource object to establish a connection to a server to receive server-sent events.

Syntax

new FetchEventSource(url)
new FetchEventSource(url, options)

Parameters

  • url
    • : A string that represents the location of the remote resource serving the events/messages.
  • options (optional)
    • : An object containing any custom settings you want to apply to the request. Accepts all RequestInit options from the Fetch API. Notable options include:
      • method (optional)
        • : The request method, e.g., "GET", "POST", "PUT", "DELETE".
      • headers (optional)
        • : Any headers you want to add to your request, contained within a Headers object or object literal.
      • body (optional)
      • mode (optional)
        • : The mode you want to use for the request, e.g., cors, no-cors, or same-origin.
      • credentials (optional)
        • : Controls what browsers do with credentials (cookies, HTTP authentication entries, and TLS client certificates).
      • signal (optional)
      • withCredentials (optional)
        • : A boolean value indicating if CORS should be set to include credentials. This option is only used when body is not provided, for backward compatibility with standard EventSource.

Return value

A FetchEventSource object configured with the provided options. If method, headers, and body are all undefined, returns a standard EventSource instance instead.

[!NOTE] When method, headers, and body are all undefined, the constructor returns a standard EventSource for backward compatibility. An empty string ("") is considered a valid body and will create a FetchEventSource instance. The class includes protection against malicious servers that send extremely large messages - any message exceeding 50MB will be skipped and an error event will be dispatched.

Body Requires Method: When providing a body parameter, you must also specify a method (typically POST or PUT). Attempting to send a body with the default GET method will result in a TypeError, as GET/HEAD requests cannot have a body according to the HTTP specification.

Automatic Headers: FetchEventSource automatically sets the following headers:

  • Cache-Control: no-store (to prevent caching)
  • Accept: text/event-stream (to request SSE format)
  • Last-Event-ID: <id> (if reconnecting after receiving an event ID)

Credentials Handling: The withCredentials option is mapped to the fetch credentials option:

  • withCredentials: truecredentials: 'include'
  • withCredentials: falsecredentials: 'same-origin' (default)

Examples

Basic usage

// Returns a standard EventSource (no method, headers, or body)
const eventSource = new FetchEventSource('https://api.example.com/events');

eventSource.onmessage = (event) => {
  console.log(event.data);
};

POST request with JSON body

const eventSource = new FetchEventSource('https://api.example.com/events', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    channel: 'updates',
    userId: '12345'
  })
});

eventSource.onopen = () => {
  console.log('Connection established');
};

eventSource.onmessage = (event) => {
  const data = JSON.parse(event.data);
  console.log('Received:', data);
};

GET request with custom headers

// Returns FetchEventSource instance because headers are provided
const eventSource = new FetchEventSource('https://api.example.com/events', {
  headers: {
    'Authorization': 'Bearer token123',
    'X-Custom-Header': 'value'
  }
});

eventSource.onmessage = (event) => {
  console.log('Authenticated message:', event.data);
};

Using AbortController

const controller = new AbortController();

const eventSource = new FetchEventSource('https://api.example.com/events', {
  method: 'POST',
  body: 'subscribe=true',
  signal: controller.signal
});

// Abort the connection after 5 seconds
setTimeout(() => {
  controller.abort();
}, 5000);

Common Mistake: Body Without Method

// ❌ WRONG - This will throw a TypeError
const eventSource = new FetchEventSource('https://api.example.com/events', {
  body: 'subscribe=true'  // Missing method!
});
// Error: "Request with GET/HEAD method cannot have body"

// ✅ CORRECT - Always specify method when using body
const eventSource = new FetchEventSource('https://api.example.com/events', {
  method: 'POST',
  body: 'subscribe=true'
});

FetchEventSource: readyState property

The readyState read-only property of the FetchEventSource interface returns a number representing the state of the connection.

Value

A number which can be one of three values:

  • 0 — connecting
  • 1 — open
  • 2 — closed

Examples

const eventSource = new FetchEventSource('https://api.example.com/events', {
  method: 'POST',
  body: 'subscribe=true'
});

console.log(eventSource.readyState); // 0 (connecting)

eventSource.onopen = () => {
  console.log(eventSource.readyState); // 1 (open)
};

eventSource.onerror = () => {
  if (eventSource.readyState === FetchEventSource.CONNECTING) {
    console.log('Reconnecting...');
  } else if (eventSource.readyState === FetchEventSource.CLOSED) {
    console.log('Connection closed');
  }
};

FetchEventSource: url property

The url read-only property of the FetchEventSource interface returns a string containing the URL of the source.

Value

A string.

Examples

const eventSource = new FetchEventSource('https://api.example.com/events', {
  method: 'POST',
  body: 'subscribe=true'
});

console.log(eventSource.url); // "https://api.example.com/events"

FetchEventSource: withCredentials property

The withCredentials read-only property of the FetchEventSource interface returns a boolean value indicating whether the FetchEventSource object was instantiated with CORS credentials set.

Value

A boolean value indicating whether the FetchEventSource object was instantiated with CORS credentials set (true), or not (false, the default).

Examples

const eventSource = new FetchEventSource('https://api.example.com/events', {
  credentials: 'include'
});

console.log(eventSource.withCredentials); // true

const eventSource2 = new FetchEventSource('https://api.example.com/events');
console.log(eventSource2.withCredentials); // false

FetchEventSource: close() method

The close() method of the FetchEventSource interface closes the connection, if one is made, and sets the FetchEventSource.readyState attribute to 2 (closed).

If the connection is already closed, the method does nothing.

When closing, the method:

  • Sets the internal "explicitly closed" flag to prevent reconnection
  • Immediately sets readyState to CLOSED
  • Clears any pending reconnection timeout
  • Cancels the active stream reader (if any)
  • Aborts the fetch request via the internal AbortController

Syntax

close()

Parameters

None.

Return value

None (undefined).

Examples

const eventSource = new FetchEventSource('https://api.example.com/events', {
  method: 'POST',
  body: 'subscribe=true'
});

eventSource.onopen = () => {
  console.log('Connected');
};

// Close the connection after 10 seconds
setTimeout(() => {
  eventSource.close();
  console.log('Connection closed');
}, 10000);

FetchEventSource: error event

The error event of the FetchEventSource interface is fired when a connection to an event source fails to be opened or when an error occurs during communication.

Like EventSource, FetchEventSource automatically attempts to reconnect after network errors, with the connection state changing to CONNECTING during reconnection attempts. However, no reconnection is attempted for HTTP error responses (including 204 No Content) or Content-Type mismatches.

Syntax

Use the event name in methods like addEventListener(), or set an event handler property.

addEventListener("error", (event) => {});

onerror = (event) => {};

Reconnection Behavior

When a network error occurs:

  • The readyState changes to CONNECTING (0)
  • An error event is dispatched
  • A reconnection attempt is scheduled after the retry delay
  • The retry delay starts at 5 seconds and can be updated by the server

No reconnection occurs if:

  • The connection was explicitly closed via close()
  • The external AbortSignal was aborted
  • The server returned a non-200 status or wrong Content-Type

Event type

An ErrorEvent with the following properties:

  • message: A string describing the error
  • error: The actual Error object (when available)

Examples

const eventSource = new FetchEventSource('https://api.example.com/events', {
  method: 'POST',
  body: 'subscribe=true'
});

// Using addEventListener
eventSource.addEventListener('error', (event) => {
  if (eventSource.readyState === FetchEventSource.CONNECTING) {
    console.log('Connection lost. Attempting to reconnect...');
  } else if (eventSource.readyState === FetchEventSource.CLOSED) {
    console.log('Connection closed');
  }
});

// Using the onerror property
eventSource.onerror = (event) => {
  console.error('An error occurred');
};

FetchEventSource: message event

The message event of the FetchEventSource interface is fired when data is received from the event source.

A message event is fired when the event source sends an event that either has no event field or has the event field set to message.

Syntax

Use the event name in methods like addEventListener(), or set an event handler property.

addEventListener("message", (event) => {});

onmessage = (event) => {};

Event type

A MessageEvent. Inherits from Event.

Event properties

This interface also inherits properties from its parent, Event.

Examples

const eventSource = new FetchEventSource('https://api.example.com/events', {
  method: 'POST',
  body: 'subscribe=true'
});

// Using addEventListener
eventSource.addEventListener('message', (event) => {
  console.log('Received data:', event.data);
  console.log('Event ID:', event.lastEventId);
});

// Using the onmessage property
eventSource.onmessage = (event) => {
  try {
    const data = JSON.parse(event.data);
    console.log('Parsed data:', data);
  } catch (e) {
    console.log('Raw data:', event.data);
  }
};

FetchEventSource: open event

The open event of the FetchEventSource interface is fired when a connection to an event source is opened.

Syntax

Use the event name in methods like addEventListener(), or set an event handler property.

addEventListener("open", (event) => {});

onopen = (event) => {};

Event type

A generic Event.

Examples

const eventSource = new FetchEventSource('https://api.example.com/events', {
  method: 'POST',
  body: 'subscribe=true'
});

// Using addEventListener
eventSource.addEventListener('open', (event) => {
  console.log('Connection opened');
  console.log('Ready state:', eventSource.readyState); // 1
});

// Using the onopen property
eventSource.onopen = (event) => {
  console.log('Successfully connected to event stream');
};

FetchEventSource: onopen property

The onopen property of the FetchEventSource interface is an event handler for the open event; this event is fired when a connection to the server is opened.

Syntax

eventSource.onopen = function;

Examples

const eventSource = new FetchEventSource('https://api.example.com/events', {
  method: 'POST',
  body: 'subscribe=true'
});

eventSource.onopen = (event) => {
  console.log('Connection opened');
  console.log('Ready state:', eventSource.readyState); // 1 (OPEN)
};

FetchEventSource: onmessage property

The onmessage property of the FetchEventSource interface is an event handler for the message event; this event is fired when data is received from the server with no event field or with the event field set to message.

Syntax

eventSource.onmessage = function;

Examples

const eventSource = new FetchEventSource('https://api.example.com/events', {
  method: 'POST',
  body: 'subscribe=true'
});

eventSource.onmessage = (event) => {
  console.log('Message received:', event.data);
  console.log('Last event ID:', event.lastEventId);
  
  try {
    const data = JSON.parse(event.data);
    console.log('Parsed data:', data);
  } catch (e) {
    console.log('Non-JSON data:', event.data);
  }
};

FetchEventSource: onerror property

The onerror property of the FetchEventSource interface is an event handler for the error event; this event is fired when an error occurs.

When a network error occurs, FetchEventSource automatically attempts to reconnect. During reconnection, the readyState changes to CONNECTING (0).

Syntax

eventSource.onerror = function;

Examples

const eventSource = new FetchEventSource('https://api.example.com/events', {
  method: 'POST',
  body: 'subscribe=true'
});

eventSource.onerror = (event) => {
  if (eventSource.readyState === FetchEventSource.CONNECTING) {
    console.log('Connection lost. Attempting to reconnect...');
  } else if (eventSource.readyState === FetchEventSource.CLOSED) {
    console.log('Connection closed permanently');
  }
};

FetchEventSource: Custom events

The FetchEventSource interface supports custom event types sent by the server. When the server sends an event with a custom event field, FetchEventSource dispatches a named event of that type.

Syntax

addEventListener("eventname", (event) => {});

Event type

A MessageEvent with the same properties as the message event.

Examples

const eventSource = new FetchEventSource('https://api.example.com/events', {
  method: 'POST',
  body: 'subscribe=true'
});

// Listen for custom 'update' events
eventSource.addEventListener('update', (event) => {
  console.log('Update event:', event.data);
});

// Listen for custom 'notification' events
eventSource.addEventListener('notification', (event) => {
  const notification = JSON.parse(event.data);
  console.log('Notification:', notification);
});

// Listen for custom 'ping' events
eventSource.addEventListener('ping', (event) => {
  console.log('Ping received at:', new Date());
});

Server-side example

The server sends custom events by including an event field:

event: update
data: {"status": "processing"}

event: notification
data: {"type": "info", "message": "Task completed"}

event: ping
data: {"timestamp": 1234567890}

Keywords

eventsource

FAQs

Package last updated on 17 Jun 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts