eventsource

js/globals/eventsource.ts

EventSource global for Server-Sent Events (SSE) clients.

Implements the browser-shaped EventSource client over Fino's server-side networking stack. The global handles connection management, automatic reconnection with Last-Event-ID resumption, and EventTarget-based event dispatch. It extends EventTarget so addEventListener() / removeEventListener() work as expected.

The client opens direct HTTP/1 socket or TLS connections and parses the SSE wire stream itself. It intentionally does not share the fetch() connection pool or provide HTTP/2 or HTTP/3 transport behavior in this release baseline. Transport-agnostic SSE parser and formatter primitives are documented in fino:net/http/eventstream.

EventSource / SSE specification: https://html.spec.whatwg.org/multipage/server-sent-events.html

Example

const es = new EventSource('http://localhost:3000/events');
es.onopen    = () => { ... };
es.onmessage = (e) => { console.log(e.data); };
es.onerror   = (e) => { ... };
es.addEventListener('update', (e) => { ... });
// later:
es.close();

SSE wire format

Each event is one or more field lines followed by a blank line: event: <type>n ← optional; defaults to "message" data: <line1>n data: <line2>n ← multi-line data: joined with "n" id: <id>n ← optional; updates lastEventId buffer retry: <ms>n ← optional; integer ms reconnection interval n ← blank line dispatches the event

Lines starting with : are comments (ignored). Unknown field names are ignored. Line terminators: LF, CRLF, or bare CR (per W3C spec).

Parser behavior

EventSource reconnection (W3C spec + pragmatic additions)

Credentials, CORS, and TLS

This is a server-side EventSource implementation. It supports explicit caller-provided headers for credentials such as bearer tokens, but it does not implement browser cookie credential modes, an implicit cookie jar, or browser CORS enforcement. Set-Cookie response headers are ignored; callers that need cookies must provide a Cookie header explicitly. TLS verification is enabled by default for https: URLs. Tests and private deployments may pass a pinned CA path through tls.ca; disabling certificate verification with tls.rejectUnauthorized: false should be limited to local development.

Interfaces

interface EventSourceInit {

Options for the EventSource client connection.

Headers are sent on the initial request and reconnect attempts. The client also adds Last-Event-ID during reconnect when an ID has been seen.

const es = new EventSource('https://example.com/events', {
  headers: { authorization: 'Bearer token' },
});

Properties

withCredentials?: boolean

Reflects the HTML EventSource credential mode flag.

Fino does not maintain a browser cookie jar or enforce browser CORS policy; this option is exposed for standards-shaped API compatibility.

new EventSource(url, { withCredentials: true }).withCredentials; // true
headers?: Record<string, string> | Headers

Extra HTTP headers for the SSE request.

new EventSource(url, { headers: new Headers({ authorization: 'Bearer t' }) });
tls?: { ca?: string; rejectUnauthorized?: boolean; }

TLS trust options for https: EventSource connections.

rejectUnauthorized defaults to true; ca points at a PEM CA file. These options are ignored for http: URLs.

new EventSource('https://localhost/events', { tls: { ca: '/tmp/test-ca.pem' } });

Classes

class EventSource extends EventTarget {

W3C EventSource — a spec-compliant SSE client.

Manages its own HTTP/1.1 connection (plain or TLS), reconnects after stream EOF, network errors, and retriable HTTP statuses, resumes from the last event ID, and dispatches events through the EventTarget interface. The reconnection delay is a fixed interval — 3000ms by default, updated when the server sends a retry: field — not an exponential backoff.

Instances begin connecting as soon as they are constructed. Named events (event: update) are delivered to addEventListener('update', ...) listeners; events without an event: field dispatch as message. Call close() to stop the stream and suppress any further reconnection.

const es = new EventSource('http://localhost:3000/events');
es.onopen = () => console.log('connected');
es.onmessage = (e) => console.log('message:', e.data);
es.onerror = () => console.log('disconnected; will retry');
es.addEventListener('update', (e) => console.log('update:', e.data));
// later:
es.close();

Static Properties

static CONNECTING

Ready state value while connecting or reconnecting.

if (es.readyState === EventSource.CONNECTING) console.log('connecting');
static OPEN

Ready state value while the stream is open.

if (es.readyState === EventSource.OPEN) console.log('open');
static CLOSED

Ready state value after close() or terminal failure.

if (es.readyState === EventSource.CLOSED) console.log('closed');

Constructors

constructor(url: string, init?: EventSourceInit)

Create and immediately start an SSE client.

Only http: and https: URLs are supported. Connection errors dispatch error and reconnect for retriable statuses unless close() is called.

Throws a SyntaxError DOMException if the URL cannot be parsed (relative URLs resolve against globalThis.location when a host defines one).

const es = new EventSource('https://example.com/events', {
  headers: { authorization: 'Bearer token' },
});
es.onmessage = (event) => console.log(event.data);

Getters

get readyState()

Current ready state: CONNECTING (0), OPEN (1), or CLOSED (2).

console.log(es.readyState);
get url()

The URL passed to the constructor.

console.log(es.url);
get lastEventId()

The last event ID received from the server.

Sent as Last-Event-ID on reconnect. Returns an empty string before any id: field is received.

console.log(es.lastEventId);
get withCredentials()

Whether the constructor was created with withCredentials: true.

Fino exposes the standards-shaped reflected property, but does not add browser-managed cookies or CORS enforcement.

const es = new EventSource('/events', { withCredentials: true });
console.log(es.withCredentials);
get onopen()

Callback for open events (connection established).

es.onopen = () => console.log('open');
get onmessage()

Callback for message events (default-type SSE events).

es.onmessage = (event) => console.log(event.data);
get onerror()

Callback for error events (connection errors and fatal failures).

es.onerror = () => console.log('stream error');

Setters

set onopen(fn: ((e: Event) => void) | null)

Set the open event callback, or null to clear it.

es.onopen = null;
set onmessage(fn: ((e: MessageEvent) => void) | null)

Set the message event callback, or null to clear it.

es.onmessage = null;
set onerror(fn: ((e: Event) => void) | null)

Set the error event callback, or null to clear it.

es.onerror = null;

Methods

close()

Close the connection and prevent any further reconnection. Idempotent — safe to call multiple times.

es.close();