@vafast/api-client 0.3.4 → 0.3.6

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
@@ -11,6 +11,25 @@
11
11
  - 📡 **SSE 支持** - 流式响应、自动重连
12
12
  - 🎨 **Go 风格错误** - `{ data, error }` 统一处理
13
13
 
14
+ ## 业界对比
15
+
16
+ | 特性 | **@vafast/api-client** | Elysia Eden | tRPC | OpenAPI Generator | Axios / ky |
17
+ |-----|------------------------|------------|------|-------------------|------------|
18
+ | **类型安全** | ✅ 完整(契约/代码生成) | ✅ 完整(类型推断) | ✅ 完整 | ⚠️ 生成代码 | ❌ |
19
+ | **API 风格** | Eden 链式 | Eden 链式(Treaty) | RPC query/mutation | REST 传统 | REST 传统 |
20
+ | **SSE 支持** | ✅ 全方法 + body + 链式 `.sse()` | ✅ 有(subscribe) | ⚠️ 仅 subscription | ❌ | ❌ |
21
+ | **SSE 走中间件** | ✅ 与普通请求一致 | ⚠️ 视实现 | - | - | - |
22
+ | **中间件/拦截器** | ✅ Koa 洋葱模型 | ⚠️ 简单 | ❌ | ❌ | ✅ 拦截器 |
23
+ | **代码生成** | ✅ vafast-cli 从服务端生成 | ❌ 无需(同构) | ❌ 无需(同构) | ✅ 多语言 | ❌ |
24
+ | **框架绑定** | 无(任意后端) | 需 Elysia 服务端 | 需 tRPC 服务端 | 无 | 无 |
25
+
26
+ **与 Elysia Eden 的差异**:
27
+
28
+ - **Eden**:与 Elysia 同构,服务端用 Elysia 时类型自动同步,零代码生成;SSE 用 `subscribe()`,流式能力与类型推断在部分场景有已知问题。
29
+ - **本库**:与具体后端框架解耦,通过 vafast 契约或 vafast-cli 生成类型;SSE 与普通请求统一为链式调用(如 `api.xxx.post(body).sse(callbacks)`),且 **SSE 请求走完整中间件链**(认证、日志等与普通请求一致);支持 GET/POST/PUT/PATCH/DELETE 全方法 + body 的 SSE。
30
+
31
+ 若后端已是 Elysia,可优先用 Eden;若后端是 vafast 或其他框架、或需要强中间件 + 全方法 SSE,本库更合适。
32
+
14
33
  ## 安装
15
34
 
16
35
  ```bash
@@ -52,11 +71,12 @@ console.log(data.users)
52
71
  | `api.users.find.post({ page })` | POST /users/find |
53
72
  | `api.videoGeneration.delete.post({ id })` | POST /videoGeneration/delete |
54
73
  | `api.users({ id: '123' }).get()` | GET /users/123 |
55
- | `api.chat.stream.sse(callbacks)` | SSE /chat/stream |
74
+ | `api.events.get({ channel }).sse(callbacks)` | GET SSE /events |
75
+ | `api.chat.stream.post(body).sse(callbacks)` | POST SSE /chat/stream |
56
76
 
57
77
  **规则**:
58
78
  - `get`, `post`, `put`, `patch`, `delete` → HTTP 方法
59
- - `sse` → SSE 订阅
79
+ - `.sse()` → 链式调用,转换为 SSE 订阅
60
80
  - 其他 → 路径段
61
81
 
62
82
  这样即使路径名是 `delete`、`get` 等,也不会与 HTTP 方法冲突。
@@ -101,6 +121,37 @@ const client = createClient({ baseURL: '/api', timeout: 30000 })
101
121
  .use(retryMiddleware({ count: 3 }))
102
122
  ```
103
123
 
124
+ ### client.requestRaw()
125
+
126
+ 发起原始请求,返回 Response 对象(不解析 JSON)。用于 SSE、流式下载等需要直接处理响应流的场景。
127
+
128
+ ```typescript
129
+ const client = createClient('http://localhost:3000')
130
+ .use(authMiddleware) // 中间件对 requestRaw 同样有效
131
+
132
+ // 发起原始请求(走完整中间件链)
133
+ const response = await client.requestRaw('GET', '/api/stream', null, {
134
+ query: { channel: 'updates' }
135
+ })
136
+
137
+ // 直接处理响应流
138
+ const reader = response.body.getReader()
139
+ for await (const chunk of readStream(reader)) {
140
+ console.log(chunk)
141
+ }
142
+ ```
143
+
144
+ **签名:**
145
+
146
+ ```typescript
147
+ requestRaw(
148
+ method: string,
149
+ path: string,
150
+ body?: unknown,
151
+ config?: RequestConfig
152
+ ): Promise<Response>
153
+ ```
154
+
104
155
  ### eden<T>(client)
105
156
 
106
157
  将 Client 实例包装为类型安全的 API 调用。
@@ -168,10 +219,16 @@ type MyApi = {
168
219
  delete: { return: { success: boolean } }
169
220
  }
170
221
  }
171
- // SSE 方法:作为一等公民
222
+ // SSE:使用普通 HTTP 方法 + .sse() 链式调用
223
+ events: {
224
+ get: { query: { channel: string }; return: EventData }
225
+ }
172
226
  chat: {
173
227
  stream: {
174
- sse: { query: { prompt: string }; return: { text: string } }
228
+ post: { // POST SSE
229
+ body: { messages: Message[] }
230
+ return: { content: string }
231
+ }
175
232
  }
176
233
  }
177
234
  }
