@ahoo-wang/fetcher-eventstream 1.0.8 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -23,6 +23,7 @@ APIs.
23
23
  - **💬 Comment Handling**: Properly ignores comment lines (lines starting with `:`) as per SSE specification
24
24
  - **🛡️ TypeScript Support**: Complete TypeScript type definitions
25
25
  - **⚡ Performance Optimized**: Efficient parsing and streaming for high-performance applications
26
+ - **🤖 LLM Streaming Ready**: Native support for streaming responses from popular LLM APIs like OpenAI GPT, Claude, etc.
26
27
 
27
28
  ## 🚀 Quick Start
28
29
 
@@ -39,6 +40,26 @@ pnpm add @ahoo-wang/fetcher-eventstream
39
40
  yarn add @ahoo-wang/fetcher-eventstream
40
41
  ```
41
42
 
43
+ ### Module Import
44
+
45
+ To use the event stream functionality, you need to import the module for its side effects:
46
+
47
+ ```typescript
48
+ import '@ahoo-wang/fetcher-eventstream';
49
+ ```
50
+
51
+ This import automatically extends the `Response` interface with methods for handling Server-Sent Events streams:
52
+
53
+ - `eventStream()` - Converts a Response with `text/event-stream` content type to a `ServerSentEventStream`
54
+ - `jsonEventStream<DATA>()` - Converts a Response with `text/event-stream` content type to a
55
+ `JsonServerSentEventStream<DATA>`
56
+ - `isEventStream` getter - Checks if the Response has a `text/event-stream` content type
57
+ - `requiredEventStream()` - Gets a `ServerSentEventStream`, throwing an error if not available
58
+ - `requiredJsonEventStream<DATA>()` - Gets a `JsonServerSentEventStream<DATA>`, throwing an error if not available
59
+
60
+ This is a common pattern in JavaScript/TypeScript for extending existing types with additional functionality without
61
+ modifying the original type definitions.
62
+
42
63
  ### Integration Test Example: LLM Client with Event Stream
43
64
 
44
65
  The following example shows how to create an LLM client with event stream support, similar to the integration test in
@@ -64,10 +85,8 @@ import {
64
85
  post,
65
86
  ResultExtractors,
66
87
  } from '@ahoo-wang/fetcher-decorator';
67
- import {
68
- EventStreamInterceptor,
69
- JsonServerSentEventStream,
70
- } from '@ahoo-wang/fetcher-eventstream';
88
+ import '@ahoo-wang/fetcher-eventstream';
89
+ import { JsonServerSentEventStream } from '@ahoo-wang/fetcher-eventstream';
71
90
  import { ChatRequest, ChatResponse } from './types';
72
91
 
73
92
  export const llmFetcherName = 'llm';
@@ -100,7 +119,6 @@ export function createLlmFetcher(options: LlmOptions): NamedFetcher {
100
119
  },
101
120
  });
102
121
  llmFetcher.interceptors.request.use(new LlmRequestInterceptor(options));
103
- llmFetcher.interceptors.response.use(new EventStreamInterceptor());
104
122
  return llmFetcher;
105
123
  }
106
124
 
@@ -111,14 +129,14 @@ export function createLlmFetcher(options: LlmOptions): NamedFetcher {
111
129
  export class LlmClient {
112
130
  @post('/completions')
113
131
  streamChat(
114
- @body() _body: ChatRequest,
132
+ @body() body: ChatRequest,
115
133
  ): Promise<JsonServerSentEventStream<ChatResponse>> {
116
- throw autoGeneratedError();
134
+ throw autoGeneratedError(body);
117
135
  }
118
136
 
119
137
  @post('/completions', { resultExtractor: ResultExtractors.Json })
120
- chat(@body() _body: ChatRequest): Promise<ChatResponse> {
121
- throw autoGeneratedError();
138
+ chat(@body() body: ChatRequest): Promise<ChatResponse> {
139
+ throw autoGeneratedError(body);
122
140
  }
123
141
  }
124
142
  ```
@@ -203,33 +221,27 @@ try {
203
221
  }
204
222
  ```
205
223
 
206
- ### Basic Usage with Interceptor
224
+ ### Basic Usage
207
225
 
208
226
  ```typescript
209
227
  import { Fetcher } from '@ahoo-wang/fetcher';
