Skip to content

Commit cdb9d58

Browse files
committed
feat: add SSE (Server-Sent Events) support
- Add SSEMessageEvent, SSECallbacks, SSEConfig types - Add parseSSEStream method for parsing SSE response - Add sse() convenience method for creating SSE connections - Support custom headers (unlike native EventSource) - Support POST requests and all HTTP methods - Support interceptors integration - Update README with SSE examples (EN & ZH)
1 parent 516b029 commit cdb9d58

72 files changed

Lines changed: 4192 additions & 2041 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,106 @@ const data2 = await cachedApi.get('/users', {}, { cache: { ttl: 5000 } }) // cac
133133
const otherApi = new Request('/api') // isolated cache
134134
```
135135

136+
## SSE (Server-Sent Events)
137+
138+
Supports SSE streaming requests, built on Fetch API with these advantages over native EventSource:
139+
- ✅ Custom Headers support
140+
- ✅ POST requests support
141+
- ✅ All HTTP methods supported
142+
143+
### Basic usage
144+
145+
```ts
146+
import { Request } from '@cc-heart/utils'
147+
148+
const api = new Request('https://api.example.com')
149+
150+
// GET SSE
151+
const handle = api.sse('/events', {
152+
onMessage(event) {
153+
console.log('Received:', event.data)
154+
},
155+
onOpen() {
156+
console.log('Connection opened')
157+
},
158+
onError(error) {
159+
console.error('Connection error:', error)
160+
},
161+
onClose() {
162+
console.log('Connection closed')
163+
}
164+
})
165+
166+
// Cancel connection
167+
handle.abort()
168+
```
169+
170+
### POST SSE (e.g., AI streaming chat)
171+
172+
```ts
173+
const handle = api.sse('/chat/completions', {
174+
method: 'POST',
175+
data: {
176+
prompt: 'Hello',
177+
model: 'gpt-4'
178+
},
179+
onMessage(event) {
180+
// Parse JSON data
181+
try {
182+
const data = JSON.parse(event.data)
183+
console.log('AI reply:', data.content)
184+
} catch {
185+
console.log('Raw data:', event.data)
186+
}
187+
},
188+
onError(err) {
189+
console.error('Request failed:', err)
190+
}
191+
})
192+
```
193+
194+
### With interceptors
195+
196+
```ts
197+
import type { RequestInterceptor } from '@cc-heart/utils'
198+
199+
const addAuth: RequestInterceptor = (config) => ({
200+
...config,
201+
headers: {
202+
...config.headers,
203+
Authorization: `Bearer ${getToken()}`
204+
}
205+
})
206+
207+
const api = new Request('https://api.example.com')
208+
api.useRequestInterceptor(addAuth)
209+
210+
// SSE requests automatically include interceptor headers
211+
const handle = api.sse('/protected/events', {
212+
onMessage(event) {
213+
console.log(event.data)
214+
}
215+
})
216+
```
217+
218+
### SSE Type definitions
219+
220+
```ts
221+
interface SSEMessageEvent {
222+
event?: string // Event type
223+
data: string // Message data
224+
id?: string // Last event ID
225+
retry?: number // Retry interval (ms)
226+
}
227+
228+
interface SSECallbacks {
229+
onMessage?: (event: SSEMessageEvent) => void
230+
onOpen?: () => void
231+
onError?: (error: unknown) => void
232+
onClose?: () => void
233+
}
234+
```
235+
136236
## LICENSE
137237

138238
`@cc-heart/utils` is licensed under the [MIT License](./LICENSE).

README_ZH.md

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,106 @@ interface RequestConfig {
165165
}
166166
```
167167

168+
## SSE (Server-Sent Events)
169+
170+
支持 SSE 流式请求,基于 Fetch API 实现,相比原生 EventSource 有以下优势:
171+
- ✅ 支持自定义 Headers
172+
- ✅ 支持 POST 请求
173+
- ✅ 支持所有 HTTP 方法
174+
175+
### 基础用法
176+
177+
```ts
178+
import { Request } from '@cc-heart/utils'
179+
180+
const api = new Request('https://api.example.com')
181+
182+
// GET SSE
183+
const handle = api.sse('/events', {
184+
onMessage(event) {
185+
console.log('收到消息:', event.data)
186+
},
187+
onOpen() {
188+
console.log('连接已建立')
189+
},
190+
onError(error) {
191+
console.error('连接错误:', error)
192+
},
193+
onClose() {
194+
console.log('连接已关闭')
195+
}
196+
})
197+
198+
// 取消连接
199+
handle.abort()
200+
```
201+
202+
### POST SSE (如 AI 流式对话)
203+
204+
```ts
205+
const handle = api.sse('/chat/completions', {
206+
method: 'POST',
207+
data: {
208+
prompt: '你好',
209+
model: 'gpt-4'
210+
},
211+
onMessage(event) {
212+
// 解析 JSON 数据
213+
try {
214+
const data = JSON.parse(event.data)
215+
console.log('AI 回复:', data.content)
216+
} catch {
217+
console.log('原始数据:', event.data)
218+
}
219+
},
220+
onError(err) {
221+
console.error('请求失败:', err)
222+
}
223+
})
224+
```
225+
226+
### 搭配拦截器使用
227+
228+
```ts
229+
import type { RequestInterceptor } from '@cc-heart/utils'
230+
231+
const addAuth: RequestInterceptor = (config) => ({
232+
...config,
233+
headers: {
234+
...config.headers,
235+
Authorization: `Bearer ${getToken()}`
236+
}
237+
})
238+
239+
const api = new Request('https://api.example.com')
240+
api.useRequestInterceptor(addAuth)
241+
242+
// SSE 请求会自动携带拦截器添加的 Headers
243+
const handle = api.sse('/protected/events', {
244+
onMessage(event) {
245+
console.log(event.data)
246+
}
247+
})
248+
```
249+
250+
### SSE 类型定义
251+
252+
```ts
253+
interface SSEMessageEvent {
254+
event?: string // 事件类型
255+
data: string // 消息数据
256+
id?: string // 最后事件 ID
257+
retry?: number // 重连间隔(毫秒)
258+
}
259+
260+
interface SSECallbacks {
261+
onMessage?: (event: SSEMessageEvent) => void
262+
onOpen?: () => void
263+
onError?: (error: unknown) => void
264+
onClose?: () => void
265+
}
266+
```
267+
168268
## 返回类型
169269

170270
```ts

docs/assets/navigation.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/assets/search.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)