@vafast/api-client 0.2.0 → 0.2.2

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/dist/index.d.mts CHANGED
@@ -74,13 +74,13 @@ type InferStatic<T> = T extends {
74
74
  static: infer S;
75
75
  } ? S : T;
76
76
  /** 从 Schema 对象提取各部分类型 */
77
- type GetSchemaQuery<S> = S extends {
77
+ type GetSchemaQuery<S$1> = S$1 extends {
78
78
  query: infer Q;
79
79
  } ? InferStatic<Q> : undefined;
80
- type GetSchemaBody<S> = S extends {
80
+ type GetSchemaBody<S$1> = S$1 extends {
81
81
  body: infer B;
82
82
  } ? InferStatic<B> : undefined;
83
- type GetSchemaParams<S> = S extends {
83
+ type GetSchemaParams<S$1> = S$1 extends {
84
84
  params: infer P;
85
85
  } ? InferStatic<P> : undefined;
86
86
  /**
@@ -91,7 +91,7 @@ type InferHandlerReturn<H$1> = H$1 extends ((...args: never[]) => infer R) ? R e
91
91
  /** 移除开头斜杠:/users → users */
92
92
  type TrimSlash<P$1 extends string> = P$1 extends `/${infer R}` ? R : P$1;
93
93
  /** 检查是否是动态参数段::id → true */
94
- type IsDynamicSegment<S extends string> = S extends `:${string}` ? true : false;
94
+ type IsDynamicSegment<S$1 extends string> = S$1 extends `:${string}` ? true : false;
95
95
  type Clean<T> = { [K in keyof T as T[K] extends undefined ? never : K]: T[K] };
96
96
  type SSEBrand = {
97
97
  readonly __brand: 'SSE';
@@ -141,15 +141,19 @@ type DeepMerge<A, B$1> = { [K in keyof A | keyof B$1]: K extends keyof A & keyof
141
141
  /** 递归合并路由数组为单一类型结构 */
142
142
  type MergeRoutes<T extends readonly unknown[]> = T extends readonly [infer First] ? RouteToTree<First> : T extends readonly [infer First, ...infer Rest] ? DeepMerge<RouteToTree<First>, MergeRoutes<Rest>> : {};
143
143
  /**
144
- * 从 defineRoute 数组自动推断 Eden 契约
144
+ * 从 defineRoutes 结果自动推断 Eden 契约
145
+ *
146
+ * 支持两种用法:
147
+ * 1. 直接从 defineRoutes 结果推断(推荐,无需 as const)
148
+ * 2. 从原始路由定义数组推断(需要 as const)
145
149
  *
146
150
  * @example
147
151
  * ```typescript
148
152
  * import { defineRoute, defineRoutes, Type } from 'vafast'
149
153
  * import { eden, InferEden } from '@vafast/api-client'
150
154
  *
151
- * // 定义路由(使用 as const 保留字面量类型)
152
- * const routeDefinitions = [
155
+ * // 方式1:直接从 defineRoutes 结果推断(推荐)
156
+ * const routes = defineRoutes([
153
157
  * defineRoute({
154
158
  * method: 'GET',
155
159
  * path: '/users',
@@ -162,14 +166,12 @@ type MergeRoutes<T extends readonly unknown[]> = T extends readonly [infer First
162
166
  * schema: { body: Type.Object({ name: Type.String() }) },
163
167
  * handler: ({ body }) => ({ id: '1', name: body.name })
164
168
  * })
165
- * ] as const
169
+ * ])
166
170
  *
167
- * // 服务端
168
- * const routes = defineRoutes(routeDefinitions)
169
171
  * const server = new Server(routes)
170
172
  *
171
- * // 客户端类型推断
172
- * type Api = InferEden<typeof routeDefinitions>
173
+ * // ✅ 类型推断自动工作,无需 as const!
174
+ * type Api = InferEden<typeof routes>
173
175
  * const api = eden<Api>('http://localhost:3000')
174
176
  *
175
177
  * // 类型安全的调用
@@ -177,7 +179,9 @@ type MergeRoutes<T extends readonly unknown[]> = T extends readonly [infer First
177
179
  * const { data: user } = await api.users.post({ name: 'John' }) // ✅ body 类型推断
178
180
  * ```
179
181
  */
180
- type InferEden<T extends readonly unknown[]> = MergeRoutes<T>;
182
+ type InferEden<T> = T extends {
183
+ __source: infer S extends readonly unknown[];
184
+ } ? MergeRoutes<S> : T extends readonly unknown[] ? MergeRoutes<T> : {};
181
185
  interface MethodDef {
182
186
  query?: unknown;
183
187
  body?: unknown;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types/index.ts","../src/core/eden.ts"],"sourcesContent":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types/index.ts","../src/core/eden.ts"],"sourcesContent":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/core/eden.ts"],"sourcesContent":["/**\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// ============= 配置 =============\n\nexport interface EdenConfig {\n headers?: Record<string, string>\n onRequest?: (request: Request) => Request | Promise<Request>\n onResponse?: <T>(response: ApiResponse<T>) => ApiResponse<T> | Promise<ApiResponse<T>>\n onError?: (error: ApiError) => void\n timeout?: number\n}\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 * 从 defineRoute 数组自动推断 Eden 契约\n * \n * @example\n * ```typescript\n * import { defineRoute, defineRoutes, Type } from 'vafast'\n * import { eden, InferEden } from '@vafast/api-client'\n * \n * // 定义路由(使用 as const 保留字面量类型)\n * const routeDefinitions = [\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 * ] as const\n * \n * // 服务端\n * const routes = defineRoutes(routeDefinitions)\n * const server = new Server(routes)\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 }) // ✅ query 类型推断\n * const { data: user } = await api.users.post({ name: 'John' }) // ✅ body 类型推断\n * ```\n */\nexport type InferEden<T extends readonly unknown[]> = MergeRoutes<T>\n\n// ============= 契约类型(手动定义时使用) =============\n\ninterface MethodDef {\n query?: unknown\n body?: unknown\n params?: unknown\n return: unknown\n sse?: SSEBrand\n}\n\ntype RouteNode = {\n get?: MethodDef\n post?: MethodDef\n put?: MethodDef\n patch?: MethodDef\n delete?: MethodDef\n ':id'?: RouteNode\n [key: string]: MethodDef | RouteNode | undefined\n}\n\n// ============= 客户端类型 =============\n\ninterface SSECallbacks<T> {\n onMessage: (data: T) => void\n onError?: (error: ApiError) => void\n onOpen?: () => void\n onClose?: () => void\n onReconnect?: (attempt: number, maxAttempts: number) => void\n onMaxReconnects?: () => void\n}\n\ntype MethodCall<M extends MethodDef, HasParams extends boolean = false> = \n M extends { sse: SSEBrand }\n ? M extends { query: infer Q }\n ? (query: Q, callbacks: SSECallbacks<M['return']>, options?: SSESubscribeOptions) => SSESubscription<M['return']>\n : (callbacks: SSECallbacks<M['return']>, options?: SSESubscribeOptions) => SSESubscription<M['return']>\n : HasParams extends true\n ? M extends { body: infer B }\n ? (body: B, config?: RequestConfig) => Promise<ApiResponse<M['return']>>\n : (config?: RequestConfig) => Promise<ApiResponse<M['return']>>\n : M extends { query: infer Q }\n ? (query?: Q, config?: RequestConfig) => Promise<ApiResponse<M['return']>>\n : M extends { body: infer B }\n ? (body: B, config?: RequestConfig) => Promise<ApiResponse<M['return']>>\n : (config?: RequestConfig) => Promise<ApiResponse<M['return']>>\n\ntype IsSSEEndpoint<M> = M extends { sse: { readonly __brand: 'SSE' } } ? true : false\n\ntype Endpoint<T, HasParams extends boolean = false> = \n {\n [K in 'get' | 'post' | 'put' | 'patch' | 'delete' as T extends { [P in K]: MethodDef } ? K : never]: \n T extends { [P in K]: infer M extends MethodDef } ? MethodCall<M, HasParams> : never\n } \n & (T extends { get: infer M extends MethodDef }\n ? IsSSEEndpoint<M> extends true \n ? { subscribe: MethodCall<M, HasParams> }\n : {}\n : {})\n\ntype HTTPMethods = 'get' | 'post' | 'put' | 'patch' | 'delete'\n\nexport type EdenClient<T, HasParams extends boolean = false> = {\n [K in keyof T as K extends HTTPMethods | `:${string}` ? never : K]: \n T[K] extends { ':id': infer Child }\n ? ((params: Record<string, string>) => EdenClient<Child, true>) & EdenClient<T[K], false>\n : EdenClient<T[K], false>\n} & Endpoint<T, HasParams>\n\n// ============= SSE 解析器 =============\n\nasync function* parseSSEStream(\n reader: ReadableStreamDefaultReader<Uint8Array>\n): AsyncGenerator<SSEEvent, void, unknown> {\n const decoder = new TextDecoder();\n let buffer = '';\n \n while (true) {\n const { done, value } = await reader.read();\n \n if (done) break;\n \n buffer += decoder.decode(value, { stream: true });\n \n const events = buffer.split('\\n\\n');\n buffer = events.pop() || '';\n \n for (const eventStr of events) {\n if (!eventStr.trim()) continue;\n \n const event: SSEEvent = { data: '' };\n const lines = eventStr.split('\\n');\n let dataLines: string[] = [];\n \n for (const line of lines) {\n if (line.startsWith('event:')) {\n event.event = line.slice(6).trim();\n } else if (line.startsWith('data:')) {\n dataLines.push(line.slice(5).trim());\n } else if (line.startsWith('id:')) {\n event.id = line.slice(3).trim();\n } else if (line.startsWith('retry:')) {\n event.retry = parseInt(line.slice(6).trim(), 10);\n }\n }\n \n const dataStr = dataLines.join('\\n');\n \n try {\n event.data = JSON.parse(dataStr);\n } catch {\n event.data = dataStr;\n }\n \n yield event;\n }\n }\n}\n\n// ============= 实现 =============\n\n/**\n * 创建 Eden 风格的类型安全 API 客户端\n */\nexport function eden<T>(\n baseURL: string,\n config?: EdenConfig\n): EdenClient<T> {\n const { headers: defaultHeaders, onRequest, onResponse, onError, timeout } = config ?? {}\n\n async function request<TReturn>(\n method: string,\n path: string,\n data?: unknown,\n requestConfig?: RequestConfig\n ): Promise<ApiResponse<TReturn>> {\n const url = new URL(path, baseURL)\n \n if (method === 'GET' && data && typeof data === 'object') {\n for (const [key, value] of Object.entries(data as Record<string, unknown>)) {\n if (value !== undefined && value !== null) {\n url.searchParams.set(key, String(value))\n }\n }\n }\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...defaultHeaders,\n ...requestConfig?.headers,\n }\n\n const controller = new AbortController()\n let timeoutId: ReturnType<typeof setTimeout> | undefined\n \n const userSignal = requestConfig?.signal\n const requestTimeout = requestConfig?.timeout ?? timeout\n \n if (userSignal) {\n if (userSignal.aborted) {\n controller.abort()\n } else {\n userSignal.addEventListener('abort', () => controller.abort())\n }\n }\n \n if (requestTimeout) {\n timeoutId = setTimeout(() => controller.abort(), requestTimeout)\n }\n\n const fetchOptions: RequestInit = { \n method, \n headers,\n signal: controller.signal \n }\n\n if (method !== 'GET' && method !== 'HEAD' && data) {\n fetchOptions.body = JSON.stringify(data)\n }\n\n let req = new Request(url.toString(), fetchOptions)\n \n if (onRequest) {\n req = await onRequest(req)\n }\n\n try {\n const response = await fetch(req)\n \n if (timeoutId) clearTimeout(timeoutId)\n \n const contentType = response.headers.get('content-type')\n let responseData: TReturn | null = null\n \n if (contentType?.includes('application/json')) {\n responseData = await response.json()\n } else if (contentType?.includes('text/')) {\n responseData = await response.text() as unknown as TReturn\n }\n\n let result: ApiResponse<TReturn>\n \n if (response.ok) {\n result = { data: responseData, error: null }\n } else {\n const errorBody = responseData as { code?: number; message?: string } | null\n result = {\n data: null,\n error: {\n code: errorBody?.code ?? response.status,\n message: errorBody?.message ?? `HTTP ${response.status}`\n }\n }\n }\n\n if (onResponse) {\n result = await onResponse(result)\n }\n\n if (result.error && onError) {\n onError(result.error)\n }\n\n return result\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error))\n const apiError: ApiError = { code: 0, message: err.message || '网络错误' }\n if (onError) onError(apiError)\n return {\n data: null,\n error: apiError,\n }\n }\n }\n\n function subscribe<TData>(\n path: string,\n query: Record<string, unknown> | undefined,\n callbacks: SSECallbacks<TData>,\n options?: SSESubscribeOptions\n ): SSESubscription<TData> {\n const url = new URL(path, baseURL)\n \n if (query) {\n for (const [key, value] of Object.entries(query)) {\n if (value !== undefined && value !== null) {\n url.searchParams.set(key, String(value))\n }\n }\n }\n\n let abortController: AbortController | null = new AbortController()\n let connected = false\n let reconnectCount = 0\n let isUnsubscribed = false\n let lastEventId: string | undefined\n \n const reconnectInterval = options?.reconnectInterval ?? 3000\n const maxReconnects = options?.maxReconnects ?? 5\n\n const connect = async () => {\n if (isUnsubscribed) return\n \n try {\n abortController = new AbortController()\n \n const headers: Record<string, string> = {\n 'Accept': 'text/event-stream',\n ...defaultHeaders,\n ...options?.headers,\n }\n \n if (lastEventId) {\n headers['Last-Event-ID'] = lastEventId\n }\n \n const response = await fetch(url.toString(), {\n method: 'GET',\n headers,\n signal: abortController.signal,\n })\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}`)\n }\n\n if (!response.body) {\n throw new Error('No response body')\n }\n\n connected = true\n reconnectCount = 0\n callbacks.onOpen?.()\n\n const reader = response.body.getReader()\n \n for await (const event of parseSSEStream(reader)) {\n if (event.id) {\n lastEventId = event.id\n }\n \n if (event.event === 'error') {\n callbacks.onError?.({ code: -1, message: String(event.data) })\n } else {\n callbacks.onMessage(event.data as TData)\n }\n }\n\n connected = false\n callbacks.onClose?.()\n \n } catch (error) {\n connected = false\n \n if ((error as Error).name === 'AbortError' || isUnsubscribed) {\n return\n }\n \n const err = error instanceof Error ? error : new Error(String(error))\n callbacks.onError?.({ code: 0, message: err.message || 'SSE 连接错误' })\n \n if (reconnectCount < maxReconnects) {\n reconnectCount++\n callbacks.onReconnect?.(reconnectCount, maxReconnects)\n \n setTimeout(() => {\n if (!isUnsubscribed) {\n connect()\n }\n }, reconnectInterval)\n } else {\n callbacks.onMaxReconnects?.()\n }\n }\n }\n\n connect()\n\n return {\n unsubscribe: () => {\n isUnsubscribed = true\n abortController?.abort()\n abortController = null\n connected = false\n },\n get connected() {\n return connected\n }\n }\n }\n\n function createEndpoint(basePath: string): unknown {\n const methods = ['get', 'post', 'put', 'patch', 'delete']\n \n const handler = (params: Record<string, string>) => {\n const paramValue = Object.values(params)[0]\n const newPath = `${basePath}/${encodeURIComponent(paramValue)}`\n return createEndpoint(newPath)\n }\n\n return new Proxy(handler as unknown as object, {\n get(_, prop: string) {\n if (methods.includes(prop)) {\n const httpMethod = prop.toUpperCase()\n return (data?: unknown, cfg?: RequestConfig) => {\n return request(httpMethod, basePath, data, cfg)\n }\n }\n \n if (prop === 'subscribe') {\n return <TData>(\n queryOrCallbacks: Record<string, unknown> | SSECallbacks<TData>,\n callbacksOrOptions?: SSECallbacks<TData> | SSESubscribeOptions,\n options?: SSESubscribeOptions\n ) => {\n if (typeof queryOrCallbacks === 'object' && 'onMessage' in queryOrCallbacks) {\n return subscribe<TData>(\n basePath, \n undefined, \n queryOrCallbacks as SSECallbacks<TData>,\n callbacksOrOptions as SSESubscribeOptions\n )\n } else {\n return subscribe<TData>(\n basePath,\n queryOrCallbacks as Record<string, unknown>,\n callbacksOrOptions as SSECallbacks<TData>,\n options\n )\n }\n }\n }\n \n const childPath = `${basePath}/${prop}`\n return createEndpoint(childPath)\n },\n apply(_, __, args) {\n const params = args[0] as Record<string, string>\n const paramValue = Object.values(params)[0]\n const newPath = `${basePath}/${encodeURIComponent(paramValue)}`\n return createEndpoint(newPath)\n }\n })\n }\n\n return new Proxy({} as EdenClient<T>, {\n get(_, prop: string) {\n return createEndpoint(`/${prop}`)\n }\n })\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/core/eden.ts"],"sourcesContent":["/**\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// ============= 配置 =============\n\nexport interface EdenConfig {\n headers?: Record<string, string>\n onRequest?: (request: Request) => Request | Promise<Request>\n onResponse?: <T>(response: ApiResponse<T>) => ApiResponse<T> | Promise<ApiResponse<T>>\n onError?: (error: ApiError) => void\n timeout?: number\n}\n\n// ============= SSE 类型 =============\n\nexport interface SSEEvent<T = unknown> {\n event?: string\n data: T\n id?: string\n retry?: number\n}\n\nexport interface SSESubscribeOptions {\n headers?: Record<string, string>\n reconnectInterval?: number\n maxReconnects?: number\n timeout?: number\n}\n\nexport interface SSESubscription<T = unknown> {\n unsubscribe: () => void\n readonly connected: boolean\n}\n\n// ============= 基础类型工具 =============\n\n/** 从 TypeBox Schema 提取静态类型 */\ntype InferStatic<T> = T extends { static: infer S } ? S : T\n\n/** 检查是否是 SSE Handler */\ntype IsSSEHandler<T> = T extends { __sse: { readonly __brand: 'SSE' } } ? true : false\n\n/** 从 Schema 对象提取各部分类型 */\ntype GetSchemaQuery<S> = S extends { query: infer Q } ? InferStatic<Q> : undefined\ntype GetSchemaBody<S> = S extends { body: infer B } ? InferStatic<B> : undefined\ntype GetSchemaParams<S> = S extends { params: infer P } ? InferStatic<P> : undefined\n\n/** \n * 从 handler 函数推断返回类型\n * handler: (ctx) => TReturn | Promise<TReturn>\n */\ntype InferHandlerReturn<H> = H extends (...args: never[]) => infer R\n ? R extends Promise<infer T> ? T : R\n : unknown\n\n// ============= 路径处理 =============\n\n/** 移除开头斜杠:/users → users */\ntype TrimSlash<P extends string> = P extends `/${infer R}` ? R : P\n\n/** 获取第一段:users/posts → users */\ntype Head<P extends string> = P extends `${infer H}/${string}` ? H : P\n\n/** 获取剩余段:users/posts → posts */\ntype Tail<P extends string> = P extends `${string}/${infer T}` ? T : never\n\n/** 检查是否是动态参数段::id → true */\ntype IsDynamicSegment<S extends string> = S extends `:${string}` ? true : false\n\n// ============= 清理 undefined 字段 =============\n\ntype Clean<T> = { [K in keyof T as T[K] extends undefined ? never : K]: T[K] }\n\n// ============= SSE 标记类型 =============\n\ntype SSEBrand = { readonly __brand: 'SSE' }\n\n// ============= 核心类型推断(适配新的 defineRoute) =============\n\n/**\n * 从 defineRoute 返回的路由配置构建方法定义\n * \n * defineRoute 返回的 LeafRouteConfig 结构:\n * {\n * method: TMethod,\n * path: TPath,\n * schema?: TSchema,\n * handler: (ctx) => TReturn | Promise<TReturn>\n * }\n */\ntype BuildMethodDef<R> = R extends {\n readonly schema?: infer TSchema\n readonly handler: infer THandler\n}\n ? Clean<{\n query: GetSchemaQuery<TSchema>\n body: GetSchemaBody<TSchema>\n params: GetSchemaParams<TSchema>\n return: InferHandlerReturn<THandler>\n }>\n : Clean<{\n return: R extends { readonly handler: infer H } ? InferHandlerReturn<H> : unknown\n }>\n\n/**\n * 递归构建嵌套路径结构\n * \n * 处理动态参数:/users/:id → { users: { ':id': { ... } } }\n */\ntype BuildPath<Path extends string, Method extends string, Def> =\n Path extends `${infer First}/${infer Rest}`\n ? IsDynamicSegment<First> extends true\n ? { ':id': BuildPath<Rest, Method, Def> }\n : { [K in First]: BuildPath<Rest, Method, Def> }\n : IsDynamicSegment<Path> extends true\n ? { ':id': { [M in Method]: Def } }\n : Path extends ''\n ? { [M in Method]: Def }\n : { [K in Path]: { [M in Method]: Def } }\n\n/**\n * 从单个路由生成嵌套类型结构\n */\ntype RouteToTree<R> = R extends {\n readonly method: infer M extends string\n readonly path: infer P extends string\n}\n ? BuildPath<TrimSlash<P>, Lowercase<M>, BuildMethodDef<R>>\n : {}\n\n// ============= 深度合并多个路由 =============\n\ntype DeepMerge<A, B> = {\n [K in keyof A | keyof B]: \n K extends keyof A & keyof B\n ? A[K] extends object\n ? B[K] extends object\n ? DeepMerge<A[K], B[K]>\n : A[K] & B[K]\n : A[K] & B[K]\n : K extends keyof A\n ? A[K]\n : K extends keyof B\n ? B[K]\n : never\n}\n\n/** 递归合并路由数组为单一类型结构 */\ntype MergeRoutes<T extends readonly unknown[]> = \n T extends readonly [infer First]\n ? RouteToTree<First>\n : T extends readonly [infer First, ...infer Rest]\n ? DeepMerge<RouteToTree<First>, MergeRoutes<Rest>>\n : {}\n\n/**\n * 从 defineRoutes 结果自动推断 Eden 契约\n * \n * 支持两种用法:\n * 1. 直接从 defineRoutes 结果推断(推荐,无需 as const)\n * 2. 从原始路由定义数组推断(需要 as const)\n * \n * @example\n * ```typescript\n * import { defineRoute, defineRoutes, Type } from 'vafast'\n * import { eden, InferEden } from '@vafast/api-client'\n * \n * // 方式1:直接从 defineRoutes 结果推断(推荐)\n * const routes = defineRoutes([\n * defineRoute({\n * method: 'GET',\n * path: '/users',\n * schema: { query: Type.Object({ page: Type.Number() }) },\n * handler: ({ query }) => ({ users: [], total: 0 })\n * }),\n * defineRoute({\n * method: 'POST',\n * path: '/users',\n * schema: { body: Type.Object({ name: Type.String() }) },\n * handler: ({ body }) => ({ id: '1', name: body.name })\n * })\n * ])\n * \n * const server = new Server(routes)\n * \n * // ✅ 类型推断自动工作,无需 as const!\n * type Api = InferEden<typeof routes>\n * const api = eden<Api>('http://localhost:3000')\n * \n * // 类型安全的调用\n * const { data } = await api.users.get({ page: 1 }) // ✅ query 类型推断\n * const { data: user } = await api.users.post({ name: 'John' }) // ✅ body 类型推断\n * ```\n */\nexport type InferEden<T> = \n // 优先从 __source 提取类型(defineRoutes 返回的结果)\n T extends { __source: infer S extends readonly unknown[] }\n ? MergeRoutes<S>\n // 否则直接作为路由数组处理(需要 as const)\n : T extends readonly unknown[]\n ? MergeRoutes<T>\n : {}\n\n// ============= 契约类型(手动定义时使用) =============\n\ninterface MethodDef {\n query?: unknown\n body?: unknown\n params?: unknown\n return: unknown\n sse?: SSEBrand\n}\n\ntype RouteNode = {\n get?: MethodDef\n post?: MethodDef\n put?: MethodDef\n patch?: MethodDef\n delete?: MethodDef\n ':id'?: RouteNode\n [key: string]: MethodDef | RouteNode | undefined\n}\n\n// ============= 客户端类型 =============\n\ninterface SSECallbacks<T> {\n onMessage: (data: T) => void\n onError?: (error: ApiError) => void\n onOpen?: () => void\n onClose?: () => void\n onReconnect?: (attempt: number, maxAttempts: number) => void\n onMaxReconnects?: () => void\n}\n\ntype MethodCall<M extends MethodDef, HasParams extends boolean = false> = \n M extends { sse: SSEBrand }\n ? M extends { query: infer Q }\n ? (query: Q, callbacks: SSECallbacks<M['return']>, options?: SSESubscribeOptions) => SSESubscription<M['return']>\n : (callbacks: SSECallbacks<M['return']>, options?: SSESubscribeOptions) => SSESubscription<M['return']>\n : HasParams extends true\n ? M extends { body: infer B }\n ? (body: B, config?: RequestConfig) => Promise<ApiResponse<M['return']>>\n : (config?: RequestConfig) => Promise<ApiResponse<M['return']>>\n : M extends { query: infer Q }\n ? (query?: Q, config?: RequestConfig) => Promise<ApiResponse<M['return']>>\n : M extends { body: infer B }\n ? (body: B, config?: RequestConfig) => Promise<ApiResponse<M['return']>>\n : (config?: RequestConfig) => Promise<ApiResponse<M['return']>>\n\ntype IsSSEEndpoint<M> = M extends { sse: { readonly __brand: 'SSE' } } ? true : false\n\ntype Endpoint<T, HasParams extends boolean = false> = \n {\n [K in 'get' | 'post' | 'put' | 'patch' | 'delete' as T extends { [P in K]: MethodDef } ? K : never]: \n T extends { [P in K]: infer M extends MethodDef } ? MethodCall<M, HasParams> : never\n } \n & (T extends { get: infer M extends MethodDef }\n ? IsSSEEndpoint<M> extends true \n ? { subscribe: MethodCall<M, HasParams> }\n : {}\n : {})\n\ntype HTTPMethods = 'get' | 'post' | 'put' | 'patch' | 'delete'\n\nexport type EdenClient<T, HasParams extends boolean = false> = {\n [K in keyof T as K extends HTTPMethods | `:${string}` ? never : K]: \n T[K] extends { ':id': infer Child }\n ? ((params: Record<string, string>) => EdenClient<Child, true>) & EdenClient<T[K], false>\n : EdenClient<T[K], false>\n} & Endpoint<T, HasParams>\n\n// ============= SSE 解析器 =============\n\nasync function* parseSSEStream(\n reader: ReadableStreamDefaultReader<Uint8Array>\n): AsyncGenerator<SSEEvent, void, unknown> {\n const decoder = new TextDecoder();\n let buffer = '';\n \n while (true) {\n const { done, value } = await reader.read();\n \n if (done) break;\n \n buffer += decoder.decode(value, { stream: true });\n \n const events = buffer.split('\\n\\n');\n buffer = events.pop() || '';\n \n for (const eventStr of events) {\n if (!eventStr.trim()) continue;\n \n const event: SSEEvent = { data: '' };\n const lines = eventStr.split('\\n');\n let dataLines: string[] = [];\n \n for (const line of lines) {\n if (line.startsWith('event:')) {\n event.event = line.slice(6).trim();\n } else if (line.startsWith('data:')) {\n dataLines.push(line.slice(5).trim());\n } else if (line.startsWith('id:')) {\n event.id = line.slice(3).trim();\n } else if (line.startsWith('retry:')) {\n event.retry = parseInt(line.slice(6).trim(), 10);\n }\n }\n \n const dataStr = dataLines.join('\\n');\n \n try {\n event.data = JSON.parse(dataStr);\n } catch {\n event.data = dataStr;\n }\n \n yield event;\n }\n }\n}\n\n// ============= 实现 =============\n\n/**\n * 创建 Eden 风格的类型安全 API 客户端\n */\nexport function eden<T>(\n baseURL: string,\n config?: EdenConfig\n): EdenClient<T> {\n const { headers: defaultHeaders, onRequest, onResponse, onError, timeout } = config ?? {}\n\n async function request<TReturn>(\n method: string,\n path: string,\n data?: unknown,\n requestConfig?: RequestConfig\n ): Promise<ApiResponse<TReturn>> {\n const url = new URL(path, baseURL)\n \n if (method === 'GET' && data && typeof data === 'object') {\n for (const [key, value] of Object.entries(data as Record<string, unknown>)) {\n if (value !== undefined && value !== null) {\n url.searchParams.set(key, String(value))\n }\n }\n }\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...defaultHeaders,\n ...requestConfig?.headers,\n }\n\n const controller = new AbortController()\n let timeoutId: ReturnType<typeof setTimeout> | undefined\n \n const userSignal = requestConfig?.signal\n const requestTimeout = requestConfig?.timeout ?? timeout\n \n if (userSignal) {\n if (userSignal.aborted) {\n controller.abort()\n } else {\n userSignal.addEventListener('abort', () => controller.abort())\n }\n }\n \n if (requestTimeout) {\n timeoutId = setTimeout(() => controller.abort(), requestTimeout)\n }\n\n const fetchOptions: RequestInit = { \n method, \n headers,\n signal: controller.signal \n }\n\n if (method !== 'GET' && method !== 'HEAD' && data) {\n fetchOptions.body = JSON.stringify(data)\n }\n\n let req = new Request(url.toString(), fetchOptions)\n \n if (onRequest) {\n req = await onRequest(req)\n }\n\n try {\n const response = await fetch(req)\n \n if (timeoutId) clearTimeout(timeoutId)\n \n const contentType = response.headers.get('content-type')\n let responseData: TReturn | null = null\n \n if (contentType?.includes('application/json')) {\n responseData = await response.json()\n } else if (contentType?.includes('text/')) {\n responseData = await response.text() as unknown as TReturn\n }\n\n let result: ApiResponse<TReturn>\n \n if (response.ok) {\n result = { data: responseData, error: null }\n } else {\n const errorBody = responseData as { code?: number; message?: string } | null\n result = {\n data: null,\n error: {\n code: errorBody?.code ?? response.status,\n message: errorBody?.message ?? `HTTP ${response.status}`\n }\n }\n }\n\n if (onResponse) {\n result = await onResponse(result)\n }\n\n if (result.error && onError) {\n onError(result.error)\n }\n\n return result\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error))\n const apiError: ApiError = { code: 0, message: err.message || '网络错误' }\n if (onError) onError(apiError)\n return {\n data: null,\n error: apiError,\n }\n }\n }\n\n function subscribe<TData>(\n path: string,\n query: Record<string, unknown> | undefined,\n callbacks: SSECallbacks<TData>,\n options?: SSESubscribeOptions\n ): SSESubscription<TData> {\n const url = new URL(path, baseURL)\n \n if (query) {\n for (const [key, value] of Object.entries(query)) {\n if (value !== undefined && value !== null) {\n url.searchParams.set(key, String(value))\n }\n }\n }\n\n let abortController: AbortController | null = new AbortController()\n let connected = false\n let reconnectCount = 0\n let isUnsubscribed = false\n let lastEventId: string | undefined\n \n const reconnectInterval = options?.reconnectInterval ?? 3000\n const maxReconnects = options?.maxReconnects ?? 5\n\n const connect = async () => {\n if (isUnsubscribed) return\n \n try {\n abortController = new AbortController()\n \n const headers: Record<string, string> = {\n 'Accept': 'text/event-stream',\n ...defaultHeaders,\n ...options?.headers,\n }\n \n if (lastEventId) {\n headers['Last-Event-ID'] = lastEventId\n }\n \n const response = await fetch(url.toString(), {\n method: 'GET',\n headers,\n signal: abortController.signal,\n })\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}`)\n }\n\n if (!response.body) {\n throw new Error('No response body')\n }\n\n connected = true\n reconnectCount = 0\n callbacks.onOpen?.()\n\n const reader = response.body.getReader()\n \n for await (const event of parseSSEStream(reader)) {\n if (event.id) {\n lastEventId = event.id\n }\n \n if (event.event === 'error') {\n callbacks.onError?.({ code: -1, message: String(event.data) })\n } else {\n callbacks.onMessage(event.data as TData)\n }\n }\n\n connected = false\n callbacks.onClose?.()\n \n } catch (error) {\n connected = false\n \n if ((error as Error).name === 'AbortError' || isUnsubscribed) {\n return\n }\n \n const err = error instanceof Error ? error : new Error(String(error))\n callbacks.onError?.({ code: 0, message: err.message || 'SSE 连接错误' })\n \n if (reconnectCount < maxReconnects) {\n reconnectCount++\n callbacks.onReconnect?.(reconnectCount, maxReconnects)\n \n setTimeout(() => {\n if (!isUnsubscribed) {\n connect()\n }\n }, reconnectInterval)\n } else {\n callbacks.onMaxReconnects?.()\n }\n }\n }\n\n connect()\n\n return {\n unsubscribe: () => {\n isUnsubscribed = true\n abortController?.abort()\n abortController = null\n connected = false\n },\n get connected() {\n return connected\n }\n }\n }\n\n function createEndpoint(basePath: string): unknown {\n const methods = ['get', 'post', 'put', 'patch', 'delete']\n \n const handler = (params: Record<string, string>) => {\n const paramValue = Object.values(params)[0]\n const newPath = `${basePath}/${encodeURIComponent(paramValue)}`\n return createEndpoint(newPath)\n }\n\n return new Proxy(handler as unknown as object, {\n get(_, prop: string) {\n if (methods.includes(prop)) {\n const httpMethod = prop.toUpperCase()\n return (data?: unknown, cfg?: RequestConfig) => {\n return request(httpMethod, basePath, data, cfg)\n }\n }\n \n if (prop === 'subscribe') {\n return <TData>(\n queryOrCallbacks: Record<string, unknown> | SSECallbacks<TData>,\n callbacksOrOptions?: SSECallbacks<TData> | SSESubscribeOptions,\n options?: SSESubscribeOptions\n ) => {\n if (typeof queryOrCallbacks === 'object' && 'onMessage' in queryOrCallbacks) {\n return subscribe<TData>(\n basePath, \n undefined, \n queryOrCallbacks as SSECallbacks<TData>,\n callbacksOrOptions as SSESubscribeOptions\n )\n } else {\n return subscribe<TData>(\n basePath,\n queryOrCallbacks as Record<string, unknown>,\n callbacksOrOptions as SSECallbacks<TData>,\n options\n )\n }\n }\n }\n \n const childPath = `${basePath}/${prop}`\n return createEndpoint(childPath)\n },\n apply(_, __, args) {\n const params = args[0] as Record<string, string>\n const paramValue = Object.values(params)[0]\n const newPath = `${basePath}/${encodeURIComponent(paramValue)}`\n return createEndpoint(newPath)\n }\n })\n }\n\n return new Proxy({} as EdenClient<T>, {\n get(_, prop: string) {\n return createEndpoint(`/${prop}`)\n }\n })\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vafast/api-client",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Type-safe API client for Vafast framework",
5
5
  "license": "MIT",
6
6
  "files": [
@@ -17,9 +17,9 @@
17
17
  "vafast": "^0.5.1"
18
18
  },
19
19
  "devDependencies": {
20
- "vafast": "^0.5.1",
21
20
  "tsdown": "^0.19.0-beta.4",
22
21
  "typescript": "^5.5.3",
22
+ "vafast": "^0.5.6",
23
23
  "vitest": "^2.1.8"
24
24
  },
25
25
  "main": "./dist/index.mjs",