Add SSE Session class

This commit is contained in:
2026-07-19 19:24:07 +00:00
parent 2189e9c4f5
commit 65be9c7dee
6 changed files with 1325 additions and 0 deletions

View File

@@ -1,3 +1,131 @@
export type SSERequestInit = {
/**
* The HTTP method to use.
*/
method: 'GET' | 'POST';
/**
* Request headers sent on every connect and reconnect.
*/
headers?: Record<string, string>;
/**
* Request body for POST-based SSE endpoints.
*/
body?: string | FormData;
};
/**
* The fetch function to use.
*
* NOTE: This is compatible with Browser/Node's native "fetch" function.
* We use this in place of "typeof fetch" so that we can accept non-standard URLs ("url" is a "string" here).
* For example, a LibP2P adapter might not use a standardized URL format (and might only include "path").
* This would cause a type error as native fetch expects type "URL".
*/
export type SSERequestFunction = {
fetch: (url: string, options: RequestInit) => Promise<Response>;
};
/**
* Lifecycle hooks invoked by {@link SSESession} during connect, read, and teardown.
*/
export type SSESessionCallbacks = {
/**
* Called before each fetch so callers can attach auth headers, cookies, or
* a `Last-Event-ID` for resume semantics.
*/
onRequest: (request: RequestInit) => Promise<RequestInit>;
/**
* Called after the HTTP stream is established and before body reading begins.
*/
onConnected: () => void;
/**
* Called when the active transport ends — including {@link SSESession.abort},
* server stream completion, and errors. Not paired with {@link SSESessionCallbacks.onConnected}
* when the initial connect never succeeds.
*/
onDisconnected: () => void;
/**
* Called on fetch or read failures. Not invoked for intentional
* {@link SSESession.abort} aborts.
*/
onError: (error: Error) => void;
};
export type SSESessionRetryInterface = {
/**
* Retry policy used while establishing the HTTP connection in
* {@link SSESession.connect}. Defaults to {@link ExponentialBackoff} with
* unlimited attempts.
*/
retry: {
run<T>(fn: () => Promise<T>, onError?: (error: Error) => void): Promise<T>;
};
};
export interface SSEParser {
/**
* Incremental SSE frame parser for the response body.
*
* {@link SSEEventParser.reset} is called by the session when abandoning a
* transport so partial frames do not carry over to the next connection.
*/
eventParser: {
parseEvents(buffer: Uint8Array): SSEvent[];
reset(): void;
};
}
export type SSELifecycleOptions = {
/**
* When true, {@link SSESession} calls {@link SSESession.connect} again after
* a transport **error** (not an intentional abort).
*/
attemptReconnect: boolean;
/**
* When true, {@link SSESession} calls {@link SSESession.connect} again after
* the **server** closes the stream normally (`done`).
*/
persistent: boolean;
};
/**
* Events emitted by {@link SSESession}.
*
* - `"connected"` — HTTP stream established.
* - `"message"` — A complete SSE event was parsed.
* - `"disconnected"` — The active transport ended (including {@link SSESession.abort}).
* - `"error"` — An unexpected fetch or read failure.
* - `"closed"` — {@link SSESession.disconnect} was called; visibility handling is detached.
*/
export type SSESessionEventMap = {
connected: void;
disconnected: void;
error: Error;
message: SSEvent;
closed: void;
};
/**
* Configuration for {@link SSESession}.
*/
export type SSESessionOptions = SSESessionCallbacks
& SSERequestInit
& SSERequestFunction
& SSESessionRetryInterface
& SSELifecycleOptions
& SSEParser;
/**
* Represents a Server-Sent Event.
*/