@vafast/api-client 0.2.3 → 0.2.7
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 +349 -100
- package/dist/index.d.mts +45 -7
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +28 -8
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -1,22 +1,103 @@
|
|
|
1
1
|
# @vafast/api-client
|
|
2
2
|
|
|
3
|
-
类型安全的 Eden 风格 API
|
|
3
|
+
类型安全的 Eden 风格 API 客户端,基于中间件架构,支持从 vafast 路由自动推断类型。
|
|
4
|
+
|
|
5
|
+
## 特性
|
|
6
|
+
|
|
7
|
+
- 🎯 **类型安全** - 从 vafast 路由自动推断,或手动定义契约
|
|
8
|
+
- 🧅 **中间件架构** - Koa 风格洋葱模型,灵活组合
|
|
9
|
+
- 🔄 **内置重试** - 支持指数退避、条件重试
|
|
10
|
+
- ⏱️ **超时控制** - 请求级别和全局超时
|
|
11
|
+
- 📡 **SSE 支持** - 流式响应、自动重连
|
|
12
|
+
- 🎨 **Go 风格错误** - `{ data, error }` 统一处理
|
|
4
13
|
|
|
5
14
|
## 安装
|
|
6
15
|
|
|
7
16
|
```bash
|
|
8
|
-
npm install @vafast/api-client
|
|
17
|
+
npm install @vafast/api-client
|
|
9
18
|
```
|
|
10
19
|
|
|
11
20
|
## 快速开始
|
|
12
21
|
|
|
13
|
-
|
|
22
|
+
```typescript
|
|
23
|
+
import { createClient, eden } from '@vafast/api-client'
|
|
24
|
+
|
|
25
|
+
// 1. 创建客户端
|
|
26
|
+
const client = createClient('http://localhost:3000')
|
|
27
|
+
.headers({ 'Authorization': 'Bearer token' })
|
|
28
|
+
.timeout(30000)
|
|
29
|
+
|
|
30
|
+
// 2. 类型包装
|
|
31
|
+
const api = eden<Api>(client)
|
|
32
|
+
|
|
33
|
+
// 3. 发起请求
|
|
34
|
+
const { data, error } = await api.users.get({ page: 1 })
|
|
35
|
+
|
|
36
|
+
if (error) {
|
|
37
|
+
console.error(`错误 ${error.code}: ${error.message}`)
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
console.log(data.users)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## 核心 API
|
|
45
|
+
|
|
46
|
+
### createClient(config)
|
|
47
|
+
|
|
48
|
+
创建 HTTP 客户端实例,支持两种方式:
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
// 方式 1:只传 baseURL(简单场景)
|
|
52
|
+
const client = createClient('http://localhost:3000')
|
|
53
|
+
.timeout(30000)
|
|
54
|
+
.use(authMiddleware)
|
|
55
|
+
|
|
56
|
+
// 方式 2:传配置对象(推荐,配置集中)
|
|
57
|
+
const client = createClient({
|
|
58
|
+
baseURL: 'http://localhost:3000',
|
|
59
|
+
timeout: 30000,
|
|
60
|
+
headers: { 'X-App-Id': 'my-app' }
|
|
61
|
+
}).use(authMiddleware)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**配置对象类型:**
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
interface ClientConfig {
|
|
68
|
+
baseURL: string
|
|
69
|
+
timeout?: number // 默认 30000ms
|
|
70
|
+
headers?: Record<string, string>
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**链式方法:**
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
const client = createClient({ baseURL: '/api', timeout: 30000 })
|
|
78
|
+
.headers({ 'X-App-Id': 'my-app' }) // 追加默认请求头
|
|
79
|
+
.timeout(60000) // 覆盖超时配置
|
|
80
|
+
.use(authMiddleware) // 添加中间件
|
|
81
|
+
.use(retryMiddleware({ count: 3 }))
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### eden<T>(client)
|
|
85
|
+
|
|
86
|
+
将 Client 实例包装为类型安全的 API 调用。
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
type Api = InferEden<typeof routes> // 从 vafast 路由推断
|
|
90
|
+
const api = eden<Api>(client)
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## 类型定义
|
|
94
|
+
|
|
95
|
+
### 方式 1:从 vafast 路由自动推断(推荐)
|
|
14
96
|
|
|
15
97
|
```typescript
|
|
16
98
|
// ============= 服务端 =============
|
|
17
99
|
import { defineRoute, defineRoutes, Type, Server } from 'vafast'
|
|
18
100
|
|
|
19
|
-
// 定义路由(使用 as const 保留字面量类型)
|
|
20
101
|
const routeDefinitions = [
|
|
21
102
|
defineRoute({
|
|
22
103
|
method: 'GET',
|
|
@@ -38,28 +119,25 @@ const routeDefinitions = [
|
|
|
38
119
|
})
|
|
39
120
|
] as const
|
|
40
121
|
|
|
41
|
-
// 创建服务器
|
|
42
122
|
const routes = defineRoutes(routeDefinitions)
|
|
43
123
|
const server = new Server(routes)
|
|
44
124
|
|
|
45
125
|
// ============= 客户端 =============
|
|
46
|
-
import { eden, InferEden } from '@vafast/api-client'
|
|
126
|
+
import { createClient, eden, InferEden } from '@vafast/api-client'
|
|
47
127
|
|
|
48
|
-
// 自动推断类型
|
|
49
128
|
type Api = InferEden<typeof routeDefinitions>
|
|
50
|
-
|
|
129
|
+
|
|
130
|
+
const client = createClient('http://localhost:3000')
|
|
131
|
+
const api = eden<Api>(client)
|
|
51
132
|
|
|
52
133
|
// ✅ 完全类型安全
|
|
53
|
-
const { data } = await api.users.get({ page: 1 })
|
|
54
|
-
const { data: user } = await api.users({ id: '123' }).get()
|
|
134
|
+
const { data } = await api.users.get({ page: 1 })
|
|
135
|
+
const { data: user } = await api.users({ id: '123' }).get()
|
|
55
136
|
```
|
|
56
137
|
|
|
57
|
-
### 方式 2
|
|
138
|
+
### 方式 2:手动定义契约
|
|
58
139
|
|
|
59
140
|
```typescript
|
|
60
|
-
import { eden } from '@vafast/api-client'
|
|
61
|
-
|
|
62
|
-
// 手动定义契约类型
|
|
63
141
|
type MyApi = {
|
|
64
142
|
users: {
|
|
65
143
|
get: { query: { page: number }; return: { users: User[]; total: number } }
|
|
@@ -72,40 +150,152 @@ type MyApi = {
|
|
|
72
150
|
}
|
|
73
151
|
}
|
|
74
152
|
|
|
75
|
-
const api = eden<MyApi>('https://api.example.com')
|
|
153
|
+
const api = eden<MyApi>(createClient('https://api.example.com'))
|
|
154
|
+
```
|
|
76
155
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
156
|
+
## 中间件
|
|
157
|
+
|
|
158
|
+
### 内置中间件
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
import {
|
|
162
|
+
createClient,
|
|
163
|
+
retryMiddleware,
|
|
164
|
+
timeoutMiddleware,
|
|
165
|
+
loggerMiddleware
|
|
166
|
+
} from '@vafast/api-client'
|
|
167
|
+
|
|
168
|
+
const client = createClient('http://localhost:3000')
|
|
169
|
+
// 重试中间件
|
|
170
|
+
.use(retryMiddleware({
|
|
171
|
+
count: 3, // 最大重试次数
|
|
172
|
+
delay: 1000, // 初始延迟
|
|
173
|
+
backoff: 2, // 退避倍数
|
|
174
|
+
on: [500, 502, 503, 504], // 触发重试的状态码
|
|
175
|
+
shouldRetry: (ctx, res) => true // 自定义重试条件
|
|
176
|
+
}))
|
|
177
|
+
// 超时中间件
|
|
178
|
+
.use(timeoutMiddleware(5000))
|
|
179
|
+
// 日志中间件
|
|
180
|
+
.use(loggerMiddleware({
|
|
181
|
+
prefix: '[API]',
|
|
182
|
+
onRequest: (ctx) => console.log('请求:', ctx.method, ctx.url),
|
|
183
|
+
onResponse: (res) => console.log('响应:', res.status)
|
|
184
|
+
}))
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### 自定义中间件
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
import { defineMiddleware } from '@vafast/api-client'
|
|
191
|
+
|
|
192
|
+
// 认证中间件
|
|
193
|
+
const authMiddleware = defineMiddleware('auth', async (ctx, next) => {
|
|
194
|
+
const token = localStorage.getItem('token')
|
|
195
|
+
if (token) {
|
|
196
|
+
ctx.headers.set('Authorization', `Bearer ${token}`)
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const response = await next()
|
|
200
|
+
|
|
201
|
+
// Token 过期处理
|
|
202
|
+
if (response.status === 401) {
|
|
203
|
+
// 刷新 token 逻辑...
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return response
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
// 动态 header 中间件
|
|
210
|
+
const dynamicHeaderMiddleware = defineMiddleware('dynamic-header', async (ctx, next) => {
|
|
211
|
+
// 从路由或 store 获取动态值
|
|
212
|
+
const orgId = getCurrentOrganizationId()
|
|
213
|
+
const appId = getCurrentAppId()
|
|
214
|
+
|
|
215
|
+
ctx.headers.set('organization-id', orgId)
|
|
216
|
+
ctx.headers.set('app-id', appId)
|
|
217
|
+
|
|
218
|
+
return next()
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
const client = createClient('http://localhost:3000')
|
|
222
|
+
.use(authMiddleware)
|
|
223
|
+
.use(dynamicHeaderMiddleware)
|
|
80
224
|
```
|
|
81
225
|
|
|
82
|
-
|
|
226
|
+
### 中间件执行顺序
|
|
227
|
+
|
|
228
|
+
中间件按照洋葱模型执行:
|
|
229
|
+
|
|
230
|
+
```
|
|
231
|
+
请求 → auth → retry → timeout → [fetch] → timeout → retry → auth → 响应
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
## 多服务配置
|
|
235
|
+
|
|
236
|
+
针对不同后端服务创建独立客户端:
|
|
83
237
|
|
|
84
238
|
```typescript
|
|
85
|
-
//
|
|
86
|
-
const
|
|
239
|
+
// 公共配置
|
|
240
|
+
const AUTH_API = { baseURL: '/authRestfulApi', timeout: 30000 }
|
|
241
|
+
const ONES_API = { baseURL: '/restfulApi', timeout: 30000 }
|
|
242
|
+
const BILLING_API = { baseURL: '/billingRestfulApi', timeout: 30000 }
|
|
243
|
+
|
|
244
|
+
// Auth 服务
|
|
245
|
+
const authClient = createClient(AUTH_API)
|
|
246
|
+
|
|
247
|
+
// API 服务(需要额外 header)
|
|
248
|
+
const apiClient = createClient(ONES_API).use(dynamicHeaderMiddleware)
|
|
249
|
+
|
|
250
|
+
// Billing 服务
|
|
251
|
+
const billingClient = createClient(BILLING_API).use(billingHeaderMiddleware)
|
|
87
252
|
|
|
88
|
-
//
|
|
89
|
-
|
|
253
|
+
// 使用 CLI 生成的类型安全客户端
|
|
254
|
+
import { createApiClient as createAuthClient } from './types/auth.generated'
|
|
255
|
+
import { createApiClient as createOnesClient } from './types/ones.generated'
|
|
256
|
+
import { createApiClient as createBillingClient } from './types/billing.generated'
|
|
90
257
|
|
|
91
|
-
|
|
92
|
-
const
|
|
93
|
-
const
|
|
94
|
-
const { data, error } = await api.users({ id: '123' }).delete()
|
|
258
|
+
export const auth = createAuthClient(authClient)
|
|
259
|
+
export const ones = createOnesClient(apiClient)
|
|
260
|
+
export const billing = createBillingClient(billingClient)
|
|
95
261
|
|
|
96
|
-
//
|
|
97
|
-
const { data, error } = await
|
|
98
|
-
|
|
262
|
+
// 使用示例
|
|
263
|
+
const { data, error } = await ones.users.find.post({ current: 1, pageSize: 10 })
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
## 请求级配置
|
|
267
|
+
|
|
268
|
+
```typescript
|
|
269
|
+
// 单次请求覆盖配置
|
|
270
|
+
const { data, error } = await api.users.get(
|
|
271
|
+
{ page: 1 },
|
|
272
|
+
{
|
|
273
|
+
headers: { 'X-Request-Id': 'xxx' }, // 额外 header
|
|
274
|
+
timeout: 5000, // 请求超时
|
|
275
|
+
signal: controller.signal // 取消信号
|
|
276
|
+
}
|
|
277
|
+
)
|
|
99
278
|
```
|
|
100
279
|
|
|
101
280
|
## Go 风格错误处理
|
|
102
281
|
|
|
282
|
+
所有请求返回 `{ data, error }` 格式:
|
|
283
|
+
|
|
103
284
|
```typescript
|
|
104
285
|
const { data, error } = await api.users.get()
|
|
105
286
|
|
|
106
287
|
if (error) {
|
|
107
288
|
// error: { code: number; message: string }
|
|
108
|
-
|
|
289
|
+
switch (error.code) {
|
|
290
|
+
case 401:
|
|
291
|
+
redirectToLogin()
|
|
292
|
+
break
|
|
293
|
+
case 403:
|
|
294
|
+
showPermissionDenied()
|
|
295
|
+
break
|
|
296
|
+
default:
|
|
297
|
+
showError(error.message)
|
|
298
|
+
}
|
|
109
299
|
return
|
|
110
300
|
}
|
|
111
301
|
|
|
@@ -113,56 +303,10 @@ if (error) {
|
|
|
113
303
|
console.log(data.users)
|
|
114
304
|
```
|
|
115
305
|
|
|
116
|
-
## 配置选项
|
|
117
|
-
|
|
118
|
-
```typescript
|
|
119
|
-
const api = eden<Api>('http://localhost:3000', {
|
|
120
|
-
// 默认请求头
|
|
121
|
-
headers: {
|
|
122
|
-
'Authorization': 'Bearer token123'
|
|
123
|
-
},
|
|
124
|
-
|
|
125
|
-
// 请求超时(毫秒)
|
|
126
|
-
timeout: 30000,
|
|
127
|
-
|
|
128
|
-
// 请求拦截器
|
|
129
|
-
onRequest: async (request) => {
|
|
130
|
-
// 可以修改请求
|
|
131
|
-
return request
|
|
132
|
-
},
|
|
133
|
-
|
|
134
|
-
// 响应拦截器
|
|
135
|
-
onResponse: async (response) => {
|
|
136
|
-
// 可以修改响应
|
|
137
|
-
return response
|
|
138
|
-
},
|
|
139
|
-
|
|
140
|
-
// 错误回调
|
|
141
|
-
onError: (error) => {
|
|
142
|
-
console.error('API Error:', error.code, error.message)
|
|
143
|
-
}
|
|
144
|
-
})
|
|
145
|
-
```
|
|
146
|
-
|
|
147
306
|
## SSE 流式响应
|
|
148
307
|
|
|
149
308
|
```typescript
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
// 服务端定义 SSE 路由
|
|
153
|
-
const routeDefinitions = [
|
|
154
|
-
defineRoute({
|
|
155
|
-
method: 'GET',
|
|
156
|
-
path: '/chat/stream',
|
|
157
|
-
schema: { query: Type.Object({ prompt: Type.String() }) },
|
|
158
|
-
handler: async function* ({ query }) {
|
|
159
|
-
yield { data: { text: 'Hello' } }
|
|
160
|
-
yield { data: { text: 'World' } }
|
|
161
|
-
}
|
|
162
|
-
})
|
|
163
|
-
] as const
|
|
164
|
-
|
|
165
|
-
// 客户端(手动标记 SSE)
|
|
309
|
+
// 定义 SSE 类型
|
|
166
310
|
type Api = {
|
|
167
311
|
chat: {
|
|
168
312
|
stream: {
|
|
@@ -175,26 +319,21 @@ type Api = {
|
|
|
175
319
|
}
|
|
176
320
|
}
|
|
177
321
|
|
|
178
|
-
const api = eden<Api>(
|
|
322
|
+
const api = eden<Api>(client)
|
|
179
323
|
|
|
180
324
|
// 订阅 SSE 流
|
|
181
325
|
const subscription = api.chat.stream.subscribe(
|
|
182
326
|
{ prompt: 'Hello' },
|
|
183
327
|
{
|
|
184
|
-
onMessage: (data) =>
|
|
185
|
-
|
|
186
|
-
},
|
|
187
|
-
onError: (error) => {
|
|
188
|
-
console.error('错误:', error.message)
|
|
189
|
-
},
|
|
328
|
+
onMessage: (data) => console.log('收到:', data.text),
|
|
329
|
+
onError: (error) => console.error('错误:', error),
|
|
190
330
|
onOpen: () => console.log('连接建立'),
|
|
191
331
|
onClose: () => console.log('连接关闭'),
|
|
192
|
-
onReconnect: (attempt, max) => console.log(
|
|
193
|
-
onMaxReconnects: () => console.log('达到最大重连次数')
|
|
332
|
+
onReconnect: (attempt, max) => console.log(`重连 ${attempt}/${max}`)
|
|
194
333
|
},
|
|
195
334
|
{
|
|
196
|
-
reconnectInterval: 3000,
|
|
197
|
-
maxReconnects: 5
|
|
335
|
+
reconnectInterval: 3000,
|
|
336
|
+
maxReconnects: 5
|
|
198
337
|
}
|
|
199
338
|
)
|
|
200
339
|
|
|
@@ -213,21 +352,131 @@ const promise = api.users.get({ page: 1 }, { signal: controller.signal })
|
|
|
213
352
|
controller.abort()
|
|
214
353
|
```
|
|
215
354
|
|
|
216
|
-
|
|
355
|
+
---
|
|
356
|
+
|
|
357
|
+
## 最佳实践:HTTP 状态码 vs 全部 200
|
|
358
|
+
|
|
359
|
+
### ✅ 推荐:使用 HTTP 状态码
|
|
360
|
+
|
|
361
|
+
`@vafast/api-client` 设计为使用 HTTP 状态码判断请求成功/失败:
|
|
362
|
+
|
|
363
|
+
| HTTP 状态码 | 含义 |
|
|
364
|
+
|------------|------|
|
|
365
|
+
| 2xx | 成功 |
|
|
366
|
+
| 400 | 客户端错误(参数错误) |
|
|
367
|
+
| 401 | 未认证(Token 无效/过期) |
|
|
368
|
+
| 403 | 无权限 |
|
|
369
|
+
| 404 | 资源不存在 |
|
|
370
|
+
| 5xx | 服务器错误 |
|
|
371
|
+
|
|
372
|
+
**后端响应示例:**
|
|
373
|
+
|
|
374
|
+
```
|
|
375
|
+
HTTP 401 Unauthorized
|
|
376
|
+
|
|
377
|
+
{
|
|
378
|
+
"code": 10001,
|
|
379
|
+
"message": "Token 已过期"
|
|
380
|
+
}
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
### ❌ 不推荐:全部返回 200 + success 字段
|
|
384
|
+
|
|
385
|
+
```json
|
|
386
|
+
HTTP 200 OK
|
|
387
|
+
|
|
388
|
+
{
|
|
389
|
+
"success": false,
|
|
390
|
+
"code": 10001,
|
|
391
|
+
"message": "Token 已过期"
|
|
392
|
+
}
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
### 为什么 HTTP 状态码更好?
|
|
396
|
+
|
|
397
|
+
| 方面 | HTTP 状态码 | 全部 200 |
|
|
398
|
+
|------|------------|----------|
|
|
399
|
+
| **监控告警** | 自动识别错误率 | 全是 200,无法识别 |
|
|
400
|
+
| **浏览器调试** | DevTools 红色标记失败 | 全绿,难以调试 |
|
|
401
|
+
| **CDN 缓存** | 不会缓存错误响应 | 可能错误缓存 |
|
|
402
|
+
| **重试策略** | 503 重试,400 不重试 | 无法区分 |
|
|
403
|
+
| **协议语义** | 符合 HTTP 标准 | 违背设计意图 |
|
|
404
|
+
|
|
405
|
+
### 兼容旧系统
|
|
406
|
+
|
|
407
|
+
如果后端暂时无法修改,使用中间件做兼容:
|
|
408
|
+
|
|
409
|
+
```typescript
|
|
410
|
+
const legacyMiddleware = defineMiddleware('legacy', async (ctx, next) => {
|
|
411
|
+
const response = await next()
|
|
412
|
+
|
|
413
|
+
// 兼容旧的 { success: false } 格式
|
|
414
|
+
if (response.status === 200 && response.data?.success === false) {
|
|
415
|
+
response.error = {
|
|
416
|
+
code: response.data.code ?? 500,
|
|
417
|
+
message: response.data.message ?? '请求失败'
|
|
418
|
+
}
|
|
419
|
+
response.data = null
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
return response
|
|
423
|
+
})
|
|
424
|
+
|
|
425
|
+
const client = createClient('http://localhost:3000')
|
|
426
|
+
.use(legacyMiddleware)
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
> ⚠️ 这只是过渡方案,建议尽快让后端返回正确的 HTTP 状态码。
|
|
430
|
+
|
|
431
|
+
---
|
|
432
|
+
|
|
433
|
+
## API 参考
|
|
434
|
+
|
|
435
|
+
### createClient(config)
|
|
436
|
+
|
|
437
|
+
创建 HTTP 客户端。
|
|
438
|
+
|
|
439
|
+
**参数:**
|
|
440
|
+
- `config: string | ClientConfig` - baseURL 字符串或配置对象
|
|
441
|
+
|
|
442
|
+
**ClientConfig:**
|
|
443
|
+
```typescript
|
|
444
|
+
interface ClientConfig {
|
|
445
|
+
baseURL: string
|
|
446
|
+
timeout?: number // 默认 30000ms
|
|
447
|
+
headers?: Record<string, string>
|
|
448
|
+
}
|
|
449
|
+
```
|
|
217
450
|
|
|
218
|
-
|
|
451
|
+
**返回值(链式):**
|
|
452
|
+
- `.headers(headers)` - 追加默认请求头
|
|
453
|
+
- `.timeout(ms)` - 设置默认超时
|
|
454
|
+
- `.use(middleware)` - 添加中间件
|
|
455
|
+
- `.request(method, path, data?, config?)` - 发起请求
|
|
219
456
|
|
|
220
|
-
|
|
457
|
+
### eden<T>(client)
|
|
221
458
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
459
|
+
创建类型安全的 API 客户端。
|
|
460
|
+
|
|
461
|
+
### defineMiddleware(name, fn)
|
|
462
|
+
|
|
463
|
+
创建命名中间件。
|
|
464
|
+
|
|
465
|
+
```typescript
|
|
466
|
+
const myMiddleware = defineMiddleware('my-middleware', async (ctx, next) => {
|
|
467
|
+
// 请求前处理
|
|
468
|
+
console.log('请求:', ctx.method, ctx.url)
|
|
469
|
+
|
|
470
|
+
const response = await next()
|
|
471
|
+
|
|
472
|
+
// 响应后处理
|
|
473
|
+
console.log('响应:', response.status)
|
|
474
|
+
|
|
475
|
+
return response
|
|
476
|
+
})
|
|
477
|
+
```
|
|
229
478
|
|
|
230
|
-
###
|
|
479
|
+
### InferEden<T>
|
|
231
480
|
|
|
232
481
|
从 `defineRoute` 数组推断 Eden 契约类型。
|
|
233
482
|
|
package/dist/index.d.mts
CHANGED
|
@@ -131,23 +131,34 @@ interface Client {
|
|
|
131
131
|
* 定义带名称的中间件
|
|
132
132
|
*/
|
|
133
133
|
declare function defineMiddleware(fn: Middleware, options?: MiddlewareOptions): NamedMiddleware;
|
|
134
|
+
/** 客户端配置 */
|
|
135
|
+
interface ClientConfig {
|
|
136
|
+
baseURL: string;
|
|
137
|
+
timeout?: number;
|
|
138
|
+
headers?: Record<string, string>;
|
|
139
|
+
}
|
|
134
140
|
/**
|
|
135
141
|
* 创建 HTTP 客户端
|
|
136
142
|
*
|
|
137
|
-
* @param
|
|
143
|
+
* @param config 基础 URL 或配置对象
|
|
138
144
|
* @returns 客户端实例
|
|
139
145
|
*
|
|
140
146
|
* @example
|
|
141
147
|
* ```typescript
|
|
142
|
-
*
|
|
148
|
+
* // 方式1:只传 baseURL
|
|
149
|
+
* const client = createClient('/api')
|
|
143
150
|
* .use(authMiddleware)
|
|
144
|
-
* .use('retry', retryMiddleware)
|
|
145
151
|
* .timeout(30000)
|
|
146
152
|
*
|
|
147
|
-
*
|
|
153
|
+
* // 方式2:传配置对象(推荐)
|
|
154
|
+
* const client = createClient({
|
|
155
|
+
* baseURL: '/api',
|
|
156
|
+
* timeout: 30000,
|
|
157
|
+
* headers: { 'X-Custom': 'value' }
|
|
158
|
+
* }).use(authMiddleware)
|
|
148
159
|
* ```
|
|
149
160
|
*/
|
|
150
|
-
declare function createClient(
|
|
161
|
+
declare function createClient(config: string | ClientConfig): Client;
|
|
151
162
|
//#endregion
|
|
152
163
|
//#region src/core/eden.d.ts
|
|
153
164
|
interface SSEEvent<T = unknown> {
|
|
@@ -316,7 +327,34 @@ type Endpoint<T, HasParams extends boolean = false> = { [K in 'get' | 'post' | '
|
|
|
316
327
|
subscribe: MethodCall<M, HasParams>;
|
|
317
328
|
} : {} : {});
|
|
318
329
|
type HTTPMethods = 'get' | 'post' | 'put' | 'patch' | 'delete';
|
|
319
|
-
|
|
330
|
+
/**
|
|
331
|
+
* 判断是否是路由节点(包含 HTTP 方法作为子键)
|
|
332
|
+
* 路由节点结构:{ post: {...} } 或 { get: {...}, post: {...} }
|
|
333
|
+
* 方法定义结构:{ body?: ..., return: ... }
|
|
334
|
+
*/
|
|
335
|
+
type HasHTTPMethod<T> = T extends {
|
|
336
|
+
get: unknown;
|
|
337
|
+
} | {
|
|
338
|
+
post: unknown;
|
|
339
|
+
} | {
|
|
340
|
+
put: unknown;
|
|
341
|
+
} | {
|
|
342
|
+
patch: unknown;
|
|
343
|
+
} | {
|
|
344
|
+
delete: unknown;
|
|
345
|
+
} ? true : false;
|
|
346
|
+
/**
|
|
347
|
+
* 判断键是否应该被过滤
|
|
348
|
+
* - 键名是动态参数 :xxx → 过滤
|
|
349
|
+
* - 键名是 HTTP 方法 且 值是方法定义(有 body/return 但没有 HTTP 方法子键)→ 过滤
|
|
350
|
+
*
|
|
351
|
+
* 注意:像 prices.delete 这样的路径段(值是 { post: {...} })不应被过滤
|
|
352
|
+
*/
|
|
353
|
+
type IsMethodDef<T> = T extends {
|
|
354
|
+
return: unknown;
|
|
355
|
+
} ? HasHTTPMethod<T> extends true ? false : true : false;
|
|
356
|
+
type ShouldFilter<K$1, T> = K$1 extends `:${string}` ? true : K$1 extends HTTPMethods ? IsMethodDef<T> : false;
|
|
357
|
+
type EdenClient<T, HasParams extends boolean = false> = { [K in keyof T as ShouldFilter<K, T[K]> extends true ? never : K]: T[K] extends {
|
|
320
358
|
':id': infer Child;
|
|
321
359
|
} ? ((params: Record<string, string>) => EdenClient<Child, true>) & EdenClient<T[K], false> : EdenClient<T[K], false> } & Endpoint<T, HasParams>;
|
|
322
360
|
/**
|
|
@@ -420,5 +458,5 @@ interface LoggerOptions {
|
|
|
420
458
|
*/
|
|
421
459
|
declare function loggerMiddleware(options?: LoggerOptions): NamedMiddleware;
|
|
422
460
|
//#endregion
|
|
423
|
-
export { type ApiError, type ApiResponse, type Client, type EdenClient, type HTTPMethod, type InferEden, type LoggerOptions, type Middleware, type MiddlewareOptions, type NamedMiddleware, type RequestConfig, type RequestContext, type ResponseContext, type RetryOptions, type SSEEvent, type SSESubscribeOptions, type SSESubscription, createClient, defineMiddleware, eden, loggerMiddleware, retryMiddleware, timeoutMiddleware };
|
|
461
|
+
export { type ApiError, type ApiResponse, type Client, type ClientConfig, type EdenClient, type HTTPMethod, type InferEden, type LoggerOptions, type Middleware, type MiddlewareOptions, type NamedMiddleware, type RequestConfig, type RequestContext, type ResponseContext, type RetryOptions, type SSEEvent, type SSESubscribeOptions, type SSESubscription, createClient, defineMiddleware, eden, loggerMiddleware, retryMiddleware, timeoutMiddleware };
|
|
424
462
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types/index.ts","../src/core/client.ts","../src/core/eden.ts","../src/middlewares/timeout.ts","../src/middlewares/retry.ts","../src/middlewares/logger.ts"],"sourcesContent":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types/index.ts","../src/core/client.ts","../src/core/eden.ts","../src/middlewares/timeout.ts","../src/middlewares/retry.ts","../src/middlewares/logger.ts"],"sourcesContent":[],"mappings":"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"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import qs from "qs";
|
|
2
|
+
|
|
1
3
|
//#region src/core/compose.ts
|
|
2
4
|
/**
|
|
3
5
|
* 组合多个中间件为单一函数
|
|
@@ -33,6 +35,11 @@ function compose(middlewares) {
|
|
|
33
35
|
//#endregion
|
|
34
36
|
//#region src/core/client.ts
|
|
35
37
|
/**
|
|
38
|
+
* HTTP 客户端实现
|
|
39
|
+
*
|
|
40
|
+
* 基于中间件模式的可扩展 HTTP 客户端
|
|
41
|
+
*/
|
|
42
|
+
/**
|
|
36
43
|
* 定义带名称的中间件
|
|
37
44
|
*/
|
|
38
45
|
function defineMiddleware(fn, options) {
|
|
@@ -152,7 +159,11 @@ var ClientImpl = class {
|
|
|
152
159
|
};
|
|
153
160
|
if (body && method !== "GET" && method !== "HEAD") fetchOptions.body = JSON.stringify(body);
|
|
154
161
|
if (method === "GET" && body && typeof body === "object") {
|
|
155
|
-
|
|
162
|
+
const queryString = qs.stringify(body, {
|
|
163
|
+
skipNulls: true,
|
|
164
|
+
arrayFormat: "indices"
|
|
165
|
+
});
|
|
166
|
+
if (queryString) url.search = queryString;
|
|
156
167
|
}
|
|
157
168
|
try {
|
|
158
169
|
const request = new Request(url.toString(), fetchOptions);
|
|
@@ -176,21 +187,30 @@ var ClientImpl = class {
|
|
|
176
187
|
/**
|
|
177
188
|
* 创建 HTTP 客户端
|
|
178
189
|
*
|
|
179
|
-
* @param
|
|
190
|
+
* @param config 基础 URL 或配置对象
|
|
180
191
|
* @returns 客户端实例
|
|
181
192
|
*
|
|
182
193
|
* @example
|
|
183
194
|
* ```typescript
|
|
184
|
-
*
|
|
195
|
+
* // 方式1:只传 baseURL
|
|
196
|
+
* const client = createClient('/api')
|
|
185
197
|
* .use(authMiddleware)
|
|
186
|
-
* .use('retry', retryMiddleware)
|
|
187
198
|
* .timeout(30000)
|
|
188
199
|
*
|
|
189
|
-
*
|
|
200
|
+
* // 方式2:传配置对象(推荐)
|
|
201
|
+
* const client = createClient({
|
|
202
|
+
* baseURL: '/api',
|
|
203
|
+
* timeout: 30000,
|
|
204
|
+
* headers: { 'X-Custom': 'value' }
|
|
205
|
+
* }).use(authMiddleware)
|
|
190
206
|
* ```
|
|
191
207
|
*/
|
|
192
|
-
function createClient(
|
|
193
|
-
return new ClientImpl(
|
|
208
|
+
function createClient(config) {
|
|
209
|
+
if (typeof config === "string") return new ClientImpl(config);
|
|
210
|
+
const client = new ClientImpl(config.baseURL);
|
|
211
|
+
if (config.timeout !== void 0) client.timeout(config.timeout);
|
|
212
|
+
if (config.headers) client.headers(config.headers);
|
|
213
|
+
return client;
|
|
194
214
|
}
|
|
195
215
|
|
|
196
216
|
//#endregion
|
|
@@ -341,7 +361,7 @@ function eden(client) {
|
|
|
341
361
|
};
|
|
342
362
|
}
|
|
343
363
|
if (prop === "subscribe") return (queryOrCallbacks, callbacksOrOptions, options) => {
|
|
344
|
-
if (typeof queryOrCallbacks === "object" && "onMessage" in queryOrCallbacks) return subscribe(basePath, void 0, queryOrCallbacks, callbacksOrOptions);
|
|
364
|
+
if (typeof queryOrCallbacks === "object" && "onMessage" in queryOrCallbacks && typeof queryOrCallbacks.onMessage === "function") return subscribe(basePath, void 0, queryOrCallbacks, callbacksOrOptions);
|
|
345
365
|
else return subscribe(basePath, queryOrCallbacks, callbacksOrOptions, options);
|
|
346
366
|
};
|
|
347
367
|
return createEndpoint(`${basePath}/${prop}`);
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../src/core/compose.ts","../src/core/client.ts","../src/core/eden.ts","../src/middlewares/timeout.ts","../src/middlewares/retry.ts","../src/middlewares/logger.ts"],"sourcesContent":["/**\n * 中间件组合函数\n * \n * 将多个中间件组合成一个执行链,类似 Koa 的洋葱模型\n */\n\nimport type { Middleware, RequestContext, ResponseContext } from '../types'\n\n/**\n * 组合多个中间件为单一函数\n * \n * @param middlewares 中间件数组\n * @returns 组合后的中间件函数\n * \n * @example\n * ```typescript\n * const chain = compose([m1, m2, m3])\n * const response = await chain(ctx, finalHandler)\n * ```\n */\nexport function compose(\n middlewares: Middleware[]\n): (ctx: RequestContext, final: () => Promise<ResponseContext>) => Promise<ResponseContext> {\n // 验证中间件\n for (const fn of middlewares) {\n if (typeof fn !== 'function') {\n throw new TypeError('Middleware must be a function')\n }\n }\n\n return function composedMiddleware(\n ctx: RequestContext,\n final: () => Promise<ResponseContext>\n ): Promise<ResponseContext> {\n let index = -1\n\n function dispatch(i: number): Promise<ResponseContext> {\n // 防止多次调用 next\n if (i <= index) {\n return Promise.reject(new Error('next() called multiple times'))\n }\n index = i\n\n // 获取当前中间件\n const fn = i < middlewares.length ? middlewares[i] : final\n\n // 如果没有更多中间件,执行最终处理器\n if (!fn) {\n return final()\n }\n\n try {\n // 执行中间件,传入 next 函数\n return Promise.resolve(\n fn(ctx, () => dispatch(i + 1))\n )\n } catch (err) {\n return Promise.reject(err)\n }\n }\n\n return dispatch(0)\n }\n}\n","/**\n * HTTP 客户端实现\n * \n * 基于中间件模式的可扩展 HTTP 客户端\n */\n\nimport type {\n ApiError,\n ApiResponse,\n Client,\n Middleware,\n NamedMiddleware,\n MiddlewareOptions,\n RequestConfig,\n RequestContext,\n ResponseContext,\n} from '../types'\nimport { compose } from './compose'\n\n// ==================== 辅助函数 ====================\n\n/**\n * 定义带名称的中间件\n */\nexport function defineMiddleware(\n fn: Middleware,\n options?: MiddlewareOptions\n): NamedMiddleware {\n const named = fn as NamedMiddleware\n if (options?.name) {\n named.middlewareName = options.name\n }\n return named\n}\n\n/**\n * 创建成功响应\n */\nfunction createSuccessResponse<T>(data: T, ctx: RequestContext, raw: Response): ResponseContext<T> {\n return {\n request: ctx,\n raw,\n data,\n error: null,\n status: raw.status,\n }\n}\n\n/**\n * 创建错误响应\n */\nfunction createErrorResponse(\n code: number,\n message: string,\n ctx: RequestContext,\n raw: Response | null = null\n): ResponseContext {\n return {\n request: ctx,\n raw,\n data: null,\n error: { code, message },\n status: raw?.status ?? 0,\n }\n}\n\n// ==================== 客户端实现 ====================\n\n/**\n * 内部客户端实现类\n */\nclass ClientImpl implements Client {\n readonly baseURL: string\n private middlewares: NamedMiddleware[] = []\n private defaultHeaders: Record<string, string> = {}\n private defaultTimeout: number = 30000\n\n constructor(baseURL: string) {\n // 移除末尾斜杠\n this.baseURL = baseURL.replace(/\\/+$/, '')\n }\n\n use(middlewareOrName: Middleware | string, middleware?: Middleware): Client {\n if (typeof middlewareOrName === 'string') {\n // use(name, middleware) 形式\n if (!middleware) {\n throw new Error('Middleware is required when name is provided')\n }\n const named = middleware as NamedMiddleware\n named.middlewareName = middlewareOrName\n this.middlewares.push(named)\n } else {\n // use(middleware) 形式\n this.middlewares.push(middlewareOrName as NamedMiddleware)\n }\n return this\n }\n\n headers(h: Record<string, string>): Client {\n this.defaultHeaders = { ...this.defaultHeaders, ...h }\n return this\n }\n\n timeout(ms: number): Client {\n this.defaultTimeout = ms\n return this\n }\n\n async request<T = unknown>(\n method: string,\n path: string,\n body?: unknown,\n config?: RequestConfig\n ): Promise<ApiResponse<T>> {\n // 构建 URL\n const url = new URL(path.startsWith('/') ? path : `/${path}`, this.baseURL)\n\n // 构建请求头\n const headers = new Headers({\n 'Content-Type': 'application/json',\n ...this.defaultHeaders,\n ...config?.headers,\n })\n\n // 构建元数据\n const meta = new Map<string, unknown>()\n if (config?.meta) {\n for (const [key, value] of Object.entries(config.meta)) {\n meta.set(key, value)\n }\n }\n\n // 构建请求上下文\n const ctx: RequestContext = {\n method: method.toUpperCase(),\n path,\n url,\n headers,\n body,\n config,\n meta,\n retryCount: 0,\n }\n\n // 最终的 fetch 处理器\n const finalHandler = async (): Promise<ResponseContext<T>> => {\n return this.executeFetch<T>(ctx)\n }\n\n try {\n // 执行中间件链\n const response = await compose(this.middlewares)(ctx, finalHandler)\n\n // 转换为 ApiResponse\n return {\n data: response.data as T | null,\n error: response.error,\n }\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err))\n return {\n data: null,\n error: { code: 0, message: error.message || '请求失败' },\n }\n }\n }\n\n /**\n * 执行实际的 fetch 请求\n */\n private async executeFetch<T>(ctx: RequestContext): Promise<ResponseContext<T>> {\n const { method, url, headers, body, config } = ctx\n\n // 超时控制\n const controller = new AbortController()\n const timeoutMs = config?.timeout ?? this.defaultTimeout\n const timeoutId = setTimeout(() => controller.abort(), timeoutMs)\n\n // 合并信号\n if (config?.signal) {\n config.signal.addEventListener('abort', () => controller.abort())\n }\n\n // 构建 fetch 选项\n const fetchOptions: RequestInit = {\n method,\n headers,\n signal: controller.signal,\n }\n\n // 添加请求体(GET/HEAD 不需要)\n if (body && method !== 'GET' && method !== 'HEAD') {\n fetchOptions.body = JSON.stringify(body)\n }\n\n // GET 请求的查询参数\n if (method === 'GET' && body && typeof body === 'object') {\n for (const [key, value] of Object.entries(body as Record<string, unknown>)) {\n if (value !== undefined && value !== null) {\n url.searchParams.set(key, String(value))\n }\n }\n }\n\n try {\n // 创建 Request 对象(便于测试和拦截)\n const request = new Request(url.toString(), fetchOptions)\n const response = await fetch(request)\n clearTimeout(timeoutId)\n\n // 解析响应\n const contentType = response.headers.get('content-type')\n let data: T | null = null\n\n if (contentType?.includes('application/json')) {\n data = await response.json()\n } else if (contentType?.includes('text/')) {\n data = await response.text() as unknown as T\n }\n\n // 成功响应\n if (response.ok) {\n return createSuccessResponse(data, ctx, response)\n }\n\n // 错误响应\n const errorData = data as { code?: number; message?: string } | null\n return createErrorResponse(\n errorData?.code ?? response.status,\n errorData?.message ?? `HTTP ${response.status}`,\n ctx,\n response\n )\n } catch (err) {\n clearTimeout(timeoutId)\n\n const error = err instanceof Error ? err : new Error(String(err))\n\n // 超时错误\n if (error.name === 'AbortError') {\n return createErrorResponse(408, '请求超时', ctx)\n }\n\n // 网络错误\n return createErrorResponse(0, error.message || '网络错误', ctx)\n }\n }\n}\n\n// ==================== 导出 ====================\n\n/**\n * 创建 HTTP 客户端\n * \n * @param baseURL 基础 URL\n * @returns 客户端实例\n * \n * @example\n * ```typescript\n * const client = createClient('http://localhost:3000')\n * .use(authMiddleware)\n * .use('retry', retryMiddleware)\n * .timeout(30000)\n * \n * const api = eden<Api>(client)\n * ```\n */\nexport function createClient(baseURL: string): Client {\n return new ClientImpl(baseURL)\n}\n","/**\n * Eden 风格 API 客户端\n * \n * 最自然的链式调用:\n * - api.users.get() // GET /users\n * - api.users.post({ name }) // POST /users\n * - api.users({ id }).get() // GET /users/:id\n * - api.users({ id }).delete() // DELETE /users/:id\n * - api.chat.stream.subscribe() // SSE 流式响应\n * \n * @example\n * ```typescript\n * import { defineRoute } from 'vafast'\n * import { eden, InferEden } from '@vafast/api-client'\n * \n * // 定义路由(保留类型)\n * const routeDefinitions = [\n * defineRoute({\n * method: 'GET',\n * path: '/users',\n * schema: { query: Type.Object({ page: Type.Number() }) },\n * handler: ({ query }) => ({ users: [], page: query.page })\n * })\n * ] as const\n * \n * // 客户端推断类型\n * type Api = InferEden<typeof routeDefinitions>\n * const api = eden<Api>('http://localhost:3000')\n * \n * // 类型安全调用\n * const { data } = await api.users.get({ page: 1 })\n * ```\n */\n\nimport type { ApiResponse, ApiError, RequestConfig } from '../types'\n\n// ============= SSE 类型 =============\n\nexport interface SSEEvent<T = unknown> {\n event?: string\n data: T\n id?: string\n retry?: number\n}\n\nexport interface SSESubscribeOptions {\n headers?: Record<string, string>\n reconnectInterval?: number\n maxReconnects?: number\n timeout?: number\n}\n\nexport interface SSESubscription<T = unknown> {\n unsubscribe: () => void\n readonly connected: boolean\n}\n\n// ============= 基础类型工具 =============\n\n/** 从 TypeBox Schema 提取静态类型 */\ntype InferStatic<T> = T extends { static: infer S } ? S : T\n\n/** 检查是否是 SSE Handler */\ntype IsSSEHandler<T> = T extends { __sse: { readonly __brand: 'SSE' } } ? true : false\n\n/** 从 Schema 对象提取各部分类型 */\ntype GetSchemaQuery<S> = S extends { query: infer Q } ? InferStatic<Q> : undefined\ntype GetSchemaBody<S> = S extends { body: infer B } ? InferStatic<B> : undefined\ntype GetSchemaParams<S> = S extends { params: infer P } ? InferStatic<P> : undefined\n\n/** \n * 从 handler 函数推断返回类型\n * handler: (ctx) => TReturn | Promise<TReturn>\n */\ntype InferHandlerReturn<H> = H extends (...args: never[]) => infer R\n ? R extends Promise<infer T> ? T : R\n : unknown\n\n// ============= 路径处理 =============\n\n/** 移除开头斜杠:/users → users */\ntype TrimSlash<P extends string> = P extends `/${infer R}` ? R : P\n\n/** 获取第一段:users/posts → users */\ntype Head<P extends string> = P extends `${infer H}/${string}` ? H : P\n\n/** 获取剩余段:users/posts → posts */\ntype Tail<P extends string> = P extends `${string}/${infer T}` ? T : never\n\n/** 检查是否是动态参数段::id → true */\ntype IsDynamicSegment<S extends string> = S extends `:${string}` ? true : false\n\n// ============= 清理 undefined 字段 =============\n\ntype Clean<T> = { [K in keyof T as T[K] extends undefined ? never : K]: T[K] }\n\n// ============= SSE 标记类型 =============\n\ntype SSEBrand = { readonly __brand: 'SSE' }\n\n// ============= 核心类型推断(适配新的 defineRoute) =============\n\n/**\n * 从 defineRoute 返回的路由配置构建方法定义\n * \n * defineRoute 返回的 LeafRouteConfig 结构:\n * {\n * method: TMethod,\n * path: TPath,\n * schema?: TSchema,\n * handler: (ctx) => TReturn | Promise<TReturn>\n * }\n */\ntype BuildMethodDef<R> = R extends {\n readonly schema?: infer TSchema\n readonly handler: infer THandler\n}\n ? Clean<{\n query: GetSchemaQuery<TSchema>\n body: GetSchemaBody<TSchema>\n params: GetSchemaParams<TSchema>\n return: InferHandlerReturn<THandler>\n }>\n : Clean<{\n return: R extends { readonly handler: infer H } ? InferHandlerReturn<H> : unknown\n }>\n\n/**\n * 递归构建嵌套路径结构\n * \n * 处理动态参数:/users/:id → { users: { ':id': { ... } } }\n */\ntype BuildPath<Path extends string, Method extends string, Def> =\n Path extends `${infer First}/${infer Rest}`\n ? IsDynamicSegment<First> extends true\n ? { ':id': BuildPath<Rest, Method, Def> }\n : { [K in First]: BuildPath<Rest, Method, Def> }\n : IsDynamicSegment<Path> extends true\n ? { ':id': { [M in Method]: Def } }\n : Path extends ''\n ? { [M in Method]: Def }\n : { [K in Path]: { [M in Method]: Def } }\n\n/**\n * 从单个路由生成嵌套类型结构\n */\ntype RouteToTree<R> = R extends {\n readonly method: infer M extends string\n readonly path: infer P extends string\n}\n ? BuildPath<TrimSlash<P>, Lowercase<M>, BuildMethodDef<R>>\n : {}\n\n// ============= 深度合并多个路由 =============\n\ntype DeepMerge<A, B> = {\n [K in keyof A | keyof B]: \n K extends keyof A & keyof B\n ? A[K] extends object\n ? B[K] extends object\n ? DeepMerge<A[K], B[K]>\n : A[K] & B[K]\n : A[K] & B[K]\n : K extends keyof A\n ? A[K]\n : K extends keyof B\n ? B[K]\n : never\n}\n\n/** 递归合并路由数组为单一类型结构 */\ntype MergeRoutes<T extends readonly unknown[]> = \n T extends readonly [infer First]\n ? RouteToTree<First>\n : T extends readonly [infer First, ...infer Rest]\n ? DeepMerge<RouteToTree<First>, MergeRoutes<Rest>>\n : {}\n\n/**\n * 从 defineRoutes 结果自动推断 Eden 契约\n * \n * 支持两种用法:\n * 1. 直接从 defineRoutes 结果推断(推荐,无需 as const)\n * 2. 从原始路由定义数组推断(需要 as const)\n * \n * @example\n * ```typescript\n * import { defineRoute, defineRoutes, Type } from 'vafast'\n * import { eden, InferEden } from '@vafast/api-client'\n * \n * // 方式1:直接从 defineRoutes 结果推断(推荐)\n * const routes = defineRoutes([\n * defineRoute({\n * method: 'GET',\n * path: '/users',\n * schema: { query: Type.Object({ page: Type.Number() }) },\n * handler: ({ query }) => ({ users: [], total: 0 })\n * }),\n * defineRoute({\n * method: 'POST',\n * path: '/users',\n * schema: { body: Type.Object({ name: Type.String() }) },\n * handler: ({ body }) => ({ id: '1', name: body.name })\n * })\n * ])\n * \n * const server = new Server(routes)\n * \n * // ✅ 类型推断自动工作,无需 as const!\n * type Api = InferEden<typeof routes>\n * const api = eden<Api>('http://localhost:3000')\n * \n * // 类型安全的调用\n * const { data } = await api.users.get({ page: 1 }) // ✅ query 类型推断\n * const { data: user } = await api.users.post({ name: 'John' }) // ✅ body 类型推断\n * ```\n */\nexport type InferEden<T> = \n // 优先从 __source 提取类型(defineRoutes 返回的结果)\n T extends { __source: infer S extends readonly unknown[] }\n ? MergeRoutes<S>\n // 否则直接作为路由数组处理(需要 as const)\n : T extends readonly unknown[]\n ? MergeRoutes<T>\n : {}\n\n// ============= 契约类型(手动定义时使用) =============\n\ninterface MethodDef {\n query?: unknown\n body?: unknown\n params?: unknown\n return: unknown\n sse?: SSEBrand\n}\n\ntype RouteNode = {\n get?: MethodDef\n post?: MethodDef\n put?: MethodDef\n patch?: MethodDef\n delete?: MethodDef\n ':id'?: RouteNode\n [key: string]: MethodDef | RouteNode | undefined\n}\n\n// ============= 客户端类型 =============\n\ninterface SSECallbacks<T> {\n onMessage: (data: T) => void\n onError?: (error: ApiError) => void\n onOpen?: () => void\n onClose?: () => void\n onReconnect?: (attempt: number, maxAttempts: number) => void\n onMaxReconnects?: () => void\n}\n\ntype MethodCall<M extends MethodDef, HasParams extends boolean = false> = \n M extends { sse: SSEBrand }\n ? M extends { query: infer Q }\n ? (query: Q, callbacks: SSECallbacks<M['return']>, options?: SSESubscribeOptions) => SSESubscription<M['return']>\n : (callbacks: SSECallbacks<M['return']>, options?: SSESubscribeOptions) => SSESubscription<M['return']>\n : HasParams extends true\n ? M extends { body: infer B }\n ? (body: B, config?: RequestConfig) => Promise<ApiResponse<M['return']>>\n : (config?: RequestConfig) => Promise<ApiResponse<M['return']>>\n : M extends { query: infer Q }\n ? (query?: Q, config?: RequestConfig) => Promise<ApiResponse<M['return']>>\n : M extends { body: infer B }\n ? (body: B, config?: RequestConfig) => Promise<ApiResponse<M['return']>>\n : (config?: RequestConfig) => Promise<ApiResponse<M['return']>>\n\ntype IsSSEEndpoint<M> = M extends { sse: { readonly __brand: 'SSE' } } ? true : false\n\ntype Endpoint<T, HasParams extends boolean = false> = \n {\n [K in 'get' | 'post' | 'put' | 'patch' | 'delete' as T extends { [P in K]: MethodDef } ? K : never]: \n T extends { [P in K]: infer M extends MethodDef } ? MethodCall<M, HasParams> : never\n } \n & (T extends { get: infer M extends MethodDef }\n ? IsSSEEndpoint<M> extends true \n ? { subscribe: MethodCall<M, HasParams> }\n : {}\n : {})\n\ntype HTTPMethods = 'get' | 'post' | 'put' | 'patch' | 'delete'\n\nexport type EdenClient<T, HasParams extends boolean = false> = {\n [K in keyof T as K extends HTTPMethods | `:${string}` ? never : K]: \n T[K] extends { ':id': infer Child }\n ? ((params: Record<string, string>) => EdenClient<Child, true>) & EdenClient<T[K], false>\n : EdenClient<T[K], false>\n} & Endpoint<T, HasParams>\n\n// ============= SSE 解析器 =============\n\nasync function* parseSSEStream(\n reader: ReadableStreamDefaultReader<Uint8Array>\n): AsyncGenerator<SSEEvent, void, unknown> {\n const decoder = new TextDecoder();\n let buffer = '';\n \n while (true) {\n const { done, value } = await reader.read();\n \n if (done) break;\n \n buffer += decoder.decode(value, { stream: true });\n \n const events = buffer.split('\\n\\n');\n buffer = events.pop() || '';\n \n for (const eventStr of events) {\n if (!eventStr.trim()) continue;\n \n const event: SSEEvent = { data: '' };\n const lines = eventStr.split('\\n');\n let dataLines: string[] = [];\n \n for (const line of lines) {\n if (line.startsWith('event:')) {\n event.event = line.slice(6).trim();\n } else if (line.startsWith('data:')) {\n dataLines.push(line.slice(5).trim());\n } else if (line.startsWith('id:')) {\n event.id = line.slice(3).trim();\n } else if (line.startsWith('retry:')) {\n event.retry = parseInt(line.slice(6).trim(), 10);\n }\n }\n \n const dataStr = dataLines.join('\\n');\n \n try {\n event.data = JSON.parse(dataStr);\n } catch {\n event.data = dataStr;\n }\n \n yield event;\n }\n }\n}\n\n// ============= Client 类型导入 ==============\n\nimport type { Client } from '../types'\n\n// ============= 实现 =============\n\n/**\n * 创建 Eden 风格的类型安全 API 客户端\n * \n * @param client - Client 实例\n * \n * @example\n * ```typescript\n * import { createClient, eden } from '@vafast/api-client'\n * \n * const client = createClient('http://localhost:3000')\n * .use(authMiddleware)\n * .use(retryMiddleware)\n * \n * const api = eden<Api>(client)\n * \n * const { data, error } = await api.users.find.post({ page: 1 })\n * ```\n */\nexport function eden<T>(client: Client): EdenClient<T> {\n // 获取 baseURL 用于 SSE\n const baseURL = client.baseURL\n \n // SSE 默认 headers(空对象,用户通过中间件添加)\n const defaultHeaders: Record<string, string> = {}\n\n // 请求函数:委托给 client\n async function request<TReturn>(\n method: string,\n path: string,\n data?: unknown,\n requestConfig?: RequestConfig\n ): Promise<ApiResponse<TReturn>> {\n return client.request<TReturn>(method, path, data, requestConfig)\n }\n\n function subscribe<TData>(\n path: string,\n query: Record<string, unknown> | undefined,\n callbacks: SSECallbacks<TData>,\n options?: SSESubscribeOptions\n ): SSESubscription<TData> {\n const url = new URL(path, baseURL)\n \n if (query) {\n for (const [key, value] of Object.entries(query)) {\n if (value !== undefined && value !== null) {\n url.searchParams.set(key, String(value))\n }\n }\n }\n\n let abortController: AbortController | null = new AbortController()\n let connected = false\n let reconnectCount = 0\n let isUnsubscribed = false\n let lastEventId: string | undefined\n \n const reconnectInterval = options?.reconnectInterval ?? 3000\n const maxReconnects = options?.maxReconnects ?? 5\n\n const connect = async () => {\n if (isUnsubscribed) return\n \n try {\n abortController = new AbortController()\n \n const headers: Record<string, string> = {\n 'Accept': 'text/event-stream',\n ...defaultHeaders,\n ...options?.headers,\n }\n \n if (lastEventId) {\n headers['Last-Event-ID'] = lastEventId\n }\n \n const response = await fetch(url.toString(), {\n method: 'GET',\n headers,\n signal: abortController.signal,\n })\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}`)\n }\n\n if (!response.body) {\n throw new Error('No response body')\n }\n\n connected = true\n reconnectCount = 0\n callbacks.onOpen?.()\n\n const reader = response.body.getReader()\n \n for await (const event of parseSSEStream(reader)) {\n if (event.id) {\n lastEventId = event.id\n }\n \n if (event.event === 'error') {\n callbacks.onError?.({ code: -1, message: String(event.data) })\n } else {\n callbacks.onMessage(event.data as TData)\n }\n }\n\n connected = false\n callbacks.onClose?.()\n \n } catch (error) {\n connected = false\n \n if ((error as Error).name === 'AbortError' || isUnsubscribed) {\n return\n }\n \n const err = error instanceof Error ? error : new Error(String(error))\n callbacks.onError?.({ code: 0, message: err.message || 'SSE 连接错误' })\n \n if (reconnectCount < maxReconnects) {\n reconnectCount++\n callbacks.onReconnect?.(reconnectCount, maxReconnects)\n \n setTimeout(() => {\n if (!isUnsubscribed) {\n connect()\n }\n }, reconnectInterval)\n } else {\n callbacks.onMaxReconnects?.()\n }\n }\n }\n\n connect()\n\n return {\n unsubscribe: () => {\n isUnsubscribed = true\n abortController?.abort()\n abortController = null\n connected = false\n },\n get connected() {\n return connected\n }\n }\n }\n\n function createEndpoint(basePath: string): unknown {\n const methods = ['get', 'post', 'put', 'patch', 'delete']\n \n const handler = (params: Record<string, string>) => {\n const paramValue = Object.values(params)[0]\n const newPath = `${basePath}/${encodeURIComponent(paramValue)}`\n return createEndpoint(newPath)\n }\n\n return new Proxy(handler as unknown as object, {\n get(_, prop: string) {\n if (methods.includes(prop)) {\n const httpMethod = prop.toUpperCase()\n return (data?: unknown, cfg?: RequestConfig) => {\n return request(httpMethod, basePath, data, cfg)\n }\n }\n \n if (prop === 'subscribe') {\n return <TData>(\n queryOrCallbacks: Record<string, unknown> | SSECallbacks<TData>,\n callbacksOrOptions?: SSECallbacks<TData> | SSESubscribeOptions,\n options?: SSESubscribeOptions\n ) => {\n if (typeof queryOrCallbacks === 'object' && 'onMessage' in queryOrCallbacks) {\n return subscribe<TData>(\n basePath, \n undefined, \n queryOrCallbacks as SSECallbacks<TData>,\n callbacksOrOptions as SSESubscribeOptions\n )\n } else {\n return subscribe<TData>(\n basePath,\n queryOrCallbacks as Record<string, unknown>,\n callbacksOrOptions as SSECallbacks<TData>,\n options\n )\n }\n }\n }\n \n const childPath = `${basePath}/${prop}`\n return createEndpoint(childPath)\n },\n apply(_, __, args) {\n const params = args[0] as Record<string, string>\n const paramValue = Object.values(params)[0]\n const newPath = `${basePath}/${encodeURIComponent(paramValue)}`\n return createEndpoint(newPath)\n }\n })\n }\n\n return new Proxy({} as EdenClient<T>, {\n get(_, prop: string) {\n return createEndpoint(`/${prop}`)\n }\n })\n}\n","/**\n * 超时中间件\n * \n * 为请求设置超时限制\n */\n\nimport type { Middleware, NamedMiddleware } from '../types'\n\n/**\n * 创建超时中间件\n * \n * @param ms 超时时间(毫秒)\n * @returns 超时中间件\n * \n * @example\n * ```typescript\n * const client = createClient(BASE_URL)\n * .use(timeoutMiddleware(30000)) // 30 秒超时\n * ```\n */\nexport function timeoutMiddleware(ms: number): NamedMiddleware {\n const middleware: Middleware = async (ctx, next) => {\n // 如果请求配置中有超时,优先使用\n const timeout = ctx.config?.timeout ?? ms\n \n // 创建超时 Promise\n const timeoutPromise = new Promise<never>((_, reject) => {\n setTimeout(() => {\n reject(new Error(`请求超时 (${timeout}ms)`))\n }, timeout)\n })\n \n // 竞争:请求 vs 超时\n try {\n const response = await Promise.race([\n next(),\n timeoutPromise,\n ])\n return response\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error))\n return {\n request: ctx,\n raw: null,\n data: null,\n error: { code: 408, message: err.message },\n status: 408,\n }\n }\n }\n \n // 添加名称\n const named = middleware as NamedMiddleware\n named.middlewareName = 'timeout'\n return named\n}\n","/**\n * 重试中间件\n * \n * 自动重试失败的请求\n */\n\nimport type { Middleware, NamedMiddleware, ResponseContext } from '../types'\n\n/**\n * 重试配置\n */\nexport interface RetryOptions {\n /** 重试次数,默认 3 */\n count?: number\n /** 重试延迟(毫秒),默认 1000 */\n delay?: number\n /** 指数退避,默认 true */\n backoff?: boolean\n /** 触发重试的状态码,默认 [408, 429, 500, 502, 503, 504] */\n on?: number[]\n /** 自定义重试判断 */\n shouldRetry?: (ctx: ResponseContext) => boolean\n}\n\n/** 默认重试状态码 */\nconst DEFAULT_RETRY_STATUS = [408, 429, 500, 502, 503, 504]\n\n/**\n * 延迟执行\n */\nfunction sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms))\n}\n\n/**\n * 创建重试中间件\n * \n * @param options 重试配置\n * @returns 重试中间件\n * \n * @example\n * ```typescript\n * const client = createClient(BASE_URL)\n * .use(retryMiddleware({ count: 3, delay: 1000 }))\n * ```\n */\nexport function retryMiddleware(options?: RetryOptions): NamedMiddleware {\n const {\n count = 3,\n delay = 1000,\n backoff = true,\n on = DEFAULT_RETRY_STATUS,\n shouldRetry,\n } = options ?? {}\n\n const middleware: Middleware = async (ctx, next) => {\n let lastResponse: ResponseContext | null = null\n let attempt = 0\n\n while (attempt <= count) {\n // 更新重试次数\n ctx.retryCount = attempt\n\n // 执行请求\n const response = await next()\n lastResponse = response\n\n // 成功或不需要重试\n if (!response.error) {\n return response\n }\n\n // 检查是否需要重试\n const needRetry = shouldRetry\n ? shouldRetry(response)\n : on.includes(response.status)\n\n if (!needRetry || attempt >= count) {\n return response\n }\n\n // 计算延迟(支持指数退避)\n const waitTime = backoff ? delay * Math.pow(2, attempt) : delay\n await sleep(waitTime)\n\n attempt++\n }\n\n // 返回最后一次响应\n return lastResponse!\n }\n\n // 添加名称\n const named = middleware as NamedMiddleware\n named.middlewareName = 'retry'\n return named\n}\n","/**\n * 日志中间件\n * \n * 记录请求和响应信息\n */\n\nimport type { Middleware, NamedMiddleware, RequestContext, ResponseContext } from '../types'\n\n/**\n * 日志配置\n */\nexport interface LoggerOptions {\n /** 请求日志回调 */\n onRequest?: (ctx: RequestContext) => void\n /** 响应日志回调 */\n onResponse?: (ctx: ResponseContext) => void\n /** 是否启用控制台日志,默认 true */\n console?: boolean\n /** 日志前缀 */\n prefix?: string\n}\n\n/**\n * 创建日志中间件\n * \n * @param options 日志配置\n * @returns 日志中间件\n * \n * @example\n * ```typescript\n * // 使用默认控制台日志\n * const client = createClient(BASE_URL)\n * .use(loggerMiddleware())\n * \n * // 自定义日志\n * const client = createClient(BASE_URL)\n * .use(loggerMiddleware({\n * onRequest: (ctx) => console.log(`[REQ] ${ctx.method} ${ctx.path}`),\n * onResponse: (ctx) => console.log(`[RES] ${ctx.status} ${ctx.request.path}`),\n * }))\n * ```\n */\nexport function loggerMiddleware(options?: LoggerOptions): NamedMiddleware {\n const {\n onRequest,\n onResponse,\n console: useConsole = true,\n prefix = '[API]',\n } = options ?? {}\n\n const middleware: Middleware = async (ctx, next) => {\n const startTime = Date.now()\n\n // 请求日志\n if (onRequest) {\n onRequest(ctx)\n }\n if (useConsole) {\n console.log(`${prefix} → ${ctx.method} ${ctx.path}`)\n }\n\n // 执行请求\n const response = await next()\n\n // 响应日志\n const duration = Date.now() - startTime\n if (onResponse) {\n onResponse(response)\n }\n if (useConsole) {\n const status = response.error ? `ERR ${response.error.code}` : `${response.status}`\n console.log(`${prefix} ← ${status} ${ctx.path} (${duration}ms)`)\n }\n\n return response\n }\n\n // 添加名称\n const named = middleware as NamedMiddleware\n named.middlewareName = 'logger'\n return named\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/core/compose.ts","../src/core/client.ts","../src/core/eden.ts","../src/middlewares/timeout.ts","../src/middlewares/retry.ts","../src/middlewares/logger.ts"],"sourcesContent":["/**\n * 中间件组合函数\n * \n * 将多个中间件组合成一个执行链,类似 Koa 的洋葱模型\n */\n\nimport type { Middleware, RequestContext, ResponseContext } from '../types'\n\n/**\n * 组合多个中间件为单一函数\n * \n * @param middlewares 中间件数组\n * @returns 组合后的中间件函数\n * \n * @example\n * ```typescript\n * const chain = compose([m1, m2, m3])\n * const response = await chain(ctx, finalHandler)\n * ```\n */\nexport function compose(\n middlewares: Middleware[]\n): (ctx: RequestContext, final: () => Promise<ResponseContext>) => Promise<ResponseContext> {\n // 验证中间件\n for (const fn of middlewares) {\n if (typeof fn !== 'function') {\n throw new TypeError('Middleware must be a function')\n }\n }\n\n return function composedMiddleware(\n ctx: RequestContext,\n final: () => Promise<ResponseContext>\n ): Promise<ResponseContext> {\n let index = -1\n\n function dispatch(i: number): Promise<ResponseContext> {\n // 防止多次调用 next\n if (i <= index) {\n return Promise.reject(new Error('next() called multiple times'))\n }\n index = i\n\n // 获取当前中间件\n const fn = i < middlewares.length ? middlewares[i] : final\n\n // 如果没有更多中间件,执行最终处理器\n if (!fn) {\n return final()\n }\n\n try {\n // 执行中间件,传入 next 函数\n return Promise.resolve(\n fn(ctx, () => dispatch(i + 1))\n )\n } catch (err) {\n return Promise.reject(err)\n }\n }\n\n return dispatch(0)\n }\n}\n","/**\n * HTTP 客户端实现\n * \n * 基于中间件模式的可扩展 HTTP 客户端\n */\n\nimport qs from 'qs'\nimport type {\n ApiError,\n ApiResponse,\n Client,\n Middleware,\n NamedMiddleware,\n MiddlewareOptions,\n RequestConfig,\n RequestContext,\n ResponseContext,\n} from '../types'\nimport { compose } from './compose'\n\n// ==================== 辅助函数 ====================\n\n/**\n * 定义带名称的中间件\n */\nexport function defineMiddleware(\n fn: Middleware,\n options?: MiddlewareOptions\n): NamedMiddleware {\n const named = fn as NamedMiddleware\n if (options?.name) {\n named.middlewareName = options.name\n }\n return named\n}\n\n/**\n * 创建成功响应\n */\nfunction createSuccessResponse<T>(data: T | null, ctx: RequestContext, raw: Response): ResponseContext<T> {\n return {\n request: ctx,\n raw,\n data,\n error: null,\n status: raw.status,\n }\n}\n\n/**\n * 创建错误响应\n */\nfunction createErrorResponse<T = unknown>(\n code: number,\n message: string,\n ctx: RequestContext,\n raw: Response | null = null\n): ResponseContext<T> {\n return {\n request: ctx,\n raw,\n data: null,\n error: { code, message },\n status: raw?.status ?? 0,\n }\n}\n\n// ==================== 客户端实现 ====================\n\n/**\n * 内部客户端实现类\n */\nclass ClientImpl implements Client {\n readonly baseURL: string\n private middlewares: NamedMiddleware[] = []\n private defaultHeaders: Record<string, string> = {}\n private defaultTimeout: number = 30000\n\n constructor(baseURL: string) {\n // 移除末尾斜杠\n this.baseURL = baseURL.replace(/\\/+$/, '')\n }\n\n use(middlewareOrName: Middleware | string, middleware?: Middleware): Client {\n if (typeof middlewareOrName === 'string') {\n // use(name, middleware) 形式\n if (!middleware) {\n throw new Error('Middleware is required when name is provided')\n }\n const named = middleware as NamedMiddleware\n named.middlewareName = middlewareOrName\n this.middlewares.push(named)\n } else {\n // use(middleware) 形式\n this.middlewares.push(middlewareOrName as NamedMiddleware)\n }\n return this\n }\n\n headers(h: Record<string, string>): Client {\n this.defaultHeaders = { ...this.defaultHeaders, ...h }\n return this\n }\n\n timeout(ms: number): Client {\n this.defaultTimeout = ms\n return this\n }\n\n async request<T = unknown>(\n method: string,\n path: string,\n body?: unknown,\n config?: RequestConfig\n ): Promise<ApiResponse<T>> {\n // 构建 URL\n const url = new URL(path.startsWith('/') ? path : `/${path}`, this.baseURL)\n\n // 构建请求头\n const headers = new Headers({\n 'Content-Type': 'application/json',\n ...this.defaultHeaders,\n ...config?.headers,\n })\n\n // 构建元数据\n const meta = new Map<string, unknown>()\n if (config?.meta) {\n for (const [key, value] of Object.entries(config.meta)) {\n meta.set(key, value)\n }\n }\n\n // 构建请求上下文\n const ctx: RequestContext = {\n method: method.toUpperCase(),\n path,\n url,\n headers,\n body,\n config,\n meta,\n retryCount: 0,\n }\n\n // 最终的 fetch 处理器\n const finalHandler = async (): Promise<ResponseContext<T>> => {\n return this.executeFetch<T>(ctx)\n }\n\n try {\n // 执行中间件链\n const response = await compose(this.middlewares)(ctx, finalHandler)\n\n // 转换为 ApiResponse\n return {\n data: response.data as T | null,\n error: response.error,\n }\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err))\n return {\n data: null,\n error: { code: 0, message: error.message || '请求失败' },\n }\n }\n }\n\n /**\n * 执行实际的 fetch 请求\n */\n private async executeFetch<T>(ctx: RequestContext): Promise<ResponseContext<T>> {\n const { method, url, headers, body, config } = ctx\n\n // 超时控制\n const controller = new AbortController()\n const timeoutMs = config?.timeout ?? this.defaultTimeout\n const timeoutId = setTimeout(() => controller.abort(), timeoutMs)\n\n // 合并信号\n if (config?.signal) {\n config.signal.addEventListener('abort', () => controller.abort())\n }\n\n // 构建 fetch 选项\n const fetchOptions: RequestInit = {\n method,\n headers,\n signal: controller.signal,\n }\n\n // 添加请求体(GET/HEAD 不需要)\n if (body && method !== 'GET' && method !== 'HEAD') {\n fetchOptions.body = JSON.stringify(body)\n }\n\n // GET 请求的查询参数(使用 qs 序列化,与后端 qs.parse 匹配)\n if (method === 'GET' && body && typeof body === 'object') {\n const queryString = qs.stringify(body as Record<string, unknown>, {\n skipNulls: true, // 跳过 null 值\n arrayFormat: 'indices', // 数组格式: ids[0]=1&ids[1]=2\n })\n if (queryString) {\n url.search = queryString\n }\n }\n\n try {\n // 创建 Request 对象(便于测试和拦截)\n const request = new Request(url.toString(), fetchOptions)\n const response = await fetch(request)\n clearTimeout(timeoutId)\n\n // 解析响应\n const contentType = response.headers.get('content-type')\n let data: T | null = null\n\n if (contentType?.includes('application/json')) {\n data = await response.json()\n } else if (contentType?.includes('text/')) {\n data = await response.text() as unknown as T\n }\n\n // 成功响应\n if (response.ok) {\n return createSuccessResponse(data, ctx, response)\n }\n\n // 错误响应\n const errorData = data as { code?: number; message?: string } | null\n return createErrorResponse<T>(\n errorData?.code ?? response.status,\n errorData?.message ?? `HTTP ${response.status}`,\n ctx,\n response\n )\n } catch (err) {\n clearTimeout(timeoutId)\n\n const error = err instanceof Error ? err : new Error(String(err))\n\n // 超时错误\n if (error.name === 'AbortError') {\n return createErrorResponse<T>(408, '请求超时', ctx)\n }\n\n // 网络错误\n return createErrorResponse<T>(0, error.message || '网络错误', ctx)\n }\n }\n}\n\n// ==================== 导出 ====================\n\n/** 客户端配置 */\nexport interface ClientConfig {\n baseURL: string\n timeout?: number\n headers?: Record<string, string>\n}\n\n/**\n * 创建 HTTP 客户端\n * \n * @param config 基础 URL 或配置对象\n * @returns 客户端实例\n * \n * @example\n * ```typescript\n * // 方式1:只传 baseURL\n * const client = createClient('/api')\n * .use(authMiddleware)\n * .timeout(30000)\n * \n * // 方式2:传配置对象(推荐)\n * const client = createClient({\n * baseURL: '/api',\n * timeout: 30000,\n * headers: { 'X-Custom': 'value' }\n * }).use(authMiddleware)\n * ```\n */\nexport function createClient(config: string | ClientConfig): Client {\n if (typeof config === 'string') {\n return new ClientImpl(config)\n }\n \n const client = new ClientImpl(config.baseURL)\n if (config.timeout !== undefined) {\n client.timeout(config.timeout)\n }\n if (config.headers) {\n client.headers(config.headers)\n }\n return client\n}\n","/**\n * Eden 风格 API 客户端\n * \n * 最自然的链式调用:\n * - api.users.get() // GET /users\n * - api.users.post({ name }) // POST /users\n * - api.users({ id }).get() // GET /users/:id\n * - api.users({ id }).delete() // DELETE /users/:id\n * - api.chat.stream.subscribe() // SSE 流式响应\n * \n * @example\n * ```typescript\n * import { defineRoute } from 'vafast'\n * import { eden, InferEden } from '@vafast/api-client'\n * \n * // 定义路由(保留类型)\n * const routeDefinitions = [\n * defineRoute({\n * method: 'GET',\n * path: '/users',\n * schema: { query: Type.Object({ page: Type.Number() }) },\n * handler: ({ query }) => ({ users: [], page: query.page })\n * })\n * ] as const\n * \n * // 客户端推断类型\n * type Api = InferEden<typeof routeDefinitions>\n * const api = eden<Api>('http://localhost:3000')\n * \n * // 类型安全调用\n * const { data } = await api.users.get({ page: 1 })\n * ```\n */\n\nimport type { ApiResponse, ApiError, RequestConfig } from '../types'\n\n// ============= SSE 类型 =============\n\nexport interface SSEEvent<T = unknown> {\n event?: string\n data: T\n id?: string\n retry?: number\n}\n\nexport interface SSESubscribeOptions {\n headers?: Record<string, string>\n reconnectInterval?: number\n maxReconnects?: number\n timeout?: number\n}\n\nexport interface SSESubscription<T = unknown> {\n unsubscribe: () => void\n readonly connected: boolean\n}\n\n// ============= 基础类型工具 =============\n\n/** 从 TypeBox Schema 提取静态类型 */\ntype InferStatic<T> = T extends { static: infer S } ? S : T\n\n/** 检查是否是 SSE Handler */\ntype IsSSEHandler<T> = T extends { __sse: { readonly __brand: 'SSE' } } ? true : false\n\n/** 从 Schema 对象提取各部分类型 */\ntype GetSchemaQuery<S> = S extends { query: infer Q } ? InferStatic<Q> : undefined\ntype GetSchemaBody<S> = S extends { body: infer B } ? InferStatic<B> : undefined\ntype GetSchemaParams<S> = S extends { params: infer P } ? InferStatic<P> : undefined\n\n/** \n * 从 handler 函数推断返回类型\n * handler: (ctx) => TReturn | Promise<TReturn>\n */\ntype InferHandlerReturn<H> = H extends (...args: never[]) => infer R\n ? R extends Promise<infer T> ? T : R\n : unknown\n\n// ============= 路径处理 =============\n\n/** 移除开头斜杠:/users → users */\ntype TrimSlash<P extends string> = P extends `/${infer R}` ? R : P\n\n/** 获取第一段:users/posts → users */\ntype Head<P extends string> = P extends `${infer H}/${string}` ? H : P\n\n/** 获取剩余段:users/posts → posts */\ntype Tail<P extends string> = P extends `${string}/${infer T}` ? T : never\n\n/** 检查是否是动态参数段::id → true */\ntype IsDynamicSegment<S extends string> = S extends `:${string}` ? true : false\n\n// ============= 清理 undefined 字段 =============\n\ntype Clean<T> = { [K in keyof T as T[K] extends undefined ? never : K]: T[K] }\n\n// ============= SSE 标记类型 =============\n\ntype SSEBrand = { readonly __brand: 'SSE' }\n\n// ============= 核心类型推断(适配新的 defineRoute) =============\n\n/**\n * 从 defineRoute 返回的路由配置构建方法定义\n * \n * defineRoute 返回的 LeafRouteConfig 结构:\n * {\n * method: TMethod,\n * path: TPath,\n * schema?: TSchema,\n * handler: (ctx) => TReturn | Promise<TReturn>\n * }\n */\ntype BuildMethodDef<R> = R extends {\n readonly schema?: infer TSchema\n readonly handler: infer THandler\n}\n ? Clean<{\n query: GetSchemaQuery<TSchema>\n body: GetSchemaBody<TSchema>\n params: GetSchemaParams<TSchema>\n return: InferHandlerReturn<THandler>\n }>\n : Clean<{\n return: R extends { readonly handler: infer H } ? InferHandlerReturn<H> : unknown\n }>\n\n/**\n * 递归构建嵌套路径结构\n * \n * 处理动态参数:/users/:id → { users: { ':id': { ... } } }\n */\ntype BuildPath<Path extends string, Method extends string, Def> =\n Path extends `${infer First}/${infer Rest}`\n ? IsDynamicSegment<First> extends true\n ? { ':id': BuildPath<Rest, Method, Def> }\n : { [K in First]: BuildPath<Rest, Method, Def> }\n : IsDynamicSegment<Path> extends true\n ? { ':id': { [M in Method]: Def } }\n : Path extends ''\n ? { [M in Method]: Def }\n : { [K in Path]: { [M in Method]: Def } }\n\n/**\n * 从单个路由生成嵌套类型结构\n */\ntype RouteToTree<R> = R extends {\n readonly method: infer M extends string\n readonly path: infer P extends string\n}\n ? BuildPath<TrimSlash<P>, Lowercase<M>, BuildMethodDef<R>>\n : {}\n\n// ============= 深度合并多个路由 =============\n\ntype DeepMerge<A, B> = {\n [K in keyof A | keyof B]: \n K extends keyof A & keyof B\n ? A[K] extends object\n ? B[K] extends object\n ? DeepMerge<A[K], B[K]>\n : A[K] & B[K]\n : A[K] & B[K]\n : K extends keyof A\n ? A[K]\n : K extends keyof B\n ? B[K]\n : never\n}\n\n/** 递归合并路由数组为单一类型结构 */\ntype MergeRoutes<T extends readonly unknown[]> = \n T extends readonly [infer First]\n ? RouteToTree<First>\n : T extends readonly [infer First, ...infer Rest]\n ? DeepMerge<RouteToTree<First>, MergeRoutes<Rest>>\n : {}\n\n/**\n * 从 defineRoutes 结果自动推断 Eden 契约\n * \n * 支持两种用法:\n * 1. 直接从 defineRoutes 结果推断(推荐,无需 as const)\n * 2. 从原始路由定义数组推断(需要 as const)\n * \n * @example\n * ```typescript\n * import { defineRoute, defineRoutes, Type } from 'vafast'\n * import { eden, InferEden } from '@vafast/api-client'\n * \n * // 方式1:直接从 defineRoutes 结果推断(推荐)\n * const routes = defineRoutes([\n * defineRoute({\n * method: 'GET',\n * path: '/users',\n * schema: { query: Type.Object({ page: Type.Number() }) },\n * handler: ({ query }) => ({ users: [], total: 0 })\n * }),\n * defineRoute({\n * method: 'POST',\n * path: '/users',\n * schema: { body: Type.Object({ name: Type.String() }) },\n * handler: ({ body }) => ({ id: '1', name: body.name })\n * })\n * ])\n * \n * const server = new Server(routes)\n * \n * // ✅ 类型推断自动工作,无需 as const!\n * type Api = InferEden<typeof routes>\n * const api = eden<Api>('http://localhost:3000')\n * \n * // 类型安全的调用\n * const { data } = await api.users.get({ page: 1 }) // ✅ query 类型推断\n * const { data: user } = await api.users.post({ name: 'John' }) // ✅ body 类型推断\n * ```\n */\nexport type InferEden<T> = \n // 优先从 __source 提取类型(defineRoutes 返回的结果)\n T extends { __source: infer S extends readonly unknown[] }\n ? MergeRoutes<S>\n // 否则直接作为路由数组处理(需要 as const)\n : T extends readonly unknown[]\n ? MergeRoutes<T>\n : {}\n\n// ============= 契约类型(手动定义时使用) =============\n\ninterface MethodDef {\n query?: unknown\n body?: unknown\n params?: unknown\n return: unknown\n sse?: SSEBrand\n}\n\ntype RouteNode = {\n get?: MethodDef\n post?: MethodDef\n put?: MethodDef\n patch?: MethodDef\n delete?: MethodDef\n ':id'?: RouteNode\n [key: string]: MethodDef | RouteNode | undefined\n}\n\n// ============= 客户端类型 =============\n\ninterface SSECallbacks<T> {\n onMessage: (data: T) => void\n onError?: (error: ApiError) => void\n onOpen?: () => void\n onClose?: () => void\n onReconnect?: (attempt: number, maxAttempts: number) => void\n onMaxReconnects?: () => void\n}\n\ntype MethodCall<M extends MethodDef, HasParams extends boolean = false> = \n M extends { sse: SSEBrand }\n ? M extends { query: infer Q }\n ? (query: Q, callbacks: SSECallbacks<M['return']>, options?: SSESubscribeOptions) => SSESubscription<M['return']>\n : (callbacks: SSECallbacks<M['return']>, options?: SSESubscribeOptions) => SSESubscription<M['return']>\n : HasParams extends true\n ? M extends { body: infer B }\n ? (body: B, config?: RequestConfig) => Promise<ApiResponse<M['return']>>\n : (config?: RequestConfig) => Promise<ApiResponse<M['return']>>\n : M extends { query: infer Q }\n ? (query?: Q, config?: RequestConfig) => Promise<ApiResponse<M['return']>>\n : M extends { body: infer B }\n ? (body: B, config?: RequestConfig) => Promise<ApiResponse<M['return']>>\n : (config?: RequestConfig) => Promise<ApiResponse<M['return']>>\n\ntype IsSSEEndpoint<M> = M extends { sse: { readonly __brand: 'SSE' } } ? true : false\n\ntype Endpoint<T, HasParams extends boolean = false> = \n {\n [K in 'get' | 'post' | 'put' | 'patch' | 'delete' as T extends { [P in K]: MethodDef } ? K : never]: \n T extends { [P in K]: infer M extends MethodDef } ? MethodCall<M, HasParams> : never\n } \n & (T extends { get: infer M extends MethodDef }\n ? IsSSEEndpoint<M> extends true \n ? { subscribe: MethodCall<M, HasParams> }\n : {}\n : {})\n\ntype HTTPMethods = 'get' | 'post' | 'put' | 'patch' | 'delete'\n\n/** \n * 判断是否是路由节点(包含 HTTP 方法作为子键)\n * 路由节点结构:{ post: {...} } 或 { get: {...}, post: {...} }\n * 方法定义结构:{ body?: ..., return: ... }\n */\ntype HasHTTPMethod<T> = T extends { get: unknown } | { post: unknown } | { put: unknown } | { patch: unknown } | { delete: unknown }\n ? true\n : false\n\n/** \n * 判断键是否应该被过滤\n * - 键名是动态参数 :xxx → 过滤\n * - 键名是 HTTP 方法 且 值是方法定义(有 body/return 但没有 HTTP 方法子键)→ 过滤\n * \n * 注意:像 prices.delete 这样的路径段(值是 { post: {...} })不应被过滤\n */\ntype IsMethodDef<T> = T extends { return: unknown } \n ? HasHTTPMethod<T> extends true ? false : true // 有 return 但没有 HTTP 方法 = 方法定义\n : false\n\ntype ShouldFilter<K, T> = K extends `:${string}` \n ? true // 动态参数始终过滤\n : K extends HTTPMethods\n ? IsMethodDef<T> // HTTP 方法名:只有当值是方法定义时才过滤\n : false\n\nexport type EdenClient<T, HasParams extends boolean = false> = {\n [K in keyof T as ShouldFilter<K, T[K]> extends true ? never : K]: \n T[K] extends { ':id': infer Child }\n ? ((params: Record<string, string>) => EdenClient<Child, true>) & EdenClient<T[K], false>\n : EdenClient<T[K], false>\n} & Endpoint<T, HasParams>\n\n// ============= SSE 解析器 =============\n\nasync function* parseSSEStream(\n reader: ReadableStreamDefaultReader<Uint8Array>\n): AsyncGenerator<SSEEvent, void, unknown> {\n const decoder = new TextDecoder();\n let buffer = '';\n \n while (true) {\n const { done, value } = await reader.read();\n \n if (done) break;\n \n buffer += decoder.decode(value, { stream: true });\n \n const events = buffer.split('\\n\\n');\n buffer = events.pop() || '';\n \n for (const eventStr of events) {\n if (!eventStr.trim()) continue;\n \n const event: SSEEvent = { data: '' };\n const lines = eventStr.split('\\n');\n let dataLines: string[] = [];\n \n for (const line of lines) {\n if (line.startsWith('event:')) {\n event.event = line.slice(6).trim();\n } else if (line.startsWith('data:')) {\n dataLines.push(line.slice(5).trim());\n } else if (line.startsWith('id:')) {\n event.id = line.slice(3).trim();\n } else if (line.startsWith('retry:')) {\n event.retry = parseInt(line.slice(6).trim(), 10);\n }\n }\n \n const dataStr = dataLines.join('\\n');\n \n try {\n event.data = JSON.parse(dataStr);\n } catch {\n event.data = dataStr;\n }\n \n yield event;\n }\n }\n}\n\n// ============= Client 类型导入 ==============\n\nimport type { Client } from '../types'\n\n// ============= 实现 =============\n\n/**\n * 创建 Eden 风格的类型安全 API 客户端\n * \n * @param client - Client 实例\n * \n * @example\n * ```typescript\n * import { createClient, eden } from '@vafast/api-client'\n * \n * const client = createClient('http://localhost:3000')\n * .use(authMiddleware)\n * .use(retryMiddleware)\n * \n * const api = eden<Api>(client)\n * \n * const { data, error } = await api.users.find.post({ page: 1 })\n * ```\n */\nexport function eden<T>(client: Client): EdenClient<T> {\n // 获取 baseURL 用于 SSE\n const baseURL = client.baseURL\n \n // SSE 默认 headers(空对象,用户通过中间件添加)\n const defaultHeaders: Record<string, string> = {}\n\n // 请求函数:委托给 client\n async function request<TReturn>(\n method: string,\n path: string,\n data?: unknown,\n requestConfig?: RequestConfig\n ): Promise<ApiResponse<TReturn>> {\n return client.request<TReturn>(method, path, data, requestConfig)\n }\n\n function subscribe<TData>(\n path: string,\n query: Record<string, unknown> | undefined,\n callbacks: SSECallbacks<TData>,\n options?: SSESubscribeOptions\n ): SSESubscription<TData> {\n const url = new URL(path, baseURL)\n \n if (query) {\n for (const [key, value] of Object.entries(query)) {\n if (value !== undefined && value !== null) {\n url.searchParams.set(key, String(value))\n }\n }\n }\n\n let abortController: AbortController | null = new AbortController()\n let connected = false\n let reconnectCount = 0\n let isUnsubscribed = false\n let lastEventId: string | undefined\n \n const reconnectInterval = options?.reconnectInterval ?? 3000\n const maxReconnects = options?.maxReconnects ?? 5\n\n const connect = async () => {\n if (isUnsubscribed) return\n \n try {\n abortController = new AbortController()\n \n const headers: Record<string, string> = {\n 'Accept': 'text/event-stream',\n ...defaultHeaders,\n ...options?.headers,\n }\n \n if (lastEventId) {\n headers['Last-Event-ID'] = lastEventId\n }\n \n const response = await fetch(url.toString(), {\n method: 'GET',\n headers,\n signal: abortController.signal,\n })\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}`)\n }\n\n if (!response.body) {\n throw new Error('No response body')\n }\n\n connected = true\n reconnectCount = 0\n callbacks.onOpen?.()\n\n const reader = response.body.getReader()\n \n for await (const event of parseSSEStream(reader)) {\n if (event.id) {\n lastEventId = event.id\n }\n \n if (event.event === 'error') {\n callbacks.onError?.({ code: -1, message: String(event.data) })\n } else {\n callbacks.onMessage(event.data as TData)\n }\n }\n\n connected = false\n callbacks.onClose?.()\n \n } catch (error) {\n connected = false\n \n if ((error as Error).name === 'AbortError' || isUnsubscribed) {\n return\n }\n \n const err = error instanceof Error ? error : new Error(String(error))\n callbacks.onError?.({ code: 0, message: err.message || 'SSE 连接错误' })\n \n if (reconnectCount < maxReconnects) {\n reconnectCount++\n callbacks.onReconnect?.(reconnectCount, maxReconnects)\n \n setTimeout(() => {\n if (!isUnsubscribed) {\n connect()\n }\n }, reconnectInterval)\n } else {\n callbacks.onMaxReconnects?.()\n }\n }\n }\n\n connect()\n\n return {\n unsubscribe: () => {\n isUnsubscribed = true\n abortController?.abort()\n abortController = null\n connected = false\n },\n get connected() {\n return connected\n }\n }\n }\n\n function createEndpoint(basePath: string): unknown {\n const methods = ['get', 'post', 'put', 'patch', 'delete']\n \n const handler = (params: Record<string, string>) => {\n const paramValue = Object.values(params)[0]\n const newPath = `${basePath}/${encodeURIComponent(paramValue)}`\n return createEndpoint(newPath)\n }\n\n return new Proxy(handler as unknown as object, {\n get(_, prop: string) {\n if (methods.includes(prop)) {\n const httpMethod = prop.toUpperCase()\n return (data?: unknown, cfg?: RequestConfig) => {\n return request(httpMethod, basePath, data, cfg)\n }\n }\n \n if (prop === 'subscribe') {\n return <TData>(\n queryOrCallbacks: Record<string, unknown> | SSECallbacks<TData>,\n callbacksOrOptions?: SSECallbacks<TData> | SSESubscribeOptions,\n options?: SSESubscribeOptions\n ) => {\n // 判断是否是 callbacks:onMessage 必须是函数\n const isCallbacks = typeof queryOrCallbacks === 'object' \n && 'onMessage' in queryOrCallbacks \n && typeof queryOrCallbacks.onMessage === 'function'\n \n if (isCallbacks) {\n return subscribe<TData>(\n basePath, \n undefined, \n queryOrCallbacks as SSECallbacks<TData>,\n callbacksOrOptions as SSESubscribeOptions\n )\n } else {\n return subscribe<TData>(\n basePath,\n queryOrCallbacks as Record<string, unknown>,\n callbacksOrOptions as SSECallbacks<TData>,\n options\n )\n }\n }\n }\n \n const childPath = `${basePath}/${prop}`\n return createEndpoint(childPath)\n },\n apply(_, __, args) {\n const params = args[0] as Record<string, string>\n const paramValue = Object.values(params)[0]\n const newPath = `${basePath}/${encodeURIComponent(paramValue)}`\n return createEndpoint(newPath)\n }\n })\n }\n\n return new Proxy({} as EdenClient<T>, {\n get(_, prop: string) {\n return createEndpoint(`/${prop}`)\n }\n })\n}\n","/**\n * 超时中间件\n * \n * 为请求设置超时限制\n */\n\nimport type { Middleware, NamedMiddleware } from '../types'\n\n/**\n * 创建超时中间件\n * \n * @param ms 超时时间(毫秒)\n * @returns 超时中间件\n * \n * @example\n * ```typescript\n * const client = createClient(BASE_URL)\n * .use(timeoutMiddleware(30000)) // 30 秒超时\n * ```\n */\nexport function timeoutMiddleware(ms: number): NamedMiddleware {\n const middleware: Middleware = async (ctx, next) => {\n // 如果请求配置中有超时,优先使用\n const timeout = ctx.config?.timeout ?? ms\n \n // 创建超时 Promise\n const timeoutPromise = new Promise<never>((_, reject) => {\n setTimeout(() => {\n reject(new Error(`请求超时 (${timeout}ms)`))\n }, timeout)\n })\n \n // 竞争:请求 vs 超时\n try {\n const response = await Promise.race([\n next(),\n timeoutPromise,\n ])\n return response\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error))\n return {\n request: ctx,\n raw: null,\n data: null,\n error: { code: 408, message: err.message },\n status: 408,\n }\n }\n }\n \n // 添加名称\n const named = middleware as NamedMiddleware\n named.middlewareName = 'timeout'\n return named\n}\n","/**\n * 重试中间件\n * \n * 自动重试失败的请求\n */\n\nimport type { Middleware, NamedMiddleware, ResponseContext } from '../types'\n\n/**\n * 重试配置\n */\nexport interface RetryOptions {\n /** 重试次数,默认 3 */\n count?: number\n /** 重试延迟(毫秒),默认 1000 */\n delay?: number\n /** 指数退避,默认 true */\n backoff?: boolean\n /** 触发重试的状态码,默认 [408, 429, 500, 502, 503, 504] */\n on?: number[]\n /** 自定义重试判断 */\n shouldRetry?: (ctx: ResponseContext) => boolean\n}\n\n/** 默认重试状态码 */\nconst DEFAULT_RETRY_STATUS = [408, 429, 500, 502, 503, 504]\n\n/**\n * 延迟执行\n */\nfunction sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms))\n}\n\n/**\n * 创建重试中间件\n * \n * @param options 重试配置\n * @returns 重试中间件\n * \n * @example\n * ```typescript\n * const client = createClient(BASE_URL)\n * .use(retryMiddleware({ count: 3, delay: 1000 }))\n * ```\n */\nexport function retryMiddleware(options?: RetryOptions): NamedMiddleware {\n const {\n count = 3,\n delay = 1000,\n backoff = true,\n on = DEFAULT_RETRY_STATUS,\n shouldRetry,\n } = options ?? {}\n\n const middleware: Middleware = async (ctx, next) => {\n let lastResponse: ResponseContext | null = null\n let attempt = 0\n\n while (attempt <= count) {\n // 更新重试次数\n ctx.retryCount = attempt\n\n // 执行请求\n const response = await next()\n lastResponse = response\n\n // 成功或不需要重试\n if (!response.error) {\n return response\n }\n\n // 检查是否需要重试\n const needRetry = shouldRetry\n ? shouldRetry(response)\n : on.includes(response.status)\n\n if (!needRetry || attempt >= count) {\n return response\n }\n\n // 计算延迟(支持指数退避)\n const waitTime = backoff ? delay * Math.pow(2, attempt) : delay\n await sleep(waitTime)\n\n attempt++\n }\n\n // 返回最后一次响应\n return lastResponse!\n }\n\n // 添加名称\n const named = middleware as NamedMiddleware\n named.middlewareName = 'retry'\n return named\n}\n","/**\n * 日志中间件\n * \n * 记录请求和响应信息\n */\n\nimport type { Middleware, NamedMiddleware, RequestContext, ResponseContext } from '../types'\n\n/**\n * 日志配置\n */\nexport interface LoggerOptions {\n /** 请求日志回调 */\n onRequest?: (ctx: RequestContext) => void\n /** 响应日志回调 */\n onResponse?: (ctx: ResponseContext) => void\n /** 是否启用控制台日志,默认 true */\n console?: boolean\n /** 日志前缀 */\n prefix?: string\n}\n\n/**\n * 创建日志中间件\n * \n * @param options 日志配置\n * @returns 日志中间件\n * \n * @example\n * ```typescript\n * // 使用默认控制台日志\n * const client = createClient(BASE_URL)\n * .use(loggerMiddleware())\n * \n * // 自定义日志\n * const client = createClient(BASE_URL)\n * .use(loggerMiddleware({\n * onRequest: (ctx) => console.log(`[REQ] ${ctx.method} ${ctx.path}`),\n * onResponse: (ctx) => console.log(`[RES] ${ctx.status} ${ctx.request.path}`),\n * }))\n * ```\n */\nexport function loggerMiddleware(options?: LoggerOptions): NamedMiddleware {\n const {\n onRequest,\n onResponse,\n console: useConsole = true,\n prefix = '[API]',\n } = options ?? {}\n\n const middleware: Middleware = async (ctx, next) => {\n const startTime = Date.now()\n\n // 请求日志\n if (onRequest) {\n onRequest(ctx)\n }\n if (useConsole) {\n console.log(`${prefix} → ${ctx.method} ${ctx.path}`)\n }\n\n // 执行请求\n const response = await next()\n\n // 响应日志\n const duration = Date.now() - startTime\n if (onResponse) {\n onResponse(response)\n }\n if (useConsole) {\n const status = response.error ? `ERR ${response.error.code}` : `${response.status}`\n console.log(`${prefix} ← ${status} ${ctx.path} (${duration}ms)`)\n }\n\n return response\n }\n\n // 添加名称\n const named = middleware as NamedMiddleware\n named.middlewareName = 'logger'\n return named\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vafast/api-client",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.7",
|
|
4
4
|
"description": "Type-safe API client for Vafast framework",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"files": [
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"vafast": "^0.5.1"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
|
+
"@types/qs": "^6.14.0",
|
|
20
21
|
"tsdown": "^0.19.0-beta.4",
|
|
21
22
|
"typescript": "^5.5.3",
|
|
22
23
|
"vafast": "^0.5.6",
|
|
@@ -51,5 +52,8 @@
|
|
|
51
52
|
"email": "team@vafast.dev"
|
|
52
53
|
},
|
|
53
54
|
"homepage": "https://github.com/vafast/vafast-api-client",
|
|
54
|
-
"bugs": "https://github.com/vafast/vafast-api-client/issues"
|
|
55
|
+
"bugs": "https://github.com/vafast/vafast-api-client/issues",
|
|
56
|
+
"dependencies": {
|
|
57
|
+
"qs": "^6.14.1"
|
|
58
|
+
}
|
|
55
59
|
}
|