@vafast/api-client 0.3.2 → 0.3.4

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
@@ -168,6 +168,12 @@ type MyApi = {
168
168
  delete: { return: { success: boolean } }
169
169
  }
170
170
  }
171
+ // SSE 方法:作为一等公民
172
+ chat: {
173
+ stream: {
174
+ sse: { query: { prompt: string }; return: { text: string } }
175
+ }
176
+ }
171
177
  }
172
178
 
173
179
  const api = eden<MyApi>(createClient('https://api.example.com'))
@@ -325,11 +331,32 @@ console.log(data.users)
325
331
 
326
332
  ## SSE 流式响应
327
333
 
334
+ `sse` 是一等公民方法,与 `get`/`post` 等 HTTP 方法平级:
335
+
336
+ ### 契约定义
337
+
338
+ ```typescript
339
+ // sse 作为独立方法定义(简洁直观)
340
+ type Api = {
341
+ chat: {
342
+ stream: {
343
+ sse: { query: { prompt: string }; return: { text: string } }
344
+ }
345
+ }
346
+ events: {
347
+ sse: { return: { type: string; data: unknown } } // 无 query 参数
348
+ }
349
+ }
350
+ ```
351
+
352
+ ### 使用方式
353
+
328
354
  ```typescript
329
355
  const api = eden<Api>(client)
330
356
 
331
- // 订阅 SSE
357
+ // query 参数
332
358
  const subscription = api.chat.stream.sse(
359
+ { prompt: '你好' }, // query 参数
333
360
  {
334
361
  onMessage: (data) => console.log('收到:', data.text),
335
362
  onError: (error) => console.error('错误:', error),
@@ -343,6 +370,11 @@ const subscription = api.chat.stream.sse(
343
370
  }
344
371
  )
345
372
 
373
+ // 无 query 参数
374
+ const eventSub = api.events.sse({
375
+ onMessage: (data) => console.log('事件:', data.type)
376
+ })
377
+
346
378
  // 取消订阅
347
379
  subscription.unsubscribe()
348
380
  ```
package/dist/index.d.mts CHANGED
@@ -44,6 +44,8 @@ interface RequestConfig {
44
44
  signal?: AbortSignal;
45
45
  /** 元数据(传递给中间件) */
46
46
  meta?: Record<string, unknown>;
47
+ /** 查询参数(POST/PUT/PATCH 请求也可携带 query) */
48
+ query?: Record<string, unknown>;
47
49
  }
48
50
  /**
49
51
  * 请求上下文 - 贯穿整个请求生命周期
@@ -201,9 +203,6 @@ type TrimSlash<P$1 extends string> = P$1 extends `/${infer R}` ? R : P$1;
201
203
  /** 检查是否是动态参数段::id → true */
202
204
  type IsDynamicSegment<S$1 extends string> = S$1 extends `:${string}` ? true : false;
203
205
  type Clean<T> = { [K in keyof T as T[K] extends undefined ? never : K]: T[K] };
204
- type SSEBrand = {
205
- readonly __brand: 'SSE';
206
- };
207
206
  /**
208
207
  * 从 defineRoute 返回的路由配置构建方法定义
209
208
  *
@@ -290,12 +289,17 @@ type MergeRoutes<T extends readonly unknown[]> = T extends readonly [infer First
290
289
  type InferEden<T> = T extends {
291
290
  __source: infer S extends readonly unknown[];
292
291
  } ? MergeRoutes<S> : T extends readonly unknown[] ? MergeRoutes<T> : {};
292
+ /** HTTP 方法定义 */
293
293
  interface MethodDef {
294
294
  query?: unknown;
295
295
  body?: unknown;
296
296
  params?: unknown;
297
297
  return: unknown;
298
- sse?: SSEBrand;
298
+ }
299
+ /** SSE 方法定义(独立于 HTTP 方法) */
300
+ interface SSEMethodDef {
301
+ query?: unknown;
302
+ return: unknown;
299
303
  }
