@ahoo-wang/fetcher-eventstream 2.9.2 → 2.9.5

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/dist/index.es.js CHANGED
@@ -1,5 +1,5 @@
1
- import { FetcherError as l, CONTENT_TYPE_HEADER as y, ContentTypeValues as h } from "@ahoo-wang/fetcher";
2
- class m {
1
+ import { FetcherError as f, CONTENT_TYPE_HEADER as h, ContentTypeValues as y } from "@ahoo-wang/fetcher";
2
+ class E {
3
3
  constructor() {
4
4
  this.buffer = "";
5
5
  }
@@ -15,8 +15,8 @@ class m {
15
15
  const n = this.buffer.split(`
16
16
  `);
17
17
  this.buffer = n.pop() || "";
18
- for (const o of n)
19
- r.enqueue(o);
18
+ for (const s of n)
19
+ r.enqueue(s);
20
20
  } catch (n) {
21
21
  r.error(n);
22
22
  }
@@ -34,9 +34,9 @@ class m {
34
34
  }
35
35
  }
36
36
  }
37
- class E extends TransformStream {
37
+ class m extends TransformStream {
38
38
  constructor() {
39
- super(new m());
39
+ super(new E());
40
40
  }
41
41
  }
42
42
  const c = class c {
@@ -61,44 +61,56 @@ function v(t, e, r) {
61
61
  }
62
62
  }
63
63
  }
64
- const a = "message";
64
+ const u = "message";
65
65
  class S {
66
66
  constructor() {
67
- this.currentEvent = {
68
- event: a,
67
+ this.currentEventState = {
68
+ event: u,
69
69
  id: void 0,
70
70
  retry: void 0,
71
71
  data: []
72
72
  };
73
73
  }
74
+ /**
75
+ * Reset the current event state to default values.
76
+ * This method is called after processing each complete event or when an error occurs.
77
+ */
78
+ resetEventState() {
79
+ this.currentEventState.event = u, this.currentEventState.id = void 0, this.currentEventState.retry = void 0, this.currentEventState.data = [];
80
+ }
74
81
  /**
75
82
  * Transform input string chunk into ServerSentEvent object.
83
+ * This method processes individual chunks of text data, parsing them according to the SSE format.
84
+ * It handles:
85
+ * - Empty lines (used as event separators)
86
+ * - Comment lines (starting with ':')
87
+ * - Field lines (field: value format)
88
+ * - Event completion and emission
76
89
  *
77
90
  * @param chunk Input string chunk
78
91
  * @param controller Controller for controlling the transform stream
79
92
  */
80
93
  transform(e, r) {
81
- const n = this.currentEvent;
94
+ const n = this.currentEventState;
82
95
  try {
83
96
  if (e.trim() === "") {
84
97
  n.data.length > 0 && (r.enqueue({
85
- event: n.event || a,
98
+ event: n.event || u,
86
99
  data: n.data.join(`
87
100
  `),
88
101
  id: n.id || "",
89
102
  retry: n.retry
90
- }), n.event = a, n.data = []);
103
+ }), n.event = u, n.data = []);
91
104
  return;
92
105
  }
93
106
  if (e.startsWith(":"))
94
107
  return;
95
- const o = e.indexOf(":");
96
- let p, s;
97
- o === -1 ? (p = e.toLowerCase(), s = "") : (p = e.substring(0, o).toLowerCase(), s = e.substring(o + 1), s.startsWith(" ") && (s = s.substring(1))), p = p.trim(), s = s.trim(), v(p, s, n);
98
- } catch (o) {
99
- r.error(
100
- o instanceof Error ? o : new Error(String(o))
101
- ), n.event = a, n.id = void 0, n.retry = void 0, n.data = [];
108
+ const s = e.indexOf(":");
109
+ let a, o;
110
+ s === -1 ? (a = e.toLowerCase(), o = "") : (a = e.substring(0, s).toLowerCase(), o = e.substring(s + 1), o.startsWith(" ") && (o = o.substring(1))), a = a.trim(), o = o.trim(), v(a, o, n);
111
+ } catch (s) {
112
+ const a = new Error(`Failed to process chunk: "${e}". ${s instanceof Error ? s.message : String(s)}`);
113
+ r.error(a), this.resetEventState();
102
114
  }
103
115
  }
104
116
  /**
@@ -107,21 +119,20 @@ class S {
107
119
  * @param controller Controller for controlling the transform stream
108
120
  */
109
121
  flush(e) {
110
- const r = this.currentEvent;
122
+ const r = this.currentEventState;
111
123
  try {
112
124
  r.data.length > 0 && e.enqueue({
113
- event: r.event || a,
125
+ event: r.event || u,
114
126
  data: r.data.join(`
115
127
  `),
116
128
  id: r.id || "",
117
129
  retry: r.retry
118
130
  });
119
131
  } catch (n) {
120
- e.error(
121
- n instanceof Error ? n : new Error(String(n))
122
- );
132
+ const s = new Error(`Failed to flush remaining data. ${n instanceof Error ? n.message : String(n)}`);
133
+ e.error(s);
123
134
  } finally {
124
- r.event = a, r.id = void 0, r.retry = void 0, r.data = [];
135
+ this.resetEventState();
125
136
  }
126
137
  }
127
138
  }
@@ -130,7 +141,7 @@ class T extends TransformStream {
130
141
  super(new S());
131
142
  }
132
143
  }
