axios-eventsource 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,139 @@
1
+ # axios-eventsource
2
+
3
+ [![NPM Package][npm]][npm-url]
4
+ [![NPM Downloads][npm-downloads]][npmtrends-url]
5
+ [![Tests][tests-badge]][tests-url]
6
+ [![Coverage][coverage-badge]][coverage-url]
7
+
8
+ Server-Sent Events (SSE) for Axios — one HTTP client for your whole app.
9
+
10
+ Native `EventSource` only supports GET and can’t send custom headers (e.g. Auth tokens). Workarounds — like fetching a one-time token with Axios and passing it in the URL — are brittle. This library gives you real SSE over your existing Axios setup: same interceptors, same auth, same base URL and headers, with an API that matches the native `EventSource` where it matters.
11
+
12
+ ## Why use this
13
+
14
+ - **One stack**: Use your existing Axios instance for both REST and SSE — no separate `EventSource` or fetch-based streaming.
15
+ - **Auth and headers**: Send `Authorization`, API keys, or any headers via interceptors or built-in `auth` options. No URL token hacks.
16
+ - **Familiar API**: `onopen`, `onmessage`, `onerror`, `addEventListener`, `readyState`, and `close()` work like native `EventSource`.
17
+ - **Production behavior**: Automatic reconnects with exponential backoff, `Last-Event-ID` replay, and server `retry:` support.
18
+ - **Everywhere**: Browser (with fetch adapter) and Node.js 18+.
19
+
20
+ ## Install
21
+
22
+ ```sh
23
+ pnpm add axios-eventsource axios
24
+ ```
25
+
26
+ ## Quick Start
27
+
28
+ ```ts
29
+ import axios from "axios";
30
+ import { axiosEventSource } from "axios-eventsource";
31
+
32
+ const client = axios.create({
33
+ baseURL: "https://api.example.com",
34
+ });
35
+
36
+ const stream = axiosEventSource(client, "/events", {
37
+ reconnect: { initialDelayMs: 1_000, maxDelayMs: 30_000 },
38
+ onopen: (event) => {
39
+ console.log("SSE connected, type:", event.type);
40
+ },
41
+ onerror: (event) => {
42
+ console.error("SSE error:", event.error);
43
+ },
44
+ });
45
+
46
+ stream.onmessage = (event) => {
47
+ console.log("message:", event.data, "lastEventId:", event.lastEventId);
48
+ };
49
+
50
+ stream.addEventListener("tick", (event) => {
51
+ const payload = JSON.parse(event.data) as { count: number };
52
+ console.log("tick:", payload.count);
53
+ });
54
+
55
+ // Later
56
+ // stream.close();
57
+ ```
58
+
59
+ ## Authentication
60
+
61
+ Use the same Axios client and interceptors you already have:
62
+
63
+ ```ts
64
+ const client = axios.create();
65
+ client.interceptors.request.use(async (config) => {
66
+ config.headers.Authorization = `Bearer ${await getFreshAccessToken()}`;
67
+ return config;
68
+ });
69
+ const stream = axiosEventSource(client, "https://api.example.com/sse");
70
+ ```
71
+
72
+ Or use built-in auth so you don’t need a pre-configured instance:
73
+
74
+ ```ts
75
+ axiosEventSource("https://api.example.com/sse", {
76
+ auth: { type: "bearer", token: async () => getFreshAccessToken() },
77
+ });
78
+
79
+ // Or: auth: { type: "none" } | { type: "basic", username, password }
80
+ ```
81
+
82
+ ## EventSource parity and behavior
83
+
84
+ The client follows the SSE spec and native `EventSource` semantics where possible:
85
+
86
+ - **`Last-Event-ID`**: Stored and sent on reconnect so the server can resume.
87
+ - **Server `retry:`**: Reconnect delay can be overridden by the server.
88
+ - **MessageEvent-like events**: Each event has `type`, `data`, `origin`, `lastEventId`, `source`, `ports`.
89
+ - **Lifecycle**: `open` and `error` via `addEventListener`; `once` and `handleEvent` object listeners supported.
90
+ - **EventTarget**: The returned instance extends `EventTarget`; `url`, `readyState` (CONNECTING/OPEN/CLOSED), and `close()` behave like native.
91
+
92
+ Additional options: configurable reconnect backoff (`initialDelayMs`, `maxDelayMs`), optional `reconnect.maxRetries`, `encoding` (default UTF-8), and `rejectNonEventStream` (default `true`) to reject non–`text/event-stream` responses. Full TypeScript types are exported.
93
+
94
+ ## API overview
95
+
96
+ - **`axiosEventSource(axiosInstance, url, options?)`** or **`axiosEventSource(url, options?)`** — returns an `EventTarget`-like stream.
97
+ - **Properties**: `readyState`, `url`, `withCredentials`; **callbacks**: `onopen`, `onmessage`, `onerror`.
98
+ - **Methods**: `addEventListener(type, listener, options?)`, `removeEventListener(type, listener)`, `close()`.
99
+ - **Options**: Any Axios request config (method, headers, etc.) plus `auth`, `reconnect`, `encoding`, `rejectNonEventStream`, `signal`, `withCredentials`, `onopen`, `onerror`.
100
+
101
+ Constants `CONNECTING`, `OPEN`, `CLOSED` and the `SseErrorEvent` class are exported; types such as `AxiosEventSourceOptions`, `SseMessageEvent`, and `AuthStrategy` are available for TypeScript.
102
+
103
+ ### Differences from native `EventSource`
104
+
105
+ | Area | Native `EventSource` | `axios-eventsource` |
106
+ | :--- | :--- | :--- |
107
+ | Constructor | `new EventSource(url)` | `axiosEventSource(client, url, opts)` |
108
+ | `onerror` | Bare `Event` | `SseErrorEvent` with `.error` for the real failure |
109
+ | Transport | Browser built-in | Axios + fetch adapter (interceptors, auth, Node.js) |
110
+ | Custom headers / POST | No | Yes |
111
+
112
+ ### Requirements
113
+
114
+ - **Adapter**: Uses Axios with the fetch adapter; response body must be a `ReadableStream<Uint8Array>`.
115
+ - **Node**: Node 18+ for `EventTarget` and `MessageEvent`.
116
+ - **Reconnect**: Runs until `close()` or `signal` abort, unless `reconnect.maxRetries` is set.
117
+
118
+ ## Local Development
119
+
120
+ ```sh
121
+ pnpm install
122
+ pnpm dev
123
+ pnpm test
124
+ ```
125
+
126
+ `pnpm dev` runs the library in watch mode, Express and Fastify SSE demos, and a demo site. See the repo for layout (`packages/axios-eventsource`, `examples/`, etc.).
127
+
128
+ ## Author
129
+
130
+ [Ben Houston](https://benhouston3d.com), Sponsored by [Land of Assets](https://landofassets.com)
131
+
132
+ [npm]: https://img.shields.io/npm/v/axios-eventsource
133
+ [npm-url]: https://www.npmjs.com/package/axios-eventsource
134
+ [npm-downloads]: https://img.shields.io/npm/dw/axios-eventsource
135
+ [npmtrends-url]: https://www.npmtrends.com/axios-eventsource
136
+ [tests-badge]: https://github.com/bhouston/axios-eventsource/workflows/Tests/badge.svg
137
+ [tests-url]: https://github.com/bhouston/axios-eventsource/actions/workflows/test.yml
138
+ [coverage-badge]: https://codecov.io/gh/bhouston/axios-eventsource/branch/main/graph/badge.svg
139
+ [coverage-url]: https://codecov.io/gh/bhouston/axios-eventsource
@@ -0,0 +1,48 @@
1
+ import { type AxiosInstance } from "axios";
2
+ import type { AxiosEventSourceFactory, AxiosEventSourceOptions, AxiosEventSourceReadyState, SseErrorEventPayload, SseEvent, SseMessageEvent } from "./types.js";
3
+ /** ReadyState constant: connection not yet open. */
4
+ export declare const CONNECTING: 0;
5
+ /** ReadyState constant: connection is open. */
6
+ export declare const OPEN: 1;
7
+ /** ReadyState constant: connection is closed. */
8
+ export declare const CLOSED: 2;
9
+ /**
10
+ * Error event with an .error property for the underlying failure.
11
+ * Dispatched when the connection fails or encounters an error.
12
+ */
13
+ export declare class SseErrorEvent extends Event {
14
+ readonly error: unknown;
15
+ constructor(error: unknown);
16
+ }
17
+ /**
18
+ * SSE client that extends EventTarget and matches the EventSource API surface.
19
+ * Uses Axios for the request so interceptors, auth, and config are reused.
20
+ */
21
+ export declare class AxiosEventSource extends EventTarget {
22
+ private readonly _client;
23
+ private readonly _options;
24
+ readonly withCredentials: boolean;
25
+ private _readyState;
26
+ private _url;
27
+ private _initialUrl;
28
+ private _origin;
29
+ private _abortController;
30
+ private _onopen;
31
+ private _onmessage;
32
+ private _onerror;
33
+ constructor(_client: AxiosInstance, url: string, _options?: AxiosEventSourceOptions);
34
+ get readyState(): AxiosEventSourceReadyState;
35
+ get url(): string;
36
+ get onopen(): ((event: SseEvent) => void) | null;
37
+ set onopen(value: ((event: SseEvent) => void) | null);
38
+ get onmessage(): ((event: SseMessageEvent) => void) | null;
39
+ set onmessage(value: ((event: SseMessageEvent) => void) | null);
40
+ get onerror(): ((event: SseErrorEventPayload) => void) | null;
41
+ set onerror(value: ((event: SseErrorEventPayload) => void) | null);
42
+ close(): void;
43
+ /** Called by the factory to start the connection loop. */
44
+ _start(): void;
45
+ }
46
+ export declare const axiosEventSource: AxiosEventSourceFactory;
47
+ export type { AddEventListenerOptions, AuthStrategy, AxiosEventSourceLike, AxiosEventSourceOptions, ReconnectOptions, SseErrorEventPayload, SseEvent, SseEventListener, SseMessageEvent, } from "./types.js";
48
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAc,EAAE,KAAK,aAAa,EAAmD,MAAM,OAAO,CAAC;AAGnG,OAAO,KAAK,EACV,uBAAuB,EAEvB,uBAAuB,EACvB,0BAA0B,EAC1B,oBAAoB,EACpB,QAAQ,EACR,eAAe,EAChB,MAAM,YAAY,CAAC;AAEpB,oDAAoD;AACpD,eAAO,MAAM,UAAU,EAAG,CAAU,CAAC;AACrC,+CAA+C;AAC/C,eAAO,MAAM,IAAI,EAAG,CAAU,CAAC;AAC/B,iDAAiD;AACjD,eAAO,MAAM,MAAM,EAAG,CAAU,CAAC;AAMjC;;;GAGG;AACH,qBAAa,aAAc,SAAQ,KAAK;IACtC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;gBACZ,KAAK,EAAE,OAAO;CAI3B;AA8DD;;;GAGG;AACH,qBAAa,gBAAiB,SAAQ,WAAW;IAY7C,OAAO,CAAC,QAAQ,CAAC,OAAO;IAExB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAb3B,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;IAClC,OAAO,CAAC,WAAW,CAAsD;IACzE,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,gBAAgB,CAAyB;IACjD,OAAO,CAAC,OAAO,CAA4C;IAC3D,OAAO,CAAC,UAAU,CAAmD;IACrE,OAAO,CAAC,QAAQ,CAAwD;gBAGrD,OAAO,EAAE,aAAa,EACvC,GAAG,EAAE,MAAM,EACM,QAAQ,GAAE,uBAA4B;IAWzD,IAAI,UAAU,IAAI,0BAA0B,CAE3C;IAED,IAAI,GAAG,IAAI,MAAM,CAEhB;IAED,IAAI,MAAM,IAAI,CAAC,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CAAC,GAAG,IAAI,CAE/C;IAED,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CAAC,GAAG,IAAI,EAEnD;IAED,IAAI,SAAS,IAAI,CAAC,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC,GAAG,IAAI,CAEzD;IAED,IAAI,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC,GAAG,IAAI,EAE7D;IAED,IAAI,OAAO,IAAI,CAAC,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,CAAC,GAAG,IAAI,CAE5D;IAED,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,CAAC,GAAG,IAAI,EAEhE;IAED,KAAK,IAAI,IAAI;IAOb,0DAA0D;IAC1D,MAAM,IAAI,IAAI;CAqIf;AAED,eAAO,MAAM,gBAAgB,EAAE,uBAc9B,CAAC;AAEF,YAAY,EACV,uBAAuB,EACvB,YAAY,EACZ,oBAAoB,EACpB,uBAAuB,EACvB,gBAAgB,EAChB,oBAAoB,EACpB,QAAQ,EACR,gBAAgB,EAChB,eAAe,GAChB,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,243 @@
1
+ import axios from "axios";
2
+ import { parseSseStream } from "./parseSseStream.js";
3
+ import { getNextDelay, getReconnectConfig, sleepWithAbort } from "./reconnect.js";
4
+ /** ReadyState constant: connection not yet open. */
5
+ export const CONNECTING = 0;
6
+ /** ReadyState constant: connection is open. */
7
+ export const OPEN = 1;
8
+ /** ReadyState constant: connection is closed. */
9
+ export const CLOSED = 2;
10
+ const READY_STATE_CONNECTING = CONNECTING;
11
+ const READY_STATE_OPEN = OPEN;
12
+ const READY_STATE_CLOSED = CLOSED;
13
+ /**
14
+ * Error event with an .error property for the underlying failure.
15
+ * Dispatched when the connection fails or encounters an error.
16
+ */
17
+ export class SseErrorEvent extends Event {
18
+ error;
19
+ constructor(error) {
20
+ super("error");
21
+ this.error = error;
22
+ }
23
+ }
24
+ function isAxiosInstance(value) {
25
+ const candidate = value;
26
+ return ((typeof value === "function" || (typeof value === "object" && value !== null)) &&
27
+ typeof candidate.request === "function" &&
28
+ typeof candidate.get === "function");
29
+ }
30
+ function toBase64(value) {
31
+ if (typeof btoa === "function") {
32
+ return btoa(value);
33
+ }
34
+ return Buffer.from(value).toString("base64");
35
+ }
36
+ async function resolveAuthHeaders(options) {
37
+ const auth = options?.auth;
38
+ if (!auth || auth.type === "none") {
39
+ return {};
40
+ }
41
+ if (auth.type === "basic") {
42
+ const token = toBase64(`${auth.username}:${auth.password}`);
43
+ return { Authorization: `Basic ${token}` };
44
+ }
45
+ const token = typeof auth.token === "function" ? await auth.token() : auth.token;
46
+ return token ? { Authorization: `Bearer ${token}` } : {};
47
+ }
48
+ function getOrigin(url) {
49
+ try {
50
+ return new URL(url).origin;
51
+ }
52
+ catch {
53
+ return "";
54
+ }
55
+ }
56
+ /** Try to get the final URL from the response (e.g. after redirects). */
57
+ function getResponseUrl(response) {
58
+ const r = response;
59
+ if (typeof r.url === "string")
60
+ return r.url;
61
+ if (typeof r.request?.responseURL === "string")
62
+ return r.request.responseURL;
63
+ if (typeof r.request?.url === "string")
64
+ return r.request.url;
65
+ return undefined;
66
+ }
67
+ function isEventStreamResponse(response) {
68
+ const ct = response.headers?.["content-type"];
69
+ if (typeof ct !== "string")
70
+ return false;
71
+ const base = ct.split(";")[0]?.trim().toLowerCase() ?? "";
72
+ return base === "text/event-stream";
73
+ }
74
+ /**
75
+ * SSE client that extends EventTarget and matches the EventSource API surface.
76
+ * Uses Axios for the request so interceptors, auth, and config are reused.
77
+ */
78
+ export class AxiosEventSource extends EventTarget {
79
+ _client;
80
+ _options;
81
+ withCredentials;
82
+ _readyState = READY_STATE_CONNECTING;
83
+ _url;
84
+ _initialUrl;
85
+ _origin;
86
+ _abortController = new AbortController();
87
+ _onopen = null;
88
+ _onmessage = null;
89
+ _onerror = null;
90
+ constructor(_client, url, _options = {}) {
91
+ super();
92
+ this._client = _client;
93
+ this._options = _options;
94
+ this._initialUrl = url;
95
+ this._url = url;
96
+ this._origin = getOrigin(url);
97
+ this.withCredentials = _options.withCredentials ?? false;
98
+ this._onopen = _options.onopen ?? null;
99
+ this._onerror = _options.onerror ?? null;
100
+ }
101
+ get readyState() {
102
+ return this._readyState;
103
+ }
104
+ get url() {
105
+ return this._url;
106
+ }
107
+ get onopen() {
108
+ return this._onopen;
109
+ }
110
+ set onopen(value) {
111
+ this._onopen = value;
112
+ }
113
+ get onmessage() {
114
+ return this._onmessage;
115
+ }
116
+ set onmessage(value) {
117
+ this._onmessage = value;
118
+ }
119
+ get onerror() {
120
+ return this._onerror;
121
+ }
122
+ set onerror(value) {
123
+ this._onerror = value;
124
+ }
125
+ close() {
126
+ if (!this._abortController.signal.aborted) {
127
+ this._abortController.abort();
128
+ }
129
+ this._readyState = READY_STATE_CLOSED;
130
+ }
131
+ /** Called by the factory to start the connection loop. */
132
+ _start() {
133
+ const options = this._options;
134
+ const reconnect = getReconnectConfig(options.reconnect);
135
+ const rejectNonEventStream = options.rejectNonEventStream !== false;
136
+ const encoding = options.encoding ?? "utf-8";
137
+ const { auth: _ignoredAuth, method: _ignoredMethod, reconnect: _ignoredReconnect, onopen: _ignoredOnopen, onerror: _ignoredOnerror, encoding: _ignoredEncoding, rejectNonEventStream: _ignoredReject, ...requestOptions } = options;
138
+ const method = options.method ?? "GET";
139
+ const url = this._initialUrl;
140
+ // If external signal is already aborted, close immediately.
141
+ if (options.signal?.aborted) {
142
+ this.close();
143
+ return;
144
+ }
145
+ options.signal?.addEventListener("abort", () => this.close(), { once: true });
146
+ const connect = async () => {
147
+ let lastEventId = "";
148
+ let baseReconnectDelay = reconnect.initialDelayMs;
149
+ let reconnectDelay = baseReconnectDelay;
150
+ let retryCount = 0;
151
+ while (!this._abortController.signal.aborted) {
152
+ try {
153
+ const authHeaders = await resolveAuthHeaders(options);
154
+ const response = await this._client.request({
155
+ method,
156
+ url,
157
+ ...requestOptions,
158
+ headers: {
159
+ Accept: "text/event-stream",
160
+ "Cache-Control": "no-cache",
161
+ ...(options.headers ?? {}),
162
+ ...authHeaders,
163
+ ...(lastEventId !== "" ? { "Last-Event-ID": lastEventId } : {}),
164
+ },
165
+ responseType: "stream",
166
+ adapter: "fetch",
167
+ decompress: false,
168
+ signal: this._abortController.signal,
169
+ });
170
+ if (response.status !== 200) {
171
+ throw new Error(`Unexpected status code: ${response.status}`);
172
+ }
173
+ if (rejectNonEventStream && !isEventStreamResponse(response)) {
174
+ throw new Error(`Expected Content-Type text/event-stream, got ${response.headers?.["content-type"] ?? "unknown"}`);
175
+ }
176
+ const responseUrl = getResponseUrl(response);
177
+ if (responseUrl !== undefined) {
178
+ this._url = responseUrl;
179
+ this._origin = getOrigin(responseUrl);
180
+ }
181
+ this._readyState = READY_STATE_OPEN;
182
+ reconnectDelay = baseReconnectDelay;
183
+ retryCount = 0;
184
+ const openEvent = new Event("open");
185
+ this.dispatchEvent(openEvent);
186
+ this._onopen?.(openEvent);
187
+ for await (const parsed of parseSseStream(response.data, {
188
+ onRetry: (ms) => {
189
+ baseReconnectDelay = ms;
190
+ reconnectDelay = ms;
191
+ },
192
+ }, encoding)) {
193
+ if (this._abortController.signal.aborted) {
194
+ return;
195
+ }
196
+ lastEventId = parsed.lastEventId;
197
+ const messageEvent = new MessageEvent(parsed.type, {
198
+ data: parsed.data,
199
+ origin: this._origin,
200
+ lastEventId: parsed.lastEventId,
201
+ });
202
+ if (parsed.type === "message") {
203
+ this._onmessage?.(messageEvent);
204
+ }
205
+ this.dispatchEvent(messageEvent);
206
+ }
207
+ }
208
+ catch (error) {
209
+ if (this._abortController.signal.aborted) {
210
+ return;
211
+ }
212
+ retryCount += 1;
213
+ const errorEvent = new SseErrorEvent(error);
214
+ this.dispatchEvent(errorEvent);
215
+ this._onerror?.(errorEvent);
216
+ }
217
+ if (this._abortController.signal.aborted) {
218
+ return;
219
+ }
220
+ const maxRetries = reconnect.maxRetries;
221
+ if (maxRetries !== undefined && retryCount >= maxRetries) {
222
+ this.close();
223
+ return;
224
+ }
225
+ this._readyState = READY_STATE_CONNECTING;
226
+ await sleepWithAbort(reconnectDelay, this._abortController.signal);
227
+ reconnectDelay = getNextDelay(reconnectDelay, reconnect.maxDelayMs);
228
+ }
229
+ };
230
+ void connect();
231
+ }
232
+ }
233
+ export const axiosEventSource = (clientOrUrl, urlOrOptions, maybeOptions) => {
234
+ const client = isAxiosInstance(clientOrUrl) ? clientOrUrl : axios.create();
235
+ const url = isAxiosInstance(clientOrUrl) ? urlOrOptions : clientOrUrl;
236
+ const options = isAxiosInstance(clientOrUrl)
237
+ ? maybeOptions
238
+ : urlOrOptions;
239
+ const instance = new AxiosEventSource(client, url, options);
240
+ instance._start();
241
+ return instance;
242
+ };
243
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,10 @@
1
+ export type ParsedSseEvent = {
2
+ type: string;
3
+ data: string;
4
+ lastEventId: string;
5
+ };
6
+ export type ParseSseStreamCallbacks = {
7
+ onRetry?: (delayMs: number) => void;
8
+ };
9
+ export declare function parseSseStream(stream: ReadableStream<Uint8Array>, callbacks?: ParseSseStreamCallbacks, encoding?: string): AsyncGenerator<ParsedSseEvent>;
10
+ //# sourceMappingURL=parseSseStream.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parseSseStream.d.ts","sourceRoot":"","sources":["../src/parseSseStream.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACrC,CAAC;AAEF,wBAAuB,cAAc,CACnC,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,EAClC,SAAS,CAAC,EAAE,uBAAuB,EACnC,QAAQ,CAAC,EAAE,MAAM,GAChB,cAAc,CAAC,cAAc,CAAC,CAqDhC"}
@@ -0,0 +1,55 @@
1
+ import { createParser } from "eventsource-parser";
2
+ export async function* parseSseStream(stream, callbacks, encoding) {
3
+ const reader = stream.getReader();
4
+ const decoder = new TextDecoder(encoding ?? "utf-8");
5
+ const queue = [];
6
+ // lastEventId accumulates across events per the SSE spec: if no id: is present
7
+ // in an event block, the event inherits the most recently seen id.
8
+ let accumulatedLastEventId = "";
9
+ const parser = createParser({
10
+ onEvent(event) {
11
+ if (event.id !== undefined) {
12
+ accumulatedLastEventId = event.id;
13
+ }
14
+ // Default to "message" only when event field is absent (undefined). Empty string is passed through.
15
+ const type = event.event === undefined ? "message" : event.event;
16
+ queue.push({
17
+ type,
18
+ data: event.data,
19
+ lastEventId: accumulatedLastEventId,
20
+ });
21
+ },
22
+ onRetry(interval) {
23
+ callbacks?.onRetry?.(interval);
24
+ },
25
+ onError() {
26
+ // Ignore malformed chunks and continue parsing.
27
+ },
28
+ });
29
+ try {
30
+ while (true) {
31
+ const { done, value } = await reader.read();
32
+ if (done) {
33
+ break;
34
+ }
35
+ parser.feed(decoder.decode(value, { stream: true }));
36
+ while (queue.length > 0) {
37
+ const nextEvent = queue.shift();
38
+ if (nextEvent) {
39
+ yield nextEvent;
40
+ }
41
+ }
42
+ }
43
+ parser.feed(decoder.decode());
44
+ while (queue.length > 0) {
45
+ const nextEvent = queue.shift();
46
+ if (nextEvent) {
47
+ yield nextEvent;
48
+ }
49
+ }
50
+ }
51
+ finally {
52
+ reader.releaseLock();
53
+ }
54
+ }
55
+ //# sourceMappingURL=parseSseStream.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parseSseStream.js","sourceRoot":"","sources":["../src/parseSseStream.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAA2B,MAAM,oBAAoB,CAAC;AAY3E,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,cAAc,CACnC,MAAkC,EAClC,SAAmC,EACnC,QAAiB;IAEjB,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC;IAClC,MAAM,OAAO,GAAG,IAAI,WAAW,CAAC,QAAQ,IAAI,OAAO,CAAC,CAAC;IACrD,MAAM,KAAK,GAAqB,EAAE,CAAC;IACnC,+EAA+E;IAC/E,mEAAmE;IACnE,IAAI,sBAAsB,GAAG,EAAE,CAAC;IAChC,MAAM,MAAM,GAAG,YAAY,CAAC;QAC1B,OAAO,CAAC,KAAyB;YAC/B,IAAI,KAAK,CAAC,EAAE,KAAK,SAAS,EAAE,CAAC;gBAC3B,sBAAsB,GAAG,KAAK,CAAC,EAAE,CAAC;YACpC,CAAC;YACD,oGAAoG;YACpG,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;YACjE,KAAK,CAAC,IAAI,CAAC;gBACT,IAAI;gBACJ,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,WAAW,EAAE,sBAAsB;aACpC,CAAC,CAAC;QACL,CAAC;QACD,OAAO,CAAC,QAAQ;YACd,SAAS,EAAE,OAAO,EAAE,CAAC,QAAQ,CAAC,CAAC;QACjC,CAAC;QACD,OAAO;YACL,gDAAgD;QAClD,CAAC;KACF,CAAC,CAAC;IAEH,IAAI,CAAC;QACH,OAAO,IAAI,EAAE,CAAC;YACZ,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;YAC5C,IAAI,IAAI,EAAE,CAAC;gBACT,MAAM;YACR,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;YACrD,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACxB,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC;gBAChC,IAAI,SAAS,EAAE,CAAC;oBACd,MAAM,SAAS,CAAC;gBAClB,CAAC;YACH,CAAC;QACH,CAAC;QAED,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;QAC9B,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC;YAChC,IAAI,SAAS,EAAE,CAAC;gBACd,MAAM,SAAS,CAAC;YAClB,CAAC;QACH,CAAC;IACH,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,WAAW,EAAE,CAAC;IACvB,CAAC;AACH,CAAC"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parseSseStream.test.d.ts","sourceRoot":"","sources":["../src/parseSseStream.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,9 @@
1
+ import type { ReconnectOptions } from "./types.js";
2
+ export declare const DEFAULT_RECONNECT_INITIAL_DELAY_MS = 1000;
3
+ export declare const DEFAULT_RECONNECT_MAX_DELAY_MS = 30000;
4
+ export declare function getReconnectConfig(options?: ReconnectOptions): Required<Pick<ReconnectOptions, "initialDelayMs" | "maxDelayMs">> & {
5
+ maxRetries?: number;
6
+ };
7
+ export declare function getNextDelay(currentDelayMs: number, maxDelayMs: number): number;
8
+ export declare function sleepWithAbort(ms: number, signal: AbortSignal): Promise<void>;
9
+ //# sourceMappingURL=reconnect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reconnect.d.ts","sourceRoot":"","sources":["../src/reconnect.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,eAAO,MAAM,kCAAkC,OAAQ,CAAC;AACxD,eAAO,MAAM,8BAA8B,QAAS,CAAC;AAErD,wBAAgB,kBAAkB,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,QAAQ,CACtE,IAAI,CAAC,gBAAgB,EAAE,gBAAgB,GAAG,YAAY,CAAC,CACxD,GAAG;IACF,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CASA;AAED,wBAAgB,YAAY,CAAC,cAAc,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAE/E;AAED,wBAAsB,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBnF"}
@@ -0,0 +1,24 @@
1
+ export const DEFAULT_RECONNECT_INITIAL_DELAY_MS = 1_000;
2
+ export const DEFAULT_RECONNECT_MAX_DELAY_MS = 30_000;
3
+ export function getReconnectConfig(options) {
4
+ const initialDelayMs = Math.max(0, options?.initialDelayMs ?? DEFAULT_RECONNECT_INITIAL_DELAY_MS);
5
+ const maxDelayMs = Math.max(initialDelayMs, options?.maxDelayMs ?? DEFAULT_RECONNECT_MAX_DELAY_MS);
6
+ const maxRetries = options?.maxRetries;
7
+ return { initialDelayMs, maxDelayMs, ...(maxRetries !== undefined && { maxRetries }) };
8
+ }
9
+ export function getNextDelay(currentDelayMs, maxDelayMs) {
10
+ return Math.min(currentDelayMs * 2, maxDelayMs);
11
+ }
12
+ export async function sleepWithAbort(ms, signal) {
13
+ if (signal.aborted || ms <= 0) {
14
+ return;
15
+ }
16
+ await new Promise((resolve) => {
17
+ const timeout = setTimeout(resolve, ms);
18
+ signal.addEventListener("abort", () => {
19
+ clearTimeout(timeout);
20
+ resolve();
21
+ }, { once: true });
22
+ });
23
+ }
24
+ //# sourceMappingURL=reconnect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reconnect.js","sourceRoot":"","sources":["../src/reconnect.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,kCAAkC,GAAG,KAAK,CAAC;AACxD,MAAM,CAAC,MAAM,8BAA8B,GAAG,MAAM,CAAC;AAErD,MAAM,UAAU,kBAAkB,CAAC,OAA0B;IAK3D,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,cAAc,IAAI,kCAAkC,CAAC,CAAC;IAClG,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CACzB,cAAc,EACd,OAAO,EAAE,UAAU,IAAI,8BAA8B,CACtD,CAAC;IACF,MAAM,UAAU,GAAG,OAAO,EAAE,UAAU,CAAC;IAEvC,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,GAAG,CAAC,UAAU,KAAK,SAAS,IAAI,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC;AACzF,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,cAAsB,EAAE,UAAkB;IACrE,OAAO,IAAI,CAAC,GAAG,CAAC,cAAc,GAAG,CAAC,EAAE,UAAU,CAAC,CAAC;AAClD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,EAAU,EAAE,MAAmB;IAClE,IAAI,MAAM,CAAC,OAAO,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;QAC9B,OAAO;IACT,CAAC;IAED,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;QAClC,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QACxC,MAAM,CAAC,gBAAgB,CACrB,OAAO,EACP,GAAG,EAAE;YACH,YAAY,CAAC,OAAO,CAAC,CAAC;YACtB,OAAO,EAAE,CAAC;QACZ,CAAC,EACD,EAAE,IAAI,EAAE,IAAI,EAAE,CACf,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reconnect.test.d.ts","sourceRoot":"","sources":["../src/reconnect.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,85 @@
1
+ import type { AxiosInstance, AxiosRequestConfig, RawAxiosRequestHeaders } from "axios";
2
+ export type AxiosEventSourceReadyState = 0 | 1 | 2;
3
+ export type AuthStrategy = {
4
+ type: "none";
5
+ } | {
6
+ type: "basic";
7
+ username: string;
8
+ password: string;
9
+ } | {
10
+ type: "bearer";
11
+ token: string | (() => string | Promise<string>);
12
+ };
13
+ export type ReconnectOptions = {
14
+ initialDelayMs?: number;
15
+ maxDelayMs?: number;
16
+ /** Maximum number of reconnect attempts after a failure. Omit for unlimited. */
17
+ maxRetries?: number;
18
+ };
19
+ /**
20
+ * Mirrors the minimal Event interface for open events.
21
+ */
22
+ export type SseEvent = {
23
+ readonly type: string;
24
+ };
25
+ /**
26
+ * Mirrors the browser MessageEvent for SSE message events.
27
+ * `source` is always null and `ports` is always empty for SSE streams.
28
+ */
29
+ export type SseMessageEvent = {
30
+ readonly type: string;
31
+ readonly data: string;
32
+ readonly origin: string;
33
+ readonly lastEventId: string;
34
+ readonly source: null;
35
+ readonly ports: readonly [];
36
+ };
37
+ /**
38
+ * Shape of the error event (type + error). The dispatched event is an instance of {@link SseErrorEvent} (class).
39
+ */
40
+ export type SseErrorEventPayload = {
41
+ readonly type: "error";
42
+ readonly error: unknown;
43
+ };
44
+ /**
45
+ * Options passed to addEventListener / removeEventListener.
46
+ * Mirrors the browser AddEventListenerOptions (subset relevant to SSE).
47
+ */
48
+ export type AddEventListenerOptions = {
49
+ once?: boolean;
50
+ };
51
+ /**
52
+ * A listener that is either a callback function or an object with a `handleEvent` method,
53
+ * matching the browser EventListenerOrEventListenerObject pattern.
54
+ */
55
+ export type SseEventListener<T> = ((event: T) => void) | {
56
+ handleEvent(event: T): void;
57
+ };
58
+ export type AxiosEventSourceOptions = Omit<AxiosRequestConfig, "adapter" | "auth" | "decompress" | "method" | "responseType" | "signal"> & {
59
+ auth?: AuthStrategy;
60
+ headers?: RawAxiosRequestHeaders;
61
+ method?: "GET" | "POST";
62
+ reconnect?: ReconnectOptions;
63
+ signal?: AbortSignal;
64
+ withCredentials?: boolean;
65
+ /** Text decoding for the stream. Default `"utf-8"`. Passed to `TextDecoder`. */
66
+ encoding?: string;
67
+ /** Reject non-200 responses or responses whose Content-Type is not `text/event-stream`. Default `true`. */
68
+ rejectNonEventStream?: boolean;
69
+ onopen?: (event: SseEvent) => void;
70
+ onerror?: (event: SseErrorEventPayload) => void;
71
+ };
72
+ export type AxiosEventSourceLike = EventTarget & {
73
+ readonly readyState: AxiosEventSourceReadyState;
74
+ readonly url: string;
75
+ readonly withCredentials: boolean;
76
+ onopen: ((event: SseEvent) => void) | null;
77
+ onmessage: ((event: SseMessageEvent) => void) | null;
78
+ onerror: ((event: SseErrorEventPayload) => void) | null;
79
+ close(): void;
80
+ };
81
+ export type AxiosEventSourceFactory = {
82
+ (axios: AxiosInstance, url: string, options?: AxiosEventSourceOptions): AxiosEventSourceLike;
83
+ (url: string, options?: AxiosEventSourceOptions): AxiosEventSourceLike;
84
+ };
85
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "axios-eventsource",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "default": "./dist/index.js"
11
+ }
12
+ },
13
+ "scripts": {
14
+ "build": "tsc -p tsconfig.build.json",
15
+ "dev": "tsc -p tsconfig.build.json --watch",
16
+ "test": "vitest run"
17
+ },
18
+ "dependencies": {
19
+ "axios": "^1.11.0",
20
+ "eventsource-parser": "^3.0.6"
21
+ }
22
+ }