@@ -311,13 +368,24 @@ const { data, error } = await api.users.get(
311
368
  const { data, error } = await api.users.get()
312
369
 
313
370
  if (error) {
314
- // error: { code: number; message: string }
315
- switch (error.code) {
316
- case 401:
317
- redirectToLogin()
371
+ // error: { code: number; message: string; type?: ErrorType }
372
+ console.log(`错误类型: ${error.type}`) // 'network' | 'timeout' | 'abort' | 'server' | 'unknown'
373
+
374
+ switch (error.type) {
375
+ case 'network':
376
+ showOfflineMessage()
318
377
  break
319
- case 403:
320
- showPermissionDenied()
378
+ case 'timeout':
379
+ showTimeoutMessage()
380
+ break
381
+ case 'abort':
382
+ // 用户取消,不需要处理
383
+ break
384
+ case 'server':
385
+ // 服务端错误,根据 code 处理
386
+ if (error.code === 401) redirectToLogin()
387
+ else if (error.code === 403) showPermissionDenied()
388
+ else showError(error.message)
321
389
  break
322
390
  default:
323
391
  showError(error.message)
@@ -329,22 +397,101 @@ if (error) {
329
397
  console.log(data.users)
330
398
  ```
331
399
 
400
+ ### 错误类型说明
401
+
402
+ | 类型 | 说明 | code |
403
+ |------|------|------|
404
+ | `network` | 网络错误(无法连接) | 0 |
405
+ | `timeout` | 请求超时 | 408 |
406
+ | `abort` | 请求被取消 | 0 |
407
+ | `server` | 服务端错误(4xx/5xx) | HTTP 状态码 |
408
+ | `unknown` | 未知错误 | 0 |
409
+
332
410
  ## SSE 流式响应
333
411
 
334
- `sse` 是一等公民方法,与 `get`/`post` HTTP 方法平级:
412
+ SSE 通过**链式调用**实现:普通 HTTP 方法后接 `.sse()`。
413
+
414
+ ### 基本用法
415
+
416
+ ```typescript
417
+ const api = eden<Api>(client)
418
+
419
+ // 普通请求(直接 await)
420
+ const result = await api.users.get({ page: 1 })
421
+
422
+ // SSE 请求(链式调用 .sse())
423
+ api.chat.stream.post({ message: 'hi' }).sse({
424
+ onMessage: (data) => console.log(data),
425
+ onClose: () => console.log('done')
426
+ })
427
+ ```
428
+
429
+ ### 懒执行
430
+
431
+ RequestBuilder 采用**懒执行**设计:
432
+
433
+ ```typescript
434
+ // 创建 builder 时不发起请求
435
+ const builder = api.users.get({ page: 1 })
436
+
437
+ // await 时才发起普通请求
438
+ await builder
439
+
440
+ // 或调用 .sse() 发起 SSE 请求
441
+ builder.sse({ onMessage })
442
+ ```
443
+
444
+ ### 中间件支持
445
+
446
+ **SSE 请求走完整的中间件链**,与普通请求一样。认证、日志、错误处理等中间件都会自动生效:
447
+
448
+ ```typescript
449
+ const client = createClient('http://localhost:3000')
450
+ .use(async (ctx, next) => {
451
+ // 这个中间件对 SSE 请求同样有效!
452
+ ctx.headers.set('Authorization', `Bearer ${token}`)
453
+ console.log(`[${ctx.method}] ${ctx.path}`)
454
+ return next()
455
+ })
456
+
457
+ const api = eden<Api>(client)
458
+
459
+ // SSE 请求会自动带上 Authorization header
460
+ api.chat.stream.post({ message: '你好' }).sse({
461
+ onMessage: console.log
462
+ })
463
+ ```
335
464
 
336
465
  ### 契约定义
337
466
 
338
467
  ```typescript
339
- // sse 作为独立方法定义(简洁直观)
340
468
  type Api = {
469
+ // GET SSE - 事件订阅
470
+ events: {
471
+ get: { query: { channel: string }; return: { type: string; data: unknown } }
472
+ }
473
+
474
+ // POST SSE - AI 对话
341
475
  chat: {
342
476
  stream: {
343
- sse: { query: { prompt: string }; return: { text: string } }
477
+ post: {
478
+ body: { messages: Array<{ role: string; content: string }> }
479
+ return: { content?: string; done?: boolean }
480
+ }
344
481
  }
345
482
  }
346
- events: {
347
- sse: { return: { type: string; data: unknown } } // query 参数
483
+
484
+ // DELETE SSE - 批量删除进度
485
+ batch: {
486
+ delete: {
487
+ body: { ids: string[] }
488
+ return: { deleted: number; total: number }
489
+ }
490
+ }
491
+
492
+ // 无参数 SSE
493
+ heartbeat: {
494
+ get: { return: { ping: string } }
348
495
  }
349
496
  }
350
497
  ```
@@ -354,29 +501,68 @@ type Api = {
354
501
  ```typescript
355
502
  const api = eden<Api>(client)
356
503
 
357
- // query 参数
358
- const subscription = api.chat.stream.sse(
359
- { prompt: '你好' }, // query 参数
360
- {
361
- onMessage: (data) => console.log('收到:', data.text),
362
- onError: (error) => console.error('错误:', error),
363
- onOpen: () => console.log('连接建立'),
364
- onClose: () => console.log('连接关闭'),
365
- onReconnect: (attempt, max) => console.log(`重连 ${attempt}/${max}`)
504
+ // GET SSE - 事件订阅
505
+ api.events.get({ channel: 'news' }).sse({
506
+ onMessage: (data) => console.log(data)
507
+ })
508
+
509
+ // POST SSE - AI 对话
510
+ api.chat.stream.post({ messages: [{ role: 'user', content: '你好' }] }).sse({
511
+ onMessage: (data) => {
512
+ if (data.content) process.stdout.write(data.content)
513
+ if (data.done) console.log('\n[完成]')
366
514
  },
367
- {
368
- reconnectInterval: 3000,
369
- maxReconnects: 5
370
- }
371
- )
515
+ onError: (error) => console.error('错误:', error),
516
+ onOpen: () => console.log('连接建立'),
517
+ onClose: () => console.log('连接关闭')
518
+ })
372
519
 
373
- // query 参数
374
- const eventSub = api.events.sse({
375
- onMessage: (data) => console.log('事件:', data.type)
520
+ // DELETE SSE - 批量删除进度
521
+ api.batch.delete({ ids: ['1', '2', '3'] }).sse({
522
+ onMessage: (data) => console.log(`删除进度: ${data.deleted}/${data.total}`)
523
+ })
524
+
525
+ // POST + query 参数
526
+ api.search.post({ query: 'TypeScript' }, { query: { page: 2 } }).sse({
527
+ onMessage: (data) => console.log(data.results)
528
+ })
529
+
530
+ // 无参数 SSE
531
+ api.heartbeat.get().sse({ onMessage: console.log })
532
+
533
+ // 带路径参数
534
+ api.rooms({ id: 'room-123' }).messages.get().sse({
535
+ onMessage: (data) => console.log(data)
376
536
  })
377
537
 
378
538
  // 取消订阅
379
- subscription.unsubscribe()
539
+ const sub = api.events.get({ channel: 'live' }).sse({ onMessage: console.log })
540
+ sub.unsubscribe()
541
+ ```
542
+
543
+ ### SSE 回调
544
+
545
+ ```typescript
546
+ interface SSECallbacks<T> {
547
+ onMessage: (data: T) => void // 必需:接收消息
548
+ onError?: (error: ApiError) => void // 错误处理
549
+ onOpen?: () => void // 连接建立
550
+ onClose?: () => void // 连接关闭
551
+ onReconnect?: (attempt: number, max: number) => void // 重连中
552
+ onMaxReconnects?: () => void // 达到最大重连次数
553
+ }
554
+ ```
555
+
556
+ ### SSE 选项
557
+
558
+ SSE 回调中还可以传递以下选项:
559
+
560
+ ```typescript
561
+ interface SSECallbackOptions {
562
+ reconnect?: boolean // 是否自动重连,默认 true
563
+ reconnectInterval?: number // 重连间隔(ms),默认 3000
564
+ maxReconnects?: number // 最大重连次数,默认 5
565
+ }
380
566
  ```
381
567
 
382
568
  ## 请求取消
@@ -420,6 +606,8 @@ HTTP 401 Unauthorized
420
606
 
421
607
  ### ❌ 不推荐:全部返回 200 + success 字段
422
608
 
609
+ **本库不推荐**将业务错误也通过 HTTP 200 返回、用 `success` 等字段表示成败的做法。应使用 HTTP 状态码表达错误(见上节)。
610
+
423
611
  ```json
424
612
  HTTP 200 OK
425
613
 
@@ -430,6 +618,8 @@ HTTP 200 OK
430
618
  }
431
619
  ```
432
620
 
621
+ 上述写法会导致监控、缓存、重试、调试都难以按 HTTP 语义工作,仅在后端无法改动时用中间件做兼容(见下节)。
622
+
433
623
  ### 为什么 HTTP 状态码更好?
434
624
 
435
625
  | 方面 | HTTP 状态码 | 全部 200 |
package/dist/index.d.mts CHANGED
@@ -4,6 +4,10 @@
4
4
  */
5
5
  /** HTTP 方法 */
6
6
  type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS';
7
+ /**
8
+ * 错误类型枚举
9
+ */
10
+ type ErrorType = 'network' | 'timeout' | 'abort' | 'server' | 'parse' | 'unknown';
7
11
  /**
8
12
  * API 错误 - Go 风格结构化错误
9
13
  */
@@ -12,6 +16,8 @@ interface ApiError {
12
16
  code: number;
13
17
  /** 错误消息 */
14
18
  message: string;
19
+ /** 错误类型(便于分类处理) */
20
+ type?: ErrorType;
15
21
  }
16
22
  /**
17
23
  * API 响应 - Go 风格
@@ -124,6 +130,19 @@ interface Client {
124
130
  headers(h: Record<string, string>): Client;
125
131
  /** 设置默认超时 */
126
132
  timeout(ms: number): Client;
133
+ /**
134
+ * 发起原始请求(返回 Response 对象,不解析 JSON)
135
+ *
136
+ * 用于 SSE/流式请求等需要直接处理响应流的场景
137
+ * 请求会完整走中间件链,但响应不会被解析
138
+ *
139
+ * @param method - HTTP 方法
140
+ * @param path - 请求路径
141
+ * @param body - 请求体
142
+ * @param config - 请求配置
143
+ * @returns 原始 Response 对象
144
+ */
145
+ requestRaw(method: string, path: string, body?: unknown, config?: RequestConfig): Promise<Response>;
127
146
  /** 发起请求 */
128
147
  request<T = unknown>(method: string, path: string, body?: unknown, config?: RequestConfig): Promise<ApiResponse<T>>;
129
148
  }
@@ -170,6 +189,10 @@ interface SSEEvent<T = unknown> {
170
189
  retry?: number;
171
190
  }
172
191
  interface SSESubscribeOptions {
192
+ /** HTTP 方法,默认 GET。有 body 时建议使用 POST/PUT/PATCH/DELETE */
193
+ method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
194
+ /** 额外的 URL 查询参数(与 body 一起使用时) */
195
+ query?: Record<string, unknown>;
173
196
  headers?: Record<string, string>;
174
197
  reconnectInterval?: number;
175
198
  maxReconnects?: number;
@@ -296,11 +319,6 @@ interface MethodDef {
296
319
  params?: unknown;
297
320
  return: unknown;
298
321
  }
299
- /** SSE 方法定义(独立于 HTTP 方法) */
300
- interface SSEMethodDef {
301
- query?: unknown;
302
- return: unknown;
303
- }
304
322
  interface SSECallbacks<T> {
305
323
  onMessage: (data: T) => void;
306
324
  onError?: (error: ApiError) => void;
@@ -309,25 +327,40 @@ interface SSECallbacks<T> {
309
327
  onReconnect?: (attempt: number, maxAttempts: number) => void;
310
328
  onMaxReconnects?: () => void;
311
329
  }
312
- /** HTTP 方法调用签名 */
330
+ /**
331
+ * SSE 回调选项(链式调用时只需要传这些)
332
+ */
333
+ type SSECallbackOptions = Omit<SSESubscribeOptions, 'method' | 'query'>;
334
+ /**
335
+ * 请求构建器 - 支持普通请求和 SSE 链式调用
336
+ *
337
+ * @example
338
+ * ```typescript
339
+ * // 普通请求(直接 await)
340
+ * const result = await api.users.get({ page: 1 })
341
+ *
342
+ * // SSE 请求(链式调用 .sse())
343
+ * api.chat.stream.post({ message: 'hi' }).sse({
344
+ * onMessage: (data) => console.log(data),
345
+ * onClose: () => console.log('done')
346
+ * })
347
+ * ```
348
+ */
349
+ interface RequestBuilder<T> extends PromiseLike<ApiResponse<T>> {
350
+ /** 转换为 SSE 订阅 */
351
+ sse(callbacks: SSECallbacks<T> & SSECallbackOptions): SSESubscription<T>;
352
+ }
353
+ /** HTTP 方法调用签名 - 返回 RequestBuilder(可 await 或 .sse()) */
313
354
  type HTTPMethodCall<M$1 extends MethodDef, HasParams extends boolean = false> = HasParams extends true ? M$1 extends {
314
355
  body: infer B;
315
- } ? (body: B, config?: RequestConfig) => Promise<ApiResponse<M$1['return']>> : (config?: RequestConfig) => Promise<ApiResponse<M$1['return']>> : M$1 extends {
356
+ } ? (body: B, config?: RequestConfig) => RequestBuilder<M$1['return']> : (config?: RequestConfig) => RequestBuilder<M$1['return']> : M$1 extends {
316
357
  query: infer Q;
317
- } ? (query?: Q, config?: RequestConfig) => Promise<ApiResponse<M$1['return']>> : M$1 extends {
358
+ } ? (query?: Q, config?: RequestConfig) => RequestBuilder<M$1['return']> : M$1 extends {
318
359
  body: infer B;
319
- } ? (body: B, config?: RequestConfig) => Promise<ApiResponse<M$1['return']>> : (config?: RequestConfig) => Promise<ApiResponse<M$1['return']>>;
320
- /** SSE 方法调用签名 */
321
- type SSEMethodCall<M$1 extends SSEMethodDef> = M$1 extends {
322
- query: infer Q;
323
- } ? (query: Q, callbacks: SSECallbacks<M$1['return']>, options?: SSESubscribeOptions) => SSESubscription<M$1['return']> : (callbacks: SSECallbacks<M$1['return']>, options?: SSESubscribeOptions) => SSESubscription<M$1['return']>;
324
- /** 端点类型:HTTP 方法 + SSE 方法 */
325
- type Endpoint<T, HasParams extends boolean = false> = { [K in 'get' | 'post' | 'put' | 'patch' | 'delete' | 'head' | 'options' as T extends { [P in K]: MethodDef } ? K : never]: T extends { [P in K]: infer M extends MethodDef } ? HTTPMethodCall<M, HasParams> : never } & (T extends {
326
- sse: infer M extends SSEMethodDef;
327
- } ? {
328
- sse: SSEMethodCall<M>;
329
- } : {});
330
- type HTTPMethods = 'get' | 'post' | 'put' | 'patch' | 'delete' | 'head' | 'options' | 'sse';
360
+ } ? (body: B, config?: RequestConfig) => RequestBuilder<M$1['return']> : (config?: RequestConfig) => RequestBuilder<M$1['return']>;
361
+ /** 端点类型:HTTP 方法(SSE 通过 .sse() 链式调用) */
362
+ type Endpoint<T, HasParams extends boolean = false> = { [K in 'get' | 'post' | 'put' | 'patch' | 'delete' | 'head' | 'options' as T extends { [P in K]: MethodDef } ? K : never]: T extends { [P in K]: infer M extends MethodDef } ? HTTPMethodCall<M, HasParams> : never };
363
+ type HTTPMethods = 'get' | 'post' | 'put' | 'patch' | 'delete' | 'head' | 'options';
331
364
  /**
332
365
  * 判断是否是路由节点(包含 HTTP 方法作为子键)
333
366
  * 路由节点结构:{ post: {...} } 或 { get: {...}, post: {...} }
@@ -459,5 +492,5 @@ interface LoggerOptions {
459
492
  */
460
493
  declare function loggerMiddleware(options?: LoggerOptions): NamedMiddleware;
461
494
  //#endregion
462
- 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 };
495
+ export { type ApiError, type ApiResponse, type Client, type ClientConfig, type EdenClient, type ErrorType, type HTTPMethod, type InferEden, type LoggerOptions, type Middleware, type MiddlewareOptions, type NamedMiddleware, type RequestBuilder, type RequestConfig, type RequestContext, type ResponseContext, type RetryOptions, type SSECallbackOptions, type SSECallbacks, type SSEEvent, type SSESubscribeOptions, type SSESubscription, createClient, defineMiddleware, eden, loggerMiddleware, retryMiddleware, timeoutMiddleware };
463
496
  //# sourceMappingURL=index.d.mts.map
@@ -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":";;AAOA;AAKA;AAoBA;AAYiB,KArCL,UAAA,GAqCkB,KAAA,GAAA,MAAA,GAAA,KAAA,GAAA,QAAA,GAAA,OAAA,GAAA,MAAA,GAAA,SAAA;;;;AAUpB,UA1CO,QAAA,CA0CP;EAAM;EAQC,IAAA,EAAA,MAAA;EAMV;EAEI,OAAA,EAAA,MAAA;;;;AAcX;;;;;;AA4BA;;;;;AAGK,UAnFY,WAmFZ,CAAA,IAAA,OAAA,CAAA,CAAA;EAAO;EAKK,IAAA,EAtFT,CAsFS,GAAA,IAAA;EAQA;EAUA,KAAA,EAtGR,QAsGc,GAAA,IAAA;;;;;AASV,UAvGI,aAAA,CAuGJ;EAAyB;EAGf,OAAA,CAAA,EAxGX,MAwGW,CAAA,MAAA,EAAA,MAAA,CAAA;EAOV;EACY,OAAA,CAAA,EAAA,MAAA;EAAZ;EAAR,MAAA,CAAA,EA5GM,WA4GN;EAAO;SA1GH;;UAEC;AC7BV;;;;AAGkB,UDkCD,cAAA,CClCC;EA0QD;EA2BD,MAAA,EAAA,MAAA;;;;EC3RC,GAAA,EF8BV,GE9BU;EAOA;EAOA,OAAA,EFkBN,OElBM;EAQZ;EAGA,IAAA,CAAA,EAAA,OAAA;EAAoB;EAA2C,MAAA,CAAA,EFWzD,aEXyD;EAAZ;EAAW,IAAA,EFa3D,GEb2D,CAAA,MAAA,EAAA,OAAA,CAAA;EAC9D;EAAmB,UAAA,EAAA,MAAA;;;;AAAyC;AACvC,UFmBT,eEnBS,CAAA,IAAA,OAAA,CAAA,CAAA;EAA4C;EAAZ,OAAA,EFqB/C,cErB+C;EAAW;EAMhE,GAAA,EFiBE,QEjBF,GAAA,IAAA;EAOA;EASA,IAAA,EFGG,CEHH,GAAA,IAAA;EAIA;EAAyB,KAAA,EFCrB,QEDqB,GAAA,IAAA;EAAK;EAAE,MAAA,EAAA,MAAA;;;;;AAAsC;;;;;;;;;;AAuBvE,KFFQ,UAAA,GEER,CAAA,GAAA,EFDG,cECH,EAAA,IAAA,EAAA,GAAA,GFAU,OEAV,CFAkB,eEAlB,CAAA,EAAA,GFCC,OEDD,CFCS,eEDT,CAAA;;;;AAMA,UFAa,eAAA,SAAwB,UEArC,CAAA;EAAK;EASJ,cAAS,CAAA,EAAA,MAAA;;;;;AAGe,UFJZ,iBAAA,CEIY;EAAQ;EAAxB,IAAA,CAAA,EAAA,MAAA;;;;;AACO,UFKH,MAAA,CELG;EACC;EAAjB,SAAA,OAAA,EAAA,MAAA;EACiB;EAAS,GAAA,CAAA,UAAA,EFQZ,UERY,CAAA,EFQC,MERD;EAC1B,GAAA,CAAA,IAAA,EAAA,MAAA,EAAA,UAAA,EFQ4B,UER5B,CAAA,EFQyC,MERzC;EACQ;EAAS,OAAA,CAAA,CAAA,EFUR,MEVQ,CAAA,MAAA,EAAA,MAAA,CAAA,CAAA,EFUiB,MEVjB;EACT;EAAe,OAAA,CAAA,EAAA,EAAA,MAAA,CAAA,EFYJ,MEZI;EAAS;EAAG,OAAA,CAAA,IAAA,OAAA,CAAA,CAAA,MAAA,EAAA,MAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,CAAA,EAAA,OAAA,EAAA,MAAA,CAAA,EFmB1B,aEnB0B,CAAA,EFoBlC,OEpBkC,CFoB1B,WEpB0B,CFoBd,CEpBc,CAAA,CAAA;AAAA;;;;;;AFpFvB,iBC7BA,gBAAA,CD6BA,EAAA,EC5BV,UD4BU,EAAA,OAAA,CAAA,EC3BJ,iBD2BI,CAAA,EC1Bb,eD0Ba;AAQhB;AAMO,UCkOU,YAAA,CDlOV;EAEI,OAAA,EAAA,MAAA;EAIA,OAAA,CAAA,EAAA,MAAA;EAEH,OAAA,CAAA,EC6NI,MD7NJ,CAAA,MAAA,EAAA,MAAA,CAAA;;AAQR;;;;;;AA4BA;;;;;;;AAQA;AAQA;AAUA;;;;;;AASsC,iBC8KtB,YAAA,CD9KsB,MAAA,EAAA,MAAA,GC8KQ,YD9KR,CAAA,EC8KuB,MD9KvB;;;AAHN,UE1Gf,QF0Ge,CAAA,IAAA,OAAA,CAAA,CAAA;EAAa,KAAA,CAAA,EAAA,MAAA;EAGhC,IAAA,EE3GL,CF2GK;EAAyB,EAAA,CAAA,EAAA,MAAA;EAGf,KAAA,CAAA,EAAA,MAAA;;AAQE,UEjHR,mBAAA,CFiHQ;EAAZ,OAAA,CAAA,EEhHD,MFgHC,CAAA,MAAA,EAAA,MAAA,CAAA;EAAR,iBAAA,CAAA,EAAA,MAAA;EAAO,aAAA,CAAA,EAAA,MAAA;;;UE1GK;ED3BD,WAAA,EAAA,GAAA,GAAgB,IAAA;EAC1B,SAAA,SAAA,EAAA,OAAA;;;KCkCD,WDhCa,CAAA,CAAA,CAAA,GCgCI,CDhCJ,SAAA;EA0QD,MAAA,EAAA,KAAA,EAAY;AA2B7B,CAAA,GAAgB,CAAA,GCrQ0C,CDqQ1C;;KClQX,sBAAoB;;AAzBzB,CAAA,GAyBwD,WAzB/B,CAyB2C,CAzB3C,CAAA,GAAA,SAEhB;AAKT,KAmBK,aAnBY,CAAA,GAAA,CAAA,GAmBO,GAnBP,SAAmB;EAOnB,IAAA,EAAA,KAAA,EAAA;AAGhB,CAAA,GASqD,WAJjD,CAI6D,CAJ7D,CAAW,GAAA,SAAA;AAA2C,KAKtD,eAFA,CAAc,GAAA,CAAA,GAEO,GAFP,SAAA;EAAM,MAAA,EAAA,KAAA,EAAA;CAA2C,GAEV,WAFU,CAEE,CAFF,CAAA,GAAA,SAAA;;;AAAD;;KAQ9D,kBAP6D,CAAA,GAAA,CAAA,GAOrC,GAPqC,UAAA,CAAA,GAAA,IAAA,EAAA,KAAA,EAAA,EAAA,GAAA,KAAA,EAAA,IAAA,CAAA,SAQpD,OARoD,CAAA,KAAA,EAAA,CAAA,GAAA,CAAA,GAAA,CAAA,GAAA,OAAA;;KAc7D,SAd4D,CAAA,YAAA,MAAA,CAAA,GAc9B,GAd8B,SAAA,IAAA,KAAA,EAAA,EAAA,GAAA,CAAA,GAcA,GAdA;AAAA;KAuB5D,gBAtBqB,CAAA,YAAA,MAAA,CAAA,GAsBgB,GAtBhB,SAAA,IAAA,MAAA,EAAA,GAAA,IAAA,GAAA,KAAA;KA0BrB,KA1BiE,CAAA,CAAA,CAAA,GAAA,QAAZ,MA0B5B,CA1B4B,IA0BvB,CA1BuB,CA0BrB,CA1BqB,CAAA,SAAA,SAAA,GAAA,KAAA,GA0BU,CA1BV,GA0Bc,CA1Bd,CA0BgB,CA1BhB,CAAA,EAAW;AAAA;AAOhD;AAM6C;AASvB;;;;;;;;AAIgC,KAmBtE,cAAA,CAAA,CAAc,CAAA,GAAM,CAAN,SAAA;EAAM,SAAA,MAAA,CAAA,EAAA,KAAA,QAAA;EAKC,SAAA,OAAA,EAAA,KAAA,SAAA;CAAf,GADP,KACO,CAAA;EACa,KAAA,EADb,cACa,CADE,OACF,CAAA;EAAd,IAAA,EAAA,aAAA,CAAc,OAAd,CAAA;EACkB,MAAA,EAAhB,eAAgB,CAAA,OAAA,CAAA;EAAhB,MAAA,EACA,kBADA,CACmB,QADnB,CAAA;CACmB,CAAA,GAE3B,KAF2B,CAAA;EAAnB,MAAA,EAGA,CAHA,SAAA;IAJR,SAAA,OAAA,EAAA,KAAA,EAAA;EAOQ,CAAA,GAA0C,kBAA1C,CAA6D,CAA7D,CAAA,GAAA,OAAA;CAA6D,CAAA;;;;AADhE;;KASJ,SAEgB,CAAA,aAAA,MAAA,EAAA,eAAA,MAAA,EAAA,GAAA,CAAA,GADnB,IACmB,SAAA,GAAA,KAAA,MAAA,IAAA,KAAA,KAAA,EAAA,GAAjB,gBAAiB,CAAA,KAAA,CAAA,SAAA,IAAA,GAAA;EAAjB,KAAA,EACS,SADT,CACmB,IADnB,EACyB,MADzB,EACiC,GADjC,CAAA;CACmB,GAAA,QACX,KADiB,GACT,SADS,CACC,IADD,EACO,MADP,EACe,GADf,CAAA,EAAQ,GAEjC,gBAFiC,CAEhB,IAFgB,CAAA,SAAA,IAAA,GAAA;EAAxB,KAAA,EAAA,QAGQ,MAFT,GAEkB,GAFlB,EAAkB;CAAM,GAGhC,IAHgC,SAAA,EAAA,GAAA,QAIxB,MAJgC,GAIvB,GAJuB,EAAxB,GAAA,QAKR,IAJS,GAAA,QAIM,MAJvB,GAIgC,GAJhC,EACiB,EAAS;;;;KAQzB,WALO,CAAA,CAAA,CAAA,GAKU,CALV,SAAA;EAAe,SAAA,MAAA,EAAA,KAAA,WAAA,MAAA;EAAS,SAAA,IAAA,EAAA,KAAA,WAAA,MAAA;CAAG,GASnC,SATmC,CASzB,SATyB,CASf,CATe,CAAA,EASX,SATW,CASD,CATC,CAAA,EASG,cATH,CASkB,CATlB,CAAA,CAAA,GAAA,CAAA,CAAA;AAAA,KAclC,SATA,CAAA,CAAA,EAAW,GAAA,CAAA,GAAA,QAAM,MAUR,CAVQ,GAAA,MAUE,GAVF,GAWpB,CAXoB,SAAA,MAWJ,CAXI,GAAA,MAWM,GAXN,GAYlB,CAZkB,CAYhB,CAZgB,CAAA,SAAA,MAAA,GAalB,GAbkB,CAahB,CAbgB,CAAA,SAAA,MAAA,GAclB,SAdkB,CAcR,CAdQ,CAcN,CAdM,CAAA,EAcF,GAdE,CAcA,CAdA,CAAA,CAAA,GAelB,CAfkB,CAehB,CAfgB,CAAA,GAeX,GAfW,CAeT,CAfS,CAAA,GAgBlB,CAhBkB,CAgBhB,CAhBgB,CAAA,GAgBX,GAhBW,CAgBT,CAhBS,CAAA,GAiBlB,CAjBkB,SAAA,MAiBF,CAjBE,GAkBlB,CAlBkB,CAkBhB,CAlBgB,CAAA,GAmBlB,CAnBkB,SAAA,MAmBF,GAnBE,GAoBlB,GApBkB,CAoBhB,CApBgB,CAAA,GAAA,KAAA,EAIE;;KAqBnB,WArBiC,CAAA,UAAA,SAAA,OAAA,EAAA,CAAA,GAsBpC,CAtBoC,SAAA,SAAA,CAAA,KAAA,MAAA,CAAA,GAuBlC,WAvBkC,CAuBtB,KAvBsB,CAAA,GAwBlC,CAxBkC,SAAA,SAAA,CAAA,KAAA,MAAA,EAAA,GAAA,KAAA,KAAA,CAAA,GAyBlC,SAzBkC,CAyBxB,WAzBwB,CAyBZ,KAzBY,CAAA,EAyBJ,WAzBI,CAyBQ,IAzBR,CAAA,CAAA,GAAA,CAAA,CAAA;;;;;;AAAzB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgBN;;AAOS,KA4CJ,SA5CI,CAAA,CAAA,CAAA,GA8Cd,CA9Cc,SAAA;EAAZ,QAAA,EAAA,KAAA,WAAA,SAAA,OAAA,EAAA;CACA,GA8CA,WA9CA,CA8CY,CA9CZ,CAAA,GAgDA,CAhDA,SAAA,SAAA,OAAA,EAAA,GAiDA,WAjDA,CAiDY,CAjDZ,CAAA,GAAA,CAAA,CAAA;;UAuDM,SAAA,CAtDI;EAAgC,KAAA,CAAA,EAAA,OAAA;EAAZ,IAAA,CAAA,EAAA,OAAA;EAA9B,MAAA,CAAA,EAAA,OAAA;EAAS,MAAA,EAAA,OAAA;AA0Cb;;UAoBU,YAAA,CAjBM;EAAZ,KAAA,CAAA,EAAA,OAAA;EAEA,MAAA,EAAA,OAAA;;UAmCM,YAlCN,CAAA,CAAA,CAAA,CAAA;EAAW,SAAA,EAAA,CAAA,IAAA,EAmCK,CAnCL,EAAA,GAAA,IAAA;EAML,OAAA,CAAA,EAAA,CAAA,KAAS,EA8BC,QA9BD,EAAA,GAAA,IAAA;EAQT,MAAA,CAAA,EAAA,GAAA,GAAY,IAAA;EAoBZ,OAAA,CAAA,EAAA,GAAA,GAAY,IAAA;EAUjB,WAAA,CAAA,EAAA,CAAA,OAAc,EAAA,MAAA,EAAA,WAAA,EAAA,MAAA,EAAA,GAAA,IAAA;EAAW,eAAA,CAAA,EAAA,GAAA,GAAA,IAAA;;;KAAzB,cAGM,CAAA,YAHmB,SAGnB,EAAA,kBAAA,OAAA,GAAA,KAAA,CAAA,GAFT,SAES,SAAA,IAAA,GADP,GACO,SAAA;EAAY,IAAA,EAAA,KAAA,EAAA;CAAsC,GAAA,CAAA,IAAA,EAAlD,CAAkD,EAAA,MAAA,CAAA,EAAtC,aAAsC,EAAA,GAApB,OAAoB,CAAZ,WAAY,CAAA,GAAA,CAAA,QAAA,CAAA,CAAA,CAAA,GAAA,CAAA,MAAA,CAAA,EAC/C,aAD+C,EAAA,GAC7B,OAD6B,CACrB,WADqB,CACT,GADS,CAAA,QAAA,CAAA,CAAA,CAAA,GAEzD,GAFyD,SAAA;EAAZ,KAAA,EAAA,KAAA,EAAA;CAAR,GAAA,CAAA,KAAA,CAAA,EAG5B,CAH4B,EAAA,MAAA,CAAA,EAGhB,aAHgB,EAAA,GAGE,OAHF,CAGU,WAHV,CAGsB,GAHtB,CAAA,QAAA,CAAA,CAAA,CAAA,GAIrC,GAJqC,SAAA;EAC3B,IAAA,EAAA,KAAA,EAAA;CAAsC,GAAA,CAAA,IAAA,EAIzC,CAJyC,EAAA,MAAA,CAAA,EAI7B,aAJ6B,EAAA,GAIX,OAJW,CAIH,WAJG,CAIS,GAJT,CAAA,QAAA,CAAA,CAAA,CAAA,GAAA,CAAA,MAAA,CAAA,EAKtC,aALsC,EAAA,GAKpB,OALoB,CAKZ,WALY,CAKA,GALA,CAAA,QAAA,CAAA,CAAA,CAAA;;KAQ/C,aAR2B,CAAA,YAQH,YARG,CAAA,GAS9B,GAT8B,SAAA;EAC5B,KAAA,EAAA,KAAA,EAAA;CACS,GAAA,CAAA,KAAA,EAQD,CARC,EAAA,SAAA,EAQa,YARb,CAQ0B,GAR1B,CAAA,QAAA,CAAA,CAAA,EAAA,OAAA,CAAA,EAQkD,mBARlD,EAAA,GAQ0E,eAR1E,CAQ0F,GAR1F,CAAA,QAAA,CAAA,CAAA,GAAA,CAAA,SAAA,EASG,YATH,CASgB,GAThB,CAAA,QAAA,CAAA,CAAA,EAAA,OAAA,CAAA,EASwC,mBATxC,EAAA,GASgE,eAThE,CASgF,GAThF,CAAA,QAAA,CAAA,CAAA;;KAYR,QAZ0D,CAAA,CAAA,EAAA,kBAAA,OAAA,GAAA,KAAA,CAAA,GAAA,QAAZ,KAAA,GAAA,MAAA,GAAA,KAAA,GAAA,OAAA,GAAA,QAAA,GAAA,MAAA,GAAA,SAAA,IAe2B,CAf3B,SAAA,QAe6C,CAfrD,GAeyD,SAfzD,EACvC,GAc8G,CAd9G,GAAA,KAAA,GAeA,CAfA,SAAA,QAekB,CAdX,GAAA,KAAA,WAc+B,SAd/B,EAAY,GAciC,cAdjC,CAcgD,CAdhD,EAcmD,SAdnD,CAAA,GAAA,KAAA,EAAsC,GAAA,CAiBxD,CAjBwD,SAAA;EAAZ,GAAA,EAAA,KAAA,WAiBX,YAjBW;CAAR,GAAA;EAC3B,GAAA,EAiBD,aAjBC,CAiBa,CAjBb,CAAA;CAAsC,GAAA,CAAA,CAAA,CAAA;KAoB/C,WAAA,GApBmC,KAAA,GAAA,MAAA,GAAA,KAAA,GAAA,OAAA,GAAA,QAAA,GAAA,MAAA,GAAA,SAAA,GAAA,KAAA;;;AAAD;;;KA2BlC,aAtBO,CAAA,CAAA,CAAA,GAsBY,CAtBZ,SAAA;EAA2B,GAAA,EAAA,OAAA;CAAb,GAAA;EAAqC,IAAA,EAAA,OAAA;CAAwC,GAAA;EAAhB,GAAA,EAAA,OAAA;CAC1D,GAAA;EAAb,KAAA,EAAA,OAAA;CAAqC,GAAA;EAAwC,MAAA,EAAA,OAAA;CAAhB,GAAA,IAAA,GAAA,KAAA;;AAAe;;;;;;KAgCvF,WAzBiB,CAAA,CAAA,CAAA,GAyBA,CAzBA,SAAA;EAAoB,MAAA,EAAA,OAAA;CAA6B,GA0BnE,aA1BmE,CA0BrD,CA1BqD,CAAA,SAAA,IAAA,GAAA,KAAA,GAAA,IAAA,GAAA,KAAA;KA6BlE,YA7BqE,CAAA,GAAA,EAAA,CAAA,CAAA,GA6BhD,GA7BgD,SAAA,IAAA,MAAA,EAAA,GAAA,IAAA,GA+BtE,GA/BsE,SA+B5D,WA/B4D,GAgCtE,WAhCsE,CAgC1D,CAhC0D,CAAA,GAAA,KAAA;AAAlB,KAmC5C,UAnC4C,CAAA,CAAA,EAAA,kBAAA,OAAA,GAAA,KAAA,CAAA,GAAA,QAGnD,MAiCS,CAjCT,IAiCc,YAjCd,CAiC2B,CAjC3B,EAiC8B,CAjC9B,CAiCgC,CAjChC,CAAA,CAAA,SAAA,IAAA,GAAA,KAAA,GAiC2D,CAjC3D,GAkCH,CAlCG,CAkCD,CAlCC,CAAA,SAAA;EAAiC,KAAA,EAAA,KAAA,MAAA;AACX,CAAA,GAAA,CAAA,CAAA,MAAA,EAkCb,MAlCa,CAAA,MAAA,EAAA,MAAA,CAAA,EAAA,GAkCc,UAlCd,CAkCyB,KAlCzB,EAAA,IAAA,CAAA,CAAA,GAkCyC,UAlCzC,CAkCoD,CAlCpD,CAkCsD,CAlCtD,CAAA,EAAA,KAAA,CAAA,GAmCvB,UAnCuB,CAmCZ,CAnCY,CAmCV,CAnCU,CAAA,EAAA,KAAA,CAAA,EAAd,GAoCT,QApCS,CAoCA,CApCA,EAoCG,SApCH,CAAA;AAAa;AAGV;AAOS;;;;;AAYR;;;;;;;AASjB;;;;AACqC,iBAgFrB,IAhFqB,CAAA,CAAA,CAAA,CAAA,MAAA,EAgFL,MAhFK,CAAA,EAgFI,UAhFJ,CAgFe,CAhFf,CAAA;;;;;;;AFpQrC;;;;;;AAsBA;;AAIO,iBGpES,iBAAA,CHoET,EAAA,EAAA,MAAA,CAAA,EGpEwC,eHoExC;;;;;;AAlCS,UI3CC,YAAA,CJ2CD;EAQC;EAMV,KAAA,CAAA,EAAA,MAAA;EAEI;EAIA,KAAA,CAAA,EAAA,MAAA;EAEH;EAAG,OAAA,CAAA,EAAA,OAAA;EAQM;EAEN,EAAA,CAAA,EAAA,MAAA,EAAA;EAEJ;EAEC,WAAA,CAAA,EAAA,CAAA,GAAA,EIrEc,eJqEd,EAAA,GAAA,OAAA;;;AAsBR;;;;;;;AAQA;AAQA;AAUA;;AAK+B,iBIjGf,eAAA,CJiGe,OAAA,CAAA,EIjGW,YJiGX,CAAA,EIjG0B,eJiG1B;;;;;;AAzFf,UK3CC,aAAA,CL2CD;EAQC;EAMV,SAAA,CAAA,EAAA,CAAA,GAAA,EKvDa,cLuDb,EAAA,GAAA,IAAA;EAEI;EAIA,UAAA,CAAA,EAAA,CAAA,GAAA,EK3DU,eL2DV,EAAA,GAAA,IAAA;EAEH;EAAG,OAAA,CAAA,EAAA,OAAA;EAQM;EAEN,MAAA,CAAA,EAAA,MAAA;;;;;AA0BX;;;;;;;AAQA;AAQA;AAUA;;;;;;;;AAmBa,iBKnHG,gBAAA,CLmHH,OAAA,CAAA,EKnH8B,aLmH9B,CAAA,EKnH8C,eLmH9C"}
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
@@ -62,14 +62,15 @@ function createSuccessResponse(data, ctx, raw) {
62
62
  /**
63
63
  * 创建错误响应
64
64
  */
65
- function createErrorResponse(code, message, ctx, raw = null) {
65
+ function createErrorResponse(code, message, ctx, raw = null, type = "unknown") {
66
66
  return {
67
67
  request: ctx,
68
68
  raw,
69
69
  data: null,
70
70
  error: {
71
71
  code,
72
- message
72
+ message,
73
+ type
73
74
  },
74
75
  status: raw?.status ?? 0
75
76
  };
@@ -114,12 +115,14 @@ var ClientImpl = class {
114
115
  this.defaultTimeout = ms;
115
116
  return this;
116
117
  }
117
- async request(method, path, body, config) {
118
- const baseURL = this.baseURL;
118
+ /**
119
+ * 构建请求上下文(公共逻辑)
120
+ */
121
+ buildContext(method, path, body, config) {
119
122
  const normalizedPath = path.startsWith("/") ? path : `/${path}`;
120
123
  const dummyURL = new URL("http://placeholder");
121
124
  dummyURL.pathname = normalizedPath;
122
- const hasBody = body && method.toUpperCase() !== "GET" && method.toUpperCase() !== "HEAD";
125
+ const hasBody = body !== void 0 && method !== "GET" && method !== "HEAD";
123
126
  const headers = new Headers({
124
127
  ...hasBody ? { "Content-Type": "application/json" } : {},
125
128
  ...this.defaultHeaders,
@@ -127,8 +130,8 @@ var ClientImpl = class {
127
130
  });
128
131
  const meta = /* @__PURE__ */ new Map();
129
132
  if (config?.meta) for (const [key, value] of Object.entries(config.meta)) meta.set(key, value);
130
- meta.set("baseURL", baseURL);
131
- const ctx = {
133
+ meta.set("baseURL", this.baseURL);
134
+ return {
132
135
  method: method.toUpperCase(),
133
136
  path,
134
137
  url: dummyURL,
@@ -138,8 +141,89 @@ var ClientImpl = class {
138
141
  meta,
139
142
  retryCount: 0
140
143
  };
144
+ }
145
+ /**
146
+ * 构建查询字符串
147
+ *
148
+ * 统一从 config.query 获取,语义清晰:
149
+ * - body 就是 body(请求体)
150
+ * - query 就是 query(URL 查询参数)
151
+ */
152
+ buildQueryString(ctx) {
153
+ const { config } = ctx;
154
+ if (config?.query && typeof config.query === "object") return qs.stringify(config.query, {
155
+ skipNulls: true,
156
+ arrayFormat: "indices"
157
+ });
158
+ return "";
159
+ }
160
+ /**
161
+ * 执行原始 fetch 请求(核心方法,不解析响应)
162
+ */
163
+ async doFetch(ctx, signal) {
164
+ const { method, path, headers, body, meta } = ctx;
165
+ const url = buildRequestURL(meta.get("baseURL") || this.baseURL, path, this.buildQueryString(ctx));
166
+ const fetchOptions = {
167
+ method,
168
+ headers,
169
+ signal
170
+ };
171
+ if (body !== void 0 && method !== "GET" && method !== "HEAD" && method !== "OPTIONS") fetchOptions.body = JSON.stringify(body);
172
+ const request = new Request(url, fetchOptions);
173
+ return fetch(request);
174
+ }
175
+ /**
176
+ * 发起原始请求(返回 Response 对象,不解析 JSON)
177
+ *
178
+ * 用于 SSE/流式请求等需要直接处理响应流的场景
179
+ * 请求会完整走中间件链,但响应不会被解析
180
+ */
181
+ async requestRaw(method, path, body, config) {
182
+ const ctx = this.buildContext(method, path, body, config);
183
+ const finalHandler = async () => {
184
+ const response$1 = await this.doFetch(ctx, config?.signal);
185
+ return {
186
+ request: ctx,
187
+ raw: response$1,
188
+ data: response$1,
189
+ error: null,
190
+ status: response$1.status
191
+ };
192
+ };
193
+ const response = await compose(this.middlewares)(ctx, finalHandler);
194
+ if (!response.raw) throw new Error("No response received");
195
+ return response.raw;
196
+ }
197
+ /**
198
+ * 发起请求(解析 JSON 响应)
199
+ */
200
+ async request(method, path, body, config) {
201
+ const ctx = this.buildContext(method, path, body, config);
141
202
  const finalHandler = async () => {
142
- return this.executeFetch(ctx);
203
+ const controller = new AbortController();
204
+ const timeoutMs = config?.timeout ?? this.defaultTimeout;
205
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
206
+ if (config?.signal) if (config.signal.aborted) controller.abort();
207
+ else config.signal.addEventListener("abort", () => controller.abort());
208
+ try {
209
+ const response = await this.doFetch(ctx, controller.signal);
210
+ clearTimeout(timeoutId);
211
+ const contentType = response.headers.get("content-type");
212
+ let data = null;
213
+ if (contentType?.includes("application/json")) data = await response.json();
214
+ else if (contentType?.includes("text/")) data = await response.text();
215
+ if (response.ok) return createSuccessResponse(data, ctx, response);
216
+ const errorData = data;
217
+ return createErrorResponse(errorData?.code ?? response.status, errorData?.message ?? `HTTP ${response.status}`, ctx, response, "server");
218
+ } catch (err) {
219
+ clearTimeout(timeoutId);
220
+ const error = err instanceof Error ? err : new Error(String(err));
221
+ if (error.name === "AbortError") {
222
+ const isTimeout = !config?.signal?.aborted;
223
+ return createErrorResponse(isTimeout ? 408 : 0, isTimeout ? "请求超时" : "请求已取消", ctx, null, isTimeout ? "timeout" : "abort");
224
+ }
225
+ return createErrorResponse(0, error.message || "网络错误", ctx, null, "network");
226
+ }
143
227
  };
144
228
  try {
145
229
  const response = await compose(this.middlewares)(ctx, finalHandler);
@@ -152,56 +236,12 @@ var ClientImpl = class {
152
236
  data: null,
153
237
  error: {
154
238
  code: 0,
155
- message: (err instanceof Error ? err : new Error(String(err))).message || "请求失败"
239
+ message: (err instanceof Error ? err : new Error(String(err))).message || "请求失败",
240
+ type: "unknown"
156
241
  }
157
242
  };
158
243
  }
159
244
  }
160
- /**
161
- * 执行实际的 fetch 请求
162
- */
163
- async executeFetch(ctx) {
164
- const { method, headers, body, config, meta } = ctx;
165
- const baseURL = meta.get("baseURL") || this.baseURL;
166
- const controller = new AbortController();
167
- const timeoutMs = config?.timeout ?? this.defaultTimeout;
168
- const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
169
- if (config?.signal) config.signal.addEventListener("abort", () => controller.abort());
170
- const fetchOptions = {
171
- method,
172
- headers,
173
- signal: controller.signal
174
- };
175
- if (body && method !== "GET" && method !== "HEAD" && method !== "OPTIONS") fetchOptions.body = JSON.stringify(body);
176
- let queryString = "";
177
- if (method === "GET" || method === "HEAD") {
178
- if (body && typeof body === "object") queryString = qs.stringify(body, {
179
- skipNulls: true,
180
- arrayFormat: "indices"
181
- });
182
- } else if (config?.query && typeof config.query === "object") queryString = qs.stringify(config.query, {
183
- skipNulls: true,
184
- arrayFormat: "indices"
185
- });
186
- try {
187
- const requestURL = buildRequestURL(baseURL, ctx.path, queryString);
188
- const request = new Request(requestURL, fetchOptions);
189
- const response = await fetch(request);
190
- clearTimeout(timeoutId);
191
- const contentType = response.headers.get("content-type");
192
- let data = null;
193
- if (contentType?.includes("application/json")) data = await response.json();
194
- else if (contentType?.includes("text/")) data = await response.text();
195
- if (response.ok) return createSuccessResponse(data, ctx, response);
196
- const errorData = data;
197
- return createErrorResponse(errorData?.code ?? response.status, errorData?.message ?? `HTTP ${response.status}`, ctx, response);
198
- } catch (err) {
199
- clearTimeout(timeoutId);
200
- const error = err instanceof Error ? err : new Error(String(err));
201
- if (error.name === "AbortError") return createErrorResponse(408, "请求超时", ctx);
202
- return createErrorResponse(0, error.message || "网络错误", ctx);
203
- }
204
- }
205
245
  };
206
246
  /**
207
247
  * 创建 HTTP 客户端
@@ -281,21 +321,20 @@ async function* parseSSEStream(reader) {
281
321
  * ```
282
322
  */
283
323
  function eden(client) {
284
- const originalBaseURL = client.baseURL || "";
285
- function getSSEBaseURL() {
286
- if (originalBaseURL.startsWith("http://") || originalBaseURL.startsWith("https://")) return originalBaseURL;
287
- const origin = typeof window !== "undefined" && window.location?.origin ? window.location.origin : "http://localhost";
288
- return originalBaseURL ? `${origin}${originalBaseURL}` : origin;
289
- }
290
- const defaultHeaders = {};
291
324
  async function request(method, path, data, requestConfig) {
292
325
  return client.request(method, path, data, requestConfig);
293
326
  }
294
- function subscribe(path, query, callbacks, options) {
295
- const url = new URL(path, getSSEBaseURL());
296
- if (query) {
297
- for (const [key, value] of Object.entries(query)) if (value !== void 0 && value !== null) url.searchParams.set(key, String(value));
298
- }
327
+ /**
328
+ * SSE 订阅(支持所有 HTTP 方法)
329
+ *
330
+ * @param path - 请求路径
331
+ * @param method - HTTP 方法,默认 GET
332
+ * @param body - 请求体(POST/PUT/PATCH/DELETE 时使用)
333
+ * @param query - URL 查询参数
334
+ * @param callbacks - 事件回调
335
+ * @param options - 订阅选项
336
+ */
337
+ function subscribe(path, method, body, query, callbacks, options) {
299
338
  let abortController = new AbortController();
300
339
  let connected = false;
301
340
  let reconnectCount = 0;
@@ -307,16 +346,15 @@ function eden(client) {
307
346
  if (isUnsubscribed) return;
308
347
  try {
309
348
  abortController = new AbortController();
310
- const headers = {
349
+ const requestHeaders = {
311
350
  "Accept": "text/event-stream",
312
- ...defaultHeaders,
313
351
  ...options?.headers
314
352
  };
315
- if (lastEventId) headers["Last-Event-ID"] = lastEventId;
316
- const response = await fetch(url.toString(), {
317
- method: "GET",
318
- headers,
319
- signal: abortController.signal
353
+ if (lastEventId) requestHeaders["Last-Event-ID"] = lastEventId;
354
+ const response = await client.requestRaw(method, path, body, {
355
+ headers: requestHeaders,
356
+ signal: abortController.signal,
357
+ query
320
358
  });
321
359
  if (!response.ok) throw new Error(`HTTP ${response.status}`);
322
360
  if (!response.body) throw new Error("No response body");
@@ -345,9 +383,10 @@ function eden(client) {
345
383
  if (reconnectCount < maxReconnects) {
346
384
  reconnectCount++;
347
385
  callbacks.onReconnect?.(reconnectCount, maxReconnects);
386
+ const backoffDelay = Math.min(reconnectInterval * Math.pow(2, reconnectCount - 1), 3e4);
348
387
  setTimeout(() => {
349
388
  if (!isUnsubscribed) connect();
350
- }, reconnectInterval);
389
+ }, backoffDelay);
351
390
  } else callbacks.onMaxReconnects?.();
352
391
  }
353
392
  };
@@ -364,6 +403,15 @@ function eden(client) {
364
403
  }
365
404
  };
366
405
  }
406
+ const httpMethodsSet = new Set([
407
+ "get",
408
+ "post",
409
+ "put",
410
+ "patch",
411
+ "delete",
412
+ "head",
413
+ "options"
414
+ ]);
367
415
  /**
368
416
  * 新方案:segments 数组 + 最后一个判断 HTTP 方法
369
417
  *
@@ -374,15 +422,6 @@ function eden(client) {
374
422
  * api.users({ id: '123' }).get() → GET /users/123
375
423
  */
376
424
  function createEndpoint(segments) {
377
- const httpMethods = [
378
- "get",
379
- "post",
380
- "put",
381
- "patch",
382
- "delete",
383
- "head",
384
- "options"
385
- ];
386
425
  return new Proxy(() => {}, {
387
426
  get(_, prop) {
388
427
  return createEndpoint([...segments, prop]);
@@ -390,20 +429,37 @@ function eden(client) {
390
429
  apply(_, __, args) {
391
430
  const [firstArg] = args;
392
431
  const last = segments[segments.length - 1];
393
- if (firstArg && typeof firstArg === "object" && !Array.isArray(firstArg) && Object.keys(firstArg).length === 1 && !("onMessage" in firstArg) && !httpMethods.includes(last) && last !== "sse") {
432
+ if (firstArg && typeof firstArg === "object" && !Array.isArray(firstArg) && Object.keys(firstArg).length === 1 && !("onMessage" in firstArg) && !httpMethodsSet.has(last) && last !== "sse") {
394
433
  const paramValue = Object.values(firstArg)[0];
395
434
  return createEndpoint([...segments, encodeURIComponent(String(paramValue))]);
396
435
  }
397
436
  const path = "/" + segments.slice(0, -1).join("/");
398
- if (last === "sse") {
399
- const [callbacksOrQuery, optionsOrCallbacks, options] = args;
400
- if (typeof callbacksOrQuery === "object" && "onMessage" in callbacksOrQuery && typeof callbacksOrQuery.onMessage === "function") return subscribe(path, void 0, callbacksOrQuery, optionsOrCallbacks);
401
- else return subscribe(path, callbacksOrQuery, optionsOrCallbacks, options);
402
- }
403
- if (httpMethods.includes(last)) {
437
+ if (httpMethodsSet.has(last)) {
404
438
  const method = last.toUpperCase();
405
439
  const [data$1, config$1] = args;
406
- return request(method, path, data$1, config$1);
440
+ let body;
441
+ let query;
442
+ if (method === "GET" || method === "HEAD") query = data$1;
443
+ else {
444
+ body = data$1;
445
+ query = config$1?.query;
446
+ }
447
+ let requestPromise = null;
448
+ return {
449
+ then(onfulfilled, onrejected) {
450
+ if (!requestPromise) requestPromise = request(method, path, body, {
451
+ ...config$1,
452
+ query
453
+ });
454
+ return requestPromise.then(onfulfilled, onrejected);
455
+ },
456
+ sse(callbacks) {
457
+ return subscribe(path, method, body, query, callbacks, {
458
+ method,
459
+ ...callbacks
460
+ });
461
+ }
462
+ };
407
463
  }
408
464
  const fullPath = "/" + segments.join("/");
409
465
  const [data, config] = args;
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["data","config"],"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 * 判断是否为绝对 URL\n */\nfunction isAbsoluteURL(url: string): boolean {\n return url.startsWith('http://') || url.startsWith('https://')\n}\n\n/**\n * 构建请求 URL(简化版)\n * - 绝对 URL:直接使用\n * - 相对路径:直接拼接(保持代理工作)\n */\nfunction buildRequestURL(baseURL: string, path: string, queryString: string): string {\n const normalizedPath = path.startsWith('/') ? path : `/${path}`\n const fullPath = `${baseURL}${normalizedPath}`\n return queryString ? `${fullPath}?${queryString}` : fullPath\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 const baseURL = this.baseURL\n const normalizedPath = path.startsWith('/') ? path : `/${path}`\n \n // 创建占位 URL 对象(用于中间件上下文)\n // 注意:实际请求时使用字符串拼接的 URL\n const dummyURL = new URL('http://placeholder')\n dummyURL.pathname = normalizedPath\n\n // 构建请求头\n // 注意:GET/HEAD 请求不应设置 Content-Type(因为没有 body)\n const hasBody = body && method.toUpperCase() !== 'GET' && method.toUpperCase() !== 'HEAD'\n const headers = new Headers({\n ...(hasBody ? { '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 // 存储 baseURL 供 executeFetch 使用\n meta.set('baseURL', baseURL)\n \n const ctx: RequestContext = {\n method: method.toUpperCase(),\n path,\n url: dummyURL,\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, headers, body, config, meta } = ctx\n const baseURL = (meta.get('baseURL') as string) || this.baseURL\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/OPTIONS 不需要)\n if (body && method !== 'GET' && method !== 'HEAD' && method !== 'OPTIONS') {\n fetchOptions.body = JSON.stringify(body)\n }\n\n // 构建查询参数\n // 1. GET 请求:body 参数转为 query string\n // 2. 其他请求:从 config.query 获取 query 参数\n let queryString = ''\n if (method === 'GET' || method === 'HEAD') {\n // GET/HEAD 请求:body 作为 query 参数\n if (body && typeof body === 'object') {\n queryString = qs.stringify(body as Record<string, unknown>, {\n skipNulls: true,\n arrayFormat: 'indices',\n })\n }\n } else if (config?.query && typeof config.query === 'object') {\n // POST/PUT/PATCH/DELETE/OPTIONS 请求:从 config.query 获取\n queryString = qs.stringify(config.query, {\n skipNulls: true,\n arrayFormat: 'indices',\n })\n }\n\n try {\n // 构建请求 URL(简化:直接字符串拼接)\n const requestURL = buildRequestURL(baseURL, ctx.path, queryString)\n \n // 创建 Request 对象\n const request = new Request(requestURL, 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/** 从 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\n/** HTTP 方法定义 */\ninterface MethodDef {\n query?: unknown\n body?: unknown\n params?: unknown\n return: unknown\n}\n\n/** SSE 方法定义(独立于 HTTP 方法) */\ninterface SSEMethodDef {\n query?: unknown\n return: unknown\n}\n\ntype RouteNode = {\n get?: MethodDef\n post?: MethodDef\n put?: MethodDef\n patch?: MethodDef\n delete?: MethodDef\n head?: MethodDef\n options?: MethodDef\n sse?: SSEMethodDef // SSE 作为一等公民方法\n ':id'?: RouteNode\n [key: string]: MethodDef | SSEMethodDef | 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\n/** HTTP 方法调用签名 */\ntype HTTPMethodCall<M extends MethodDef, HasParams extends boolean = false> =\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\n/** SSE 方法调用签名 */\ntype SSEMethodCall<M extends SSEMethodDef> =\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\n/** 端点类型:HTTP 方法 + SSE 方法 */\ntype Endpoint<T, HasParams extends boolean = false> =\n // HTTP 方法\n {\n [K in 'get' | 'post' | 'put' | 'patch' | 'delete' | 'head' | 'options' as T extends { [P in K]: MethodDef } ? K : never]:\n T extends { [P in K]: infer M extends MethodDef } ? HTTPMethodCall<M, HasParams> : never\n }\n // SSE 方法(作为一等公民)\n & (T extends { sse: infer M extends SSEMethodDef }\n ? { sse: SSEMethodCall<M> }\n : {})\n\ntype HTTPMethods = 'get' | 'post' | 'put' | 'patch' | 'delete' | 'head' | 'options' | 'sse'\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(用于普通请求)\n const originalBaseURL = client.baseURL || ''\n\n // SSE 需要绝对 URL,延迟构建(只在实际使用 SSE 时才需要)\n function getSSEBaseURL(): string {\n if (originalBaseURL.startsWith('http://') || originalBaseURL.startsWith('https://')) {\n return originalBaseURL\n }\n // 相对路径:转换为绝对 URL\n const origin = typeof window !== 'undefined' && window.location?.origin\n ? window.location.origin\n : 'http://localhost'\n return originalBaseURL ? `${origin}${originalBaseURL}` : origin\n }\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, getSSEBaseURL())\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 /**\n * 新方案:segments 数组 + 最后一个判断 HTTP 方法\n * \n * api.users.find.post() → POST /users/find\n * api.users.get() → GET /users\n * api.videoGeneration.delete.post() → POST /videoGeneration/delete\n * api.chat.stream.sse(callbacks) → SSE /chat/stream\n * api.users({ id: '123' }).get() → GET /users/123\n */\n function createEndpoint(segments: string[]): unknown {\n const httpMethods = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options']\n\n return new Proxy(() => { }, {\n get(_, prop: string) {\n // 所有属性访问都添加到 segments\n return createEndpoint([...segments, prop])\n },\n apply(_, __, args) {\n const [firstArg] = args\n const last = segments[segments.length - 1]\n\n // 动态参数:api.users({ id: '123' }) → 继续构建路径\n // 注意:只有当最后一个不是 HTTP 方法名或 sse 时才考虑动态参数\n // 否则 api.users.get({ page: 1 }) 的 { page: 1 } 会被误判为动态参数\n if (\n firstArg\n && typeof firstArg === 'object'\n && !Array.isArray(firstArg)\n && Object.keys(firstArg).length === 1\n && !('onMessage' in firstArg) // 排除 SSE callbacks\n && !httpMethods.includes(last) // 不是 HTTP 方法\n && last !== 'sse' // 不是 SSE\n ) {\n const paramValue = Object.values(firstArg)[0]\n return createEndpoint([...segments, encodeURIComponent(String(paramValue))])\n }\n\n const pathSegments = segments.slice(0, -1)\n const path = '/' + pathSegments.join('/')\n\n // SSE 订阅\n if (last === 'sse') {\n const [callbacksOrQuery, optionsOrCallbacks, options] = args as [\n Record<string, unknown> | SSECallbacks<unknown>,\n SSECallbacks<unknown> | SSESubscribeOptions | undefined,\n SSESubscribeOptions | undefined\n ]\n\n // 判断第一个参数是 callbacks 还是 query\n const isCallbacks = typeof callbacksOrQuery === 'object'\n && 'onMessage' in callbacksOrQuery\n && typeof callbacksOrQuery.onMessage === 'function'\n\n if (isCallbacks) {\n return subscribe(path, undefined, callbacksOrQuery as SSECallbacks<unknown>, optionsOrCallbacks as SSESubscribeOptions)\n } else {\n return subscribe(path, callbacksOrQuery as Record<string, unknown>, optionsOrCallbacks as SSECallbacks<unknown>, options)\n }\n }\n\n // HTTP 方法\n if (httpMethods.includes(last)) {\n const method = last.toUpperCase()\n const [data, config] = args as [unknown?, RequestConfig?]\n return request(method, path, data, config)\n }\n\n // 默认 POST(路径末尾不是方法名)\n const fullPath = '/' + segments.join('/')\n const [data, config] = args as [unknown?, RequestConfig?]\n return request('POST', fullPath, data, config)\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":["response","data","config"],"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 ErrorType,\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 type: ErrorType = 'unknown'\n): ResponseContext<T> {\n return {\n request: ctx,\n raw,\n data: null,\n error: { code, message, type },\n status: raw?.status ?? 0,\n }\n}\n\n/**\n * 判断是否为绝对 URL\n */\nfunction isAbsoluteURL(url: string): boolean {\n return url.startsWith('http://') || url.startsWith('https://')\n}\n\n/**\n * 构建请求 URL(简化版)\n * - 绝对 URL:直接使用\n * - 相对路径:直接拼接(保持代理工作)\n */\nfunction buildRequestURL(baseURL: string, path: string, queryString: string): string {\n const normalizedPath = path.startsWith('/') ? path : `/${path}`\n const fullPath = `${baseURL}${normalizedPath}`\n return queryString ? `${fullPath}?${queryString}` : fullPath\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 /**\n * 构建请求上下文(公共逻辑)\n */\n private buildContext(\n method: string,\n path: string,\n body?: unknown,\n config?: RequestConfig\n ): RequestContext {\n const normalizedPath = path.startsWith('/') ? path : `/${path}`\n const dummyURL = new URL('http://placeholder')\n dummyURL.pathname = normalizedPath\n\n // 构建请求头(有 body 时才设置 Content-Type)\n const hasBody = body !== undefined && method !== 'GET' && method !== 'HEAD'\n const headers = new Headers({\n ...(hasBody ? { '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 meta.set('baseURL', this.baseURL)\n\n return {\n method: method.toUpperCase(),\n path,\n url: dummyURL,\n headers,\n body,\n config,\n meta,\n retryCount: 0,\n }\n }\n\n /**\n * 构建查询字符串\n * \n * 统一从 config.query 获取,语义清晰:\n * - body 就是 body(请求体)\n * - query 就是 query(URL 查询参数)\n */\n private buildQueryString(ctx: RequestContext): string {\n const { config } = ctx\n \n if (config?.query && typeof config.query === 'object') {\n return qs.stringify(config.query, { skipNulls: true, arrayFormat: 'indices' })\n }\n \n return ''\n }\n\n /**\n * 执行原始 fetch 请求(核心方法,不解析响应)\n */\n private async doFetch(ctx: RequestContext, signal?: AbortSignal): Promise<Response> {\n const { method, path, headers, body, meta } = ctx\n const baseURL = (meta.get('baseURL') as string) || this.baseURL\n const queryString = this.buildQueryString(ctx)\n const url = buildRequestURL(baseURL, path, queryString)\n\n const fetchOptions: RequestInit = {\n method,\n headers,\n signal,\n }\n\n // 添加请求体(GET/HEAD/OPTIONS 不需要)\n if (body !== undefined && method !== 'GET' && method !== 'HEAD' && method !== 'OPTIONS') {\n fetchOptions.body = JSON.stringify(body)\n }\n\n // 创建 Request 对象(便于测试和中间件)\n const request = new Request(url, fetchOptions)\n return fetch(request)\n }\n\n /**\n * 发起原始请求(返回 Response 对象,不解析 JSON)\n * \n * 用于 SSE/流式请求等需要直接处理响应流的场景\n * 请求会完整走中间件链,但响应不会被解析\n */\n async requestRaw(\n method: string,\n path: string,\n body?: unknown,\n config?: RequestConfig\n ): Promise<Response> {\n const ctx = this.buildContext(method, path, body, config)\n\n const finalHandler = async (): Promise<ResponseContext<Response>> => {\n const response = await this.doFetch(ctx, config?.signal)\n return {\n request: ctx,\n raw: response,\n data: response,\n error: null,\n status: response.status,\n }\n }\n\n const response = await compose(this.middlewares)(ctx, finalHandler)\n \n if (!response.raw) {\n throw new Error('No response received')\n }\n \n return response.raw\n }\n\n /**\n * 发起请求(解析 JSON 响应)\n */\n async request<T = unknown>(\n method: string,\n path: string,\n body?: unknown,\n config?: RequestConfig\n ): Promise<ApiResponse<T>> {\n const ctx = this.buildContext(method, path, body, config)\n\n const finalHandler = async (): Promise<ResponseContext<T>> => {\n // 超时控制\n const controller = new AbortController()\n const timeoutMs = config?.timeout ?? this.defaultTimeout\n const timeoutId = setTimeout(() => controller.abort(), timeoutMs)\n\n // 合并用户传入的 signal\n if (config?.signal) {\n // 检查是否已经 aborted\n if (config.signal.aborted) {\n controller.abort()\n } else {\n config.signal.addEventListener('abort', () => controller.abort())\n }\n }\n\n try {\n const response = await this.doFetch(ctx, controller.signal)\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 if (response.ok) {\n return createSuccessResponse(data, ctx, response)\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 'server'\n )\n } catch (err) {\n clearTimeout(timeoutId)\n const error = err instanceof Error ? err : new Error(String(err))\n\n // 区分错误类型\n if (error.name === 'AbortError') {\n // 检查是超时还是主动取消\n const isTimeout = !config?.signal?.aborted\n return createErrorResponse<T>(\n isTimeout ? 408 : 0,\n isTimeout ? '请求超时' : '请求已取消',\n ctx,\n null,\n isTimeout ? 'timeout' : 'abort'\n )\n }\n\n return createErrorResponse<T>(0, error.message || '网络错误', ctx, null, 'network')\n }\n }\n\n try {\n const response = await compose(this.middlewares)(ctx, finalHandler)\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 || '请求失败', type: 'unknown' },\n }\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 /** HTTP 方法,默认 GET。有 body 时建议使用 POST/PUT/PATCH/DELETE */\n method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'\n /** 额外的 URL 查询参数(与 body 一起使用时) */\n query?: Record<string, unknown>\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/** 从 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\n/** HTTP 方法定义 */\ninterface MethodDef {\n query?: unknown\n body?: unknown\n params?: unknown\n return: unknown\n}\n\n/** \n * SSE 方法定义(支持所有 HTTP 方法)\n * \n * @example\n * ```typescript\n * // GET SSE(默认)\n * sse: { query: QuerySchema, return: EventSchema }\n * \n * // POST SSE(带 body)\n * sse: { method: 'POST', body: BodySchema, return: EventSchema }\n * \n * // DELETE SSE(批量删除进度)\n * sse: { method: 'DELETE', body: IdsSchema, return: ProgressSchema }\n * ```\n */\ninterface SSEMethodDef {\n method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'\n query?: unknown\n body?: unknown\n return: unknown\n}\n\ntype RouteNode = {\n get?: MethodDef\n post?: MethodDef\n put?: MethodDef\n patch?: MethodDef\n delete?: MethodDef\n head?: MethodDef\n options?: MethodDef\n sse?: SSEMethodDef // SSE 作为一等公民方法\n ':id'?: RouteNode\n [key: string]: MethodDef | SSEMethodDef | RouteNode | undefined\n}\n\n// ============= 客户端类型 =============\n\nexport interface 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\n/** \n * SSE 回调选项(链式调用时只需要传这些)\n */\nexport type SSECallbackOptions = Omit<SSESubscribeOptions, 'method' | 'query'>\n\n/**\n * 请求构建器 - 支持普通请求和 SSE 链式调用\n * \n * @example\n * ```typescript\n * // 普通请求(直接 await)\n * const result = await api.users.get({ page: 1 })\n * \n * // SSE 请求(链式调用 .sse())\n * api.chat.stream.post({ message: 'hi' }).sse({\n * onMessage: (data) => console.log(data),\n * onClose: () => console.log('done')\n * })\n * ```\n */\nexport interface RequestBuilder<T> extends PromiseLike<ApiResponse<T>> {\n /** 转换为 SSE 订阅 */\n sse(callbacks: SSECallbacks<T> & SSECallbackOptions): SSESubscription<T>\n}\n\n/** HTTP 方法调用签名 - 返回 RequestBuilder(可 await 或 .sse()) */\ntype HTTPMethodCall<M extends MethodDef, HasParams extends boolean = false> =\n HasParams extends true\n ? M extends { body: infer B }\n ? (body: B, config?: RequestConfig) => RequestBuilder<M['return']>\n : (config?: RequestConfig) => RequestBuilder<M['return']>\n : M extends { query: infer Q }\n ? (query?: Q, config?: RequestConfig) => RequestBuilder<M['return']>\n : M extends { body: infer B }\n ? (body: B, config?: RequestConfig) => RequestBuilder<M['return']>\n : (config?: RequestConfig) => RequestBuilder<M['return']>\n\n/** 端点类型:HTTP 方法(SSE 通过 .sse() 链式调用) */\ntype Endpoint<T, HasParams extends boolean = false> =\n {\n [K in 'get' | 'post' | 'put' | 'patch' | 'delete' | 'head' | 'options' as T extends { [P in K]: MethodDef } ? K : never]:\n T extends { [P in K]: infer M extends MethodDef } ? HTTPMethodCall<M, HasParams> : never\n }\n\ntype HTTPMethods = 'get' | 'post' | 'put' | 'patch' | 'delete' | 'head' | 'options'\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 // 请求函数:委托给 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 /**\n * SSE 订阅(支持所有 HTTP 方法)\n * \n * @param path - 请求路径\n * @param method - HTTP 方法,默认 GET\n * @param body - 请求体(POST/PUT/PATCH/DELETE 时使用)\n * @param query - URL 查询参数\n * @param callbacks - 事件回调\n * @param options - 订阅选项\n */\n function subscribe<TData>(\n path: string,\n method: string,\n body: unknown | undefined,\n query: Record<string, unknown> | undefined,\n callbacks: SSECallbacks<TData>,\n options?: SSESubscribeOptions\n ): SSESubscription<TData> {\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 // 构建请求配置(中间件会自动添加认证头)\n const requestHeaders: Record<string, string> = {\n 'Accept': 'text/event-stream',\n ...options?.headers,\n }\n\n if (lastEventId) {\n requestHeaders['Last-Event-ID'] = lastEventId\n }\n\n // 通过 client.requestRaw() 发起请求\n // 这样请求会完整走中间件链(认证、日志等)\n const response = await client.requestRaw(\n method,\n path,\n body,\n {\n headers: requestHeaders,\n signal: abortController.signal,\n query,\n }\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 // 指数退避重连:1s, 2s, 4s, 8s...(最大 30s)\n const backoffDelay = Math.min(\n reconnectInterval * Math.pow(2, reconnectCount - 1),\n 30000\n )\n\n setTimeout(() => {\n if (!isUnsubscribed) {\n connect()\n }\n }, backoffDelay)\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 // HTTP 方法列表(提取到外部避免重复创建)\n const httpMethods = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options'] as const\n const httpMethodsSet = new Set(httpMethods)\n\n /**\n * 新方案:segments 数组 + 最后一个判断 HTTP 方法\n * \n * api.users.find.post() → POST /users/find\n * api.users.get() → GET /users\n * api.videoGeneration.delete.post() → POST /videoGeneration/delete\n * api.chat.stream.sse(callbacks) → SSE /chat/stream\n * api.users({ id: '123' }).get() → GET /users/123\n */\n function createEndpoint(segments: string[]): unknown {\n\n return new Proxy(() => { }, {\n get(_, prop: string) {\n // 所有属性访问都添加到 segments\n return createEndpoint([...segments, prop])\n },\n apply(_, __, args) {\n const [firstArg] = args\n const last = segments[segments.length - 1]\n\n // 动态参数:api.users({ id: '123' }) → 继续构建路径\n // 注意:只有当最后一个不是 HTTP 方法名或 sse 时才考虑动态参数\n // 否则 api.users.get({ page: 1 }) 的 { page: 1 } 会被误判为动态参数\n if (\n firstArg\n && typeof firstArg === 'object'\n && !Array.isArray(firstArg)\n && Object.keys(firstArg).length === 1\n && !('onMessage' in firstArg) // 排除 SSE callbacks\n && !httpMethodsSet.has(last as typeof httpMethods[number]) // 不是 HTTP 方法\n && last !== 'sse' // 不是 SSE\n ) {\n const paramValue = Object.values(firstArg)[0]\n return createEndpoint([...segments, encodeURIComponent(String(paramValue))])\n }\n\n const pathSegments = segments.slice(0, -1)\n const path = '/' + pathSegments.join('/')\n\n // HTTP 方法 - 返回 RequestBuilder(可 await 或 .sse())\n if (httpMethodsSet.has(last as typeof httpMethods[number])) {\n const method = last.toUpperCase()\n const [data, config] = args as [unknown?, RequestConfig?]\n\n // 确定 body 和 query\n let body: unknown\n let query: Record<string, unknown> | undefined\n\n if (method === 'GET' || method === 'HEAD') {\n // GET/HEAD:data 是 query 参数\n query = data as Record<string, unknown>\n } else {\n // 其他方法:data 是 body\n body = data\n query = config?.query\n }\n\n // 创建 RequestBuilder(支持 await 和 .sse())\n // 注意:请求是懒执行的,只有 await 或 .sse() 才会触发\n let requestPromise: Promise<ApiResponse<unknown>> | null = null\n\n const builder: RequestBuilder<unknown> = {\n // PromiseLike - 支持 await(懒执行)\n then<TResult1 = ApiResponse<unknown>, TResult2 = never>(\n onfulfilled?: ((value: ApiResponse<unknown>) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null\n ): Promise<TResult1 | TResult2> {\n // 懒执行:只有 await 时才发起请求\n if (!requestPromise) {\n requestPromise = request(method, path, body, { ...config, query })\n }\n return requestPromise.then(onfulfilled, onrejected)\n },\n\n // SSE 链式调用\n sse(callbacks: SSECallbacks<unknown> & SSECallbackOptions): SSESubscription<unknown> {\n const sseMethod = method as 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'\n return subscribe(path, method, body, query, callbacks, { method: sseMethod, ...callbacks })\n }\n }\n\n return builder\n }\n\n // 默认 POST(路径末尾不是方法名)\n const fullPath = '/' + segments.join('/')\n const [data, config] = args as [unknown?, RequestConfig?]\n return request('POST', fullPath, data, config)\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.3.4",
3
+ "version": "0.3.6",
4
4
  "description": "Type-safe API client for Vafast framework",
5
5
  "license": "MIT",
6
6
  "files": [