133
- class u extends l {
144
+ class p extends f {
134
145
  /**
135
146
  * Creates a new EventStreamConvertError instance.
136
147
  * @param response - The Response object associated with the error
@@ -138,13 +149,13 @@ class u extends l {
138
149
  * @param cause - Optional underlying error that caused this error
139
150
  */
140
151
  constructor(e, r, n) {
141
- super(r, n), this.response = e, this.name = "EventStreamConvertError", Object.setPrototypeOf(this, u.prototype);
152
+ super(r, n), this.response = e, this.name = "EventStreamConvertError", Object.setPrototypeOf(this, p.prototype);
142
153
  }
143
154
  }
144
155
  function b(t) {
145
156
  if (!t.body)
146
- throw new u(t, "Response body is null");
147
- return t.body.pipeThrough(new TextDecoderStream("utf-8")).pipeThrough(new E()).pipeThrough(new T());
157
+ throw new p(t, "Response body is null");
158
+ return t.body.pipeThrough(new TextDecoderStream("utf-8")).pipeThrough(new m()).pipeThrough(new T());
148
159
  }
149
160
  class R {
150
161
  transform(e, r) {
@@ -173,18 +184,18 @@ Object.prototype.hasOwnProperty.call(
173
184
  d
174
185
  ) || Object.defineProperty(Response.prototype, d, {
175
186
  get() {
176
- return this.headers.get(y);
187
+ return this.headers.get(h);
177
188
  },
178
189
  configurable: !0
179
190
  });
180
- const f = "isEventStream";
191
+ const l = "isEventStream";
181
192
  Object.prototype.hasOwnProperty.call(
182
193
  Response.prototype,
183
- f
184
- ) || Object.defineProperty(Response.prototype, f, {
194
+ l
195
+ ) || Object.defineProperty(Response.prototype, l, {
185
196
  get() {
186
197
  const t = this.contentType;
187
- return t ? t.includes(h.TEXT_EVENT_STREAM) : !1;
198
+ return t ? t.includes(y.TEXT_EVENT_STREAM) : !1;
188
199
  },
189
200
  configurable: !0
190
201
  });
@@ -197,7 +208,7 @@ Object.prototype.hasOwnProperty.call(
197
208
  ) || (Response.prototype.requiredEventStream = function() {
198
209
  const t = this.eventStream();
199
210
  if (!t)
200
- throw new u(
211
+ throw new p(
201
212
  this,
202
213
  `Event stream is not available. Response content-type: [${this.contentType}]`
203
214
  );
@@ -213,7 +224,7 @@ Object.prototype.hasOwnProperty.call(
213
224
  ) || (Response.prototype.requiredJsonEventStream = function() {
214
225
  const t = this.jsonEventStream();
215
226
  if (!t)
216
- throw new u(
227
+ throw new p(
217
228
  this,
218
229
  `Event stream is not available. Response content-type: [${this.contentType}]`
219
230
  );
@@ -299,7 +310,7 @@ P || (ReadableStream.prototype[Symbol.asyncIterator] = function() {
299
310
  return new O(this);
300
311
  });
301
312
  export {
302
- u as EventStreamConvertError,
313
+ p as EventStreamConvertError,
303
314
  N as EventStreamResultExtractor,
304
315
  q as JsonEventStreamResultExtractor,
305
316
  R as JsonServerSentEventTransform,
@@ -308,8 +319,8 @@ export {
308
319
  i as ServerSentEventFields,
309
320
  T as ServerSentEventTransformStream,
310
321
  S as ServerSentEventTransformer,
311
- E as TextLineTransformStream,
312
- m as TextLineTransformer,
322
+ m as TextLineTransformStream,
323
+ E as TextLineTransformer,
313
324
  P as isReadableStreamAsyncIterableSupported,
314
325
  g as toJsonServerSentEventStream,
315
326
  b as toServerSentEventStream
@@ -1 +1 @@
1
- {"version":3,"file":"index.es.js","sources":["../src/textLineTransformStream.ts","../src/serverSentEventTransformStream.ts","../src/eventStreamConverter.ts","../src/jsonServerSentEventTransformStream.ts","../src/eventStreamResultExtractor.ts","../src/responses.ts","../src/readableStreamAsyncIterable.ts","../src/readableStreams.ts"],"sourcesContent":["/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Transformer that splits text into lines.\n *\n * This transformer accumulates chunks of text and splits them by newline characters,\n * emitting each line as a separate chunk while preserving the remaining buffer\n * for the next chunk.\n */\nexport class TextLineTransformer implements Transformer<string, string> {\n private buffer = '';\n\n /**\n * Transform input string chunk by splitting it into lines.\n *\n * @param chunk Input string chunk\n * @param controller Controller for controlling the transform stream\n */\n transform(\n chunk: string,\n controller: TransformStreamDefaultController<string>,\n ) {\n try {\n this.buffer += chunk;\n const lines = this.buffer.split('\\n');\n this.buffer = lines.pop() || '';\n\n for (const line of lines) {\n controller.enqueue(line);\n }\n } catch (error) {\n controller.error(error);\n }\n }\n\n /**\n * Flush remaining buffer when the stream ends.\n *\n * @param controller Controller for controlling the transform stream\n */\n flush(controller: TransformStreamDefaultController<string>) {\n try {\n // Only send when buffer is not empty, avoid sending meaningless empty lines\n if (this.buffer) {\n controller.enqueue(this.buffer);\n }\n } catch (error) {\n controller.error(error);\n }\n }\n}\n\n/**\n * A TransformStream that splits text into lines.\n */\nexport class TextLineTransformStream extends TransformStream<string, string> {\n constructor() {\n super(new TextLineTransformer());\n }\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Represents a message sent in an event stream.\n *\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format}\n */\nexport interface ServerSentEvent {\n /** The event ID to set the EventSource object's last event ID value. */\n id?: string;\n /** A string identifying the type of event described. */\n event: string;\n /** The event data */\n data: string;\n /** The reconnection interval (in milliseconds) to wait before retrying the connection */\n retry?: number;\n}\n\nexport class ServerSentEventFields {\n static readonly ID = 'id';\n static readonly RETRY = 'retry';\n static readonly EVENT = 'event';\n static readonly DATA = 'data';\n}\n\n/**\n * Process field value\n * @param field Field name\n * @param value Field value\n * @param currentEvent Current event state\n */\nfunction processFieldInternal(\n field: string,\n value: string,\n currentEvent: EventState,\n) {\n switch (field) {\n case ServerSentEventFields.EVENT:\n currentEvent.event = value;\n break;\n case ServerSentEventFields.DATA:\n currentEvent.data.push(value);\n break;\n case ServerSentEventFields.ID:\n currentEvent.id = value;\n break;\n case ServerSentEventFields.RETRY: {\n const retryValue = parseInt(value, 10);\n if (!isNaN(retryValue)) {\n currentEvent.retry = retryValue;\n }\n break;\n }\n default:\n // Ignore unknown fields\n break;\n }\n}\n\ninterface EventState {\n event?: string;\n id?: string;\n retry?: number;\n data: string[];\n}\n\nconst DEFAULT_EVENT_TYPE = 'message';\n\n/**\n * Transformer responsible for converting a string stream into a ServerSentEvent object stream.\n *\n * Implements the Transformer interface for processing data transformation in TransformStream.\n */\nexport class ServerSentEventTransformer\n implements Transformer<string, ServerSentEvent> {\n // Initialize currentEvent with default values in a closure\n private currentEvent: EventState = {\n event: DEFAULT_EVENT_TYPE,\n id: undefined,\n retry: undefined,\n data: [],\n };\n\n /**\n * Transform input string chunk into ServerSentEvent object.\n *\n * @param chunk Input string chunk\n * @param controller Controller for controlling the transform stream\n */\n transform(\n chunk: string,\n controller: TransformStreamDefaultController<ServerSentEvent>,\n ) {\n const currentEvent = this.currentEvent;\n try {\n // Skip empty lines (event separator)\n if (chunk.trim() === '') {\n // If there is accumulated event data, send event\n if (currentEvent.data.length > 0) {\n controller.enqueue({\n event: currentEvent.event || DEFAULT_EVENT_TYPE,\n data: currentEvent.data.join('\\n'),\n id: currentEvent.id || '',\n retry: currentEvent.retry,\n } as ServerSentEvent);\n\n // Reset current event (preserve id and retry for subsequent events)\n currentEvent.event = DEFAULT_EVENT_TYPE;\n // Preserve id and retry for subsequent events (no need to reassign to themselves)\n currentEvent.data = [];\n }\n return;\n }\n\n // Ignore comment lines (starting with colon)\n if (chunk.startsWith(':')) {\n return;\n }\n\n // Parse fields\n const colonIndex = chunk.indexOf(':');\n let field: string;\n let value: string;\n\n if (colonIndex === -1) {\n // No colon, entire line as field name, value is empty\n field = chunk.toLowerCase();\n value = '';\n } else {\n // Extract field name and value\n field = chunk.substring(0, colonIndex).toLowerCase();\n value = chunk.substring(colonIndex + 1);\n\n // If value starts with space, remove leading space\n if (value.startsWith(' ')) {\n value = value.substring(1);\n }\n }\n\n // Remove trailing newlines from field and value\n field = field.trim();\n value = value.trim();\n\n processFieldInternal(field, value, currentEvent);\n } catch (error) {\n controller.error(\n error instanceof Error ? error : new Error(String(error)),\n );\n // Reset state\n currentEvent.event = DEFAULT_EVENT_TYPE;\n currentEvent.id = undefined;\n currentEvent.retry = undefined;\n currentEvent.data = [];\n }\n }\n\n /**\n * Called when the stream ends, used to process remaining data.\n *\n * @param controller Controller for controlling the transform stream\n */\n flush(controller: TransformStreamDefaultController<ServerSentEvent>) {\n const currentEvent = this.currentEvent;\n try {\n // Send the last event (if any)\n if (currentEvent.data.length > 0) {\n controller.enqueue({\n event: currentEvent.event || DEFAULT_EVENT_TYPE,\n data: currentEvent.data.join('\\n'),\n id: currentEvent.id || '',\n retry: currentEvent.retry,\n } as ServerSentEvent);\n }\n } catch (error) {\n controller.error(\n error instanceof Error ? error : new Error(String(error)),\n );\n } finally {\n // Reset state\n currentEvent.event = DEFAULT_EVENT_TYPE;\n currentEvent.id = undefined;\n currentEvent.retry = undefined;\n currentEvent.data = [];\n }\n }\n}\n\n/**\n * A TransformStream that converts a stream of strings into a stream of ServerSentEvent objects.\n */\nexport class ServerSentEventTransformStream extends TransformStream<\n string,\n ServerSentEvent\n> {\n constructor() {\n super(new ServerSentEventTransformer());\n }\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { TextLineTransformStream } from './textLineTransformStream';\nimport {\n type ServerSentEvent,\n ServerSentEventTransformStream,\n} from './serverSentEventTransformStream';\nimport { FetcherError } from '@ahoo-wang/fetcher';\n\n/**\n * A ReadableStream of ServerSentEvent objects.\n */\nexport type ServerSentEventStream = ReadableStream<ServerSentEvent>;\n\n/**\n * Custom error class for event stream conversion errors.\n * Thrown when there are issues converting a Response to a ServerSentEventStream.\n */\nexport class EventStreamConvertError extends FetcherError {\n /**\n * Creates a new EventStreamConvertError instance.\n * @param response - The Response object associated with the error\n * @param errorMsg - Optional error message describing what went wrong during conversion\n * @param cause - Optional underlying error that caused this error\n */\n constructor(\n public readonly response: Response,\n errorMsg?: string,\n cause?: Error | any,\n ) {\n super(errorMsg, cause);\n this.name = 'EventStreamConvertError';\n // Restore prototype chain for proper inheritance\n Object.setPrototypeOf(this, EventStreamConvertError.prototype);\n }\n}\n\n/**\n * Converts a Response object to a ServerSentEventStream.\n *\n * Processes the response body through a series of transform streams:\n * 1. TextDecoderStream: Decode Uint8Array data to UTF-8 strings\n * 2. TextLineStream: Split text by lines\n * 3. ServerSentEventStream: Parse line data into server-sent events\n *\n * @param response - The Response object to convert\n * @returns A ReadableStream of ServerSentEvent objects\n * @throws Error if the response body is null\n */\nexport function toServerSentEventStream(\n response: Response,\n): ServerSentEventStream {\n if (!response.body) {\n throw new EventStreamConvertError(response, 'Response body is null');\n }\n\n return response.body\n .pipeThrough(new TextDecoderStream('utf-8'))\n .pipeThrough(new TextLineTransformStream())\n .pipeThrough(new ServerSentEventTransformStream());\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { type ServerSentEvent } from './serverSentEventTransformStream';\nimport { ServerSentEventStream } from './eventStreamConverter';\n\nexport interface JsonServerSentEvent<DATA>\n extends Omit<ServerSentEvent, 'data'> {\n data: DATA;\n}\n\nexport class JsonServerSentEventTransform<DATA>\n implements Transformer<ServerSentEvent, JsonServerSentEvent<DATA>> {\n transform(\n chunk: ServerSentEvent,\n controller: TransformStreamDefaultController<JsonServerSentEvent<DATA>>,\n ) {\n const json = JSON.parse(chunk.data) as DATA;\n controller.enqueue({\n data: json,\n event: chunk.event,\n id: chunk.id,\n retry: chunk.retry,\n });\n }\n}\n\nexport class JsonServerSentEventTransformStream<DATA> extends TransformStream<\n ServerSentEvent,\n JsonServerSentEvent<DATA>\n> {\n constructor() {\n super(new JsonServerSentEventTransform());\n }\n}\n\nexport type JsonServerSentEventStream<DATA> = ReadableStream<\n JsonServerSentEvent<DATA>\n>;\n\nexport function toJsonServerSentEventStream<DATA>(\n serverSentEventStream: ServerSentEventStream,\n): JsonServerSentEventStream<DATA> {\n return serverSentEventStream.pipeThrough(\n new JsonServerSentEventTransformStream<DATA>(),\n );\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { FetchExchange, ResultExtractor } from '@ahoo-wang/fetcher';\nimport { ServerSentEventStream } from './eventStreamConverter';\nimport { JsonServerSentEventStream } from './jsonServerSentEventTransformStream';\n\n/**\n * ServerSentEventStream result extractor, used to extract server-sent event stream from FetchExchange\n *\n * @param exchange - FetchExchange object containing request and response information\n * @returns Readable stream object of server-sent event stream\n * @throws ExchangeError exception when server does not support ServerSentEventStream\n */\nexport const EventStreamResultExtractor: ResultExtractor<\n ServerSentEventStream\n> = (exchange: FetchExchange) => {\n return exchange.requiredResponse.requiredEventStream();\n};\n\n/**\n * JsonServerSentEventStream result extractor, used to extract JSON server-sent event stream from FetchExchange\n *\n * @param exchange - FetchExchange object containing request and response information\n * @returns Readable stream object of JSON server-sent event stream\n * @throws ExchangeError exception when server does not support JsonServerSentEventStream\n */\nexport const JsonEventStreamResultExtractor: ResultExtractor<\n JsonServerSentEventStream<any>\n> = (exchange: FetchExchange) => {\n return exchange.requiredResponse.requiredJsonEventStream();\n};\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n EventStreamConvertError,\n type ServerSentEventStream,\n toServerSentEventStream,\n} from './eventStreamConverter';\nimport {\n type JsonServerSentEventStream,\n toJsonServerSentEventStream,\n} from './jsonServerSentEventTransformStream';\nimport { CONTENT_TYPE_HEADER, ContentTypeValues } from '@ahoo-wang/fetcher';\n\ndeclare global {\n interface Response {\n /**\n * Gets the content type of the response.\n *\n * This property provides access to the Content-Type header of the response,\n * which indicates the media type of the resource transmitted in the response.\n *\n * @returns The content type header value as a string, or null if the header is not set\n */\n get contentType(): string | null;\n\n /**\n * Checks if the response is an event stream.\n *\n * This property examines the Content-Type header to determine if the response\n * contains server-sent events data (text/event-stream).\n *\n * @returns true if the response is an event stream, false otherwise\n */\n get isEventStream(): boolean;\n\n /**\n * Returns a ServerSentEventStream for consuming server-sent events.\n *\n * This method is added to Response objects by the EventStreamInterceptor\n * when the response content type indicates a server-sent event stream.\n *\n * @returns A ReadableStream of ServerSentEvent objects, or null if not an event stream\n */\n eventStream(): ServerSentEventStream | null;\n\n /**\n * Returns a ServerSentEventStream for consuming server-sent events.\n *\n * This method is similar to eventStream() but will throw an error if the event stream is not available.\n * It is added to Response objects by the EventStreamInterceptor when the response content type\n * indicates a server-sent event stream.\n *\n * @returns A ReadableStream of ServerSentEvent objects\n * @throws {Error} if the event stream is not available\n */\n requiredEventStream(): ServerSentEventStream;\n\n /**\n * Returns a JsonServerSentEventStream for consuming server-sent events with JSON data.\n *\n * This method is added to Response objects by the EventStreamInterceptor\n * when the response content type indicates a server-sent event stream.\n *\n * @template DATA - The type of the JSON data in the server-sent events\n * @returns A ReadableStream of ServerSentEvent objects with JSON data, or null if not an event stream\n */\n jsonEventStream<DATA>(): JsonServerSentEventStream<DATA> | null;\n\n /**\n * Returns a JsonServerSentEventStream for consuming server-sent events with JSON data.\n *\n * This method is similar to jsonEventStream() but will throw an error if the event stream is not available.\n * It is added to Response objects by the EventStreamInterceptor when the response content type\n * indicates a server-sent event stream with JSON data.\n *\n * @template DATA - The type of the JSON data in the server-sent events\n * @returns A ReadableStream of ServerSentEvent objects with JSON data\n * @throws {Error} if the event stream is not available\n */\n requiredJsonEventStream<DATA>(): JsonServerSentEventStream<DATA>;\n }\n}\n\nconst CONTENT_TYPE_PROPERTY_NAME = 'contentType';\n/**\n * Defines the contentType property on Response prototype.\n * This property provides a convenient way to access the Content-Type header value.\n */\nif (\n !Object.prototype.hasOwnProperty.call(\n Response.prototype,\n CONTENT_TYPE_PROPERTY_NAME,\n )\n) {\n Object.defineProperty(Response.prototype, CONTENT_TYPE_PROPERTY_NAME, {\n get() {\n return this.headers.get(CONTENT_TYPE_HEADER);\n },\n configurable: true,\n });\n}\n\nconst IS_EVENT_STREAM_PROPERTY_NAME = 'isEventStream';\n/**\n * Defines the isEventStream property on Response prototype.\n * This property checks if the response has a Content-Type header indicating it's an event stream.\n */\nif (\n !Object.prototype.hasOwnProperty.call(\n Response.prototype,\n IS_EVENT_STREAM_PROPERTY_NAME,\n )\n) {\n Object.defineProperty(Response.prototype, IS_EVENT_STREAM_PROPERTY_NAME, {\n get() {\n const contentType = this.contentType;\n if (!contentType) {\n return false;\n }\n return contentType.includes(ContentTypeValues.TEXT_EVENT_STREAM);\n },\n configurable: true,\n });\n}\n\n/**\n * Implementation of the eventStream method for Response objects.\n * Converts a Response with text/event-stream content type to a ServerSentEventStream.\n *\n * @returns A ServerSentEventStream if the response is an event stream, null otherwise\n */\nif (!Object.prototype.hasOwnProperty.call(Response.prototype, 'eventStream')) {\n Response.prototype.eventStream = function() {\n if (!this.isEventStream) {\n return null;\n }\n return toServerSentEventStream(this);\n };\n}\n\n/**\n * Implementation of the requiredEventStream method for Response objects.\n * Converts a Response with text/event-stream content type to a ServerSentEventStream,\n * throwing an error if the response is not an event stream.\n *\n * @returns A ServerSentEventStream if the response is an event stream\n * @throws {Error} if the response is not an event stream\n */\nif (\n !Object.prototype.hasOwnProperty.call(\n Response.prototype,\n 'requiredEventStream',\n )\n) {\n Response.prototype.requiredEventStream = function() {\n const eventStream = this.eventStream();\n if (!eventStream) {\n throw new EventStreamConvertError(\n this,\n `Event stream is not available. Response content-type: [${this.contentType}]`,\n );\n }\n return eventStream;\n };\n}\n\n/**\n * Implementation of the jsonEventStream method for Response objects.\n * Converts a Response with text/event-stream content type to a JsonServerSentEventStream.\n *\n * @template DATA - The type of the JSON data in the server-sent events\n * @returns A JsonServerSentEventStream if the response is an event stream, null otherwise\n */\nif (\n !Object.prototype.hasOwnProperty.call(Response.prototype, 'jsonEventStream')\n) {\n Response.prototype.jsonEventStream = function <DATA>() {\n const eventStream = this.eventStream();\n if (!eventStream) {\n return null;\n }\n return toJsonServerSentEventStream<DATA>(eventStream);\n };\n}\n\n/**\n * Implementation of the requiredJsonEventStream method for Response objects.\n * Converts a Response with text/event-stream content type to a JsonServerSentEventStream,\n * throwing an error if the response is not an event stream.\n *\n * @template DATA - The type of the JSON data in the server-sent events\n * @returns A JsonServerSentEventStream if the response is an event stream\n * @throws {Error} if the response is not an event stream\n */\nif (\n !Object.prototype.hasOwnProperty.call(\n Response.prototype,\n 'requiredJsonEventStream',\n )\n) {\n Response.prototype.requiredJsonEventStream = function <DATA>() {\n const eventStream = this.jsonEventStream<DATA>();\n if (!eventStream) {\n throw new EventStreamConvertError(\n this,\n `Event stream is not available. Response content-type: [${this.contentType}]`,\n );\n }\n return eventStream;\n };\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * A wrapper class that converts a ReadableStream into an AsyncIterable.\n * This allows consuming a ReadableStream using for-await...of loops.\n */\nexport class ReadableStreamAsyncIterable<T> implements AsyncIterable<T> {\n private readonly reader: ReadableStreamDefaultReader<T>;\n private _locked: boolean = true;\n\n /**\n * Creates a new ReadableStreamAsyncIterable instance.\n * @param stream - The ReadableStream to wrap.\n */\n constructor(private readonly stream: ReadableStream<T>) {\n this.reader = stream.getReader();\n }\n\n /**\n * Gets the lock status of the reader.\n * @returns True if the reader is currently locked, false otherwise.\n */\n get locked(): boolean {\n return this._locked;\n }\n\n /**\n * Releases the reader lock if currently locked.\n * This method safely releases the reader lock by catching any potential errors.\n */\n releaseLock() {\n if (!this._locked) return false;\n this._locked = false;\n try {\n this.reader.releaseLock();\n return true;\n } catch (error) {\n console.debug('Failed to release reader lock:', error);\n return false;\n }\n }\n\n /**\n * Implements the AsyncIterable interface by returning this iterator.\n * @returns The async iterator for this instance.\n */\n [Symbol.asyncIterator]() {\n return this;\n }\n\n /**\n * Gets the next value from the stream.\n * Reads the next chunk from the stream and returns it as an IteratorResult.\n * If the stream is done, releases the lock and returns a done result.\n * @returns A promise that resolves to an IteratorResult containing the next value or done status.\n * @throws If an error occurs while reading from the stream.\n */\n async next(): Promise<IteratorResult<T>> {\n try {\n const { done, value } = await this.reader.read();\n if (done) {\n this.releaseLock();\n return { done: true, value: undefined };\n }\n\n return { done: false, value };\n } catch (error) {\n this.releaseLock();\n throw error;\n }\n }\n\n /**\n * Implements the return method of the async iterator.\n * Cancels the stream reader and releases the lock.\n * @returns A promise that resolves to a done IteratorResult.\n */\n async return(): Promise<IteratorResult<T>> {\n try {\n await this.reader.cancel();\n } catch (error) {\n console.debug('Failed to cancel stream reader:', error);\n } finally {\n this.releaseLock();\n }\n return { done: true, value: undefined };\n }\n\n /**\n * Implements the throw method of the async iterator.\n * Releases the lock and returns a done result.\n * @param error - The error to be thrown.\n * @returns A promise that resolves to a done IteratorResult.\n */\n async throw(error: any): Promise<IteratorResult<T>> {\n // Ensure the reader lock is released before throwing\n console.debug('Throwing error:', error);\n this.releaseLock();\n return { done: true, value: undefined };\n }\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ReadableStreamAsyncIterable } from './readableStreamAsyncIterable';\n\ndeclare global {\n interface ReadableStream<R = any> {\n /**\n * Makes ReadableStream async iterable for use with for-await loops.\n *\n * This allows the stream to be consumed using `for await (const chunk of stream)` syntax.\n *\n * @returns An async iterator for the stream\n */\n [Symbol.asyncIterator](): AsyncIterator<R>;\n }\n}\n\n// Check if ReadableStream already has [Symbol.asyncIterator] implemented\nexport const isReadableStreamAsyncIterableSupported =\n typeof ReadableStream.prototype[Symbol.asyncIterator] === 'function';\n\n// Add [Symbol.asyncIterator] to ReadableStream if not already implemented\nif (!isReadableStreamAsyncIterableSupported) {\n ReadableStream.prototype[Symbol.asyncIterator] = function <R = any>() {\n return new ReadableStreamAsyncIterable<R>(this as ReadableStream<R>);\n };\n}\n"],"names":["TextLineTransformer","chunk","controller","lines","line","error","TextLineTransformStream","_ServerSentEventFields","ServerSentEventFields","processFieldInternal","field","value","currentEvent","retryValue","DEFAULT_EVENT_TYPE","ServerSentEventTransformer","colonIndex","ServerSentEventTransformStream","EventStreamConvertError","FetcherError","response","errorMsg","cause","toServerSentEventStream","JsonServerSentEventTransform","json","JsonServerSentEventTransformStream","toJsonServerSentEventStream","serverSentEventStream","EventStreamResultExtractor","exchange","JsonEventStreamResultExtractor","CONTENT_TYPE_PROPERTY_NAME","CONTENT_TYPE_HEADER","IS_EVENT_STREAM_PROPERTY_NAME","contentType","ContentTypeValues","eventStream","ReadableStreamAsyncIterable","stream","done","isReadableStreamAsyncIterableSupported"],"mappings":"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"}
1
+ {"version":3,"file":"index.es.js","sources":["../src/textLineTransformStream.ts","../src/serverSentEventTransformStream.ts","../src/eventStreamConverter.ts","../src/jsonServerSentEventTransformStream.ts","../src/eventStreamResultExtractor.ts","../src/responses.ts","../src/readableStreamAsyncIterable.ts","../src/readableStreams.ts"],"sourcesContent":["/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Transformer that splits text into lines.\n *\n * This transformer accumulates chunks of text and splits them by newline characters,\n * emitting each line as a separate chunk while preserving the remaining buffer\n * for the next chunk.\n */\nexport class TextLineTransformer implements Transformer<string, string> {\n private buffer = '';\n\n /**\n * Transform input string chunk by splitting it into lines.\n *\n * @param chunk Input string chunk\n * @param controller Controller for controlling the transform stream\n */\n transform(\n chunk: string,\n controller: TransformStreamDefaultController<string>,\n ) {\n try {\n this.buffer += chunk;\n const lines = this.buffer.split('\\n');\n this.buffer = lines.pop() || '';\n\n for (const line of lines) {\n controller.enqueue(line);\n }\n } catch (error) {\n controller.error(error);\n }\n }\n\n /**\n * Flush remaining buffer when the stream ends.\n *\n * @param controller Controller for controlling the transform stream\n */\n flush(controller: TransformStreamDefaultController<string>) {\n try {\n // Only send when buffer is not empty, avoid sending meaningless empty lines\n if (this.buffer) {\n controller.enqueue(this.buffer);\n }\n } catch (error) {\n controller.error(error);\n }\n }\n}\n\n/**\n * A TransformStream that splits text into lines.\n */\nexport class TextLineTransformStream extends TransformStream<string, string> {\n constructor() {\n super(new TextLineTransformer());\n }\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Represents a message sent in an event stream.\n *\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format}\n */\nexport interface ServerSentEvent {\n /** The event ID to set the EventSource object's last event ID value. */\n id?: string;\n /** A string identifying the type of event described. */\n event: string;\n /** The event data */\n data: string;\n /** The reconnection interval (in milliseconds) to wait before retrying the connection */\n retry?: number;\n}\n\nexport class ServerSentEventFields {\n static readonly ID = 'id';\n static readonly RETRY = 'retry';\n static readonly EVENT = 'event';\n static readonly DATA = 'data';\n}\n\n/**\n * Process field value\n * @param field Field name\n * @param value Field value\n * @param currentEvent Current event state\n */\nfunction processFieldInternal(\n field: string,\n value: string,\n currentEvent: EventState,\n) {\n switch (field) {\n case ServerSentEventFields.EVENT:\n currentEvent.event = value;\n break;\n case ServerSentEventFields.DATA:\n currentEvent.data.push(value);\n break;\n case ServerSentEventFields.ID:\n currentEvent.id = value;\n break;\n case ServerSentEventFields.RETRY: {\n const retryValue = parseInt(value, 10);\n if (!isNaN(retryValue)) {\n currentEvent.retry = retryValue;\n }\n break;\n }\n default:\n // Ignore unknown fields\n break;\n }\n}\n\ninterface EventState {\n event?: string;\n id?: string;\n retry?: number;\n data: string[];\n}\n\nconst DEFAULT_EVENT_TYPE = 'message';\n\n/**\n * Transformer responsible for converting a string stream into a ServerSentEvent object stream.\n *\n * Implements the Transformer interface for processing data transformation in TransformStream.\n * This transformer handles the parsing of Server-Sent Events (SSE) according to the W3C specification.\n * It processes incoming text chunks and converts them into structured ServerSentEvent objects.\n */\nexport class ServerSentEventTransformer\n implements Transformer<string, ServerSentEvent> {\n // Initialize currentEventState with default values in a closure\n private currentEventState: EventState = {\n event: DEFAULT_EVENT_TYPE,\n id: undefined,\n retry: undefined,\n data: [],\n };\n\n /**\n * Reset the current event state to default values.\n * This method is called after processing each complete event or when an error occurs.\n */\n private resetEventState() {\n this.currentEventState.event = DEFAULT_EVENT_TYPE;\n this.currentEventState.id = undefined;\n this.currentEventState.retry = undefined;\n this.currentEventState.data = [];\n }\n\n /**\n * Transform input string chunk into ServerSentEvent object.\n * This method processes individual chunks of text data, parsing them according to the SSE format.\n * It handles:\n * - Empty lines (used as event separators)\n * - Comment lines (starting with ':')\n * - Field lines (field: value format)\n * - Event completion and emission\n *\n * @param chunk Input string chunk\n * @param controller Controller for controlling the transform stream\n */\n transform(\n chunk: string,\n controller: TransformStreamDefaultController<ServerSentEvent>,\n ) {\n const currentEvent = this.currentEventState;\n try {\n // Skip empty lines (event separator)\n if (chunk.trim() === '') {\n // If there is accumulated event data, send event\n if (currentEvent.data.length > 0) {\n controller.enqueue({\n event: currentEvent.event || DEFAULT_EVENT_TYPE,\n data: currentEvent.data.join('\\n'),\n id: currentEvent.id || '',\n retry: currentEvent.retry,\n } as ServerSentEvent);\n\n // Reset current event (preserve id and retry for subsequent events)\n currentEvent.event = DEFAULT_EVENT_TYPE;\n // Preserve id and retry for subsequent events (no need to reassign to themselves)\n currentEvent.data = [];\n }\n return;\n }\n\n // Ignore comment lines (starting with colon)\n if (chunk.startsWith(':')) {\n return;\n }\n\n // Parse fields\n const colonIndex = chunk.indexOf(':');\n let field: string;\n let value: string;\n\n if (colonIndex === -1) {\n // No colon, entire line as field name, value is empty\n field = chunk.toLowerCase();\n value = '';\n } else {\n // Extract field name and value\n field = chunk.substring(0, colonIndex).toLowerCase();\n value = chunk.substring(colonIndex + 1);\n\n // If value starts with space, remove leading space\n if (value.startsWith(' ')) {\n value = value.substring(1);\n }\n }\n\n // Remove trailing newlines from field and value\n field = field.trim();\n value = value.trim();\n\n processFieldInternal(field, value, currentEvent);\n } catch (error) {\n const enhancedError = new Error(`Failed to process chunk: \"${chunk}\". ${error instanceof Error ? error.message : String(error)}`);\n controller.error(enhancedError);\n // Reset state\n this.resetEventState();\n }\n }\n\n /**\n * Called when the stream ends, used to process remaining data.\n *\n * @param controller Controller for controlling the transform stream\n */\n flush(controller: TransformStreamDefaultController<ServerSentEvent>) {\n const currentEvent = this.currentEventState;\n try {\n // Send the last event (if any)\n if (currentEvent.data.length > 0) {\n controller.enqueue({\n event: currentEvent.event || DEFAULT_EVENT_TYPE,\n data: currentEvent.data.join('\\n'),\n id: currentEvent.id || '',\n retry: currentEvent.retry,\n } as ServerSentEvent);\n }\n } catch (error) {\n const enhancedError = new Error(`Failed to flush remaining data. ${error instanceof Error ? error.message : String(error)}`);\n controller.error(enhancedError);\n } finally {\n // Reset state\n this.resetEventState();\n }\n }\n}\n\n/**\n * A TransformStream that converts a stream of strings into a stream of ServerSentEvent objects.\n */\nexport class ServerSentEventTransformStream extends TransformStream<\n string,\n ServerSentEvent\n> {\n constructor() {\n super(new ServerSentEventTransformer());\n }\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { TextLineTransformStream } from './textLineTransformStream';\nimport {\n type ServerSentEvent,\n ServerSentEventTransformStream,\n} from './serverSentEventTransformStream';\nimport { FetcherError } from '@ahoo-wang/fetcher';\n\n/**\n * A ReadableStream of ServerSentEvent objects.\n */\nexport type ServerSentEventStream = ReadableStream<ServerSentEvent>;\n\n/**\n * Custom error class for event stream conversion errors.\n * Thrown when there are issues converting a Response to a ServerSentEventStream.\n */\nexport class EventStreamConvertError extends FetcherError {\n /**\n * Creates a new EventStreamConvertError instance.\n * @param response - The Response object associated with the error\n * @param errorMsg - Optional error message describing what went wrong during conversion\n * @param cause - Optional underlying error that caused this error\n */\n constructor(\n public readonly response: Response,\n errorMsg?: string,\n cause?: Error | any,\n ) {\n super(errorMsg, cause);\n this.name = 'EventStreamConvertError';\n // Restore prototype chain for proper inheritance\n Object.setPrototypeOf(this, EventStreamConvertError.prototype);\n }\n}\n\n/**\n * Converts a Response object to a ServerSentEventStream.\n *\n * Processes the response body through a series of transform streams:\n * 1. TextDecoderStream: Decode Uint8Array data to UTF-8 strings\n * 2. TextLineStream: Split text by lines\n * 3. ServerSentEventStream: Parse line data into server-sent events\n *\n * @param response - The Response object to convert\n * @returns A ReadableStream of ServerSentEvent objects\n * @throws Error if the response body is null\n */\nexport function toServerSentEventStream(\n response: Response,\n): ServerSentEventStream {\n if (!response.body) {\n throw new EventStreamConvertError(response, 'Response body is null');\n }\n\n return response.body\n .pipeThrough(new TextDecoderStream('utf-8'))\n .pipeThrough(new TextLineTransformStream())\n .pipeThrough(new ServerSentEventTransformStream());\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { type ServerSentEvent } from './serverSentEventTransformStream';\nimport { ServerSentEventStream } from './eventStreamConverter';\n\nexport interface JsonServerSentEvent<DATA>\n extends Omit<ServerSentEvent, 'data'> {\n data: DATA;\n}\n\nexport class JsonServerSentEventTransform<DATA>\n implements Transformer<ServerSentEvent, JsonServerSentEvent<DATA>> {\n transform(\n chunk: ServerSentEvent,\n controller: TransformStreamDefaultController<JsonServerSentEvent<DATA>>,\n ) {\n const json = JSON.parse(chunk.data) as DATA;\n controller.enqueue({\n data: json,\n event: chunk.event,\n id: chunk.id,\n retry: chunk.retry,\n });\n }\n}\n\nexport class JsonServerSentEventTransformStream<DATA> extends TransformStream<\n ServerSentEvent,\n JsonServerSentEvent<DATA>\n> {\n constructor() {\n super(new JsonServerSentEventTransform());\n }\n}\n\nexport type JsonServerSentEventStream<DATA> = ReadableStream<\n JsonServerSentEvent<DATA>\n>;\n\nexport function toJsonServerSentEventStream<DATA>(\n serverSentEventStream: ServerSentEventStream,\n): JsonServerSentEventStream<DATA> {\n return serverSentEventStream.pipeThrough(\n new JsonServerSentEventTransformStream<DATA>(),\n );\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { FetchExchange, ResultExtractor } from '@ahoo-wang/fetcher';\nimport { ServerSentEventStream } from './eventStreamConverter';\nimport { JsonServerSentEventStream } from './jsonServerSentEventTransformStream';\n\n/**\n * ServerSentEventStream result extractor, used to extract server-sent event stream from FetchExchange\n *\n * @param exchange - FetchExchange object containing request and response information\n * @returns Readable stream object of server-sent event stream\n * @throws ExchangeError exception when server does not support ServerSentEventStream\n */\nexport const EventStreamResultExtractor: ResultExtractor<\n ServerSentEventStream\n> = (exchange: FetchExchange) => {\n return exchange.requiredResponse.requiredEventStream();\n};\n\n/**\n * JsonServerSentEventStream result extractor, used to extract JSON server-sent event stream from FetchExchange\n *\n * @param exchange - FetchExchange object containing request and response information\n * @returns Readable stream object of JSON server-sent event stream\n * @throws ExchangeError exception when server does not support JsonServerSentEventStream\n */\nexport const JsonEventStreamResultExtractor: ResultExtractor<\n JsonServerSentEventStream<any>\n> = (exchange: FetchExchange) => {\n return exchange.requiredResponse.requiredJsonEventStream();\n};\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n EventStreamConvertError,\n type ServerSentEventStream,\n toServerSentEventStream,\n} from './eventStreamConverter';\nimport {\n type JsonServerSentEventStream,\n toJsonServerSentEventStream,\n} from './jsonServerSentEventTransformStream';\nimport { CONTENT_TYPE_HEADER, ContentTypeValues } from '@ahoo-wang/fetcher';\n\ndeclare global {\n interface Response {\n /**\n * Gets the content type of the response.\n *\n * This property provides access to the Content-Type header of the response,\n * which indicates the media type of the resource transmitted in the response.\n *\n * @returns The content type header value as a string, or null if the header is not set\n */\n get contentType(): string | null;\n\n /**\n * Checks if the response is an event stream.\n *\n * This property examines the Content-Type header to determine if the response\n * contains server-sent events data (text/event-stream).\n *\n * @returns true if the response is an event stream, false otherwise\n */\n get isEventStream(): boolean;\n\n /**\n * Returns a ServerSentEventStream for consuming server-sent events.\n *\n * This method is added to Response objects by the EventStreamInterceptor\n * when the response content type indicates a server-sent event stream.\n *\n * @returns A ReadableStream of ServerSentEvent objects, or null if not an event stream\n */\n eventStream(): ServerSentEventStream | null;\n\n /**\n * Returns a ServerSentEventStream for consuming server-sent events.\n *\n * This method is similar to eventStream() but will throw an error if the event stream is not available.\n * It is added to Response objects by the EventStreamInterceptor when the response content type\n * indicates a server-sent event stream.\n *\n * @returns A ReadableStream of ServerSentEvent objects\n * @throws {Error} if the event stream is not available\n */\n requiredEventStream(): ServerSentEventStream;\n\n /**\n * Returns a JsonServerSentEventStream for consuming server-sent events with JSON data.\n *\n * This method is added to Response objects by the EventStreamInterceptor\n * when the response content type indicates a server-sent event stream.\n *\n * @template DATA - The type of the JSON data in the server-sent events\n * @returns A ReadableStream of ServerSentEvent objects with JSON data, or null if not an event stream\n */\n jsonEventStream<DATA>(): JsonServerSentEventStream<DATA> | null;\n\n /**\n * Returns a JsonServerSentEventStream for consuming server-sent events with JSON data.\n *\n * This method is similar to jsonEventStream() but will throw an error if the event stream is not available.\n * It is added to Response objects by the EventStreamInterceptor when the response content type\n * indicates a server-sent event stream with JSON data.\n *\n * @template DATA - The type of the JSON data in the server-sent events\n * @returns A ReadableStream of ServerSentEvent objects with JSON data\n * @throws {Error} if the event stream is not available\n */\n requiredJsonEventStream<DATA>(): JsonServerSentEventStream<DATA>;\n }\n}\n\nconst CONTENT_TYPE_PROPERTY_NAME = 'contentType';\n/**\n * Defines the contentType property on Response prototype.\n * This property provides a convenient way to access the Content-Type header value.\n */\nif (\n !Object.prototype.hasOwnProperty.call(\n Response.prototype,\n CONTENT_TYPE_PROPERTY_NAME,\n )\n) {\n Object.defineProperty(Response.prototype, CONTENT_TYPE_PROPERTY_NAME, {\n get() {\n return this.headers.get(CONTENT_TYPE_HEADER);\n },\n configurable: true,\n });\n}\n\nconst IS_EVENT_STREAM_PROPERTY_NAME = 'isEventStream';\n/**\n * Defines the isEventStream property on Response prototype.\n * This property checks if the response has a Content-Type header indicating it's an event stream.\n */\nif (\n !Object.prototype.hasOwnProperty.call(\n Response.prototype,\n IS_EVENT_STREAM_PROPERTY_NAME,\n )\n) {\n Object.defineProperty(Response.prototype, IS_EVENT_STREAM_PROPERTY_NAME, {\n get() {\n const contentType = this.contentType;\n if (!contentType) {\n return false;\n }\n return contentType.includes(ContentTypeValues.TEXT_EVENT_STREAM);\n },\n configurable: true,\n });\n}\n\n/**\n * Implementation of the eventStream method for Response objects.\n * Converts a Response with text/event-stream content type to a ServerSentEventStream.\n *\n * @returns A ServerSentEventStream if the response is an event stream, null otherwise\n */\nif (!Object.prototype.hasOwnProperty.call(Response.prototype, 'eventStream')) {\n Response.prototype.eventStream = function() {\n if (!this.isEventStream) {\n return null;\n }\n return toServerSentEventStream(this);\n };\n}\n\n/**\n * Implementation of the requiredEventStream method for Response objects.\n * Converts a Response with text/event-stream content type to a ServerSentEventStream,\n * throwing an error if the response is not an event stream.\n *\n * @returns A ServerSentEventStream if the response is an event stream\n * @throws {Error} if the response is not an event stream\n */\nif (\n !Object.prototype.hasOwnProperty.call(\n Response.prototype,\n 'requiredEventStream',\n )\n) {\n Response.prototype.requiredEventStream = function() {\n const eventStream = this.eventStream();\n if (!eventStream) {\n throw new EventStreamConvertError(\n this,\n `Event stream is not available. Response content-type: [${this.contentType}]`,\n );\n }\n return eventStream;\n };\n}\n\n/**\n * Implementation of the jsonEventStream method for Response objects.\n * Converts a Response with text/event-stream content type to a JsonServerSentEventStream.\n *\n * @template DATA - The type of the JSON data in the server-sent events\n * @returns A JsonServerSentEventStream if the response is an event stream, null otherwise\n */\nif (\n !Object.prototype.hasOwnProperty.call(Response.prototype, 'jsonEventStream')\n) {\n Response.prototype.jsonEventStream = function <DATA>() {\n const eventStream = this.eventStream();\n if (!eventStream) {\n return null;\n }\n return toJsonServerSentEventStream<DATA>(eventStream);\n };\n}\n\n/**\n * Implementation of the requiredJsonEventStream method for Response objects.\n * Converts a Response with text/event-stream content type to a JsonServerSentEventStream,\n * throwing an error if the response is not an event stream.\n *\n * @template DATA - The type of the JSON data in the server-sent events\n * @returns A JsonServerSentEventStream if the response is an event stream\n * @throws {Error} if the response is not an event stream\n */\nif (\n !Object.prototype.hasOwnProperty.call(\n Response.prototype,\n 'requiredJsonEventStream',\n )\n) {\n Response.prototype.requiredJsonEventStream = function <DATA>() {\n const eventStream = this.jsonEventStream<DATA>();\n if (!eventStream) {\n throw new EventStreamConvertError(\n this,\n `Event stream is not available. Response content-type: [${this.contentType}]`,\n );\n }\n return eventStream;\n };\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * A wrapper class that converts a ReadableStream into an AsyncIterable.\n * This allows consuming a ReadableStream using for-await...of loops.\n */\nexport class ReadableStreamAsyncIterable<T> implements AsyncIterable<T> {\n private readonly reader: ReadableStreamDefaultReader<T>;\n private _locked: boolean = true;\n\n /**\n * Creates a new ReadableStreamAsyncIterable instance.\n * @param stream - The ReadableStream to wrap.\n */\n constructor(private readonly stream: ReadableStream<T>) {\n this.reader = stream.getReader();\n }\n\n /**\n * Gets the lock status of the reader.\n * @returns True if the reader is currently locked, false otherwise.\n */\n get locked(): boolean {\n return this._locked;\n }\n\n /**\n * Releases the reader lock if currently locked.\n * This method safely releases the reader lock by catching any potential errors.\n */\n releaseLock() {\n if (!this._locked) return false;\n this._locked = false;\n try {\n this.reader.releaseLock();\n return true;\n } catch (error) {\n console.debug('Failed to release reader lock:', error);\n return false;\n }\n }\n\n /**\n * Implements the AsyncIterable interface by returning this iterator.\n * @returns The async iterator for this instance.\n */\n [Symbol.asyncIterator]() {\n return this;\n }\n\n /**\n * Gets the next value from the stream.\n * Reads the next chunk from the stream and returns it as an IteratorResult.\n * If the stream is done, releases the lock and returns a done result.\n * @returns A promise that resolves to an IteratorResult containing the next value or done status.\n * @throws If an error occurs while reading from the stream.\n */\n async next(): Promise<IteratorResult<T>> {\n try {\n const { done, value } = await this.reader.read();\n if (done) {\n this.releaseLock();\n return { done: true, value: undefined };\n }\n\n return { done: false, value };\n } catch (error) {\n this.releaseLock();\n throw error;\n }\n }\n\n /**\n * Implements the return method of the async iterator.\n * Cancels the stream reader and releases the lock.\n * @returns A promise that resolves to a done IteratorResult.\n */\n async return(): Promise<IteratorResult<T>> {\n try {\n await this.reader.cancel();\n } catch (error) {\n console.debug('Failed to cancel stream reader:', error);\n } finally {\n this.releaseLock();\n }\n return { done: true, value: undefined };\n }\n\n /**\n * Implements the throw method of the async iterator.\n * Releases the lock and returns a done result.\n * @param error - The error to be thrown.\n * @returns A promise that resolves to a done IteratorResult.\n */\n async throw(error: any): Promise<IteratorResult<T>> {\n // Ensure the reader lock is released before throwing\n console.debug('Throwing error:', error);\n this.releaseLock();\n return { done: true, value: undefined };\n }\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ReadableStreamAsyncIterable } from './readableStreamAsyncIterable';\n\ndeclare global {\n interface ReadableStream<R = any> {\n /**\n * Makes ReadableStream async iterable for use with for-await loops.\n *\n * This allows the stream to be consumed using `for await (const chunk of stream)` syntax.\n *\n * @returns An async iterator for the stream\n */\n [Symbol.asyncIterator](): AsyncIterator<R>;\n }\n}\n\n// Check if ReadableStream already has [Symbol.asyncIterator] implemented\nexport const isReadableStreamAsyncIterableSupported =\n typeof ReadableStream.prototype[Symbol.asyncIterator] === 'function';\n\n// Add [Symbol.asyncIterator] to ReadableStream if not already implemented\nif (!isReadableStreamAsyncIterableSupported) {\n ReadableStream.prototype[Symbol.asyncIterator] = function <R = any>() {\n return new ReadableStreamAsyncIterable<R>(this as ReadableStream<R>);\n };\n}\n"],"names":["TextLineTransformer","chunk","controller","lines","line","error","TextLineTransformStream","_ServerSentEventFields","ServerSentEventFields","processFieldInternal","field","value","currentEvent","retryValue","DEFAULT_EVENT_TYPE","ServerSentEventTransformer","colonIndex","enhancedError","ServerSentEventTransformStream","EventStreamConvertError","FetcherError","response","errorMsg","cause","toServerSentEventStream","JsonServerSentEventTransform","json","JsonServerSentEventTransformStream","toJsonServerSentEventStream","serverSentEventStream","EventStreamResultExtractor","exchange","JsonEventStreamResultExtractor","CONTENT_TYPE_PROPERTY_NAME","CONTENT_TYPE_HEADER","IS_EVENT_STREAM_PROPERTY_NAME","contentType","ContentTypeValues","eventStream","ReadableStreamAsyncIterable","stream","done","isReadableStreamAsyncIterableSupported"],"mappings":"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"}
package/dist/index.umd.js CHANGED
@@ -1,5 +1,5 @@
1
1
  (function(o,i){typeof exports=="object"&&typeof module<"u"?i(exports,require("@ahoo-wang/fetcher")):typeof define=="function"&&define.amd?define(["exports","@ahoo-wang/fetcher"],i):(o=typeof globalThis<"u"?globalThis:o||self,i(o.FetcherEventStream={},o.Fetcher))})(this,(function(o,i){"use strict";class l{constructor(){this.buffer=""}transform(e,r){try{this.buffer+=e;const n=this.buffer.split(`
2
- `);this.buffer=n.pop()||"";for(const s of n)r.enqueue(s)}catch(n){r.error(n)}}flush(e){try{this.buffer&&e.enqueue(this.buffer)}catch(r){e.error(r)}}}class y extends TransformStream{constructor(){super(new l)}}const f=class f{};f.ID="id",f.RETRY="retry",f.EVENT="event",f.DATA="data";let c=f;function O(t,e,r){switch(t){case c.EVENT:r.event=e;break;case c.DATA:r.data.push(e);break;case c.ID:r.id=e;break;case c.RETRY:{const n=parseInt(e,10);isNaN(n)||(r.retry=n);break}}}const u="message";class h{constructor(){this.currentEvent={event:u,id:void 0,retry:void 0,data:[]}}transform(e,r){const n=this.currentEvent;try{if(e.trim()===""){n.data.length>0&&(r.enqueue({event:n.event||u,data:n.data.join(`
3
- `),id:n.id||"",retry:n.retry}),n.event=u,n.data=[]);return}if(e.startsWith(":"))return;const s=e.indexOf(":");let p,a;s===-1?(p=e.toLowerCase(),a=""):(p=e.substring(0,s).toLowerCase(),a=e.substring(s+1),a.startsWith(" ")&&(a=a.substring(1))),p=p.trim(),a=a.trim(),O(p,a,n)}catch(s){r.error(s instanceof Error?s:new Error(String(s))),n.event=u,n.id=void 0,n.retry=void 0,n.data=[]}}flush(e){const r=this.currentEvent;try{r.data.length>0&&e.enqueue({event:r.event||u,data:r.data.join(`
4
- `),id:r.id||"",retry:r.retry})}catch(n){e.error(n instanceof Error?n:new Error(String(n)))}finally{r.event=u,r.id=void 0,r.retry=void 0,r.data=[]}}}class m extends TransformStream{constructor(){super(new h)}}class d extends i.FetcherError{constructor(e,r,n){super(r,n),this.response=e,this.name="EventStreamConvertError",Object.setPrototypeOf(this,d.prototype)}}function S(t){if(!t.body)throw new d(t,"Response body is null");return t.body.pipeThrough(new TextDecoderStream("utf-8")).pipeThrough(new y).pipeThrough(new m)}class v{transform(e,r){const n=JSON.parse(e.data);r.enqueue({data:n,event:e.event,id:e.id,retry:e.retry})}}class E extends TransformStream{constructor(){super(new v)}}function T(t){return t.pipeThrough(new E)}const j=t=>t.requiredResponse.requiredEventStream(),P=t=>t.requiredResponse.requiredJsonEventStream(),b="contentType";Object.prototype.hasOwnProperty.call(Response.prototype,b)||Object.defineProperty(Response.prototype,b,{get(){return this.headers.get(i.CONTENT_TYPE_HEADER)},configurable:!0});const R="isEventStream";Object.prototype.hasOwnProperty.call(Response.prototype,R)||Object.defineProperty(Response.prototype,R,{get(){const t=this.contentType;return t?t.includes(i.ContentTypeValues.TEXT_EVENT_STREAM):!1},configurable:!0}),Object.prototype.hasOwnProperty.call(Response.prototype,"eventStream")||(Response.prototype.eventStream=function(){return this.isEventStream?S(this):null}),Object.prototype.hasOwnProperty.call(Response.prototype,"requiredEventStream")||(Response.prototype.requiredEventStream=function(){const t=this.eventStream();if(!t)throw new d(this,`Event stream is not available. Response content-type: [${this.contentType}]`);return t}),Object.prototype.hasOwnProperty.call(Response.prototype,"jsonEventStream")||(Response.prototype.jsonEventStream=function(){const t=this.eventStream();return t?T(t):null}),Object.prototype.hasOwnProperty.call(Response.prototype,"requiredJsonEventStream")||(Response.prototype.requiredJsonEventStream=function(){const t=this.jsonEventStream();if(!t)throw new d(this,`Event stream is not available. Response content-type: [${this.contentType}]`);return t});class w{constructor(e){this.stream=e,this._locked=!0,this.reader=e.getReader()}get locked(){return this._locked}releaseLock(){if(!this._locked)return!1;this._locked=!1;try{return this.reader.releaseLock(),!0}catch(e){return console.debug("Failed to release reader lock:",e),!1}}[Symbol.asyncIterator](){return this}async next(){try{const{done:e,value:r}=await this.reader.read();return e?(this.releaseLock(),{done:!0,value:void 0}):{done:!1,value:r}}catch(e){throw this.releaseLock(),e}}async return(){try{await this.reader.cancel()}catch(e){console.debug("Failed to cancel stream reader:",e)}finally{this.releaseLock()}return{done:!0,value:void 0}}async throw(e){return console.debug("Throwing error:",e),this.releaseLock(),{done:!0,value:void 0}}}const g=typeof ReadableStream.prototype[Symbol.asyncIterator]=="function";g||(ReadableStream.prototype[Symbol.asyncIterator]=function(){return new w(this)}),o.EventStreamConvertError=d,o.EventStreamResultExtractor=j,o.JsonEventStreamResultExtractor=P,o.JsonServerSentEventTransform=v,o.JsonServerSentEventTransformStream=E,o.ReadableStreamAsyncIterable=w,o.ServerSentEventFields=c,o.ServerSentEventTransformStream=m,o.ServerSentEventTransformer=h,o.TextLineTransformStream=y,o.TextLineTransformer=l,o.isReadableStreamAsyncIterableSupported=g,o.toJsonServerSentEventStream=T,o.toServerSentEventStream=S,Object.defineProperty(o,Symbol.toStringTag,{value:"Module"})}));
2
+ `);this.buffer=n.pop()||"";for(const s of n)r.enqueue(s)}catch(n){r.error(n)}}flush(e){try{this.buffer&&e.enqueue(this.buffer)}catch(r){e.error(r)}}}class h extends TransformStream{constructor(){super(new l)}}const f=class f{};f.ID="id",f.RETRY="retry",f.EVENT="event",f.DATA="data";let c=f;function O(t,e,r){switch(t){case c.EVENT:r.event=e;break;case c.DATA:r.data.push(e);break;case c.ID:r.id=e;break;case c.RETRY:{const n=parseInt(e,10);isNaN(n)||(r.retry=n);break}}}const p="message";class S{constructor(){this.currentEventState={event:p,id:void 0,retry:void 0,data:[]}}resetEventState(){this.currentEventState.event=p,this.currentEventState.id=void 0,this.currentEventState.retry=void 0,this.currentEventState.data=[]}transform(e,r){const n=this.currentEventState;try{if(e.trim()===""){n.data.length>0&&(r.enqueue({event:n.event||p,data:n.data.join(`
3
+ `),id:n.id||"",retry:n.retry}),n.event=p,n.data=[]);return}if(e.startsWith(":"))return;const s=e.indexOf(":");let u,a;s===-1?(u=e.toLowerCase(),a=""):(u=e.substring(0,s).toLowerCase(),a=e.substring(s+1),a.startsWith(" ")&&(a=a.substring(1))),u=u.trim(),a=a.trim(),O(u,a,n)}catch(s){const u=new Error(`Failed to process chunk: "${e}". ${s instanceof Error?s.message:String(s)}`);r.error(u),this.resetEventState()}}flush(e){const r=this.currentEventState;try{r.data.length>0&&e.enqueue({event:r.event||p,data:r.data.join(`
4
+ `),id:r.id||"",retry:r.retry})}catch(n){const s=new Error(`Failed to flush remaining data. ${n instanceof Error?n.message:String(n)}`);e.error(s)}finally{this.resetEventState()}}}class m extends TransformStream{constructor(){super(new S)}}class d extends i.FetcherError{constructor(e,r,n){super(r,n),this.response=e,this.name="EventStreamConvertError",Object.setPrototypeOf(this,d.prototype)}}function y(t){if(!t.body)throw new d(t,"Response body is null");return t.body.pipeThrough(new TextDecoderStream("utf-8")).pipeThrough(new h).pipeThrough(new m)}class v{transform(e,r){const n=JSON.parse(e.data);r.enqueue({data:n,event:e.event,id:e.id,retry:e.retry})}}class E extends TransformStream{constructor(){super(new v)}}function T(t){return t.pipeThrough(new E)}const j=t=>t.requiredResponse.requiredEventStream(),P=t=>t.requiredResponse.requiredJsonEventStream(),b="contentType";Object.prototype.hasOwnProperty.call(Response.prototype,b)||Object.defineProperty(Response.prototype,b,{get(){return this.headers.get(i.CONTENT_TYPE_HEADER)},configurable:!0});const R="isEventStream";Object.prototype.hasOwnProperty.call(Response.prototype,R)||Object.defineProperty(Response.prototype,R,{get(){const t=this.contentType;return t?t.includes(i.ContentTypeValues.TEXT_EVENT_STREAM):!1},configurable:!0}),Object.prototype.hasOwnProperty.call(Response.prototype,"eventStream")||(Response.prototype.eventStream=function(){return this.isEventStream?y(this):null}),Object.prototype.hasOwnProperty.call(Response.prototype,"requiredEventStream")||(Response.prototype.requiredEventStream=function(){const t=this.eventStream();if(!t)throw new d(this,`Event stream is not available. Response content-type: [${this.contentType}]`);return t}),Object.prototype.hasOwnProperty.call(Response.prototype,"jsonEventStream")||(Response.prototype.jsonEventStream=function(){const t=this.eventStream();return t?T(t):null}),Object.prototype.hasOwnProperty.call(Response.prototype,"requiredJsonEventStream")||(Response.prototype.requiredJsonEventStream=function(){const t=this.jsonEventStream();if(!t)throw new d(this,`Event stream is not available. Response content-type: [${this.contentType}]`);return t});class w{constructor(e){this.stream=e,this._locked=!0,this.reader=e.getReader()}get locked(){return this._locked}releaseLock(){if(!this._locked)return!1;this._locked=!1;try{return this.reader.releaseLock(),!0}catch(e){return console.debug("Failed to release reader lock:",e),!1}}[Symbol.asyncIterator](){return this}async next(){try{const{done:e,value:r}=await this.reader.read();return e?(this.releaseLock(),{done:!0,value:void 0}):{done:!1,value:r}}catch(e){throw this.releaseLock(),e}}async return(){try{await this.reader.cancel()}catch(e){console.debug("Failed to cancel stream reader:",e)}finally{this.releaseLock()}return{done:!0,value:void 0}}async throw(e){return console.debug("Throwing error:",e),this.releaseLock(),{done:!0,value:void 0}}}const g=typeof ReadableStream.prototype[Symbol.asyncIterator]=="function";g||(ReadableStream.prototype[Symbol.asyncIterator]=function(){return new w(this)}),o.EventStreamConvertError=d,o.EventStreamResultExtractor=j,o.JsonEventStreamResultExtractor=P,o.JsonServerSentEventTransform=v,o.JsonServerSentEventTransformStream=E,o.ReadableStreamAsyncIterable=w,o.ServerSentEventFields=c,o.ServerSentEventTransformStream=m,o.ServerSentEventTransformer=S,o.TextLineTransformStream=h,o.TextLineTransformer=l,o.isReadableStreamAsyncIterableSupported=g,o.toJsonServerSentEventStream=T,o.toServerSentEventStream=y,Object.defineProperty(o,Symbol.toStringTag,{value:"Module"})}));
5
5
  //# sourceMappingURL=index.umd.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.umd.js","sources":["../src/textLineTransformStream.ts","../src/serverSentEventTransformStream.ts","../src/eventStreamConverter.ts","../src/jsonServerSentEventTransformStream.ts","../src/eventStreamResultExtractor.ts","../src/responses.ts","../src/readableStreamAsyncIterable.ts","../src/readableStreams.ts"],"sourcesContent":["/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Transformer that splits text into lines.\n *\n * This transformer accumulates chunks of text and splits them by newline characters,\n * emitting each line as a separate chunk while preserving the remaining buffer\n * for the next chunk.\n */\nexport class TextLineTransformer implements Transformer<string, string> {\n private buffer = '';\n\n /**\n * Transform input string chunk by splitting it into lines.\n *\n * @param chunk Input string chunk\n * @param controller Controller for controlling the transform stream\n */\n transform(\n chunk: string,\n controller: TransformStreamDefaultController<string>,\n ) {\n try {\n this.buffer += chunk;\n const lines = this.buffer.split('\\n');\n this.buffer = lines.pop() || '';\n\n for (const line of lines) {\n controller.enqueue(line);\n }\n } catch (error) {\n controller.error(error);\n }\n }\n\n /**\n * Flush remaining buffer when the stream ends.\n *\n * @param controller Controller for controlling the transform stream\n */\n flush(controller: TransformStreamDefaultController<string>) {\n try {\n // Only send when buffer is not empty, avoid sending meaningless empty lines\n if (this.buffer) {\n controller.enqueue(this.buffer);\n }\n } catch (error) {\n controller.error(error);\n }\n }\n}\n\n/**\n * A TransformStream that splits text into lines.\n */\nexport class TextLineTransformStream extends TransformStream<string, string> {\n constructor() {\n super(new TextLineTransformer());\n }\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Represents a message sent in an event stream.\n *\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format}\n */\nexport interface ServerSentEvent {\n /** The event ID to set the EventSource object's last event ID value. */\n id?: string;\n /** A string identifying the type of event described. */\n event: string;\n /** The event data */\n data: string;\n /** The reconnection interval (in milliseconds) to wait before retrying the connection */\n retry?: number;\n}\n\nexport class ServerSentEventFields {\n static readonly ID = 'id';\n static readonly RETRY = 'retry';\n static readonly EVENT = 'event';\n static readonly DATA = 'data';\n}\n\n/**\n * Process field value\n * @param field Field name\n * @param value Field value\n * @param currentEvent Current event state\n */\nfunction processFieldInternal(\n field: string,\n value: string,\n currentEvent: EventState,\n) {\n switch (field) {\n case ServerSentEventFields.EVENT:\n currentEvent.event = value;\n break;\n case ServerSentEventFields.DATA:\n currentEvent.data.push(value);\n break;\n case ServerSentEventFields.ID:\n currentEvent.id = value;\n break;\n case ServerSentEventFields.RETRY: {\n const retryValue = parseInt(value, 10);\n if (!isNaN(retryValue)) {\n currentEvent.retry = retryValue;\n }\n break;\n }\n default:\n // Ignore unknown fields\n break;\n }\n}\n\ninterface EventState {\n event?: string;\n id?: string;\n retry?: number;\n data: string[];\n}\n\nconst DEFAULT_EVENT_TYPE = 'message';\n\n/**\n * Transformer responsible for converting a string stream into a ServerSentEvent object stream.\n *\n * Implements the Transformer interface for processing data transformation in TransformStream.\n */\nexport class ServerSentEventTransformer\n implements Transformer<string, ServerSentEvent> {\n // Initialize currentEvent with default values in a closure\n private currentEvent: EventState = {\n event: DEFAULT_EVENT_TYPE,\n id: undefined,\n retry: undefined,\n data: [],\n };\n\n /**\n * Transform input string chunk into ServerSentEvent object.\n *\n * @param chunk Input string chunk\n * @param controller Controller for controlling the transform stream\n */\n transform(\n chunk: string,\n controller: TransformStreamDefaultController<ServerSentEvent>,\n ) {\n const currentEvent = this.currentEvent;\n try {\n // Skip empty lines (event separator)\n if (chunk.trim() === '') {\n // If there is accumulated event data, send event\n if (currentEvent.data.length > 0) {\n controller.enqueue({\n event: currentEvent.event || DEFAULT_EVENT_TYPE,\n data: currentEvent.data.join('\\n'),\n id: currentEvent.id || '',\n retry: currentEvent.retry,\n } as ServerSentEvent);\n\n // Reset current event (preserve id and retry for subsequent events)\n currentEvent.event = DEFAULT_EVENT_TYPE;\n // Preserve id and retry for subsequent events (no need to reassign to themselves)\n currentEvent.data = [];\n }\n return;\n }\n\n // Ignore comment lines (starting with colon)\n if (chunk.startsWith(':')) {\n return;\n }\n\n // Parse fields\n const colonIndex = chunk.indexOf(':');\n let field: string;\n let value: string;\n\n if (colonIndex === -1) {\n // No colon, entire line as field name, value is empty\n field = chunk.toLowerCase();\n value = '';\n } else {\n // Extract field name and value\n field = chunk.substring(0, colonIndex).toLowerCase();\n value = chunk.substring(colonIndex + 1);\n\n // If value starts with space, remove leading space\n if (value.startsWith(' ')) {\n value = value.substring(1);\n }\n }\n\n // Remove trailing newlines from field and value\n field = field.trim();\n value = value.trim();\n\n processFieldInternal(field, value, currentEvent);\n } catch (error) {\n controller.error(\n error instanceof Error ? error : new Error(String(error)),\n );\n // Reset state\n currentEvent.event = DEFAULT_EVENT_TYPE;\n currentEvent.id = undefined;\n currentEvent.retry = undefined;\n currentEvent.data = [];\n }\n }\n\n /**\n * Called when the stream ends, used to process remaining data.\n *\n * @param controller Controller for controlling the transform stream\n */\n flush(controller: TransformStreamDefaultController<ServerSentEvent>) {\n const currentEvent = this.currentEvent;\n try {\n // Send the last event (if any)\n if (currentEvent.data.length > 0) {\n controller.enqueue({\n event: currentEvent.event || DEFAULT_EVENT_TYPE,\n data: currentEvent.data.join('\\n'),\n id: currentEvent.id || '',\n retry: currentEvent.retry,\n } as ServerSentEvent);\n }\n } catch (error) {\n controller.error(\n error instanceof Error ? error : new Error(String(error)),\n );\n } finally {\n // Reset state\n currentEvent.event = DEFAULT_EVENT_TYPE;\n currentEvent.id = undefined;\n currentEvent.retry = undefined;\n currentEvent.data = [];\n }\n }\n}\n\n/**\n * A TransformStream that converts a stream of strings into a stream of ServerSentEvent objects.\n */\nexport class ServerSentEventTransformStream extends TransformStream<\n string,\n ServerSentEvent\n> {\n constructor() {\n super(new ServerSentEventTransformer());\n }\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { TextLineTransformStream } from './textLineTransformStream';\nimport {\n type ServerSentEvent,\n ServerSentEventTransformStream,\n} from './serverSentEventTransformStream';\nimport { FetcherError } from '@ahoo-wang/fetcher';\n\n/**\n * A ReadableStream of ServerSentEvent objects.\n */\nexport type ServerSentEventStream = ReadableStream<ServerSentEvent>;\n\n/**\n * Custom error class for event stream conversion errors.\n * Thrown when there are issues converting a Response to a ServerSentEventStream.\n */\nexport class EventStreamConvertError extends FetcherError {\n /**\n * Creates a new EventStreamConvertError instance.\n * @param response - The Response object associated with the error\n * @param errorMsg - Optional error message describing what went wrong during conversion\n * @param cause - Optional underlying error that caused this error\n */\n constructor(\n public readonly response: Response,\n errorMsg?: string,\n cause?: Error | any,\n ) {\n super(errorMsg, cause);\n this.name = 'EventStreamConvertError';\n // Restore prototype chain for proper inheritance\n Object.setPrototypeOf(this, EventStreamConvertError.prototype);\n }\n}\n\n/**\n * Converts a Response object to a ServerSentEventStream.\n *\n * Processes the response body through a series of transform streams:\n * 1. TextDecoderStream: Decode Uint8Array data to UTF-8 strings\n * 2. TextLineStream: Split text by lines\n * 3. ServerSentEventStream: Parse line data into server-sent events\n *\n * @param response - The Response object to convert\n * @returns A ReadableStream of ServerSentEvent objects\n * @throws Error if the response body is null\n */\nexport function toServerSentEventStream(\n response: Response,\n): ServerSentEventStream {\n if (!response.body) {\n throw new EventStreamConvertError(response, 'Response body is null');\n }\n\n return response.body\n .pipeThrough(new TextDecoderStream('utf-8'))\n .pipeThrough(new TextLineTransformStream())\n .pipeThrough(new ServerSentEventTransformStream());\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { type ServerSentEvent } from './serverSentEventTransformStream';\nimport { ServerSentEventStream } from './eventStreamConverter';\n\nexport interface JsonServerSentEvent<DATA>\n extends Omit<ServerSentEvent, 'data'> {\n data: DATA;\n}\n\nexport class JsonServerSentEventTransform<DATA>\n implements Transformer<ServerSentEvent, JsonServerSentEvent<DATA>> {\n transform(\n chunk: ServerSentEvent,\n controller: TransformStreamDefaultController<JsonServerSentEvent<DATA>>,\n ) {\n const json = JSON.parse(chunk.data) as DATA;\n controller.enqueue({\n data: json,\n event: chunk.event,\n id: chunk.id,\n retry: chunk.retry,\n });\n }\n}\n\nexport class JsonServerSentEventTransformStream<DATA> extends TransformStream<\n ServerSentEvent,\n JsonServerSentEvent<DATA>\n> {\n constructor() {\n super(new JsonServerSentEventTransform());\n }\n}\n\nexport type JsonServerSentEventStream<DATA> = ReadableStream<\n JsonServerSentEvent<DATA>\n>;\n\nexport function toJsonServerSentEventStream<DATA>(\n serverSentEventStream: ServerSentEventStream,\n): JsonServerSentEventStream<DATA> {\n return serverSentEventStream.pipeThrough(\n new JsonServerSentEventTransformStream<DATA>(),\n );\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { FetchExchange, ResultExtractor } from '@ahoo-wang/fetcher';\nimport { ServerSentEventStream } from './eventStreamConverter';\nimport { JsonServerSentEventStream } from './jsonServerSentEventTransformStream';\n\n/**\n * ServerSentEventStream result extractor, used to extract server-sent event stream from FetchExchange\n *\n * @param exchange - FetchExchange object containing request and response information\n * @returns Readable stream object of server-sent event stream\n * @throws ExchangeError exception when server does not support ServerSentEventStream\n */\nexport const EventStreamResultExtractor: ResultExtractor<\n ServerSentEventStream\n> = (exchange: FetchExchange) => {\n return exchange.requiredResponse.requiredEventStream();\n};\n\n/**\n * JsonServerSentEventStream result extractor, used to extract JSON server-sent event stream from FetchExchange\n *\n * @param exchange - FetchExchange object containing request and response information\n * @returns Readable stream object of JSON server-sent event stream\n * @throws ExchangeError exception when server does not support JsonServerSentEventStream\n */\nexport const JsonEventStreamResultExtractor: ResultExtractor<\n JsonServerSentEventStream<any>\n> = (exchange: FetchExchange) => {\n return exchange.requiredResponse.requiredJsonEventStream();\n};\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n EventStreamConvertError,\n type ServerSentEventStream,\n toServerSentEventStream,\n} from './eventStreamConverter';\nimport {\n type JsonServerSentEventStream,\n toJsonServerSentEventStream,\n} from './jsonServerSentEventTransformStream';\nimport { CONTENT_TYPE_HEADER, ContentTypeValues } from '@ahoo-wang/fetcher';\n\ndeclare global {\n interface Response {\n /**\n * Gets the content type of the response.\n *\n * This property provides access to the Content-Type header of the response,\n * which indicates the media type of the resource transmitted in the response.\n *\n * @returns The content type header value as a string, or null if the header is not set\n */\n get contentType(): string | null;\n\n /**\n * Checks if the response is an event stream.\n *\n * This property examines the Content-Type header to determine if the response\n * contains server-sent events data (text/event-stream).\n *\n * @returns true if the response is an event stream, false otherwise\n */\n get isEventStream(): boolean;\n\n /**\n * Returns a ServerSentEventStream for consuming server-sent events.\n *\n * This method is added to Response objects by the EventStreamInterceptor\n * when the response content type indicates a server-sent event stream.\n *\n * @returns A ReadableStream of ServerSentEvent objects, or null if not an event stream\n */\n eventStream(): ServerSentEventStream | null;\n\n /**\n * Returns a ServerSentEventStream for consuming server-sent events.\n *\n * This method is similar to eventStream() but will throw an error if the event stream is not available.\n * It is added to Response objects by the EventStreamInterceptor when the response content type\n * indicates a server-sent event stream.\n *\n * @returns A ReadableStream of ServerSentEvent objects\n * @throws {Error} if the event stream is not available\n */\n requiredEventStream(): ServerSentEventStream;\n\n /**\n * Returns a JsonServerSentEventStream for consuming server-sent events with JSON data.\n *\n * This method is added to Response objects by the EventStreamInterceptor\n * when the response content type indicates a server-sent event stream.\n *\n * @template DATA - The type of the JSON data in the server-sent events\n * @returns A ReadableStream of ServerSentEvent objects with JSON data, or null if not an event stream\n */\n jsonEventStream<DATA>(): JsonServerSentEventStream<DATA> | null;\n\n /**\n * Returns a JsonServerSentEventStream for consuming server-sent events with JSON data.\n *\n * This method is similar to jsonEventStream() but will throw an error if the event stream is not available.\n * It is added to Response objects by the EventStreamInterceptor when the response content type\n * indicates a server-sent event stream with JSON data.\n *\n * @template DATA - The type of the JSON data in the server-sent events\n * @returns A ReadableStream of ServerSentEvent objects with JSON data\n * @throws {Error} if the event stream is not available\n */\n requiredJsonEventStream<DATA>(): JsonServerSentEventStream<DATA>;\n }\n}\n\nconst CONTENT_TYPE_PROPERTY_NAME = 'contentType';\n/**\n * Defines the contentType property on Response prototype.\n * This property provides a convenient way to access the Content-Type header value.\n */\nif (\n !Object.prototype.hasOwnProperty.call(\n Response.prototype,\n CONTENT_TYPE_PROPERTY_NAME,\n )\n) {\n Object.defineProperty(Response.prototype, CONTENT_TYPE_PROPERTY_NAME, {\n get() {\n return this.headers.get(CONTENT_TYPE_HEADER);\n },\n configurable: true,\n });\n}\n\nconst IS_EVENT_STREAM_PROPERTY_NAME = 'isEventStream';\n/**\n * Defines the isEventStream property on Response prototype.\n * This property checks if the response has a Content-Type header indicating it's an event stream.\n */\nif (\n !Object.prototype.hasOwnProperty.call(\n Response.prototype,\n IS_EVENT_STREAM_PROPERTY_NAME,\n )\n) {\n Object.defineProperty(Response.prototype, IS_EVENT_STREAM_PROPERTY_NAME, {\n get() {\n const contentType = this.contentType;\n if (!contentType) {\n return false;\n }\n return contentType.includes(ContentTypeValues.TEXT_EVENT_STREAM);\n },\n configurable: true,\n });\n}\n\n/**\n * Implementation of the eventStream method for Response objects.\n * Converts a Response with text/event-stream content type to a ServerSentEventStream.\n *\n * @returns A ServerSentEventStream if the response is an event stream, null otherwise\n */\nif (!Object.prototype.hasOwnProperty.call(Response.prototype, 'eventStream')) {\n Response.prototype.eventStream = function() {\n if (!this.isEventStream) {\n return null;\n }\n return toServerSentEventStream(this);\n };\n}\n\n/**\n * Implementation of the requiredEventStream method for Response objects.\n * Converts a Response with text/event-stream content type to a ServerSentEventStream,\n * throwing an error if the response is not an event stream.\n *\n * @returns A ServerSentEventStream if the response is an event stream\n * @throws {Error} if the response is not an event stream\n */\nif (\n !Object.prototype.hasOwnProperty.call(\n Response.prototype,\n 'requiredEventStream',\n )\n) {\n Response.prototype.requiredEventStream = function() {\n const eventStream = this.eventStream();\n if (!eventStream) {\n throw new EventStreamConvertError(\n this,\n `Event stream is not available. Response content-type: [${this.contentType}]`,\n );\n }\n return eventStream;\n };\n}\n\n/**\n * Implementation of the jsonEventStream method for Response objects.\n * Converts a Response with text/event-stream content type to a JsonServerSentEventStream.\n *\n * @template DATA - The type of the JSON data in the server-sent events\n * @returns A JsonServerSentEventStream if the response is an event stream, null otherwise\n */\nif (\n !Object.prototype.hasOwnProperty.call(Response.prototype, 'jsonEventStream')\n) {\n Response.prototype.jsonEventStream = function <DATA>() {\n const eventStream = this.eventStream();\n if (!eventStream) {\n return null;\n }\n return toJsonServerSentEventStream<DATA>(eventStream);\n };\n}\n\n/**\n * Implementation of the requiredJsonEventStream method for Response objects.\n * Converts a Response with text/event-stream content type to a JsonServerSentEventStream,\n * throwing an error if the response is not an event stream.\n *\n * @template DATA - The type of the JSON data in the server-sent events\n * @returns A JsonServerSentEventStream if the response is an event stream\n * @throws {Error} if the response is not an event stream\n */\nif (\n !Object.prototype.hasOwnProperty.call(\n Response.prototype,\n 'requiredJsonEventStream',\n )\n) {\n Response.prototype.requiredJsonEventStream = function <DATA>() {\n const eventStream = this.jsonEventStream<DATA>();\n if (!eventStream) {\n throw new EventStreamConvertError(\n this,\n `Event stream is not available. Response content-type: [${this.contentType}]`,\n );\n }\n return eventStream;\n };\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * A wrapper class that converts a ReadableStream into an AsyncIterable.\n * This allows consuming a ReadableStream using for-await...of loops.\n */\nexport class ReadableStreamAsyncIterable<T> implements AsyncIterable<T> {\n private readonly reader: ReadableStreamDefaultReader<T>;\n private _locked: boolean = true;\n\n /**\n * Creates a new ReadableStreamAsyncIterable instance.\n * @param stream - The ReadableStream to wrap.\n */\n constructor(private readonly stream: ReadableStream<T>) {\n this.reader = stream.getReader();\n }\n\n /**\n * Gets the lock status of the reader.\n * @returns True if the reader is currently locked, false otherwise.\n */\n get locked(): boolean {\n return this._locked;\n }\n\n /**\n * Releases the reader lock if currently locked.\n * This method safely releases the reader lock by catching any potential errors.\n */\n releaseLock() {\n if (!this._locked) return false;\n this._locked = false;\n try {\n this.reader.releaseLock();\n return true;\n } catch (error) {\n console.debug('Failed to release reader lock:', error);\n return false;\n }\n }\n\n /**\n * Implements the AsyncIterable interface by returning this iterator.\n * @returns The async iterator for this instance.\n */\n [Symbol.asyncIterator]() {\n return this;\n }\n\n /**\n * Gets the next value from the stream.\n * Reads the next chunk from the stream and returns it as an IteratorResult.\n * If the stream is done, releases the lock and returns a done result.\n * @returns A promise that resolves to an IteratorResult containing the next value or done status.\n * @throws If an error occurs while reading from the stream.\n */\n async next(): Promise<IteratorResult<T>> {\n try {\n const { done, value } = await this.reader.read();\n if (done) {\n this.releaseLock();\n return { done: true, value: undefined };\n }\n\n return { done: false, value };\n } catch (error) {\n this.releaseLock();\n throw error;\n }\n }\n\n /**\n * Implements the return method of the async iterator.\n * Cancels the stream reader and releases the lock.\n * @returns A promise that resolves to a done IteratorResult.\n */\n async return(): Promise<IteratorResult<T>> {\n try {\n await this.reader.cancel();\n } catch (error) {\n console.debug('Failed to cancel stream reader:', error);\n } finally {\n this.releaseLock();\n }\n return { done: true, value: undefined };\n }\n\n /**\n * Implements the throw method of the async iterator.\n * Releases the lock and returns a done result.\n * @param error - The error to be thrown.\n * @returns A promise that resolves to a done IteratorResult.\n */\n async throw(error: any): Promise<IteratorResult<T>> {\n // Ensure the reader lock is released before throwing\n console.debug('Throwing error:', error);\n this.releaseLock();\n return { done: true, value: undefined };\n }\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ReadableStreamAsyncIterable } from './readableStreamAsyncIterable';\n\ndeclare global {\n interface ReadableStream<R = any> {\n /**\n * Makes ReadableStream async iterable for use with for-await loops.\n *\n * This allows the stream to be consumed using `for await (const chunk of stream)` syntax.\n *\n * @returns An async iterator for the stream\n */\n [Symbol.asyncIterator](): AsyncIterator<R>;\n }\n}\n\n// Check if ReadableStream already has [Symbol.asyncIterator] implemented\nexport const isReadableStreamAsyncIterableSupported =\n typeof ReadableStream.prototype[Symbol.asyncIterator] === 'function';\n\n// Add [Symbol.asyncIterator] to ReadableStream if not already implemented\nif (!isReadableStreamAsyncIterableSupported) {\n ReadableStream.prototype[Symbol.asyncIterator] = function <R = any>() {\n return new ReadableStreamAsyncIterable<R>(this as ReadableStream<R>);\n };\n}\n"],"names":["TextLineTransformer","chunk","controller","lines","line","error","TextLineTransformStream","_ServerSentEventFields","ServerSentEventFields","processFieldInternal","field","value","currentEvent","retryValue","DEFAULT_EVENT_TYPE","ServerSentEventTransformer","colonIndex","ServerSentEventTransformStream","EventStreamConvertError","FetcherError","response","errorMsg","cause","toServerSentEventStream","JsonServerSentEventTransform","json","JsonServerSentEventTransformStream","toJsonServerSentEventStream","serverSentEventStream","EventStreamResultExtractor","exchange","JsonEventStreamResultExtractor","CONTENT_TYPE_PROPERTY_NAME","CONTENT_TYPE_HEADER","IS_EVENT_STREAM_PROPERTY_NAME","contentType","ContentTypeValues","eventStream","ReadableStreamAsyncIterable","stream","done","isReadableStreamAsyncIterableSupported"],"mappings":"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"}
1
+ {"version":3,"file":"index.umd.js","sources":["../src/textLineTransformStream.ts","../src/serverSentEventTransformStream.ts","../src/eventStreamConverter.ts","../src/jsonServerSentEventTransformStream.ts","../src/eventStreamResultExtractor.ts","../src/responses.ts","../src/readableStreamAsyncIterable.ts","../src/readableStreams.ts"],"sourcesContent":["/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Transformer that splits text into lines.\n *\n * This transformer accumulates chunks of text and splits them by newline characters,\n * emitting each line as a separate chunk while preserving the remaining buffer\n * for the next chunk.\n */\nexport class TextLineTransformer implements Transformer<string, string> {\n private buffer = '';\n\n /**\n * Transform input string chunk by splitting it into lines.\n *\n * @param chunk Input string chunk\n * @param controller Controller for controlling the transform stream\n */\n transform(\n chunk: string,\n controller: TransformStreamDefaultController<string>,\n ) {\n try {\n this.buffer += chunk;\n const lines = this.buffer.split('\\n');\n this.buffer = lines.pop() || '';\n\n for (const line of lines) {\n controller.enqueue(line);\n }\n } catch (error) {\n controller.error(error);\n }\n }\n\n /**\n * Flush remaining buffer when the stream ends.\n *\n * @param controller Controller for controlling the transform stream\n */\n flush(controller: TransformStreamDefaultController<string>) {\n try {\n // Only send when buffer is not empty, avoid sending meaningless empty lines\n if (this.buffer) {\n controller.enqueue(this.buffer);\n }\n } catch (error) {\n controller.error(error);\n }\n }\n}\n\n/**\n * A TransformStream that splits text into lines.\n */\nexport class TextLineTransformStream extends TransformStream<string, string> {\n constructor() {\n super(new TextLineTransformer());\n }\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Represents a message sent in an event stream.\n *\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format}\n */\nexport interface ServerSentEvent {\n /** The event ID to set the EventSource object's last event ID value. */\n id?: string;\n /** A string identifying the type of event described. */\n event: string;\n /** The event data */\n data: string;\n /** The reconnection interval (in milliseconds) to wait before retrying the connection */\n retry?: number;\n}\n\nexport class ServerSentEventFields {\n static readonly ID = 'id';\n static readonly RETRY = 'retry';\n static readonly EVENT = 'event';\n static readonly DATA = 'data';\n}\n\n/**\n * Process field value\n * @param field Field name\n * @param value Field value\n * @param currentEvent Current event state\n */\nfunction processFieldInternal(\n field: string,\n value: string,\n currentEvent: EventState,\n) {\n switch (field) {\n case ServerSentEventFields.EVENT:\n currentEvent.event = value;\n break;\n case ServerSentEventFields.DATA:\n currentEvent.data.push(value);\n break;\n case ServerSentEventFields.ID:\n currentEvent.id = value;\n break;\n case ServerSentEventFields.RETRY: {\n const retryValue = parseInt(value, 10);\n if (!isNaN(retryValue)) {\n currentEvent.retry = retryValue;\n }\n break;\n }\n default:\n // Ignore unknown fields\n break;\n }\n}\n\ninterface EventState {\n event?: string;\n id?: string;\n retry?: number;\n data: string[];\n}\n\nconst DEFAULT_EVENT_TYPE = 'message';\n\n/**\n * Transformer responsible for converting a string stream into a ServerSentEvent object stream.\n *\n * Implements the Transformer interface for processing data transformation in TransformStream.\n * This transformer handles the parsing of Server-Sent Events (SSE) according to the W3C specification.\n * It processes incoming text chunks and converts them into structured ServerSentEvent objects.\n */\nexport class ServerSentEventTransformer\n implements Transformer<string, ServerSentEvent> {\n // Initialize currentEventState with default values in a closure\n private currentEventState: EventState = {\n event: DEFAULT_EVENT_TYPE,\n id: undefined,\n retry: undefined,\n data: [],\n };\n\n /**\n * Reset the current event state to default values.\n * This method is called after processing each complete event or when an error occurs.\n */\n private resetEventState() {\n this.currentEventState.event = DEFAULT_EVENT_TYPE;\n this.currentEventState.id = undefined;\n this.currentEventState.retry = undefined;\n this.currentEventState.data = [];\n }\n\n /**\n * Transform input string chunk into ServerSentEvent object.\n * This method processes individual chunks of text data, parsing them according to the SSE format.\n * It handles:\n * - Empty lines (used as event separators)\n * - Comment lines (starting with ':')\n * - Field lines (field: value format)\n * - Event completion and emission\n *\n * @param chunk Input string chunk\n * @param controller Controller for controlling the transform stream\n */\n transform(\n chunk: string,\n controller: TransformStreamDefaultController<ServerSentEvent>,\n ) {\n const currentEvent = this.currentEventState;\n try {\n // Skip empty lines (event separator)\n if (chunk.trim() === '') {\n // If there is accumulated event data, send event\n if (currentEvent.data.length > 0) {\n controller.enqueue({\n event: currentEvent.event || DEFAULT_EVENT_TYPE,\n data: currentEvent.data.join('\\n'),\n id: currentEvent.id || '',\n retry: currentEvent.retry,\n } as ServerSentEvent);\n\n // Reset current event (preserve id and retry for subsequent events)\n currentEvent.event = DEFAULT_EVENT_TYPE;\n // Preserve id and retry for subsequent events (no need to reassign to themselves)\n currentEvent.data = [];\n }\n return;\n }\n\n // Ignore comment lines (starting with colon)\n if (chunk.startsWith(':')) {\n return;\n }\n\n // Parse fields\n const colonIndex = chunk.indexOf(':');\n let field: string;\n let value: string;\n\n if (colonIndex === -1) {\n // No colon, entire line as field name, value is empty\n field = chunk.toLowerCase();\n value = '';\n } else {\n // Extract field name and value\n field = chunk.substring(0, colonIndex).toLowerCase();\n value = chunk.substring(colonIndex + 1);\n\n // If value starts with space, remove leading space\n if (value.startsWith(' ')) {\n value = value.substring(1);\n }\n }\n\n // Remove trailing newlines from field and value\n field = field.trim();\n value = value.trim();\n\n processFieldInternal(field, value, currentEvent);\n } catch (error) {\n const enhancedError = new Error(`Failed to process chunk: \"${chunk}\". ${error instanceof Error ? error.message : String(error)}`);\n controller.error(enhancedError);\n // Reset state\n this.resetEventState();\n }\n }\n\n /**\n * Called when the stream ends, used to process remaining data.\n *\n * @param controller Controller for controlling the transform stream\n */\n flush(controller: TransformStreamDefaultController<ServerSentEvent>) {\n const currentEvent = this.currentEventState;\n try {\n // Send the last event (if any)\n if (currentEvent.data.length > 0) {\n controller.enqueue({\n event: currentEvent.event || DEFAULT_EVENT_TYPE,\n data: currentEvent.data.join('\\n'),\n id: currentEvent.id || '',\n retry: currentEvent.retry,\n } as ServerSentEvent);\n }\n } catch (error) {\n const enhancedError = new Error(`Failed to flush remaining data. ${error instanceof Error ? error.message : String(error)}`);\n controller.error(enhancedError);\n } finally {\n // Reset state\n this.resetEventState();\n }\n }\n}\n\n/**\n * A TransformStream that converts a stream of strings into a stream of ServerSentEvent objects.\n */\nexport class ServerSentEventTransformStream extends TransformStream<\n string,\n ServerSentEvent\n> {\n constructor() {\n super(new ServerSentEventTransformer());\n }\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { TextLineTransformStream } from './textLineTransformStream';\nimport {\n type ServerSentEvent,\n ServerSentEventTransformStream,\n} from './serverSentEventTransformStream';\nimport { FetcherError } from '@ahoo-wang/fetcher';\n\n/**\n * A ReadableStream of ServerSentEvent objects.\n */\nexport type ServerSentEventStream = ReadableStream<ServerSentEvent>;\n\n/**\n * Custom error class for event stream conversion errors.\n * Thrown when there are issues converting a Response to a ServerSentEventStream.\n */\nexport class EventStreamConvertError extends FetcherError {\n /**\n * Creates a new EventStreamConvertError instance.\n * @param response - The Response object associated with the error\n * @param errorMsg - Optional error message describing what went wrong during conversion\n * @param cause - Optional underlying error that caused this error\n */\n constructor(\n public readonly response: Response,\n errorMsg?: string,\n cause?: Error | any,\n ) {\n super(errorMsg, cause);\n this.name = 'EventStreamConvertError';\n // Restore prototype chain for proper inheritance\n Object.setPrototypeOf(this, EventStreamConvertError.prototype);\n }\n}\n\n/**\n * Converts a Response object to a ServerSentEventStream.\n *\n * Processes the response body through a series of transform streams:\n * 1. TextDecoderStream: Decode Uint8Array data to UTF-8 strings\n * 2. TextLineStream: Split text by lines\n * 3. ServerSentEventStream: Parse line data into server-sent events\n *\n * @param response - The Response object to convert\n * @returns A ReadableStream of ServerSentEvent objects\n * @throws Error if the response body is null\n */\nexport function toServerSentEventStream(\n response: Response,\n): ServerSentEventStream {\n if (!response.body) {\n throw new EventStreamConvertError(response, 'Response body is null');\n }\n\n return response.body\n .pipeThrough(new TextDecoderStream('utf-8'))\n .pipeThrough(new TextLineTransformStream())\n .pipeThrough(new ServerSentEventTransformStream());\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { type ServerSentEvent } from './serverSentEventTransformStream';\nimport { ServerSentEventStream } from './eventStreamConverter';\n\nexport interface JsonServerSentEvent<DATA>\n extends Omit<ServerSentEvent, 'data'> {\n data: DATA;\n}\n\nexport class JsonServerSentEventTransform<DATA>\n implements Transformer<ServerSentEvent, JsonServerSentEvent<DATA>> {\n transform(\n chunk: ServerSentEvent,\n controller: TransformStreamDefaultController<JsonServerSentEvent<DATA>>,\n ) {\n const json = JSON.parse(chunk.data) as DATA;\n controller.enqueue({\n data: json,\n event: chunk.event,\n id: chunk.id,\n retry: chunk.retry,\n });\n }\n}\n\nexport class JsonServerSentEventTransformStream<DATA> extends TransformStream<\n ServerSentEvent,\n JsonServerSentEvent<DATA>\n> {\n constructor() {\n super(new JsonServerSentEventTransform());\n }\n}\n\nexport type JsonServerSentEventStream<DATA> = ReadableStream<\n JsonServerSentEvent<DATA>\n>;\n\nexport function toJsonServerSentEventStream<DATA>(\n serverSentEventStream: ServerSentEventStream,\n): JsonServerSentEventStream<DATA> {\n return serverSentEventStream.pipeThrough(\n new JsonServerSentEventTransformStream<DATA>(),\n );\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { FetchExchange, ResultExtractor } from '@ahoo-wang/fetcher';\nimport { ServerSentEventStream } from './eventStreamConverter';\nimport { JsonServerSentEventStream } from './jsonServerSentEventTransformStream';\n\n/**\n * ServerSentEventStream result extractor, used to extract server-sent event stream from FetchExchange\n *\n * @param exchange - FetchExchange object containing request and response information\n * @returns Readable stream object of server-sent event stream\n * @throws ExchangeError exception when server does not support ServerSentEventStream\n */\nexport const EventStreamResultExtractor: ResultExtractor<\n ServerSentEventStream\n> = (exchange: FetchExchange) => {\n return exchange.requiredResponse.requiredEventStream();\n};\n\n/**\n * JsonServerSentEventStream result extractor, used to extract JSON server-sent event stream from FetchExchange\n *\n * @param exchange - FetchExchange object containing request and response information\n * @returns Readable stream object of JSON server-sent event stream\n * @throws ExchangeError exception when server does not support JsonServerSentEventStream\n */\nexport const JsonEventStreamResultExtractor: ResultExtractor<\n JsonServerSentEventStream<any>\n> = (exchange: FetchExchange) => {\n return exchange.requiredResponse.requiredJsonEventStream();\n};\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n EventStreamConvertError,\n type ServerSentEventStream,\n toServerSentEventStream,\n} from './eventStreamConverter';\nimport {\n type JsonServerSentEventStream,\n toJsonServerSentEventStream,\n} from './jsonServerSentEventTransformStream';\nimport { CONTENT_TYPE_HEADER, ContentTypeValues } from '@ahoo-wang/fetcher';\n\ndeclare global {\n interface Response {\n /**\n * Gets the content type of the response.\n *\n * This property provides access to the Content-Type header of the response,\n * which indicates the media type of the resource transmitted in the response.\n *\n * @returns The content type header value as a string, or null if the header is not set\n */\n get contentType(): string | null;\n\n /**\n * Checks if the response is an event stream.\n *\n * This property examines the Content-Type header to determine if the response\n * contains server-sent events data (text/event-stream).\n *\n * @returns true if the response is an event stream, false otherwise\n */\n get isEventStream(): boolean;\n\n /**\n * Returns a ServerSentEventStream for consuming server-sent events.\n *\n * This method is added to Response objects by the EventStreamInterceptor\n * when the response content type indicates a server-sent event stream.\n *\n * @returns A ReadableStream of ServerSentEvent objects, or null if not an event stream\n */\n eventStream(): ServerSentEventStream | null;\n\n /**\n * Returns a ServerSentEventStream for consuming server-sent events.\n *\n * This method is similar to eventStream() but will throw an error if the event stream is not available.\n * It is added to Response objects by the EventStreamInterceptor when the response content type\n * indicates a server-sent event stream.\n *\n * @returns A ReadableStream of ServerSentEvent objects\n * @throws {Error} if the event stream is not available\n */\n requiredEventStream(): ServerSentEventStream;\n\n /**\n * Returns a JsonServerSentEventStream for consuming server-sent events with JSON data.\n *\n * This method is added to Response objects by the EventStreamInterceptor\n * when the response content type indicates a server-sent event stream.\n *\n * @template DATA - The type of the JSON data in the server-sent events\n * @returns A ReadableStream of ServerSentEvent objects with JSON data, or null if not an event stream\n */\n jsonEventStream<DATA>(): JsonServerSentEventStream<DATA> | null;\n\n /**\n * Returns a JsonServerSentEventStream for consuming server-sent events with JSON data.\n *\n * This method is similar to jsonEventStream() but will throw an error if the event stream is not available.\n * It is added to Response objects by the EventStreamInterceptor when the response content type\n * indicates a server-sent event stream with JSON data.\n *\n * @template DATA - The type of the JSON data in the server-sent events\n * @returns A ReadableStream of ServerSentEvent objects with JSON data\n * @throws {Error} if the event stream is not available\n */\n requiredJsonEventStream<DATA>(): JsonServerSentEventStream<DATA>;\n }\n}\n\nconst CONTENT_TYPE_PROPERTY_NAME = 'contentType';\n/**\n * Defines the contentType property on Response prototype.\n * This property provides a convenient way to access the Content-Type header value.\n */\nif (\n !Object.prototype.hasOwnProperty.call(\n Response.prototype,\n CONTENT_TYPE_PROPERTY_NAME,\n )\n) {\n Object.defineProperty(Response.prototype, CONTENT_TYPE_PROPERTY_NAME, {\n get() {\n return this.headers.get(CONTENT_TYPE_HEADER);\n },\n configurable: true,\n });\n}\n\nconst IS_EVENT_STREAM_PROPERTY_NAME = 'isEventStream';\n/**\n * Defines the isEventStream property on Response prototype.\n * This property checks if the response has a Content-Type header indicating it's an event stream.\n */\nif (\n !Object.prototype.hasOwnProperty.call(\n Response.prototype,\n IS_EVENT_STREAM_PROPERTY_NAME,\n )\n) {\n Object.defineProperty(Response.prototype, IS_EVENT_STREAM_PROPERTY_NAME, {\n get() {\n const contentType = this.contentType;\n if (!contentType) {\n return false;\n }\n return contentType.includes(ContentTypeValues.TEXT_EVENT_STREAM);\n },\n configurable: true,\n });\n}\n\n/**\n * Implementation of the eventStream method for Response objects.\n * Converts a Response with text/event-stream content type to a ServerSentEventStream.\n *\n * @returns A ServerSentEventStream if the response is an event stream, null otherwise\n */\nif (!Object.prototype.hasOwnProperty.call(Response.prototype, 'eventStream')) {\n Response.prototype.eventStream = function() {\n if (!this.isEventStream) {\n return null;\n }\n return toServerSentEventStream(this);\n };\n}\n\n/**\n * Implementation of the requiredEventStream method for Response objects.\n * Converts a Response with text/event-stream content type to a ServerSentEventStream,\n * throwing an error if the response is not an event stream.\n *\n * @returns A ServerSentEventStream if the response is an event stream\n * @throws {Error} if the response is not an event stream\n */\nif (\n !Object.prototype.hasOwnProperty.call(\n Response.prototype,\n 'requiredEventStream',\n )\n) {\n Response.prototype.requiredEventStream = function() {\n const eventStream = this.eventStream();\n if (!eventStream) {\n throw new EventStreamConvertError(\n this,\n `Event stream is not available. Response content-type: [${this.contentType}]`,\n );\n }\n return eventStream;\n };\n}\n\n/**\n * Implementation of the jsonEventStream method for Response objects.\n * Converts a Response with text/event-stream content type to a JsonServerSentEventStream.\n *\n * @template DATA - The type of the JSON data in the server-sent events\n * @returns A JsonServerSentEventStream if the response is an event stream, null otherwise\n */\nif (\n !Object.prototype.hasOwnProperty.call(Response.prototype, 'jsonEventStream')\n) {\n Response.prototype.jsonEventStream = function <DATA>() {\n const eventStream = this.eventStream();\n if (!eventStream) {\n return null;\n }\n return toJsonServerSentEventStream<DATA>(eventStream);\n };\n}\n\n/**\n * Implementation of the requiredJsonEventStream method for Response objects.\n * Converts a Response with text/event-stream content type to a JsonServerSentEventStream,\n * throwing an error if the response is not an event stream.\n *\n * @template DATA - The type of the JSON data in the server-sent events\n * @returns A JsonServerSentEventStream if the response is an event stream\n * @throws {Error} if the response is not an event stream\n */\nif (\n !Object.prototype.hasOwnProperty.call(\n Response.prototype,\n 'requiredJsonEventStream',\n )\n) {\n Response.prototype.requiredJsonEventStream = function <DATA>() {\n const eventStream = this.jsonEventStream<DATA>();\n if (!eventStream) {\n throw new EventStreamConvertError(\n this,\n `Event stream is not available. Response content-type: [${this.contentType}]`,\n );\n }\n return eventStream;\n };\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * A wrapper class that converts a ReadableStream into an AsyncIterable.\n * This allows consuming a ReadableStream using for-await...of loops.\n */\nexport class ReadableStreamAsyncIterable<T> implements AsyncIterable<T> {\n private readonly reader: ReadableStreamDefaultReader<T>;\n private _locked: boolean = true;\n\n /**\n * Creates a new ReadableStreamAsyncIterable instance.\n * @param stream - The ReadableStream to wrap.\n */\n constructor(private readonly stream: ReadableStream<T>) {\n this.reader = stream.getReader();\n }\n\n /**\n * Gets the lock status of the reader.\n * @returns True if the reader is currently locked, false otherwise.\n */\n get locked(): boolean {\n return this._locked;\n }\n\n /**\n * Releases the reader lock if currently locked.\n * This method safely releases the reader lock by catching any potential errors.\n */\n releaseLock() {\n if (!this._locked) return false;\n this._locked = false;\n try {\n this.reader.releaseLock();\n return true;\n } catch (error) {\n console.debug('Failed to release reader lock:', error);\n return false;\n }\n }\n\n /**\n * Implements the AsyncIterable interface by returning this iterator.\n * @returns The async iterator for this instance.\n */\n [Symbol.asyncIterator]() {\n return this;\n }\n\n /**\n * Gets the next value from the stream.\n * Reads the next chunk from the stream and returns it as an IteratorResult.\n * If the stream is done, releases the lock and returns a done result.\n * @returns A promise that resolves to an IteratorResult containing the next value or done status.\n * @throws If an error occurs while reading from the stream.\n */\n async next(): Promise<IteratorResult<T>> {\n try {\n const { done, value } = await this.reader.read();\n if (done) {\n this.releaseLock();\n return { done: true, value: undefined };\n }\n\n return { done: false, value };\n } catch (error) {\n this.releaseLock();\n throw error;\n }\n }\n\n /**\n * Implements the return method of the async iterator.\n * Cancels the stream reader and releases the lock.\n * @returns A promise that resolves to a done IteratorResult.\n */\n async return(): Promise<IteratorResult<T>> {\n try {\n await this.reader.cancel();\n } catch (error) {\n console.debug('Failed to cancel stream reader:', error);\n } finally {\n this.releaseLock();\n }\n return { done: true, value: undefined };\n }\n\n /**\n * Implements the throw method of the async iterator.\n * Releases the lock and returns a done result.\n * @param error - The error to be thrown.\n * @returns A promise that resolves to a done IteratorResult.\n */\n async throw(error: any): Promise<IteratorResult<T>> {\n // Ensure the reader lock is released before throwing\n console.debug('Throwing error:', error);\n this.releaseLock();\n return { done: true, value: undefined };\n }\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ReadableStreamAsyncIterable } from './readableStreamAsyncIterable';\n\ndeclare global {\n interface ReadableStream<R = any> {\n /**\n * Makes ReadableStream async iterable for use with for-await loops.\n *\n * This allows the stream to be consumed using `for await (const chunk of stream)` syntax.\n *\n * @returns An async iterator for the stream\n */\n [Symbol.asyncIterator](): AsyncIterator<R>;\n }\n}\n\n// Check if ReadableStream already has [Symbol.asyncIterator] implemented\nexport const isReadableStreamAsyncIterableSupported =\n typeof ReadableStream.prototype[Symbol.asyncIterator] === 'function';\n\n// Add [Symbol.asyncIterator] to ReadableStream if not already implemented\nif (!isReadableStreamAsyncIterableSupported) {\n ReadableStream.prototype[Symbol.asyncIterator] = function <R = any>() {\n return new ReadableStreamAsyncIterable<R>(this as ReadableStream<R>);\n };\n}\n"],"names":["TextLineTransformer","chunk","controller","lines","line","error","TextLineTransformStream","_ServerSentEventFields","ServerSentEventFields","processFieldInternal","field","value","currentEvent","retryValue","DEFAULT_EVENT_TYPE","ServerSentEventTransformer","colonIndex","enhancedError","ServerSentEventTransformStream","EventStreamConvertError","FetcherError","response","errorMsg","cause","toServerSentEventStream","JsonServerSentEventTransform","json","JsonServerSentEventTransformStream","toJsonServerSentEventStream","serverSentEventStream","EventStreamResultExtractor","exchange","JsonEventStreamResultExtractor","CONTENT_TYPE_PROPERTY_NAME","CONTENT_TYPE_HEADER","IS_EVENT_STREAM_PROPERTY_NAME","contentType","ContentTypeValues","eventStream","ReadableStreamAsyncIterable","stream","done","isReadableStreamAsyncIterableSupported"],"mappings":"0SAoBO,MAAMA,CAA2D,CAAjE,aAAA,CACL,KAAQ,OAAS,EAAA,CAQjB,UACEC,EACAC,EACA,CACA,GAAI,CACF,KAAK,QAAUD,EACf,MAAME,EAAQ,KAAK,OAAO,MAAM;AAAA,CAAI,EACpC,KAAK,OAASA,EAAM,IAAA,GAAS,GAE7B,UAAWC,KAAQD,EACjBD,EAAW,QAAQE,CAAI,CAE3B,OAASC,EAAO,CACdH,EAAW,MAAMG,CAAK,CACxB,CACF,CAOA,MAAMH,EAAsD,CAC1D,GAAI,CAEE,KAAK,QACPA,EAAW,QAAQ,KAAK,MAAM,CAElC,OAASG,EAAO,CACdH,EAAW,MAAMG,CAAK,CACxB,CACF,CACF,CAKO,MAAMC,UAAgC,eAAgC,CAC3E,aAAc,CACZ,MAAM,IAAIN,CAAqB,CACjC,CACF,CCzCO,MAAMO,EAAN,MAAMA,CAAsB,CAKnC,EAJEA,EAAgB,GAAK,KACrBA,EAAgB,MAAQ,QACxBA,EAAgB,MAAQ,QACxBA,EAAgB,KAAO,OAJlB,IAAMC,EAAND,EAaP,SAASE,EACPC,EACAC,EACAC,EACA,CACA,OAAQF,EAAA,CACN,KAAKF,EAAsB,MACzBI,EAAa,MAAQD,EACrB,MACF,KAAKH,EAAsB,KACzBI,EAAa,KAAK,KAAKD,CAAK,EAC5B,MACF,KAAKH,EAAsB,GACzBI,EAAa,GAAKD,EAClB,MACF,KAAKH,EAAsB,MAAO,CAChC,MAAMK,EAAa,SAASF,EAAO,EAAE,EAChC,MAAME,CAAU,IACnBD,EAAa,MAAQC,GAEvB,KACF,CAGE,CAEN,CASA,MAAMC,EAAqB,UASpB,MAAMC,CACqC,CAD3C,aAAA,CAGL,KAAQ,kBAAgC,CACtC,MAAOD,EACP,GAAI,OACJ,MAAO,OACP,KAAM,CAAA,CAAC,CACT,CAMQ,iBAAkB,CACxB,KAAK,kBAAkB,MAAQA,EAC/B,KAAK,kBAAkB,GAAK,OAC5B,KAAK,kBAAkB,MAAQ,OAC/B,KAAK,kBAAkB,KAAO,CAAA,CAChC,CAcA,UACEb,EACAC,EACA,CACA,MAAMU,EAAe,KAAK,kBAC1B,GAAI,CAEF,GAAIX,EAAM,KAAA,IAAW,GAAI,CAEnBW,EAAa,KAAK,OAAS,IAC7BV,EAAW,QAAQ,CACjB,MAAOU,EAAa,OAASE,EAC7B,KAAMF,EAAa,KAAK,KAAK;AAAA,CAAI,EACjC,GAAIA,EAAa,IAAM,GACvB,MAAOA,EAAa,KAAA,CACF,EAGpBA,EAAa,MAAQE,EAErBF,EAAa,KAAO,CAAA,GAEtB,MACF,CAGA,GAAIX,EAAM,WAAW,GAAG,EACtB,OAIF,MAAMe,EAAaf,EAAM,QAAQ,GAAG,EACpC,IAAIS,EACAC,EAEAK,IAAe,IAEjBN,EAAQT,EAAM,YAAA,EACdU,EAAQ,KAGRD,EAAQT,EAAM,UAAU,EAAGe,CAAU,EAAE,YAAA,EACvCL,EAAQV,EAAM,UAAUe,EAAa,CAAC,EAGlCL,EAAM,WAAW,GAAG,IACtBA,EAAQA,EAAM,UAAU,CAAC,IAK7BD,EAAQA,EAAM,KAAA,EACdC,EAAQA,EAAM,KAAA,EAEdF,EAAqBC,EAAOC,EAAOC,CAAY,CACjD,OAASP,EAAO,CACd,MAAMY,EAAgB,IAAI,MAAM,6BAA6BhB,CAAK,MAAMI,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EAAE,EAChIH,EAAW,MAAMe,CAAa,EAE9B,KAAK,gBAAA,CACP,CACF,CAOA,MAAMf,EAA+D,CACnE,MAAMU,EAAe,KAAK,kBAC1B,GAAI,CAEEA,EAAa,KAAK,OAAS,GAC7BV,EAAW,QAAQ,CACjB,MAAOU,EAAa,OAASE,EAC7B,KAAMF,EAAa,KAAK,KAAK;AAAA,CAAI,EACjC,GAAIA,EAAa,IAAM,GACvB,MAAOA,EAAa,KAAA,CACF,CAExB,OAASP,EAAO,CACd,MAAMY,EAAgB,IAAI,MAAM,mCAAmCZ,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EAAE,EAC3HH,EAAW,MAAMe,CAAa,CAChC,QAAA,CAEE,KAAK,gBAAA,CACP,CACF,CACF,CAKO,MAAMC,UAAuC,eAGlD,CACA,aAAc,CACZ,MAAM,IAAIH,CAA4B,CACxC,CACF,CC9LO,MAAMI,UAAgCC,EAAAA,YAAa,CAOxD,YACkBC,EAChBC,EACAC,EACA,CACA,MAAMD,EAAUC,CAAK,EAJL,KAAA,SAAAF,EAKhB,KAAK,KAAO,0BAEZ,OAAO,eAAe,KAAMF,EAAwB,SAAS,CAC/D,CACF,CAcO,SAASK,EACdH,EACuB,CACvB,GAAI,CAACA,EAAS,KACZ,MAAM,IAAIF,EAAwBE,EAAU,uBAAuB,EAGrE,OAAOA,EAAS,KACb,YAAY,IAAI,kBAAkB,OAAO,CAAC,EAC1C,YAAY,IAAIf,CAAyB,EACzC,YAAY,IAAIY,CAAgC,CACrD,CClDO,MAAMO,CACwD,CACnE,UACExB,EACAC,EACA,CACA,MAAMwB,EAAO,KAAK,MAAMzB,EAAM,IAAI,EAClCC,EAAW,QAAQ,CACjB,KAAMwB,EACN,MAAOzB,EAAM,MACb,GAAIA,EAAM,GACV,MAAOA,EAAM,KAAA,CACd,CACH,CACF,CAEO,MAAM0B,UAAiD,eAG5D,CACA,aAAc,CACZ,MAAM,IAAIF,CAA8B,CAC1C,CACF,CAMO,SAASG,EACdC,EACiC,CACjC,OAAOA,EAAsB,YAC3B,IAAIF,CAAyC,CAEjD,CChCO,MAAMG,EAERC,GACIA,EAAS,iBAAiB,oBAAA,EAUtBC,EAERD,GACIA,EAAS,iBAAiB,wBAAA,ECsD7BE,EAA6B,cAMhC,OAAO,UAAU,eAAe,KAC/B,SAAS,UACTA,CACF,GAEA,OAAO,eAAe,SAAS,UAAWA,EAA4B,CACpE,KAAM,CACJ,OAAO,KAAK,QAAQ,IAAIC,qBAAmB,CAC7C,EACA,aAAc,EAAA,CACf,EAGH,MAAMC,EAAgC,gBAMnC,OAAO,UAAU,eAAe,KAC/B,SAAS,UACTA,CACF,GAEA,OAAO,eAAe,SAAS,UAAWA,EAA+B,CACvE,KAAM,CACJ,MAAMC,EAAc,KAAK,YACzB,OAAKA,EAGEA,EAAY,SAASC,EAAAA,kBAAkB,iBAAiB,EAFtD,EAGX,EACA,aAAc,EAAA,CACf,EASE,OAAO,UAAU,eAAe,KAAK,SAAS,UAAW,aAAa,IACzE,SAAS,UAAU,YAAc,UAAW,CAC1C,OAAK,KAAK,cAGHb,EAAwB,IAAI,EAF1B,IAGX,GAYC,OAAO,UAAU,eAAe,KAC/B,SAAS,UACT,qBACF,IAEA,SAAS,UAAU,oBAAsB,UAAW,CAClD,MAAMc,EAAc,KAAK,YAAA,EACzB,GAAI,CAACA,EACH,MAAM,IAAInB,EACR,KACA,0DAA0D,KAAK,WAAW,GAAA,EAG9E,OAAOmB,CACT,GAWC,OAAO,UAAU,eAAe,KAAK,SAAS,UAAW,iBAAiB,IAE3E,SAAS,UAAU,gBAAkB,UAAkB,CACrD,MAAMA,EAAc,KAAK,YAAA,EACzB,OAAKA,EAGEV,EAAkCU,CAAW,EAF3C,IAGX,GAaC,OAAO,UAAU,eAAe,KAC/B,SAAS,UACT,yBACF,IAEA,SAAS,UAAU,wBAA0B,UAAkB,CAC7D,MAAMA,EAAc,KAAK,gBAAA,EACzB,GAAI,CAACA,EACH,MAAM,IAAInB,EACR,KACA,0DAA0D,KAAK,WAAW,GAAA,EAG9E,OAAOmB,CACT,GC3MK,MAAMC,CAA2D,CAQtE,YAA6BC,EAA2B,CAA3B,KAAA,OAAAA,EAN7B,KAAQ,QAAmB,GAOzB,KAAK,OAASA,EAAO,UAAA,CACvB,CAMA,IAAI,QAAkB,CACpB,OAAO,KAAK,OACd,CAMA,aAAc,CACZ,GAAI,CAAC,KAAK,QAAS,MAAO,GAC1B,KAAK,QAAU,GACf,GAAI,CACF,YAAK,OAAO,YAAA,EACL,EACT,OAASnC,EAAO,CACd,eAAQ,MAAM,iCAAkCA,CAAK,EAC9C,EACT,CACF,CAMA,CAAC,OAAO,aAAa,GAAI,CACvB,OAAO,IACT,CASA,MAAM,MAAmC,CACvC,GAAI,CACF,KAAM,CAAE,KAAAoC,EAAM,MAAA9B,CAAA,EAAU,MAAM,KAAK,OAAO,KAAA,EAC1C,OAAI8B,GACF,KAAK,YAAA,EACE,CAAE,KAAM,GAAM,MAAO,MAAA,GAGvB,CAAE,KAAM,GAAO,MAAA9B,CAAA,CACxB,OAASN,EAAO,CACd,WAAK,YAAA,EACCA,CACR,CACF,CAOA,MAAM,QAAqC,CACzC,GAAI,CACF,MAAM,KAAK,OAAO,OAAA,CACpB,OAASA,EAAO,CACd,QAAQ,MAAM,kCAAmCA,CAAK,CACxD,QAAA,CACE,KAAK,YAAA,CACP,CACA,MAAO,CAAE,KAAM,GAAM,MAAO,MAAA,CAC9B,CAQA,MAAM,MAAMA,EAAwC,CAElD,eAAQ,MAAM,kBAAmBA,CAAK,EACtC,KAAK,YAAA,EACE,CAAE,KAAM,GAAM,MAAO,MAAA,CAC9B,CACF,CClFO,MAAMqC,EACX,OAAO,eAAe,UAAU,OAAO,aAAa,GAAM,WAGvDA,IACH,eAAe,UAAU,OAAO,aAAa,EAAI,UAAqB,CACpE,OAAO,IAAIH,EAA+B,IAAyB,CACrE"}
@@ -23,11 +23,24 @@ export declare class ServerSentEventFields {
23
23
  * Transformer responsible for converting a string stream into a ServerSentEvent object stream.
24
24
  *
25
25
  * Implements the Transformer interface for processing data transformation in TransformStream.
26
+ * This transformer handles the parsing of Server-Sent Events (SSE) according to the W3C specification.
27
+ * It processes incoming text chunks and converts them into structured ServerSentEvent objects.
26
28
  */
27
29
  export declare class ServerSentEventTransformer implements Transformer<string, ServerSentEvent> {
28
- private currentEvent;
30
+ private currentEventState;
31
+ /**
32
+ * Reset the current event state to default values.
33
+ * This method is called after processing each complete event or when an error occurs.
34
+ */
35
+ private resetEventState;
29
36
  /**
30
37
  * Transform input string chunk into ServerSentEvent object.
38
+ * This method processes individual chunks of text data, parsing them according to the SSE format.
39
+ * It handles:
40
+ * - Empty lines (used as event separators)
41
+ * - Comment lines (starting with ':')
42
+ * - Field lines (field: value format)
43
+ * - Event completion and emission
31
44
  *
32
45
  * @param chunk Input string chunk
33
46
  * @param controller Controller for controlling the transform stream
@@ -1 +1 @@
1
- {"version":3,"file":"serverSentEventTransformStream.d.ts","sourceRoot":"","sources":["../src/serverSentEventTransformStream.ts"],"names":[],"mappings":"AAaA;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,wEAAwE;IACxE,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,wDAAwD;IACxD,KAAK,EAAE,MAAM,CAAC;IACd,qBAAqB;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,yFAAyF;IACzF,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,qBAAqB;IAChC,MAAM,CAAC,QAAQ,CAAC,EAAE,QAAQ;IAC1B,MAAM,CAAC,QAAQ,CAAC,KAAK,WAAW;IAChC,MAAM,CAAC,QAAQ,CAAC,KAAK,WAAW;IAChC,MAAM,CAAC,QAAQ,CAAC,IAAI,UAAU;CAC/B;AA6CD;;;;GAIG;AACH,qBAAa,0BACX,YAAW,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC;IAE/C,OAAO,CAAC,YAAY,CAKlB;IAEF;;;;;OAKG;IACH,SAAS,CACP,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,gCAAgC,CAAC,eAAe,CAAC;IAiE/D;;;;OAIG;IACH,KAAK,CAAC,UAAU,EAAE,gCAAgC,CAAC,eAAe,CAAC;CAwBpE;AAED;;GAEG;AACH,qBAAa,8BAA+B,SAAQ,eAAe,CACjE,MAAM,EACN,eAAe,CAChB;;CAIA"}
1
+ {"version":3,"file":"serverSentEventTransformStream.d.ts","sourceRoot":"","sources":["../src/serverSentEventTransformStream.ts"],"names":[],"mappings":"AAaA;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,wEAAwE;IACxE,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,wDAAwD;IACxD,KAAK,EAAE,MAAM,CAAC;IACd,qBAAqB;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,yFAAyF;IACzF,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,qBAAqB;IAChC,MAAM,CAAC,QAAQ,CAAC,EAAE,QAAQ;IAC1B,MAAM,CAAC,QAAQ,CAAC,KAAK,WAAW;IAChC,MAAM,CAAC,QAAQ,CAAC,KAAK,WAAW;IAChC,MAAM,CAAC,QAAQ,CAAC,IAAI,UAAU;CAC/B;AA6CD;;;;;;GAMG;AACH,qBAAa,0BACX,YAAW,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC;IAE/C,OAAO,CAAC,iBAAiB,CAKvB;IAEF;;;OAGG;IACH,OAAO,CAAC,eAAe;IAOvB;;;;;;;;;;;OAWG;IACH,SAAS,CACP,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,gCAAgC,CAAC,eAAe,CAAC;IA6D/D;;;;OAIG;IACH,KAAK,CAAC,UAAU,EAAE,gCAAgC,CAAC,eAAe,CAAC;CAoBpE;AAED;;GAEG;AACH,qBAAa,8BAA+B,SAAQ,eAAe,CACjE,MAAM,EACN,eAAe,CAChB;;CAIA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ahoo-wang/fetcher-eventstream",
3
- "version": "2.9.2",
3
+ "version": "2.9.5",
4
4
  "description": "Server-Sent Events (SSE) support for Fetcher HTTP client with native LLM streaming API support. Enables real-time data streaming and token-by-token LLM response handling.",
5
5
  "keywords": [
6
6
  "fetch",
@@ -49,9 +49,9 @@
49
49
  "globals": "^16.4.0",
50
50
  "prettier": "^3.6.2",
51
51
  "typescript": "^5.9.3",
52
- "typescript-eslint": "^8.46.0",
52
+ "typescript-eslint": "^8.46.1",
53
53
  "unplugin-dts": "1.0.0-beta.6",
54
- "vite": "^7.1.9",
54
+ "vite": "^7.1.10",
55
55
  "vite-bundle-analyzer": "^1.2.3",
56
56
  "vitest": "^3.2.4"
57
57
  },