210
- import { EventStreamInterceptor } from '@ahoo-wang/fetcher-eventstream';
228
+ import '@ahoo-wang/fetcher-eventstream';
211
229
 
212
230
  const fetcher = new Fetcher({
213
231
  baseURL: 'https://api.example.com',
214
232
  });
215
233
 
216
- // Add the event stream interceptor
217
- fetcher.interceptors.response.use(new EventStreamInterceptor());
218
-
219
- // Using the eventStream method on responses with text/event-stream content type
234
+ // In responses with text/event-stream content type,
235
+ // Response objects will automatically have eventStream() and jsonEventStream() methods
220
236
  const response = await fetcher.get('/events');
221
- if (response.eventStream) {
222
- for await (const event of response.eventStream()) {
223
- console.log('Received event:', event);
224
- }
237
+ for await (const event of response.requiredEventStream()) {
238
+ console.log('Received event:', event);
225
239
  }
226
240
 
227
- // Using the jsonEventStream method for JSON data
241
+ // Using jsonEventStream for JSON data
228
242
  const jsonResponse = await fetcher.get('/json-events');
229
- if (response.jsonEventStream) {
230
- for await (const event of response.jsonEventStream<MyDataType>()) {
231
- console.log('Received JSON event:', event.data);
232
- }
243
+ for await (const event of response.requiredJsonEventStream<MyDataType>()) {
244
+ console.log('Received JSON event:', event.data);
233
245
  }
234
246
  ```
235
247
 
@@ -257,20 +269,48 @@ try {
257
269
 
258
270
  ## 📚 API Reference
259
271
 
260
- ### EventStreamInterceptor
272
+ ### Module Import
273
+
274
+ To use the event stream functionality, you need to import the module for its side effects:
275
+
276
+ ```typescript
277
+ import '@ahoo-wang/fetcher-eventstream';
278
+ ```
279
+
280
+ This import automatically extends the global `Response` interface with methods for handling Server-Sent Events streams:
261
281
 
262
- A response interceptor that automatically adds an `eventStream()` method to responses with `text/event-stream` content
263
- type.
282
+ - `eventStream()` - Converts a Response with `text/event-stream` content type to a `ServerSentEventStream`
283
+ - `jsonEventStream<DATA>()` - Converts a Response with `text/event-stream` content type to a
284
+ `JsonServerSentEventStream<DATA>`
285
+ - `isEventStream` getter - Checks if the Response has a `text/event-stream` content type
286
+ - `requiredEventStream()` - Gets a `ServerSentEventStream`, throwing an error if not available
287
+ - `requiredJsonEventStream<DATA>()` - Gets a `JsonServerSentEventStream<DATA>`, throwing an error if not available
264
288
 
265
- #### Usage
289
+ This is a common pattern in JavaScript/TypeScript for extending existing types with additional functionality without
290
+ modifying the original type definitions.
291
+
292
+ In integration tests and real applications, this import is essential for working with event streams. For example:
266
293
 
267
294
  ```typescript
268
- fetcher.interceptors.response.use(new EventStreamInterceptor());
295
+ import { Fetcher } from '@ahoo-wang/fetcher';
296
+ import '@ahoo-wang/fetcher-eventstream';
297
+
298
+ const fetcher = new Fetcher({
299
+ baseURL: 'https://api.example.com',
300
+ });
301
+
302
+ // Response objects will automatically have eventStream() and jsonEventStream() methods
303
+ const response = await fetcher.get('/events');
304
+ // Handle event stream
305
+ for await (const event of response.requiredEventStream()) {
306
+ console.log('Received event:', event);
307
+ }
269
308
  ```
270
309
 
271
310
  ### toJsonServerSentEventStream
272
311
 
273
- Converts a ServerSentEventStream to a JsonServerSentEventStream for consuming server-sent events with JSON data.
312
+ Converts a `ServerSentEventStream` to a `JsonServerSentEventStream<DATA>` for handling Server-Sent Events with JSON
313
+ data.
274
314
 
275
315
  #### Signature
276
316
 
@@ -282,11 +322,11 @@ function toJsonServerSentEventStream<DATA>(
282
322
 
283
323
  #### Parameters
284
324
 
285
- - `serverSentEventStream`: The ServerSentEventStream to convert
325
+ - `serverSentEventStream`: The `ServerSentEventStream` to convert
286
326
 
287
327
  #### Returns
288
328
 
289
- - `JsonServerSentEventStream<DATA>`: A readable stream of ServerSentEvent objects with JSON data
329
+ - `JsonServerSentEventStream<DATA>`: A readable stream of `JsonServerSentEvent<DATA>` objects
290
330
 
291
331
  ### JsonServerSentEvent
292
332
 
@@ -294,13 +334,13 @@ Interface defining the structure of a Server-Sent Event with JSON data.
294
334
 
295
335
  ```typescript
296
336
  interface JsonServerSentEvent<DATA> extends Omit<ServerSentEvent, 'data'> {
297
- data: DATA; // Event data as parsed JSON
337
+ data: DATA; // The event data parsed as JSON
298
338
  }
299
339
  ```
300
340
 
301
341
  ### JsonServerSentEventStream
302
342
 
303
- Type alias for a readable stream of ServerSentEvent objects with JSON data.
343
+ Type alias for a readable stream of `JsonServerSentEvent<DATA>` objects.
304
344
 
305
345
  ```typescript
306
346
  type JsonServerSentEventStream<DATA> = ReadableStream<
@@ -310,7 +350,7 @@ type JsonServerSentEventStream<DATA> = ReadableStream<
310
350
 
311
351
  ### toServerSentEventStream
312
352
 
313
- Converts a Response object with a `text/event-stream` body to a readable stream of ServerSentEvent objects.
353
+ Converts a `Response` object with a `text/event-stream` body to a `ServerSentEventStream`.
314
354
 
315
355
  #### Signature
316
356
 
@@ -320,11 +360,11 @@ function toServerSentEventStream(response: Response): ServerSentEventStream;
320
360
 
321
361
  #### Parameters
322
362
 
323
- - `response`: The HTTP response with `text/event-stream` content type
363
+ - `response`: An HTTP response with `text/event-stream` content type
324
364
 
325
365
  #### Returns
326
366
 
327
- - `ServerSentEventStream`: A readable stream of ServerSentEvent objects
367
+ - `ServerSentEventStream`: A readable stream of `ServerSentEvent` objects
328
368
 
329
369
  ### ServerSentEvent
330
370
 
@@ -332,16 +372,16 @@ Interface defining the structure of a Server-Sent Event.
332
372
 
333
373
  ```typescript
334
374
  interface ServerSentEvent {
335
- data: string; // Event data (required)
336
- event?: string; // Event type (optional, defaults to 'message')
337
- id?: string; // Event ID (optional)
338
- retry?: number; // Retry timeout in milliseconds (optional)
375
+ data: string; // The event data (required)
376
+ event?: string; // The event type (optional, defaults to 'message')
377
+ id?: string; // The event ID (optional)
378
+ retry?: number; // The reconnection time in milliseconds (optional)
339
379
  }
340
380
  ```
341
381
 
342
382
  ### ServerSentEventStream
343
383
 
344
- Type alias for a readable stream of ServerSentEvent objects.
384
+ Type alias for a readable stream of `ServerSentEvent` objects.
345
385
 
346
386
  ```typescript
347
387
  type ServerSentEventStream = ReadableStream<ServerSentEvent>;
@@ -353,30 +393,27 @@ type ServerSentEventStream = ReadableStream<ServerSentEvent>;
353
393
 
354
394
  ```typescript
355
395
  import { Fetcher } from '@ahoo-wang/fetcher';
356
- import { EventStreamInterceptor } from '@ahoo-wang/fetcher-eventstream';
396
+ import '@ahoo-wang/fetcher-eventstream';
357
397
 
358
398
  const fetcher = new Fetcher({
359
399
  baseURL: 'https://api.example.com',
360
400
  });
361
- fetcher.interceptors.response.use(new EventStreamInterceptor());
362
401
 
363
402
  // Listen for real-time notifications
364
403
  const response = await fetcher.get('/notifications');
365
- if (response.eventStream) {
366
- for await (const event of response.eventStream()) {
367
- switch (event.event) {
368
- case 'message':
369
- showNotification('Message', event.data);
370
- break;
371
- case 'alert':
372
- showAlert('Alert', event.data);
373
- break;
374
- case 'update':
375
- handleUpdate(JSON.parse(event.data));
376
- break;
377
- default:
378
- console.log('Unknown event:', event);
379
- }
404
+ for await (const event of response.requiredEventStream()) {
405
+ switch (event.event) {
406
+ case 'message':
407
+ showNotification('Message', event.data);
408
+ break;
409
+ case 'alert':
410
+ showAlert('Alert', event.data);
411
+ break;
412
+ case 'update':
413
+ handleUpdate(JSON.parse(event.data));
414
+ break;
415
+ default:
416
+ console.log('Unknown event:', event);
380
417
  }
381
418
  }
382
419
  ```
@@ -385,24 +422,20 @@ if (response.eventStream) {
385
422
 
386
423
  ```typescript
387
424
  import { Fetcher } from '@ahoo-wang/fetcher';
388
- import { EventStreamInterceptor } from '@ahoo-wang/fetcher-eventstream';
389
425
 
390
426
  const fetcher = new Fetcher({
391
427
  baseURL: 'https://api.example.com',
392
428
  });
393
- fetcher.interceptors.response.use(new EventStreamInterceptor());
394
429
 
395
430
  // Track long-running task progress
396
431
  const response = await fetcher.get('/tasks/123/progress');
397
- if (response.eventStream) {
398
- for await (const event of response.eventStream()) {
399
- if (event.event === 'progress') {
400
- const progress = JSON.parse(event.data);
401
- updateProgressBar(progress.percentage);
402
- } else if (event.event === 'complete') {
403
- showCompletionMessage(event.data);
404
- break;
405
- }
432
+ for await (const event of response.requiredEventStream()) {
433
+ if (event.event === 'progress') {
434
+ const progress = JSON.parse(event.data);
435
+ updateProgressBar(progress.percentage);
436
+ } else if (event.event === 'complete') {
437
+ showCompletionMessage(event.data);
438
+ break;
406
439
  }
407
440
  }
408
441
  ```
@@ -411,25 +444,21 @@ if (response.eventStream) {
411
444
 
412
445
  ```typescript
413
446
  import { Fetcher } from '@ahoo-wang/fetcher';
414
- import { EventStreamInterceptor } from '@ahoo-wang/fetcher-eventstream';
415
447
 
416
448
  const fetcher = new Fetcher({
417
449
  baseURL: 'https://chat-api.example.com',
418
450
  });
419
- fetcher.interceptors.response.use(new EventStreamInterceptor());
420
451
 
421
452
  // Real-time chat messages
422
453
  const response = await fetcher.get('/rooms/123/messages');
423
- if (response.eventStream) {
424
- for await (const event of response.eventStream()) {
425
- if (event.event === 'message') {
426
- const message = JSON.parse(event.data);
427
- displayMessage(message);
428
- } else if (event.event === 'user-joined') {
429
- showUserJoined(event.data);
430
- } else if (event.event === 'user-left') {
431
- showUserLeft(event.data);
432
- }
454
+ for await (const event of response.requiredEventStream()) {
455
+ if (event.event === 'message') {
456
+ const message = JSON.parse(event.data);
457
+ displayMessage(message);
458
+ } else if (event.event === 'user-joined') {
459
+ showUserJoined(event.data);
460
+ } else if (event.event === 'user-left') {
461
+ showUserLeft(event.data);
433
462
  }
434
463
  }
435
464
  ```
package/README.zh-CN.md CHANGED
@@ -13,12 +13,13 @@
13
13
  ## 🌟 特性
14
14
 
15
15
  - **📡 事件流转换**:将 `text/event-stream` 响应转换为 `ServerSentEvent` 对象的异步生成器
16
- - **🔌 拦截器集成**:自动为 `text/event-stream` 内容类型的响应添加 `eventStream()` 和 `jsonEventStream()` 方法
16
+ - **🔌 自动扩展**:模块导入时自动扩展 `Response` 原型,添加事件流方法
17
17
  - **📋 SSE 解析**:根据规范解析服务器发送事件,包括数据、事件、ID 和重试字段
18
18
  - **🔄 流支持**:正确处理分块数据和多行事件
19
19
  - **💬 注释处理**:正确忽略注释行(以 `:` 开头的行)
20
20
  - **🛡️ TypeScript 支持**:完整的 TypeScript 类型定义
21
21
  - **⚡ 性能优化**:高效的解析和流处理,适用于高性能应用
22
+ - **🤖 LLM 流准备就绪**: 原生支持来自流行 LLM API(如 OpenAI GPT、Claude 等)的流式响应
22
23
 
23
24
  ## 🚀 快速开始
24
25
 
@@ -35,6 +36,24 @@ pnpm add @ahoo-wang/fetcher-eventstream
35
36
  yarn add @ahoo-wang/fetcher-eventstream
36
37
  ```
37
38
 
39
+ ### 模块导入
40
+
41
+ 要使用事件流功能,您需要导入模块以执行其副作用:
42
+
43
+ ```typescript
44
+ import '@ahoo-wang/fetcher-eventstream';
45
+ ```
46
+
47
+ 此导入会自动扩展 `Response` 接口以处理服务器发送事件流:
48
+
49
+ - `eventStream()` - 将带有 `text/event-stream` 内容类型的响应转换为 `ServerSentEventStream`
50
+ - `jsonEventStream<DATA>()` - 将带有 `text/event-stream` 内容类型的响应转换为 `JsonServerSentEventStream<DATA>`
51
+ - `isEventStream` getter - 检查响应是否具有 `text/event-stream` 内容类型
52
+ - `requiredEventStream()` - 获取 `ServerSentEventStream`,如果不可用则抛出错误
53
+ - `requiredJsonEventStream<DATA>()` - 获取 `JsonServerSentEventStream<DATA>`,如果不可用则抛出错误
54
+
55
+ 这是 JavaScript/TypeScript 中常见的模式,用于在不修改原始类型定义的情况下扩展现有类型的功能。
56
+
38
57
  ### 集成测试示例:带事件流的 LLM 客户端
39
58
 
40
59
  以下示例展示了如何创建带事件流支持的 LLM 客户端,类似于 Fetcher
@@ -59,10 +78,8 @@ import {
59
78
  post,
60
79
  ResultExtractors,
61
80
  } from '@ahoo-wang/fetcher-decorator';
62
- import {
63
- EventStreamInterceptor,
64
- JsonServerSentEventStream,
65
- } from '@ahoo-wang/fetcher-eventstream';
81
+ import '@ahoo-wang/fetcher-eventstream';
82
+ import { JsonServerSentEventStream } from '@ahoo-wang/fetcher-eventstream';
66
83
  import { ChatRequest, ChatResponse } from './types';
67
84
 
68
85
  export const llmFetcherName = 'llm';
@@ -95,7 +112,6 @@ export function createLlmFetcher(options: LlmOptions): NamedFetcher {
95
112
  },
96
113
  });
97
114
  llmFetcher.interceptors.request.use(new LlmRequestInterceptor(options));
98
- llmFetcher.interceptors.response.use(new EventStreamInterceptor());
99
115
  return llmFetcher;
100
116
  }
101
117
 
@@ -106,14 +122,14 @@ export function createLlmFetcher(options: LlmOptions): NamedFetcher {
106
122
  export class LlmClient {
107
123
  @post('/completions')
108
124
  streamChat(
109
- @body() _body: ChatRequest,
125
+ @body() body: ChatRequest,
110
126
  ): Promise<JsonServerSentEventStream<ChatResponse>> {
111
- throw autoGeneratedError();
127
+ throw autoGeneratedError(body);
112
128
  }
113
129
 
114
130
  @post('/completions', { resultExtractor: ResultExtractors.Json })
115
- chat(@body() _body: ChatRequest): Promise<ChatResponse> {
116
- throw autoGeneratedError();
131
+ chat(@body() body: ChatRequest): Promise<ChatResponse> {
132
+ throw autoGeneratedError(body);
117
133
  }
118
134
  }
119
135
  ```
@@ -176,33 +192,27 @@ function updateUI(content: string) {
176
192
  }
177
193
  ```
178
194
 
179
- ### 带拦截器的基本用法
195
+ ### 基本用法
180
196
 
181
197
  ```typescript
182
198
  import { Fetcher } from '@ahoo-wang/fetcher';
183
- import { EventStreamInterceptor } from '@ahoo-wang/fetcher-eventstream';
199
+ import '@ahoo-wang/fetcher-eventstream';
184
200
 
185
201
  const fetcher = new Fetcher({
186
202
  baseURL: 'https://api.example.com',
187
203
  });
188
204
 
189
- // 添加事件流拦截器
190
- fetcher.interceptors.response.use(new EventStreamInterceptor());
191
-
192
205
  // 在响应中使用 eventStream 方法处理 text/event-stream 内容类型
206
+ // Response 对象将自动具有 eventStream() 和 jsonEventStream() 方法
193
207
  const response = await fetcher.get('/events');
194
- if (response.eventStream) {
195
- for await (const event of response.eventStream()) {
196
- console.log('收到事件:', event);
197
- }
208
+ for await (const event of response.requiredEventStream()) {
209
+ console.log('收到事件:', event);
198
210
  }
199
211
 
200
212
  // 使用 jsonEventStream 方法处理 JSON 数据
201
213
  const jsonResponse = await fetcher.get('/json-events');
202
- if (response.jsonEventStream) {
203
- for await (const event of response.jsonEventStream<MyDataType>()) {
204
- console.log('收到 JSON 事件:', event.data);
205
- }
214
+ for await (const event of response.requiredJsonEventStream<MyDataType>()) {
215
+ console.log('收到 JSON 事件:', event.data);
206
216
  }
207
217
  ```
208
218
 
@@ -230,19 +240,45 @@ try {
230
240
 
231
241
  ## 📚 API 参考
232
242
 
233
- ### EventStreamInterceptor
243
+ ### 模块导入
244
+
245
+ 要使用事件流功能,您需要导入模块以执行其副作用:
246
+
247
+ ```typescript
248
+ import '@ahoo-wang/fetcher-eventstream';
249
+ ```
250
+
251
+ 此导入会自动扩展全局 `Response` 接口以处理服务器发送事件流:
234
252
 
235
- 响应拦截器,自动为 `text/event-stream` 内容类型的响应添加 `eventStream()` 方法。
253
+ - `eventStream()` - 将带有 `text/event-stream` 内容类型的响应转换为 `ServerSentEventStream`
254
+ - `jsonEventStream<DATA>()` - 将带有 `text/event-stream` 内容类型的响应转换为 `JsonServerSentEventStream<DATA>`
255
+ - `isEventStream` getter - 检查响应是否具有 `text/event-stream` 内容类型
256
+ - `requiredEventStream()` - 获取 `ServerSentEventStream`,如果不可用则抛出错误
257
+ - `requiredJsonEventStream<DATA>()` - 获取 `JsonServerSentEventStream<DATA>`,如果不可用则抛出错误
236
258
 
237
- #### 用法
259
+ 这是 JavaScript/TypeScript 中常见的模式,用于在不修改原始类型定义的情况下扩展现有类型的功能。
260
+
261
+ 在集成测试和实际应用中,此导入对于处理事件流至关重要。例如:
238
262
 
239
263
  ```typescript
240
- fetcher.interceptors.response.use(new EventStreamInterceptor());
264
+ import { Fetcher } from '@ahoo-wang/fetcher';
265
+ import '@ahoo-wang/fetcher-eventstream';
266
+
267
+ const fetcher = new Fetcher({
268
+ baseURL: 'https://api.example.com',
269
+ });
270
+
271
+ // Response 对象将自动具有 eventStream() 和 jsonEventStream() 方法
272
+ const response = await fetcher.get('/events');
273
+ // 处理事件流
274
+ for await (const event of response.requiredEventStream()) {
275
+ console.log('收到事件:', event);
276
+ }
241
277
  ```
242
278
 
243
279
  ### toJsonServerSentEventStream
244
280
 
245
- 将 ServerSentEventStream 转换为 JsonServerSentEventStream,用于处理带有 JSON 数据的服务器发送事件。
281
+ `ServerSentEventStream` 转换为 `JsonServerSentEventStream<DATA>`,用于处理带有 JSON 数据的服务器发送事件。
246
282
 
247
283
  #### 签名
248
284
 
@@ -325,30 +361,27 @@ type ServerSentEventStream = ReadableStream<ServerSentEvent>;
325
361
 
326
362
  ```typescript
327
363
  import { Fetcher } from '@ahoo-wang/fetcher';
328
- import { EventStreamInterceptor } from '@ahoo-wang/fetcher-eventstream';
364
+ import '@ahoo-wang/fetcher-eventstream';
329
365
 
330
366
  const fetcher = new Fetcher({
331
367
  baseURL: 'https://api.example.com',
332
368
  });
333
- fetcher.interceptors.response.use(new EventStreamInterceptor());
334
369
 
335
370
  // 监听实时通知
336
371
  const response = await fetcher.get('/notifications');
337
- if (response.eventStream) {
338
- for await (const event of response.eventStream()) {
339
- switch (event.event) {
340
- case 'message':
341
- showNotification('消息', event.data);
342
- break;
343
- case 'alert':
344
- showAlert('警报', event.data);
345
- break;
346
- case 'update':
347
- handleUpdate(JSON.parse(event.data));
348
- break;
349
- default:
350
- console.log('未知事件:', event);
351
- }
372
+ for await (const event of response.requiredEventStream()) {
373
+ switch (event.event) {
374
+ case 'message':
375
+ showNotification('消息', event.data);
376
+ break;
377
+ case 'alert':
378
+ showAlert('警报', event.data);
379
+ break;
380
+ case 'update':
381
+ handleUpdate(JSON.parse(event.data));
382
+ break;
383
+ default:
384
+ console.log('未知事件:', event);
352
385
  }
353
386
  }
354
387
  ```
@@ -357,24 +390,20 @@ if (response.eventStream) {
357
390
 
358
391
  ```typescript
359
392
  import { Fetcher } from '@ahoo-wang/fetcher';
360
- import { EventStreamInterceptor } from '@ahoo-wang/fetcher-eventstream';
361
393
 
362
394
  const fetcher = new Fetcher({
363
395
  baseURL: 'https://api.example.com',
364
396
  });
365
- fetcher.interceptors.response.use(new EventStreamInterceptor());
366
397
 
367
398
  // 跟踪长时间运行的任务进度
368
399
  const response = await fetcher.get('/tasks/123/progress');
369
- if (response.eventStream) {
370
- for await (const event of response.eventStream()) {
371
- if (event.event === 'progress') {
372
- const progress = JSON.parse(event.data);
373
- updateProgressBar(progress.percentage);
374
- } else if (event.event === 'complete') {
375
- showCompletionMessage(event.data);
376
- break;
377
- }
400
+ for await (const event of response.requiredEventStream()) {
401
+ if (event.event === 'progress') {
402
+ const progress = JSON.parse(event.data);
403
+ updateProgressBar(progress.percentage);
404
+ } else if (event.event === 'complete') {
405
+ showCompletionMessage(event.data);
406
+ break;
378
407
  }
379
408
  }
380
409
  ```
@@ -383,25 +412,21 @@ if (response.eventStream) {
383
412
 
384
413
  ```typescript
385
414
  import { Fetcher } from '@ahoo-wang/fetcher';
386
- import { EventStreamInterceptor } from '@ahoo-wang/fetcher-eventstream';
387
415
 
388
416
  const fetcher = new Fetcher({
389
417
  baseURL: 'https://chat-api.example.com',
390
418
  });
391
- fetcher.interceptors.response.use(new EventStreamInterceptor());
392
419
 
393
420
  // 实时聊天消息
394
421
  const response = await fetcher.get('/rooms/123/messages');
395
- if (response.eventStream) {
396
- for await (const event of response.eventStream()) {
397
- if (event.event === 'message') {
398
- const message = JSON.parse(event.data);
399
- displayMessage(message);
400
- } else if (event.event === 'user-joined') {
401
- showUserJoined(event.data);
402
- } else if (event.event === 'user-left') {
403
- showUserLeft(event.data);
404
- }
422
+ for await (const event of response.requiredEventStream()) {
423
+ if (event.event === 'message') {
424
+ const message = JSON.parse(event.data);
425
+ displayMessage(message);
426
+ } else if (event.event === 'user-joined') {
427
+ showUserJoined(event.data);
428
+ } else if (event.event === 'user-left') {
429
+ showUserLeft(event.data);
405
430
  }
406
431
  }
407
432
  ```
@@ -413,17 +438,16 @@ if (response.eventStream) {
413
438
  pnpm test
414
439
 
415
440
  # 运行带覆盖率的测试
416
- pnpm test --coverage
441
+ pnpm test -- --coverage
417
442
  ```
418
443
 
419
444
  测试套件包括:
420
445
 
421
446
  - 事件流转换测试
422
- - 拦截器功能测试
423
- - 边界情况处理(畸形事件、分块数据等)
447
+ - 边缘情况处理(格式错误的事件、分块数据等)
424
448
  - 大事件流的性能测试
425
449
 
426
- ## 📋 服务器发送事件规范合规性
450
+ ## 📋 服务器发送事件规范兼容性
427
451
 
428
452
  此包完全实现了 [服务器发送事件规范](https://html.spec.whatwg.org/multipage/server-sent-events.html):
429
453