300
304
  interface SSECallbacks<T> {
301
305
  onMessage: (data: T) => void;
@@ -305,28 +309,25 @@ interface SSECallbacks<T> {
305
309
  onReconnect?: (attempt: number, maxAttempts: number) => void;
306
310
  onMaxReconnects?: () => void;
307
311
  }
308
- type MethodCall<M$1 extends MethodDef, HasParams extends boolean = false> = M$1 extends {
309
- sse: SSEBrand;
310
- } ? M$1 extends {
311
- query: infer Q;
312
- } ? (query: Q, callbacks: SSECallbacks<M$1['return']>, options?: SSESubscribeOptions) => SSESubscription<M$1['return']> : (callbacks: SSECallbacks<M$1['return']>, options?: SSESubscribeOptions) => SSESubscription<M$1['return']> : HasParams extends true ? M$1 extends {
312
+ /** HTTP 方法调用签名 */
313
+ type HTTPMethodCall<M$1 extends MethodDef, HasParams extends boolean = false> = HasParams extends true ? M$1 extends {
313
314
  body: infer B;
314
315
  } ? (body: B, config?: RequestConfig) => Promise<ApiResponse<M$1['return']>> : (config?: RequestConfig) => Promise<ApiResponse<M$1['return']>> : M$1 extends {
315
316
  query: infer Q;
316
317
  } ? (query?: Q, config?: RequestConfig) => Promise<ApiResponse<M$1['return']>> : M$1 extends {
317
318
  body: infer B;
318
319
  } ? (body: B, config?: RequestConfig) => Promise<ApiResponse<M$1['return']>> : (config?: RequestConfig) => Promise<ApiResponse<M$1['return']>>;
319
- type IsSSEEndpoint<M$1> = M$1 extends {
320
- sse: {
321
- readonly __brand: 'SSE';
322
- };
323
- } ? true : false;
324
- type Endpoint<T, HasParams extends boolean = false> = { [K in 'get' | 'post' | 'put' | 'patch' | 'delete' as T extends { [P in K]: MethodDef } ? K : never]: T extends { [P in K]: infer M extends MethodDef } ? MethodCall<M, HasParams> : never } & (T extends {
325
- get: infer M extends MethodDef;
326
- } ? IsSSEEndpoint<M> extends true ? {
327
- subscribe: MethodCall<M, HasParams>;
328
- } : {} : {});
329
- type HTTPMethods = 'get' | 'post' | 'put' | 'patch' | 'delete';
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';
330
331
  /**
331
332
  * 判断是否是路由节点(包含 HTTP 方法作为子键)
332
333
  * 路由节点结构:{ post: {...} } 或 { get: {...}, post: {...} }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types/index.ts","../src/core/client.ts","../src/core/eden.ts","../src/middlewares/timeout.ts","../src/middlewares/retry.ts","../src/middlewares/logger.ts"],"sourcesContent":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types/index.ts","../src/core/client.ts","../src/core/eden.ts","../src/middlewares/timeout.ts","../src/middlewares/retry.ts","../src/middlewares/logger.ts"],"sourcesContent":[],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -119,8 +119,9 @@ var ClientImpl = class {
119
119
  const normalizedPath = path.startsWith("/") ? path : `/${path}`;
120
120
  const dummyURL = new URL("http://placeholder");
121
121
  dummyURL.pathname = normalizedPath;
122
+ const hasBody = body && method.toUpperCase() !== "GET" && method.toUpperCase() !== "HEAD";
122
123
  const headers = new Headers({
123
- "Content-Type": "application/json",
124
+ ...hasBody ? { "Content-Type": "application/json" } : {},
124
125
  ...this.defaultHeaders,
125
126
  ...config?.headers
126
127
  });
@@ -171,9 +172,14 @@ var ClientImpl = class {
171
172
  headers,
172
173
  signal: controller.signal
173
174
  };
174
- if (body && method !== "GET" && method !== "HEAD") fetchOptions.body = JSON.stringify(body);
175
+ if (body && method !== "GET" && method !== "HEAD" && method !== "OPTIONS") fetchOptions.body = JSON.stringify(body);
175
176
  let queryString = "";
176
- if (method === "GET" && body && typeof body === "object") queryString = qs.stringify(body, {
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, {
177
183
  skipNulls: true,
178
184
  arrayFormat: "indices"
179
185
  });
@@ -373,7 +379,9 @@ function eden(client) {
373
379
  "post",
374
380
  "put",
375
381
  "patch",
376
- "delete"
382
+ "delete",
383
+ "head",
384
+ "options"
377
385
  ];
378
386
  return new Proxy(() => {}, {
379
387
  get(_, prop) {
@@ -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 const headers = new Headers({\n 'Content-Type': 'application/json',\n ...this.defaultHeaders,\n ...config?.headers,\n })\n\n // 构建元数据\n const meta = new Map<string, unknown>()\n if (config?.meta) {\n for (const [key, value] of Object.entries(config.meta)) {\n meta.set(key, value)\n }\n }\n // 存储 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 不需要)\n if (body && method !== 'GET' && method !== 'HEAD') {\n fetchOptions.body = JSON.stringify(body)\n }\n\n // GET 请求的查询参数\n let queryString = ''\n if (method === 'GET' && body && typeof body === 'object') {\n queryString = qs.stringify(body as Record<string, unknown>, {\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/** 检查是否是 SSE Handler */\ntype IsSSEHandler<T> = T extends { __sse: { readonly __brand: 'SSE' } } ? true : false\n\n/** 从 Schema 对象提取各部分类型 */\ntype GetSchemaQuery<S> = S extends { query: infer Q } ? InferStatic<Q> : undefined\ntype GetSchemaBody<S> = S extends { body: infer B } ? InferStatic<B> : undefined\ntype GetSchemaParams<S> = S extends { params: infer P } ? InferStatic<P> : undefined\n\n/** \n * 从 handler 函数推断返回类型\n * handler: (ctx) => TReturn | Promise<TReturn>\n */\ntype InferHandlerReturn<H> = H extends (...args: never[]) => infer R\n ? R extends Promise<infer T> ? T : R\n : unknown\n\n// ============= 路径处理 =============\n\n/** 移除开头斜杠:/users → users */\ntype TrimSlash<P extends string> = P extends `/${infer R}` ? R : P\n\n/** 获取第一段:users/posts → users */\ntype Head<P extends string> = P extends `${infer H}/${string}` ? H : P\n\n/** 获取剩余段:users/posts → posts */\ntype Tail<P extends string> = P extends `${string}/${infer T}` ? T : never\n\n/** 检查是否是动态参数段::id → true */\ntype IsDynamicSegment<S extends string> = S extends `:${string}` ? true : false\n\n// ============= 清理 undefined 字段 =============\n\ntype Clean<T> = { [K in keyof T as T[K] extends undefined ? never : K]: T[K] }\n\n// ============= SSE 标记类型 =============\n\ntype SSEBrand = { readonly __brand: 'SSE' }\n\n// ============= 核心类型推断(适配新的 defineRoute) =============\n\n/**\n * 从 defineRoute 返回的路由配置构建方法定义\n * \n * defineRoute 返回的 LeafRouteConfig 结构:\n * {\n * method: TMethod,\n * path: TPath,\n * schema?: TSchema,\n * handler: (ctx) => TReturn | Promise<TReturn>\n * }\n */\ntype BuildMethodDef<R> = R extends {\n readonly schema?: infer TSchema\n readonly handler: infer THandler\n}\n ? Clean<{\n query: GetSchemaQuery<TSchema>\n body: GetSchemaBody<TSchema>\n params: GetSchemaParams<TSchema>\n return: InferHandlerReturn<THandler>\n }>\n : Clean<{\n return: R extends { readonly handler: infer H } ? InferHandlerReturn<H> : unknown\n }>\n\n/**\n * 递归构建嵌套路径结构\n * \n * 处理动态参数:/users/:id → { users: { ':id': { ... } } }\n */\ntype BuildPath<Path extends string, Method extends string, Def> =\n Path extends `${infer First}/${infer Rest}`\n ? IsDynamicSegment<First> extends true\n ? { ':id': BuildPath<Rest, Method, Def> }\n : { [K in First]: BuildPath<Rest, Method, Def> }\n : IsDynamicSegment<Path> extends true\n ? { ':id': { [M in Method]: Def } }\n : Path extends ''\n ? { [M in Method]: Def }\n : { [K in Path]: { [M in Method]: Def } }\n\n/**\n * 从单个路由生成嵌套类型结构\n */\ntype RouteToTree<R> = R extends {\n readonly method: infer M extends string\n readonly path: infer P extends string\n}\n ? BuildPath<TrimSlash<P>, Lowercase<M>, BuildMethodDef<R>>\n : {}\n\n// ============= 深度合并多个路由 =============\n\ntype DeepMerge<A, B> = {\n [K in keyof A | keyof B]:\n K extends keyof A & keyof B\n ? A[K] extends object\n ? B[K] extends object\n ? DeepMerge<A[K], B[K]>\n : A[K] & B[K]\n : A[K] & B[K]\n : K extends keyof A\n ? A[K]\n : K extends keyof B\n ? B[K]\n : never\n}\n\n/** 递归合并路由数组为单一类型结构 */\ntype MergeRoutes<T extends readonly unknown[]> =\n T extends readonly [infer First]\n ? RouteToTree<First>\n : T extends readonly [infer First, ...infer Rest]\n ? DeepMerge<RouteToTree<First>, MergeRoutes<Rest>>\n : {}\n\n/**\n * 从 defineRoutes 结果自动推断 Eden 契约\n * \n * 支持两种用法:\n * 1. 直接从 defineRoutes 结果推断(推荐,无需 as const)\n * 2. 从原始路由定义数组推断(需要 as const)\n * \n * @example\n * ```typescript\n * import { defineRoute, defineRoutes, Type } from 'vafast'\n * import { eden, InferEden } from '@vafast/api-client'\n * \n * // 方式1:直接从 defineRoutes 结果推断(推荐)\n * const routes = defineRoutes([\n * defineRoute({\n * method: 'GET',\n * path: '/users',\n * schema: { query: Type.Object({ page: Type.Number() }) },\n * handler: ({ query }) => ({ users: [], total: 0 })\n * }),\n * defineRoute({\n * method: 'POST',\n * path: '/users',\n * schema: { body: Type.Object({ name: Type.String() }) },\n * handler: ({ body }) => ({ id: '1', name: body.name })\n * })\n * ])\n * \n * const server = new Server(routes)\n * \n * // ✅ 类型推断自动工作,无需 as const!\n * type Api = InferEden<typeof routes>\n * const api = eden<Api>('http://localhost:3000')\n * \n * // 类型安全的调用\n * const { data } = await api.users.get({ page: 1 }) // ✅ query 类型推断\n * const { data: user } = await api.users.post({ name: 'John' }) // ✅ body 类型推断\n * ```\n */\nexport type InferEden<T> =\n // 优先从 __source 提取类型(defineRoutes 返回的结果)\n T extends { __source: infer S extends readonly unknown[] }\n ? MergeRoutes<S>\n // 否则直接作为路由数组处理(需要 as const)\n : T extends readonly unknown[]\n ? MergeRoutes<T>\n : {}\n\n// ============= 契约类型(手动定义时使用) =============\n\ninterface MethodDef {\n query?: unknown\n body?: unknown\n params?: unknown\n return: unknown\n sse?: SSEBrand\n}\n\ntype RouteNode = {\n get?: MethodDef\n post?: MethodDef\n put?: MethodDef\n patch?: MethodDef\n delete?: MethodDef\n ':id'?: RouteNode\n [key: string]: MethodDef | RouteNode | undefined\n}\n\n// ============= 客户端类型 =============\n\ninterface SSECallbacks<T> {\n onMessage: (data: T) => void\n onError?: (error: ApiError) => void\n onOpen?: () => void\n onClose?: () => void\n onReconnect?: (attempt: number, maxAttempts: number) => void\n onMaxReconnects?: () => void\n}\n\ntype MethodCall<M extends MethodDef, HasParams extends boolean = false> =\n M extends { sse: SSEBrand }\n ? M extends { query: infer Q }\n ? (query: Q, callbacks: SSECallbacks<M['return']>, options?: SSESubscribeOptions) => SSESubscription<M['return']>\n : (callbacks: SSECallbacks<M['return']>, options?: SSESubscribeOptions) => SSESubscription<M['return']>\n : HasParams extends true\n ? M extends { body: infer B }\n ? (body: B, config?: RequestConfig) => Promise<ApiResponse<M['return']>>\n : (config?: RequestConfig) => Promise<ApiResponse<M['return']>>\n : M extends { query: infer Q }\n ? (query?: Q, config?: RequestConfig) => Promise<ApiResponse<M['return']>>\n : M extends { body: infer B }\n ? (body: B, config?: RequestConfig) => Promise<ApiResponse<M['return']>>\n : (config?: RequestConfig) => Promise<ApiResponse<M['return']>>\n\ntype IsSSEEndpoint<M> = M extends { sse: { readonly __brand: 'SSE' } } ? true : false\n\ntype Endpoint<T, HasParams extends boolean = false> =\n {\n [K in 'get' | 'post' | 'put' | 'patch' | 'delete' as T extends { [P in K]: MethodDef } ? K : never]:\n T extends { [P in K]: infer M extends MethodDef } ? MethodCall<M, HasParams> : never\n }\n & (T extends { get: infer M extends MethodDef }\n ? IsSSEEndpoint<M> extends true\n ? { subscribe: MethodCall<M, HasParams> }\n : {}\n : {})\n\ntype HTTPMethods = 'get' | 'post' | 'put' | 'patch' | 'delete'\n\n/** \n * 判断是否是路由节点(包含 HTTP 方法作为子键)\n * 路由节点结构:{ post: {...} } 或 { get: {...}, post: {...} }\n * 方法定义结构:{ body?: ..., return: ... }\n */\ntype HasHTTPMethod<T> = T extends { get: unknown } | { post: unknown } | { put: unknown } | { patch: unknown } | { delete: unknown }\n ? true\n : false\n\n/** \n * 判断键是否应该被过滤\n * - 键名是动态参数 :xxx → 过滤\n * - 键名是 HTTP 方法 且 值是方法定义(有 body/return 但没有 HTTP 方法子键)→ 过滤\n * \n * 注意:像 prices.delete 这样的路径段(值是 { post: {...} })不应被过滤\n */\ntype IsMethodDef<T> = T extends { return: unknown }\n ? HasHTTPMethod<T> extends true ? false : true // 有 return 但没有 HTTP 方法 = 方法定义\n : false\n\ntype ShouldFilter<K, T> = K extends `:${string}`\n ? true // 动态参数始终过滤\n : K extends HTTPMethods\n ? IsMethodDef<T> // HTTP 方法名:只有当值是方法定义时才过滤\n : false\n\nexport type EdenClient<T, HasParams extends boolean = false> = {\n [K in keyof T as ShouldFilter<K, T[K]> extends true ? never : K]:\n T[K] extends { ':id': infer Child }\n ? ((params: Record<string, string>) => EdenClient<Child, true>) & EdenClient<T[K], false>\n : EdenClient<T[K], false>\n} & Endpoint<T, HasParams>\n\n// ============= SSE 解析器 =============\n\nasync function* parseSSEStream(\n reader: ReadableStreamDefaultReader<Uint8Array>\n): AsyncGenerator<SSEEvent, void, unknown> {\n const decoder = new TextDecoder();\n let buffer = '';\n\n while (true) {\n const { done, value } = await reader.read();\n\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n\n const events = buffer.split('\\n\\n');\n buffer = events.pop() || '';\n\n for (const eventStr of events) {\n if (!eventStr.trim()) continue;\n\n const event: SSEEvent = { data: '' };\n const lines = eventStr.split('\\n');\n let dataLines: string[] = [];\n\n for (const line of lines) {\n if (line.startsWith('event:')) {\n event.event = line.slice(6).trim();\n } else if (line.startsWith('data:')) {\n dataLines.push(line.slice(5).trim());\n } else if (line.startsWith('id:')) {\n event.id = line.slice(3).trim();\n } else if (line.startsWith('retry:')) {\n event.retry = parseInt(line.slice(6).trim(), 10);\n }\n }\n\n const dataStr = dataLines.join('\\n');\n\n try {\n event.data = JSON.parse(dataStr);\n } catch {\n event.data = dataStr;\n }\n\n yield event;\n }\n }\n}\n\n// ============= Client 类型导入 ==============\n\nimport type { Client } from '../types'\n\n// ============= 实现 =============\n\n/**\n * 创建 Eden 风格的类型安全 API 客户端\n * \n * @param client - Client 实例\n * \n * @example\n * ```typescript\n * import { createClient, eden } from '@vafast/api-client'\n * \n * const client = createClient('http://localhost:3000')\n * .use(authMiddleware)\n * .use(retryMiddleware)\n * \n * const api = eden<Api>(client)\n * \n * const { data, error } = await api.users.find.post({ page: 1 })\n * ```\n */\nexport function eden<T>(client: Client): EdenClient<T> {\n // 获取原始 baseURL(用于普通请求)\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']\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":";;;;;;;;;;;;;;;AAoBA,SAAgB,QACd,aAC0F;AAE1F,MAAK,MAAM,MAAM,YACf,KAAI,OAAO,OAAO,WAChB,OAAM,IAAI,UAAU,gCAAgC;AAIxD,QAAO,SAAS,mBACd,KACA,OAC0B;EAC1B,IAAI,QAAQ;EAEZ,SAAS,SAAS,GAAqC;AAErD,OAAI,KAAK,MACP,QAAO,QAAQ,uBAAO,IAAI,MAAM,+BAA+B,CAAC;AAElE,WAAQ;GAGR,MAAM,KAAK,IAAI,YAAY,SAAS,YAAY,KAAK;AAGrD,OAAI,CAAC,GACH,QAAO,OAAO;AAGhB,OAAI;AAEF,WAAO,QAAQ,QACb,GAAG,WAAW,SAAS,IAAI,EAAE,CAAC,CAC/B;YACM,KAAK;AACZ,WAAO,QAAQ,OAAO,IAAI;;;AAI9B,SAAO,SAAS,EAAE;;;;;;;;;;;;;;ACpCtB,SAAgB,iBACd,IACA,SACiB;CACjB,MAAM,QAAQ;AACd,KAAI,SAAS,KACX,OAAM,iBAAiB,QAAQ;AAEjC,QAAO;;;;;AAMT,SAAS,sBAAyB,MAAgB,KAAqB,KAAmC;AACxG,QAAO;EACL,SAAS;EACT;EACA;EACA,OAAO;EACP,QAAQ,IAAI;EACb;;;;;AAMH,SAAS,oBACP,MACA,SACA,KACA,MAAuB,MACH;AACpB,QAAO;EACL,SAAS;EACT;EACA,MAAM;EACN,OAAO;GAAE;GAAM;GAAS;EACxB,QAAQ,KAAK,UAAU;EACxB;;;;;;;AAeH,SAAS,gBAAgB,SAAiB,MAAc,aAA6B;CAEnF,MAAM,WAAW,GAAG,UADG,KAAK,WAAW,IAAI,GAAG,OAAO,IAAI;AAEzD,QAAO,cAAc,GAAG,SAAS,GAAG,gBAAgB;;;;;AAQtD,IAAM,aAAN,MAAmC;CACjC,AAAS;CACT,AAAQ,cAAiC,EAAE;CAC3C,AAAQ,iBAAyC,EAAE;CACnD,AAAQ,iBAAyB;CAEjC,YAAY,SAAiB;AAE3B,OAAK,UAAU,QAAQ,QAAQ,QAAQ,GAAG;;CAG5C,IAAI,kBAAuC,YAAiC;AAC1E,MAAI,OAAO,qBAAqB,UAAU;AAExC,OAAI,CAAC,WACH,OAAM,IAAI,MAAM,+CAA+C;GAEjE,MAAM,QAAQ;AACd,SAAM,iBAAiB;AACvB,QAAK,YAAY,KAAK,MAAM;QAG5B,MAAK,YAAY,KAAK,iBAAoC;AAE5D,SAAO;;CAGT,QAAQ,GAAmC;AACzC,OAAK,iBAAiB;GAAE,GAAG,KAAK;GAAgB,GAAG;GAAG;AACtD,SAAO;;CAGT,QAAQ,IAAoB;AAC1B,OAAK,iBAAiB;AACtB,SAAO;;CAGT,MAAM,QACJ,QACA,MACA,MACA,QACyB;EACzB,MAAM,UAAU,KAAK;EACrB,MAAM,iBAAiB,KAAK,WAAW,IAAI,GAAG,OAAO,IAAI;EAIzD,MAAM,WAAW,IAAI,IAAI,qBAAqB;AAC9C,WAAS,WAAW;EAGpB,MAAM,UAAU,IAAI,QAAQ;GAC1B,gBAAgB;GAChB,GAAG,KAAK;GACR,GAAG,QAAQ;GACZ,CAAC;EAGF,MAAM,uBAAO,IAAI,KAAsB;AACvC,MAAI,QAAQ,KACV,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,OAAO,KAAK,CACpD,MAAK,IAAI,KAAK,MAAM;AAIxB,OAAK,IAAI,WAAW,QAAQ;EAE5B,MAAM,MAAsB;GAC1B,QAAQ,OAAO,aAAa;GAC5B;GACA,KAAK;GACL;GACA;GACA;GACA;GACA,YAAY;GACb;EAGD,MAAM,eAAe,YAAyC;AAC5D,UAAO,KAAK,aAAgB,IAAI;;AAGlC,MAAI;GAEF,MAAM,WAAW,MAAM,QAAQ,KAAK,YAAY,CAAC,KAAK,aAAa;AAGnE,UAAO;IACL,MAAM,SAAS;IACf,OAAO,SAAS;IACjB;WACM,KAAK;AAEZ,UAAO;IACL,MAAM;IACN,OAAO;KAAE,MAAM;KAAG,UAHN,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,IAAI,CAAC,EAG9B,WAAW;KAAQ;IACrD;;;;;;CAOL,MAAc,aAAgB,KAAkD;EAC9E,MAAM,EAAE,QAAQ,SAAS,MAAM,QAAQ,SAAS;EAChD,MAAM,UAAW,KAAK,IAAI,UAAU,IAAe,KAAK;EAGxD,MAAM,aAAa,IAAI,iBAAiB;EACxC,MAAM,YAAY,QAAQ,WAAW,KAAK;EAC1C,MAAM,YAAY,iBAAiB,WAAW,OAAO,EAAE,UAAU;AAGjE,MAAI,QAAQ,OACV,QAAO,OAAO,iBAAiB,eAAe,WAAW,OAAO,CAAC;EAInE,MAAM,eAA4B;GAChC;GACA;GACA,QAAQ,WAAW;GACpB;AAGD,MAAI,QAAQ,WAAW,SAAS,WAAW,OACzC,cAAa,OAAO,KAAK,UAAU,KAAK;EAI1C,IAAI,cAAc;AAClB,MAAI,WAAW,SAAS,QAAQ,OAAO,SAAS,SAC9C,eAAc,GAAG,UAAU,MAAiC;GAC1D,WAAW;GACX,aAAa;GACd,CAAC;AAGJ,MAAI;GAEF,MAAM,aAAa,gBAAgB,SAAS,IAAI,MAAM,YAAY;GAGlE,MAAM,UAAU,IAAI,QAAQ,YAAY,aAAa;GACrD,MAAM,WAAW,MAAM,MAAM,QAAQ;AACrC,gBAAa,UAAU;GAGvB,MAAM,cAAc,SAAS,QAAQ,IAAI,eAAe;GACxD,IAAI,OAAiB;AAErB,OAAI,aAAa,SAAS,mBAAmB,CAC3C,QAAO,MAAM,SAAS,MAAM;YACnB,aAAa,SAAS,QAAQ,CACvC,QAAO,MAAM,SAAS,MAAM;AAI9B,OAAI,SAAS,GACX,QAAO,sBAAsB,MAAM,KAAK,SAAS;GAInD,MAAM,YAAY;AAClB,UAAO,oBACL,WAAW,QAAQ,SAAS,QAC5B,WAAW,WAAW,QAAQ,SAAS,UACvC,KACA,SACD;WACM,KAAK;AACZ,gBAAa,UAAU;GAEvB,MAAM,QAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,IAAI,CAAC;AAGjE,OAAI,MAAM,SAAS,aACjB,QAAO,oBAAuB,KAAK,QAAQ,IAAI;AAIjD,UAAO,oBAAuB,GAAG,MAAM,WAAW,QAAQ,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;AAmCpE,SAAgB,aAAa,QAAuC;AAClE,KAAI,OAAO,WAAW,SACpB,QAAO,IAAI,WAAW,OAAO;CAG/B,MAAM,SAAS,IAAI,WAAW,OAAO,QAAQ;AAC7C,KAAI,OAAO,YAAY,OACrB,QAAO,QAAQ,OAAO,QAAQ;AAEhC,KAAI,OAAO,QACT,QAAO,QAAQ,OAAO,QAAQ;AAEhC,QAAO;;;;;ACET,gBAAgB,eACd,QACyC;CACzC,MAAM,UAAU,IAAI,aAAa;CACjC,IAAI,SAAS;AAEb,QAAO,MAAM;EACX,MAAM,EAAE,MAAM,UAAU,MAAM,OAAO,MAAM;AAE3C,MAAI,KAAM;AAEV,YAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,MAAM,CAAC;EAEjD,MAAM,SAAS,OAAO,MAAM,OAAO;AACnC,WAAS,OAAO,KAAK,IAAI;AAEzB,OAAK,MAAM,YAAY,QAAQ;AAC7B,OAAI,CAAC,SAAS,MAAM,CAAE;GAEtB,MAAM,QAAkB,EAAE,MAAM,IAAI;GACpC,MAAM,QAAQ,SAAS,MAAM,KAAK;GAClC,IAAI,YAAsB,EAAE;AAE5B,QAAK,MAAM,QAAQ,MACjB,KAAI,KAAK,WAAW,SAAS,CAC3B,OAAM,QAAQ,KAAK,MAAM,EAAE,CAAC,MAAM;YACzB,KAAK,WAAW,QAAQ,CACjC,WAAU,KAAK,KAAK,MAAM,EAAE,CAAC,MAAM,CAAC;YAC3B,KAAK,WAAW,MAAM,CAC/B,OAAM,KAAK,KAAK,MAAM,EAAE,CAAC,MAAM;YACtB,KAAK,WAAW,SAAS,CAClC,OAAM,QAAQ,SAAS,KAAK,MAAM,EAAE,CAAC,MAAM,EAAE,GAAG;GAIpD,MAAM,UAAU,UAAU,KAAK,KAAK;AAEpC,OAAI;AACF,UAAM,OAAO,KAAK,MAAM,QAAQ;WAC1B;AACN,UAAM,OAAO;;AAGf,SAAM;;;;;;;;;;;;;;;;;;;;;;AA6BZ,SAAgB,KAAQ,QAA+B;CAErD,MAAM,kBAAkB,OAAO,WAAW;CAG1C,SAAS,gBAAwB;AAC/B,MAAI,gBAAgB,WAAW,UAAU,IAAI,gBAAgB,WAAW,WAAW,CACjF,QAAO;EAGT,MAAM,SAAS,OAAO,WAAW,eAAe,OAAO,UAAU,SAC7D,OAAO,SAAS,SAChB;AACJ,SAAO,kBAAkB,GAAG,SAAS,oBAAoB;;CAI3D,MAAM,iBAAyC,EAAE;CAGjD,eAAe,QACb,QACA,MACA,MACA,eAC+B;AAC/B,SAAO,OAAO,QAAiB,QAAQ,MAAM,MAAM,cAAc;;CAGnE,SAAS,UACP,MACA,OACA,WACA,SACwB;EACxB,MAAM,MAAM,IAAI,IAAI,MAAM,eAAe,CAAC;AAE1C,MAAI,OACF;QAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,MAAM,CAC9C,KAAI,UAAU,UAAa,UAAU,KACnC,KAAI,aAAa,IAAI,KAAK,OAAO,MAAM,CAAC;;EAK9C,IAAI,kBAA0C,IAAI,iBAAiB;EACnE,IAAI,YAAY;EAChB,IAAI,iBAAiB;EACrB,IAAI,iBAAiB;EACrB,IAAI;EAEJ,MAAM,oBAAoB,SAAS,qBAAqB;EACxD,MAAM,gBAAgB,SAAS,iBAAiB;EAEhD,MAAM,UAAU,YAAY;AAC1B,OAAI,eAAgB;AAEpB,OAAI;AACF,sBAAkB,IAAI,iBAAiB;IAEvC,MAAM,UAAkC;KACtC,UAAU;KACV,GAAG;KACH,GAAG,SAAS;KACb;AAED,QAAI,YACF,SAAQ,mBAAmB;IAG7B,MAAM,WAAW,MAAM,MAAM,IAAI,UAAU,EAAE;KAC3C,QAAQ;KACR;KACA,QAAQ,gBAAgB;KACzB,CAAC;AAEF,QAAI,CAAC,SAAS,GACZ,OAAM,IAAI,MAAM,QAAQ,SAAS,SAAS;AAG5C,QAAI,CAAC,SAAS,KACZ,OAAM,IAAI,MAAM,mBAAmB;AAGrC,gBAAY;AACZ,qBAAiB;AACjB,cAAU,UAAU;IAEpB,MAAM,SAAS,SAAS,KAAK,WAAW;AAExC,eAAW,MAAM,SAAS,eAAe,OAAO,EAAE;AAChD,SAAI,MAAM,GACR,eAAc,MAAM;AAGtB,SAAI,MAAM,UAAU,QAClB,WAAU,UAAU;MAAE,MAAM;MAAI,SAAS,OAAO,MAAM,KAAK;MAAE,CAAC;SAE9D,WAAU,UAAU,MAAM,KAAc;;AAI5C,gBAAY;AACZ,cAAU,WAAW;YAEd,OAAO;AACd,gBAAY;AAEZ,QAAK,MAAgB,SAAS,gBAAgB,eAC5C;IAGF,MAAM,MAAM,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,MAAM,CAAC;AACrE,cAAU,UAAU;KAAE,MAAM;KAAG,SAAS,IAAI,WAAW;KAAY,CAAC;AAEpE,QAAI,iBAAiB,eAAe;AAClC;AACA,eAAU,cAAc,gBAAgB,cAAc;AAEtD,sBAAiB;AACf,UAAI,CAAC,eACH,UAAS;QAEV,kBAAkB;UAErB,WAAU,mBAAmB;;;AAKnC,WAAS;AAET,SAAO;GACL,mBAAmB;AACjB,qBAAiB;AACjB,qBAAiB,OAAO;AACxB,sBAAkB;AAClB,gBAAY;;GAEd,IAAI,YAAY;AACd,WAAO;;GAEV;;;;;;;;;;;CAYH,SAAS,eAAe,UAA6B;EACnD,MAAM,cAAc;GAAC;GAAO;GAAQ;GAAO;GAAS;GAAS;AAE7D,SAAO,IAAI,YAAY,IAAK;GAC1B,IAAI,GAAG,MAAc;AAEnB,WAAO,eAAe,CAAC,GAAG,UAAU,KAAK,CAAC;;GAE5C,MAAM,GAAG,IAAI,MAAM;IACjB,MAAM,CAAC,YAAY;IACnB,MAAM,OAAO,SAAS,SAAS,SAAS;AAKxC,QACE,YACG,OAAO,aAAa,YACpB,CAAC,MAAM,QAAQ,SAAS,IACxB,OAAO,KAAK,SAAS,CAAC,WAAW,KACjC,EAAE,eAAe,aACjB,CAAC,YAAY,SAAS,KAAK,IAC3B,SAAS,OACZ;KACA,MAAM,aAAa,OAAO,OAAO,SAAS,CAAC;AAC3C,YAAO,eAAe,CAAC,GAAG,UAAU,mBAAmB,OAAO,WAAW,CAAC,CAAC,CAAC;;IAI9E,MAAM,OAAO,MADQ,SAAS,MAAM,GAAG,GAAG,CACV,KAAK,IAAI;AAGzC,QAAI,SAAS,OAAO;KAClB,MAAM,CAAC,kBAAkB,oBAAoB,WAAW;AAWxD,SAJoB,OAAO,qBAAqB,YAC3C,eAAe,oBACf,OAAO,iBAAiB,cAAc,WAGzC,QAAO,UAAU,MAAM,QAAW,kBAA2C,mBAA0C;SAEvH,QAAO,UAAU,MAAM,kBAA6C,oBAA6C,QAAQ;;AAK7H,QAAI,YAAY,SAAS,KAAK,EAAE;KAC9B,MAAM,SAAS,KAAK,aAAa;KACjC,MAAM,CAACA,QAAMC,YAAU;AACvB,YAAO,QAAQ,QAAQ,MAAMD,QAAMC,SAAO;;IAI5C,MAAM,WAAW,MAAM,SAAS,KAAK,IAAI;IACzC,MAAM,CAAC,MAAM,UAAU;AACvB,WAAO,QAAQ,QAAQ,UAAU,MAAM,OAAO;;GAEjD,CAAC;;AAGJ,QAAO,IAAI,MAAM,EAAE,EAAmB,EACpC,IAAI,GAAG,MAAc;AACnB,SAAO,eAAe,CAAC,KAAK,CAAC;IAEhC,CAAC;;;;;;;;;;;;;;;;;ACtlBJ,SAAgB,kBAAkB,IAA6B;CAC7D,MAAM,aAAyB,OAAO,KAAK,SAAS;EAElD,MAAM,UAAU,IAAI,QAAQ,WAAW;EAGvC,MAAM,iBAAiB,IAAI,SAAgB,GAAG,WAAW;AACvD,oBAAiB;AACf,2BAAO,IAAI,MAAM,SAAS,QAAQ,KAAK,CAAC;MACvC,QAAQ;IACX;AAGF,MAAI;AAKF,UAJiB,MAAM,QAAQ,KAAK,CAClC,MAAM,EACN,eACD,CAAC;WAEK,OAAO;AAEd,UAAO;IACL,SAAS;IACT,KAAK;IACL,MAAM;IACN,OAAO;KAAE,MAAM;KAAK,UALV,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,MAAM,CAAC,EAKlC;KAAS;IAC1C,QAAQ;IACT;;;CAKL,MAAM,QAAQ;AACd,OAAM,iBAAiB;AACvB,QAAO;;;;;;AC7BT,MAAM,uBAAuB;CAAC;CAAK;CAAK;CAAK;CAAK;CAAK;CAAI;;;;AAK3D,SAAS,MAAM,IAA2B;AACxC,QAAO,IAAI,SAAQ,YAAW,WAAW,SAAS,GAAG,CAAC;;;;;;;;;;;;;;AAexD,SAAgB,gBAAgB,SAAyC;CACvE,MAAM,EACJ,QAAQ,GACR,QAAQ,KACR,UAAU,MACV,KAAK,sBACL,gBACE,WAAW,EAAE;CAEjB,MAAM,aAAyB,OAAO,KAAK,SAAS;EAClD,IAAI,eAAuC;EAC3C,IAAI,UAAU;AAEd,SAAO,WAAW,OAAO;AAEvB,OAAI,aAAa;GAGjB,MAAM,WAAW,MAAM,MAAM;AAC7B,kBAAe;AAGf,OAAI,CAAC,SAAS,MACZ,QAAO;AAQT,OAAI,EAJc,cACd,YAAY,SAAS,GACrB,GAAG,SAAS,SAAS,OAAO,KAEd,WAAW,MAC3B,QAAO;AAKT,SAAM,MADW,UAAU,QAAQ,KAAK,IAAI,GAAG,QAAQ,GAAG,MACrC;AAErB;;AAIF,SAAO;;CAIT,MAAM,QAAQ;AACd,OAAM,iBAAiB;AACvB,QAAO;;;;;;;;;;;;;;;;;;;;;;;;;ACrDT,SAAgB,iBAAiB,SAA0C;CACzE,MAAM,EACJ,WACA,YACA,SAAS,aAAa,MACtB,SAAS,YACP,WAAW,EAAE;CAEjB,MAAM,aAAyB,OAAO,KAAK,SAAS;EAClD,MAAM,YAAY,KAAK,KAAK;AAG5B,MAAI,UACF,WAAU,IAAI;AAEhB,MAAI,WACF,SAAQ,IAAI,GAAG,OAAO,KAAK,IAAI,OAAO,GAAG,IAAI,OAAO;EAItD,MAAM,WAAW,MAAM,MAAM;EAG7B,MAAM,WAAW,KAAK,KAAK,GAAG;AAC9B,MAAI,WACF,YAAW,SAAS;AAEtB,MAAI,YAAY;GACd,MAAM,SAAS,SAAS,QAAQ,OAAO,SAAS,MAAM,SAAS,GAAG,SAAS;AAC3E,WAAQ,IAAI,GAAG,OAAO,KAAK,OAAO,GAAG,IAAI,KAAK,IAAI,SAAS,KAAK;;AAGlE,SAAO;;CAIT,MAAM,QAAQ;AACd,OAAM,iBAAiB;AACvB,QAAO"}
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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vafast/api-client",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
4
4
  "description": "Type-safe API client for Vafast framework",
5
5
  "license": "MIT",
6
6
  "files": [
@@ -14,13 +14,12 @@
14
14
  "release": "npm run build && npm run test && npx bumpp && npm publish --access=public"
15
15
  },
16
16
  "peerDependencies": {
17
- "vafast": "^0.5.1"
17
+ "vafast": "<2.0.0"
18
18
  },
19
19
  "devDependencies": {
20
20
  "@types/qs": "^6.14.0",
21
21
  "tsdown": "^0.19.0-beta.4",
22
22
  "typescript": "^5.5.3",
23
- "vafast": "^0.5.6",
24
23
  "vitest": "^2.1.8"
25
24
  },
26
25
  "main": "./dist/index.mjs",